Compare commits

..
Author SHA1 Message Date
Tucker Babcock 4adfa0fc86 updting io benchmark 2020-05-05 15:44:44 -04:00
Tucker Babcock 857a24f6c4 Merge branch 'PCFinalProject' of github.com:mfem/mfem into PCFinalProject 2020-05-04 11:14:22 -07:00
Tucker Babcock 1ae22c7c69 adding io benchmark 2020-05-04 11:13:42 -07:00
Tucker Babcock 161ebff2a1 Merge branch 'PCFinalProject' of https://github.com/mfem/mfem into PCFinalProject 2020-05-04 12:42:18 -04:00
Tucker Babcock 3548f2cb83 adding num ranks printing 2020-05-04 12:42:13 -04:00
Tucker Babcock 41a7730048 adding barriers ahead of timings and averaging timing over all ranks 2020-05-04 09:40:57 -07:00
Tucker Babcock b638fb8960 adding all of the operator testing to one file 2020-05-03 22:02:26 -07:00
Tucker Babcock dc80f42710 Merge branch 'PCFinalProject' of https://github.com/mfem/mfem into PCFinalProject 2020-05-04 00:51:51 -04:00
Tucker Babcock 4414a3fc01 adding test to mfem examples 2020-05-04 00:50:16 -04:00
Tucker Babcock 2f683f80fa Merge branch 'mpiio-gf-dev' into PCFinalProject 2020-04-30 14:09:33 -07:00
Tucker Babcock 6ea2f7bf55 Merge branch 'mpiio-gf-dev' of github.com:mfem/mfem into mpiio-gf-dev 2020-04-30 14:06:16 -07:00
Tucker Babcock 581cafa7a7 updating documentation 2020-04-30 14:06:10 -07:00
Tucker Babcock c5bab73f9a Merge branch 'mpiio-gf-dev' into PCFinalProject 2020-04-30 15:45:12 -04:00
Tucker Babcock b02eb71967 adding number of files printing control to example 1 2020-04-30 15:39:19 -04:00
Tucker Babcock d236571e4a cleaned up code in pgridfunc and added printing to example two. 2020-04-28 21:04:11 -07:00
Tucker Babcock 8d444d7f92 ordering by nodes appears to work now as well 2020-04-28 16:28:07 -07:00
Tucker Babcock 71937096f8 ordering by vdim works with high order 2020-04-28 16:26:30 -07:00
Tucker Babcock 4e0978cf3b can save and load files correctly for p = 1, errors otherwise. 2020-04-28 15:10:12 -07:00
Tucker Babcock e52fdd205a initial commit adding MPI-IO writing of GridFunction supporting writing to arbitrary number of files. Reading support to come 2020-04-27 22:41:28 -07:00
218 changed files with 5969 additions and 24697 deletions
-4
View File
@@ -29,8 +29,6 @@ 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
@@ -169,7 +167,6 @@ 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
@@ -183,7 +180,6 @@ 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*
+6 -3
View File
@@ -11,6 +11,8 @@
language: cpp
sudo: false
stages:
- checks
- tests
@@ -368,10 +370,8 @@ script:
# Compiler
- if [ $MPI == "YES" ]; then
export MYCXX=mpic++;
export MAKE_CXX_FLAG=MPICXX=$MYCXX;
else
export MYCXX="$CXX";
export MAKE_CXX_FLAG=CXX=$MYCXX;
fi
# Print the compiler version
@@ -384,9 +384,12 @@ script:
if [ "$CODECOV" == "YES" ]; then
CPPFLAGS="--coverage -g";
fi;
if [ "$CXX" == "clang++" ]; then
export MFEM_PERF_SW=clang;
fi
# Configure the library
- make config MFEM_USE_MPI=$MPI MFEM_DEBUG=$DEBUG $MAKE_CXX_FLAG
- make config MFEM_USE_MPI=$MPI MFEM_DEBUG=$DEBUG MFEM_CXX="$MYCXX"
MFEM_MPI_NP=$NPROCS CPPFLAGS="$CPPFLAGS"
# Show the configuration
- make info
+8 -73
View File
@@ -23,27 +23,6 @@ Meshing improvements
Hessian for r-adaptivity using discrete fields, and allows use of skewness
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.
- 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
------------------------
- Added support for explicit vectorization in the high-performance templated
code, which can now take advantage of specific intrinsics classes on the
following architectures:
- x86 (SSE/AVX/AVX2/AVX512),
- Power8 & Power9 (VSX),
- BG/Q (QPX).
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.
@@ -56,26 +35,6 @@ Discretization improvements
- Added support for simplices in GSLIB-FindPoints.
- Added support for H1 and L2 element matrix assembly in the mass, convection,
diffusion, transpose, and the face DG trace integrators. This is compatible
with GPU device execution and is illustrated in Example 9/9p, see the option
'-ea'. When enabled, this level of assembly stores independent dense matrices
for the elements, and independent dense matrices for the faces in the DG case.
- Added new partial assembly kernels for H(div) bilinear forms, as well as
VectorFEDivergenceIntegrator.
- Improved the documentation of the GridFunction GetValue and GetVectorValue
methods. Expanded the GetValue and GetVectorValue methods which accept an
ElementTransformation argument to support evaluation on boundary elements
and, in the continuous field case, arbitrary mesh edges and faces.
- Added new coefficient and vector coefficient classes for QuadratureFunctions.
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
@@ -84,17 +43,6 @@ Linear and nonlinear solvers
- Added initial support for h- and p-multigrid solvers and preconditioners for
matrix-based and matrix-free discretizations with basic GPU capability.
- Added a new IterativeSolverMonitor class that allows to monitor the residual
and solution during the solving process of an IterativeSolver after every
iteration.
- Block arrays of parallel matrices can now be merged into a single parallel
matrix with the function HypreParMatrixFromBlocks. This could be useful for
solving block systems with parallel direct solvers such as STRUMPACK.
- In SLISolver, changed the residual inner product from (Br,r) to (Br,Br) so the
solver can work with non-SPD preconditioner B.
New and updated examples and miniapps
-------------------------------------
- Added a new example, Example 25/25p, to demonstrate the use of a Perfectly
@@ -104,10 +52,11 @@ 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 procedure
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
procedures 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
@@ -116,18 +65,6 @@ New and updated examples and miniapps
- Added a new meshing miniapp, Minimal Surface, which solves Plateau's problem:
the Dirichlet problem for the minimal surface equation.
- Added partial assembly support to examples 4/4p and 5/5p, with diagonal
preconditioning.
- 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
@@ -137,17 +74,15 @@ Improved testing
Miscellaneous
-------------
- In SLISolver, changed the residual inner product from (Br,r) to (Br,Br) so the
solver can work with non-SPD preconditioner B.
- Added support for ADIOS2 for parallel I/O with ParaView visualization. The
classes adios2stream and ADIOS2DataCollection are introduced in mfem as the
interfaces to generate ADIOS2 Binary Pack (BP4) directory datasets for the
entire spatial and temporal data. In addition, ADIOS2 allows for setting a
user-defined number of data substreams/subfiles. See examples 5, 9, 12, 16.
- The integration order used in the ComputeLpError and ComputeElementLpError
methods of class GridFunction has been increased.
- Various other simplifications, extensions, and bugfixes in the code.
Version 4.1, released on March 10, 2020
=======================================
+1 -10
View File
@@ -396,12 +396,6 @@ MFEM_USE_SIDRE = YES/NO
blueprint specification. When enabled, this option requires installation of
HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project.
MFEM_USE_SIMD = YES/NO
Enables the high performance templated classes to use architecture dependent
SIMD intrinsics instead of the generic implementation of class AutoSIMD in
linalg/simd/auto.hpp. This option should be combined with suitable
compiler options, such as -march=native, to enable optimal vectorization.
MFEM_USE_CONDUIT = YES/NO
Enables support for converting MFEM Mesh and Grid Function objects to and
from Conduit Mesh Blueprint Descriptions (https://github.com/LLNL/conduit/)
@@ -432,8 +426,6 @@ MFEM_USE_PUMI = YES/NO
data management system that is capable of handling general non-manifold
models and effectively supports automated adaptive analysis. PUMI enables
support for parallel unstructured mesh modifications in MFEM.
The develop branch of PUMI repository (https://github.com/SCOREC/core)
should be used for most updated features.
MFEM_USE_UMPIRE = YES/NO
Enables support for Umpire, a resource management library that allows the
@@ -617,9 +609,8 @@ The specific libraries and their options are:
- PUMI (optional), used when MFEM_USE_PUMI = YES.
URL: https://scorec.rpi.edu/pumi
https://github.com/SCOREC/core
Options: PUMI_OPT, PUMI_LIB.
Versions: PUMI >= 2.2.3.
Versions: PUMI >= 2.2.0.
- HiOp (optional), used when MFEM_USE_HIOP = YES.
URL: https://github.com/LLNL/hiop
-1
View File
@@ -47,7 +47,6 @@ set(MFEM_USE_OCCA @MFEM_USE_OCCA@)
set(MFEM_USE_RAJA @MFEM_USE_RAJA@)
set(MFEM_USE_CEED @MFEM_USE_CEED@)
set(MFEM_USE_UMPIRE @MFEM_USE_UMPIRE@)
set(MFEM_USE_SIMD @MFEM_USE_SIMD@)
set(MFEM_USE_ADIOS2 @MFEM_USE_ADIOS2@)
set(MFEM_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
-3
View File
@@ -107,9 +107,6 @@
// Enable MFEM functionality based on the Sidre library
#cmakedefine MFEM_USE_SIDRE
// Enable the use of SIMD in the high performance templated classes
#cmakedefine MFEM_USE_SIMD
// Enable MFEM functionality based on Conduit
#cmakedefine MFEM_USE_CONDUIT
@@ -733,7 +733,7 @@ function(mfem_export_mk_files)
MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS
MFEM_USE_GSLIB MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_CUDA MFEM_USE_OCCA MFEM_USE_RAJA
MFEM_USE_UMPIRE MFEM_USE_SIMD MFEM_USE_ADIOS2)
MFEM_USE_UMPIRE)
foreach(var ${CONFIG_MK_BOOL_VARS})
if (${var})
set(${var} YES)
@@ -743,7 +743,6 @@ function(mfem_export_mk_files)
endforeach()
# TODO: Add support for MFEM_USE_CUDA=YES
set(MFEM_CXX ${CMAKE_CXX_COMPILER})
set(MFEM_HOST_CXX ${MFEM_CXX})
set(MFEM_CPPFLAGS "")
string(STRIP "${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}"
MFEM_CXXFLAGS)
-3
View File
@@ -106,9 +106,6 @@
// Enable Sidre support
// #define MFEM_USE_SIDRE
// Enable the use of SIMD in the high performance templated classes
// #define MFEM_USE_SIMD
// Enable Conduit support
// #define MFEM_USE_CONDUIT
-2
View File
@@ -49,12 +49,10 @@ MFEM_USE_RAJA = @MFEM_USE_RAJA@
MFEM_USE_OCCA = @MFEM_USE_OCCA@
MFEM_USE_CEED = @MFEM_USE_CEED@
MFEM_USE_UMPIRE = @MFEM_USE_UMPIRE@
MFEM_USE_SIMD = @MFEM_USE_SIMD@
MFEM_USE_ADIOS2 = @MFEM_USE_ADIOS2@
# Compiler, compile options, and link options
MFEM_CXX = @MFEM_CXX@
MFEM_HOST_CXX = @MFEM_HOST_CXX@
MFEM_CPPFLAGS = @MFEM_CPPFLAGS@
MFEM_CXXFLAGS = @MFEM_CXXFLAGS@
MFEM_TPLFLAGS = @MFEM_TPLFLAGS@
-1
View File
@@ -49,7 +49,6 @@ option(MFEM_USE_OCCA "Enable OCCA" OFF)
option(MFEM_USE_RAJA "Enable RAJA" OFF)
option(MFEM_USE_CEED "Enable CEED" OFF)
option(MFEM_USE_UMPIRE "Enable Umpire" OFF)
option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" ON)
option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
-1
View File
@@ -137,7 +137,6 @@ MFEM_USE_RAJA = NO
MFEM_USE_OCCA = NO
MFEM_USE_CEED = NO
MFEM_USE_UMPIRE = NO
MFEM_USE_SIMD = YES
MFEM_USE_ADIOS2 = NO
# Compile and link options for zlib.
+6 -13
View File
@@ -29,20 +29,8 @@
#define MFEM_ALWAYS_INLINE
#endif
// --- MFEM_VECTORIZE_LOOP (disabled)
#if (__cplusplus >= 201103L) && !defined(MFEM_DEBUG) && defined(__GNUC__)
//#define MFEM_VECTORIZE_LOOP _Pragma("GCC ivdep")
#define MFEM_VECTORIZE_LOOP
#else
#define MFEM_VECTORIZE_LOOP
#endif
// MFEM_TEMPLATE_BLOCK_SIZE is the block size used by the template matrix-matrix
// multiply, Mult_AB, defined in tmatrix.hpp. This parameter will generally
// require tuning to determine good value. It is probably highly influenced by
// the SIMD width when Mult_AB is used with a SIMD type like AutoSIMD.
#define MFEM_TEMPLATE_BLOCK_SIZE 4
#define MFEM_SIMD_SIZE 32
#define MFEM_TEMPLATE_ENABLE_SERIALIZE
// #define MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
@@ -50,6 +38,11 @@
// #define MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS
#define MFEM_TEMPLATE_INTRULE_COEFF_PRECOMP
// derived macros
#define MFEM_ROUNDUP(val,base) ((((val)+(base)-1)/(base))*(base))
#define MFEM_ALIGN_SIZE(size,type) \
MFEM_ROUNDUP(size,(MFEM_SIMD_SIZE)/sizeof(type))
#ifdef MFEM_COUNT_FLOPS
namespace mfem
{
-37
View File
@@ -1,37 +0,0 @@
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";
-185
View File
@@ -1,185 +0,0 @@
$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
-25
View File
@@ -1,25 +0,0 @@
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
-155
View File
@@ -1,155 +0,0 @@
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
+29 -14
View File
@@ -16,21 +16,36 @@ 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(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)
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)
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)
+3 -3
View File
@@ -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 = web/logo-small.png
PROJECT_LOGO =
# 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 = warnings.log
WARN_LOGFILE =
#---------------------------------------------------------------------------
# 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 = http://cdn.mathjax.org/mathjax/latest
MATHJAX_RELPATH = https://cdn.llnl.gov/mathjax/2.7.2
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
-1
View File
@@ -149,7 +149,6 @@ 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
+4 -11
View File
@@ -9,25 +9,18 @@
# 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)
@# 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
doxygen $(DOXYGEN_CONF)
rm -f CodeDocumentation.html
ln -s CodeDocumentation/html/index.html CodeDocumentation.html
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.

Before

Width:  |  Height:  |  Size: 12 KiB

+2
View File
@@ -64,6 +64,8 @@ if (MFEM_USE_MPI)
ex25p.cpp
ex26p.cpp
ex27p.cpp
pa_oper.cpp
io_benchmark.cpp
)
endif()
-2
View File
@@ -9,8 +9,6 @@
// 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
-2
View File
@@ -8,8 +8,6 @@
// 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
-34
View File
@@ -35,38 +35,6 @@
using namespace std;
using namespace mfem;
class CustomSolverMonitor : public IterativeSolverMonitor
{
public:
CustomSolverMonitor(const ParMesh *m,
ParGridFunction *f) :
pmesh(m),
pgf(f) {}
void MonitorSolution(int i, double norm, const Vector &x, bool final)
{
char vishost[] = "localhost";
int visport = 19916;
int num_procs, myid;
MPI_Comm_size(pmesh->GetComm(),&num_procs);
MPI_Comm_rank(pmesh->GetComm(),&myid);
pgf->SetFromTrueDofs(x);
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << *pgf
<< "window_title 'Iteration no " << i << "'"
<< "keys rRjlc\n" << flush;
}
private:
const ParMesh *pmesh;
ParGridFunction *pgf;
};
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
@@ -220,7 +188,6 @@ int main(int argc, char *argv[])
}
else
{
CustomSolverMonitor monitor(pmesh, &x);
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetAbsTol(0.0);
gmres.SetRelTol(1e-12);
@@ -229,7 +196,6 @@ int main(int argc, char *argv[])
gmres.SetPrintLevel(1);
gmres.SetOperator(*A);
gmres.SetPreconditioner(*amg);
gmres.SetMonitor(monitor);
gmres.Mult(*B, *X);
}
delete amg;
+3 -3
View File
@@ -418,7 +418,7 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
{
intorder++;
}
const IntegrationRule *ir = &IntRules.Get(Tr.GetGeometryType(), intorder);
const IntegrationRule *ir = &IntRules.Get(Tr.FaceGeom, intorder);
for (int i = 0; i < ir->GetNPoints(); i++)
{
@@ -435,10 +435,10 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
elfun1_mat.MultTranspose(shape1, funval1);
elfun2_mat.MultTranspose(shape2, funval2);
Tr.SetIntPoint(&ip);
Tr.Face->SetIntPoint(&ip);
// Get the normal vector and the flux on the face
CalcOrtho(Tr.Jacobian(), nor);
CalcOrtho(Tr.Face->Jacobian(), nor);
const double mcs = rsolver.Eval(funval1, funval2, nor, fluxN);
// Update max char speed
+3 -44
View File
@@ -38,42 +38,6 @@
using namespace std;
using namespace mfem;
class GeneralResidualMonitor : public IterativeSolverMonitor
{
public:
GeneralResidualMonitor(const std::string& prefix_, int print_lvl)
: prefix(prefix_)
{
print_level = print_lvl;
}
virtual void MonitorResidual(int it, double norm, const Vector &r, bool final);
private:
const std::string prefix;
int print_level;
mutable double norm0;
};
void GeneralResidualMonitor::MonitorResidual(int it, double norm,
const Vector &r, bool final)
{
if (print_level == 1 || (print_level == 3 && (final || it == 0)))
{
mfem::out << prefix << " iteration " << setw(2) << it
<< " : ||r|| = " << norm;
if (it > 0)
{
mfem::out << ", ||r||/||r_0|| = " << norm/norm0;
}
else
{
norm0 = norm;
}
mfem::out << '\n';
}
}
// Custom block preconditioner for the Jacobian of the incompressible nonlinear
// elasticity operator. It has the form
//
@@ -139,11 +103,9 @@ protected:
// Newton solver for the hyperelastic operator
NewtonSolver newton_solver;
GeneralResidualMonitor newton_monitor;
// Solver for the Jacobian solve in the Newton method
Solver *j_solver;
GeneralResidualMonitor j_monitor;
// Preconditioner for the Jacobian
Solver *j_prec;
@@ -448,8 +410,7 @@ RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
int iter,
Coefficient &c_mu)
: Operator(fes[0]->GetVSize() + fes[1]->GetVSize()),
newton_solver(), newton_monitor("Newton", 1),
j_monitor(" GMRES", 3), mu(c_mu), block_offsets(offsets)
newton_solver(), mu(c_mu), block_offsets(offsets)
{
Array<Vector *> rhs(2);
rhs = NULL; // Set all entries in the array
@@ -485,8 +446,7 @@ RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
j_gmres->SetRelTol(1e-12);
j_gmres->SetAbsTol(1e-12);
j_gmres->SetMaxIter(300);
j_gmres->SetPrintLevel(-1);
j_gmres->SetMonitor(j_monitor);
j_gmres->SetPrintLevel(0);
j_gmres->SetPreconditioner(*j_prec);
j_solver = j_gmres;
@@ -494,8 +454,7 @@ RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
newton_solver.iterative_mode = true;
newton_solver.SetSolver(*j_solver);
newton_solver.SetOperator(*this);
newton_solver.SetPrintLevel(-1);
newton_solver.SetMonitor(newton_monitor);
newton_solver.SetPrintLevel(1);
newton_solver.SetRelTol(rel_tol);
newton_solver.SetAbsTol(abs_tol);
newton_solver.SetMaxIter(iter);
+3 -60
View File
@@ -38,56 +38,6 @@
using namespace std;
using namespace mfem;
class GeneralResidualMonitor : public IterativeSolverMonitor
{
public:
GeneralResidualMonitor(MPI_Comm comm, const std::string& prefix_,
int print_lvl)
: prefix(prefix_)
{
#ifndef MFEM_USE_MPI
print_level = print_lvl;
#else
int rank;
MPI_Comm_rank(comm, &rank);
if (rank == 0)
{
print_level = print_lvl;
}
else
{
print_level = -1;
}
#endif
}
virtual void MonitorResidual(int it, double norm, const Vector &r, bool final);
private:
const std::string prefix;
int print_level;
mutable double norm0;
};
void GeneralResidualMonitor::MonitorResidual(int it, double norm,
const Vector &r, bool final)
{
if (print_level == 1 || (print_level == 3 && (final || it == 0)))
{
mfem::out << prefix << " iteration " << setw(2) << it
<< " : ||r|| = " << norm;
if (it > 0)
{
mfem::out << ", ||r||/||r_0|| = " << norm/norm0;
}
else
{
norm0 = norm;
}
mfem::out << '\n';
}
}
// Custom block preconditioner for the Jacobian of the incompressible nonlinear
// elasticity operator. It has the form
//
@@ -153,11 +103,9 @@ protected:
// Newton solver for the hyperelastic operator
NewtonSolver newton_solver;
GeneralResidualMonitor newton_monitor;
// Solver for the Jacobian solve in the Newton method
Solver *j_solver;
GeneralResidualMonitor j_monitor;
// Preconditioner for the Jacobian
Solver *j_prec;
@@ -511,10 +459,7 @@ RubberOperator::RubberOperator(Array<ParFiniteElementSpace *> &fes,
int iter,
Coefficient &c_mu)
: Operator(fes[0]->TrueVSize() + fes[1]->TrueVSize()),
newton_solver(fes[0]->GetComm()),
newton_monitor(fes[0]->GetComm(), "Newton", 1),
j_monitor(fes[0]->GetComm(), " GMRES", 3),
mu(c_mu), block_trueOffsets(trueOffsets)
newton_solver(fes[0]->GetComm()), mu(c_mu), block_trueOffsets(trueOffsets)
{
Array<Vector *> rhs(2);
rhs = NULL; // Set all entries in the array
@@ -554,8 +499,7 @@ RubberOperator::RubberOperator(Array<ParFiniteElementSpace *> &fes,
j_gmres->SetRelTol(1e-12);
j_gmres->SetAbsTol(1e-12);
j_gmres->SetMaxIter(300);
j_gmres->SetPrintLevel(-1);
j_gmres->SetMonitor(j_monitor);
j_gmres->SetPrintLevel(0);
j_gmres->SetPreconditioner(*j_prec);
j_solver = j_gmres;
@@ -563,8 +507,7 @@ RubberOperator::RubberOperator(Array<ParFiniteElementSpace *> &fes,
newton_solver.iterative_mode = true;
newton_solver.SetSolver(*j_solver);
newton_solver.SetOperator(*this);
newton_solver.SetPrintLevel(-1);
newton_solver.SetMonitor(newton_monitor);
newton_solver.SetPrintLevel(1);
newton_solver.SetRelTol(rel_tol);
newton_solver.SetAbsTol(abs_tol);
newton_solver.SetMaxIter(iter);
+41 -9
View File
@@ -9,8 +9,6 @@
// 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
@@ -72,6 +70,7 @@ int main(int argc, char *argv[])
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
int nfiles = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -88,6 +87,7 @@ int main(int argc, char *argv[])
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&nfiles, "-nf", "--num-files", "Number of files to write.");
args.Parse();
if (!args.Good())
{
@@ -160,7 +160,7 @@ int main(int argc, char *argv[])
{
fec = new H1_FECollection(order = 1, dim);
}
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec, 1, 0);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
@@ -239,20 +239,52 @@ int main(int argc, char *argv[])
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
std::string filename("nranks_");
filename += to_string(num_procs);
filename += ".gf";
{
double t1;
t1 = MPI_Wtime();
x.Save(filename.c_str(), nfiles);
double t2 = MPI_Wtime();
if (myid == 0)
{
err << "elapsed write time: " << t2 - t1 << endl;
}
}
{
double t1;
t1 = MPI_Wtime();
ParGridFunction new_x(fespace, filename.c_str());
double t2 = MPI_Wtime();
if (myid == 0)
{
err << "elapsed read time: " << t2 - t1 << endl;
}
// new_x -= x;
// out << "GF difference: " << new_x.Norml1() << endl;
}
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
//mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << num_procs << setfill('0') << setw(6) << myid;
//ofstream mesh_ofs(mesh_name.str().c_str());
//mesh_ofs.precision(8);
//pmesh->Print(mesh_ofs);
double t1 = MPI_Wtime();
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
double t2 = MPI_Wtime();
if (myid == 0)
{
err << t2 - t1 << endl;
}
}
// 16. Send the solution by socket to a GLVis server.
+77 -164
View File
@@ -6,7 +6,6 @@
// ex24 -m ../data/square-disc.mesh -o 2
// ex24 -m ../data/beam-tet.mesh
// ex24 -m ../data/beam-hex.mesh -o 2 -pa
// ex24 -m ../data/beam-hex.mesh -o 2 -pa -p 1
// ex24 -m ../data/escher.mesh
// ex24 -m ../data/escher.mesh -o 2
// ex24 -m ../data/fichera.mesh
@@ -24,15 +23,11 @@
// ex24 -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code illustrates usage of mixed finite element
// spaces, with two variants:
// spaces. Using two different approaches, we project a gradient
// of a function in H^1 to H(curl). Other spaces and example
// computations are to be added in the future.
//
// 1) (grad p, u) for p in H^1 tested against u in H(curl)
// 2) (div v, q) for v in H(div) tested against q in L_2
//
// Using different approaches, we project the gradient or
// divergence to the appropriate space.
//
// We recommend viewing examples 1, 3, and 5 before viewing this
// We recommend viewing examples 1 and 3 before viewing this
// example.
#include "mfem.hpp"
@@ -44,7 +39,6 @@ using namespace mfem;
double p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
double div_gradp_exact(const Vector &x);
int dim;
@@ -53,7 +47,6 @@ int main(int argc, char *argv[])
// 1. Parse command-line options.
const char *mesh_file = "../data/beam-hex.mesh";
int order = 1;
int prob = 0;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
@@ -64,8 +57,6 @@ int main(int argc, char *argv[])
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: H(Curl) or 1: H(Div)");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
@@ -109,107 +100,72 @@ int main(int argc, char *argv[])
}
mesh->ReorientTetMesh();
// 5. Define a finite element space on the mesh. Here we use Nedelec or
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *trial_fec = NULL;
FiniteElementCollection *test_fec = NULL;
// 5. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
FiniteElementCollection *H1fec = new H1_FECollection(order, dim);
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
FiniteElementSpace *H1fespace = new FiniteElementSpace(mesh, H1fec);
if (prob == 0)
{
trial_fec = new H1_FECollection(order, dim);
test_fec = new ND_FECollection(order, dim);
}
else
{
trial_fec = new RT_FECollection(order - 1, dim);
test_fec = new L2_FECollection(order - 1, dim);
}
int size = fespace->GetTrueVSize();
int H1size = H1fespace->GetTrueVSize();
cout << "Number of Nedelec finite element unknowns: " << size << endl;
cout << "Number of H1 finite element unknowns: " << H1size << endl;
FiniteElementSpace trial_fes(mesh, trial_fec);
FiniteElementSpace test_fes(mesh, test_fec);
int trial_size = trial_fes.GetTrueVSize();
int test_size = test_fes.GetTrueVSize();
if (prob == 0)
{
cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
cout << "Number of H1 finite element unknowns: " << trial_size << endl;
}
else
{
cout << "Number of Raviart-Thomas finite element unknowns: "
<< trial_size << endl;
cout << "Number of L2 finite element unknowns: " << test_size << endl;
}
// 6. Define the solution vector as a finite element grid function
// corresponding to the trial fespace.
GridFunction gftest(&test_fes);
GridFunction gftrial(&trial_fes);
GridFunction x(&test_fes);
// 6. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
GridFunction x(fespace);
FunctionCoefficient p_coef(p_exact);
GridFunction p(H1fespace);
p.ProjectCoefficient(p_coef);
p.SetTrueVector();
p.SetFromTrueVector();
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
FunctionCoefficient divgradp_coef(div_gradp_exact);
if (prob == 0)
{
gftrial.ProjectCoefficient(p_coef);
}
else
{
gftrial.ProjectCoefficient(gradp_coef);
}
gftrial.SetTrueVector();
gftrial.SetFromTrueVector();
// 7. Set up the bilinear forms for L2 projection.
ConstantCoefficient one(1.0);
BilinearForm a(&test_fes);
MixedBilinearForm a_mixed(&trial_fes, &test_fes);
// 7. Set up the bilinear forms.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
BilinearForm *a = new BilinearForm(fespace);
MixedBilinearForm *a_NDH1 = new MixedBilinearForm(H1fespace, fespace);
if (pa)
{
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_mixed.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a->SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_NDH1->SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
if (prob == 0)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorGradientIntegrator(one));
}
else
{
a.AddDomainIntegrator(new MassIntegrator(one));
a_mixed.AddDomainIntegrator(new VectorFEDivergenceIntegrator(one));
}
// First approach: L2 projection
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
a_NDH1->AddDomainIntegrator(new MixedVectorGradientIntegrator(*muinv));
// 8. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a.EnableStaticCondensation(); }
// 8. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a.Assemble();
if (!pa) { a.Finalize(); }
a->Assemble();
if (!pa) { a->Finalize(); }
a_mixed.Assemble();
if (!pa) { a_mixed.Finalize(); }
a_NDH1->Assemble();
if (!pa) { a_NDH1->Finalize(); }
if (pa)
{
a_mixed.Mult(gftrial, x);
a_NDH1->Mult(p, x);
}
else
{
SparseMatrix& mixed = a_mixed.SpMat();
mixed.Mult(gftrial, x);
SparseMatrix& NDH1 = a_NDH1->SpMat();
NDH1.Mult(p, x);
}
// 9. Define and apply a PCG solver for Ax = b with Jacobi preconditioner.
{
GridFunction rhs(&test_fes);
GridFunction rhs(fespace);
rhs = x;
x = 0.0;
@@ -220,15 +176,15 @@ int main(int argc, char *argv[])
if (pa)
{
Array<int> ess_tdof_list; // empty
OperatorJacobiSmoother Jacobi(a, ess_tdof_list);
OperatorJacobiSmoother Jacobi(*a, ess_tdof_list);
cg.SetOperator(a);
cg.SetOperator(*a);
cg.SetPreconditioner(Jacobi);
cg.Mult(rhs, x);
}
else
{
SparseMatrix& Amat = a.SpMat();
SparseMatrix& Amat = a->SpMat();
DSmoother Jacobi(Amat);
cg.SetOperator(Amat);
@@ -237,68 +193,33 @@ int main(int argc, char *argv[])
}
}
// 10. Compute the same field by applying a DiscreteInterpolator.
GridFunction discreteInterpolant(&test_fes);
DiscreteLinearOperator dlo(&trial_fes, &test_fes);
if (prob == 0)
{
dlo.AddDomainInterpolator(new GradientInterpolator());
}
else
{
dlo.AddDomainInterpolator(new DivergenceInterpolator());
}
// 10. Second approach: compute the same solution by applying
// GradientInterpolator in H(curl).
DiscreteLinearOperator grad(H1fespace, fespace);
grad.AddDomainInterpolator(new GradientInterpolator());
grad.Assemble();
dlo.Assemble();
dlo.Mult(gftrial, discreteInterpolant);
GridFunction gradp(fespace);
grad.Mult(p, gradp);
// 11. Compute the projection of the exact field.
GridFunction exact_proj(&test_fes);
if (prob == 0)
{
exact_proj.ProjectCoefficient(gradp_coef);
}
else
{
exact_proj.ProjectCoefficient(divgradp_coef);
}
// 11. Compute the projection of the exact grad p.
GridFunction exact_gradp(fespace);
exact_gradp.ProjectCoefficient(gradp_coef);
exact_gradp.SetTrueVector();
exact_gradp.SetFromTrueVector();
exact_proj.SetTrueVector();
exact_proj.SetFromTrueVector();
// 12. Compute and print the L_2 norm of the error.
if (prob == 0)
// 12. Compute and print the L^2 norm of the error.
{
double errSol = x.ComputeL2Error(gradp_coef);
double errInterp = discreteInterpolant.ComputeL2Error(gradp_coef);
double errProj = exact_proj.ComputeL2Error(gradp_coef);
double errInterp = gradp.ComputeL2Error(gradp_coef);
double errProj = exact_gradp.ComputeL2Error(gradp_coef);
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in H(curl): "
"|| E_h - grad p ||_{L_2} = " << errSol << '\n' << endl;
"|| E_h - grad p ||_{L^2} = " << errSol << '\n' << endl;
cout << " Gradient interpolant E_h = grad p_h in H(curl): || E_h - grad p"
"||_{L_2} = " << errInterp << '\n' << endl;
"||_{L^2} = " << errInterp << '\n' << endl;
cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
"||_{L_2} = " << errProj << '\n' << endl;
}
else
{
int order_quad = max(2, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
double errSol = x.ComputeL2Error(divgradp_coef, irs);
double errInterp = discreteInterpolant.ComputeL2Error(divgradp_coef, irs);
double errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
cout << "\n Solution of (f_h,q) = (div v_h,q) for f_h and q in L_2: "
"|| f_h - div v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Divergence interpolant f_h = div v_h in L_2: || f_h - div v"
"||_{L_2} = " << errInterp << '\n' << endl;
cout << " Projection f_h of exact div v in L_2: || f_h - div v "
"||_{L_2} = " << errProj << '\n' << endl;
"||_{L^2} = " << errProj << '\n' << endl;
}
// 13. Save the refined mesh and the solution. This output can be viewed
@@ -321,8 +242,14 @@ int main(int argc, char *argv[])
}
// 15. Free the used memory.
delete trial_fec;
delete test_fec;
delete a;
delete a_NDH1;
delete sigma;
delete muinv;
delete fespace;
delete H1fespace;
delete fec;
delete H1fec;
delete mesh;
return 0;
@@ -357,17 +284,3 @@ void gradp_exact(const Vector &x, Vector &f)
if (x.Size() == 3) { f(2) = 0.0; }
}
}
double div_gradp_exact(const Vector &x)
{
if (dim == 3)
{
return -3.0 * sin(x(0)) * sin(x(1)) * sin(x(2));
}
else if (dim == 2)
{
return -2.0 * sin(x(0)) * sin(x(1));
}
return 0.0;
}
+81 -171
View File
@@ -6,7 +6,6 @@
// mpirun -np 4 ex24p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex24p -m ../data/beam-tet.mesh
// mpirun -np 4 ex24p -m ../data/beam-hex.mesh -o 2 -pa
// mpirun -np 4 ex24p -m ../data/beam-hex.mesh -o 2 -p 1 -pa
// mpirun -np 4 ex24p -m ../data/escher.mesh
// mpirun -np 4 ex24p -m ../data/escher.mesh -o 2
// mpirun -np 4 ex24p -m ../data/fichera.mesh
@@ -24,15 +23,11 @@
// mpirun -np 4 ex24p -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code illustrates usage of mixed finite element
// spaces, with two variants:
// spaces. Using two different approaches, we project a gradient
// of a function in H^1 to H(curl). Other spaces and example
// computations are to be added in the future.
//
// 1) (grad p, u) for p in H^1 tested against u in H(curl)
// 2) (div v, q) for v in H(div) tested against q in L_2
//
// Using different approaches, we project the gradient or
// divergence to the appropriate space.
//
// We recommend viewing examples 1, 3, and 5 before viewing this
// We recommend viewing examples 1 and 3 before viewing this
// example.
#include "mfem.hpp"
@@ -44,7 +39,6 @@ using namespace mfem;
double p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
double div_gradp_exact(const Vector &x);
int dim;
@@ -59,7 +53,6 @@ int main(int argc, char *argv[])
// 2. Parse command-line options.
const char *mesh_file = "../data/beam-hex.mesh";
int order = 1;
int prob = 0;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
@@ -70,8 +63,6 @@ int main(int argc, char *argv[])
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: H(Curl) or 1: H(Div)");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
@@ -138,115 +129,80 @@ int main(int argc, char *argv[])
pmesh->ReorientTetMesh();
// 7. Define a parallel finite element space on the parallel mesh. Here we
// use Nedelec or Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *trial_fec = NULL;
FiniteElementCollection *test_fec = NULL;
if (prob == 0)
{
trial_fec = new H1_FECollection(order, dim);
test_fec = new ND_FECollection(order, dim);
}
else
{
trial_fec = new RT_FECollection(order - 1, dim);
test_fec = new L2_FECollection(order - 1, dim);
}
ParFiniteElementSpace trial_fes(pmesh, trial_fec);
ParFiniteElementSpace test_fes(pmesh, test_fec);
HYPRE_Int trial_size = trial_fes.GlobalTrueVSize();
HYPRE_Int test_size = test_fes.GlobalTrueVSize();
// use the Nedelec finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
FiniteElementCollection *H1fec = new H1_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
ParFiniteElementSpace *H1fespace = new ParFiniteElementSpace(pmesh, H1fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
HYPRE_Int H1size = H1fespace->GlobalTrueVSize();
if (myid == 0)
{
if (prob == 0)
{
cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
cout << "Number of H1 finite element unknowns: " << trial_size << endl;
}
else
{
cout << "Number of Raviart-Thomas finite element unknowns: "
<< trial_size << endl;
cout << "Number of L2 finite element unknowns: " << test_size << endl;
}
cout << "Number of Nedelec finite element unknowns: " << size << endl;
cout << "Number of H1 finite element unknowns: " << H1size << endl;
}
// 8. Define the solution vector as a parallel finite element grid function
// corresponding to the trial fespace.
ParGridFunction gftest(&test_fes);
ParGridFunction gftrial(&trial_fes);
ParGridFunction x(&test_fes);
// 8. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
FunctionCoefficient p_coef(p_exact);
ParGridFunction p(H1fespace);
p.ProjectCoefficient(p_coef);
p.SetTrueVector();
p.SetFromTrueVector();
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
FunctionCoefficient divgradp_coef(div_gradp_exact);
if (prob == 0)
{
gftrial.ProjectCoefficient(p_coef);
}
else
{
gftrial.ProjectCoefficient(gradp_coef);
}
gftrial.SetTrueVector();
gftrial.SetFromTrueVector();
// 9. Set up the parallel bilinear forms for L2 projection.
ConstantCoefficient one(1.0);
ParBilinearForm a(&test_fes);
ParMixedBilinearForm a_mixed(&trial_fes, &test_fes);
// 9. Set up the parallel bilinear forms.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
ParMixedBilinearForm *a_NDH1 = new ParMixedBilinearForm(H1fespace, fespace);
if (pa)
{
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_mixed.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a->SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_NDH1->SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
if (prob == 0)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorGradientIntegrator(one));
}
else
{
a.AddDomainIntegrator(new MassIntegrator(one));
a_mixed.AddDomainIntegrator(new VectorFEDivergenceIntegrator(one));
}
// First approach: L2 projection
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
a_NDH1->AddDomainIntegrator(new MixedVectorGradientIntegrator(*muinv));
// 10. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a.EnableStaticCondensation(); }
if (static_cond) { a->EnableStaticCondensation(); }
a.Assemble();
if (!pa) { a.Finalize(); }
a->Assemble();
if (!pa) { a->Finalize(); }
a_mixed.Assemble();
if (!pa) { a_mixed.Finalize(); }
a_NDH1->Assemble();
if (!pa) { a_NDH1->Finalize(); }
Vector B(test_fes.GetTrueVSize());
Vector X(test_fes.GetTrueVSize());
Vector B(fespace->GetTrueVSize());
Vector X(fespace->GetTrueVSize());
if (pa)
{
ParLinearForm b(&test_fes); // used as a vector
a_mixed.Mult(gftrial, b); // process-local multiplication
b.ParallelAssemble(B);
ParLinearForm *b = new ParLinearForm(fespace); // used as a vector
a_NDH1->Mult(p, *b); // process-local multiplication
b->ParallelAssemble(B);
delete b;
}
else
{
HypreParMatrix *mixed = a_mixed.ParallelAssemble();
HypreParMatrix *NDH1 = a_NDH1->ParallelAssemble();
Vector P(trial_fes.GetTrueVSize());
gftrial.GetTrueDofs(P);
Vector P(H1fespace->GetTrueVSize());
p.GetTrueDofs(P);
mixed->Mult(P,B);
NDH1->Mult(P,B);
delete mixed;
delete NDH1;
}
// 11. Define and apply a parallel PCG solver for AX=B with Jacobi
@@ -256,9 +212,9 @@ int main(int argc, char *argv[])
Array<int> ess_tdof_list; // empty
OperatorPtr A;
a.FormSystemMatrix(ess_tdof_list, A);
a->FormSystemMatrix(ess_tdof_list, A);
OperatorJacobiSmoother Jacobi(a, ess_tdof_list);
OperatorJacobiSmoother Jacobi(*a, ess_tdof_list);
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
@@ -271,7 +227,7 @@ int main(int argc, char *argv[])
}
else
{
HypreParMatrix *Amat = a.ParallelAssemble();
HypreParMatrix *Amat = a->ParallelAssemble();
HypreDiagScale Jacobi(*Amat);
HyprePCG pcg(*Amat);
pcg.SetTol(1e-12);
@@ -286,73 +242,35 @@ int main(int argc, char *argv[])
x.SetFromTrueDofs(X);
// 12. Compute the same field by applying a DiscreteInterpolator.
ParGridFunction discreteInterpolant(&test_fes);
ParDiscreteLinearOperator dlo(&trial_fes, &test_fes);
if (prob == 0)
{
dlo.AddDomainInterpolator(new GradientInterpolator());
}
else
{
dlo.AddDomainInterpolator(new DivergenceInterpolator());
}
// 12. Second approach: compute the same solution by applying
// GradientInterpolator in H(curl).
ParDiscreteLinearOperator grad(H1fespace, fespace);
grad.AddDomainInterpolator(new GradientInterpolator());
grad.Assemble();
dlo.Assemble();
dlo.Mult(gftrial, discreteInterpolant);
ParGridFunction gradp(fespace);
grad.Mult(p, gradp);
// 13. Compute the projection of the exact field.
ParGridFunction exact_proj(&test_fes);
if (prob == 0)
{
exact_proj.ProjectCoefficient(gradp_coef);
}
else
{
exact_proj.ProjectCoefficient(divgradp_coef);
}
// 13. Compute the projection of the exact grad p.
ParGridFunction exact_gradp(fespace);
exact_gradp.ProjectCoefficient(gradp_coef);
exact_gradp.SetTrueVector();
exact_gradp.SetFromTrueVector();
exact_proj.SetTrueVector();
exact_proj.SetFromTrueVector();
// 14. Compute and print the L_2 norm of the error.
if (prob == 0)
// 14. Compute and print the L^2 norm of the error.
{
double errSol = x.ComputeL2Error(gradp_coef);
double errInterp = discreteInterpolant.ComputeL2Error(gradp_coef);
double errProj = exact_proj.ComputeL2Error(gradp_coef);
double errInterp = gradp.ComputeL2Error(gradp_coef);
double errProj = exact_gradp.ComputeL2Error(gradp_coef);
if (myid == 0)
{
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in H(curl): "
"|| E_h - grad p ||_{L_2} = " << errSol << '\n' << endl;
cout << " Gradient interpolant E_h = grad p_h in H(curl): || E_h - grad p"
"||_{L_2} = " << errInterp << '\n' << endl;
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in "
"H(curl): || E_h - grad p ||_{L^2} = " << errSol << '\n' << endl;
cout << " Gradient interpolant E_h = grad p_h in H(curl): || E_h - "
"grad p ||_{L^2} = " << errInterp << '\n' << endl;
cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
"||_{L_2} = " << errProj << '\n' << endl;
}
}
else
{
int order_quad = max(2, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
double errSol = x.ComputeL2Error(divgradp_coef, irs);
double errInterp = discreteInterpolant.ComputeL2Error(divgradp_coef, irs);
double errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
if (myid == 0)
{
cout << "\n Solution of (f_h,q) = (div v_h,q) for f_h and q in L_2: "
"|| f_h - div v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Divergence interpolant f_h = div v_h in L_2: || f_h - div v"
"||_{L_2} = " << errInterp << '\n' << endl;
cout << " Projection f_h of exact div v in L_2: || f_h - div v "
"||_{L_2} = " << errProj << '\n' << endl;
"||_{L^2} = " << errProj << '\n' << endl;
}
}
@@ -384,8 +302,14 @@ int main(int argc, char *argv[])
}
// 17. Free the used memory.
delete trial_fec;
delete test_fec;
delete a;
delete a_NDH1;
delete sigma;
delete muinv;
delete fespace;
delete H1fespace;
delete fec;
delete H1fec;
delete pmesh;
MPI_Finalize();
@@ -422,17 +346,3 @@ void gradp_exact(const Vector &x, Vector &f)
if (x.Size() == 3) { f(2) = 0.0; }
}
}
double div_gradp_exact(const Vector &x)
{
if (dim == 3)
{
return -3.0 * sin(x(0)) * sin(x(1)) * sin(x(2));
}
else if (dim == 2)
{
return -2.0 * sin(x(0)) * sin(x(1));
}
return 0.0;
}
+7
View File
@@ -274,6 +274,13 @@ int main(int argc, char *argv[])
pmesh->SetNodalFESpace(fespace);
}
{
x.Save("ex2p.gf", 1);
ParGridFunction new_x(fespace, "ex2p.gf");
new_x -= x;
out << "GF difference: " << new_x.Norml1() << endl;
}
// 16. Save in parallel the displaced mesh and the inverted solution (which
// gives the backward displacements to the original grid). This output
// can be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
+26 -60
View File
@@ -6,7 +6,6 @@
// ex4 -m ../data/star.mesh
// ex4 -m ../data/beam-tet.mesh
// ex4 -m ../data/beam-hex.mesh
// ex4 -m ../data/beam-hex.mesh -o 2 -pa
// ex4 -m ../data/escher.mesh
// ex4 -m ../data/fichera.mesh -o 2 -hb
// ex4 -m ../data/fichera-q2.vtk
@@ -21,12 +20,6 @@
// ex4 -m ../data/fichera-amr.mesh -o 2 -sc
// ex4 -m ../data/star-surf.mesh -o 1
//
// Device sample runs:
// ex4 -m ../data/star.mesh -pa -d cuda
// ex4 -m ../data/star.mesh -pa -d raja-cuda
// ex4 -m ../data/star.mesh -pa -d raja-omp
// ex4 -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code solves a simple 2D/3D H(div) diffusion
// problem corresponding to the second order definite equation
// -grad(alpha div F) + beta F = f with boundary condition F dot n
@@ -62,8 +55,6 @@ int main(int argc, char *argv[])
bool set_bc = true;
bool static_cond = false;
bool hybridization = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -79,10 +70,6 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
"--no-hybridization", "Enable hybridization.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -95,19 +82,14 @@ int main(int argc, char *argv[])
args.PrintOptions(cout);
kappa = freq * M_PI;
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume, as well as
// periodic meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the mesh to increase the resolution. In this example we do
// 3. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 25,000
// elements.
@@ -120,14 +102,14 @@ int main(int argc, char *argv[])
}
}
// 5. Define a finite element space on the mesh. Here we use the
// 4. Define a finite element space on the mesh. Here we use the
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *fec = new RT_FECollection(order-1, dim);
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
cout << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
@@ -139,7 +121,7 @@ int main(int argc, char *argv[])
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 7. Set up the linear form b(.) which corresponds to the right-hand side
// 6. Set up the linear form b(.) which corresponds to the right-hand side
// of the FEM linear system, which in this case is (f,phi_i) where f is
// given by the function f_exact and phi_i are the basis functions in the
// finite element fespace.
@@ -148,7 +130,7 @@ int main(int argc, char *argv[])
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 8. Define the solution vector x as a finite element grid function
// 7. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary faces will be used
// when eliminating the non-homogeneous boundary condition to modify the
@@ -157,17 +139,16 @@ int main(int argc, char *argv[])
VectorFunctionCoefficient F(sdim, F_exact);
x.ProjectCoefficient(F);
// 9. Set up the bilinear form corresponding to the H(div) diffusion operator
// 8. Set up the bilinear form corresponding to the H(div) diffusion operator
// grad alpha div + beta I, by adding the div-div and the mass domain
// integrators.
Coefficient *alpha = new ConstantCoefficient(1.0);
Coefficient *beta = new ConstantCoefficient(1.0);
BilinearForm *a = new BilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
// 10. Assemble the bilinear form and the corresponding linear system,
// 9. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, hybridization, etc.
@@ -186,47 +167,32 @@ int main(int argc, char *argv[])
}
a->Assemble();
OperatorPtr A;
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A->Height() << endl;
cout << "Size of linear system: " << A.Height() << endl;
// 11. Solve the linear system A X = B.
if (!pa)
{
#ifndef MFEM_USE_SUITESPARSE
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 1, 10000, 1e-20, 0.0);
// 10. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
PCG(A, M, B, X, 1, 10000, 1e-20, 0.0);
#else
// If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(*A);
umf_solver.Mult(B, X);
// 10. If compiled with SuiteSparse support, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
#endif
}
else // Jacobi preconditioning in partial assembly mode
{
if (UsesTensorBasis(*fespace))
{
OperatorJacobiSmoother M(*a, ess_tdof_list);
PCG(*A, M, B, X, 1, 10000, 1e-20, 0.0);
}
else
{
CG(*A, B, X, 1, 10000, 1e-20, 0.0);
}
}
// 12. Recover the solution as a finite element grid function.
// 11. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 13. Compute and print the L^2 norm of the error.
// 12. Compute and print the L^2 norm of the error.
cout << "\n|| F_h - F ||_{L^2} = " << x.ComputeL2Error(F) << '\n' << endl;
// 14. Save the refined mesh and the solution. This output can be viewed
// 13. Save the refined mesh and the solution. This output can be viewed
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
{
ofstream mesh_ofs("refined.mesh");
@@ -237,7 +203,7 @@ int main(int argc, char *argv[])
x.Save(sol_ofs);
}
// 15. Send the solution by socket to a GLVis server.
// 14. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
@@ -247,7 +213,7 @@ int main(int argc, char *argv[])
sol_sock << "solution\n" << *mesh << x << flush;
}
// 16. Free the used memory.
// 15. Free the used memory.
delete hfes;
delete hfec;
delete a;
@@ -269,7 +235,7 @@ void F_exact(const Vector &p, Vector &F)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if F is changed to depend on z
// double z = (dim == 3) ? p(2) : 0.0;
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
@@ -286,7 +252,7 @@ void f_exact(const Vector &p, Vector &f)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if f is changed to depend on z
// double z = (dim == 3) ? p(2) : 0.0;
double temp = 1 + 2*kappa*kappa;
+29 -50
View File
@@ -6,7 +6,6 @@
// mpirun -np 4 ex4p -m ../data/star.mesh
// mpirun -np 4 ex4p -m ../data/beam-tet.mesh
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh -o 2 -pa
// mpirun -np 4 ex4p -m ../data/escher.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/fichera.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/fichera-q2.vtk
@@ -20,12 +19,6 @@
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
//
// Device sample runs:
// mpirun -np 4 ex4p -m ../data/star.mesh -pa -d cuda
// mpirun -np 4 ex4p -m ../data/star.mesh -pa -d raja-cuda
// mpirun -np 4 ex4p -m ../data/star.mesh -pa -d raja-omp
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code solves a simple 2D/3D H(div) diffusion
// problem corresponding to the second order definite equation
// -grad(alpha div F) + beta F = f with boundary condition F dot n
@@ -67,8 +60,6 @@ int main(int argc, char *argv[])
bool set_bc = true;
bool static_cond = false;
bool hybridization = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -84,10 +75,6 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
"--no-hybridization", "Enable hybridization.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -107,19 +94,14 @@ int main(int argc, char *argv[])
}
kappa = freq * M_PI;
// 3. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume, as well as periodic meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 5. Refine the serial mesh on all processors to increase the resolution. In
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
@@ -132,7 +114,7 @@ int main(int argc, char *argv[])
}
}
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
@@ -148,7 +130,7 @@ int main(int argc, char *argv[])
}
pmesh->ReorientTetMesh();
// 7. Define a parallel finite element space on the parallel mesh. Here we
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *fec = new RT_FECollection(order-1, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
@@ -158,7 +140,7 @@ int main(int argc, char *argv[])
cout << "Number of finite element unknowns: " << size << endl;
}
// 8. Determine the list of true (i.e. parallel conforming) essential
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
@@ -170,7 +152,7 @@ int main(int argc, char *argv[])
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 9. Set up the parallel linear form b(.) which corresponds to the
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
@@ -179,7 +161,7 @@ int main(int argc, char *argv[])
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 10. Define the solution vector x as a parallel finite element grid function
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary faces will be used
// when eliminating the non-homogeneous boundary condition to modify the
@@ -188,17 +170,16 @@ int main(int argc, char *argv[])
VectorFunctionCoefficient F(sdim, F_exact);
x.ProjectCoefficient(F);
// 11. Set up the parallel bilinear form corresponding to the H(div)
// 10. Set up the parallel bilinear form corresponding to the H(div)
// diffusion operator grad alpha div + beta I, by adding the div-div and
// the mass domain integrators.
Coefficient *alpha = new ConstantCoefficient(1.0);
Coefficient *beta = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
// 12. Assemble the parallel bilinear form and the corresponding linear
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation,
@@ -218,43 +199,41 @@ int main(int argc, char *argv[])
}
a->Assemble();
OperatorPtr A;
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0 && !pa)
HYPRE_Int glob_size = A.GetGlobalNumRows();
if (myid == 0)
{
cout << "Size of linear system: "
<< A.As<HypreParMatrix>()->GetGlobalNumRows() << endl;
cout << "Size of linear system: " << glob_size << endl;
}
// 13. Define and apply a parallel PCG solver for A X = B with the 2D AMS or
// 12. Define and apply a parallel PCG solver for A X = B with the 2D AMS or
// the 3D ADS preconditioners from hypre. If using hybridization, the
// system is preconditioned with hypre's BoomerAMG. In the partial
// assembly case, use Jacobi preconditioning.
Solver *prec = NULL;
CGSolver *pcg = new CGSolver(MPI_COMM_WORLD);
pcg->SetOperator(*A);
// system is preconditioned with hypre's BoomerAMG.
HypreSolver *prec = NULL;
CGSolver *pcg = new CGSolver(A.GetComm());
pcg->SetOperator(A);
pcg->SetRelTol(1e-12);
pcg->SetMaxIter(2000);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(1);
if (hybridization) { prec = new HypreBoomerAMG(*A.As<HypreParMatrix>()); }
else if (pa) { prec = new OperatorJacobiSmoother(*a, ess_tdof_list); }
if (hybridization) { prec = new HypreBoomerAMG(A); }
else
{
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
if (dim == 2) { prec = new HypreAMS(*A.As<HypreParMatrix>(), prec_fespace); }
else { prec = new HypreADS(*A.As<HypreParMatrix>(), prec_fespace); }
if (dim == 2) { prec = new HypreAMS(A, prec_fespace); }
else { prec = new HypreADS(A, prec_fespace); }
}
pcg->SetPreconditioner(*prec);
pcg->Mult(B, X);
// 14. Recover the parallel grid function corresponding to X. This is the
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// 15. Compute and print the L^2 norm of the error.
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(F);
if (myid == 0)
@@ -263,7 +242,7 @@ int main(int argc, char *argv[])
}
}
// 16. Save the refined mesh and the solution in parallel. This output can
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
@@ -279,7 +258,7 @@ int main(int argc, char *argv[])
x.Save(sol_ofs);
}
// 17. Send the solution by socket to a GLVis server.
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
@@ -290,7 +269,7 @@ int main(int argc, char *argv[])
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 18. Free the used memory.
// 17. Free the used memory.
delete pcg;
delete prec;
delete hfes;
@@ -316,7 +295,7 @@ void F_exact(const Vector &p, Vector &F)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if F is changed to depend on z
// double z = (dim == 3) ? p(2) : 0.0;
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
@@ -333,7 +312,7 @@ void f_exact(const Vector &p, Vector &f)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if f is changed to depend on z
// double z = (dim == 3) ? p(2) : 0.0;
double temp = 1 + 2*kappa*kappa;
+24 -76
View File
@@ -4,10 +4,8 @@
//
// Sample runs: ex5 -m ../data/square-disc.mesh
// ex5 -m ../data/star.mesh
// ex5 -m ../data/star.mesh -pa
// ex5 -m ../data/beam-tet.mesh
// ex5 -m ../data/beam-hex.mesh
// ex5 -m ../data/beam-hex.mesh -pa
// ex5 -m ../data/escher.mesh
// ex5 -m ../data/fichera.mesh
//
@@ -49,7 +47,6 @@ int main(int argc, char *argv[])
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
bool pa = false;
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -57,8 +54,6 @@ int main(int argc, char *argv[])
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -151,39 +146,22 @@ int main(int argc, char *argv[])
BilinearForm *mVarf(new BilinearForm(R_space));
MixedBilinearForm *bVarf(new MixedBilinearForm(R_space, W_space));
if (pa) { mVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(k));
mVarf->Assemble();
if (!pa) { mVarf->Finalize(); }
mVarf->Finalize();
SparseMatrix &M(mVarf->SpMat());
if (pa) { bVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
bVarf->Assemble();
if (!pa) { bVarf->Finalize(); }
bVarf->Finalize();
SparseMatrix & B(bVarf->SpMat());
B *= -1.;
SparseMatrix *BT = Transpose(B);
BlockOperator darcyOp(block_offsets);
TransposeOperator *Bt = NULL;
if (pa)
{
Bt = new TransposeOperator(bVarf);
darcyOp.SetBlock(0,0, mVarf);
darcyOp.SetBlock(0,1, Bt, -1.0);
darcyOp.SetBlock(1,0, bVarf, -1.0);
}
else
{
SparseMatrix &M(mVarf->SpMat());
SparseMatrix &B(bVarf->SpMat());
B *= -1.;
Bt = new TransposeOperator(&B);
darcyOp.SetBlock(0,0, &M);
darcyOp.SetBlock(0,1, Bt);
darcyOp.SetBlock(1,0, &B);
}
BlockMatrix darcyMatrix(block_offsets);
darcyMatrix.SetBlock(0,0, &M);
darcyMatrix.SetBlock(0,1, BT);
darcyMatrix.SetBlock(1,0, &B);
// 9. Construct the operators for preconditioner
//
@@ -192,57 +170,27 @@ int main(int argc, char *argv[])
//
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
// pressure Schur Complement
SparseMatrix *MinvBt = NULL;
Vector Md(mVarf->Height());
SparseMatrix *MinvBt = Transpose(B);
Vector Md(M.Height());
M.GetDiag(Md);
for (int i = 0; i < Md.Size(); i++)
{
MinvBt->ScaleRow(i, 1./Md(i));
}
SparseMatrix *S = Mult(B, *MinvBt);
BlockDiagonalPreconditioner darcyPrec(block_offsets);
Solver *invM, *invS;
SparseMatrix *S = NULL;
if (pa)
{
mVarf->AssembleDiagonal(Md);
Vector invMd(mVarf->Height());
for (int i=0; i<mVarf->Height(); ++i)
{
invMd(i) = 1.0 / Md(i);
}
Vector BMBt_diag(bVarf->Height());
bVarf->AssembleDiagonal_ADAt(invMd, BMBt_diag);
Array<int> ess_tdof_list; // empty
invM = new OperatorJacobiSmoother(Md, ess_tdof_list);
invS = new OperatorJacobiSmoother(BMBt_diag, ess_tdof_list);
}
else
{
SparseMatrix &M(mVarf->SpMat());
M.GetDiag(Md);
SparseMatrix &B(bVarf->SpMat());
MinvBt = Transpose(B);
for (int i = 0; i < Md.Size(); i++)
{
MinvBt->ScaleRow(i, 1./Md(i));
}
S = Mult(B, *MinvBt);
invM = new DSmoother(M);
invM = new DSmoother(M);
#ifndef MFEM_USE_SUITESPARSE
invS = new GSSmoother(*S);
invS = new GSSmoother(*S);
#else
invS = new UMFPackSolver(*S);
invS = new UMFPackSolver(*S);
#endif
}
invM->iterative_mode = false;
invS->iterative_mode = false;
BlockDiagonalPreconditioner darcyPrec(block_offsets);
darcyPrec.SetDiagonalBlock(0, invM);
darcyPrec.SetDiagonalBlock(1, invS);
@@ -258,7 +206,7 @@ int main(int argc, char *argv[])
solver.SetAbsTol(atol);
solver.SetRelTol(rtol);
solver.SetMaxIter(maxIter);
solver.SetOperator(darcyOp);
solver.SetOperator(darcyMatrix);
solver.SetPreconditioner(darcyPrec);
solver.SetPrintLevel(1);
x = 0.0;
@@ -347,8 +295,8 @@ int main(int argc, char *argv[])
delete invM;
delete invS;
delete S;
delete Bt;
delete MinvBt;
delete BT;
delete mVarf;
delete bVarf;
delete W_space;
+25 -84
View File
@@ -4,10 +4,8 @@
//
// Sample runs: mpirun -np 4 ex5p -m ../data/square-disc.mesh
// mpirun -np 4 ex5p -m ../data/star.mesh
// mpirun -np 4 ex5p -m ../data/star.mesh -r 2 -pa
// mpirun -np 4 ex5p -m ../data/beam-tet.mesh
// mpirun -np 4 ex5p -m ../data/beam-hex.mesh
// mpirun -np 4 ex5p -m ../data/beam-hex.mesh -pa
// mpirun -np 4 ex5p -m ../data/escher.mesh
// mpirun -np 4 ex5p -m ../data/fichera.mesh
//
@@ -56,25 +54,19 @@ int main(int argc, char *argv[])
// 2. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int ref_levels = -1;
int order = 1;
bool par_format = false;
bool pa = false;
bool visualization = 1;
bool adios2 = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&par_format, "-pf", "--parallel-format", "-sf",
"--serial-format",
"Format to use when saving the results for VisIt.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -105,13 +97,10 @@ int main(int argc, char *argv[])
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 10,000 elements, unless the user specifies it as input.
// more than 10,000 elements.
{
if (ref_levels == -1)
{
ref_levels = (int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
}
int ref_levels =
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
@@ -207,47 +196,25 @@ int main(int argc, char *argv[])
ParBilinearForm *mVarf(new ParBilinearForm(R_space));
ParMixedBilinearForm *bVarf(new ParMixedBilinearForm(R_space, W_space));
HypreParMatrix *M = NULL;
HypreParMatrix *B = NULL;
HypreParMatrix *M, *B;
if (pa) { mVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(k));
mVarf->Assemble();
if (!pa) { mVarf->Finalize(); }
mVarf->Finalize();
M = mVarf->ParallelAssemble();
if (pa) { bVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
bVarf->Assemble();
if (!pa) { bVarf->Finalize(); }
bVarf->Finalize();
B = bVarf->ParallelAssemble();
(*B) *= -1;
HypreParMatrix *BT = B->Transpose();
BlockOperator *darcyOp = new BlockOperator(block_trueOffsets);
Array<int> empty_tdof_list; // empty
OperatorPtr opM, opB;
TransposeOperator *Bt = NULL;
if (pa)
{
mVarf->FormSystemMatrix(empty_tdof_list, opM);
bVarf->FormRectangularSystemMatrix(empty_tdof_list, empty_tdof_list, opB);
Bt = new TransposeOperator(opB.Ptr());
darcyOp->SetBlock(0,0, opM.Ptr());
darcyOp->SetBlock(0,1, Bt, -1.0);
darcyOp->SetBlock(1,0, opB.Ptr(), -1.0);
}
else
{
M = mVarf->ParallelAssemble();
B = bVarf->ParallelAssemble();
(*B) *= -1;
Bt = new TransposeOperator(B);
darcyOp->SetBlock(0,0, M);
darcyOp->SetBlock(0,1, Bt);
darcyOp->SetBlock(1,0, B);
}
darcyOp->SetBlock(0,0, M);
darcyOp->SetBlock(0,1, BT);
darcyOp->SetBlock(1,0, B);
// 11. Construct the operators for preconditioner
//
@@ -256,43 +223,17 @@ int main(int argc, char *argv[])
//
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
// pressure Schur Complement.
HypreParMatrix *MinvBt = NULL;
HypreParVector *Md = NULL;
HypreParMatrix *S = NULL;
Vector Md_PA;
Solver *invM, *invS;
HypreParMatrix *MinvBt = B->Transpose();
HypreParVector *Md = new HypreParVector(MPI_COMM_WORLD, M->GetGlobalNumRows(),
M->GetRowStarts());
M->GetDiag(*Md);
if (pa)
{
Md_PA.SetSize(R_space->GetTrueVSize());
mVarf->AssembleDiagonal(Md_PA);
Vector invMd(Md_PA.Size());
for (int i=0; i<Md_PA.Size(); ++i)
{
invMd(i) = 1.0 / Md_PA(i);
}
MinvBt->InvScaleRows(*Md);
HypreParMatrix *S = ParMult(B, MinvBt);
Vector BMBt_diag(W_space->GetTrueVSize());
bVarf->AssembleDiagonal_ADAt(invMd, BMBt_diag);
Array<int> ess_tdof_list; // empty
invM = new OperatorJacobiSmoother(Md_PA, ess_tdof_list);
invS = new OperatorJacobiSmoother(BMBt_diag, ess_tdof_list);
}
else
{
Md = new HypreParVector(MPI_COMM_WORLD, M->GetGlobalNumRows(),
M->GetRowStarts());
M->GetDiag(*Md);
MinvBt = B->Transpose();
MinvBt->InvScaleRows(*Md);
S = ParMult(B, MinvBt);
invM = new HypreDiagScale(*M);
invS = new HypreBoomerAMG(*S);
}
HypreSolver *invM, *invS;
invM = new HypreDiagScale(*M);
invS = new HypreBoomerAMG(*S);
invM->iterative_mode = false;
invS->iterative_mode = false;
@@ -304,7 +245,7 @@ int main(int argc, char *argv[])
// 12. Solve the linear system with MINRES.
// Check the norm of the unpreconditioned residual.
int maxIter(pa ? 1000 : 500);
int maxIter(500);
double rtol(1.e-6);
double atol(1.e-10);
@@ -454,7 +395,7 @@ int main(int argc, char *argv[])
delete S;
delete Md;
delete MinvBt;
delete Bt;
delete BT;
delete B;
delete M;
delete mVarf;
+1 -11
View File
@@ -19,7 +19,6 @@
//
// Device sample runs:
// ex9 -pa
// ex9 -ea
// ex9 -pa -m ../data/periodic-cube.mesh
// ex9 -pa -m ../data/periodic-cube.mesh -d cuda
//
@@ -143,7 +142,6 @@ int main(int argc, char *argv[])
int ref_levels = 2;
int order = 3;
bool pa = false;
bool ea = false;
const char *device_config = "cpu";
int ode_solver_type = 4;
double t_final = 10.0;
@@ -168,8 +166,6 @@ int main(int argc, char *argv[])
"Order (degree) of the finite elements.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
@@ -273,11 +269,6 @@ int main(int argc, char *argv[])
m.SetAssemblyLevel(AssemblyLevel::PARTIAL);
k.SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
else if (ea)
{
m.SetAssemblyLevel(AssemblyLevel::ELEMENT);
k.SetAssemblyLevel(AssemblyLevel::ELEMENT);
}
m.AddDomainIntegrator(new MassIntegrator);
k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
k.AddInteriorFaceIntegrator(
@@ -438,9 +429,8 @@ FE_Evolution::FE_Evolution(BilinearForm &_M, BilinearForm &_K, const Vector &_b)
: TimeDependentOperator(_M.Height()), M(_M), K(_K), b(_b), z(_M.Height())
{
bool pa = M.GetAssemblyLevel() == AssemblyLevel::PARTIAL;
bool ea = M.GetAssemblyLevel() == AssemblyLevel::ELEMENT;
Array<int> ess_tdof_list;
if (pa || ea)
if (pa)
{
M_prec = new OperatorJacobiSmoother(M, ess_tdof_list);
M_solver.SetOperator(M);
+2 -12
View File
@@ -19,7 +19,6 @@
//
// Device sample runs:
// mpirun -np 4 ex9p -pa
// mpirun -np 4 ex9p -ea
// mpirun -np 4 ex9p -pa -m ../data/periodic-cube.mesh
// mpirun -np 4 ex9p -pa -m ../data/periodic-cube.mesh -d cuda
//
@@ -162,7 +161,6 @@ int main(int argc, char *argv[])
int par_ref_levels = 0;
int order = 3;
bool pa = false;
bool ea = false;
const char *device_config = "cpu";
int ode_solver_type = 4;
double t_final = 10.0;
@@ -190,8 +188,6 @@ int main(int argc, char *argv[])
"Order (degree) of the finite elements.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
@@ -323,11 +319,6 @@ int main(int argc, char *argv[])
m->SetAssemblyLevel(AssemblyLevel::PARTIAL);
k->SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
else if (ea)
{
m->SetAssemblyLevel(AssemblyLevel::ELEMENT);
k->SetAssemblyLevel(AssemblyLevel::ELEMENT);
}
m->AddDomainIntegrator(new MassIntegrator);
k->AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
k->AddInteriorFaceIntegrator(
@@ -565,9 +556,8 @@ FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K,
z(_M.Height())
{
bool pa = _M.GetAssemblyLevel()==AssemblyLevel::PARTIAL;
bool ea = _M.GetAssemblyLevel()==AssemblyLevel::ELEMENT;
if (pa || ea)
if (pa)
{
M.Reset(&_M, false);
K.Reset(&_K, false);
@@ -581,7 +571,7 @@ FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K,
M_solver.SetOperator(*M);
Array<int> ess_tdof_list;
if (pa || ea)
if (pa)
{
M_prec = new OperatorJacobiSmoother(_M, ess_tdof_list);
dg_solver = NULL;
+292
View File
@@ -0,0 +1,292 @@
// MFEM Example 1 - Parallel Version
//
// Compile with: make ex1p
//
// Sample runs: mpirun -np 4 ex1p -m ../data/square-disc.mesh
// mpirun -np 4 ex1p -m ../data/star.mesh
// mpirun -np 4 ex1p -m ../data/star-mixed.mesh
// mpirun -np 4 ex1p -m ../data/escher.mesh
// 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/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
// mpirun -np 4 ex1p -m ../data/star-mixed-p2.mesh -o 2
// mpirun -np 4 ex1p -m ../data/disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/pipe-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/ball-nurbs.mesh -o 2
// mpirun -np 4 ex1p -m ../data/fichera-mixed-p2.mesh -o 2
// mpirun -np 4 ex1p -m ../data/star-surf.mesh
// mpirun -np 4 ex1p -m ../data/square-disc-surf.mesh
// mpirun -np 4 ex1p -m ../data/inline-segment.mesh
// mpirun -np 4 ex1p -m ../data/amr-quad.mesh
// mpirun -np 4 ex1p -m ../data/amr-hex.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh -o -1 -sc
//
// Device sample runs:
// mpirun -np 4 ex1p -pa -d cuda
// mpirun -np 4 ex1p -pa -d occa-cuda
// mpirun -np 4 ex1p -pa -d raja-omp
// mpirun -np 4 ex1p -pa -d ceed-cpu
// mpirun -np 4 ex1p -pa -d ceed-cuda
// mpirun -np 4 ex1p -m ../data/beam-tet.mesh -pa -d ceed-cpu
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include "mpi.h"
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
// const char *mesh_file = "../data/star.mesh";
const char *mesh_file = "../data/square-disc.mesh";
int order = 1;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = false;
int nfiles = 1;
// const char *out_file = "0_0.gf";
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&nfiles, "-nf", "--num-files", "Number of files to write.");
// args.AddOption(&out_file, "-o", "--outfile",
// "Name of file to write.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 5. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 10,000 elements.
{
int ref_levels =
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
{
int par_ref_levels = 2;
for (int l = 0; l < par_ref_levels; l++)
{
pmesh->UniformRefinement();
}
}
// 7. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (pmesh->GetNodes())
{
fec = pmesh->GetNodes()->OwnFEC();
if (myid == 0)
{
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec, 1, 0);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 8. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 9. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (1,phi_i) where phi_i are the basis functions in fespace.
ParLinearForm *b = new ParLinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 10. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(fespace);
x = 0.0;
// 11. Set up the parallel bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
ParBilinearForm *a = new ParBilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 12. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
OperatorPtr A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
// 13. Solve the linear system A X = B.
// * With full assembly, use the BoomerAMG preconditioner from hypre.
// * With partial assembly, use Jacobi smoothing, for now.
Solver *prec = NULL;
if (pa)
{
if (UsesTensorBasis(*fespace))
{
prec = new OperatorJacobiSmoother(*a, ess_tdof_list);
}
}
else
{
prec = new HypreBoomerAMG;
}
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
if (prec) { cg.SetPreconditioner(*prec); }
cg.SetOperator(*A);
cg.Mult(B, X);
delete prec;
// 14. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
std::string filename = to_string(num_procs) + "_" + to_string(nfiles) + "_";
{
double t1;
t1 = MPI_Wtime();
x.Save(filename.c_str(), nfiles);
double t2 = MPI_Wtime();
double write_time = t2 - t1;
double average_write_time;
MPI_Reduce(&write_time, &average_write_time, 1,
MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (myid == 0)
{
std::cout << "Average write time: " << average_write_time / num_procs << " for "
<< nfiles << " files and " << num_procs << " ranks\n";
}
}
{
double t1;
t1 = MPI_Wtime();
ParGridFunction temp_gf(fespace, filename.c_str());
double t2 = MPI_Wtime();
double read_time = t2 - t1;
double average_read_time;
MPI_Reduce(&read_time, &average_read_time, 1,
MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (myid == 0)
{
std::cout << "Average read time: " << average_read_time / num_procs << " for "
<< nfiles << " files and " << num_procs << " ranks\n";
}
}
// 17. Free the used memory.
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete pmesh;
MPI_Finalize();
return 0;
}
+906
View File
@@ -0,0 +1,906 @@
// MFEM Example 9
//
// Compile with: make serial_nogpu
//
// Description: This code solves the time-dependent advection-diffusion
// equation:
// \frac(\partial u}{\partial t}
// = \mathbf{a} \cdot \Nabla u - \nu \Nabla^2 u
// where a is a given advection velocity, \nu is the diffusion
// parameter, and u0(x) = u(0,x) is a given initial condition.
//
// The demonstrates explicit time marching with H1 elements of
// arbitrary order. Periodic boundary conditions are used through
// periodic meshes. GLVis can be used for visualization of a
// time-evolving solution.
#include <fstream>
#include <iostream>
#include <algorithm>
#include "mfem.hpp"
#include "mpi.h"
using namespace std;
using namespace mfem;
/** A time-dependent operator for the right-hand side of the ODE. The weak
form of du/dt = -a.grad(u) + nu Delta(u) is M du/dt = K u + b, where M and
K are the mass and advection-diffusion matrices, and b describes the flow
on the boundary. This can be written as a general ODE,
du/dt = M^{-1} (K u + b), and this class is used to evaluate the right-hand
side. */
class AdvectionDiffusionEvolution : public mfem::TimeDependentOperator
{
public:
/// \param[in] M - bilinear form for mass matrix
/// \param[in] K - bilinear form for stiffness matrix
/// \param[in] b - load vector
AdvectionDiffusionEvolution(mfem::BilinearForm &M, mfem::BilinearForm &K,
const mfem::Vector &b);
/// Perform the action of the operator: y = k = f(x, t), where k solves
/// Compute k = M^-1(Kx + l)
void Mult(const mfem::Vector &x, mfem::Vector &y) const override;
/// Solve the implicit equation: k = f(x + dt k, t), for the unknown k at
/// the current time t.
void ImplicitSolve(const double dt, const mfem::Vector &x,
mfem::Vector &k) override;
virtual ~AdvectionDiffusionEvolution();
private:
mfem::BilinearForm &M, &K;
const mfem::Vector &b;
/// solver for inverting mass matrix for explicit time-marching
std::unique_ptr<mfem::Solver> M_prec;
mfem::CGSolver M_solver;
/// solver for implicit time-marching
mfem::GSSmoother prec;
mfem::GMRESSolver linear_solver;
mfem::NewtonSolver newton;
mutable mfem::Vector z;
/// pointer-to-implementation idiom
/// Hides implementation details of this operator
class SystemOperator;
/// Operator that combines the linear spatial discretization with
/// the load vector into one operator used for implicit solves
std::unique_ptr<SystemOperator> combined_oper;
/// sets the state and dt for the combined operator
/// \param[in] dt - time increment
/// \param[in] x - the current state
void setOperParameters(double dt, const mfem::Vector *x);
};
class PAJacobianOperator : public mfem::Operator
{
public:
PAJacobianOperator(mfem::ParBilinearForm &_mass,
mfem::ParBilinearForm &_stiff);
/// Compute r = J@k = M@k + dt*K@k
/// \param[in] k - dx/dt
/// \param[out] r - J@k = M@k + dt*K@k
void Mult(const mfem::Vector &k, mfem::Vector &r) const override;
/// Set current dt values - needed to compute action of Jacobian.
void setParameters(double dt);
private:
mfem::ParBilinearForm &mass;
mfem::ParBilinearForm &stiff;
double dt;
};
class ParSystemOperator : public mfem::Operator
{
public:
/// Nonlinear operator of the form that combines the mass, res, stiff,
/// and load elements for implicit/explicit ODE integration
/// \param[in] ess_bdr - array of boundaries attributes marked essential
/// \param[in] mass - bilinear form for mass matrix (not owned)
/// \param[in] res - nonlinear residual operator (not owned)
/// \param[in] stiff - bilinear form for stiffness matrix (not owned)
/// \param[in] load - load vector (not owned)
/// \param[in] a - used to move the spatial residual to the rhs
ParSystemOperator(mfem::ParBilinearForm &_mass,
mfem::ParBilinearForm &_stiff);
/// Compute r = M@k + K@(x+dt*k)
/// (with `@` denoting matrix-vector multiplication)
/// \param[in] k - dx/dt
/// \param[out] r - the residual
/// \note the signs on each operator must be accounted for elsewhere
void Mult(const mfem::Vector &k, mfem::Vector &r) const override;
/// Compute J = M + dt * K
/// \param[in] k - dx/dt
mfem::Operator &GetGradient(const mfem::Vector &k) const override;
/// Set current dt and x values - needed to compute action and Jacobian.
void setParameters(double _dt, const mfem::Vector *_x);
~ParSystemOperator();
private:
mfem::ParBilinearForm &mass;
mfem::ParBilinearForm &stiff;
mutable mfem::HypreParMatrix *jacobian, *stiff_jacobian;
double dt;
const mfem::Vector *x;
mutable mfem::Vector work, work2;
std::unique_ptr<PAJacobianOperator> pa_jac;
};
/** A time-dependent operator for the right-hand side of the ODE. The weak
form of du/dt = -a.grad(u) + nu Delta(u) is M du/dt = K u + b, where M and
K are the mass and advection-diffusion matrices, and b describes the flow
on the boundary. This can be written as a general ODE,
du/dt = M^{-1} (K u + b), and this class is used to evaluate the right-hand
side. */
class ParAdvectionDiffusionEvolution : public mfem::TimeDependentOperator
{
public:
/// \param[in] M - parallel bilinear form for mass matrix
/// \param[in] K - parallel bilinear form for stiffness matrix
ParAdvectionDiffusionEvolution(mfem::ParBilinearForm &M,
mfem::ParBilinearForm &K);
/// Perform the action of the operator: y = k = f(x, t), where k solves
/// Compute k = M^-1(Kx + l)
void Mult(const mfem::Vector &x, mfem::Vector &y) const override;
/// Solve the implicit equation: k = f(x + dt k, t), for the unknown k at
/// the current time t.
void ImplicitSolve(const double dt, const mfem::Vector &x,
mfem::Vector &k) override;
virtual ~ParAdvectionDiffusionEvolution();
private:
mfem::OperatorHandle M_;
mfem::ParBilinearForm &M, &K;
/// solver for inverting mass matrix for explicit time-marching
std::unique_ptr<mfem::Solver> M_prec;
mfem::CGSolver M_solver;
/// solver for implicit time-marching
mfem::Solver *prec;
mfem::GMRESSolver linear_solver;
mfem::NewtonSolver newton;
mfem::Vector diag;
mutable mfem::Vector z, work, work2;
/// pointer-to-implementation idiom
/// Hides implementation details of this operator
/// Operator that combines the linear spatial discretization with
/// the load vector into one operator used for implicit solves
std::unique_ptr<ParSystemOperator> combined_oper;
/// sets the state and dt for the combined operator
/// \param[in] dt - time increment
/// \param[in] x - the current state
void setOperParameters(double dt, const mfem::Vector *x);
};
// Choice for the problem setup. The fluid velocity, initial condition and
// inflow boundary condition are chosen based on this parameter.
int problem;
// Velocity coefficient
void velocity_function(const Vector &X, Vector &v);
// Initial condition
double u0_function(const Vector &X);
// Inflow boundary condition
double inflow_function(const Vector &X, const double t);
// Mesh bounding box
Vector bb_min, bb_max;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
problem = 3;
const char *mesh_file = "../data/periodic-square.mesh";
int ser_ref_levels = 0;
int par_ref_levels = 0;
int order = 3;
const char *device_config = "cpu";
int ode_solver_type = 22;
double t_final = 3 * 2*M_PI;
double dt = 0.01;
bool glvis = false;
bool paraview = false;
int vis_steps = 5;
double nu_val = 0.001;
int precision = 8;
cout.precision(precision);
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&problem, "-p", "--problem",
"Problem setup to use. See options in velocity_function().");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
"Number of times to refine the mesh uniformly in parallel.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6.");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
"Time step.");
args.AddOption(&glvis, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&paraview, "-paraview", "--paraview-datafiles", "-no-paraview",
"--no-paraview-datafiles",
"Save data files for ParaView (paraview.org) visualization.");
args.AddOption(&vis_steps, "-vs", "--visualization-steps",
"Visualize every n-th timestep.");
args.AddOption(&nu_val, "-nu", "--nu-value",
"Value for \nu, the parameter that controls diffusion.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
std::cout << "Num ranks: " << num_procs << "\n";
args.PrintOptions(cout);
}
Device device(device_config);
if (myid == 0) { device.Print(); }
// 3. Read the serial mesh from the given mesh file on all processors. We can
// handle geometrically periodic meshes in this code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 5. Refine the mesh in serial to increase the resolution. In this example
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
// a command-line parameter. If the mesh is of NURBS type, we convert it
// to a (piecewise-polynomial) high-order mesh.
for (int lev = 0; lev < ser_ref_levels; lev++)
{
mesh->UniformRefinement();
}
mesh->GetBoundingBox(bb_min, bb_max, max(order, 1));
// 6. Define the parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
for (int lev = 0; lev < par_ref_levels; lev++)
{
pmesh->UniformRefinement();
}
// 7. Define the finite element space of the given
// polynomial order on the refined mesh.
H1_FECollection fec(order, dim, BasisType::GaussLobatto);
ParFiniteElementSpace *fes = new ParFiniteElementSpace(pmesh, &fec);
HYPRE_Int global_vSize = fes->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of unknowns: " << global_vSize << endl;
}
// 8. Set up and assemble the bilinear and linear forms corresponding to the
// CG discretization.
/// negative to move the diffusion terms to the right side
ConstantCoefficient nu(-nu_val);
ConstantCoefficient one(1.0);
VectorFunctionCoefficient velocity(dim, velocity_function);
FunctionCoefficient u0(u0_function);
ParBilinearForm *m_pa = new ParBilinearForm(fes);
ParBilinearForm *k_pa = new ParBilinearForm(fes);
m_pa->SetAssemblyLevel(AssemblyLevel::PARTIAL);
k_pa->SetAssemblyLevel(AssemblyLevel::PARTIAL);
/// create mass matrix
m_pa->AddDomainIntegrator(new MassIntegrator(one));
/// add advection terms to stiffness matrix
k_pa->AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
/// add diffusion terms to stiffness matrix
k_pa->AddDomainIntegrator(new DiffusionIntegrator(nu));
m_pa->Assemble();
int skip_zeros = 0;
k_pa->Assemble(skip_zeros);
m_pa->Finalize();
k_pa->Finalize(skip_zeros);
ParBilinearForm *m = new ParBilinearForm(fes);
ParBilinearForm *k = new ParBilinearForm(fes);
/// create mass matrix
m->AddDomainIntegrator(new MassIntegrator);
/// add advection terms to stiffness matrix
k->AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
/// add diffusion terms to stiffness matrix
k->AddDomainIntegrator(new DiffusionIntegrator(nu));
m->Assemble();
k->Assemble(skip_zeros);
m->Finalize();
k->Finalize(skip_zeros);
ParGridFunction *u = new ParGridFunction(fes);
u->UseDevice(true);
u->ProjectCoefficient(u0);
HypreParVector *U = u->GetTrueDofs();
ParSystemOperator pso(*m, *k);
ParSystemOperator pso_pa(*m_pa, *k_pa);
pso.setParameters(dt, U);
pso_pa.setParameters(dt, U);
MPI_Barrier(MPI_COMM_WORLD);
mfem::Vector pso_r(U->Size());
double t1 = MPI_Wtime();
pso.Mult(*U, pso_r);
double t2 = MPI_Wtime();
double fa_mult_time = t2 - t1;
double average_fa_mult_time;
MPI_Reduce(&fa_mult_time, &average_fa_mult_time, 1,
MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (myid == 0)
std::cout << "FA Mult time: " << average_fa_mult_time / num_procs << endl;
MPI_Barrier(MPI_COMM_WORLD);
mfem::Vector pso_pa_r(U->Size());
double t3 = MPI_Wtime();
pso_pa.Mult(*U, pso_pa_r);
double t4 = MPI_Wtime();
double pa_mult_time = t4 - t3;
double average_pa_mult_time;
MPI_Reduce(&pa_mult_time, &average_pa_mult_time, 1,
MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (myid == 0)
std::cout << "FA Mult time: " << average_pa_mult_time / num_procs << endl;
double local_mult_speedup = (t2-t1) / (t4-t3);
double global_mult_speedup;
MPI_Reduce(&local_mult_speedup, &global_mult_speedup, 1,
MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (myid == 0)
std::cout << "PA mult speedup: " << global_mult_speedup / num_procs << endl;
mfem::Vector diff_r(pso_pa_r);
diff_r -= pso_r;
// std::cout << "r diff: " << diff_r.Norml2() << std::endl;
mfem::Operator &pso_jac = pso.GetGradient(*U);
mfem::Operator &pso_pa_jac = pso_pa.GetGradient(*U);
MPI_Barrier(MPI_COMM_WORLD);
mfem::Vector pso_jac_r(U->Size());
double t5 = MPI_Wtime();
pso_jac.Mult(*U, pso_jac_r);
double t6 = MPI_Wtime();
double fa_jac_mult_time = t6-t5;
double average_fa_jac_time;
MPI_Reduce(&fa_jac_mult_time, &average_fa_jac_time, 1,
MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (myid == 0)
std::cout << "FA Jac Mult time: " << average_fa_jac_time / num_procs << endl;
MPI_Barrier(MPI_COMM_WORLD);
mfem::Vector pso_pa_jac_r(U->Size());
double t7 = MPI_Wtime();
pso_pa_jac.Mult(*U, pso_pa_jac_r);
double t8 = MPI_Wtime();
double pa_jac_mult_time = t8-t7;
double average_pa_jac_time;
MPI_Reduce(&pa_jac_mult_time, &average_pa_jac_time, 1,
MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (myid == 0)
std::cout << "PA Jac Mult time: " << average_pa_jac_time / num_procs << endl;
double local_jac_speedup = (t6-t5) / (t8-t7);
double global_jac_speedup;
MPI_Reduce(&local_jac_speedup, &global_jac_speedup, 1,
MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (myid == 0)
std::cout << "PA Jac mult speedup: " << global_jac_speedup / num_procs << endl;
// 13. Free the used memory.
delete U;
delete u;
delete k;
delete m;
delete fes;
delete pmesh;
MPI_Finalize();
return 0;
}
// Velocity coefficient
void velocity_function(const Vector &x, Vector &v)
{
int dim = x.Size();
// map to the reference [-1,1] domain
Vector X(dim);
for (int i = 0; i < dim; i++)
{
double center = (bb_min[i] + bb_max[i]) * 0.5;
X(i) = 2 * (x(i) - center) / (bb_max[i] - bb_min[i]);
}
switch (problem)
{
case 3:
{
// Translations in 1D, 2D, and 3D
switch (dim)
{
case 1: v(0) = 1.0; break;
case 2: v(0) = sqrt(2./3.); v(1) = sqrt(1./3.); break;
case 3: v(0) = sqrt(3./6.); v(1) = sqrt(2./6.); v(2) = sqrt(1./6.);
break;
}
break;
}
case 1:
case 2:
{
// Clockwise rotation in 2D around the origin
const double w = M_PI/2;
switch (dim)
{
case 1: v(0) = 1.0; break;
case 2: v(0) = w*X(1); v(1) = -w*X(0); break;
case 3: v(0) = w*X(1); v(1) = -w*X(0); v(2) = 0.0; break;
}
break;
}
case 0:
{
// Clockwise twisting rotation in 2D around the origin
const double w = M_PI/2;
double d = max((X(0)+1.)*(1.-X(0)),0.) * max((X(1)+1.)*(1.-X(1)),0.);
d = d*d;
switch (dim)
{
case 1: v(0) = 1.0; break;
case 2: v(0) = d*w*X(1); v(1) = -d*w*X(0); break;
case 3: v(0) = d*w*X(1); v(1) = -d*w*X(0); v(2) = 0.0; break;
}
break;
}
}
}
// Initial condition
double u0_function(const Vector &x)
{
int dim = x.Size();
// map to the reference [-1,1] domain
Vector X(dim);
for (int i = 0; i < dim; i++)
{
double center = (bb_min[i] + bb_max[i]) * 0.5;
X(i) = 2 * (x(i) - center) / (bb_max[i] - bb_min[i]);
}
switch (problem)
{
case 0:
case 1:
{
switch (dim)
{
case 1:
return exp(-40.*pow(X(0)-0.5,2));
case 2:
case 3:
{
double rx = 0.45, ry = 0.25, cx = 0., cy = -0.2, w = 10.;
if (dim == 3)
{
const double s = (1. + 0.25*cos(2*M_PI*X(2)));
rx *= s;
ry *= s;
}
return ( erfc(w*(X(0)-cx-rx))*erfc(-w*(X(0)-cx+rx)) *
erfc(w*(X(1)-cy-ry))*erfc(-w*(X(1)-cy+ry)) )/16;
}
}
}
case 2:
{
double x_ = X(0), y_ = X(1), rho, phi;
rho = hypot(x_, y_);
phi = atan2(y_, x_);
return pow(sin(M_PI*rho),2)*sin(3*phi);
}
case 3:
{
const double f = M_PI;
return sin(f*X(0))*sin(f*X(1));
}
}
return 0.0;
}
// Inflow boundary condition (zero for the problems considered in this example)
double inflow_function(const Vector &x, const double t)
{
switch (problem)
{
case 0:
case 1:
case 2:
case 3: return 0.0;
}
return 0.0;
}
class AdvectionDiffusionEvolution::SystemOperator : public mfem::Operator
{
public:
/// Nonlinear operator of the form that combines the mass, res, stiff,
/// and load elements for implicit/explicit ODE integration
/// \param[in] mass - bilinear form for mass matrix (not owned)
/// \param[in] res - nonlinear residual operator (not owned)
/// \param[in] stiff - bilinear form for stiffness matrix (not owned)
/// \param[in] load - load vector (not owned)
/// \param[in] a - used to move the spatial residual to the rhs
SystemOperator(BilinearForm &_mass, BilinearForm &_stiff,
const mfem::Vector &b)
: Operator(_mass.Height()), mass(_mass), stiff(_stiff),
load(b), Jacobian(NULL), dt(0.0), x(NULL), work(height)
{ }
/// Compute r = M@k + K@(x+dt*k) + l
/// (with `@` denoting matrix-vector multiplication)
/// \param[in] k - dx/dt
/// \param[out] r - the residual
/// \note the signs on each operator must be accounted for elsewhere
void Mult(const mfem::Vector &k, mfem::Vector &r) const override
{
/// work = x+dt*k = x+dt*dx/dt = x+dx
add(1.0, *x, dt, k, work);
r = 0.0;
stiff.AddMult(work, r);
r += load;
mass.AddMult(k, r, -1.0);
}
/// Compute J = M + dt * K
/// \param[in] k - dx/dt
mfem::Operator &GetGradient(const mfem::Vector &k) const override
{
delete Jacobian;
Jacobian = Add(-1.0, mass.SpMat(), dt, stiff.SpMat());
return *Jacobian;
}
/// Set current dt and x values - needed to compute action and Jacobian.
void setParameters(double _dt, const mfem::Vector *_x)
{
dt = _dt;
x = _x;
};
~SystemOperator() {delete Jacobian;};
private:
BilinearForm &mass;
BilinearForm &stiff;
const mfem::Vector &load;
mutable mfem::SparseMatrix *Jacobian;
double dt;
const mfem::Vector *x;
mutable mfem::Vector work, work2;
};
AdvectionDiffusionEvolution::AdvectionDiffusionEvolution(
BilinearForm &_M, BilinearForm &_K, const Vector &_b)
: TimeDependentOperator(_M.Height()), M(_M), K(_K), b(_b),
z(_M.Height())
{
bool pa = M.GetAssemblyLevel() == AssemblyLevel::PARTIAL;
Array<int> ess_tdof_list;
if (pa)
{
M_prec.reset(new OperatorJacobiSmoother(M, ess_tdof_list));
M_solver.SetOperator(M);
}
else
{
M_prec.reset(new DSmoother(M.SpMat()));
M_solver.SetOperator(M.SpMat());
}
combined_oper.reset(new SystemOperator(_M, _K, _b));
M_solver.SetPreconditioner(*M_prec);
M_solver.iterative_mode = false;
M_solver.SetRelTol(1e-9);
M_solver.SetAbsTol(0.0);
M_solver.SetMaxIter(100);
M_solver.SetPrintLevel(0);
linear_solver.iterative_mode = true;
linear_solver.SetRelTol(1e-12);
linear_solver.SetAbsTol(0.0);
linear_solver.SetMaxIter(100);
linear_solver.SetPrintLevel(0);
linear_solver.SetPreconditioner(prec);
newton.iterative_mode = false;
newton.SetRelTol(1e-9);
newton.SetAbsTol(0.0);
newton.SetMaxIter(100);
newton.SetPrintLevel(-1);
newton.SetSolver(linear_solver);
newton.SetOperator(*combined_oper);
}
void AdvectionDiffusionEvolution::Mult(const Vector &x, Vector &y) const
{
// y = M^{-1} (K x + b)
K.Mult(x, z);
z += b;
M_solver.Mult(z, y);
}
void AdvectionDiffusionEvolution::ImplicitSolve(const double dt,
const Vector &x,
Vector &k)
{
setOperParameters(dt, &x);
Vector zero; // empty vector is interpreted as zero r.h.s. by NewtonSolver
newton.Mult(zero, k);
MFEM_VERIFY(newton.GetConverged(), "Newton solver did not converge!");
}
void AdvectionDiffusionEvolution::setOperParameters(double dt,
const mfem::Vector *x)
{
combined_oper->setParameters(dt, x);
}
AdvectionDiffusionEvolution::~AdvectionDiffusionEvolution() {}
PAJacobianOperator::PAJacobianOperator(ParBilinearForm &_mass, ParBilinearForm &_stiff)
: Operator(_mass.ParFESpace()->GetTrueVSize()), mass(_mass), stiff(_stiff),
dt(0.0) { }
void PAJacobianOperator::Mult(const mfem::Vector &k, mfem::Vector &r) const
{
r.UseDevice(true);
r = 0.0;
stiff.TrueAddMult(k, r, dt);
mass.TrueAddMult(k, r, -1.0);
}
void PAJacobianOperator::setParameters(const double _dt)
{
dt = _dt;
};
ParSystemOperator::ParSystemOperator(ParBilinearForm &_mass, ParBilinearForm &_stiff)
: Operator(_mass.ParFESpace()->GetTrueVSize()), mass(_mass), stiff(_stiff),
jacobian(NULL), stiff_jacobian(NULL), dt(0.0), x(NULL),
work(height)
{
pa_jac.reset(new PAJacobianOperator(mass, stiff));
}
/// Compute r = M@k + K@(x+dt*k)
/// (with `@` denoting matrix-vector multiplication)
/// \param[in] k - dx/dt
/// \param[out] r - the residual
/// \note the signs on each operator must be accounted for elsewhere
void ParSystemOperator::Mult(const mfem::Vector &k, mfem::Vector &r) const
{
r = 0.0;
work.UseDevice(true);
work = 0.0;
/// work = x+dt*k = x+dt*dx/dt = x+dx
if (x)
{
add(1.0, *x, dt, k, work);
}
stiff.TrueAddMult(work, r);
mass.TrueAddMult(k, r, -1.0);
}
/// Compute J = M + dt * K
/// \param[in] k - dx/dt
mfem::Operator &ParSystemOperator::GetGradient(const mfem::Vector &k) const
{
bool mass_pa = mass.GetAssemblyLevel() == AssemblyLevel::PARTIAL;
bool stiff_pa = stiff.GetAssemblyLevel() == AssemblyLevel::PARTIAL;
if (mass_pa && stiff_pa)
{
return *pa_jac.get();
}
else
{
delete stiff_jacobian;
delete jacobian;
jacobian = mass.ParallelAssemble();
*jacobian *= -1.0; //alpha;
stiff_jacobian = stiff.ParallelAssemble();
jacobian->Add(dt, *stiff_jacobian);
return *jacobian;
}
}
/// Set current dt and x values - needed to compute action and Jacobian.
void ParSystemOperator::setParameters(const double _dt, const mfem::Vector *_x)
{
dt = _dt;
x = _x;
pa_jac->setParameters(_dt);
};
ParSystemOperator::~ParSystemOperator()
{
delete jacobian;
delete stiff_jacobian;
};
ParAdvectionDiffusionEvolution::ParAdvectionDiffusionEvolution(
ParBilinearForm &_M, ParBilinearForm &_K)
: TimeDependentOperator(_M.ParFESpace()->GetTrueVSize()), M(_M), K(_K), z(_M.Height())
{
bool mass_pa = M.GetAssemblyLevel() == AssemblyLevel::PARTIAL;
bool stiff_pa = K.GetAssemblyLevel() == AssemblyLevel::PARTIAL;
Array<int> ess_tdof_list;
M_solver = CGSolver(MPI_COMM_WORLD);
if (mass_pa)
{
M_prec.reset(new OperatorJacobiSmoother(M, ess_tdof_list));
M_solver.SetOperator(M);
}
else
{
M_.Reset(_M.ParallelAssemble(), true);
// M_prec.reset(new HypreSmoother());
// M_solver.SetOperator(M.As<HypreParMatrix>());
HypreParMatrix &M_mat = *M_.As<HypreParMatrix>();
// HypreParMatrix &K_mat = *K.As<HypreParMatrix>();
M_prec.reset(new HypreSmoother(M_mat, HypreSmoother::Jacobi));
}
combined_oper.reset(new ParSystemOperator(_M, _K));
M_solver.SetPreconditioner(*M_prec);
M_solver.iterative_mode = false;
M_solver.SetRelTol(1e-9);
M_solver.SetAbsTol(0.0);
M_solver.SetMaxIter(100);
M_solver.SetPrintLevel(0);
if (mass_pa && stiff_pa)
{
diag.UseDevice(true);
diag.SetSize(M.ParFESpace()->GetTrueVSize());
diag = 0.0;
work.UseDevice(true);
work2.UseDevice(true);
work.SetSize(M.ParFESpace()->GetTrueVSize());
work2.SetSize(M.ParFESpace()->GetTrueVSize());
work = 0.0;
work2 = 0.0;
M.AssembleDiagonal(work);
ParBilinearForm k(M.ParFESpace());
ConstantCoefficient nu(-0.01);
k.AddDomainIntegrator(new mfem::DiffusionIntegrator(nu));
k.SetAssemblyLevel(AssemblyLevel::PARTIAL);
k.Assemble(0);
k.Finalize(0);
k.AssembleDiagonal(work2);
double dt = 0.1;
add(-1.0, work, dt, work2, diag);
prec = new OperatorChebyshevSmoother(combined_oper.get(), diag,
ess_tdof_list, 5,
M.ParFESpace()->GetComm());
}
else
{
prec = new HypreSmoother();
}
linear_solver = GMRESSolver(MPI_COMM_WORLD);
linear_solver.iterative_mode = true;
linear_solver.SetRelTol(1e-12);
linear_solver.SetAbsTol(0.0);
linear_solver.SetMaxIter(2000);
linear_solver.SetPrintLevel(0);
linear_solver.SetPreconditioner(*prec);
linear_solver.SetKDim(2000);
newton.iterative_mode = true;
newton.SetRelTol(1e-9);
newton.SetAbsTol(0.0);
newton.SetMaxIter(10);
newton.SetPrintLevel(-1);
newton.SetSolver(linear_solver);
newton.SetOperator(*combined_oper);
}
void ParAdvectionDiffusionEvolution::Mult(const Vector &x, Vector &y) const
{
// y = M^{-1} (K x + b)
K.Mult(x, z);
M_solver.Mult(z, y);
}
void ParAdvectionDiffusionEvolution::ImplicitSolve(const double dt,
const Vector &x,
Vector &k)
{
setOperParameters(dt, &x);
Vector zero; // empty vector is interpreted as zero r.h.s. by NewtonSolver
newton.Mult(zero, k);
MFEM_VERIFY(newton.GetConverged(), "Newton solver did not converge!");
}
void ParAdvectionDiffusionEvolution::setOperParameters(const double dt,
const mfem::Vector *x)
{
combined_oper->setParameters(dt, x);
}
ParAdvectionDiffusionEvolution::~ParAdvectionDiffusionEvolution() {delete prec;}
-7
View File
@@ -32,13 +32,6 @@
// is used for the Finite Element order and "-go" is used for the
// geometry order. Note that they can be used independently, i.e.
// "-o 8 -go 3" solves for 8th order FE on a third order geometry.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
-8
View File
@@ -36,14 +36,6 @@
// option "-o" is used for the Finite Element order and "-go" for
// the geometry order. Note that they can be used independently:
// "-o 8 -go 3" solves for 8th order FE on third order geometry.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
-8
View File
@@ -43,14 +43,6 @@
// also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
+2 -8
View File
@@ -1,7 +1,7 @@
// MFEM Example 6 - Parallel Version
// PUMI Modification
//
// Compile with: make ex6p
// Compile with: make ex1p
//
// Sample runs: mpirun -np 8 ex6p
//
@@ -18,13 +18,6 @@
// is added to modify the "adapt_ratio" which is the fraction of
// allowable error that scales the output size field of the error
// estimator.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
@@ -339,6 +332,7 @@ int main(int argc, char *argv[])
apf::destroyField(Tmag_field);
apf::destroyField(ipfield);
apf::destroyNumbering(pumi_mesh->findNumbering("LocalVertexNumbering"));
// 18. Perform MesAdapt.
ma::Input* erinput = ma::configure(pumi_mesh, sizefield);
+4 -11
View File
@@ -13,20 +13,13 @@ set(SRCS
bilinearform.cpp
bilinearform_ext.cpp
bilininteg.cpp
bilininteg_convection_pa.cpp
bilininteg_convection_ea.cpp
bilininteg_dgtrace_pa.cpp
bilininteg_dgtrace_ea.cpp
bilininteg_diffusion_pa.cpp
bilininteg_diffusion_ea.cpp
bilininteg_convection.cpp
bilininteg_dgtrace.cpp
bilininteg_diffusion.cpp
bilininteg_divergence.cpp
bilininteg_hcurl.cpp
bilininteg_hdiv.cpp
bilininteg_vectorfe.cpp
bilininteg_gradient.cpp
bilininteg_mass_pa.cpp
bilininteg_mass_ea.cpp
bilininteg_transpose_ea.cpp
bilininteg_mass.cpp
bilininteg_vecdiffusion.cpp
bilininteg_vecmass.cpp
coefficient.cpp
+1 -3
View File
@@ -15,8 +15,6 @@
#include "adios2datacollection.hpp"
#ifdef MFEM_USE_ADIOS2
namespace mfem
{
@@ -89,4 +87,4 @@ noexcept
} //end namespace mfem
#endif // MFEM_USE_ADIOS2
-5
View File
@@ -17,9 +17,6 @@
#define MFEM_ADIOS2DATACOLLECTION
#include "../config/config.hpp"
#ifdef MFEM_USE_ADIOS2
#include "../general/adios2stream.hpp"
#include "datacollection.hpp"
@@ -88,6 +85,4 @@ private:
} // namespace mfem
#endif // MFEM_USE_ADIOS2
#endif /* MFEM_ADIOS2DATACOLLECTION */
+2 -49
View File
@@ -126,7 +126,8 @@ void BilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
// Use the original BilinearForm implementation for now
break;
case AssemblyLevel::ELEMENT:
ext = new EABilinearFormExtension(this);
mfem_error("Element assembly not supported yet... stay tuned!");
// ext = new EABilinearFormExtension(this);
break;
case AssemblyLevel::PARTIAL:
ext = new PABilinearFormExtension(this);
@@ -1431,54 +1432,6 @@ void MixedBilinearForm::Assemble (int skip_zeros)
}
}
void MixedBilinearForm::AssembleDiagonal_ADAt(const Vector &D,
Vector &diag) const
{
if (ext)
{
MFEM_ASSERT(diag.Size() == test_fes->GetTrueVSize(),
"Vector for holding diagonal has wrong size!");
MFEM_ASSERT(D.Size() == trial_fes->GetTrueVSize(),
"Vector for holding diagonal has wrong size!");
const Operator *P_trial = trial_fes->GetProlongationMatrix();
const Operator *P_test = test_fes->GetProlongationMatrix();
if (!IsIdentityProlongation(P_trial))
{
Vector local_D(P_trial->Height());
P_trial->Mult(D, local_D);
if (!IsIdentityProlongation(P_test))
{
Vector local_diag(P_test->Height());
ext->AssembleDiagonal_ADAt(local_D, local_diag);
P_test->MultTranspose(local_diag, diag);
}
else
{
ext->AssembleDiagonal_ADAt(local_D, diag);
}
}
else
{
if (!IsIdentityProlongation(P_test))
{
Vector local_diag(P_test->Height());
ext->AssembleDiagonal_ADAt(D, local_diag);
P_test->MultTranspose(local_diag, diag);
}
else
{
ext->AssembleDiagonal_ADAt(D, diag);
}
}
}
else
{
MFEM_ABORT("Not implemented. Maybe assemble your bilinear form into a "
"matrix and use SparseMatrix functions?");
}
}
void MixedBilinearForm::ConformingAssemble()
{
if (assembly != AssemblyLevel::FULL)
+36 -97
View File
@@ -25,8 +25,8 @@
namespace mfem
{
/** @brief Enumeration defining the assembly level for bilinear and nonlinear
form classes derived from Operator. */
/// 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,19 +44,15 @@ enum class AssemblyLevel
};
/** @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 for bilinear form - "Matrix" with associated FE space and
BLFIntegrators. */
class BilinearForm : public Matrix
{
protected:
/// Sparse matrix \f$ M \f$ to be associated with the form. Owned.
/// Sparse matrix to be associated with the form. Owned.
SparseMatrix *mat;
/** @brief Sparse Matrix \f$ M_e \f$ used to store the eliminations
from the b.c. Owned.
\f$ M + M_e = M_{original} \f$ */
/// Matrix used to eliminate b.c. Owned.
SparseMatrix *mat_e;
/// FE space on which the form lives. Not owned.
@@ -66,12 +62,12 @@ protected:
AssemblyLevel assembly;
/// Element batch size used in the form action (1, 8, num_elems, etc.)
int batch;
/** @brief Extension for supporting Full Assembly (FA), Element Assembly (EA),
/** Extension for supporting Full Assembly (FA), Element Assembly (EA),
Partial Assembly (PA), or Matrix Free assembly (MF). */
BilinearFormExtension *ext;
/** @brief Indicates the Mesh::sequence corresponding to the current state of
the BilinearForm. */
/// Indicates the Mesh::sequence corresponding to the current state of the
/// BilinearForm.
long sequence;
/** @brief Indicates the BilinearFormIntegrator%s stored in #dbfi, #bbfi,
@@ -151,43 +147,35 @@ public:
/// Get the size of the BilinearForm as a square matrix.
int Size() const { return height; }
/// Set the desired assembly level.
/** Valid choices are:
- AssemblyLevel::FULL (default)
- AssemblyLevel::PARTIAL
- AssemblyLevel::ELEMENT
- AssemblyLevel::NONE
This method must be called before assembly. */
/// Set the desired assembly level. The default is AssemblyLevel::FULL.
/** This method must be called before assembly. */
void SetAssemblyLevel(AssemblyLevel assembly_level);
/// Returns the assembly level
AssemblyLevel GetAssemblyLevel() const { return assembly; }
/** @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
/** 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();
/** @brief Check if static condensation was actually enabled by a previous
call to EnableStaticCondensation(). */
/** 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);
/** @brief For scalar FE spaces, precompute the sparsity pattern of the matrix
/** 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; }
@@ -206,16 +194,15 @@ 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 the integrators added with AddDomainIntegrator().
/// Access all integrators added with AddDomainIntegrator().
Array<BilinearFormIntegrator*> *GetDBFI() { return &dbfi; }
/// Access all the integrators added with AddBoundaryIntegrator().
/// Access all 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
@@ -232,85 +219,64 @@ 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 a reference to: \f$ M_{ij} \f$
/// Returns reference to a_{ij}.
virtual double &Elem(int i, int j);
/// Returns constant reference to: \f$ M_{ij} \f$
/// Returns constant reference to a_{ij}.
virtual const double &Elem(int i, int j) const;
/// Matrix vector multiplication: \f$ y = M x \f$
/// Matrix vector multiplication.
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: \f$ M^{-1} \f$
/// Returns a pointer to (approximation) of the matrix inverse.
virtual MatrixInverse *Inverse() const;
/// Finalizes the matrix initialization.
virtual void Finalize(int skip_zeros = 1);
/// Returns a const reference to the sparse matrix.
/// Returns a 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 const reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$
/// Returns a reference to the sparse matrix of eliminated b.c.
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");
@@ -345,7 +311,6 @@ 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; }
@@ -363,10 +328,10 @@ public:
for an AMR mesh. */
void AssembleDiagonal(Vector &diag) const;
/// Get the finite element space prolongation operator.
/// Get the finite element space prolongation matrix
virtual const Operator *GetProlongation() const
{ return fes->GetConformingProlongation(); }
/// Get the finite element space restriction operator
/// Get the finite element space restriction matrix
virtual const Operator *GetRestriction() const
{ return fes->GetConformingRestriction(); }
/// Get the output finite element space prolongation matrix
@@ -526,12 +491,10 @@ 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 in \f$ M_e \f$.
/// Eliminate the given @a vdofs, storing the eliminated part internally.
/** 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. */
@@ -560,11 +523,9 @@ 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.
@@ -576,13 +537,7 @@ public:
/// Read-only access to the associated FiniteElementSpace.
const FiniteElementSpace *FESpace() const { return fes; }
/// 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)
*/
/// Sets diagonal policy used upon construction of the linear system
void SetDiagonalPolicy(DiagonalPolicy policy);
/// Indicate that integrators are not owned by the BilinearForm
@@ -595,16 +550,16 @@ public:
/**
Class for assembling of bilinear forms `a(u,v)` defined on different
trial and test spaces. The assembled matrix `M` is such that
trial and test spaces. The assembled matrix `A` is such that
a(u,v) = V^t M U
a(u,v) = V^t A 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 M = dimension of the test space and
# of cols of M = dimension of the trial space.
# of rows of A = dimension of the test space and
# of cols of A = dimension of the trial space.
Both trial and test spaces should be defined on the same mesh.
*/
@@ -673,15 +628,11 @@ 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;
@@ -691,7 +642,6 @@ 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
@@ -699,14 +649,8 @@ 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.
@@ -753,7 +697,6 @@ 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.
@@ -762,10 +705,6 @@ public:
void Assemble(int skip_zeros = 1);
/** @brief Assemble the diagonal of ADA^T into diag, where A is this mixed
bilinear form and D is a diagonal. */
void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const;
/// Get the input finite element space prolongation matrix
virtual const Operator *GetProlongation() const
{ return trial_fes->GetProlongationMatrix(); }
+4 -376
View File
@@ -47,7 +47,7 @@ PABilinearFormExtension::PABilinearFormExtension(BilinearForm *form)
bdr_face_restrict_lex = NULL;
}
void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
void PABilinearFormExtension::SetupRestrictionOperators()
{
ElementDofOrdering ordering = UsesTensorBasis(*a->FESpace())?
ElementDofOrdering::LEXICOGRAPHIC:
@@ -65,8 +65,7 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
if (int_face_restrict_lex == NULL && a->GetFBFI()->Size() > 0)
{
int_face_restrict_lex = trialFes->GetFaceRestriction(
ElementDofOrdering::LEXICOGRAPHIC,
FaceType::Interior);
ElementDofOrdering::LEXICOGRAPHIC, FaceType::Interior);
faceIntX.SetSize(int_face_restrict_lex->Height(), Device::GetMemoryType());
faceIntY.SetSize(int_face_restrict_lex->Height(), Device::GetMemoryType());
faceIntY.UseDevice(true); // ensure 'faceIntY = 0.0' is done on device
@@ -75,9 +74,7 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
if (bdr_face_restrict_lex == NULL && a->GetBFBFI()->Size() > 0)
{
bdr_face_restrict_lex = trialFes->GetFaceRestriction(
ElementDofOrdering::LEXICOGRAPHIC,
FaceType::Boundary,
m);
ElementDofOrdering::LEXICOGRAPHIC, FaceType::Boundary);
faceBdrX.SetSize(bdr_face_restrict_lex->Height(), Device::GetMemoryType());
faceBdrY.SetSize(bdr_face_restrict_lex->Height(), Device::GetMemoryType());
faceBdrY.UseDevice(true); // ensure 'faceBoundY = 0.0' is done on device
@@ -86,7 +83,7 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
void PABilinearFormExtension::Assemble()
{
SetupRestrictionOperators(L2FaceValues::DoubleValued);
SetupRestrictionOperators();
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int integratorCount = integrators.Size();
@@ -290,311 +287,6 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
}
}
// Data and methods for element-assembled bilinear forms
EABilinearFormExtension::EABilinearFormExtension(BilinearForm *form)
: PABilinearFormExtension(form)
{
}
void EABilinearFormExtension::Assemble()
{
SetupRestrictionOperators(L2FaceValues::SingleValued);
ne = trialFes->GetMesh()->GetNE();
elemDofs = trialFes->GetFE(0)->GetDof();
ea_data.SetSize(ne*elemDofs*elemDofs, Device::GetMemoryType());
ea_data.UseDevice(true);
ea_data = 0.0;
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int integratorCount = integrators.Size();
for (int i = 0; i < integratorCount; ++i)
{
integrators[i]->AssembleEA(*a->FESpace(), ea_data);
}
faceDofs = trialFes ->
GetTraceElement(0, trialFes->GetMesh()->GetFaceBaseGeometry(0)) ->
GetDof();
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int intFaceIntegratorCount = intFaceIntegrators.Size();
if (intFaceIntegratorCount>0)
{
nf_int = trialFes->GetNFbyType(FaceType::Interior);
ea_data_int.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_ext.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_int = 0.0;
ea_data_ext = 0.0;
}
for (int i = 0; i < intFaceIntegratorCount; ++i)
{
intFaceIntegrators[i]->AssembleEAInteriorFaces(*a->FESpace(),
ea_data_int,
ea_data_ext);
}
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int boundFaceIntegratorCount = bdrFaceIntegrators.Size();
if (boundFaceIntegratorCount>0)
{
nf_bdr = trialFes->GetNFbyType(FaceType::Boundary);
ea_data_bdr.SetSize(nf_bdr*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_bdr = 0.0;
}
for (int i = 0; i < boundFaceIntegratorCount; ++i)
{
bdrFaceIntegrators[i]->AssembleEABoundaryFaces(*a->FESpace(),ea_data_bdr);
}
}
void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
{
// Apply the Element Restriction
const bool useRestrict = !DeviceCanUseCeed() && elem_restrict;
if (!useRestrict)
{
y.UseDevice(true); // typically this is a large vector, so store on device
y = 0.0;
}
else
{
elem_restrict->Mult(x, localX);
localY = 0.0;
}
// Apply the Element Matrices
const int NDOFS = elemDofs;
auto X = Reshape(useRestrict?localX.Read():x.Read(), NDOFS, ne);
auto Y = Reshape(useRestrict?localY.ReadWrite():y.ReadWrite(), NDOFS, ne);
auto A = Reshape(ea_data.Read(), NDOFS, NDOFS, ne);
MFEM_FORALL(glob_j, ne*NDOFS,
{
const int e = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(i, j, e)*X(i, e);
}
Y(j, e) += res;
});
// Apply the Element Restriction transposed
if (useRestrict)
{
elem_restrict->MultTranspose(localY, y);
}
// Treatment of interior faces
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int iFISz = intFaceIntegrators.Size();
if (int_face_restrict_lex && iFISz>0)
{
// Apply the Interior Face Restriction
int_face_restrict_lex->Mult(x, faceIntX);
if (faceIntX.Size()>0)
{
faceIntY = 0.0;
// Apply the interior face matrices
const int NDOFS = faceDofs;
auto X = Reshape(faceIntX.Read(), NDOFS, 2, nf_int);
auto Y = Reshape(faceIntY.ReadWrite(), NDOFS, 2, nf_int);
auto A_int = Reshape(ea_data_int.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(i, j, 0, f)*X(i, 0, f);
}
Y(j, 0, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(i, j, 1, f)*X(i, 1, f);
}
Y(j, 1, f) += res;
});
auto A_ext = Reshape(ea_data_ext.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(i, j, 0, f)*X(i, 0, f);
}
Y(j, 1, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(i, j, 1, f)*X(i, 1, f);
}
Y(j, 0, f) += res;
});
// Apply the Interior Face Restriction transposed
int_face_restrict_lex->MultTranspose(faceIntY, y);
}
}
// Treatment of boundary faces
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (bdr_face_restrict_lex && bFISz>0)
{
// Apply the Boundary Face Restriction
bdr_face_restrict_lex->Mult(x, faceBdrX);
if (faceBdrX.Size()>0)
{
faceBdrY = 0.0;
// Apply the boundary face matrices
const int NDOFS = faceDofs;
auto X = Reshape(faceBdrX.Read(), NDOFS, nf_bdr);
auto Y = Reshape(faceBdrY.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
MFEM_FORALL(glob_j, nf_bdr*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(i, j, f)*X(i, f);
}
Y(j, f) += res;
});
// Apply the Boundary Face Restriction transposed
bdr_face_restrict_lex->MultTranspose(faceBdrY, y);
}
}
}
void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
{
// Apply the Element Restriction
const bool useRestrict = DeviceCanUseCeed() || !elem_restrict;
if (!useRestrict)
{
y.UseDevice(true); // typically this is a large vector, so store on device
y = 0.0;
}
else
{
elem_restrict->Mult(x, localX);
localY = 0.0;
}
// Apply the Element Matrices transposed
const int NDOFS = elemDofs;
auto X = Reshape(useRestrict?localX.Read():x.Read(), NDOFS, ne);
auto Y = Reshape(useRestrict?localY.ReadWrite():y.ReadWrite(), NDOFS, ne);
auto A = Reshape(ea_data.Read(), NDOFS, NDOFS, ne);
MFEM_FORALL(glob_j, ne*NDOFS,
{
const int e = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(j, i, e)*X(i, e);
}
Y(j, e) += res;
});
// Apply the Element Restriction transposed
if (useRestrict)
{
elem_restrict->MultTranspose(localY, y);
}
// Treatment of interior faces
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int iFISz = intFaceIntegrators.Size();
if (int_face_restrict_lex && iFISz>0)
{
// Apply the Interior Face Restriction
int_face_restrict_lex->Mult(x, faceIntX);
if (faceIntX.Size()>0)
{
faceIntY = 0.0;
// Apply the interior face matrices transposed
const int NDOFS = faceDofs;
auto X = Reshape(faceIntX.Read(), NDOFS, 2, nf_int);
auto Y = Reshape(faceIntY.ReadWrite(), NDOFS, 2, nf_int);
auto A_int = Reshape(ea_data_int.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(j, i, 0, f)*X(i, 0, f);
}
Y(j, 0, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(j, i, 1, f)*X(i, 1, f);
}
Y(j, 1, f) += res;
});
auto A_ext = Reshape(ea_data_ext.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(j, i, 0, f)*X(i, 0, f);
}
Y(j, 1, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(j, i, 1, f)*X(i, 1, f);
}
Y(j, 0, f) += res;
});
// Apply the Interior Face Restriction transposed
int_face_restrict_lex->MultTranspose(faceIntY, y);
}
}
// Treatment of boundary faces
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (bdr_face_restrict_lex && bFISz>0)
{
// Apply the Boundary Face Restriction
bdr_face_restrict_lex->Mult(x, faceBdrX);
if (faceBdrX.Size()>0)
{
faceBdrY = 0.0;
// Apply the boundary face matrices transposed
const int NDOFS = faceDofs;
auto X = Reshape(faceBdrX.Read(), NDOFS, nf_bdr);
auto Y = Reshape(faceBdrY.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
MFEM_FORALL(glob_j, nf_bdr*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(j, i, f)*X(i, f);
}
Y(j, f) += res;
});
// Apply the Boundary Face Restriction transposed
bdr_face_restrict_lex->MultTranspose(faceBdrY, y);
}
}
}
MixedBilinearFormExtension::MixedBilinearFormExtension(MixedBilinearForm *form)
: Operator(form->Height(), form->Width()), a(form)
{
@@ -795,68 +487,4 @@ void PAMixedBilinearFormExtension::AddMultTranspose(const Vector &x, Vector &y,
}
}
void PAMixedBilinearFormExtension::AssembleDiagonal_ADAt(const Vector &D,
Vector &diag) const
{
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int iSz = integrators.Size();
if (elem_restrict_trial)
{
const ElementRestriction* H1elem_restrict_trial =
dynamic_cast<const ElementRestriction*>(elem_restrict_trial);
if (H1elem_restrict_trial)
{
H1elem_restrict_trial->MultUnsigned(D, localTrial);
}
else
{
elem_restrict_trial->Mult(D, localTrial);
}
}
if (elem_restrict_test)
{
localTest = 0.0;
for (int i = 0; i < iSz; ++i)
{
if (elem_restrict_trial)
{
integrators[i]->AssembleDiagonalPA_ADAt(localTrial, localTest);
}
else
{
integrators[i]->AssembleDiagonalPA_ADAt(D, localTest);
}
}
const ElementRestriction* H1elem_restrict_test =
dynamic_cast<const ElementRestriction*>(elem_restrict_test);
if (H1elem_restrict_test)
{
H1elem_restrict_test->MultTransposeUnsigned(localTest, diag);
}
else
{
elem_restrict_test->MultTranspose(localTest, diag);
}
}
else
{
diag.UseDevice(true); // typically this is a large vector, so store on device
diag = 0.0;
for (int i = 0; i < iSz; ++i)
{
if (elem_restrict_trial)
{
integrators[i]->AssembleDiagonalPA_ADAt(localTrial, diag);
}
else
{
integrators[i]->AssembleDiagonalPA_ADAt(D, diag);
}
}
}
}
} // namespace mfem
+29 -42
View File
@@ -22,12 +22,9 @@ namespace mfem
class BilinearForm;
class MixedBilinearForm;
/// Class extending the BilinearForm class to support different AssemblyLevels.
/** FA - Full Assembly
PA - Partial Assembly
EA - Element Assembly
MF - Matrix Free
*/
/** @brief Class extending the BilinearForm class to support the different
AssemblyLevel%s. */
class BilinearFormExtension : public Operator
{
protected:
@@ -45,7 +42,6 @@ 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
@@ -62,8 +58,7 @@ public:
virtual void Update() = 0;
};
/** @brief Data and methods for fully-assembled bilinear forms.
Not yet implemented! Use the BilinearForm Class instead. */
/// Data and methods for fully-assembled bilinear forms
class FABilinearFormExtension : public BilinearFormExtension
{
public:
@@ -83,6 +78,26 @@ public:
~FABilinearFormExtension() {}
};
/// Data and methods for element-assembled bilinear forms
class EABilinearFormExtension : public BilinearFormExtension
{
public:
EABilinearFormExtension(BilinearForm *form)
: BilinearFormExtension(form) { }
/// TODO
void Assemble() {}
void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A) {}
void FormLinearSystem(const Array<int> &ess_tdof_list,
Vector &x, Vector &b,
OperatorHandle &A, Vector &X, Vector &B,
int copy_interior = 0) {}
void Mult(const Vector &x, Vector &y) const {}
void MultTranspose(const Vector &x, Vector &y) const {}
void Update() {}
~EABilinearFormExtension() {}
};
/// Data and methods for partially-assembled bilinear forms
class PABilinearFormExtension : public BilinearFormExtension
{
@@ -98,6 +113,7 @@ protected:
public:
PABilinearFormExtension(BilinearForm*);
void SetupRestrictionOperators();
void Assemble();
void AssembleDiagonal(Vector &diag) const;
void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A);
@@ -105,34 +121,14 @@ public:
Vector &x, Vector &b,
OperatorHandle &A, Vector &X, Vector &B,
int copy_interior = 0);
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const;
void Update();
protected:
void SetupRestrictionOperators(const L2FaceValues m);
};
/// Data and methods for element-assembled bilinear forms
class EABilinearFormExtension : public PABilinearFormExtension
{
protected:
int ne;
int elemDofs;
Vector ea_data;
int nf_int, nf_bdr;
int faceDofs;
Vector ea_data_int, ea_data_ext, ea_data_bdr;
public:
EABilinearFormExtension(BilinearForm *form);
void Assemble();
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const;
};
/// Data and methods for matrix-free bilinear forms NOT YET IMPLEMENTED.
/// Data and methods for matrix-free bilinear forms
class MFBilinearFormExtension : public BilinearFormExtension
{
public:
@@ -152,12 +148,8 @@ public:
~MFBilinearFormExtension() {}
};
/// Class extending the MixedBilinearForm class to support different AssemblyLevels.
/** FA - Full Assembly
PA - Partial Assembly
EA - Element Assembly
MF - Matrix Free
*/
/** @brief Class extending the MixedBilinearForm class to support the different
AssemblyLevel%s. */
class MixedBilinearFormExtension : public Operator
{
protected:
@@ -194,8 +186,6 @@ public:
virtual void AddMultTranspose(const Vector &x, Vector &y,
const double c=1.0) const = 0;
virtual void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const = 0;
virtual void Update() = 0;
};
@@ -246,9 +236,6 @@ public:
void MultTranspose(const Vector &x, Vector &y) const;
/// y += c*A^T*x
void AddMultTranspose(const Vector &x, Vector &y, const double c=1.0) const;
/// Assemble the diagonal of ADA^T for a diagonal vector D.
void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const;
/// Update internals for when a new MixedBilinearForm is given to this class
void Update();
};
+28 -50
View File
@@ -47,37 +47,7 @@ void BilinearFormIntegrator::AssemblePABoundaryFaces(const FiniteElementSpace&)
void BilinearFormIntegrator::AssembleDiagonalPA(Vector &)
{
mfem_error ("BilinearFormIntegrator::AssembleDiagonalPA(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &emat)
{
mfem_error ("BilinearFormIntegrator::AssembleEA(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
&fes,
Vector &ea_data_int,
Vector &ea_data_ext)
{
mfem_error ("BilinearFormIntegrator::AssembleEAInteriorFaces(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace
&fes,
Vector &ea_data_bdr)
{
mfem_error ("BilinearFormIntegrator::AssembleEABoundaryFaces(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleDiagonalPA_ADAt(const Vector &, Vector &)
{
MFEM_ABORT("BilinearFormIntegrator::AssembleDiagonalPA_ADAt(...)\n"
MFEM_ABORT("BilinearFormIntegrator::AssembleDiagonalPA(...)\n"
" is not implemented for this class.");
}
@@ -919,7 +889,7 @@ void BoundaryMassIntegrator::AssembleFaceMatrix(
{
int order = 2 * el1.GetOrder();
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
elmat = 0.0;
@@ -930,11 +900,11 @@ void BoundaryMassIntegrator::AssembleFaceMatrix(
Trans.Loc1.Transform(ip, eip);
el1.CalcShape(eip, shape);
Trans.SetIntPoint(&ip);
w = Trans.Weight() * ip.weight;
Trans.Face->SetIntPoint(&ip);
w = Trans.Face->Weight() * ip.weight;
if (Q)
{
w *= Q -> Eval(Trans, ip);
w *= Q -> Eval(*Trans.Face, ip);
}
AddMult_a_VVt(w, shape, elmat);
@@ -2004,7 +1974,7 @@ void VectorFEMassIntegrator::AssembleElementMatrix2(
D.SetSize(VQ ? VQ->GetVDim() : 0);
K.SetSize(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0);
#endif
DenseMatrix tmp(test_vshape.Height(), K.Width());
DenseMatrix tmp(trial_vshape.Height(), K.Width());
elmat.SetSize (test_dof, trial_dof);
@@ -2565,7 +2535,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
{
order++;
}
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
@@ -2579,7 +2549,8 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
}
el1.CalcShape(eip1, shape1);
Trans.SetIntPoint(&ip);
Trans.Face->SetIntPoint(&ip);
Trans.Elem1->SetIntPoint(&eip1);
u->Eval(vu, *Trans.Elem1, eip1);
@@ -2589,7 +2560,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
}
else
{
CalcOrtho(Trans.Jacobian(), nor);
CalcOrtho(Trans.Face->Jacobian(), nor);
}
un = vu * nor;
@@ -2604,6 +2575,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
double rho_p;
if (un >= 0.0 && ndof2)
{
Trans.Elem2->SetIntPoint(&eip2);
rho_p = rho->Eval(*Trans.Elem2, eip2);
}
else
@@ -2719,7 +2691,7 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
{
order = 2*el1.GetOrder();
}
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
// assemble: < {(Q \nabla u).n},[v] > --> elmat
@@ -2730,18 +2702,19 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
IntegrationPoint eip1, eip2;
Trans.Loc1.Transform(ip, eip1);
Trans.SetIntPoint(&ip);
Trans.Face->SetIntPoint(&ip);
if (dim == 1)
{
nor(0) = 2*eip1.x - 1.0;
}
else
{
CalcOrtho(Trans.Jacobian(), nor);
CalcOrtho(Trans.Face->Jacobian(), nor);
}
el1.CalcShape(eip1, shape1);
el1.CalcDShape(eip1, dshape1);
Trans.Elem1->SetIntPoint(&eip1);
w = ip.weight/Trans.Elem1->Weight();
if (ndof2)
{
@@ -2790,6 +2763,7 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
Trans.Loc2.Transform(ip, eip2);
el2.CalcShape(eip2, shape2);
el2.CalcDShape(eip2, dshape2);
Trans.Elem2->SetIntPoint(&eip2);
w = ip.weight/2/Trans.Elem2->Weight();
if (!MQ)
{
@@ -2999,7 +2973,7 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
{
// a simple choice for the integration order; is this OK?
const int order = 2 * max(el1.GetOrder(), ndofs2 ? el2.GetOrder() : 0);
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
for (int pind = 0; pind < ir->GetNPoints(); ++pind)
@@ -3007,7 +2981,8 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
const IntegrationPoint &ip = ir->IntPoint(pind);
IntegrationPoint eip1, eip2; // integration point in the reference space
Trans.Loc1.Transform(ip, eip1);
Trans.SetIntPoint(&ip);
Trans.Face->SetIntPoint(&ip);
Trans.Elem1->SetIntPoint(&eip1);
el1.CalcShape(eip1, shape1);
el1.CalcDShape(eip1, dshape1);
@@ -3021,13 +2996,14 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
}
else
{
CalcOrtho(Trans.Jacobian(), nor);
CalcOrtho(Trans.Face->Jacobian(), nor);
}
double w, wLM;
if (ndofs2)
{
Trans.Loc2.Transform(ip, eip2);
Trans.Elem2->SetIntPoint(&eip2);
el2.CalcShape(eip2, shape2);
el2.CalcDShape(eip2, dshape2);
CalcAdjugate(Trans.Elem2->Jacobian(), adjJ);
@@ -3157,9 +3133,9 @@ void TraceJumpIntegrator::AssembleFaceMatrix(
order += trial_face_fe.GetOrder();
if (trial_face_fe.GetMapType() == FiniteElement::VALUE)
{
order += Trans.OrderW();
order += Trans.Face->OrderW();
}
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
@@ -3167,21 +3143,23 @@ void TraceJumpIntegrator::AssembleFaceMatrix(
const IntegrationPoint &ip = ir->IntPoint(p);
IntegrationPoint eip1, eip2;
// Trace finite element shape function
Trans.SetIntPoint(&ip);
Trans.Face->SetIntPoint(&ip);
trial_face_fe.CalcShape(ip, face_shape);
// Side 1 finite element shape function
Trans.Loc1.Transform(ip, eip1);
test_fe1.CalcShape(eip1, shape1);
Trans.Elem1->SetIntPoint(&eip1);
if (ndof2)
{
// Side 2 finite element shape function
Trans.Loc2.Transform(ip, eip2);
test_fe2.CalcShape(eip2, shape2);
Trans.Elem2->SetIntPoint(&eip2);
}
w = ip.weight;
if (trial_face_fe.GetMapType() == FiniteElement::VALUE)
{
w *= Trans.Weight();
w *= Trans.Face->Weight();
}
face_shape *= w;
for (i = 0; i < ndof1; i++)
@@ -3246,7 +3224,7 @@ void NormalTraceJumpIntegrator::AssembleFaceMatrix(
order = test_fe1.GetOrder() - 1;
}
order += trial_face_fe.GetOrder();
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
+2 -74
View File
@@ -57,9 +57,6 @@ public:
/// Assemble diagonal and add it to Vector @a diag.
virtual void AssembleDiagonalPA(Vector &diag);
/// Assemble diagonal of ADA^T (A is this integrator) and add it to @a diag.
virtual void AssembleDiagonalPA_ADAt(const Vector &D, Vector &diag);
/// Method for partially assembled action.
/** Perform the action of integrator on the input @a x and add the result to
the output @a y. Both @a x and @a y are E-vectors, i.e. they represent
@@ -78,22 +75,6 @@ public:
called. */
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
/// Method defining element assembly.
/** The result of the element assembly is added and stored in the @a emat
Vector. */
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
/** Used with BilinearFormIntegrators that have different spaces. */
// virtual void AssembleEA(const FiniteElementSpace &trial_fes,
// const FiniteElementSpace &test_fes,
// Vector &emat);
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
Vector &ea_data_bdr);
/// Given a particular Finite Element computes the element matrix elmat.
virtual void AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
@@ -199,8 +180,6 @@ public:
virtual ~BilinearFormIntegrator() { }
};
/** Wraps a given @a BilinearFormIntegrator and transposes the resulting element
matrices. See for example ex9, ex9p. */
class TransposeIntegrator : public BilinearFormIntegrator
{
private:
@@ -255,15 +234,6 @@ public:
bfi->AddMultTransposePA(x, y);
}
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
Vector &ea_data_bdr);
virtual ~TransposeIntegrator() { if (own_bfi) { delete bfi; } }
};
@@ -1565,7 +1535,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 or L2 and v is in H1. */
and where V is a vector coefficient, u is in H1 and v is in H1. */
class MixedScalarWeakDivergenceIntegrator : public MixedScalarVectorIntegrator
{
public:
@@ -1915,8 +1885,6 @@ public:
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleDiagonalPA(Vector &diag);
virtual void AddMultPA(const Vector&, Vector&) const;
@@ -1990,8 +1958,6 @@ public:
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleDiagonalPA(Vector &diag);
virtual void AddMultPA(const Vector&, Vector&) const;
@@ -2003,7 +1969,6 @@ 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:
@@ -2046,8 +2011,6 @@ public:
virtual void AssemblePA(const FiniteElementSpace&);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AddMultPA(const Vector&, Vector&) const;
static const IntegrationRule &GetRule(const FiniteElement &el,
@@ -2147,25 +2110,11 @@ class VectorFEDivergenceIntegrator : public BilinearFormIntegrator
protected:
Coefficient *Q;
using BilinearFormIntegrator::AssemblePA;
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes);
virtual void AddMultPA(const Vector&, Vector&) const;
virtual void AddMultTransposePA(const Vector&, Vector&) const;
private:
#ifndef MFEM_THREAD_SAFE
Vector divshape, shape;
#endif
// PA extension
Vector pa_data;
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *L2mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
int dim, ne, dofs1D, L2dofs1D, quad1D;
public:
VectorFEDivergenceIntegrator() { Q = NULL; }
VectorFEDivergenceIntegrator(Coefficient &q) { Q = &q; }
@@ -2176,8 +2125,6 @@ public:
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
virtual void AssembleDiagonalPA_ADAt(const Vector &D, Vector &diag);
};
@@ -2361,7 +2308,7 @@ protected:
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
const GeometricFactors *geom; ///< Not owned
int dim, ne, nq, dofs1D, quad1D, fetype;
int dim, ne, nq, dofs1D, quad1D;
public:
VectorFEMassIntegrator() { Init(NULL, NULL, NULL); }
@@ -2440,23 +2387,11 @@ class DivDivIntegrator: public BilinearFormIntegrator
protected:
Coefficient *Q;
using BilinearFormIntegrator::AssemblePA;
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AddMultPA(const Vector &x, Vector &y) const;
virtual void AssembleDiagonalPA(Vector& diag);
private:
#ifndef MFEM_THREAD_SAFE
Vector divshape;
#endif
// PA extension
Vector pa_data;
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
const GeometricFactors *geom; ///< Not owned
int dim, ne, dofs1D, quad1D;
public:
DivDivIntegrator() { Q = NULL; }
DivDivIntegrator(Coefficient &q) : Q(&q) { }
@@ -2609,13 +2544,6 @@ public:
virtual void AddMultPA(const Vector&, Vector&) const;
virtual void AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr);
static const IntegrationRule &GetRule(Geometry::Type geom, int order,
FaceElementTransformations &T);
-258
View File
@@ -1,258 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
template<int T_D1D = 0, int T_Q1D = 0>
static void EAConvectionAssemble1D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_Gi[MQ1];
double r_Bj[MQ1];
for (int q = 0; q < Q1D; q++)
{
r_Gi[q] = G(q,MFEM_THREAD_ID(x));
r_Bj[q] = B(q,MFEM_THREAD_ID(y));
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val += r_Bj[k1] * D(k1, e) * r_Gi[k1];
}
A(i1, j1, e) = val;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAConvectionAssemble2D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][2];
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2][0] = D(k1,k2,0,e);
s_D[k1][k2][1] = D(k1,k2,1,e);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val += (r_G[k1][i1] * r_B[k2][i2] * s_D[k1][k2][0]
+ r_B[k1][i1] * r_G[k2][i2] * s_D[k1][k2][1])
* r_B[k1][j1]* r_B[k2][j2];
}
}
A(i1, i2, j1, j2, e) = val;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAConvectionAssemble3D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 3, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
MFEM_FOREACH_THREAD(i3,z,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
for (int j3 = 0; j3 < D1D; ++j3)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
for (int k3 = 0; k3 < Q1D; ++k3)
{
double D0 = D(k1,k2,k3,0,e);
double D1 = D(k1,k2,k3,1,e);
double D2 = D(k1,k2,k3,2,e);
val += (r_G[k1][i1] * r_B[k2][i2] * r_B[k3][i3] * D0
+ r_B[k1][i1] * r_G[k2][i2] * r_B[k3][i3] * D1
+ r_B[k1][i1] * r_B[k2][i2] * r_G[k3][i3] * D2)
* r_B[k1][j1] * r_B[k2][j2] * r_B[k3][j3];
}
}
}
A(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
}
}
}
});
}
void ConvectionIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
const Array<double> &B = maps->B;
const Array<double> &G = maps->G;
if (dim == 1)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAConvectionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EAConvectionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EAConvectionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EAConvectionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EAConvectionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EAConvectionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EAConvectionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EAConvectionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAConvectionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EAConvectionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EAConvectionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EAConvectionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EAConvectionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EAConvectionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EAConvectionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EAConvectionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EAConvectionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
case 0x34: return EAConvectionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
case 0x45: return EAConvectionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
case 0x56: return EAConvectionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
case 0x67: return EAConvectionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
case 0x78: return EAConvectionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
case 0x89: return EAConvectionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
-414
View File
@@ -1,414 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
static void EADGTraceAssemble1DInt(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext)
{
auto D = Reshape(padata.Read(), 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), 2, NF);
MFEM_FORALL(f, NF,
{
double val_int0, val_int1, val_ext01, val_ext10;
val_int0 = D(0, 0, f);
val_ext10 = D(1, 0, f);
val_ext01 = D(0, 1, f);
val_int1 = D(1, 1, f);
A_int(0, f) += val_int0;
A_int(1, f) += val_int1;
A_ext(0, f) += val_ext01;
A_ext(1, f) += val_ext10;
});
}
static void EADGTraceAssemble1DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr)
{
auto D = Reshape(padata.Read(), 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), NF);
MFEM_FORALL(f, NF,
{
A_bdr(f) += D(0, 0, f);
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble2DInt(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), D1D, D1D, 2, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val_int0 = 0.0;
double val_int1 = 0.0;
double val_ext01 = 0.0;
double val_ext10 = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val_int0 += B(k1,i1) * B(k1,j1) * D(k1, 0, 0, f);
val_ext01 += B(k1,i1) * B(k1,j1) * D(k1, 0, 1, f);
val_ext10 += B(k1,i1) * B(k1,j1) * D(k1, 1, 0, f);
val_int1 += B(k1,i1) * B(k1,j1) * D(k1, 1, 1, f);
}
A_int(i1, j1, 0, f) += val_int0;
A_int(i1, j1, 1, f) += val_int1;
A_ext(i1, j1, 0, f) += val_ext01;
A_ext(i1, j1, 1, f) += val_ext10;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble2DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), D1D, D1D, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val_bdr = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val_bdr += B(k1,i1) * B(k1,j1) * D(k1, 0, 0, f);
}
A_bdr(i1, j1, f) += val_bdr;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble3DInt(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, D1D, D1D, 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), D1D, D1D, D1D, D1D, 2, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][2][2];
for (int i=0; i < 2; i++)
{
for (int j=0; j < 2; j++)
{
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2][i][j] = D(k1,k2,i,j,f);
}
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val_int0 = 0.0;
double val_int1 = 0.0;
double val_ext01 = 0.0;
double val_ext10 = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val_int0 += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][0][0];
val_int1 += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][1][1];
val_ext01+= r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][0][1];
val_ext10+= r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][1][0];
}
}
A_int(i1, i2, j1, j2, 0, f) += val_int0;
A_int(i1, i2, j1, j2, 1, f) += val_int1;
A_ext(i1, i2, j1, j2, 0, f) += val_ext01;
A_ext(i1, i2, j1, j2, 1, f) += val_ext10;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble3DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), D1D, D1D, D1D, D1D, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][2][2];
for (int i=0; i < 2; i++)
{
for (int j=0; j < 2; j++)
{
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2][i][j] = D(k1,k2,i,j,f);
}
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val_bdr = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val_bdr += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][0][0];
}
}
A_bdr(i1, i2, j1, j2, f) += val_bdr;
}
}
}
}
});
}
void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext)
{
SetupPA(fes, FaceType::Interior);
nf = fes.GetNFbyType(FaceType::Interior);
if (nf==0) { return; }
const Array<double> &B = maps->B;
if (dim == 1)
{
return EADGTraceAssemble1DInt(nf,B,pa_data,ea_data_int,ea_data_ext);
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22:
return EADGTraceAssemble2DInt<2,2>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x33:
return EADGTraceAssemble2DInt<3,3>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x44:
return EADGTraceAssemble2DInt<4,4>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x55:
return EADGTraceAssemble2DInt<5,5>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x66:
return EADGTraceAssemble2DInt<6,6>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x77:
return EADGTraceAssemble2DInt<7,7>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x88:
return EADGTraceAssemble2DInt<8,8>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x99:
return EADGTraceAssemble2DInt<9,9>(nf,B,pa_data,ea_data_int,
ea_data_ext);
default:
return EADGTraceAssemble2DInt(nf,B,pa_data,ea_data_int,
ea_data_ext,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23:
return EADGTraceAssemble3DInt<2,3>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x34:
return EADGTraceAssemble3DInt<3,4>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x45:
return EADGTraceAssemble3DInt<4,5>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x56:
return EADGTraceAssemble3DInt<5,6>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x67:
return EADGTraceAssemble3DInt<6,7>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x78:
return EADGTraceAssemble3DInt<7,8>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x89:
return EADGTraceAssemble3DInt<8,9>(nf,B,pa_data,ea_data_int,
ea_data_ext);
default:
return EADGTraceAssemble3DInt(nf,B,pa_data,ea_data_int,
ea_data_ext,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
void DGTraceIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr)
{
SetupPA(fes, FaceType::Boundary);
nf = fes.GetNFbyType(FaceType::Boundary);
if (nf==0) { return; }
const Array<double> &B = maps->B;
if (dim == 1)
{
return EADGTraceAssemble1DBdr(nf,B,pa_data,ea_data_bdr);
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADGTraceAssemble2DBdr<2,2>(nf,B,pa_data,ea_data_bdr);
case 0x33: return EADGTraceAssemble2DBdr<3,3>(nf,B,pa_data,ea_data_bdr);
case 0x44: return EADGTraceAssemble2DBdr<4,4>(nf,B,pa_data,ea_data_bdr);
case 0x55: return EADGTraceAssemble2DBdr<5,5>(nf,B,pa_data,ea_data_bdr);
case 0x66: return EADGTraceAssemble2DBdr<6,6>(nf,B,pa_data,ea_data_bdr);
case 0x77: return EADGTraceAssemble2DBdr<7,7>(nf,B,pa_data,ea_data_bdr);
case 0x88: return EADGTraceAssemble2DBdr<8,8>(nf,B,pa_data,ea_data_bdr);
case 0x99: return EADGTraceAssemble2DBdr<9,9>(nf,B,pa_data,ea_data_bdr);
default:
return EADGTraceAssemble2DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EADGTraceAssemble3DBdr<2,3>(nf,B,pa_data,ea_data_bdr);
case 0x34: return EADGTraceAssemble3DBdr<3,4>(nf,B,pa_data,ea_data_bdr);
case 0x45: return EADGTraceAssemble3DBdr<4,5>(nf,B,pa_data,ea_data_bdr);
case 0x56: return EADGTraceAssemble3DBdr<5,6>(nf,B,pa_data,ea_data_bdr);
case 0x67: return EADGTraceAssemble3DBdr<6,7>(nf,B,pa_data,ea_data_bdr);
case 0x78: return EADGTraceAssemble3DBdr<7,8>(nf,B,pa_data,ea_data_bdr);
case 0x89: return EADGTraceAssemble3DBdr<8,9>(nf,B,pa_data,ea_data_bdr);
default:
return EADGTraceAssemble3DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
-275
View File
@@ -1,275 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
template<int T_D1D = 0, int T_Q1D = 0>
static void EADiffusionAssemble1D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_Gi[MQ1];
double r_Gj[MQ1];
for (int q = 0; q < Q1D; q++)
{
r_Gi[q] = G(q,MFEM_THREAD_ID(x));
r_Gj[q] = G(q,MFEM_THREAD_ID(y));
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val += r_Gj[k1] * D(k1, e) * r_Gi[k1];
}
A(i1, j1, e) = val;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADiffusionAssemble2D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 3, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
double bgi = r_G[k1][i1] * r_B[k2][i2];
double gbi = r_B[k1][i1] * r_G[k2][i2];
double bgj = r_G[k1][j1] * r_B[k2][j2];
double gbj = r_B[k1][j1] * r_G[k2][j2];
double D00 = D(k1,k2,0,e);
double D10 = D(k1,k2,1,e);
double D01 = D10;
double D11 = D(k1,k2,2,e);
val += bgi * D00 * bgj
+ gbi * D01 * bgj
+ bgi * D10 * gbj
+ gbi * D11 * gbj;
}
}
A(i1, i2, j1, j2, e) = val;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADiffusionAssemble3D(const int NE,
const Array<double> &g,
const Array<double> &b,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 6, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
MFEM_FOREACH_THREAD(i3,z,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
for (int j3 = 0; j3 < D1D; ++j3)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
for (int k3 = 0; k3 < Q1D; ++k3)
{
double bbgi = r_G[k1][i1] * r_B[k2][i2] * r_B[k3][i3];
double bgbi = r_B[k1][i1] * r_G[k2][i2] * r_B[k3][i3];
double gbbi = r_B[k1][i1] * r_B[k2][i2] * r_G[k3][i3];
double bbgj = r_G[k1][j1] * r_B[k2][j2] * r_B[k3][j3];
double bgbj = r_B[k1][j1] * r_G[k2][j2] * r_B[k3][j3];
double gbbj = r_B[k1][j1] * r_B[k2][j2] * r_G[k3][j3];
double D00 = D(k1,k2,k3,0,e);
double D10 = D(k1,k2,k3,1,e);
double D20 = D(k1,k2,k3,2,e);
double D01 = D10;
double D11 = D(k1,k2,k3,3,e);
double D21 = D(k1,k2,k3,4,e);
double D02 = D20;
double D12 = D21;
double D22 = D(k1,k2,k3,5,e);
val += bbgi * D00 * bbgj
+ bgbi * D10 * bbgj
+ gbbi * D20 * bbgj
+ bbgi * D01 * bgbj
+ bgbi * D11 * bgbj
+ gbbi * D21 * bgbj
+ bbgi * D02 * gbbj
+ bgbi * D12 * gbbj
+ gbbi * D22 * gbbj;
}
}
}
A(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
}
}
}
});
}
void DiffusionIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
const Array<double> &B = maps->B;
const Array<double> &G = maps->G;
if (dim == 1)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADiffusionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EADiffusionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EADiffusionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EADiffusionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EADiffusionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EADiffusionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EADiffusionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EADiffusionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADiffusionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EADiffusionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EADiffusionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EADiffusionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EADiffusionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EADiffusionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EADiffusionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EADiffusionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EADiffusionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
case 0x34: return EADiffusionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
case 0x45: return EADiffusionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
case 0x56: return EADiffusionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
case 0x67: return EADiffusionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
case 0x78: return EADiffusionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
case 0x89: return EADiffusionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
+240 -77
View File
@@ -24,12 +24,12 @@ constexpr int HCURL_MAX_D1D = 5;
constexpr int HCURL_MAX_Q1D = 6;
// PA H(curl) Mass Assemble 2D kernel
void PAHcurlSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op)
static void PAHcurlSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op)
{
const int NQ = Q1D*Q1D;
auto W = w.Read();
@@ -55,12 +55,12 @@ void PAHcurlSetup2D(const int Q1D,
}
// PA H(curl) Mass Assemble 3D kernel
void PAHcurlSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op)
static void PAHcurlSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op)
{
const int NQ = Q1D*Q1D*Q1D;
auto W = w.Read();
@@ -106,16 +106,78 @@ void PAHcurlSetup3D(const int Q1D,
});
}
void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement *fel = fes.GetFE(0);
const VectorTensorFiniteElement *el =
dynamic_cast<const VectorTensorFiniteElement*>(fel);
MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*el, *el,
*mesh->GetElementTransformation(0));
const int dims = el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
Vector coeff(ne * nq);
coeff = 1.0;
if (Q)
{
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
static void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
{
constexpr static int VDIM = 2;
@@ -232,13 +294,13 @@ void PAHcurlMassApply2D(const int D1D,
}); // end of element loop
}
void PAHcurlMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag)
static void PAHcurlMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag)
{
constexpr static int VDIM = 2;
@@ -286,17 +348,15 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
}); // end of element loop
}
void PAHcurlMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag)
template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
static void PAHcurlMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag)
{
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
@@ -356,20 +416,28 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
}); // end of element loop
}
void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
{
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
if (dim == 3)
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
else
PAHcurlMassAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
static void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
{
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
@@ -547,6 +615,20 @@ void PAHcurlMassApply3D(const int D1D,
}); // end of element loop
}
void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
{
PAHcurlMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else
{
PAHcurlMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
}
// PA H(curl) curl-curl assemble 2D kernel
static void PACurlCurlSetup2D(const int Q1D,
const int NE,
@@ -1596,25 +1678,92 @@ void CurlCurlIntegrator::AssembleDiagonalPA(Vector& diag)
}
}
void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
&trial_fes,
const FiniteElementSpace &test_fes)
{
// Assumes tensor-product elements, with a vector test space and H^1 trial space.
Mesh *mesh = trial_fes.GetMesh();
const FiniteElement *trial_fel = trial_fes.GetFE(0);
const FiniteElement *test_fel = test_fes.GetFE(0);
const NodalTensorFiniteElement *trial_el =
dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
MFEM_VERIFY(trial_el != NULL, "Only NodalTensorFiniteElement is supported!");
const VectorTensorFiniteElement *test_el =
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
*mesh->GetElementTransformation(0));
const int dims = trial_el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
ne = trial_fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
Vector coeff(ne * nq);
coeff = 1.0;
if (Q)
{
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
// Use the same setup functions as VectorFEMassIntegrator.
if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
// Apply to x corresponding to DOF's in H^1 (trial), whose gradients are integrated
// against H(curl) test functions corresponding to y.
void PAHcurlH1Apply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
static void PAHcurlH1Apply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
{
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
@@ -1788,16 +1937,16 @@ void PAHcurlH1Apply3D(const int D1D,
// Apply to x corresponding to DOF's in H^1 (trial), whose gradients are integrated
// against H(curl) test functions corresponding to y.
void PAHcurlH1Apply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
static void PAHcurlH1Apply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
{
constexpr static int VDIM = 2;
@@ -1908,4 +2057,18 @@ void PAHcurlH1Apply2D(const int D1D,
}); // end of element loop
}
void MixedVectorGradientIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
PAHcurlH1Apply3D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
else if (dim == 2)
PAHcurlH1Apply2D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
} // namespace mfem
File diff suppressed because it is too large Load Diff
-255
View File
@@ -1,255 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
template<int T_D1D = 0, int T_Q1D = 0>
static void EAMassAssemble1D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto M = Reshape(eadata.Write(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_Bi[MQ1];
double r_Bj[MQ1];
for (int q = 0; q < Q1D; q++)
{
r_Bi[q] = B(q,MFEM_THREAD_ID(x));
r_Bj[q] = B(q,MFEM_THREAD_ID(y));
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val += r_Bi[k1] * r_Bj[k1] * D(k1, e);
}
M(i1, j1, e) = val;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAMassAssemble2D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, NE);
auto M = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1];
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2] = D(k1,k2,e);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2];
}
}
M(i1, i2, j1, j2, e) = val;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAMassAssemble3D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, NE);
auto M = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][MQ1];
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
MFEM_FOREACH_THREAD(k3,z,Q1D)
{
s_D[k1][k2][k3] = D(k1,k2,k3,e);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
MFEM_FOREACH_THREAD(i3,z,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
for (int j3 = 0; j3 < D1D; ++j3)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
for (int k3 = 0; k3 < Q1D; ++k3)
{
val += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* r_B[k3][i3] * r_B[k3][j3]
* s_D[k1][k2][k3];
}
}
}
M(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
}
}
}
});
}
void MassIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
const Array<double> &B = maps->B;
if (dim == 1)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAMassAssemble1D<2,2>(ne,B,pa_data,ea_data);
case 0x33: return EAMassAssemble1D<3,3>(ne,B,pa_data,ea_data);
case 0x44: return EAMassAssemble1D<4,4>(ne,B,pa_data,ea_data);
case 0x55: return EAMassAssemble1D<5,5>(ne,B,pa_data,ea_data);
case 0x66: return EAMassAssemble1D<6,6>(ne,B,pa_data,ea_data);
case 0x77: return EAMassAssemble1D<7,7>(ne,B,pa_data,ea_data);
case 0x88: return EAMassAssemble1D<8,8>(ne,B,pa_data,ea_data);
case 0x99: return EAMassAssemble1D<9,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble1D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAMassAssemble2D<2,2>(ne,B,pa_data,ea_data);
case 0x33: return EAMassAssemble2D<3,3>(ne,B,pa_data,ea_data);
case 0x44: return EAMassAssemble2D<4,4>(ne,B,pa_data,ea_data);
case 0x55: return EAMassAssemble2D<5,5>(ne,B,pa_data,ea_data);
case 0x66: return EAMassAssemble2D<6,6>(ne,B,pa_data,ea_data);
case 0x77: return EAMassAssemble2D<7,7>(ne,B,pa_data,ea_data);
case 0x88: return EAMassAssemble2D<8,8>(ne,B,pa_data,ea_data);
case 0x99: return EAMassAssemble2D<9,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble2D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EAMassAssemble3D<2,3>(ne,B,pa_data,ea_data);
case 0x34: return EAMassAssemble3D<3,4>(ne,B,pa_data,ea_data);
case 0x45: return EAMassAssemble3D<4,5>(ne,B,pa_data,ea_data);
case 0x56: return EAMassAssemble3D<5,6>(ne,B,pa_data,ea_data);
case 0x67: return EAMassAssemble3D<6,7>(ne,B,pa_data,ea_data);
case 0x78: return EAMassAssemble3D<7,8>(ne,B,pa_data,ea_data);
case 0x89: return EAMassAssemble3D<8,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble3D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
-103
View File
@@ -1,103 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
namespace mfem
{
void TransposeIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
Vector ea_data_tmp(ea_data.Size());
ea_data_tmp = 0.0;
bfi->AssembleEA(fes, ea_data_tmp);
const int ne = fes.GetNE();
if (ne == 0) { return; }
const int dofs = fes.GetFE(0)->GetDof();
auto A = Reshape(ea_data_tmp.Write(), dofs, dofs, ne);
auto AT = Reshape(ea_data.Write(), dofs, dofs, ne);
MFEM_FORALL(e, ne,
{
for (int i = 0; i < dofs; i++)
{
for (int j = 0; j < dofs; j++)
{
const double a = A(i, j, e);
AT(j, i, e) += a;
}
}
});
}
void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext)
{
const int nf = fes.GetNFbyType(FaceType::Interior);
if (nf == 0) { return; }
Vector ea_data_int_tmp(ea_data_int.Size());
Vector ea_data_ext_tmp(ea_data_ext.Size());
ea_data_int_tmp = 0.0;
ea_data_ext_tmp = 0.0;
bfi->AssembleEAInteriorFaces(fes, ea_data_int_tmp, ea_data_ext_tmp);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_int = Reshape(ea_data_int_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
auto AT_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
MFEM_FORALL(f, nf,
{
for (int i = 0; i < faceDofs; i++)
{
for (int j = 0; j < faceDofs; j++)
{
const double a_int0 = A_int(i, j, 0, f);
const double a_int1 = A_int(i, j, 1, f);
const double a_ext0 = A_ext(i, j, 0, f);
const double a_ext1 = A_ext(i, j, 1, f);
AT_int(j, i, 0, f) += a_int0;
AT_int(j, i, 1, f) += a_int1;
AT_ext(j, i, 0, f) += a_ext1;
AT_ext(j, i, 1, f) += a_ext0;
}
}
});
}
void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr)
{
const int nf = fes.GetNFbyType(FaceType::Boundary);
if (nf == 0) { return; }
Vector ea_data_bdr_tmp(ea_data_bdr.Size());
ea_data_bdr_tmp = 0.0;
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr_tmp);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
MFEM_FORALL(f, nf,
{
for (int i = 0; i < faceDofs; i++)
{
for (int j = 0; j < faceDofs; j++)
{
const double a_bdr = A_bdr(i, j, f);
AT_bdr(j, i, f) += a_bdr;
}
}
});
}
}
-379
View File
@@ -1,379 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "bilininteg.hpp"
namespace mfem
{
void PAHcurlSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHcurlSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHcurlMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHcurlMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHdivSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHdivSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHcurlH1Apply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHcurlH1Apply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHdivMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHdivMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHdivMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHdivMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement *fel = fes.GetFE(0);
const VectorTensorFiniteElement *el =
dynamic_cast<const VectorTensorFiniteElement*>(fel);
MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*el, *el,
*mesh->GetElementTransformation(0));
const int dims = el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
Vector coeff(ne * nq);
coeff = 1.0;
if (Q)
{
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
fetype = el->GetDerivType();
if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 3)
{
PAHdivSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 2)
{
PAHdivSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
{
if (dim == 3)
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassAssembleDiagonal3D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
else
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
}
void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
else
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
}
void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
&trial_fes,
const FiniteElementSpace &test_fes)
{
// Assumes tensor-product elements, with a vector test space and H^1 trial space.
Mesh *mesh = trial_fes.GetMesh();
const FiniteElement *trial_fel = trial_fes.GetFE(0);
const FiniteElement *test_fel = test_fes.GetFE(0);
const NodalTensorFiniteElement *trial_el =
dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
MFEM_VERIFY(trial_el != NULL, "Only NodalTensorFiniteElement is supported!");
const VectorTensorFiniteElement *test_el =
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
*mesh->GetElementTransformation(0));
const int dims = trial_el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
ne = trial_fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
Vector coeff(ne * nq);
coeff = 1.0;
if (Q)
{
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
// Use the same setup functions as VectorFEMassIntegrator.
if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
void MixedVectorGradientIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
PAHcurlH1Apply3D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
else if (dim == 2)
PAHcurlH1Apply2D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
} // namespace mfem
+26 -82
View File
@@ -49,7 +49,7 @@ double FunctionCoefficient::Eval(ElementTransformation & T,
double GridFunctionCoefficient::Eval (ElementTransformation &T,
const IntegrationPoint &ip)
{
return GridF -> GetValue (T, ip, Component);
return GridF -> GetValue (T.ElementNo, ip, Component);
}
double TransformedCoefficient::Eval(ElementTransformation &T,
@@ -160,13 +160,13 @@ void VectorArrayCoefficient::Eval(Vector &V, ElementTransformation &T,
}
VectorGridFunctionCoefficient::VectorGridFunctionCoefficient (
const GridFunction *gf)
GridFunction *gf)
: VectorCoefficient ((gf) ? gf -> VectorDim() : 0)
{
GridFunc = gf;
}
void VectorGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
void VectorGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
{
GridFunc = gf; vdim = (gf) ? gf -> VectorDim() : 0;
}
@@ -174,7 +174,24 @@ void VectorGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
void VectorGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
GridFunc->GetVectorValue(T, ip, V);
Mesh *mesh = GridFunc->FESpace()->GetMesh();
if (mesh->Dimension() == T.GetDimension())
{
GridFunc->GetVectorValue(T.ElementNo, ip, V);
}
else // Assuming T is a boundary element transformation
{
int el_id, el_info;
mesh->GetBdrElementAdjacentElement(T.ElementNo, el_id, el_info);
IntegrationPointTransformation loc_T;
mesh->GetLocalFaceTransformation(mesh->GetBdrElementType(T.ElementNo),
mesh->GetElementType(el_id),
loc_T.Transf,
el_info);
IntegrationPoint eip;
loc_T.Transform(ip, eip);
GridFunc->GetVectorValue(el_id, eip, V);
}
}
void VectorGridFunctionCoefficient::Eval(
@@ -184,14 +201,14 @@ void VectorGridFunctionCoefficient::Eval(
}
GradientGridFunctionCoefficient::GradientGridFunctionCoefficient (
const GridFunction *gf)
GridFunction *gf)
: VectorCoefficient((gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0)
{
GridFunc = gf;
}
void GradientGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
void GradientGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
{
GridFunc = gf; vdim = (gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0;
@@ -210,14 +227,14 @@ void GradientGridFunctionCoefficient::Eval(
}
CurlGridFunctionCoefficient::CurlGridFunctionCoefficient (
const GridFunction *gf)
GridFunction *gf)
: VectorCoefficient ((gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0)
{
GridFunc = gf;
}
void CurlGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
void CurlGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
{
GridFunc = gf; vdim = (gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0;
@@ -230,7 +247,7 @@ void CurlGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
}
DivergenceGridFunctionCoefficient::DivergenceGridFunctionCoefficient (
const GridFunction *gf) : Coefficient()
GridFunction *gf) : Coefficient()
{
GridFunc = gf;
}
@@ -285,22 +302,6 @@ void VectorRestrictedCoefficient::Eval(
}
}
void UnitNormalCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
V.SetSize(vdim);
V = 0.0;
const DenseMatrix & J = T.Jacobian();
if (J.Width() == J.Height() - 1)
{
CalcOrtho(J, V);
double norm = V.Norml2();
MFEM_ASSERT(norm > 0.0, "Length of normal vector is non-positive!");
V /= norm;
}
}
void MatrixFunctionCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
@@ -774,61 +775,4 @@ double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh,
}
#endif
VectorQuadratureFunctionCoefficient::VectorQuadratureFunctionCoefficient(
QuadratureFunction &qf)
: VectorCoefficient(qf.GetVDim()), QuadF(qf), index(0) { }
void VectorQuadratureFunctionCoefficient::SetComponent(int _index, int _length)
{
MFEM_VERIFY(_index >= 0, "Index must be >= 0");
MFEM_VERIFY(_index < QuadF.GetVDim(),
"Index must be < QuadratureFunction length");
index = _index;
MFEM_VERIFY(_length > 0, "Length must be > 0");
MFEM_VERIFY(_length <= QuadF.GetVDim() - index,
"Length must be <= (QuadratureFunction length - index)");
vdim = _length;
}
void VectorQuadratureFunctionCoefficient::Eval(Vector &V,
ElementTransformation &T,
const IntegrationPoint &ip)
{
QuadF.HostRead();
if (index == 0 && vdim == QuadF.GetVDim())
{
QuadF.GetElementValues(T.ElementNo, ip.index, V);
}
else
{
Vector temp;
QuadF.GetElementValues(T.ElementNo, ip.index, temp);
V.SetSize(vdim);
for (int i = 0; i < vdim; i++)
{
V(i) = temp(index + i);
}
}
return;
}
QuadratureFunctionCoefficient::QuadratureFunctionCoefficient(
QuadratureFunction &qf) : QuadF(qf)
{
MFEM_VERIFY(qf.GetVDim() == 1, "QuadratureFunction's vdim must be 1");
}
double QuadratureFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
QuadF.HostRead();
Vector temp(1);
QuadF.GetElementValues(T.ElementNo, ip.index, temp);
return temp[0];
}
}
+80 -346
View File
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -739,6 +739,12 @@ ParaViewDataCollection::ParaViewDataCollection(const std::string&
#endif
}
void ParaViewDataCollection::RegisterField(const std::string& field_name,
mfem::GridFunction *gf)
{
DataCollection::RegisterField(field_name,gf);
}
void ParaViewDataCollection::SetLevelsOfDetail(int levels_of_detail_)
{
levels_of_detail = levels_of_detail_;
@@ -809,7 +815,7 @@ void ParaViewDataCollection::Save()
// the directory is created
// create pvd file if needed
if (myid == 0 && !pvd_stream.is_open())
if (!pvd_stream.is_open())
{
std::string dpath=GenerateCollectionPath();
std::string pvdname=dpath+"/"+GeneratePVDFileName();
+4
View File
@@ -501,6 +501,10 @@ public:
ParaViewDataCollection(const std::string& collection_name,
mfem::Mesh *mesh_ = NULL);
/// Add a grid function to the collection
virtual void RegisterField(const std::string& field_name,
mfem::GridFunction *gf) override;
/// Set refinement levels - every element is uniformly split based on
/// levels_of_detail_
void SetLevelsOfDetail(int levels_of_detail_);
-73
View File
@@ -19,7 +19,6 @@ namespace mfem
ElementTransformation::ElementTransformation()
: IntPoint(static_cast<IntegrationPoint *>(NULL)),
EvalState(0),
geom(Geometry::INVALID),
Attribute(-1),
ElementNo(-1)
{ }
@@ -552,76 +551,4 @@ void IntegrationPointTransformation::Transform (const IntegrationRule &ir1,
}
}
void FaceElementTransformations::SetIntPoint(const IntegrationPoint *ip)
{
IsoparametricTransformation::SetIntPoint(ip);
if (Elem1)
{
Loc1.Transform(*ip, eip1);
Elem1->SetIntPoint(&eip1);
}
if (Elem2)
{
Loc2.Transform(*ip, eip2);
Elem2->SetIntPoint(&eip2);
}
}
ElementTransformation &
FaceElementTransformations::GetElement1Transformation()
{
MFEM_VERIFY(mask & 1 && Elem1 != NULL, "The ElementTransformation "
"for the element has not been configured for side 1.");
return *Elem1;
}
ElementTransformation &
FaceElementTransformations::GetElement2Transformation()
{
MFEM_VERIFY(mask & 2 && Elem2 != NULL, "The ElementTransformation "
"for the element has not been configured for side 2.");
return *Elem2;
}
IntegrationPointTransformation &
FaceElementTransformations::GetIntPoint1Transformation()
{
MFEM_VERIFY(mask & 4, "The IntegrationPointTransformation "
"for the element has not been configured for side 1.");
return Loc1;
}
IntegrationPointTransformation &
FaceElementTransformations::GetIntPoint2Transformation()
{
MFEM_VERIFY(mask & 8, "The IntegrationPointTransformation "
"for the element has not been configured for side 2.");
return Loc2;
}
void FaceElementTransformations::Transform(const IntegrationPoint &ip,
Vector &trans)
{
MFEM_VERIFY(mask & 16, "The ElementTransformation "
"for the face has not been configured.");
IsoparametricTransformation::Transform(ip, trans);
}
void FaceElementTransformations::Transform(const IntegrationRule &ir,
DenseMatrix &tr)
{
MFEM_VERIFY(mask & 16, "The ElementTransformation "
"for the face has not been configured.");
IsoparametricTransformation::Transform(ir, tr);
}
void FaceElementTransformations::Transform(const DenseMatrix &matrix,
DenseMatrix &result)
{
MFEM_VERIFY(mask & 16, "The ElementTransformation "
"for the face has not been configured.");
IsoparametricTransformation::Transform(matrix, result);
}
}
+19 -149
View File
@@ -38,12 +38,9 @@ protected:
};
Geometry::Type geom;
/** @brief Evaluate the Jacobian of the transformation at the IntPoint and
store it in dFdx. */
// 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();
@@ -51,53 +48,18 @@ protected:
const DenseMatrix &EvalInverseJ();
public:
/** This enumeration declares the values stored in
ElementTransformation::ElementType and indicates which group of objects
the index stored in ElementTransformation::ElementNo refers:
| ElementType | Range of ElementNo
+-------------+-------------------------
| ELEMENT | [0, Mesh::GetNE() )
| BDR_ELEMENT | [0, Mesh::GetNBE() )
| EDGE | [0, Mesh::GetNEdges() )
| FACE | [0, Mesh::GetNFaces() )
| BDR_FACE | [0, Mesh::GetNBE() )
*/
enum
{
ELEMENT = 1,
BDR_ELEMENT = 2,
EDGE = 3,
FACE = 4,
BDR_FACE = 5
};
int Attribute, ElementNo, ElementType;
int Attribute, ElementNo;
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;
/** @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. */
/// Transform columns of 'matrix', store result in 'result'.
virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result) = 0;
/** @brief Return the Jacobian matrix of the transformation at the currently
@@ -108,44 +70,27 @@ 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;
/// Return the order of \f$ adj(J)^T \nabla fi \f$
/// Order of adj(J)^t.grad(fi)
virtual int OrderGrad(const FiniteElement *fe) const = 0;
/// Return the Geometry::Type of the reference element.
Geometry::Type GetGeometryType() const { return geom; }
/// Return the topological dimension of the reference element.
/// Return the dimension of the reference element.
int GetDimension() const { return Geometry::Dimension[geom]; }
/// Get the dimension of the target (physical) space.
@@ -341,7 +286,7 @@ public:
virtual int Transform(const Vector &pt, IntegrationPoint &ip);
};
/// A standard isoparametric element transformation
class IsoparametricTransformation : public ElementTransformation
{
private:
@@ -351,29 +296,26 @@ private:
const FiniteElement *FElem;
DenseMatrix PointMat; // dim x dof
/** @brief Evaluate the Jacobian of the transformation at the IntPoint and
store it in dFdx. */
// 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$
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. */
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. */
void SetPointMat(const DenseMatrix &pm) { PointMat = pm; }
/// Return the stored point matrix.
@@ -382,44 +324,19 @@ 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);
@@ -439,62 +356,15 @@ public:
void Transform (const IntegrationRule &, IntegrationRule &);
};
class FaceElementTransformations : public IsoparametricTransformation
class FaceElementTransformations
{
private:
int mask;
IntegrationPoint eip1, eip2;
public:
int Elem1No, Elem2No;
Geometry::Type &FaceGeom; ///< @deprecated Use GetGeometryType instead
ElementTransformation *Elem1, *Elem2;
ElementTransformation *Face; ///< @deprecated No longer necessary
int Elem1No, Elem2No, FaceGeom;
ElementTransformation *Elem1, *Elem2, *Face;
IntegrationPointTransformation Loc1, Loc2;
FaceElementTransformations() : FaceGeom(geom), Face(this) {}
/** @brief Method to set the geometry type of the face.
@note This method is designed to be used when
[Par]Mesh::GetFaceTransformation will not be called i.e. when the face
transformation will not be needed but the neighboring element
transformations will be. Using this method to override the GeometryType
should only be done with great care.
*/
void SetGeometryType(Geometry::Type g) { geom = g; }
/// Set the mask indicating which portions of the object have been setup
/** The argument @a m is a bitmask used in
Mesh::GetFaceElementTransformations to indicate which portions of the
FaceElement Transformations object have been configured.
mask & 1: Elem1 is configured
mask & 2: Elem2 is configured
mask & 4: Loc1 is configured
mask & 8: Loc2 is configured
mask & 16: The Face transformation itself is configured
*/
void SetConfigurationMask(int m) { mask = m; }
int GetConfigurationMask() const { return mask; }
/** @brief Set the integration point in the Face and the two neighboring
elements, if present. */
void SetIntPoint(const IntegrationPoint *ip);
virtual void Transform(const IntegrationPoint &, Vector &);
virtual void Transform(const IntegrationRule &, DenseMatrix &);
virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result);
ElementTransformation & GetElement1Transformation();
ElementTransformation & GetElement2Transformation();
IntegrationPointTransformation & GetIntPoint1Transformation();
IntegrationPointTransformation & GetIntPoint2Transformation();
};
/** Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x))
/* Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x))
Physical Space
-17
View File
@@ -50,21 +50,4 @@ void L2ZienkiewiczZhuEstimator::ComputeEstimates()
#endif // MFEM_USE_MPI
void LpErrorEstimator::ComputeEstimates()
{
MFEM_VERIFY(coef != NULL || vcoef != NULL,
"LpErrorEstimator has no coefficient! Call SetCoef first.");
error_estimates.SetSize(sol->FESpace()->GetMesh()->GetNE());
if (coef)
{
sol->ComputeElementLpErrors(local_norm_p, *coef, error_estimates);
}
else
{
sol->ComputeElementLpErrors(local_norm_p, *vcoef, error_estimates);
}
current_sequence = sol->FESpace()->GetMesh()->GetSequence();
}
} // namespace mfem
-92
View File
@@ -45,7 +45,6 @@ public:
/// Force recomputation of the estimates on the next call to GetLocalErrors.
virtual void Reset() = 0;
/// Destruct the error estimator
virtual ~ErrorEstimator() { }
};
@@ -67,14 +66,6 @@ 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().
*/
@@ -226,7 +217,6 @@ 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,
@@ -314,88 +304,6 @@ public:
#endif // MFEM_USE_MPI
/** @brief The LpErrorEstimator class compares the solution to a known
coefficient.
This class can be used, for example, to adapt a mesh to a non-trivial
initial condition in a time-dependent simulation. It can also be used to
force refinement in the neighborhood of small features before switching to a
more traditional error estimator.
The LpErrorEstimator supports either scalar or vector coefficients and works
both in serial and in parallel.
*/
class LpErrorEstimator : public ErrorEstimator
{
protected:
long current_sequence;
int local_norm_p;
Vector error_estimates;
Coefficient * coef;
VectorCoefficient * vcoef;
GridFunction * sol;
/// Check if the mesh of the solution was modified.
bool MeshIsModified()
{
long mesh_sequence = sol->FESpace()->GetMesh()->GetSequence();
MFEM_ASSERT(mesh_sequence >= current_sequence, "");
return (mesh_sequence > current_sequence);
}
/// Compute the element error estimates.
void ComputeEstimates();
public:
/** @brief Construct a new LpErrorEstimator object for a scalar field.
@param p Integer which selects which Lp norm to use.
@param sol The GridFunction representation of the scalar field.
Note: the coefficient must be set before use with the SetCoef method.
*/
LpErrorEstimator(int p, GridFunction &sol)
: current_sequence(-1), local_norm_p(p),
error_estimates(0), coef(NULL), vcoef(NULL), sol(&sol) { }
/** @brief Construct a new LpErrorEstimator object for a scalar field.
@param p Integer which selects which Lp norm to use.
@param coef The scalar Coefficient to compare to the solution.
@param sol The GridFunction representation of the scalar field.
*/
LpErrorEstimator(int p, Coefficient &coef, GridFunction &sol)
: current_sequence(-1), local_norm_p(p),
error_estimates(0), coef(&coef), vcoef(NULL), sol(&sol) { }
/** @brief Construct a new LpErrorEstimator object for a vector field.
@param p Integer which selects which Lp norm to use.
@param coef The vector VectorCoefficient to compare to the solution.
@param sol The GridFunction representation of the vector field.
*/
LpErrorEstimator(int p, VectorCoefficient &coef, GridFunction &sol)
: current_sequence(-1), local_norm_p(p),
error_estimates(0), coef(NULL), vcoef(&coef), sol(&sol) { }
/** @brief Set the exponent, p, of the Lp norm used for computing the local
element errors. */
void SetLocalErrorNormP(int p) { local_norm_p = p; }
void SetCoef(Coefficient &A) { coef = &A; }
void SetCoef(VectorCoefficient &A) { vcoef = &A; }
/// Reset the error estimator.
virtual void Reset() { current_sequence = -1; }
/// Get a Vector with all element errors.
virtual const Vector &GetLocalErrors()
{
if (MeshIsModified()) { ComputeEstimates(); }
return error_estimates;
}
/// Destructor
virtual ~LpErrorEstimator() {}
};
} // namespace mfem
#endif // MFEM_ERROR_ESTIMATORS
+510 -519
View File
File diff suppressed because it is too large Load Diff
+189 -437
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -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] = 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]];
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]];
}
template <Geometry::Type geom, Geometry::Type f_geom,
+47 -176
View File
@@ -19,10 +19,10 @@
namespace mfem
{
/** @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. */
/** 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:
@@ -40,14 +40,6 @@ protected:
const int face_info);
public:
/** @brief Enumeration for ContType: defines the continuity of the field
across element interfaces. */
enum { CONTINUOUS, ///< Field is continuous across element interfaces
TANGENTIAL, ///< Tangential components of vector field
NORMAL, ///< Normal component of vector field
DISCONTINUOUS ///< Field is discontinuous across element interfaces
};
virtual const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const = 0;
@@ -60,8 +52,6 @@ public:
virtual const char * Name() const { return "Undefined"; }
virtual int GetContType() const = 0;
int HasFaceDofs(Geometry::Type GeomType) const;
virtual const FiniteElement *TraceFiniteElementForGeometry(
@@ -76,81 +66,15 @@ 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;
};
@@ -178,7 +102,6 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char *Name() const { return h1_name; }
virtual int GetContType() const { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const;
int GetBasisType() const { return b_type; }
@@ -188,8 +111,8 @@ public:
virtual ~H1_FECollection();
};
/** @brief Arbitrary order H1-conforming (continuous) finite elements with
positive basis functions. */
/** Arbitrary order H1-conforming (continuous) finite elements with positive
basis functions. */
class H1Pos_FECollection : public H1_FECollection
{
public:
@@ -197,7 +120,6 @@ 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
@@ -207,9 +129,9 @@ public:
: H1_FECollection(p, dim, BasisType::Serendipity) { };
};
/** @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. */
/** 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:
@@ -252,8 +174,6 @@ public:
int Or) const;
virtual const char *Name() const { return d_name; }
virtual int GetContType() const { return DISCONTINUOUS; }
virtual const FiniteElement *TraceFiniteElementForGeometry(
Geometry::Type GeomType) const
{
@@ -301,15 +221,14 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char *Name() const { return rt_name; }
virtual int GetContType() const { return NORMAL; }
FiniteElementCollection *GetTraceCollection() const;
virtual ~RT_FECollection();
};
/** @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. */
/** 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:
@@ -351,15 +270,14 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char *Name() const { return nd_name; }
virtual int GetContType() const { return TANGENTIAL; }
FiniteElementCollection *GetTraceCollection() const;
virtual ~ND_FECollection();
};
/** @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. */
/** 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:
@@ -416,15 +334,13 @@ public:
virtual const char *Name() const { return name; }
virtual int GetContType() const { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const;
virtual ~NURBSFECollection();
};
/// Piecewise-(bi/tri)linear continuous finite elements.
/// Piecewise-(bi)linear continuous finite elements.
class LinearFECollection : public FiniteElementCollection
{
private:
@@ -447,8 +363,6 @@ public:
int Or) const;
virtual const char * Name() const { return "Linear"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Piecewise-(bi)quadratic continuous finite elements.
@@ -475,8 +389,6 @@ public:
int Or) const;
virtual const char * Name() const { return "Quadratic"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Version of QuadraticFECollection with positive basis functions.
@@ -498,8 +410,6 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticPos"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Piecewise-(bi)cubic continuous finite elements.
@@ -527,8 +437,6 @@ public:
int Or) const;
virtual const char * Name() const { return "Cubic"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Crouzeix-Raviart nonconforming elements in 2D.
@@ -550,8 +458,6 @@ public:
int Or) const;
virtual const char * Name() const { return "CrouzeixRaviart"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Piecewise-linear nonconforming finite elements in 3D.
@@ -575,13 +481,11 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearNonConf3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief First order Raviart-Thomas finite elements in 2D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
/** 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:
@@ -600,12 +504,10 @@ public:
int Or) const;
virtual const char * Name() const { return "RT0_2D"; }
virtual int GetContType() const { return NORMAL; }
};
/** @brief Second order Raviart-Thomas finite elements in 2D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
/** 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:
@@ -624,12 +526,10 @@ public:
int Or) const;
virtual const char * Name() const { return "RT1_2D"; }
virtual int GetContType() const { return NORMAL; }
};
/** @brief Third order Raviart-Thomas finite elements in 2D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
/** 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:
@@ -648,13 +548,10 @@ public:
int Or) const;
virtual const char * Name() const { return "RT2_2D"; }
virtual int GetContType() const { return NORMAL; }
};
/** @brief Piecewise-constant discontinuous finite elements in 2D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
/** 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:
@@ -672,13 +569,10 @@ public:
int Or) const;
virtual const char * Name() const { return "Const2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-linear discontinuous finite elements in 2D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
/** 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:
@@ -697,8 +591,6 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Version of LinearDiscont2DFECollection with dofs in the Gaussian points.
@@ -721,8 +613,6 @@ public:
int Or) const;
virtual const char * Name() const { return "GaussLinearDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Linear (P1) finite elements on quadrilaterals.
@@ -738,12 +628,10 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char * Name() const { return "P1OnQuad"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-quadratic discontinuous finite elements in 2D. This class
is kept only for backward compatibility, consider using L2_FECollection
instead. */
/** 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:
@@ -762,7 +650,6 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Version of QuadraticDiscont2DFECollection with positive basis functions.
@@ -780,7 +667,6 @@ public:
int Or) const
{ return NULL; }
virtual const char * Name() const { return "QuadraticPosDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Version of QuadraticDiscont2DFECollection with dofs in the Gaussian points.
@@ -803,12 +689,10 @@ public:
int Or) const;
virtual const char * Name() const { return "GaussQuadraticDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-cubic discontinuous finite elements in 2D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
/** 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:
@@ -827,12 +711,10 @@ public:
int Or) const;
virtual const char * Name() const { return "CubicDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-constant discontinuous finite elements in 3D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
/** 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:
@@ -852,12 +734,10 @@ public:
int Or) const;
virtual const char * Name() const { return "Const3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-linear discontinuous finite elements in 3D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
/** 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:
@@ -876,12 +756,10 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearDiscont3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-quadratic discontinuous finite elements in 3D. This class
is kept only for backward compatibility, consider using L2_FECollection
instead. */
/** 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:
@@ -900,7 +778,6 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticDiscont3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Finite element collection on a macro-element.
@@ -926,12 +803,10 @@ public:
int Or) const;
virtual const char * Name() const { return "RefinedLinear"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/** @brief Lowest order Nedelec finite elements in 3D. This class is kept only
for backward compatibility, consider using the new ND_FECollection
instead. */
/** 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:
@@ -950,11 +825,10 @@ public:
int Or) const;
virtual const char * Name() const { return "ND1_3D"; }
virtual int GetContType() const { return TANGENTIAL; }
};
/** @brief First order Raviart-Thomas finite elements in 3D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
/** 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:
@@ -974,11 +848,10 @@ public:
int Or) const;
virtual const char * Name() const { return "RT0_3D"; }
virtual int GetContType() const { return NORMAL; }
};
/** @brief Second order Raviart-Thomas finite elements in 3D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
/** 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:
@@ -997,7 +870,6 @@ public:
int Or) const;
virtual const char * Name() const { return "RT1_3D"; }
virtual int GetContType() const { return NORMAL; }
};
/// Discontinuous collection defined locally by a given finite element.
@@ -1022,7 +894,6 @@ public:
virtual const char *Name() const { return d_name; }
virtual ~Local_FECollection() { delete Local_Element; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
}
+49 -175
View File
@@ -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), face_dof(NULL),
elem_dof(NULL), bdrElem_dof(NULL),
NURBSext(NULL), own_ext(false),
cP(NULL), cR(NULL), cP_is_set(false),
Th(Operator::ANY_TYPE),
@@ -233,54 +233,6 @@ 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;
@@ -1504,7 +1456,6 @@ 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);
@@ -1554,8 +1505,6 @@ NURBSExtension *FiniteElementSpace::StealNURBSext()
void FiniteElementSpace::UpdateNURBS()
{
MFEM_VERIFY(NURBSext, "NURBSExt not defined.");
nvdofs = 0;
nedofs = 0;
nfdofs = 0;
@@ -1563,10 +1512,6 @@ 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();
@@ -1574,55 +1519,6 @@ 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.
@@ -1630,7 +1526,6 @@ void FiniteElementSpace::Construct()
elem_dof = NULL;
bdrElem_dof = NULL;
face_dof = NULL;
ndofs = 0;
nedofs = nfdofs = nbdofs = 0;
@@ -1893,68 +1788,59 @@ void FiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
void FiniteElementSpace::GetFaceDofs(int i, Array<int> &dofs) const
{
// 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;
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)
// 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++)
{
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 (j = 0; j < nv; j++)
{
for (j = 0; j < nv; j++)
dofs[k*nv+j] = V[k]*nv+j;
}
}
}
nv *= V.Size();
if (ne > 0)
{
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[k*nv+j] = V[k]*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];
}
}
}
nv *= V.Size();
if (ne > 0)
}
ne = nv + ne * E.Size();
if (nf > 0)
{
for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++)
{
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;
}
dofs[ne+k] = j;
}
}
}
@@ -2083,21 +1969,14 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const
fe = fec->FiniteElementForGeometry(mesh->GetFaceBaseGeometry(i));
}
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);
}
// if (NURBSext)
// NURBSext->LoadFaceElement(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);
}
@@ -2145,14 +2024,11 @@ 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;
@@ -2739,9 +2615,7 @@ const Operator &InterpolationGridTransfer::BackwardOperator()
L2ProjectionGridTransfer::L2Projection::L2Projection(
const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_)
: Operator(fes_lor_.GetVSize(), fes_ho_.GetVSize()),
fes_ho(fes_ho_),
fes_lor(fes_lor_)
: fes_ho(fes_ho_), fes_lor(fes_lor_)
{
Mesh *mesh_ho = fes_ho.GetMesh();
MFEM_VERIFY(mesh_ho->GetNumGeometries(mesh_ho->Dimension()) <= 1,
+30 -75
View File
@@ -111,9 +111,7 @@ protected:
int *fdofs, *bdofs;
mutable Table *elem_dof; // if NURBS FE space, not owned; otherwise, 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.
Table *bdrElem_dof; // used only with NURBS FE spaces; not owned.
Array<int> dof_elem_array, dof_ldof_array;
@@ -160,14 +158,6 @@ 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)
@@ -216,7 +206,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.
@@ -235,12 +225,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;
@@ -258,13 +248,11 @@ protected:
/// Calculate GridFunction restriction matrix after mesh derefinement.
SparseMatrix* DerefinementMatrix(int old_ndofs, const Table* old_elem_dof);
/** @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. */
// 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;
@@ -479,11 +467,11 @@ public:
/// Returns indexes of degrees of freedom for i'th boundary element.
virtual void GetBdrElementDofs(int i, Array<int> &dofs) const;
/** @brief eturns the indexes of the degrees of freedom for i'th face
/** Returns 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;
/** @brief Returns the indexes of the degrees of freedom for i'th edge
/** 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;
@@ -538,59 +526,28 @@ 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();
/// 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(). */
const Table &GetElementToDofTable() const { return *elem_dof; }
const Table &GetBdrElementToDofTable() const { return *bdrElem_dof; }
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]; }
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th element in the mesh object. */
/// Returns pointer to the FiniteElement associated with i'th element.
const FiniteElement *GetFE(int i) const;
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th boundary face in the mesh object. */
/// Returns pointer to the FiniteElement for the i'th boundary element.
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;
/** @brief Mark degrees of freedom associated with boundary elements with
/** 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. */
@@ -598,7 +555,7 @@ public:
Array<int> &ess_vdofs,
int component = -1) const;
/** @brief Get a list of essential true dofs, ess_tdof_list, corresponding to the
/** 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. */
@@ -609,19 +566,19 @@ public:
/// Convert a Boolean marker array to a list containing all marked indices.
static void MarkerToList(const Array<int> &marker, Array<int> &list);
/** @brief Convert an array of indices (list) to a Boolean marker array where all
/** 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);
/** @brief For a partially conforming FE space, convert a marker array (nonzero
/** 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);
/** @brief For a partially conforming FE space, convert a marker array (nonzero
/** 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
@@ -629,15 +586,15 @@ public:
conforming dof. */
void ConvertFromConformingVDofs(const Array<int> &cdofs, Array<int> &dofs);
/** @brief Generate the global restriction matrix from a discontinuous
/** 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);
/** @brief Generate the global restriction matrix from a discontinuous
/** Generate the global restriction matrix from a discontinuous
FE space to the piecewise constant FE space. */
SparseMatrix *D2Const_GlobalRestrictionMatrix(FiniteElementSpace *cfes);
/** @brief Construct the restriction matrix from the FE space given by
/** 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);
@@ -674,7 +631,7 @@ public:
virtual void GetTrueTransferOperator(const FiniteElementSpace &coarse_fes,
OperatorHandle &T) const;
/** @brief Reflect changes in the mesh: update number of DOFs, etc. Also, calculate
/** 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);
@@ -712,7 +669,6 @@ 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
@@ -950,8 +906,7 @@ protected:
const L2Projection &l2proj;
public:
L2Prolongation(const L2Projection &l2proj_)
: Operator(l2proj_.Width(), l2proj_.Height()), l2proj(l2proj_) { }
L2Prolongation(const L2Projection &l2proj_) : l2proj(l2proj_) { }
void Mult(const Vector &x, Vector &y) const
{
l2proj.Prolongate(x, y);
+29 -372
View File
@@ -236,6 +236,7 @@ void GridFunction::MakeTRef(FiniteElementSpace *f, Vector &tv, int tv_offset)
}
}
void GridFunction::SumFluxAndCount(BilinearFormIntegrator &blfi,
GridFunction &flux,
Array<int>& count,
@@ -616,354 +617,17 @@ int GridFunction::GetFaceValues(int i, int side, const IntegrationRule &ir,
return dir;
}
void GridFunction::GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
Tr->Transform(ir, tr);
GetVectorValues(*Tr, ir, vals);
}
void be_to_bfe(Geometry::Type geom, int o, const IntegrationPoint &ip,
IntegrationPoint &fip)
{
if (geom == Geometry::TRIANGLE)
{
if (o == 2)
{
fip.x = 1.0 - ip.x - ip.y;
fip.y = ip.x;
}
else if (o == 4)
{
fip.x = ip.y;
fip.y = 1.0 - ip.x - ip.y;
}
else
{
fip.x = ip.x;
fip.y = ip.y;
}
fip.z = ip.z;
}
else
{
if (o == 2)
{
fip.x = ip.y;
fip.y = 1.0 - ip.x;
}
else if (o == 4)
{
fip.x = 1.0 - ip.x;
fip.y = 1.0 - ip.y;
}
else if (o == 6)
{
fip.x = 1.0 - ip.y;
fip.y = ip.x;
}
else
{
fip.x = ip.x;
fip.y = ip.y;
}
fip.z = ip.z;
}
fip.weight = ip.weight;
fip.index = ip.index;
}
double GridFunction::GetValue(ElementTransformation &T,
const IntegrationPoint &ip,
int comp, Vector *tr) const
{
if (tr)
{
T.SetIntPoint(&ip);
T.Transform(ip, *tr);
}
const FiniteElement * fe = NULL;
Array<int> dofs;
switch (T.ElementType)
{
case ElementTransformation::ELEMENT:
fe = fes->GetFE(T.ElementNo);
fes->GetElementDofs(T.ElementNo, dofs);
break;
case ElementTransformation::EDGE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetEdgeElement(T.ElementNo);
fes->GetEdgeDofs(T.ElementNo, dofs);
}
else
{
MFEM_ABORT("GridFunction::GetValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh edges.");
return NAN;
}
break;
case ElementTransformation::FACE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetFaceElement(T.ElementNo);
fes->GetFaceDofs(T.ElementNo, dofs);
}
else
{
MFEM_ABORT("GridFunction::GetValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh faces.");
return NAN;
}
break;
case ElementTransformation::BDR_ELEMENT:
{
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
// This is a continuous field so we can evaluate it on the boundary.
fe = fes->GetBE(T.ElementNo);
fes->GetBdrElementDofs(T.ElementNo, dofs);
}
else
{
// This is a discontinuous field which cannot be evaluated on the
// boundary so we'll evaluate it in the neighboring element.
FaceElementTransformations * FET =
fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo);
// Boundary elements and Boundary Faces may have different
// orientations so adjust the integration point if necessary.
int o = 0;
if (fes->GetMesh()->Dimension() == 3)
{
int f;
fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
}
IntegrationPoint fip;
be_to_bfe(FET->GetGeometryType(), o, ip, fip);
FET->SetIntPoint(&fip);
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetValue(T1, T1.GetIntPoint(), comp);
}
break;
}
case ElementTransformation::BDR_FACE:
{
FaceElementTransformations * FET =
dynamic_cast<FaceElementTransformations *>(&T);
// Evaluate in neighboring element for both continuous and
// discontinuous fields.
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetValue(T1, T1.GetIntPoint(), comp);
}
default:
{
MFEM_ABORT("GridFunction::GetValue: Unsupported element type \""
<< T.ElementType << "\"");
return NAN;
}
}
fes->DofsToVDofs(comp-1, dofs);
Vector DofVal(dofs.Size()), LocVec;
if (fe->GetMapType() == FiniteElement::VALUE)
{
fe->CalcShape(ip, DofVal);
}
else
{
fe->CalcPhysShape(T, DofVal);
}
GetSubVector(dofs, LocVec);
return (DofVal * LocVec);
}
void GridFunction::GetValues(ElementTransformation &T,
const IntegrationRule &ir,
Vector &vals, int comp,
DenseMatrix *tr) const
{
if (tr)
{
T.Transform(ir, *tr);
}
int nip = ir.GetNPoints();
vals.SetSize(nip);
for (int j = 0; j < nip; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
T.SetIntPoint(&ip);
vals[j] = GetValue(T, ip, comp);
}
}
void GridFunction::GetVectorValue(ElementTransformation &T,
const IntegrationPoint &ip,
Vector &val, Vector *tr) const
{
if (tr)
{
T.SetIntPoint(&ip);
T.Transform(ip, *tr);
}
Array<int> vdofs;
const FiniteElement *fe = NULL;
switch (T.ElementType)
{
case ElementTransformation::ELEMENT:
fes->GetElementVDofs(T.ElementNo, vdofs);
fe = fes->GetFE(T.ElementNo);
break;
case ElementTransformation::EDGE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetEdgeElement(T.ElementNo);
fes->GetEdgeVDofs(T.ElementNo, vdofs);
}
else
{
MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh edges.");
return;
}
break;
case ElementTransformation::FACE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetFaceElement(T.ElementNo);
fes->GetFaceVDofs(T.ElementNo, vdofs);
}
else
{
MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh faces.");
return;
}
break;
case ElementTransformation::BDR_ELEMENT:
{
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
// This is a continuous field so we can evaluate it on the boundary.
fes->GetBdrElementVDofs(T.ElementNo, vdofs);
fe = fes->GetBE(T.ElementNo);
}
else
{
// This is a discontinuous vector field which cannot be evaluated on
// the boundary so we'll evaluate it in the neighboring element.
FaceElementTransformations * FET =
fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo);
// Boundary elements and Boundary Faces may have different
// orientations so adjust the integration point if necessary.
int o = 0;
if (fes->GetMesh()->Dimension() == 3)
{
int f;
fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
}
IntegrationPoint fip;
be_to_bfe(FET->GetGeometryType(), o, ip, fip);
FET->SetIntPoint(&fip);
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetVectorValue(T1, T1.GetIntPoint(), val);
}
break;
}
case ElementTransformation::BDR_FACE:
{
FaceElementTransformations * FET =
dynamic_cast<FaceElementTransformations *>(&T);
// Evaluate in neighboring element for both continuous and
// discontinuous fields.
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetVectorValue(T1, T1.GetIntPoint(), val);
}
default:
{
MFEM_ABORT("GridFunction::GetVectorValue: Unsupported element type \""
<< T.ElementType << "\"");
if (val.Size() > 0) { val = NAN; }
return;
}
}
int dof = fe->GetDof();
Vector loc_data;
GetSubVector(vdofs, loc_data);
if (fe->GetRangeType() == FiniteElement::SCALAR)
{
Vector shape(dof);
if (fe->GetMapType() == FiniteElement::VALUE)
{
fe->CalcShape(ip, shape);
}
else
{
fe->CalcPhysShape(T, shape);
}
int vdim = fes->GetVDim();
val.SetSize(vdim);
for (int k = 0; k < vdim; k++)
{
val(k) = shape * ((const double *)loc_data + dof * k);
}
}
else
{
int spaceDim = fes->GetMesh()->SpaceDimension();
DenseMatrix vshape(dof, spaceDim);
fe->CalcVShape(T, vshape);
val.SetSize(spaceDim);
vshape.MultTranspose(loc_data, val);
}
}
void GridFunction::GetVectorValues(ElementTransformation &T,
const IntegrationRule &ir,
DenseMatrix &vals,
DenseMatrix *tr) const
DenseMatrix &vals) const
{
if (tr)
{
T.Transform(ir, *tr);
}
const FiniteElement *FElem = fes->GetFE(T.ElementNo);
int dof = FElem->GetDof();
Array<int> vdofs;
fes->GetElementVDofs(T.ElementNo, vdofs);
Vector loc_data;
GetSubVector(vdofs, loc_data);
int nip = ir.GetNPoints();
if (FElem->GetRangeType() == FiniteElement::SCALAR)
{
MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
@@ -975,7 +639,6 @@ void GridFunction::GetVectorValues(ElementTransformation &T,
{
const IntegrationPoint &ip = ir.IntPoint(j);
FElem->CalcShape(ip, shape);
for (int k = 0; k < vdim; k++)
{
vals(k,j) = shape * ((const double *)loc_data + dof * k);
@@ -986,22 +649,28 @@ void GridFunction::GetVectorValues(ElementTransformation &T,
{
int spaceDim = fes->GetMesh()->SpaceDimension();
DenseMatrix vshape(dof, spaceDim);
vals.SetSize(spaceDim, nip);
Vector val_j;
for (int j = 0; j < nip; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
T.SetIntPoint(&ip);
FElem->CalcVShape(T, vshape);
vals.GetColumnReference(j, val_j);
vshape.MultTranspose(loc_data, val_j);
}
}
}
void GridFunction::GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
Tr->Transform(ir, tr);
GetVectorValues(*Tr, ir, vals);
}
int GridFunction::GetFaceVectorValues(
int i, int side, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const
@@ -1033,13 +702,13 @@ int GridFunction::GetFaceVectorValues(
{
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 4);
Transf->Loc1.Transform(ir, eir);
GetVectorValues(*Transf->Elem1, eir, vals, &tr);
GetVectorValues(Transf->Elem1No, eir, vals, tr);
}
else
{
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 8);
Transf->Loc2.Transform(ir, eir);
GetVectorValues(*Transf->Elem2, eir, vals, &tr);
GetVectorValues(Transf->Elem2No, eir, vals, tr);
}
return di;
@@ -2047,8 +1716,6 @@ void GridFunction::ProjectCoefficient(
ElementTransformation *T = NULL;
const FiniteElement *fe = NULL;
fes->BuildDofToArrays(); // ensures GetElementForDof(), GetLocalDofForDof() initialized.
for (int i = 0; i < dofs.Size(); i++)
{
int dof = dofs[i], j = fes->GetElementForDof(dof);
@@ -2090,8 +1757,6 @@ void GridFunction::ProjectCoefficient(
Vector val;
fes->BuildDofToArrays(); // ensures GetElementForDof(), GetLocalDofForDof() initialized.
for (int i = 0; i < dofs.Size(); i++)
{
int dof = dofs[i], j = fes->GetElementForDof(dof);
@@ -2344,7 +2009,7 @@ double GridFunction::ComputeL2Error(
fdof = fe->GetDof();
transf = fes->GetElementTransformation(i);
shape.SetSize(fdof);
intorder = 2*fe->GetOrder() + 3; // <----------
intorder = 2*fe->GetOrder() + 1; // <----------
const IntegrationRule *ir;
if (irs)
{
@@ -2399,7 +2064,7 @@ double GridFunction::ComputeL2Error(
{
if (elems != NULL && (*elems)[i] == 0) { continue; }
fe = fes->GetFE(i);
int intorder = 2*fe->GetOrder() + 3; // <----------
int intorder = 2*fe->GetOrder() + 1; // <----------
const IntegrationRule *ir;
if (irs)
{
@@ -2503,7 +2168,7 @@ double GridFunction::ComputeH1Error(
}
intorder = 2 * intorder; // <-------------
const IntegrationRule &ir =
IntRules.Get(face_elem_transf->GetGeometryType(), intorder);
IntRules.Get(face_elem_transf->FaceGeom, intorder);
err_val.SetSize(ir.GetNPoints());
ell_coeff_val.SetSize(ir.GetNPoints());
// side 1
@@ -2560,7 +2225,7 @@ double GridFunction::ComputeH1Error(
}
}
face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
transf = face_elem_transf;
transf = face_elem_transf->Face;
for (j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
@@ -2594,7 +2259,7 @@ double GridFunction::ComputeMaxError(
fdof = fe->GetDof();
transf = fes->GetElementTransformation(i);
shape.SetSize(fdof);
intorder = 2*fe->GetOrder() + 3; // <----------
intorder = 2*fe->GetOrder() + 1; // <----------
const IntegrationRule *ir;
if (irs)
{
@@ -2760,7 +2425,7 @@ double GridFunction::ComputeLpError(const double p, Coefficient &exsol,
}
else
{
int intorder = 2*fe->GetOrder() + 3; // <----------
int intorder = 2*fe->GetOrder() + 1; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
GetValues(i, *ir, vals);
@@ -2807,13 +2472,10 @@ double GridFunction::ComputeLpError(const double p, Coefficient &exsol,
}
void GridFunction::ComputeElementLpErrors(const double p, Coefficient &exsol,
Vector &error,
GridFunction &error,
Coefficient *weight,
const IntegrationRule *irs[]) const
{
MFEM_ASSERT(error.Size() == fes->GetNE(),
"Incorrect size for result vector");
error = 0.0;
const FiniteElement *fe;
ElementTransformation *T;
@@ -2829,7 +2491,7 @@ void GridFunction::ComputeElementLpErrors(const double p, Coefficient &exsol,
}
else
{
int intorder = 2*fe->GetOrder() + 3; // <----------
int intorder = 2*fe->GetOrder() + 1; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
GetValues(i, *ir, vals);
@@ -2893,7 +2555,7 @@ double GridFunction::ComputeLpError(const double p, VectorCoefficient &exsol,
}
else
{
int intorder = 2*fe->GetOrder() + 3; // <----------
int intorder = 2*fe->GetOrder() + 1; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
T = fes->GetElementTransformation(i);
@@ -2965,14 +2627,11 @@ double GridFunction::ComputeLpError(const double p, VectorCoefficient &exsol,
void GridFunction::ComputeElementLpErrors(const double p,
VectorCoefficient &exsol,
Vector &error,
GridFunction &error,
Coefficient *weight,
VectorCoefficient *v_weight,
const IntegrationRule *irs[]) const
{
MFEM_ASSERT(error.Size() == fes->GetNE(),
"Incorrect size for result vector");
error = 0.0;
const FiniteElement *fe;
ElementTransformation *T;
@@ -2989,7 +2648,7 @@ void GridFunction::ComputeElementLpErrors(const double p,
}
else
{
int intorder = 2*fe->GetOrder() + 3; // <----------
int intorder = 2*fe->GetOrder() + 1; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
T = fes->GetElementTransformation(i);
@@ -2999,15 +2658,15 @@ void GridFunction::ComputeElementLpErrors(const double p,
loc_errs.SetSize(vals.Width());
if (!v_weight)
{
// compute the lengths of the errors at the integration points thus the
// vector norm is rotationally invariant
// compute the lengths of the errors at the integration points
// thus the vector norm is rotationally invariant
vals.Norm2(loc_errs);
}
else
{
v_weight->Eval(exact_vals, *T, *ir);
// column-wise dot product of the vector error (in vals) and the vector
// weight (in exact_vals)
// column-wise dot product of the vector error (in vals) and the
// vector weight (in exact_vals)
for (int j = 0; j < vals.Width(); j++)
{
double err = 0.0;
@@ -3139,9 +2798,7 @@ void GridFunction::SaveVTK(std::ostream &out, const std::string &field_name,
RefG = GlobGeometryRefiner.Refine(
mesh->GetElementBaseGeometry(i), ref, 1);
// GetVectorValues(i, RefG->RefPts, vval, pmat);
ElementTransformation * T = mesh->GetElementTransformation(i);
GetVectorValues(*T, RefG->RefPts, vval, &pmat);
GetVectorValues(i, RefG->RefPts, vval, pmat);
for (int j = 0; j < vval.Width(); j++)
{
+28 -161
View File
@@ -144,133 +144,17 @@ public:
/// Returns the values in the vertices of i'th element for dimension vdim.
void GetNodalValues(int i, Array<double> &nval, int vdim = 1) const;
/** @name Element index Get Value Methods
These methods take an element index and return the interpolated value of
the field at a given reference point within the element.
@warning These methods retrieve and use the ElementTransformation object
from the mfem::Mesh. This can alter the state of the element
transformation object and can also lead to unexpected results when the
ElementTransformation object is already in use such as when these methods
are called from within an integration loop. Consider using
GetValue(ElementTransformation &T, ...) instead.
*/
///@{
/** Return a scalar value from within the given element. */
virtual double GetValue(int i, const IntegrationPoint &ip,
int vdim = 1) const;
/** Return a vector value from within the given element. */
void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const;
///@}
/** @name Element Index Get Values Methods
These are convenience methods for repeatedly calling GetValue for
multiple points within a given element. The GetValues methods are
optimized and should perform better than repeatedly calling GetValue. The
GetVectorValues method simply calls GetVectorValue repeatedly.
@warning These methods retrieve and use the ElementTransformation object
from the mfem::Mesh. This can alter the state of the element
transformation object and can also lead to unexpected results when the
ElementTransformation object is already in use such as when these methods
are called from within an integration loop. Consider using
GetValues(ElementTransformation &T, ...) instead.
*/
///@{
/** Compute a collection of scalar values from within the element indicated
by the index i. */
void GetValues(int i, const IntegrationRule &ir, Vector &vals,
int vdim = 1) const;
/** Compute a collection of vector values from within the element indicated
by the index i. */
void GetValues(int i, const IntegrationRule &ir, Vector &vals,
DenseMatrix &tr, int vdim = 1) const;
void GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
///@}
/** @name ElementTransformation Get Value Methods
These member functions are designed for use within
GridFunctionCoefficient objects. These can be used with
ElementTransformation objects coming from either
Mesh::GetElementTransformation() or Mesh::GetBdrElementTransformation().
@note These methods do not reset the ElementTransformation object so they
should be safe to use within integration loops or other contexts where
the ElementTransformation is already in use.
*/
///@{
/** Return a scalar value from within the element indicated by the
ElementTransformation Object. */
double GetValue(ElementTransformation &T, const IntegrationPoint &ip,
int comp = 0, Vector *tr = NULL) const;
/** Return a vector value from within the element indicated by the
ElementTransformation Object. */
void GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip,
Vector &val, Vector *tr = NULL) const;
///@}
/** @name ElementTransformation Get Values Methods
These are convenience methods for repeatedly calling GetValue for
multiple points within a given element. They work by calling either the
ElementTransformation or FaceElementTransformations versions described
above. Consequently, these methods should not be expected to run faster
than calling the above methods in an external loop.
@note These methods do not reset the ElementTransformation object so they
should be safe to use within integration loops or other contexts where
the ElementTransformation is already in use.
@note These methods can also be used with FaceElementTransformations
objects.
*/
///@{
/** Compute a collection of scalar values from within the element indicated
by the ElementTransformation object. */
void GetValues(ElementTransformation &T, const IntegrationRule &ir,
Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const;
/** Compute a collection of vector values from within the element indicated
by the ElementTransformation object. */
void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix *tr = NULL) const;
///@}
/** @name Face Index Get Values Methods
These methods are designed to work with Discontinuous Galerkin basis
functions. They compute field values on the interface between elements,
or on boundary elements, by interpolating the field in a neighboring
element. The \a side argument indices which neighboring element should be
used: 0, 1, or 2 (automatically chosen).
@warning These methods retrieve and use the FaceElementTransformations
object from the mfem::Mesh. This can alter the state of the face element
transformations object and can also lead to unexpected results when the
FaceElementTransformations object is already in use such as when these
methods are called from within an integration loop. Consider using
GetValues(ElementTransformation &T, ...) instead.
*/
///@{
/** Compute a collection of scalar values from within the face
indicated by the index i. */
int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals,
DenseMatrix &tr, int vdim = 1) const;
/** Compute a collection of vector values from within the face
indicated by the index i. */
int GetFaceVectorValues(int i, int side, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
///@}
void GetLaplacians(int i, const IntegrationRule &ir, Vector &laps,
int vdim = 1) const;
@@ -283,6 +167,18 @@ public:
void GetHessians(int i, const IntegrationRule &ir, DenseMatrix &hess,
DenseMatrix &tr, int vdim = 1) const;
int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals,
DenseMatrix &tr, int vdim = 1) const;
void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir,
DenseMatrix &vals) const;
void GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
int GetFaceVectorValues(int i, int side, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
void GetValuesFrom(const GridFunction &orig_func);
void GetBdrValuesFrom(const GridFunction &orig_func);
@@ -340,10 +236,12 @@ public:
virtual void ProjectCoefficient(Coefficient &coeff);
// call fes -> BuildDofToArrays() before using this projection
void ProjectCoefficient(Coefficient &coeff, Array<int> &dofs, int vd = 0);
void ProjectCoefficient(VectorCoefficient &vcoeff);
// call fes -> BuildDofToArrays() before using this projection
void ProjectCoefficient(VectorCoefficient &vcoeff, Array<int> &dofs);
void ProjectCoefficient(Coefficient *coeff[]);
@@ -467,28 +365,28 @@ public:
const IntegrationRule *irs[] = NULL) const;
/** Compute the Lp error in each element of the mesh and store the results in
the Vector @a error. The result should be of length number of elements,
for example an L2 GridFunction of order zero using map type VALUE. */
the GridFunction @a error. The result should be an L2 GridFunction of
order zero using map type VALUE. */
virtual void ComputeElementLpErrors(const double p, Coefficient &exsol,
Vector &error,
GridFunction &error,
Coefficient *weight = NULL,
const IntegrationRule *irs[] = NULL
) const;
virtual void ComputeElementL1Errors(Coefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(1.0, exsol, error, NULL, irs); }
virtual void ComputeElementL2Errors(Coefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(2.0, exsol, error, NULL, irs); }
virtual void ComputeElementMaxErrors(Coefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(infinity(), exsol, error, NULL, irs); }
@@ -502,29 +400,29 @@ public:
const IntegrationRule *irs[] = NULL) const;
/** Compute the Lp error in each element of the mesh and store the results in
the Vector @ error. The result should be of length number of elements,
for example an L2 GridFunction of order zero using map type VALUE. */
the GridFunction @ error. The result should be an L2 GridFunction of
order zero using map type VALUE. */
virtual void ComputeElementLpErrors(const double p, VectorCoefficient &exsol,
Vector &error,
GridFunction &error,
Coefficient *weight = NULL,
VectorCoefficient *v_weight = NULL,
const IntegrationRule *irs[] = NULL
) const;
virtual void ComputeElementL1Errors(VectorCoefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(1.0, exsol, error, NULL, NULL, irs); }
virtual void ComputeElementL2Errors(VectorCoefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(2.0, exsol, error, NULL, NULL, irs); }
virtual void ComputeElementMaxErrors(VectorCoefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(infinity(), exsol, error, NULL, NULL, irs); }
@@ -598,13 +496,11 @@ public:
type = adios2stream::data_type::point_data) const;
#endif
/** @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
/** 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.
@@ -737,16 +633,6 @@ public:
*/
inline void GetElementValues(int idx, Vector &values) const;
/// Return the quadrature function values at an integration point.
/** The result is stored in the Vector @a values as a reference to the
global values. */
inline void GetElementValues(int idx, const int ip_num, Vector &values);
/// Return the quadrature function values at an integration point.
/** The result is stored in the Vector @a values as a copy to the
global values. */
inline void GetElementValues(int idx, const int ip_num, Vector &values) const;
/// Return all values associated with mesh element @a idx in a DenseMatrix.
/** The result is stored in the DenseMatrix @a values as a reference to the
global values.
@@ -851,25 +737,6 @@ inline void QuadratureFunction::GetElementValues(int idx, Vector &values) const
}
}
inline void QuadratureFunction::GetElementValues(int idx, const int ip_num,
Vector &values)
{
const int s_offset = qspace->element_offsets[idx] * vdim + ip_num * vdim;
values.NewDataAndSize(data + s_offset, vdim);
}
inline void QuadratureFunction::GetElementValues(int idx, const int ip_num,
Vector &values) const
{
const int s_offset = qspace->element_offsets[idx] * vdim + ip_num * vdim;
values.SetSize(vdim);
const double *q = data + s_offset;
for (int i = 0; i < values.Size(); i++)
{
values(i) = *(q++);
}
}
inline void QuadratureFunction::GetElementValues(int idx, DenseMatrix &values)
{
const int s_offset = qspace->element_offsets[idx];
+31 -99
View File
@@ -29,14 +29,12 @@ namespace mfem
{
FindPointsGSLIB::FindPointsGSLIB()
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
: mesh(NULL), ir_simplex(NULL), gsl_mesh(), fdata2D(NULL), fdata3D(NULL),
dim(-1)
{
gsl_comm = new comm;
#ifdef MFEM_USE_MPI
int initialized;
MPI_Initialized(&initialized);
if (!initialized) { MPI_Init(NULL, NULL); }
MPI_Init(NULL, NULL);
MPI_Comm comm = MPI_COMM_WORLD;;
comm_init(gsl_comm, comm);
#else
@@ -52,29 +50,28 @@ FindPointsGSLIB::~FindPointsGSLIB()
#ifdef MFEM_USE_MPI
FindPointsGSLIB::FindPointsGSLIB(MPI_Comm _comm)
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
: mesh(NULL), ir_simplex(NULL), gsl_mesh(), fdata2D(NULL), fdata3D(NULL),
dim(-1)
{
gsl_comm = new comm;
comm_init(gsl_comm, _comm);
}
#endif
void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
const int npt_max)
void FindPointsGSLIB::Setup(Mesh &m, double bb_t, double newt_tol, int npt_max)
{
MFEM_VERIFY(m.GetNodes() != NULL, "Mesh nodes are required.");
MFEM_VERIFY(m.GetNumGeometries(m.Dimension()) == 1,
"Mixed meshes are not currently supported in FindPointsGSLIB.");
// call FreeData if FindPointsGSLIB::Setup has been called already
if (setupflag) { FreeData(); }
mesh = &m;
dim = mesh->Dimension();
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
unsigned dof1D = fe->GetOrder() + 1;
const int gt = fe->GetGeomType();
int NE = mesh->GetNE(),
dof_cnt = fe->GetDof(),
pts_cnt = NE * dof_cnt,
gt = fe->GetGeomType();
if (gt == Geometry::TRIANGLE || gt == Geometry::TETRAHEDRON ||
gt == Geometry::PRISM)
@@ -90,8 +87,8 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
MFEM_ABORT("Element type not currently supported in FindPointsGSLIB.");
}
const int pts_cnt = gsl_mesh.Size()/dim,
NEtot = pts_cnt/(int)pow(dof1D, dim);
pts_cnt = gsl_mesh.Size()/dim;
int NEtot = pts_cnt/(int)pow(dof1D, dim);
if (dim == 2)
{
@@ -110,7 +107,6 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
fdata3D = findpts_setup_3(gsl_comm, elx, nr, NEtot, mr, bb_t,
pts_cnt, pts_cnt, npt_max, newt_tol);
}
setupflag = true;
}
void FindPointsGSLIB::FindPoints(const Vector &point_pos,
@@ -119,7 +115,6 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos,
Array<unsigned int> &elem_ids,
Vector &ref_pos, Vector &dist)
{
MFEM_VERIFY(setupflag, "Use FindPointsGSLIB::Setup before finding points.");
const int points_cnt = point_pos.Size() / dim;
if (dim == 2)
{
@@ -155,90 +150,34 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos,
}
}
void FindPointsGSLIB::FindPoints(const Vector &point_pos)
{
const int points_cnt = point_pos.Size() / dim;
gsl_code.SetSize(points_cnt);
gsl_proc.SetSize(points_cnt);
gsl_elem.SetSize(points_cnt);
gsl_ref.SetSize(points_cnt * dim);
gsl_dist.SetSize(points_cnt);
FindPoints(point_pos, gsl_code, gsl_proc, gsl_elem, gsl_ref, gsl_dist);
}
void FindPointsGSLIB::FindPoints(Mesh &m, const Vector &point_pos,
const double bb_t, const double newt_tol,
const int npt_max)
{
if (!setupflag || (mesh != &m) )
{
Setup(m, bb_t, newt_tol, npt_max);
}
FindPoints(point_pos);
}
void FindPointsGSLIB::Interpolate(Array<unsigned int> &codes,
Array<unsigned int> &proc_ids,
Array<unsigned int> &elem_ids,
Vector &ref_pos, const GridFunction &field_in,
Vector &field_out)
{
FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
GridFunction field_in_scalar(&ind_fes);
Vector node_vals;
GetNodeValues(field_in, node_vals);
const int ncomp = field_in.FESpace()->GetVDim(),
points_fld = field_in.Size() / ncomp,
points_cnt = codes.Size();
for (int i = 0; i < ncomp; i++)
const int points_cnt = ref_pos.Size() / dim;
if (dim==2)
{
const int dataptrin = i*points_fld,
dataptrout = i*points_cnt;
field_in_scalar.NewDataAndSize(field_in.GetData()+dataptrin, points_fld);
GetNodeValues(field_in_scalar, node_vals);
if (dim==2)
{
findpts_eval_2(field_out.GetData()+dataptrout, sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata2D);
}
else
{
findpts_eval_3(field_out.GetData()+dataptrout, sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata3D);
}
findpts_eval_2(field_out.GetData(), sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata2D);
}
else
{
findpts_eval_3(field_out.GetData(), sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata3D);
}
}
void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
Vector &field_out)
{
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::Interpolate(const Vector &point_pos,
const GridFunction &field_in, Vector &field_out)
{
FindPoints(point_pos);
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::Interpolate(Mesh &m, const Vector &point_pos,
const GridFunction &field_in, Vector &field_out)
{
FindPoints(m, point_pos);
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::FreeData()
@@ -251,13 +190,7 @@ void FindPointsGSLIB::FreeData()
{
findpts_free_3(fdata3D);
}
setupflag = false;
gsl_code.DeleteAll();
gsl_proc.DeleteAll();
gsl_elem.DeleteAll();
gsl_mesh.Destroy();
gsl_ref.Destroy();
gsl_dist.Destroy();
}
void FindPointsGSLIB::GetNodeValues(const GridFunction &gf_in,
@@ -359,7 +292,7 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
const GridFunction *nodes = mesh->GetNodes();
Mesh *meshsplit = NULL;
const int NE = mesh->GetNE();
int NEsplit = -1;
int NEsplit;
// Split the reference element into a reference submesh of quads or hexes.
if (gt == Geometry::TRIANGLE)
@@ -453,7 +386,6 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
}
meshsplit->FinalizeHexMesh(1, 1, true);
}
else { MFEM_ABORT("Unsupported geometry type."); }
// Curve the reference submesh.
H1_FECollection fec(fe->GetOrder(), dim);
+3 -30
View File
@@ -29,12 +29,10 @@ class FindPointsGSLIB
protected:
Mesh *mesh;
IntegrationRule *ir_simplex;
Vector gsl_mesh;
struct findpts_data_2 *fdata2D;
struct findpts_data_3 *fdata3D;
int dim;
Array<unsigned int> gsl_code, gsl_proc, gsl_elem;
Vector gsl_mesh, gsl_ref, gsl_dist;
bool setupflag;
struct comm *gsl_comm;
@@ -61,8 +59,7 @@ public:
@param[in] newt_tol Newton tolerance for the gslib search methods.
@param[in] npt_max Number of points for simultaneous iteration. This
alters performance and memory footprint. */
void Setup(Mesh &m, const double bb_t = 0.1, const double newt_tol = 1.0e-12,
const int npt_max = 256);
void Setup(Mesh &m, double bb_t, double newt_tol, int npt_max);
/** Searches positions given in physical space by @a point_pos. All output
Arrays and Vectors are expected to have the correct size.
@@ -76,15 +73,11 @@ public:
@param[out] ref_pos Reference coordinates of the found point. Ordered
by vdim (XYZ,XYZ,XYZ...).
Note: the gslib reference frame is [-1,1].
@param[out] dist Distance between the sought and the found point
@param[out] dist Distance between the seeked and the found point
in physical space. */
void FindPoints(const Vector &point_pos, Array<unsigned int> &codes,
Array<unsigned int> &proc_ids, Array<unsigned int> &elem_ids,
Vector &ref_pos, Vector &dist);
void FindPoints(const Vector &point_pos);
/// Setup FindPoints and search positions
void FindPoints(Mesh &m, const Vector &point_pos, const double bb_t = 0.1,
const double newt_tol = 1.0e-12, const int npt_max = 256);
/** Interpolation of field values at prescribed reference space positions.
@@ -103,31 +96,11 @@ public:
void Interpolate(Array<unsigned int> &codes, Array<unsigned int> &proc_ids,
Array<unsigned int> &elem_ids, Vector &ref_pos,
const GridFunction &field_in, Vector &field_out);
void Interpolate(const GridFunction &field_in, Vector &field_out);
/** Search positions and interpolate */
void Interpolate(const Vector &point_pos, const GridFunction &field_in,
Vector &field_out);
/** Setup FindPoints, search positions and interpolate */
void Interpolate(Mesh &m, const Vector &point_pos,
const GridFunction &field_in, Vector &field_out);
/** Cleans up memory allocated internally by gslib.
Note that in parallel, this must be called before MPI_Finalize(), as
it calls MPI_Comm_free() for internal gslib communicators. */
void FreeData();
/// Return code for each point searched by FindPoints: inside element (0), on
/// element boundary (1), or not found (2).
const Array<unsigned int> &GetCode() const { return gsl_code; }
/// Return element number for each point found by FindPoints.
const Array<unsigned int> &GetElem() const { return gsl_elem; }
/// Return MPI rank on which each point was found by FindPoints.
const Array<unsigned int> &GetProc() const { return gsl_proc; }
/// Return reference coordinates for each point found by FindPoints.
const Vector &GetReferencePosition() const { return gsl_ref; }
/// Return distance Distance between the sought and the found point
/// in physical space, for each point found by FindPoints.
const Vector &GetDist() const { return gsl_dist; }
};
} // namespace mfem
+1 -1
View File
@@ -40,7 +40,7 @@ struct CeedConstCoeff
struct CeedGridCoeff
{
const GridFunction* coeff;
GridFunction* coeff;
CeedBasis basis;
CeedElemRestriction restr;
CeedVector coeffVector;
+1 -1
View File
@@ -19,7 +19,7 @@
namespace mfem
{
/// Vector with associated FE space and LinearFormIntegrators.
/// Class for linear form - Vector with associated FE space and LFIntegrators.
class LinearForm : public Vector
{
protected:
+20 -77
View File
@@ -307,7 +307,7 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
if (ir == NULL)
{
int intorder = 2*el.GetOrder();
ir = &IntRules.Get(Tr.GetGeometryType(), intorder);
ir = &IntRules.Get(Tr.FaceGeom, intorder);
}
for (int i = 0; i < ir->GetNPoints(); i++)
@@ -316,11 +316,9 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
IntegrationPoint eip;
Tr.Loc1.Transform(ip, eip);
Tr.SetIntPoint(&ip);
// Use Tr transformation in case Q depends on boundary attribute
Q.Eval(vec, Tr, ip);
vec *= Tr.Weight() * ip.weight;
Tr.Face->SetIntPoint(&ip);
Q.Eval(vec, *Tr.Face, ip);
vec *= Tr.Face->Weight() * ip.weight;
el.CalcShape(eip, shape);
for (int k = 0; k < vdim; k++)
{
@@ -512,7 +510,7 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
{
order++;
}
ir = &IntRules.Get(Tr.GetGeometryType(), order);
ir = &IntRules.Get(Tr.FaceGeom, order);
}
shape.SetSize(ndof);
@@ -526,10 +524,8 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
Tr.Loc1.Transform(ip, eip);
el.CalcShape(eip, shape);
Tr.SetIntPoint(&ip);
Tr.Face->SetIntPoint(&ip);
// Use Tr.Elem1 transformation for u so that it matches the coefficient
// used with the ConvectionIntegrator and/or the DGTraceIntegrator.
u->Eval(vu, *Tr.Elem1, eip);
if (dim == 1)
@@ -538,12 +534,12 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
}
else
{
CalcOrtho(Tr.Jacobian(), nor);
CalcOrtho(Tr.Face->Jacobian(), nor);
}
un = vu * nor;
w = 0.5*alpha*un - beta*fabs(un);
w *= ip.weight*f->Eval(Tr, ip);
w *= ip.weight*f->Eval(*Tr.Elem1, eip);
elvect.Add(w, shape);
}
}
@@ -586,7 +582,7 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect(
{
// a simple choice for the integration order; is this OK?
int order = 2*el.GetOrder();
ir = &IntRules.Get(Tr.GetGeometryType(), order);
ir = &IntRules.Get(Tr.FaceGeom, order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
@@ -595,33 +591,33 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect(
IntegrationPoint eip;
Tr.Loc1.Transform(ip, eip);
Tr.SetIntPoint(&ip);
Tr.Face->SetIntPoint(&ip);
if (dim == 1)
{
nor(0) = 2*eip.x - 1.0;
}
else
{
CalcOrtho(Tr.Jacobian(), nor);
CalcOrtho(Tr.Face->Jacobian(), nor);
}
el.CalcShape(eip, shape);
el.CalcDShape(eip, dshape);
Tr.Elem1->SetIntPoint(&eip);
// compute uD through the face transformation
w = ip.weight * uD->Eval(Tr, ip) / Tr.Elem1->Weight();
w = ip.weight * uD->Eval(*Tr.Face, ip) / Tr.Elem1->Weight();
if (!MQ)
{
if (Q)
{
w *= Q->Eval(Tr, ip);
w *= Q->Eval(*Tr.Elem1, eip);
}
ni.Set(w, nor);
}
else
{
nh.Set(w, nor);
MQ->Eval(mq, Tr, ip);
MQ->Eval(mq, *Tr.Elem1, eip);
mq.MultTranspose(nh, ni);
}
CalcAdjugate(Tr.Elem1->Jacobian(), adjJ);
@@ -680,7 +676,7 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
if (ir == NULL)
{
const int order = 2*el.GetOrder(); // <-----
ir = &IntRules.Get(Tr.GetGeometryType(), order);
ir = &IntRules.Get(Tr.FaceGeom, order);
}
for (int pi = 0; pi < ir->GetNPoints(); ++pi)
@@ -688,10 +684,11 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
const IntegrationPoint &ip = ir->IntPoint(pi);
IntegrationPoint eip;
Tr.Loc1.Transform(ip, eip);
Tr.SetIntPoint(&ip);
Tr.Face->SetIntPoint(&ip);
Tr.Elem1->SetIntPoint(&eip);
// Evaluate the Dirichlet b.c. using the face transformation.
uD.Eval(u_dir, Tr, ip);
uD.Eval(u_dir, *Tr.Face, ip);
el.CalcShape(eip, shape);
el.CalcDShape(eip, dshape);
@@ -705,7 +702,7 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
}
else
{
CalcOrtho(Tr.Jacobian(), nor);
CalcOrtho(Tr.Face->Jacobian(), nor);
}
double wL, wM, jcoef;
@@ -771,58 +768,4 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
}
}
void VectorQuadratureLFIntegrator::AssembleRHSElementVect(
const FiniteElement &fe, ElementTransformation &Tr, Vector &elvect)
{
const IntegrationRule *ir =
&vqfc.GetQuadFunction().GetSpace()->GetElementIntRule(Tr.ElementNo);
const int nqp = ir->GetNPoints();
const int vdim = vqfc.GetVDim();
const int ndofs = fe.GetDof();
Vector shape(ndofs);
Vector temp(vdim);
elvect.SetSize(vdim * ndofs);
elvect = 0.0;
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir->IntPoint(q);
Tr.SetIntPoint(&ip);
const double w = Tr.Weight() * ip.weight;
vqfc.Eval(temp, Tr, ip);
fe.CalcShape(ip, shape);
for (int ind = 0; ind < vdim; ind++)
{
for (int nd = 0; nd < ndofs; nd++)
{
elvect(nd + ind * ndofs) += w * shape(nd) * temp(ind);
}
}
}
}
void QuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe,
ElementTransformation &Tr,
Vector &elvect)
{
const IntegrationRule *ir =
&qfc.GetQuadFunction().GetSpace()->GetElementIntRule(Tr.ElementNo);
const int nqp = ir->GetNPoints();
const int ndofs = fe.GetDof();
Vector shape(ndofs);
elvect.SetSize(ndofs);
elvect = 0.0;
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir->IntPoint(q);
Tr.SetIntPoint (&ip);
const double w = Tr.Weight() * ip.weight;
double temp = qfc.Eval(Tr, ip);
fe.CalcShape(ip, shape);
shape *= (w * temp);
elvect += shape;
}
}
}
+1 -64
View File
@@ -36,7 +36,7 @@ public:
FaceElementTransformations &Tr,
Vector &elvect);
virtual void SetIntRule(const IntegrationRule *ir) { IntRule = ir; }
void SetIntRule(const IntegrationRule *ir) { IntRule = ir; }
const IntegrationRule* GetIntRule() { return IntRule; }
virtual ~LinearFormIntegrator() { }
@@ -426,69 +426,6 @@ public:
Vector &elvect);
};
/** Class for domain integration of L(v) := (f, v), where
f=(f1,...,fn) and v=(v1,...,vn). that makes use of
VectorQuadratureFunctionCoefficient*/
class VectorQuadratureLFIntegrator : public LinearFormIntegrator
{
private:
VectorQuadratureFunctionCoefficient &vqfc;
public:
VectorQuadratureLFIntegrator(VectorQuadratureFunctionCoefficient &vqfc,
const IntegrationRule *ir)
: LinearFormIntegrator(ir), vqfc(vqfc)
{
if (ir)
{
MFEM_WARNING("Integration rule not used in this class. "
"The QuadratureFunction integration rules are used instead");
}
}
using LinearFormIntegrator::AssembleRHSElementVect;
virtual void AssembleRHSElementVect(const FiniteElement &fe,
ElementTransformation &Tr,
Vector &elvect);
virtual void SetIntRule(const IntegrationRule *ir)
{
MFEM_WARNING("Integration rule not used in this class. "
"The QuadratureFunction integration rules are used instead");
}
};
/** Class for domain integration L(v) := (f, v) that makes use
of QuadratureFunctionCoefficient. */
class QuadratureLFIntegrator : public LinearFormIntegrator
{
private:
QuadratureFunctionCoefficient &qfc;
public:
QuadratureLFIntegrator(QuadratureFunctionCoefficient &qfc,
const IntegrationRule *ir)
: LinearFormIntegrator(ir), qfc(qfc)
{
if (ir)
{
MFEM_WARNING("Integration rule not used in this class. "
"The QuadratureFunction integration rules are used instead");
}
}
using LinearFormIntegrator::AssembleRHSElementVect;
virtual void AssembleRHSElementVect(const FiniteElement &fe,
ElementTransformation &Tr,
Vector &elvect);
virtual void SetIntRule(const IntegrationRule *ir)
{
MFEM_WARNING("Integration rule not used in this class. "
"The QuadratureFunction integration rules are used instead");
}
};
}
#endif
+4 -3
View File
@@ -20,9 +20,10 @@
namespace mfem
{
/** @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. */
/** 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. */
class NonlinearFormIntegrator
{
protected:
-5
View File
@@ -487,11 +487,6 @@ 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())
{
+1 -1
View File
@@ -376,7 +376,7 @@ public:
void PrintPartitionStats();
/// Obsolete, kept for backward compatibility
// Obsolete, kept for backward compatibility
int TrueVSize() const { return ltdof_size; }
};
+420 -2
View File
@@ -16,6 +16,7 @@
#include "fem.hpp"
#include <iostream>
#include <limits>
#include <string>
#include "../general/forall.hpp"
using namespace std;
@@ -78,6 +79,229 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, std::istream &input)
fes = pfes;
}
ParGridFunction::ParGridFunction(ParFiniteElementSpace *pf,
const char *_filename)
: GridFunction(pf), pfes(pf)
{
MPI_Comm fes_comm;
int fes_rank, n_fes_ranks;
fes_comm = pfes->GetComm();
MPI_Comm_size(fes_comm, &n_fes_ranks);
MPI_Comm_rank(fes_comm, &fes_rank);
std::string filename(_filename);
std::string file_prefix;
std::string file_ext;
{
size_t i = filename.rfind('.', filename.length());
if (i != string::npos)
{
file_prefix = (filename.substr(0, i));
file_ext = (filename.substr(i, filename.length() - i));
}
}
int nfiles = 1;
if (fes_rank == 0)
{
int n_rfes_ranks;
int tmp[2];
std::string mpi_filename;
size_t i = filename.rfind('.', filename.length());
if (i != string::npos)
{
mpi_filename = file_prefix + to_string(0) + file_ext;
}
else
{
mpi_filename = filename + to_string(0);
}
MPI_File fh;
MPI_File_open(MPI_COMM_SELF, mpi_filename.c_str(), MPI_MODE_RDONLY,
MPI_INFO_NULL, &fh);
MPI_File_read_at(fh, 0, tmp, 2, MPI_INT, MPI_STATUS_IGNORE);
MPI_File_close(&fh);
n_rfes_ranks = tmp[0];
nfiles = tmp[1];
MFEM_ASSERT(n_fes_ranks == n_rfes_ranks,
"ParGridFunction::ParGridFunction(ParFiniteElementSpace *pf,"
" const char *_filename):\n"
"\tThe number of MPI ranks used to save the GridFunction is\n"
"\tnot the same as the number used to load it!");
}
MPI_Bcast(&nfiles, 1, MPI_INT, 0, fes_comm);
int color = fes_rank * nfiles / n_fes_ranks;
MPI_Comm file_comm;
MPI_Comm_split(fes_comm, color, fes_rank, &file_comm);
int file_rank, n_file_ranks;
MPI_Comm_size(file_comm, &n_file_ranks);
MPI_Comm_rank(file_comm, &file_rank);
std::string mpi_filename;
{
size_t i = filename.rfind('.', filename.length());
if (i != string::npos) {
mpi_filename = file_prefix + std::to_string(color) + file_ext;
}
else
{
mpi_filename = filename + std::to_string(color);
}
}
MPI_File fh;
MPI_File_open(file_comm, mpi_filename.c_str(), MPI_MODE_RDONLY,
MPI_INFO_NULL, &fh);
int *dof_counts = new int[5*n_file_ranks];
int **nv = new int*[n_file_ranks];
int **nvdofs = new int*[n_file_ranks];
int **nedofs = new int*[n_file_ranks];
int **nfdofs = new int*[n_file_ranks];
int **nrdofs = new int*[n_file_ranks];
for (int i = 0; i < n_file_ranks; ++i)
{
nv[i] = &dof_counts[i*5+0];
nvdofs[i] = &dof_counts[i*5+1];
nedofs[i] = &dof_counts[i*5+2];
nfdofs[i] = &dof_counts[i*5+3];
nrdofs[i] = &dof_counts[i*5+4];
}
*nv[file_rank] = pfes->GetVSize();
*nvdofs[file_rank] = pfes->GetNVDofs();
*nedofs[file_rank] = pfes->GetNEDofs();
*nfdofs[file_rank] = pfes->GetNFDofs();
int vdim = pfes->GetVDim();
*nrdofs[file_rank] = *nv[file_rank] / vdim - *nvdofs[file_rank] -
*nedofs[file_rank] - *nfdofs[file_rank];
MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, &dof_counts[0], 5,
MPI_INT, file_comm);
double *data_ = HostWrite();
MPI_Offset header_offset = 0;
header_offset += 2 * sizeof(int);
MPI_Offset v_offset, e_offset, f_offset, r_offset;
int total_vdofs = 0, total_edofs = 0, total_fdofs = 0, total_rdofs = 0;
int total_scalar_dofs = 0;
for (int i = 0; i < n_file_ranks; ++i)
{
total_vdofs += *nvdofs[i];
total_edofs += *nedofs[i];
total_fdofs += *nfdofs[i];
total_rdofs += *nrdofs[i];
total_scalar_dofs += *nv[i];
}
total_scalar_dofs /= vdim;
if (pfes->GetOrdering() == Ordering::byNODES)
{
for (int d = 0; d < vdim; ++d)
{
int v_data_offset = 0 + *nv[file_rank] * d / vdim ;
int e_data_offset = v_data_offset + *nvdofs[file_rank];
int f_data_offset = e_data_offset + *nedofs[file_rank];
int r_data_offset = f_data_offset + *nfdofs[file_rank];
v_offset = header_offset;
e_offset = header_offset;
f_offset = header_offset;
r_offset = header_offset;
v_offset += total_scalar_dofs * d * sizeof(double);
e_offset += (total_vdofs + total_scalar_dofs * d) * sizeof(double);
f_offset += (total_vdofs + total_edofs +
total_scalar_dofs * d) * sizeof(double);
r_offset += (total_vdofs + total_edofs + total_fdofs +
total_scalar_dofs * d) * sizeof(double);
for (int i = 0; i < file_rank; ++i)
{
v_offset += *nvdofs[i] * sizeof(double);
e_offset += *nedofs[i] * sizeof(double);
f_offset += *nfdofs[i] * sizeof(double);
r_offset += *nrdofs[i] * sizeof(double);
}
MPI_File_read_at_all(fh, v_offset, &data_[v_data_offset],
*nvdofs[file_rank], MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_read_at_all(fh, e_offset, &data_[e_data_offset],
*nedofs[file_rank], MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_read_at_all(fh, f_offset, &data_[f_data_offset],
*nfdofs[file_rank], MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_read_at_all(fh, r_offset, &data_[r_data_offset],
*nrdofs[file_rank], MPI_DOUBLE,
MPI_STATUS_IGNORE);
}
}
else
{
v_offset = header_offset;
e_offset = v_offset + total_vdofs * vdim * sizeof(double);
f_offset = e_offset + total_edofs * vdim * sizeof(double);
r_offset = f_offset + total_fdofs * vdim * sizeof(double);
for (int i = 0; i < file_rank; ++i)
{
v_offset += *nvdofs[i] * sizeof(double) * vdim;
e_offset += *nedofs[i] * sizeof(double) * vdim;
f_offset += *nfdofs[i] * sizeof(double) * vdim;
r_offset += *nrdofs[i] * sizeof(double) * vdim;
}
int v_data_offset = 0;
int e_data_offset = v_data_offset + *nvdofs[file_rank] * vdim;
int f_data_offset = e_data_offset + *nedofs[file_rank] * vdim;
int r_data_offset = f_data_offset + *nfdofs[file_rank] * vdim;
MPI_File_read_at_all(fh, v_offset, &data_[v_data_offset],
*nvdofs[file_rank] * vdim, MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_read_at_all(fh, e_offset, &data_[e_data_offset],
*nedofs[file_rank] * vdim, MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_read_at_all(fh, f_offset, &data_[f_data_offset],
*nfdofs[file_rank] * vdim, MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_read_at_all(fh, r_offset, &data_[r_data_offset],
*nrdofs[file_rank] * vdim, MPI_DOUBLE,
MPI_STATUS_IGNORE);
}
MPI_File_close(&fh);
MPI_Comm_free(&file_comm);
for (int i = 0; i < size; i++)
{
if (pfes->GetDofSign(i) < 0) { data_[i] = -data_[i]; }
}
delete[] dof_counts;
delete[] nv;
delete[] nvdofs;
delete[] nedofs;
delete[] nfdofs;
delete[] nrdofs;
}
void ParGridFunction::Update()
{
face_nbr_data.Destroy();
@@ -232,8 +456,7 @@ void ParGridFunction::ExchangeFaceNbrData()
auto d_send_data = send_data.Write();
MFEM_FORALL(i, send_data.Size(),
{
const int ldof = d_send_ldof[i];
d_send_data[i] = d_data[ldof >= 0 ? ldof : -1-ldof];
d_send_data[i] = d_data[d_send_ldof[i]];
});
bool mpi_gpu_aware = Device::GetGPUAwareMPI();
@@ -519,6 +742,201 @@ void ParGridFunction::Save(adios2stream &out,
}
#endif
void ParGridFunction::Save(const char *_filename, const int nfiles)
{
MPI_Comm fes_comm;
int fes_rank, n_fes_ranks;
fes_comm = pfes->GetComm();
MPI_Comm_size(fes_comm, &n_fes_ranks);
MPI_Comm_rank(fes_comm, &fes_rank);
int color = fes_rank * nfiles / n_fes_ranks;
MPI_Comm file_comm;
MPI_Comm_split(fes_comm, color, fes_rank, &file_comm);
int file_rank, n_file_ranks;
MPI_Comm_size(file_comm, &n_file_ranks);
MPI_Comm_rank(file_comm, &file_rank);
std::string filename(_filename);
std::string file_prefix;
std::string file_ext;
std::string mpi_filename;
{
size_t i = filename.rfind('.', filename.length());
if (i != string::npos)
{
file_prefix = (filename.substr(0, i));
file_ext = (filename.substr(i, filename.length() - i));
mpi_filename = file_prefix + std::to_string(color) + file_ext;
}
else
{
mpi_filename = filename + std::to_string(color);
}
}
MPI_File fh;
MPI_File_open(file_comm, mpi_filename.c_str(), MPI_MODE_CREATE |
MPI_MODE_WRONLY,
MPI_INFO_NULL, &fh);
int *dof_counts = new int[5*n_file_ranks];
int **nv = new int*[n_file_ranks];
int **nvdofs = new int*[n_file_ranks];
int **nedofs = new int*[n_file_ranks];
int **nfdofs = new int*[n_file_ranks];
int **nrdofs = new int*[n_file_ranks];
for (int i = 0; i < n_file_ranks; ++i)
{
nv[i] = &dof_counts[i*5+0];
nvdofs[i] = &dof_counts[i*5+1];
nedofs[i] = &dof_counts[i*5+2];
nfdofs[i] = &dof_counts[i*5+3];
nrdofs[i] = &dof_counts[i*5+4];
}
*nv[file_rank] = pfes->GetVSize();
*nvdofs[file_rank] = pfes->GetNVDofs();
*nedofs[file_rank] = pfes->GetNEDofs();
*nfdofs[file_rank] = pfes->GetNFDofs();
int vdim = pfes->GetVDim();
*nrdofs[file_rank] = *nv[file_rank] / vdim - *nvdofs[file_rank] -
*nedofs[file_rank] - *nfdofs[file_rank];
MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, &dof_counts[0], 5,
MPI_INT, file_comm);
double *data_ = const_cast<double*>(HostRead());
for (int i = 0; i < size; i++)
{
if (pfes->GetDofSign(i) < 0) { data_[i] = -data_[i]; }
}
MPI_Offset header_offset = 0;
if (file_rank == 0)
{
int tmp[] = {n_fes_ranks, nfiles};
MPI_File_write_at(fh, header_offset, &tmp, 2, MPI_INT,
MPI_STATUS_IGNORE);
}
header_offset += 2 * sizeof(int);
MPI_Offset v_offset, e_offset, f_offset, r_offset;
int total_vdofs = 0, total_edofs = 0, total_fdofs = 0, total_rdofs = 0;
int total_scalar_dofs = 0;
for (int i = 0; i < n_file_ranks; ++i)
{
total_vdofs += *nvdofs[i];
total_edofs += *nedofs[i];
total_fdofs += *nfdofs[i];
total_rdofs += *nrdofs[i];
total_scalar_dofs += *nv[i];
}
total_scalar_dofs /= vdim;
if (pfes->GetOrdering() == Ordering::byNODES)
{
for (int d = 0; d < vdim; ++d)
{
int v_data_offset = 0 + *nv[file_rank] * d / vdim ;
int e_data_offset = v_data_offset + *nvdofs[file_rank];
int f_data_offset = e_data_offset + *nedofs[file_rank];
int r_data_offset = f_data_offset + *nfdofs[file_rank];
v_offset = header_offset;
e_offset = header_offset;
f_offset = header_offset;
r_offset = header_offset;
v_offset += total_scalar_dofs * d * sizeof(double);
e_offset += (total_vdofs + total_scalar_dofs * d) * sizeof(double);
f_offset += (total_vdofs + total_edofs +
total_scalar_dofs * d) * sizeof(double);
r_offset += (total_vdofs + total_edofs + total_fdofs +
total_scalar_dofs * d) * sizeof(double);
for (int i = 0; i < file_rank; ++i)
{
v_offset += *nvdofs[i] * sizeof(double);
e_offset += *nedofs[i] * sizeof(double);
f_offset += *nfdofs[i] * sizeof(double);
r_offset += *nrdofs[i] * sizeof(double);
}
MPI_File_write_at_all(fh, v_offset, &data_[v_data_offset],
*nvdofs[file_rank], MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_write_at_all(fh, e_offset, &data_[e_data_offset],
*nedofs[file_rank], MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_write_at_all(fh, f_offset, &data_[f_data_offset],
*nfdofs[file_rank], MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_write_at_all(fh, r_offset, &data_[r_data_offset],
*nrdofs[file_rank], MPI_DOUBLE,
MPI_STATUS_IGNORE);
}
}
else
{
v_offset = header_offset;
e_offset = v_offset + total_vdofs * vdim * sizeof(double);
f_offset = e_offset + total_edofs * vdim * sizeof(double);
r_offset = f_offset + total_fdofs * vdim * sizeof(double);
for (int i = 0; i < file_rank; ++i)
{
v_offset += *nvdofs[i] * sizeof(double) * vdim;
e_offset += *nedofs[i] * sizeof(double) * vdim;
f_offset += *nfdofs[i] * sizeof(double) * vdim;
r_offset += *nrdofs[i] * sizeof(double) * vdim;
}
int v_data_offset = 0;
int e_data_offset = v_data_offset + *nvdofs[file_rank] * vdim;
int f_data_offset = e_data_offset + *nedofs[file_rank] * vdim;
int r_data_offset = f_data_offset + *nfdofs[file_rank] * vdim;
MPI_File_write_at_all(fh, v_offset, &data_[v_data_offset],
*nvdofs[file_rank] * vdim, MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_write_at_all(fh, e_offset, &data_[e_data_offset],
*nedofs[file_rank] * vdim, MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_write_at_all(fh, f_offset, &data_[f_data_offset],
*nfdofs[file_rank] * vdim, MPI_DOUBLE,
MPI_STATUS_IGNORE);
MPI_File_write_at_all(fh, r_offset, &data_[r_data_offset],
*nrdofs[file_rank] * vdim, MPI_DOUBLE,
MPI_STATUS_IGNORE);
}
MPI_File_close(&fh);
MPI_Comm_free(&file_comm);
for (int i = 0; i < size; i++)
{
if (pfes->GetDofSign(i) < 0) { data_[i] = -data_[i]; }
}
delete[] dof_counts;
delete[] nv;
delete[] nvdofs;
delete[] nedofs;
delete[] nfdofs;
delete[] nrdofs;
}
void ParGridFunction::SaveAsOne(std::ostream &out)
{
int i, p;
+21
View File
@@ -83,6 +83,13 @@ public:
constructed. The new ParGridFunction assumes ownership of both. */
ParGridFunction(ParMesh *pmesh, std::istream &input);
/// Construct a ParGridFunction by loading a ParGridFunction saved using
/// ParGridFunction::Save(char *filename, int nfiles).
/** The parallel space @a *pf and the space used by the GridFunction saved
in @a *filename should match. The number of ranks used when loading the
ParGridFunction must be the same as when it was saved. */
ParGridFunction(ParFiniteElementSpace *pf, const char *filename);
/// Copy assignment. Only the data of the base class Vector is copied.
/** It is assumed that this object and @a rhs use ParFiniteElementSpace%s
that have the same size.
@@ -324,6 +331,20 @@ public:
const adios2stream::data_type type = adios2stream::data_type::point_data) const;
#endif
/** Save the local grid functions to n number of files, where each file will
contain the grid functions from potentially multiple ranks. This is
similar to the syncIO approach from "Fu, Jing, et al. 'Scalable parallel
I/O alternatives for massively parallel partitioned solver systems.'
2010 IEEE International Symposium on Parallel & Distributed Processing,
Workshops and Phd Forum (IPDPSW). IEEE, 2010."
@param[in] filename - filename for output files with extension
@param[in] nfiles - number of files to write using MPI-IO
@note - takes into account the signs of the local dofs.
@note - writes a binary file without the FESpace header; the saved file
should only be loaded by the accompanying constructor:
ParGridFunction(ParFiniteElementSpace *pf, const char *filename) */
void Save(const char *filename, const int nfiles = 1);
/// Merge the local grid functions
void SaveAsOne(std::ostream &out = mfem::out);
+17 -62
View File
@@ -168,27 +168,6 @@ void ElementRestriction::Mult(const Vector& x, Vector& y) const
});
}
void ElementRestriction::MultUnsigned(const Vector& x, Vector& y) const
{
// Assumes all elements have the same number of dofs
const int nd = dof;
const int vd = vdim;
const bool t = byvdim;
auto d_x = Reshape(x.Read(), t?vd:ndofs, t?ndofs:vd);
auto d_y = Reshape(y.Write(), nd, vd, ne);
auto d_gatherMap = gatherMap.Read();
MFEM_FORALL(i, dof*ne,
{
const int gid = d_gatherMap[i];
const int j = gid >= 0 ? gid : -1-gid;
for (int c = 0; c < vd; ++c)
{
d_y(i % nd, c, i / nd) = d_x(t?c:j, t?j:c);
}
});
}
void ElementRestriction::MultTranspose(const Vector& x, Vector& y) const
{
// Assumes all elements have the same number of dofs
@@ -987,51 +966,27 @@ void L2FaceRestriction::MultTranspose(const Vector& x, Vector& y) const
const int dofs = nfdofs;
auto d_offsets = offsets.Read();
auto d_indices = gather_indices.Read();
if (m == L2FaceValues::DoubleValued)
auto d_x = Reshape(x.Read(), nd, vd, 2, nf);
auto d_y = Reshape(y.Write(), t?vd:ndofs, t?ndofs:vd);
MFEM_FORALL(i, ndofs,
{
auto d_x = Reshape(x.Read(), nd, vd, 2, nf);
auto d_y = Reshape(y.Write(), t?vd:ndofs, t?ndofs:vd);
MFEM_FORALL(i, ndofs,
const int offset = d_offsets[i];
const int nextOffset = d_offsets[i + 1];
for (int c = 0; c < vd; ++c)
{
const int offset = d_offsets[i];
const int nextOffset = d_offsets[i + 1];
for (int c = 0; c < vd; ++c)
double dofValue = 0;
for (int j = offset; j < nextOffset; ++j)
{
double dofValue = 0;
for (int j = offset; j < nextOffset; ++j)
{
int idx_j = d_indices[j];
bool isE1 = idx_j < dofs;
idx_j = isE1 ? idx_j : idx_j - dofs;
dofValue += isE1 ?
d_x(idx_j % nd, c, 0, idx_j / nd)
:d_x(idx_j % nd, c, 1, idx_j / nd);
}
d_y(t?c:i,t?i:c) += dofValue;
int idx_j = d_indices[j];
bool isE1 = idx_j < dofs;
idx_j = isE1 ? idx_j : idx_j - dofs;
dofValue += isE1 ?
d_x(idx_j % nd, c, 0, idx_j / nd)
:d_x(idx_j % nd, c, 1, idx_j / nd);
}
});
}
else
{
auto d_x = Reshape(x.Read(), nd, vd, nf);
auto d_y = Reshape(y.Write(), t?vd:ndofs, t?ndofs:vd);
MFEM_FORALL(i, ndofs,
{
const int offset = d_offsets[i];
const int nextOffset = d_offsets[i + 1];
for (int c = 0; c < vd; ++c)
{
double dofValue = 0;
for (int j = offset; j < nextOffset; ++j)
{
int idx_j = d_indices[j];
dofValue += d_x(idx_j % nd, c, idx_j / nd);
}
d_y(t?c:i,t?i:c) += dofValue;
}
});
}
d_y(t?c:i,t?i:c) += dofValue;
}
});
}
int ToLexOrdering(const int dim, const int face_id, const int size1d,
-2
View File
@@ -47,8 +47,6 @@ public:
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const;
/// Compute Mult without applying signs based on DOF orientations.
void MultUnsigned(const Vector &x, Vector &y) const;
/// Compute MultTranspose without applying signs based on DOF orientations.
void MultTransposeUnsigned(const Vector &x, Vector &y) const;
+146 -239
View File
@@ -13,7 +13,6 @@
#define MFEM_TEMPLATE_BILINEAR_FORM
#include "../config/tconfig.hpp"
#include "../linalg/simd.hpp"
#include "../linalg/ttensor.hpp"
#include "bilinearform.hpp"
#include "tevaluator.hpp"
@@ -24,32 +23,16 @@
namespace mfem
{
/** @brief Templated bilinear form class, cf. bilinearform.?pp
// 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,
typename complex_t = double, typename real_t = double,
typename impl_traits_t = AutoSIMDTraits<complex_t,real_t> >
typename complex_t = double, typename real_t = double>
class TBilinearForm : public Operator
{
public:
typedef impl_traits_t impl_traits_type;
protected:
typedef complex_t complex_type;
typedef real_t real_type;
@@ -65,47 +48,26 @@ protected:
static const int dofs = solFE_type::dofs;
static const int vdim = solVecLayout_t::vec_dim;
static const int qpts = IR::qpts;
static const int AB = impl_traits_t::align_bytes;
static const int SS = impl_traits_t::simd_size;
static const int BE = impl_traits_t::batch_size;
static const int TE = SS*BE;
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 integ_t::template kernel<sdim,dim,complex_t>::type kernel_t;
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;
typedef TElementTransformation<meshType,IR,real_t> Trans_t;
struct T_result
template <int NE> struct T_result
{
static const int EvalOps =
Trans_t::template Get<coeff_t,kernel_t>::EvalOps;
typedef typename Trans_t::template Result<EvalOps,impl_traits_t> Type;
typedef typename Trans_t::template Result<EvalOps,NE> Type;
};
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
template <int BE> struct S_spec
{
typedef typename solFieldEval::template Spec<kernel_t,impl_traits_t> Spec;
typedef typename solFieldEval::template Spec<kernel_t,BE> Spec;
typedef typename Spec::DataType DataType;
typedef typename Spec::ElementMatrix ElementMatrix;
};
@@ -124,7 +86,7 @@ protected:
coeff_t coeff;
Memory<p_assembled_t> assembled_data;
p_assembled_t *assembled_data;
const FiniteElementSpace &in_fes;
@@ -139,17 +101,13 @@ public:
solVecLayout(sol_fes),
int_rule(),
coeff(integ.coeff),
assembled_data(),
assembled_data(NULL),
in_fes(sol_fes)
{
assembled_data.Reset(AB == 64 ? MemoryType::HOST_64 :
AB == 32 ? MemoryType::HOST_32 :
MemoryType::HOST);
}
{ }
virtual ~TBilinearForm()
{
assembled_data.Delete();
delete [] assembled_data;
}
/// Get the input finite element space prolongation matrix
@@ -161,9 +119,10 @@ public:
virtual void Mult(const Vector &x, Vector &y) const
{
if (!assembled_data.Empty())
if (assembled_data)
{
MultAssembled(x, y);
const int num_elem = 1;
MultAssembled<num_elem>(x, y);
}
else
{
@@ -176,6 +135,10 @@ public:
{
y = 0.0;
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
// For better performance, create stack copies of solFES, and solEval
// inside 'solFEval'. The element-transformation 'T' also copies the
// meshFES, meshEval, etc internally.
@@ -186,49 +149,49 @@ public:
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el += TE)
for (int el = 0; el < NE; el++)
{
#if 0
typename S_spec::DataType R;
typename S_spec<BE>::DataType R;
solFEval.Eval(el, R);
typename T_result::Type F;
typename T_result<BE>::Type F;
T.Eval(el, F);
#else
typename T_result::Type F;
typename T_result<BE>::Type F;
T.Eval(el, F);
typename S_spec::DataType R;
typename S_spec<BE>::DataType R;
solFEval.Eval(el, R);
#endif
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
for (int k = 0; k < BE; k++)
{
kernel_t::Action(k, F, wQ, res, R);
}
kernel_t::Action(0, F, wQ, res, R);
solFEval.template Assemble<true>(R);
}
}
/// Partial assembly of quadrature point data
// Partial assembly of quadrature point data
void Assemble()
{
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
Trans_t T(mesh, meshEval);
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
if (assembled_data.Empty())
if (!assembled_data)
{
const int size = ((NE+TE-1)/TE)*BE;
assembled_data.New(size, assembled_data.GetMemoryType());
assembled_data = new p_assembled_t[NE];
}
for (int el = 0; el < NE; el += TE)
for (int el = 0; el < NE; el++) // BE == 1
{
typename T_result::Type F;
typename T_result<BE>::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
@@ -236,26 +199,28 @@ public:
for (int k = 0; k < BE; k++)
{
kernel_t::Assemble(k, F, wQ, res, assembled_data[el/SS+k]);
kernel_t::Assemble(k, F, wQ, res, assembled_data[el+k]);
}
}
}
template <int num_elem>
inline MFEM_ALWAYS_INLINE
void ElementAddMultAssembled(int el, solFieldEval &solFEval) const
{
typename S_spec::DataType R;
typename S_spec<num_elem>::DataType R;
solFEval.Eval(el, R);
for (int k = 0; k < BE; k++)
for (int k = 0; k < num_elem; k++)
{
kernel_t::MultAssembled(k, assembled_data[el/SS+k], R);
kernel_t::MultAssembled(k, assembled_data[el+k], R);
}
solFEval.template Assemble<true>(R);
}
// complex_t = double
template <int num_elem>
void MultAssembled(const Vector &x, Vector &y) const
{
y = 0.0;
@@ -264,9 +229,14 @@ public:
x.GetData(), y.GetData());
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el += TE)
const int bNE = NE-NE%num_elem;
for (int el = 0; el < bNE; el += num_elem)
{
ElementAddMultAssembled(el, solFEval);
ElementAddMultAssembled<num_elem>(el, solFEval);
}
for (int el = bNE; el < NE; el++)
{
ElementAddMultAssembled<1>(el, solFEval);
}
}
@@ -279,10 +249,10 @@ public:
solVecLayout_type solVecLayout(this->solVecLayout);
solFESpace solFES(this->solFES);
TTensor3<dofs,vdim,BE,vcomplex_t> xy_dof;
TTensor3<dofs,vdim,1,complex_t> xy_dof;
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el += TE)
for (int el = 0; el < NE; el++)
{
solFES.SetElement(el);
@@ -296,108 +266,98 @@ public:
{
typedef typename meshType::FESpace_type meshFESpace;
meshFESpace meshFES(mesh.t_fes);
typedef TTensor3<meshFE_type::dofs,sdim,BE,vreal_t> lnodes_t;
typedef TTensor3<meshFE_type::dofs,sdim,1,real_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
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);
sNodes.MakeDataOwner();
for (int el = 0; el < NE; el += TE)
sNodes.SetSize(lnodes_t::size*NE);
real_t *lNodes = sNodes.GetData();
for (int el = 0; el < NE; el++)
{
meshFES.SetElement(el);
meshFES.VectorExtract(mesh.node_layout, mesh.Nodes,
lnodes_t::layout, vsNodes);
vsNodes += lnodes_t::size;
lnodes_t::layout, lNodes);
lNodes += lnodes_t::size;
}
}
/// Partial assembly from "serialized" nodes
// partial assembly from "serialized" nodes
// real_t = double
void AssembleFromSerializedNodes(const Vector &sNodes)
{
Trans_t T(mesh, meshEval);
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
Trans_t T(this->mesh, this->meshEval);
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
if (assembled_data.Empty())
if (!assembled_data)
{
const int size = ((NE+TE-1)/TE)*BE;
assembled_data.New(size, assembled_data.GetMemoryType());
assembled_data = new p_assembled_t[NE];
}
const vreal_t *vsNodes = (const vreal_t*)(sNodes.GetData());
for (int el = 0; el < NE; el += TE)
for (int el = 0; el < NE; el++)
{
typename T_result::Type F;
T.EvalSerialized(el, vsNodes, F);
typename T_result<BE>::Type F;
T.EvalSerialized(el, sNodes.GetData(), F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
for (int k = 0; k < BE; k++)
{
kernel_t::Assemble(k, F, wQ, res, assembled_data[el/SS+k]);
}
kernel_t::Assemble(0, F, wQ, res, assembled_data[el]);
}
}
// complex_t = double
void Serialize(const Vector &x, Vector &sx) const
{
typedef TTensor3<dofs,vdim,BE,vcomplex_t> vdof_data_t;
solVecLayout_t solVecLayout(this->solVecLayout);
typedef TTensor3<dofs,vdim,1,complex_t> vdof_data_t;
solFESpace solFES(this->solFES);
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
const int NVE = (NE+TE-1)/TE;
vreal_t *vsx = new vreal_t[vdof_data_t::size*NVE];
sx.NewDataAndSize(vsx[0].vec, (vdof_data_t::size*SS)*NVE);
sx.MakeDataOwner();
for (int el = 0; el < NE; el += TE)
sx.SetSize(vdim*dofs*NE);
complex_t *loc_sx = sx.GetData();
for (int el = 0; el < NE; el++)
{
solFES.SetElement(el);
solFES.VectorExtract(solVecLayout, x, vdof_data_t::layout, vsx);
vsx += vdof_data_t::size;
solFES.VectorExtract(solVecLayout, x, vdof_data_t::layout, loc_sx);
loc_sx += vdim*dofs;
}
}
/// serialized vector sx --> serialized vector 'sy'
// serialized vector sx --> serialized vector 'sy'
// complex_t = double
void MultAssembledSerialized(const Vector &sx, Vector &sy) const
{
solFieldEval solFEval(solFES, solEval, solVecLayout, NULL, NULL);
const int NE = mesh.GetNE();
const vreal_t *vsx = (const vreal_t*)(sx.GetData());
vreal_t *vsy = (vreal_t*)(sy.GetData());
for (int el = 0; el < NE; el += TE)
const complex_t *loc_sx = sx.GetData();
complex_t *loc_sy = sy.GetData();
for (int el = 0; el < NE; el++)
{
typename S_spec::DataType R;
solFEval.EvalSerialized(vsx, R);
typename S_spec<1>::DataType R;
solFEval.EvalSerialized(loc_sx, R);
for (int k = 0; k < BE; k++)
{
kernel_t::MultAssembled(k, assembled_data[el/SS+k], R);
}
kernel_t::MultAssembled(0, assembled_data[el], R);
solFEval.template AssembleSerialized<false>(R, vsy);
solFEval.template AssembleSerialized<false>(R, loc_sy);
vsx += vdim*dofs*BE;
vsy += vdim*dofs*BE;
loc_sx += vdim*dofs;
loc_sy += vdim*dofs;
}
}
#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
{
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
Trans_t T(mesh, meshEval);
solFESpace solFES(this->solFES);
solShapeEval solEval(this->solEval);
@@ -405,100 +365,79 @@ public:
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el += TE)
for (int el = 0; el < NE; el++)
{
f_assembled_t asm_qpt_data[BE];
f_assembled_t asm_qpt_data;
{
typename T_result::Type F;
typename T_result<BE>::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
for (int k = 0; k < BE; k++)
{
kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]);
}
kernel_t::Assemble(0, F, wQ, res, asm_qpt_data);
}
// For now, when vdim > 1, assume block-diagonal matrix with the same
// diagonal block for all components.
for (int k = 0; k < BE; k++)
TMatrix<dofs,dofs> M_loc;
S_spec<BE>::ElementMatrix::Compute(
asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval);
solFES.SetElement(el);
for (int bi = 0; bi < vdim; bi++)
{
const int el_k = el+SS*k;
if (el_k >= NE) { break; }
TMatrix<dofs,dofs,vcomplex_t> M_loc;
S_spec::ElementMatrix::Compute(
asm_qpt_data[k].layout, asm_qpt_data[k], M_loc.layout, M_loc,
solEval);
solFES.SetElement(el_k);
for (int bi = 0; bi < vdim; bi++)
{
solFES.AssembleBlock(bi, bi, solVecLayout, M_loc, M);
}
solFES.AssembleBlock(bi, bi, solVecLayout, M_loc, M);
}
}
}
/// 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
{
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
Trans_t T(mesh, meshEval);
solShapeEval solEval(this->solEval);
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el += TE)
for (int el = 0; el < NE; el++)
{
f_assembled_t asm_qpt_data[BE];
f_assembled_t asm_qpt_data;
{
typename T_result::Type F;
typename T_result<BE>::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
for (int k = 0; k < BE; k++)
{
kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]);
}
kernel_t::Assemble(0, F, wQ, res, asm_qpt_data);
}
// For now, when vdim > 1, assume block-diagonal matrix with the same
// diagonal block for all components.
// M is assumed to be (dof x dof x NE).
for (int k = 0; k < BE; k++)
{
const int el_k = el+SS*k;
if (el_k >= NE) { break; }
TMatrix<dofs,dofs> M_loc;
S_spec<BE>::ElementMatrix::Compute(
asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval);
TMatrix<dofs,dofs,vcomplex_t> M_loc;
S_spec::ElementMatrix::Compute(
asm_qpt_data[k].layout, asm_qpt_data[k], M_loc.layout, M_loc,
solEval);
for (int s = 0; s < SS && el_k+s < NE; s++)
{
complex_t *M_data = M.GetData(el_k+s);
for (int j = 0; j < dofs; j++)
{
for (int i = 0; i < dofs; i++)
{
M_data[j+dofs*i] = M_loc(i,j)[s];
}
}
}
}
complex_t *M_data = M.GetData(el);
M_loc.template AssignTo<AssignOp::Set>(M_data);
}
}
/// 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
{
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
Trans_t T(mesh, meshEval);
solShapeEval solEval(this->solEval);
coeff_eval_t wQ(int_rule, coeff);
@@ -509,93 +448,61 @@ public:
DenseMatrix M_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el += TE)
for (int el = 0; el < NE; el++)
{
f_assembled_t asm_qpt_data[BE];
f_assembled_t asm_qpt_data;
{
typename T_result::Type F;
typename T_result<BE>::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
for (int k = 0; k < BE; k++)
{
kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]);
}
kernel_t::Assemble(0, F, wQ, res, asm_qpt_data);
}
// For now, when vdim > 1, assume block-diagonal matrix with the same
// diagonal block for all components.
for (int k = 0; k < BE; k++)
TMatrix<dofs,dofs> M_loc;
S_spec<BE>::ElementMatrix::Compute(
asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval);
if (dof_map) // switch from tensor-product ordering
{
const int el_k = el+SS*k;
if (el_k >= NE) { break; }
TMatrix<dofs,dofs,vcomplex_t> M_loc;
S_spec::ElementMatrix::Compute(
asm_qpt_data[k].layout, asm_qpt_data[k], M_loc.layout, M_loc,
solEval);
if (dof_map) // switch from tensor-product ordering
for (int i = 0; i < dofs; i++)
{
for (int s = 0; s < SS && el_k+s < NE; s++)
for (int j = 0; j < dofs; j++)
{
for (int i = 0; i < dofs; i++)
{
for (int j = 0; j < dofs; j++)
{
M_loc_perm(dof_map_[i],dof_map_[j]) = M_loc(i,j)[s];
}
}
for (int bi = 1; bi < vdim; bi++)
{
M_loc_perm.CopyMN(M_loc_perm, dofs, dofs, 0, 0,
bi*dofs, bi*dofs);
}
a.AssembleElementMatrix(el_k+s, M_loc_perm, vdofs);
M_loc_perm(dof_map_[i],dof_map_[j]) = M_loc(i,j);
}
}
else if (SS == 1)
for (int bi = 1; bi < vdim; bi++)
{
DenseMatrix DM(M_loc.data[0].vec, dofs, dofs);
if (vdim == 1)
{
a.AssembleElementMatrix(el_k, DM, vdofs);
}
else
{
for (int bi = 0; bi < vdim; bi++)
{
M_loc_perm.CopyMN(DM, dofs, dofs, 0, 0, bi*dofs, bi*dofs);
}
a.AssembleElementMatrix(el_k, M_loc_perm, vdofs);
}
M_loc_perm.CopyMN(M_loc_perm, dofs, dofs, 0, 0,
bi*dofs, bi*dofs);
}
a.AssembleElementMatrix(el, M_loc_perm, vdofs);
}
else
{
DenseMatrix DM(M_loc.data, dofs, dofs);
if (vdim == 1)
{
a.AssembleElementMatrix(el, DM, vdofs);
}
else
{
for (int s = 0; s < SS && el_k+s < NE; s++)
for (int bi = 0; bi < vdim; bi++)
{
for (int i = 0; i < dofs; i++)
{
for (int j = 0; j < dofs; j++)
{
M_loc_perm(i,j) = M_loc(i,j)[s];
}
}
for (int bi = 1; bi < vdim; bi++)
{
M_loc_perm.CopyMN(M_loc_perm, dofs, dofs, 0, 0,
bi*dofs, bi*dofs);
}
a.AssembleElementMatrix(el_k+s, M_loc_perm, vdofs);
M_loc_perm.CopyMN(DM, dofs, dofs, 0, 0, bi*dofs, bi*dofs);
}
a.AssembleElementMatrix(el, M_loc_perm, vdofs);
}
}
}
}
/// 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
{
@@ -606,7 +513,7 @@ public:
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el++)
{
TTensor3<dofs,vdim,1,AutoSIMD<complex_t,1,1> > x_dof, y_dof;
TTensor3<dofs,vdim,1,complex_t> x_dof, y_dof;
solFES.SetElement(el);
solFES.VectorExtract(solVecLayout, x, x_dof.layout, x_dof);
+140 -159
View File
@@ -21,7 +21,8 @@ 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
{
@@ -37,48 +38,46 @@ 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;
/// @name Needed for the FieldEvaluator::Data class
///@{
// 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;
///@}
/** @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. */
// 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; };
/** @brief Partially assembled data type for one element with the given
number of quadrature points. This type is used in full element matrix
assembly. */
// 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; };
template <typename IR, typename coeff_t, typename impl_traits_t>
template <typename IR, typename coeff_t, int NE>
struct CoefficientEval
{
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
typedef typename IntRuleCoefficient<IR,coeff_t,NE>::Type Type;
};
/** @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) */
// 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)
template <typename T_result_t, typename Q_t, typename q_t,
typename S_data_t>
static inline MFEM_ALWAYS_INLINE
@@ -102,16 +101,13 @@ struct TMassKernel
}
}
/** @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
*/
// 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)
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,
@@ -128,12 +124,11 @@ struct TMassKernel
}
}
/** @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
*/
// 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
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)
@@ -153,54 +148,51 @@ struct TMassKernel
};
/** @brief Diffusion kernel
@tparam complex_t - type for the assembled data
*/
// Diffusion kernel
// 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;
///@}
/** @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. */
// 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; };
/** @brief Partially assembled data type for one element with the given number of
quadrature points. This type is used in full element matrix assembly. */
// 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; };
template <typename IR, typename coeff_t, typename impl_traits_t>
template <typename IR, typename coeff_t, int NE>
struct CoefficientEval
{
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
typedef typename IntRuleCoefficient<IR,coeff_t,NE>::Type Type;
};
/** @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 */
// 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
template <typename T_result_t, typename Q_t, typename q_t,
typename S_data_t>
static inline MFEM_ALWAYS_INLINE
@@ -222,20 +214,17 @@ struct TDiffusionKernel<1,1,complex_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
*/
// 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
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,
@@ -251,13 +240,13 @@ struct TDiffusionKernel<1,1,complex_t>
A[i] = Q.get(q,i,k) / F.Jt(i,0,0,k);
}
}
/** @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
*/
// 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,1,complex_t> &A,
@@ -277,49 +266,46 @@ 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;
///@}
/** @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. */
// 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; };
/** @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. */
// 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; };
template <typename IR, typename coeff_t, typename impl_traits_t>
template <typename IR, typename coeff_t, int NE>
struct CoefficientEval
{
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
typedef typename IntRuleCoefficient<IR,coeff_t,NE>::Type Type;
};
/** @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
*/
// 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
template <typename T_result_t, typename Q_t, typename q_t,
typename S_data_t>
static inline MFEM_ALWAYS_INLINE
@@ -352,18 +338,17 @@ struct TDiffusionKernel<2,2,complex_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
*/
// 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
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,
@@ -391,13 +376,12 @@ struct TDiffusionKernel<2,2,complex_t>
}
}
/** @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
*/
// 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,3,complex_t> &A,
@@ -423,48 +407,46 @@ 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;
///@}
/** @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. */
// 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; };
/** @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. */
// 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; };
template <typename IR, typename coeff_t, typename impl_traits_t>
template <typename IR, typename coeff_t, int NE>
struct CoefficientEval
{
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
typedef typename IntRuleCoefficient<IR,coeff_t,NE>::Type Type;
};
/** @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
*/
// 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
template <typename T_result_t, typename Q_t, typename q_t,
typename S_data_t>
static inline MFEM_ALWAYS_INLINE
@@ -495,18 +477,17 @@ struct TDiffusionKernel<3,3,complex_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
*/
// 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
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,
@@ -537,12 +518,12 @@ struct TDiffusionKernel<3,3,complex_t>
}
}
/** @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
*/
// 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,
+18 -40
View File
@@ -21,7 +21,7 @@
namespace mfem
{
/// Templated coefficient classes, cf. coefficient.?pp
// Templated coefficient classes, cf. coefficient.?pp
class TCoefficient
{
@@ -56,13 +56,12 @@ public:
};
/** @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. */
// 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.
template <typename Func, typename complex_t = double>
class TFunctionCoefficient : public TCoefficient
{
@@ -82,15 +81,11 @@ protected:
{
const int qpts = T_result_t::x_type::layout_type::dim_1;
const int ne = T_result_t::x_type::layout_type::dim_3;
const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]);
for (int k = 0; k < ne; k++)
{
for (int i = 0; i < qpts; i++)
{
for (int s = 0; s < vs; s++)
{
c[l.ind(i,k)][s] = F.Eval1D(T.x(i,0,k)[s]);
}
c[l.ind(i,k)] = F.Eval1D(T.x(i,0,k));
}
}
}
@@ -103,15 +98,11 @@ protected:
{
const int qpts = T_result_t::x_type::layout_type::dim_1;
const int ne = T_result_t::x_type::layout_type::dim_3;
const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]);
for (int k = 0; k < ne; k++)
{
for (int i = 0; i < qpts; i++)
{
for (int s = 0; s < vs; s++)
{
c[l.ind(i,k)][s] = F.Eval2D(T.x(i,0,k)[s], T.x(i,1,k)[s]);
}
c[l.ind(i,k)] = F.Eval2D(T.x(i,0,k), T.x(i,1,k));
}
}
}
@@ -124,25 +115,20 @@ protected:
{
const int qpts = T_result_t::x_type::layout_type::dim_1;
const int ne = T_result_t::x_type::layout_type::dim_3;
const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]);
for (int k = 0; k < ne; k++)
{
for (int i = 0; i < qpts; i++)
{
for (int s = 0; s < vs; s++)
{
c[l.ind(i,k)][s] =
F.Eval3D(T.x(i,0,k)[s], T.x(i,1,k)[s], T.x(i,2,k)[s]);
}
c[l.ind(i,k)] = F.Eval3D(T.x(i,0,k), T.x(i,1,k), T.x(i,2,k));
}
}
}
};
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.
@@ -184,21 +170,14 @@ public:
void Eval(const T_result_t &T, const c_layout_t &l, c_data_t &c)
{
const int ne = T_result_t::ne;
const int vs = sizeof(T.attrib[0])/sizeof(T.attrib[0][0]);
MFEM_STATIC_ASSERT(vs == sizeof(c[0])/sizeof(c[0][0]), "");
for (int i = 0; i < ne; i++)
{
typename c_data_t::data_type ci;
for (int s = 0; s < vs; s++)
{
ci[s] = constants(T.attrib[i][s]-1);
}
TAssign<AssignOp::Set>(l.ind2(i), c, ci);
TAssign<AssignOp::Set>(l.ind2(i), c, constants(T.attrib[i]-1));
}
}
};
/// GridFunction coefficient class.
template <typename FieldEval>
class TGridFunctionCoefficient : public TCoefficient
{
@@ -264,13 +243,12 @@ public:
/// Auxiliary class that is used to simplify the evaluation of a coefficient and
/// scaling it by the weights of a quadrature rule.
template <typename IR, typename coeff_t, typename impl_traits_t>
template <typename IR, typename coeff_t, int NE>
struct IntRuleCoefficient
{
static const int qpts = IR::qpts;
static const int ne = impl_traits_t::batch_size;
static const int ne = NE;
typedef typename coeff_t::complex_type complex_type;
typedef typename impl_traits_t::vcomplex_t vcomplex_t;
template <bool is_const, bool dummy> struct Aux;
@@ -299,7 +277,7 @@ struct IntRuleCoefficient
// non-constant coefficient
template <bool dummy> struct Aux<false,dummy>
{
typedef TMatrix<qpts,ne,vcomplex_t> result_t;
typedef TMatrix<qpts,ne,complex_type> result_t;
#ifdef MFEM_TEMPLATE_INTRULE_COEFF_PRECOMP
TMatrix<qpts,1,typename IR::real_type> w;
#else
@@ -334,7 +312,7 @@ struct IntRuleCoefficient
}
inline MFEM_ALWAYS_INLINE
const vcomplex_t &get(const result_t &res, int i, int k) const
const complex_type &get(const result_t &res, int i, int k) const
{
return res(i,k);
}
+74 -115
View File
@@ -21,14 +21,12 @@ namespace mfem
// Templated element transformation classes, cf. eltrans.?pp
/** @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.
*/
// 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
{
@@ -41,9 +39,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,
@@ -53,8 +51,6 @@ 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 =
@@ -65,14 +61,12 @@ public:
(EvalJacobians * kernel_t::uses_Jacobians);
};
/** @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;
// 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 parameter NE is the number of elements to be
// processed in the Eval() method.
template<int EvalOps, int NE> struct Result;
static const int dim = Mesh_t::dim;
static const int sdim = Mesh_t::space_dim;
@@ -91,17 +85,13 @@ protected:
const Element* const *elements;
template <typename vint_t, int NE>
template <int NE>
inline MFEM_ALWAYS_INLINE
void SetAttributes(int el, vint_t (&attrib)[NE]) const
void SetAttributes(int el, int (&attrib)[NE]) const
{
const int vsize = sizeof(vint_t)/sizeof(attrib[0][0]);
for (int i = 0; i < NE; i++)
{
for (int j = 0; j < vsize; i++)
{
attrib[i][j] = elements[el+j+i*vsize]->GetAttribute();
}
attrib[i] = elements[el+i]->GetAttribute();
}
}
@@ -115,31 +105,26 @@ public:
elements(mesh.m_mesh.GetElementsArray())
{ }
/// Evaluate coordinates and/or Jacobian matrices at quadrature points.
template<int EvalOps, typename impl_traits_t>
// Evaluate coordinates and/or Jacobian matrices at quadrature points.
template<int EvalOps, int NE>
inline MFEM_ALWAYS_INLINE
void Eval(int el, Result<EvalOps,impl_traits_t> &F)
void Eval(int el, Result<EvalOps,NE> &F)
{
F.Eval(el, *this);
}
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
template<int EvalOps, typename impl_traits_t>
template<int EvalOps, int NE>
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, const typename impl_traits_t::vreal_t *nodeData,
Result<EvalOps,impl_traits_t> &F)
void EvalSerialized(int el, const real_t *nodeData, Result<EvalOps,NE> &F)
{
F.EvalSerialized(el, *this, nodeData);
}
#endif
// Specialization of the Result<> class
// Case EvalOps = 0 = EvalNone
template <typename it_t> struct Result<0,it_t>
template <int NE> struct Result<0,NE> // 0 = EvalNone
{
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
static const int ne = NE;
// x_type x;
// Jt_type Jt;
// int attrib[NE];
@@ -152,23 +137,20 @@ public:
}
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData) { }
void EvalSerialized(int el, T_type &T, const real_t *nodeData) { }
#endif
};
// Case EvalOps = 1 = EvalCoordinates
template <typename it_t> struct Result<1,it_t>
template <int NE> struct Result<1,NE> // 1 = EvalCoordinates
{
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
static const int ne = NE;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
typedef TTensor3<qpts,sdim,NE,vreal_t,true> x_type;
typedef TTensor3<qpts,sdim,NE,real_t,true> x_type;
#else
typedef TTensor3<qpts,sdim,ne,vreal_t/*,true*/> x_type;
typedef TTensor3<qpts,sdim,NE,real_t/*,true*/> x_type;
#endif
x_type x;
typedef TTensor3<dofs,sdim,ne,vreal_t> nodes_dof_t;
typedef TTensor3<dofs,sdim,NE,real_t> nodes_dof_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
nodes_dof_t nodes_dof;
#endif
@@ -177,8 +159,8 @@ public:
void Eval(int el, T_type &T)
{
#ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported");
TTensor3<dofs,sdim,1,vreal_t> &nodes_dof = T.nodes_dof;
MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported");
TTensor3<dofs,sdim,1,real_t> &nodes_dof = T.nodes_dof;
#elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES)
nodes_dof_t nodes_dof;
#endif
@@ -191,30 +173,25 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData)
void EvalSerialized(int el, T_type &T, const real_t *nodeData)
{
const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]);
MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el);
T.evaluator.Calc(nodes_dof_t::layout.merge_23(),
&nodeData[el/SS*nodes_dof_t::size],
&nodeData[el*nodes_dof_t::size],
x.layout.merge_23(), x);
}
#endif
};
// Case EvalOps = 2 = EvalJacobians
template <typename it_t> struct Result<2,it_t>
template <int NE> struct Result<2,NE> // 2 = EvalJacobians
{
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
static const int ne = NE;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
typedef TTensor4<qpts,dim,sdim,ne,vreal_t,true> Jt_type;
typedef TTensor4<qpts,dim,sdim,NE,real_t,true> Jt_type;
#else
typedef TTensor4<qpts,dim,sdim,ne,vreal_t/*,true*/> Jt_type;
typedef TTensor4<qpts,dim,sdim,NE,real_t/*,true*/> Jt_type;
#endif
Jt_type Jt;
typedef TTensor3<dofs,sdim,ne,vreal_t> nodes_dof_t;
typedef TTensor3<dofs,sdim,NE,real_t> nodes_dof_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
nodes_dof_t nodes_dof;
#endif
@@ -223,8 +200,8 @@ public:
void Eval(int el, T_type &T)
{
#ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported");
TTensor3<dofs,sdim,1,vreal_t> &nodes_dof = T.nodes_dof;
MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported");
TTensor3<dofs,sdim,1,real_t> &nodes_dof = T.nodes_dof;
#elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES)
nodes_dof_t nodes_dof;
#endif
@@ -237,32 +214,27 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData)
void EvalSerialized(int el, T_type &T, const real_t *nodeData)
{
const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]);
MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el);
T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(),
&nodeData[el/SS*nodes_dof_t::size],
&nodeData[el*nodes_dof_t::size],
Jt.layout.merge_34(), Jt);
}
#endif
};
// Case EvalOps = 3 = EvalCoordinates|EvalJacobians
template <typename it_t> struct Result<3,it_t>
template <int NE> struct Result<3,NE> // 3 = EvalCoordinates|EvalJacobians
{
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
typedef TTensor3<qpts,sdim,ne,vreal_t,true> x_type;
static const int ne = NE;
typedef TTensor3<qpts,sdim,NE,real_t,true> x_type;
x_type x;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
typedef TTensor4<qpts,dim,sdim,ne,vreal_t,true> Jt_type;
typedef TTensor4<qpts,dim,sdim,NE,real_t,true> Jt_type;
#else
typedef TTensor4<qpts,dim,sdim,ne,vreal_t/*,true*/> Jt_type;
typedef TTensor4<qpts,dim,sdim,NE,real_t/*,true*/> Jt_type;
#endif
Jt_type Jt;
typedef TTensor3<dofs,sdim,ne,vreal_t> nodes_dof_t;
typedef TTensor3<dofs,sdim,NE,real_t> nodes_dof_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
nodes_dof_t nodes_dof;
#endif
@@ -271,8 +243,8 @@ public:
void Eval(int el, T_type &T)
{
#ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported");
TTensor3<dofs,sdim,1,vreal_t> &nodes_dof = T.nodes_dof;
MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported");
TTensor3<dofs,sdim,1,real_t> &nodes_dof = T.nodes_dof;
#elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES)
nodes_dof_t nodes_dof;
#endif
@@ -287,45 +259,39 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData)
void EvalSerialized(int el, T_type &T, const real_t *nodeData)
{
const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]);
MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el);
T.evaluator.Calc(nodes_dof_t::layout.merge_23(),
&nodeData[el/SS*nodes_dof_t::size],
&nodeData[el*nodes_dof_t::size],
x.layout.merge_23(), x);
T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(),
&nodeData[el/SS*nodes_dof_t::size],
&nodeData[el*nodes_dof_t::size],
Jt.layout.merge_34(), Jt);
}
#endif
};
// Case EvalOps = 6 = EvalJacobians|LoadAttributes
template <typename it_t> struct Result<6,it_t>
template <int NE> struct Result<6,NE> // 6 = EvalJacobians|LoadAttributes
{
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
typedef typename it_t::vint_t vint_t;
static const int ne = NE;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
typedef TTensor4<qpts,dim,sdim,ne,vreal_t,true> Jt_type;
typedef TTensor4<qpts,dim,sdim,NE,real_t,true> Jt_type;
#else
typedef TTensor4<qpts,dim,sdim,ne,vreal_t/*,true*/> Jt_type;
typedef TTensor4<qpts,dim,sdim,NE,real_t/*,true*/> Jt_type;
#endif
Jt_type Jt;
typedef TTensor3<dofs,sdim,ne,vreal_t> nodes_dof_t;
typedef TTensor3<dofs,sdim,NE,real_t> nodes_dof_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
nodes_dof_t nodes_dof;
#endif
vint_t attrib[ne];
int attrib[NE];
inline MFEM_ALWAYS_INLINE
void Eval(int el, T_type &T)
{
#ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported");
TTensor3<dofs,sdim,1,vreal_t> &nodes_dof = T.nodes_dof;
MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported");
TTensor3<dofs,sdim,1,real_t> &nodes_dof = T.nodes_dof;
#elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES)
nodes_dof_t nodes_dof;
#endif
@@ -339,31 +305,26 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData)
void EvalSerialized(int el, T_type &T, const real_t *nodeData)
{
const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]);
MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el);
T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(),
&nodeData[el/SS*nodes_dof_t::size],
&nodeData[el*nodes_dof_t::size],
Jt.layout.merge_34(), Jt);
T.SetAttributes(el, attrib);
}
#endif
};
// Case EvalOps = 10 = EvalJacobians|LoadElementIdxs
template <typename it_t> struct Result<10,it_t>
template <int NE> struct Result<10,NE> // 10 = EvalJacobians|LoadElementIdxs
{
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
static const int ne = NE;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
typedef TTensor4<qpts,dim,sdim,ne,vreal_t,true> Jt_type;
typedef TTensor4<qpts,dim,sdim,NE,real_t,true> Jt_type;
#else
typedef TTensor4<qpts,dim,sdim,ne,vreal_t/*,true*/> Jt_type;
typedef TTensor4<qpts,dim,sdim,NE,real_t/*,true*/> Jt_type;
#endif
Jt_type Jt;
typedef TTensor3<dofs,sdim,ne,vreal_t> nodes_dof_t;
typedef TTensor3<dofs,sdim,NE,real_t> nodes_dof_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
nodes_dof_t nodes_dof;
#endif
@@ -373,8 +334,8 @@ public:
void Eval(int el, T_type &T)
{
#ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported");
TTensor3<dofs,sdim,1,vreal_t> &nodes_dof = T.nodes_dof;
MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported");
TTensor3<dofs,sdim,1,real_t> &nodes_dof = T.nodes_dof;
#elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES)
nodes_dof_t nodes_dof;
#endif
@@ -388,12 +349,10 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData)
void EvalSerialized(int el, T_type &T, const real_t *nodeData)
{
const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]);
MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el);
T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(),
&nodeData[el/SS*nodes_dof_t::size],
&nodeData[el*nodes_dof_t::size],
Jt.layout.merge_34(), Jt);
first_elem_idx = el;
}
+168 -210
View File
@@ -23,16 +23,12 @@ namespace mfem
// Templated classes for transitioning between degrees of freedom and quadrature
// points values.
/** @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
*/
// Shape evaluators -- values of basis functions on the reference element
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>
{
@@ -58,11 +54,11 @@ public:
// default copy constructor
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). */
// 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
MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
@@ -80,12 +76,12 @@ public:
qpt_layout, qpt_data);
}
/** @brief Multi-component shape evaluation transpose from quadrature points to
DOFs. qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */
// 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>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
@@ -103,11 +99,11 @@ public:
dof_layout, dof_data);
}
/** @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). */
// 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
MFEM_ALWAYS_INLINE
void CalcGrad(const dof_layout_t &dof_layout,
const dof_data_t &dof_data,
const grad_layout_t &grad_layout,
@@ -128,12 +124,12 @@ public:
grad_layout.merge_12(), grad_data);
}
/** @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). */
// 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>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void CalcGradT(const grad_layout_t &grad_layout,
const grad_data_t &grad_data,
const dof_layout_t &dof_layout,
@@ -154,12 +150,11 @@ public:
dof_layout, dof_data);
}
/** @brief Multi-component assemble.
qpt_layout is (NIP x NumComp),
M_layout is (DOF x DOF x NumComp) */
// 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
MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const M_layout_t &M_layout, M_data_t &M_data) const
{
@@ -178,20 +173,19 @@ public:
#endif
}
/** @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). */
// 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
MFEM_ALWAYS_INLINE
void AssembleGradGrad(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
D_data_t &D_data) const
{
const int NC = qpt_layout_t::dim_4;
typedef typename qpt_data_t::data_type entry_type;
TTensor4<NIP,DIM,DOF,NC,entry_type> F;
TTensor4<NIP,DIM,DOF,NC> F;
for (int k = 0; k < NC; k++)
{
// Next loop performs a batch of matrix-matrix products of size
@@ -213,7 +207,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>
{
@@ -226,11 +220,11 @@ protected:
public:
TProductShapeEvaluator() { }
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). */
// 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
MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
@@ -239,12 +233,12 @@ public:
qpt_layout, qpt_data);
}
/** @brief Multi-component shape evaluation transpose from quadrature points
to DOFs. qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */
// 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>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
@@ -253,11 +247,11 @@ public:
dof_layout, dof_data);
}
/** @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). */
// 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
MFEM_ALWAYS_INLINE
void CalcGrad(const dof_layout_t &dof_layout,
const dof_data_t &dof_data,
const grad_layout_t &grad_layout,
@@ -269,12 +263,12 @@ public:
grad_layout.merge_12(), grad_data);
}
/** @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). */
// 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>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void CalcGradT(const grad_layout_t &grad_layout,
const grad_data_t &grad_data,
const dof_layout_t &dof_layout,
@@ -287,11 +281,11 @@ public:
dof_layout, dof_data);
}
/** @brief Multi-component assemble.
qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp) */
// 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
MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const M_layout_t &M_layout, M_data_t &M_data) const
{
@@ -310,12 +304,12 @@ public:
#endif
}
/** @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). */
// 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
MFEM_ALWAYS_INLINE
void AssembleGradGrad(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
@@ -337,7 +331,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>
{
@@ -354,14 +348,13 @@ public:
template <bool Dx, bool Dy,
typename dof_layout_t, typename dof_data_t,
typename qpt_layout_t, typename qpt_data_t>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
const int NC = dof_layout_t::dim_2;
typedef typename qpt_data_t::data_type entry_type;
// DOF x DOF x NC --> NIP x DOF x NC --> NIP x NIP x NC
TTensor3<NIP,DOF,NC,entry_type> A;
TTensor3<NIP,DOF,NC> A;
// (1) A_{i,j,k} = \sum_s B_1d_{i,s} dof_data_{s,j,k}
Mult_2_1<false>(B_1d.layout, Dx ? G_1d : B_1d,
@@ -373,11 +366,11 @@ public:
qpt_layout.template split_1<NIP,NIP>(), qpt_data);
}
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). */
// 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
MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
@@ -387,14 +380,13 @@ public:
template <bool Dx, bool Dy, bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename dof_layout_t, typename dof_data_t>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
const int NC = dof_layout_t::dim_2;
typedef typename qpt_data_t::data_type entry_type;
// NIP x NIP X NC --> NIP x DOF x NC --> DOF x DOF x NC
TTensor3<NIP,DOF,NC,entry_type> A;
TTensor3<NIP,DOF,NC> A;
// (1) A_{i,j,k} = \sum_s B_1d_{s,j} qpt_data_{i,s,k}
Mult_1_2<false>(B_1d.layout, Dy ? G_1d : B_1d,
@@ -406,23 +398,23 @@ public:
dof_layout.template split_1<DOF,DOF>(), dof_data);
}
/** @brief Multi-component shape evaluation transpose from quadrature points to DOFs.
qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). */
// 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>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
CalcT<false,false,Add>(qpt_layout, qpt_data, dof_layout, dof_data);
}
/** @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). */
// 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
MFEM_ALWAYS_INLINE
void CalcGrad(const dof_layout_t &dof_layout,
const dof_data_t &dof_data,
const grad_layout_t &grad_layout,
@@ -434,13 +426,13 @@ public:
grad_layout.ind2(1), grad_data);
}
/** @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). */
// 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>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void CalcGradT(const grad_layout_t &grad_layout,
const grad_data_t &grad_data,
const dof_layout_t &dof_layout,
@@ -452,16 +444,15 @@ public:
dof_layout, dof_data);
}
/** @brief Multi-component assemble.
qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp) */
// 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
MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const M_layout_t &M_layout, M_data_t &M_data) const
{
const int NC = qpt_layout_t::dim_2;
typedef typename qpt_data_t::data_type entry_type;
// Using TensorAssemble: <I,NIP,J> --> <DOF,I,DOF,J>
@@ -478,7 +469,7 @@ public:
TTensor3<DOF,NIP,DOF*NC>::layout, A,
M_layout.merge_23().template split_12<DOF,DOF,DOF,DOF*NC>(), M_data);
#elif 1
TTensor4<DOF,NIP,DOF,NC,entry_type> A;
TTensor4<DOF,NIP,DOF,NC> A;
// qpt_data<NIP1,NIP2,NC> --> A<DOF2,NIP1,DOF2,NC>
TensorAssemble<false>(
Bt_1d.layout, Bt_1d, B_1d.layout, B_1d,
@@ -519,15 +510,14 @@ public:
template <int D1, int D2, bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename D_layout_t, typename D_data_t>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
D_data_t &D_data) const
{
const int NC = qpt_layout_t::dim_2;
typedef typename qpt_data_t::data_type entry_type;
TTensor4<DOF,NIP,DOF,NC,entry_type> A;
TTensor4<DOF,NIP,DOF,NC> A;
// Using TensorAssemble: <I,NIP,J> --> <DOF,I,DOF,J>
@@ -541,16 +531,16 @@ public:
TensorAssemble<Add>(
Bt_1d.layout, D1 == 1 ? Bt_1d : Gt_1d,
B_1d.layout, D2 == 1 ? B_1d : G_1d,
A.layout.merge_34(), A,
TTensor3<DOF,NIP,DOF*NC>::layout, A,
D_layout.merge_23().template split_12<DOF,DOF,DOF,DOF*NC>(), D_data);
}
/** @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). */
// 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
MFEM_ALWAYS_INLINE
void AssembleGradGrad(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
@@ -617,7 +607,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>
{
@@ -634,14 +624,13 @@ public:
template <bool Dx, bool Dy, bool Dz,
typename dof_layout_t, typename dof_data_t,
typename qpt_layout_t, typename qpt_data_t>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
const int NC = dof_layout_t::dim_2;
typedef typename qpt_data_t::data_type entry_type;
TVector<NIP*DOF*DOF*NC,entry_type> QDD;
TVector<NIP*NIP*DOF*NC,entry_type> QQD;
TVector<NIP*DOF*DOF*NC> QDD;
TVector<NIP*NIP*DOF*NC> QQD;
// QDD_{i,jj,k} = \sum_s B_1d_{i,s} dof_data_{s,jj,k}
Mult_2_1<false>(B_1d.layout, Dx ? G_1d : B_1d,
@@ -657,11 +646,11 @@ public:
qpt_layout.template split_1<NIP*NIP,NIP>(), qpt_data);
}
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). */
// 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
MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
@@ -671,14 +660,13 @@ public:
template <bool Dx, bool Dy, bool Dz, bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename dof_layout_t, typename dof_data_t>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
const int NC = dof_layout_t::dim_2;
typedef typename qpt_data_t::data_type entry_type;
TVector<NIP*DOF*DOF*NC,entry_type> QDD;
TVector<NIP*NIP*DOF*NC,entry_type> QQD;
TVector<NIP*DOF*DOF*NC> QDD;
TVector<NIP*NIP*DOF*NC> QQD;
// QQD_{ii,j,k} = \sum_s B_1d_{s,j} qpt_data_{ii,s,k}
Mult_1_2<false>(B_1d.layout, Dz ? G_1d : B_1d,
@@ -694,23 +682,23 @@ public:
dof_layout.template split_1<DOF,DOF*DOF>(), dof_data);
}
/** @brief Multi-component shape evaluation transpose from quadrature points to DOFs.
qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). */
// 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>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
CalcT<false,false,false,Add>(qpt_layout, qpt_data, dof_layout, dof_data);
}
/** @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). */
// 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
MFEM_ALWAYS_INLINE
void CalcGrad(const dof_layout_t &dof_layout,
const dof_data_t &dof_data,
const grad_layout_t &grad_layout,
@@ -726,13 +714,13 @@ public:
// y-derivatives and second time for the z-derivatives.
}
/** @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). */
// 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>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void CalcGradT(const grad_layout_t &grad_layout,
const grad_data_t &grad_data,
const dof_layout_t &dof_layout,
@@ -746,18 +734,17 @@ public:
dof_layout, dof_data);
}
/** @brief Multi-component assemble.
qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp) */
// 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
MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const M_layout_t &M_layout, M_data_t &M_data) const
{
const int NC = qpt_layout_t::dim_2;
typedef typename qpt_data_t::data_type entry_type;
TTensor4<DOF,NIP*NIP,DOF,NC,entry_type> A1;
TTensor4<DOF,DOF*NIP,DOF,DOF*NC,entry_type> A2;
TTensor4<DOF,NIP*NIP,DOF,NC> A1;
TTensor4<DOF,DOF*NIP,DOF,DOF*NC> A2;
// Using TensorAssemble: <I,NIP,J> --> <DOF,I,DOF,J>
@@ -801,16 +788,15 @@ public:
template <int D1, int D2, bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename D_layout_t, typename D_data_t>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
D_data_t &D_data) const
{
const int NC = qpt_layout_t::dim_2;
typedef typename qpt_data_t::data_type entry_type;
TTensor4<DOF,NIP*NIP,DOF,NC,entry_type> A1;
TTensor4<DOF,DOF*NIP,DOF,DOF*NC,entry_type> A2;
TTensor4<DOF,NIP*NIP,DOF,NC> A1;
TTensor4<DOF,DOF*NIP,DOF,DOF*NC> A2;
// Using TensorAssemble: <I,NIP,J> --> <DOF,I,DOF,J>
@@ -838,7 +824,7 @@ public:
#if 0
template <typename qpt_layout_t, typename qpt_data_t,
typename D_layout_t, typename D_data_t>
inline MFEM_ALWAYS_INLINE
MFEM_ALWAYS_INLINE
void Assemble(int D1, int D2,
const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
@@ -873,12 +859,12 @@ public:
}
#endif
/** @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). */
// 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
MFEM_ALWAYS_INLINE
void AssembleGradGrad(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
@@ -909,7 +895,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>
@@ -935,7 +921,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>
@@ -960,9 +946,8 @@ public:
};
/** @brief Field evaluators -- values of a given global FE grid function
This is roughly speaking a templated version of GridFunction
*/
// Field evaluators -- values of a given global FE grid function
template <typename FESpace_t, typename VecLayout_t, typename IR,
typename complex_t, typename real_t>
class FieldEvaluator_base
@@ -975,7 +960,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)
@@ -984,14 +969,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
@@ -1024,7 +1009,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,
@@ -1034,7 +1019,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)
@@ -1043,7 +1028,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)
@@ -1064,25 +1049,25 @@ 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)
{
const int ne = val_layout_t::dim_3;
TTensor3<dofs,vdim,ne,typename val_data_t::data_type> val_dofs;
TTensor3<dofs,vdim,ne,complex_type> val_dofs;
SetElement(el);
fespace.VectorExtract(vec_layout, data_in, val_dofs.layout, val_dofs);
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)
{
const int ne = grad_layout_t::dim_4;
TTensor3<dofs,vdim,ne,typename grad_data_t::data_type> val_dofs;
TTensor3<dofs,vdim,ne,complex_type> val_dofs;
SetElement(el);
fespace.VectorExtract(vec_layout, data_in, val_dofs.layout, val_dofs);
shapeEval.CalcGrad(val_dofs.layout.merge_23(), val_dofs,
@@ -1127,25 +1112,23 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
template <typename DataType>
inline MFEM_ALWAYS_INLINE
void EvalSerialized(const typename DataType::vcomplex_t *loc_dofs,
DataType &F)
void EvalSerialized(const complex_t *loc_dofs, DataType &F)
{
Action<DataType::InData,true>::EvalSerialized(*this, loc_dofs, F);
}
template <bool Add, typename DataType>
inline MFEM_ALWAYS_INLINE
void AssembleSerialized(const DataType &F,
typename DataType::vcomplex_t *loc_dofs)
void AssembleSerialized(const DataType &F, complex_t *loc_dofs)
{
Action<DataType::OutData,true>::
template AssembleSerialized<Add>(*this, F, loc_dofs);
}
#endif
/** @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. */
// 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.
enum InOutData
{
None = 0,
@@ -1153,72 +1136,65 @@ public:
Gradients = 2
};
/** @brief Auxiliary templated struct AData, used by the Eval() and Assemble()
methods.
// 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, int NE> struct AData;
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
template <int NE> struct AData<0,NE> // 0 = None
{
// Do we need this?
};
template <typename it_t> struct AData<1,it_t> // 1 = Values
template <int NE> struct AData<1,NE> // 1 = Values
{
static const int ne = it_t::batch_size;
typedef typename it_t::vcomplex_t vcomplex_t;
#ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS
typedef TTensor3<dofs,vdim,ne,vcomplex_t,true> val_dofs_t;
typedef TTensor3<dofs,vdim,NE,complex_t,true> val_dofs_t;
val_dofs_t val_dofs;
#else
typedef TTensor3<dofs,vdim,ne,vcomplex_t> val_dofs_t;
typedef TTensor3<dofs,vdim,NE,complex_t> val_dofs_t;
#endif
TTensor3<qpts,vdim,ne,vcomplex_t> val_qpts;
TTensor3<qpts,vdim,NE,complex_t> val_qpts;
};
template <typename it_t> struct AData<2,it_t> // 2 = Gradients
template <int NE> struct AData<2,NE> // 2 = Gradients
{
static const int ne = it_t::batch_size;
typedef typename it_t::vcomplex_t vcomplex_t;
#ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS
typedef TTensor3<dofs,vdim,ne,vcomplex_t,true> val_dofs_t;
typedef TTensor3<dofs,vdim,NE,complex_t,true> val_dofs_t;
val_dofs_t val_dofs;
#else
typedef TTensor3<dofs,vdim,ne,vcomplex_t> val_dofs_t;
typedef TTensor3<dofs,vdim,NE,complex_t> val_dofs_t;
#endif
TTensor4<qpts,dim,vdim,ne,vcomplex_t> grad_qpts;
TTensor4<qpts,dim,vdim,NE,complex_t> grad_qpts;
};
template <typename it_t> struct AData<3,it_t> // 3 = Values+Gradients
template <int NE> struct AData<3,NE> // 3 = Values+Gradients
{
static const int ne = it_t::batch_size;
typedef typename it_t::vcomplex_t vcomplex_t;
#ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS
typedef TTensor3<dofs,vdim,ne,vcomplex_t,true> val_dofs_t;
typedef TTensor3<dofs,vdim,NE,complex_t,true> val_dofs_t;
val_dofs_t val_dofs;
#else
typedef TTensor3<dofs,vdim,ne,vcomplex_t> val_dofs_t;
typedef TTensor3<dofs,vdim,NE,complex_t> val_dofs_t;
#endif
TTensor3<qpts, vdim,ne,vcomplex_t,true> val_qpts;
TTensor4<qpts,dim,vdim,ne,vcomplex_t> grad_qpts;
TTensor3<qpts, vdim,NE,complex_t,true> val_qpts;
TTensor4<qpts,dim,vdim,NE,complex_t> grad_qpts;
};
/** @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>
// 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, int NE>
struct BData : public AData<IData|OData,NE>
{
typedef T_type eval_type;
static const int ne = NE;
static const int InData = IData;
static const int OutData = OData;
};
/** @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. */
// 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
@@ -1262,9 +1238,7 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
template <typename AData_t>
static inline MFEM_ALWAYS_INLINE
void EvalSerialized(T_type &T,
const typename AData_t::vcomplex_t *loc_dofs,
AData_t &D)
void EvalSerialized(T_type &T, const complex_t *loc_dofs, AData_t &D)
{
T.shapeEval.Calc(AData_t::val_dofs_t::layout.merge_23(), loc_dofs,
D.val_qpts.layout.merge_23(), D.val_qpts);
@@ -1272,8 +1246,7 @@ public:
template <bool Add, typename AData_t>
static inline MFEM_ALWAYS_INLINE
void AssembleSerialized(T_type &T, const AData_t &D,
typename AData_t::vcomplex_t *loc_dofs)
void AssembleSerialized(T_type &T, const AData_t &D, complex_t *loc_dofs)
{
T.shapeEval.template CalcT<Add>(
D.val_qpts.layout.merge_23(), D.val_qpts,
@@ -1318,9 +1291,7 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
template <typename AData_t>
static inline MFEM_ALWAYS_INLINE
void EvalSerialized(T_type &T,
const typename AData_t::vcomplex_t *loc_dofs,
AData_t &D)
void EvalSerialized(T_type &T, const complex_t *loc_dofs, AData_t &D)
{
T.shapeEval.CalcGrad(AData_t::val_dofs_t::layout.merge_23(), loc_dofs,
D.grad_qpts.layout.merge_34(), D.grad_qpts);
@@ -1328,8 +1299,7 @@ public:
template <bool Add, typename AData_t>
static inline MFEM_ALWAYS_INLINE
void AssembleSerialized(T_type &T, const AData_t &D,
typename AData_t::vcomplex_t *loc_dofs)
void AssembleSerialized(T_type &T, const AData_t &D, complex_t *loc_dofs)
{
T.shapeEval.template CalcGradT<Add>(
D.grad_qpts.layout.merge_34(), D.grad_qpts,
@@ -1379,9 +1349,7 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
template <typename AData_t>
static inline MFEM_ALWAYS_INLINE
void EvalSerialized(T_type &T,
const typename AData_t::vcomplex_t *loc_dofs,
AData_t &D)
void EvalSerialized(T_type &T, const complex_t *loc_dofs, AData_t &D)
{
T.shapeEval.Calc(AData_t::val_dofs_t::layout.merge_23(), loc_dofs,
D.val_qpts.layout.merge_23(), D.val_qpts);
@@ -1391,8 +1359,7 @@ public:
template <bool Add, typename AData_t>
static inline MFEM_ALWAYS_INLINE
void AssembleSerialized(T_type &T, const AData_t &D,
typename AData_t::vcomplex_t *loc_dofs)
void AssembleSerialized(T_type &T, const AData_t &D, complex_t *loc_dofs)
{
T.shapeEval.template CalcT<Add>(
D.val_qpts.layout.merge_23(), D.val_qpts,
@@ -1404,15 +1371,14 @@ public:
#endif
};
/** @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;
// This struct implements element matrix computation for some combinations
// of input (InOps) and output (OutOps) operations.
template <int InOps, int OutOps, int NE> struct TElementMatrix;
// Case 1,1 = Values,Values
template <typename it_t> struct TElementMatrix<1,1,it_t>
template <int NE> struct TElementMatrix<1,1,NE> // 1,1 = Values,Values
{
// qpt_layout_t is (nip), M_layout_t is (dof x dof)
// it_t::batch_size = 1 is assumed
// 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
@@ -1424,18 +1390,10 @@ public:
}
};
// Case 2,2 = Gradients,Gradients
template <typename it_t> struct TElementMatrix<2,2,it_t>
template <int NE> struct TElementMatrix<2,2,NE> // 2,2 = Gradients,Gradients
{
/** @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 */
// qpt_layout_t is (nip x dim x dim), 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
@@ -1447,15 +1405,15 @@ public:
}
};
template <typename kernel_t, typename impl_traits_t> struct Spec
template <typename kernel_t, int NE> struct Spec
{
static const int InData =
Values*kernel_t::in_values + Gradients*kernel_t::in_gradients;
static const int OutData =
Values*kernel_t::out_values + Gradients*kernel_t::out_gradients;
typedef BData<InData,OutData,impl_traits_t> DataType;
typedef TElementMatrix<InData,OutData,impl_traits_t> ElementMatrix;
typedef BData<InData,OutData,NE> DataType;
typedef TElementMatrix<InData,OutData,NE> ElementMatrix;
};
};

Some files were not shown because too many files have changed in this diff Show More