diff --git a/.gitignore b/.gitignore
index e2a2e99043..de260ce9ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,8 @@ config/sample-runs-build.log
doc/CodeDocumentation.conf
doc/CodeDocumentation.html
doc/CodeDocumentation
+doc/undoc.log
+doc/warnings.log
# Temporary files created by the tests.
*.stderr
@@ -120,7 +122,7 @@ examples/sundials/ex16-final.*
examples/sundials/Example16*
examples/petsc/ex[1-69]p
-examples/petsc/ex10p
+examples/petsc/ex1[0-1]p
examples/petsc/mesh.*
examples/petsc/sol.*
@@ -135,6 +137,7 @@ examples/petsc/Example9*
examples/petsc/deformed.*
examples/petsc/velocity.*
examples/petsc/elastic_energy.*
+examples/petsc/mode_*
examples/pumi/ex1
examples/pumi/ex[126]p
@@ -167,6 +170,7 @@ miniapps/meshing/twist
miniapps/meshing/mesh-explorer
miniapps/meshing/shaper
miniapps/meshing/extruder
+miniapps/meshing/trimmer
miniapps/meshing/mesh-optimizer
miniapps/meshing/pmesh-optimizer
miniapps/meshing/minimal-surface
@@ -180,6 +184,7 @@ miniapps/meshing/mesh-explorer.mesh
miniapps/meshing/partitioning.txt
miniapps/meshing/shaper.mesh
miniapps/meshing/extruder.mesh
+miniapps/meshing/trimmer.mesh
miniapps/meshing/optimized*
miniapps/meshing/perturbed*
diff --git a/.travis.yml b/.travis.yml
index b678d91809..4adc20c551 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,8 +11,6 @@
language: cpp
-sudo: false
-
stages:
- checks
- tests
@@ -370,8 +368,10 @@ 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,12 +384,9 @@ 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 MFEM_CXX="$MYCXX"
+ - make config MFEM_USE_MPI=$MPI MFEM_DEBUG=$DEBUG $MAKE_CXX_FLAG
MFEM_MPI_NP=$NPROCS CPPFLAGS="$CPPFLAGS"
# Show the configuration
- make info
diff --git a/CHANGELOG b/CHANGELOG
index a703361f95..e3ceab1f21 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -23,6 +23,27 @@ 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.
@@ -44,6 +65,17 @@ Discretization improvements
- 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
@@ -52,10 +84,19 @@ 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.
+
+- Added support for the SLEPc eigensolver package.
+
New and updated examples and miniapps
-------------------------------------
- Added a new example, Example 25/25p, to demonstrate the use of a Perfectly
@@ -65,11 +106,17 @@ New and updated examples and miniapps
- Added a new Example 26/26p to demonstrate the construction of a matrix-free
geometric and p-multigrid preconditioner for the Laplace problem.
-- Added a new example, Example 27/27p, to demonstrate the enforcement of
- various boundary conditions with the Laplace operator. The example shows the
- procedures for applying Dirichlet, Neumann (both homogeneous and
- inhomogeneous), Robin, and periodic boundary conditions with either H1 or DG
- discretizations.
+- Added a new example, Example 27/27p, to demonstrate the enforcement of various
+ boundary conditions with the Laplace operator. The example shows the procedure
+ for applying Dirichlet, Neumann (both homogeneous and inhomogeneous), Robin,
+ and periodic boundary conditions with either H1 or DG discretizations.
+
+- Added a new miniapp, Navier, that solves the time-dependent Navier-Stokes
+ equations of incompressible fluid dynamics. See the miniapps/navier directory
+ for more details.
+
+- Ported Example 11p to SLEPc, to demonstrate solving the Laplace eigenvalue
+ equation with the shift-and-invert spectral transformation method.
- Added a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of
stitching together opposite surfaces of a mesh to create a topologically
@@ -84,6 +131,12 @@ New and updated examples and miniapps
- Added a new test problem in example 24/24p, demonstrating a mixed bilinear
form for H(div) and L_2, with partial assembly support.
+- Added weak Dirichlet boundary conditions (Nitsche) to the NURBS miniapp.
+
+- Added a simple mesh editing miniapp, Trimmer, which trims away portions of a
+ mesh based on element attributes. Any newly exposed boundary elements are
+ assigned attribute numbers related to the trimmed element attributes.
+
Improved testing
----------------
- Added a GitLab pipeline that automates PR testing on supercomputing systems
@@ -93,9 +146,6 @@ 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
@@ -105,9 +155,8 @@ Miscellaneous
- The integration order used in the ComputeLpError and ComputeElementLpError
methods of class GridFunction has been increased.
-- Added a new IterativeSolverMonitor class that allows to monitor the residual
- and solution during the solving process of an IterativeSolver after every
- iteration.
+- Various other simplifications, extensions, and bugfixes in the code.
+
Version 4.1, released on March 10, 2020
=======================================
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0ebdbc318f..e407e5f95a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -149,9 +149,13 @@ if (MFEM_USE_MPI)
message(FATAL_ERROR "PETSc version >= 3.8.0 is required")
endif()
set(PETSC_INCLUDE_DIRS ${PETSC_INCLUDES})
+ if (MFEM_USE_SLEPC)
+ find_package(SLEPc REQUIRED config)
+ message(STATUS "Found SLEPc version ${SLEPC_VERSION}")
+ endif()
endif()
else()
- set(PKGS_NEED_MPI SUPERLU PETSC STRUMPACK PUMI)
+ set(PKGS_NEED_MPI SUPERLU PETSC SLEPC STRUMPACK PUMI)
foreach(PKG IN LISTS PKGS_NEED_MPI)
if (MFEM_USE_${PKG})
message(STATUS "Disabling package ${PKG} - requires MPI")
@@ -352,7 +356,7 @@ endif()
# integers, the METIS header (with 32-bit indices, as used by mfem) needs to
# be before SuiteSparse.
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
- MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
+ SLEPC MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
diff --git a/INSTALL b/INSTALL
index ddc911225b..6fdc5c4360 100644
--- a/INSTALL
+++ b/INSTALL
@@ -383,6 +383,10 @@ MFEM_USE_PETSC = YES/NO
and other features based on the PETSc package. When enabled, this option uses
the PETSC_* library options, see below.
+MFEM_USE_SLEPC = YES/NO
+ Enable MFEM eigensolvers based on the SLEPc package. When enabled, this
+ option uses the SLEPC_* library options, see below.
+
MFEM_USE_MPFR = YES/NO
MPFR is a library for multiple-precision floating-point computations. This
option enables the use of MPFR in MFEM, e.g. for precise computation of 1D
@@ -396,6 +400,12 @@ 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/)
@@ -426,6 +436,8 @@ 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
@@ -589,6 +601,12 @@ The specific libraries and their options are:
Options: PETSC_OPT, PETSC_LIB.
Versions: PETSc >= 3.8.0.
+- SLEPc (optional), used when MFEM_USE_SLEPC = YES. SLEPc depends on PETSc and
+ uses some of the PETSc options when compiled.
+ URL: https://slepc.upv.es/
+ Options: SLEPC_OPT, SLEPC_LIB.
+ Versions: SLEPc >= 3.8.0.
+
- Sidre (optional), part of LLNL's axom project, used when MFEM_USE_SIDRE = YES.
Starting with MFEM v4.1, Axom version 0.3.1 or later is required.
URL: https://github.com/LLNL/axom
@@ -609,8 +627,9 @@ 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.0.
+ Versions: PUMI >= 2.2.3.
- HiOp (optional), used when MFEM_USE_HIOP = YES.
URL: https://github.com/LLNL/hiop
@@ -640,12 +659,11 @@ The specific libraries and their options are:
Options: OCCA_DIR, OCCA_OPT, OCCA_LIB.
Versions: OCCA >= 1.0.9.
-- libCEED (optional), used when MFEM_USE_CEED = YES. Requires libCEED v0.6
- or later version, specifically, git-hash 3d05795 or later.
+- libCEED (optional), used when MFEM_USE_CEED = YES.
URL: https://github.com/CEED/libCEED
https://ceed.exascaleproject.org/libceed
Options: CEED_DIR, CEED_OPT, CEED_LIB.
- Versions: libCEED >= 0.6.
+ Versions: libCEED >= 0.6, git-hash a970f63.
- RAJA (optional), used when MFEM_USE_RAJA = YES.
Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported.
diff --git a/config/XSDKDefaults.cmake b/config/XSDKDefaults.cmake
index da9f380b78..0cb8339501 100644
--- a/config/XSDKDefaults.cmake
+++ b/config/XSDKDefaults.cmake
@@ -244,6 +244,10 @@ IF (DEFINED TPL_ENABLE_PETSC)
SET(MFEM_USE_PETSC ${TPL_ENABLE_PETSC} CACHE BOOL "Enable PETSc support." FORCE)
ENDIF()
+IF (DEFINED TPL_ENABLE_SLEPC)
+ SET(MFEM_USE_SLEPC ${TPL_ENABLE_SLEPC} CACHE BOOL "Enable SLEPc support." FORCE)
+ENDIF()
+
IF (DEFINED TPL_ENABLE_MPFR)
SET(MFEM_USE_MPFR ${TPL_ENABLE_MPFR} CACHE BOOL "Enable MPFR usage." FORCE)
ENDIF()
diff --git a/config/cmake/MFEMConfig.cmake.in b/config/cmake/MFEMConfig.cmake.in
index 896e1c3510..de7e679184 100644
--- a/config/cmake/MFEMConfig.cmake.in
+++ b/config/cmake/MFEMConfig.cmake.in
@@ -38,6 +38,7 @@ set(MFEM_USE_GNUTLS @MFEM_USE_GNUTLS@)
set(MFEM_USE_GSLIB @MFEM_USE_GSLIB@)
set(MFEM_USE_NETCDF @MFEM_USE_NETCDF@)
set(MFEM_USE_PETSC @MFEM_USE_PETSC@)
+set(MFEM_USE_SLEPC @MFEM_USE_SLEPC@)
set(MFEM_USE_MPFR @MFEM_USE_MPFR@)
set(MFEM_USE_SIDRE @MFEM_USE_SIDRE@)
set(MFEM_USE_CONDUIT @MFEM_USE_CONDUIT@)
@@ -47,6 +48,7 @@ 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@")
diff --git a/config/cmake/config.hpp.in b/config/cmake/config.hpp.in
index 26327ae59b..aa784d25bc 100644
--- a/config/cmake/config.hpp.in
+++ b/config/cmake/config.hpp.in
@@ -104,9 +104,15 @@
// Enable MFEM functionality based on the PETSc library
#cmakedefine MFEM_USE_PETSC
+// Enable MFEM functionality based on the SLEPc library
+#cmakedefine MFEM_USE_SLEPC
+
// 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
diff --git a/config/cmake/modules/FindSLEPc.cmake b/config/cmake/modules/FindSLEPc.cmake
new file mode 100644
index 0000000000..fa02139910
--- /dev/null
+++ b/config/cmake/modules/FindSLEPc.cmake
@@ -0,0 +1,44 @@
+# 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.
+
+# Sets the following variables:
+# - SLEPC_FOUND
+# - SLEPC_INCLUDE_DIRS
+# - SLEPC_LIBRARIES
+
+set(SLEPc_REQUIRED_PACKAGES "PETSC" CACHE STRING
+ "Additional packages required by SLEPc")
+
+include(MfemCmakeUtilities)
+mfem_find_package(SLEPc SLEPC SLEPC_DIR
+ "include" "slepceps.h"
+ "${PETSC_ARCH}/lib" "slepc" # add NAMES_PER_DIR?
+ "Paths to headers required by SLEPc."
+ "Libraries required by SLEPc."
+ ADD_COMPONENT "config" "${PETSC_ARCH}/include" "slepcconf.h" "" ""
+ CHECK_BUILD SLEPC_VERSION_OK TRUE
+"
+#include \"petsc.h\"
+#include \"slepceps.h\"
+int main()
+{
+ PetscErrorCode ierr;
+ int argc = 0;
+ char** argv = NULL;
+ ierr = SlepcInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL);
+ EPS eps;
+ ierr = EPSCreate(PETSC_COMM_SELF, &eps); CHKERRQ(ierr);
+ ierr = EPSDestroy(&eps); CHKERRQ(ierr);
+ ierr = SlepcFinalize(); CHKERRQ(ierr);
+ return 0;
+}
+"
+ )
diff --git a/config/cmake/modules/MfemCmakeUtilities.cmake b/config/cmake/modules/MfemCmakeUtilities.cmake
index 6f3428933c..bcb8e5354c 100644
--- a/config/cmake/modules/MfemCmakeUtilities.cmake
+++ b/config/cmake/modules/MfemCmakeUtilities.cmake
@@ -731,9 +731,9 @@ function(mfem_export_mk_files)
MFEM_USE_LAPACK MFEM_THREAD_SAFE MFEM_USE_OPENMP MFEM_USE_LEGACY_OPENMP
MFEM_USE_MEMALLOC MFEM_USE_SUNDIALS MFEM_USE_MESQUITE MFEM_USE_SUITESPARSE
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_GSLIB MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_SLEPC 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_UMPIRE MFEM_USE_SIMD MFEM_USE_ADIOS2)
foreach(var ${CONFIG_MK_BOOL_VARS})
if (${var})
set(${var} YES)
@@ -743,6 +743,7 @@ 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)
diff --git a/config/config.hpp b/config/config.hpp
index 8d96d2a054..74ae1507fc 100644
--- a/config/config.hpp
+++ b/config/config.hpp
@@ -48,6 +48,9 @@
#ifdef MFEM_USE_PETSC
#error Building with PETSc (MFEM_USE_PETSC=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
+#ifdef MFEM_USE_SLEPC
+#error Building with SLEPc (MFEM_USE_SLEPC=YES) requires MPI (MFEM_USE_MPI=YES)
+#endif
#ifdef MFEM_USE_PUMI
#error Building with PUMI (MFEM_USE_PUMI=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
diff --git a/config/config.hpp.in b/config/config.hpp.in
index d71cfcfbe0..ef56636ec5 100644
--- a/config/config.hpp.in
+++ b/config/config.hpp.in
@@ -106,6 +106,9 @@
// 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
@@ -115,6 +118,9 @@
// Enable functionality based on the PETSc library
// #define MFEM_USE_PETSC
+// Enable functionality based on the SLEPc library
+// #define MFEM_USE_SLEPC
+
// Enable functionality based on the MPFR library.
// #define MFEM_USE_MPFR
diff --git a/config/config.mk.in b/config/config.mk.in
index 4d7c34affc..17afecc3e0 100644
--- a/config/config.mk.in
+++ b/config/config.mk.in
@@ -37,6 +37,7 @@ MFEM_USE_GINKGO = @MFEM_USE_GINKGO@
MFEM_USE_GNUTLS = @MFEM_USE_GNUTLS@
MFEM_USE_NETCDF = @MFEM_USE_NETCDF@
MFEM_USE_PETSC = @MFEM_USE_PETSC@
+MFEM_USE_SLEPC = @MFEM_USE_SLEPC@
MFEM_USE_MPFR = @MFEM_USE_MPFR@
MFEM_USE_SIDRE = @MFEM_USE_SIDRE@
MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@
@@ -49,10 +50,12 @@ 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@
diff --git a/config/defaults.cmake b/config/defaults.cmake
index 5854e6916e..38d41cda98 100644
--- a/config/defaults.cmake
+++ b/config/defaults.cmake
@@ -39,6 +39,7 @@ option(MFEM_USE_GNUTLS "Enable GNUTLS usage" OFF)
option(MFEM_USE_GSLIB "Enable GSLIB usage" OFF)
option(MFEM_USE_NETCDF "Enable NETCDF usage" OFF)
option(MFEM_USE_PETSC "Enable PETSc support." OFF)
+option(MFEM_USE_SLEPC "Enable SLEPc support." OFF)
option(MFEM_USE_MPFR "Enable MPFR usage." OFF)
option(MFEM_USE_SIDRE "Enable Axom/Sidre usage" OFF)
option(MFEM_USE_CONDUIT "Enable Conduit usage" OFF)
@@ -49,6 +50,7 @@ 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")
@@ -154,6 +156,10 @@ set(PETSC_DIR "${MFEM_DIR}/../petsc" CACHE PATH
"Path to the PETSc main directory.")
set(PETSC_ARCH "arch-linux2-c-debug" CACHE STRING "PETSc build architecture.")
+set(SLEPC_DIR "${MFEM_DIR}/../slepc" CACHE PATH
+ "Path to the SLEPc main directory.")
+set(SLEPC_ARCH "arch-linux2-c-debug" CACHE STRING "SLEPC build architecture.")
+
set(MPFR_DIR "" CACHE PATH "Path to the MPFR library.")
set(CONDUIT_DIR "${MFEM_DIR}/../conduit" CACHE PATH
diff --git a/config/defaults.mk b/config/defaults.mk
index 490fa4f0e3..2c4b027be7 100644
--- a/config/defaults.mk
+++ b/config/defaults.mk
@@ -125,6 +125,7 @@ MFEM_USE_GINKGO = NO
MFEM_USE_GNUTLS = NO
MFEM_USE_NETCDF = NO
MFEM_USE_PETSC = NO
+MFEM_USE_SLEPC = NO
MFEM_USE_MPFR = NO
MFEM_USE_SIDRE = NO
MFEM_USE_CONDUIT = NO
@@ -137,6 +138,7 @@ 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.
@@ -275,6 +277,20 @@ ifeq ($(PETSC_FOUND),YES)
-L$(abspath $(PETSC_DIR))/lib -lpetsc $(PETSC_LIB)
endif
+SLEPC_DIR := $(MFEM_DIR)/../slepc
+SLEPC_VARS := $(SLEPC_DIR)/lib/slepc/conf/slepc_variables
+SLEPC_FOUND := $(if $(wildcard $(SLEPC_VARS)),YES,)
+SLEPC_INC_VAR = SLEPC_INCLUDE
+SLEPC_LIB_VAR = SLEPC_EXTERNAL_LIB
+ifeq ($(SLEPC_FOUND),YES)
+ SLEPC_OPT := $(shell sed -n "s/$(SLEPC_INC_VAR) *= *//p" $(SLEPC_VARS))
+ # Some additional external libraries might be defined in this file
+ -include ${SLEPC_DIR}/${PETSC_ARCH}/lib/slepc/conf/slepcvariables
+ SLEPC_LIB := $(shell sed -n "s/$(SLEPC_LIB_VAR) *= *//p" $(SLEPC_VARS))
+ SLEPC_LIB := -Wl,-rpath,$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib\
+ -L$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib -lslepc $(SLEPC_LIB)
+endif
+
# MPFR library configuration
MPFR_OPT =
MPFR_LIB = -lmpfr
diff --git a/config/tconfig.hpp b/config/tconfig.hpp
index 59cc77ecd9..a10ae8f4b6 100644
--- a/config/tconfig.hpp
+++ b/config/tconfig.hpp
@@ -29,8 +29,20 @@
#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
@@ -38,11 +50,6 @@
// #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
{
diff --git a/miniapps/nurbs/cube-nurbs.mesh b/data/cube-nurbs.mesh
similarity index 100%
rename from miniapps/nurbs/cube-nurbs.mesh
rename to data/cube-nurbs.mesh
diff --git a/data/periodic-annulus-sector.geo b/data/periodic-annulus-sector.geo
new file mode 100644
index 0000000000..655b41bddf
--- /dev/null
+++ b/data/periodic-annulus-sector.geo
@@ -0,0 +1,37 @@
+SetFactory("OpenCASCADE");
+
+R1 = 1.0;
+R2 = 2.0;
+
+Point(1) = {0.0, 0, 0, 1.0};
+Point(2) = {R1, 0, 0, 1.0};
+Point(3) = {R2, 0, 0, 1.0};
+Point(4) = {R1*Cos(Pi/3), R1*Sin(Pi/3), 0, 1.0};
+Point(5) = {R2*Cos(Pi/3), R2*Sin(Pi/3), 0, 1.0};
+Line(1) = {2, 3};
+Line(2) = {4, 5};
+Circle(3) = {2, 1, 4};
+Circle(4) = {3, 1, 5};
+Curve Loop(5) = {1, 4, -2, -3};
+Plane Surface(1) = {5};
+
+Transfinite Curve{1} = 7;
+Transfinite Curve{2} = 7;
+Transfinite Curve{3} = 4;
+Transfinite Curve{4} = 10;
+
+// Set a rotation periodicity constraint:
+Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Pi/3};
+
+// Tag surfaces and volumes with positive integers
+Physical Curve(1) = {3};
+Physical Curve(2) = {4};
+Physical Curve(3) = {1};
+Physical Curve(4) = {2};
+Physical Surface(1) = {1};
+
+// Generate 2D mesh
+Mesh 2;
+Mesh.MshFileVersion = 2.2;
+
+Save "periodic-annulus-sector.msh";
diff --git a/data/periodic-annulus-sector.msh b/data/periodic-annulus-sector.msh
new file mode 100644
index 0000000000..8c70fef1f6
--- /dev/null
+++ b/data/periodic-annulus-sector.msh
@@ -0,0 +1,185 @@
+$MeshFormat
+2.2 0 8
+$EndMeshFormat
+$Nodes
+55
+1 1 0 0
+2 2 0 0
+3 0.5000000000000001 0.8660254037844386 0
+4 1 1.732050807568877 0
+5 1.166666666666667 0 0
+6 1.333333333333333 0 0
+7 1.5 0 0
+8 1.666666666666667 0 0
+9 1.833333333333333 0 0
+10 0.5833333333333335 1.010362971081845 0
+11 0.6666666666666667 1.154700538379251 0
+12 0.7500000000000002 1.299038105676658 0
+13 0.8333333333333335 1.443375672974064 0
+14 0.9166666666666669 1.587713240271471 0
+15 0.9396926207859085 0.3420201433256683 0
+16 0.7660444431189786 0.6427876096865386 0
+17 1.986476715483886 0.2321858282504602 0
+18 1.946089741159648 0.4612317414848793 0
+19 1.879385241571817 0.6840402866513365 0
+20 1.787265280646825 0.8975983604009234 0
+21 1.670975622825874 1.09901795614161 0
+22 1.532088886237958 1.285575219373077 0
+23 1.372483275737469 1.454747283146095 0
+24 1.194317183405575 1.604246385510085 0
+25 1.425989114816062 0.1915326920916892 0
+26 0.8788667344146573 1.13917645290495 0
+27 1.630372059110754 0.7154531062316609 0
+28 1.436395769298814 1.053728612482506 0
+29 1.081023776188756 0.6241293681829633 0
+30 1.168737372335971 1.428012728596308 0
+31 1.821063986059922 0.298149890497067 0
+32 1.234707097211386 0.3469796339295647 0
+33 1.377747393186519 0.6200150626754309 0
+34 1.457047681210906 0.3890895843559762 0
+35 0.917846726184522 0.8957978954532204 0
+36 1.218335619030348 0.9017812086952638 0
+37 1.066623110765233 1.061857005744772 0
+38 1.587029716281926 0.1355955181472859 0
+39 1.744445799211916 0.1441515753740107 0
+40 1.25 0.1443375672974065 0
+41 1.453660070628011 0.8435769396609902 0
+42 1.741367044061892 0.499612708014486 0
+43 1.30550638526547 1.257610469847477 0
+44 1.118213276932792 0.1666674689105279 0
+45 0.9109440214958271 1.306610291787315 0
+46 0.9970618258753989 1.438658589955562 0
+47 0.7499999999999998 1.010362971081845 0
+48 0.7034449005273667 0.8850673702175776 0
+49 1.605449512513618 0.9269067082200894 0
+50 1.561654019115059 0.5298592532912715 0
+51 1.229782222487711 1.096820457143683 0
+52 1.617066998712459 0.3090202662210922 0
+53 1.079645953234324 1.246963713711438 0
+54 1.877063966817811 0.1348974588243076 0
+55 1.055356609656722 1.558136350380461 0
+$EndNodes
+$Elements
+108
+1 1 2 3 1 1 5
+2 1 2 3 1 5 6
+3 1 2 3 1 6 7
+4 1 2 3 1 7 8
+5 1 2 3 1 8 9
+6 1 2 3 1 9 2
+7 1 2 4 2 3 10
+8 1 2 4 2 10 11
+9 1 2 4 2 11 12
+10 1 2 4 2 12 13
+11 1 2 4 2 13 14
+12 1 2 4 2 14 4
+13 1 2 1 3 1 15
+14 1 2 1 3 15 16
+15 1 2 1 3 16 3
+16 1 2 2 4 2 17
+17 1 2 2 4 17 18
+18 1 2 2 4 18 19
+19 1 2 2 4 19 20
+20 1 2 2 4 20 21
+21 1 2 2 4 21 22
+22 1 2 2 4 22 23
+23 1 2 2 4 23 24
+24 1 2 2 4 24 4
+25 2 2 1 1 32 40 25
+26 2 2 1 1 25 34 32
+27 2 2 1 1 33 41 36
+28 2 2 1 1 38 52 25
+29 2 2 1 1 33 36 29
+30 2 2 1 1 26 47 35
+31 2 2 1 1 35 37 26
+32 2 2 1 1 25 52 34
+33 2 2 1 1 32 44 40
+34 2 2 1 1 15 32 29
+35 2 2 1 1 15 29 16
+36 2 2 1 1 36 41 28
+37 2 2 1 1 32 33 29
+38 2 2 1 1 50 52 42
+39 2 2 1 1 32 34 33
+40 2 2 1 1 42 52 31
+41 2 2 1 1 43 53 51
+42 2 2 1 1 27 41 33
+43 2 2 1 1 26 53 45
+44 2 2 1 1 18 31 17
+45 2 2 1 1 29 35 16
+46 2 2 1 1 29 36 35
+47 2 2 1 1 24 30 23
+48 2 2 1 1 30 53 43
+49 2 2 1 1 17 54 2
+50 2 2 1 1 4 55 24
+51 2 2 1 1 28 51 36
+52 2 2 1 1 47 48 35
+53 2 2 1 1 36 37 35
+54 2 2 1 1 37 53 26
+55 2 2 1 1 22 28 21
+56 2 2 1 1 20 27 19
+57 2 2 1 1 33 50 27
+58 2 2 1 1 15 44 32
+59 2 2 1 1 18 42 31
+60 2 2 1 1 30 43 23
+61 2 2 1 1 35 48 16
+62 2 2 1 1 31 54 17
+63 2 2 1 1 9 39 8
+64 2 2 1 1 8 38 7
+65 2 2 1 1 7 25 6
+66 2 2 1 1 22 43 28
+67 2 2 1 1 23 43 22
+68 2 2 1 1 39 54 31
+69 2 2 1 1 19 42 18
+70 2 2 1 1 24 55 30
+71 2 2 1 1 27 42 19
+72 2 2 1 1 13 46 14
+73 2 2 1 1 51 53 37
+74 2 2 1 1 39 52 38
+75 2 2 1 1 6 40 5
+76 2 2 1 1 34 52 50
+77 2 2 1 1 12 45 13
+78 2 2 1 1 30 55 46
+79 2 2 1 1 10 47 11
+80 2 2 1 1 8 39 38
+81 2 2 1 1 28 49 21
+82 2 2 1 1 7 38 25
+83 2 2 1 1 41 49 28
+84 2 2 1 1 20 49 27
+85 2 2 1 1 11 26 12
+86 2 2 1 1 27 49 41
+87 2 2 1 1 31 52 39
+88 2 2 1 1 25 40 6
+89 2 2 1 1 2 54 9
+90 2 2 1 1 14 55 4
+91 2 2 1 1 45 53 46
+92 2 2 1 1 45 46 13
+93 2 2 1 1 5 44 1
+94 2 2 1 1 21 49 20
+95 2 2 1 1 46 53 30
+96 2 2 1 1 3 48 10
+97 2 2 1 1 34 50 33
+98 2 2 1 1 36 51 37
+99 2 2 1 1 26 45 12
+100 2 2 1 1 11 47 26
+101 2 2 1 1 27 50 42
+102 2 2 1 1 40 44 5
+103 2 2 1 1 43 51 28
+104 2 2 1 1 10 48 47
+105 2 2 1 1 9 54 39
+106 2 2 1 1 46 55 14
+107 2 2 1 1 1 44 15
+108 2 2 1 1 16 48 3
+$EndElements
+$Periodic
+1
+1 1 2
+Affine 0.5000000000000001 0.8660254037844386 0 0 -0.8660254037844386 0.5000000000000001 0 0 0 0 1 0 0 0 0 1
+7
+9 14
+6 11
+8 13
+5 10
+7 12
+2 4
+1 3
+$EndPeriodic
diff --git a/data/periodic-torus-sector.geo b/data/periodic-torus-sector.geo
new file mode 100644
index 0000000000..05eacae908
--- /dev/null
+++ b/data/periodic-torus-sector.geo
@@ -0,0 +1,25 @@
+SetFactory("OpenCASCADE");
+
+R = 1.5;
+r = 0.5;
+
+Torus(1) = {0,0,0, R, r, Pi/3};
+
+pts() = PointsOf{ Volume{1}; };
+
+Characteristic Length{ pts() } = 0.25;
+
+// Set a rotation periodicity constraint:
+Periodic Surface{3} = {2} Rotate{{0,0,1}, {0,0,0}, Pi/3};
+
+// Tag surfaces and volumes with positive integers
+Physical Surface(1) = {1};
+Physical Surface(2) = {2};
+Physical Surface(3) = {3};
+Physical Volume(1) = {1};
+
+// Generate 3D mesh
+Mesh 3;
+
+Mesh.MshFileVersion = 2.2;
+Save "periodic-torus-sector.msh";
diff --git a/data/periodic-torus-sector.msh b/data/periodic-torus-sector.msh
new file mode 100644
index 0000000000..2bb34fd344
--- /dev/null
+++ b/data/periodic-torus-sector.msh
@@ -0,0 +1,1056 @@
+$MeshFormat
+2.2 0 8
+$EndMeshFormat
+$Nodes
+178
+1 1 1.732050807568877 -1.224646799147353e-16
+2 2 0 -1.224646799147353e-16
+3 1.986476715483886 0.2321858282504604 -1.224646799147353e-16
+4 1.946089741159648 0.4612317414848803 -1.224646799147353e-16
+5 1.879385241571817 0.6840402866513373 -1.224646799147353e-16
+6 1.787265280646825 0.8975983604009242 -1.224646799147353e-16
+7 1.670975622825873 1.099017956141612 -1.224646799147353e-16
+8 1.532088886237956 1.285575219373079 -1.224646799147353e-16
+9 1.372483275737467 1.454747283146097 -1.224646799147353e-16
+10 1.194317183405573 1.604246385510087 -1.224646799147353e-16
+11 0.9713640064107713 1.682451811747116 0.2323615860315311
+12 0.8920161844090693 1.545017352570237 0.4114919360856992
+13 0.7801341700627819 1.351232019269317 0.4963544370492818
+14 0.6613487770564798 1.145489683385365 0.467508120445488
+15 0.5628723129571309 0.9749234442155601 0.3315613291201853
+16 0.5072645455148519 0.8786079657100585 0.1196578310999915
+17 0.5072645456434897 0.8786079659328657 -0.1196578321437994
+18 0.5628723130955459 0.9749234444553019 -0.3315613294326618
+19 0.6613487782393664 1.145489685434185 -0.4675081213427075
+20 0.7801341701356748 1.351232019395571 -0.4963544370315802
+21 0.8920161866827891 1.545017356508435 -0.4114919329468283
+22 0.9713640064234279 1.682451811769038 -0.2323615859833005
+23 1.942728012826605 0 0.2323615860218843
+24 1.784032373365578 0 0.4114919329468282
+25 1.560268340127662 0 0.496354437049027
+26 1.322697556478732 0 0.4675081213427075
+27 1.12574462591445 0 0.3315613291203977
+28 1.014529091286974 0 0.119657832143779
+29 1.014529091286974 0 -0.1196578321437787
+30 1.125744625914449 0 -0.3315613291203975
+31 1.322697556478732 0 -0.4675081213427074
+32 1.560268340127661 0 -0.496354437049027
+33 1.784032373365578 0 -0.4114919329468283
+34 1.942728012826605 0 -0.2323615860218846
+35 0.9094092833839373 1.140104827634976 0.4982645365438731
+36 0.9145403631597188 1.127554721496875 -0.4976726875517566
+37 1.439543163169036 0.2066277058988615 0.4979068470620236
+38 1.438046243463446 0.2043628722395764 -0.4977381412060781
+39 1.696686878481083 0.9795826260215588 0.1979072290649842
+40 1.705046974097277 0.9627338322458719 -0.2004271899713759
+41 1.425045163821982 1.344460771417579 0.1979072290649849
+42 1.426940472289519 1.3461283575362 -0.1919478807927782
+43 1.881724626638111 0.5593582007143618 -0.1885115572979801
+44 1.876859764350238 0.561894927701204 0.197907229064985
+45 0.6673803921678336 0.7447234565204733 0.002192541055854352
+46 1.050984583067059 0.1682970125584115 0.2454183754604045
+47 1.04172076116343 0.2047537321359636 -0.240523499060071
+48 1.113311450848127 1.513972982303749 0.3258377535851458
+49 1.113311453634618 1.513972982601351 -0.3258377513847104
+50 1.867794790374375 0.2071695099506198 0.3258377513964845
+51 1.867794790374375 0.2071695099506223 -0.3258377513964847
+52 0.699980884447671 0.7923257843216313 0.2322978976561902
+53 0.8143742402024221 0.6091370533569924 0.1292055331351144
+54 0.9234512163817853 0.6950259596839291 0.362644934140704
+55 0.8149471563398465 0.6014811214666318 -0.1127408743463922
+56 0.9089882740735398 0.4178664121885499 0.02087403616690475
+57 0.8036391734156695 0.9174735877750071 0.4140227221617467
+58 1.04528975873691 0.9197904008254907 0.488274495579655
+59 1.132701372162777 0.6901822877229037 0.4688993254694935
+60 1.277010042388928 0.8802828084812561 0.4973904977528614
+61 1.353438092664882 0.6544862687155961 0.4999885855347576
+62 1.206606309387528 1.137304388082402 0.4743397986991702
+63 1.203861688615928 0.4781648664665324 0.456198716333284
+64 1.420536892021458 1.019694143898059 0.4338017162656254
+65 0.9513629883317927 0.4940253704652492 0.2584636609340892
+66 0.706186918123033 0.8068591038835513 -0.258902571664125
+67 0.8997137668513249 0.6778946202619701 -0.332423851739337
+68 0.8754534158794457 0.8896155968337219 -0.431929083733448
+69 1.068014665374453 0.7835782676774907 -0.4682372295982862
+70 1.094885326848669 0.5587005809631567 -0.420314909746101
+71 1.278914902324639 0.6814395891060806 -0.4974057052434921
+72 1.253859094818866 0.9188999749034799 -0.4970184215451375
+73 1.467592256574374 0.8234236412687718 -0.4653816350826456
+74 1.493455917091833 0.5922523984885606 -0.4885036149289653
+75 1.427903945844154 1.053079485024634 -0.4180895076610792
+76 1.192654033939925 1.176482818815241 -0.468273221931405
+77 1.664532079158557 0.7347462962335058 -0.3846173119001672
+78 1.684193467076019 0.4966353289223597 -0.4295574916595252
+79 0.9581284611377014 0.4449942507914502 -0.2307371775066812
+80 1.060510603934137 1.323992179178645 0.4598289463295096
+81 1.20965670082534 0.1918462924921296 -0.4174342094103178
+82 1.306569861240723 0.4081890859478611 -0.4824924751602535
+83 1.222973879657449 0.2262967791144349 0.429334321634214
+84 1.804078223352526 0.7663783517359284 -0.1956990807188041
+85 1.57086252165904 1.155773912505517 -0.2174559627111528
+86 1.574823294802248 1.167621289969356 0.1948731313716022
+87 1.799061725861226 0.7760394771228164 0.1975920088688854
+88 1.736321519153448 0.6195058019401377 0.3633011133312876
+89 1.680111207596174 0.2053409065696982 0.4614111573472731
+90 1.585805226690124 0.4095866832898705 0.4806230171620565
+91 1.033769170861085 1.346420377509085 -0.4593379913029474
+92 1.686177954337897 0.2595089698405005 -0.4555780070333795
+93 0.9805825388808332 0.1961068189584932 0
+94 1.267064046804422 1.349831092695157 0.3557435462640699
+95 1.479801458923729 0.8235937501426396 0.4610179491301168
+96 1.806713163893442 0.41291149496386 0.3538099754989008
+97 1.660304769719565 0.8158013561953625 0.3571657671790813
+98 1.272522679585459 1.496027967309635 0.1862154784961512
+99 1.273193945142967 1.495820795927453 -0.1855231731675253
+100 1.262667463342245 1.368719575871037 -0.3447086919841124
+101 1.931859564293957 0.3540229855991108 0.1862154775733828
+102 1.934684648085233 0.3534998953881237 -0.1793804689566357
+103 1.044602110326715 0.9883306626754986 -0.496147496375881
+104 1.531662137703001 0.3834487538500693 -0.4937306551344234
+105 1.551796568960546 0.6139737231494753 0.4706294779813407
+106 1.581724214084509 0.9482897902504869 -0.3626575574879038
+107 1.096782839124086 0.35444480392985 -0.3596337488065346
+108 1.387291936348416 0.4077234230541955 0.497071738421552
+109 1.08924964123622 0.3634521195547355 0.355383901525496
+110 1.441115266930556 1.203974457102059 0.3274445044904424
+111 1.395080190203861 1.235707600010656 -0.3431511175769478
+112 1.133587364788978 1.610473031723204 -0.1721570661176043
+113 1.961520334484167 0.1716255200510413 0.1732789072467822
+114 1.961422513597609 0.1736228878529459 -0.1730685535438358
+115 1.82696920620189 0.4017949294223938 -0.3356092840765813
+116 1.131073087671027 1.61183028132059 0.1730685525791028
+117 1.580661987779667 0.9904905866376601 0.3413397946090942
+118 1.053798949591161 0.5492367868134354 0.3909838746147544
+119 0.7242610698965356 0.986066622565408 -0.4165714295663997
+120 1.776913423346694 0.6100558234668472 -0.3264522078233214
+121 0.976815381999997 0.3286770548430039 0.1723113781768278
+122 0.9684597721183544 0.3086573347446573 -0.1272227140227045
+123 1.598657272365354 0 -0.2601378477606267
+124 1.336856475131923 0 0.2435465079686098
+125 1.264366353304017 0 -0.1342496457412713
+126 1.708248762070371 0 0.1844923042412902
+127 1.770132970054707 0 -0.06658179719356594
+128 1.627974743938903 0 0.3374416670744554
+129 1.518381683403412 0 0.189367998345964
+130 1.388026045801723 0 0.02759910094603191
+131 1.57082733902861 0 -0.01324440776767719
+132 1.205770154876862 0 0.09185560579891296
+133 1.448748593218543 0 -0.1456951042254292
+134 1.386747123568126 0 -0.3059177475399098
+135 1.773887657153061 0 -0.2426432909807264
+136 1.855277436237921 0 0.08756802326740212
+137 1.456499046249551 0 0.3582625863623187
+138 0.7993286361826776 1.384477809813136 -0.2601378477606267
+139 0.6684282375659617 1.157751668677965 0.2435465079686098
+140 0.6321831766520087 1.09497338165157 -0.1342496457412713
+141 0.8541243810351855 1.47938682393626 0.1844923042412902
+142 0.885066485027354 1.532980120143776 -0.06658179719356594
+143 0.8139873719694519 1.409867484970557 0.3374416670744554
+144 0.7591908417017061 1.314957110468335 0.189367998345964
+145 0.6940130229008615 1.202065816778755 0.02759910094603191
+146 0.7854136695143054 1.360376380557887 -0.01324440776767719
+147 0.6028850774384313 1.04422758524846 0.09185560579891296
+148 0.7243742966092718 1.254653085424226 -0.1456951042254292
+149 0.6933735617840632 1.200958237634995 -0.3059177475399098
+150 0.8869438285765309 1.536231774554212 -0.2426432909807264
+151 0.9276387181189605 1.606717390850103 0.08756802326740212
+152 0.7282495231247758 1.261365174639917 0.3582625863623187
+153 1.411918130602168 0.496166241357142 -0.00157291651681768
+154 1.137417628047573 0.9720715936541285 -0.004558233820192492
+155 1.450923907048078 0.835854081603992 0.008303709726106997
+156 1.195281628759975 0.6892135661795487 0.1379139557683655
+157 1.667647997439524 0.3046155345731573 -0.01063985748379645
+158 1.095077566932522 1.30506262456116 0.008783669059526909
+159 1.449746181951948 0.2899752883377874 -0.2128942904574569
+160 1.425404656176498 0.2838646166858353 0.2090378240215375
+161 1.237422074642534 0.6934452933460877 -0.1740536126458837
+162 0.9265939870131148 1.089233825798041 0.146036662270623
+163 0.9141871309006279 1.035605401598253 -0.1819109563473867
+164 1.230559284884559 0.2965650718118637 -0.0489211473166503
+165 1.633700383529476 0.5873280387970766 -0.1078820007088586
+166 1.381887166693965 0.5422592078649243 0.2595533680109433
+167 1.628614112376115 0.5120437923677087 0.1405317590914031
+168 1.296790159421439 0.9296724900104604 0.2103100611208717
+169 1.43040652357321 0.5390860673292487 -0.2497801650023363
+170 1.187552760136346 0.4469311325853691 0.1497889600434833
+171 1.136555246481813 0.9253132713408032 -0.2607675417720481
+172 1.169875547734923 1.157176703594696 0.209783121723046
+173 1.252256239782287 1.161539312959809 -0.1396154626225087
+174 0.9854410532992778 1.295312212838649 0.232826117690098
+175 0.8998494176549744 0.8641570369932714 0.01526132714743774
+176 1.047849560177692 0.8788161627502054 0.2215760845022245
+177 1.402089433100673 1.077521710164203 0.04039637986273873
+178 1.03525188898502 1.249979305919021 -0.2281501268865102
+$EndNodes
+$Elements
+835
+1 2 2 1 1 10 112 1
+2 2 2 1 1 1 116 10
+3 2 2 1 1 11 116 1
+4 2 2 1 1 1 112 22
+5 2 2 1 1 3 113 2
+6 2 2 1 1 2 114 3
+7 2 2 1 1 2 113 23
+8 2 2 1 1 34 114 2
+9 2 2 1 1 4 101 3
+10 2 2 1 1 3 102 4
+11 2 2 1 1 101 113 3
+12 2 2 1 1 3 114 102
+13 2 2 1 1 4 43 5
+14 2 2 1 1 5 44 4
+15 2 2 1 1 4 102 43
+16 2 2 1 1 44 101 4
+17 2 2 1 1 5 84 6
+18 2 2 1 1 6 87 5
+19 2 2 1 1 43 84 5
+20 2 2 1 1 5 87 44
+21 2 2 1 1 7 39 6
+22 2 2 1 1 6 40 7
+23 2 2 1 1 39 87 6
+24 2 2 1 1 6 84 40
+25 2 2 1 1 7 85 8
+26 2 2 1 1 8 86 7
+27 2 2 1 1 7 86 39
+28 2 2 1 1 40 85 7
+29 2 2 1 1 9 41 8
+30 2 2 1 1 8 42 9
+31 2 2 1 1 41 86 8
+32 2 2 1 1 8 85 42
+33 2 2 1 1 10 98 9
+34 2 2 1 1 9 99 10
+35 2 2 1 1 9 98 41
+36 2 2 1 1 42 99 9
+37 2 2 1 1 10 116 98
+38 2 2 1 1 99 112 10
+39 2 2 1 1 23 50 24
+40 2 2 1 1 23 113 50
+41 2 2 1 1 24 89 25
+42 2 2 1 1 50 89 24
+43 2 2 1 1 25 37 26
+44 2 2 1 1 25 89 37
+45 2 2 1 1 26 83 27
+46 2 2 1 1 37 83 26
+47 2 2 1 1 27 46 28
+48 2 2 1 1 27 83 46
+49 2 2 1 1 28 93 29
+50 2 2 1 1 46 93 28
+51 2 2 1 1 29 47 30
+52 2 2 1 1 29 93 47
+53 2 2 1 1 30 81 31
+54 2 2 1 1 47 81 30
+55 2 2 1 1 31 38 32
+56 2 2 1 1 31 81 38
+57 2 2 1 1 32 92 33
+58 2 2 1 1 38 92 32
+59 2 2 1 1 33 51 34
+60 2 2 1 1 33 92 51
+61 2 2 1 1 51 114 34
+62 2 2 1 1 12 48 11
+63 2 2 1 1 48 116 11
+64 2 2 1 1 13 80 12
+65 2 2 1 1 12 80 48
+66 2 2 1 1 14 35 13
+67 2 2 1 1 35 80 13
+68 2 2 1 1 15 57 14
+69 2 2 1 1 14 57 35
+70 2 2 1 1 16 52 15
+71 2 2 1 1 52 57 15
+72 2 2 1 1 17 45 16
+73 2 2 1 1 45 52 16
+74 2 2 1 1 18 66 17
+75 2 2 1 1 17 66 45
+76 2 2 1 1 19 119 18
+77 2 2 1 1 18 119 66
+78 2 2 1 1 20 36 19
+79 2 2 1 1 36 119 19
+80 2 2 1 1 21 91 20
+81 2 2 1 1 20 91 36
+82 2 2 1 1 22 49 21
+83 2 2 1 1 49 91 21
+84 2 2 1 1 22 112 49
+85 2 2 1 1 57 58 35
+86 2 2 1 1 58 62 35
+87 2 2 1 1 62 80 35
+88 2 2 1 1 36 103 68
+89 2 2 1 1 68 119 36
+90 2 2 1 1 36 91 76
+91 2 2 1 1 76 103 36
+92 2 2 1 1 37 108 83
+93 2 2 1 1 89 90 37
+94 2 2 1 1 90 108 37
+95 2 2 1 1 81 82 38
+96 2 2 1 1 82 104 38
+97 2 2 1 1 38 104 92
+98 2 2 1 1 86 117 39
+99 2 2 1 1 39 97 87
+100 2 2 1 1 39 117 97
+101 2 2 1 1 40 84 77
+102 2 2 1 1 77 106 40
+103 2 2 1 1 40 106 85
+104 2 2 1 1 41 110 86
+105 2 2 1 1 41 98 94
+106 2 2 1 1 94 110 41
+107 2 2 1 1 85 111 42
+108 2 2 1 1 42 100 99
+109 2 2 1 1 42 111 100
+110 2 2 1 1 43 120 84
+111 2 2 1 1 102 115 43
+112 2 2 1 1 115 120 43
+113 2 2 1 1 87 88 44
+114 2 2 1 1 88 96 44
+115 2 2 1 1 96 101 44
+116 2 2 1 1 45 53 52
+117 2 2 1 1 45 55 53
+118 2 2 1 1 45 66 55
+119 2 2 1 1 83 109 46
+120 2 2 1 1 46 121 93
+121 2 2 1 1 109 121 46
+122 2 2 1 1 79 107 47
+123 2 2 1 1 47 122 79
+124 2 2 1 1 47 107 81
+125 2 2 1 1 93 122 47
+126 2 2 1 1 80 94 48
+127 2 2 1 1 94 98 48
+128 2 2 1 1 98 116 48
+129 2 2 1 1 49 100 91
+130 2 2 1 1 99 100 49
+131 2 2 1 1 49 112 99
+132 2 2 1 1 50 96 89
+133 2 2 1 1 50 101 96
+134 2 2 1 1 50 113 101
+135 2 2 1 1 92 115 51
+136 2 2 1 1 102 114 51
+137 2 2 1 1 51 115 102
+138 2 2 1 1 53 54 52
+139 2 2 1 1 54 57 52
+140 2 2 1 1 53 65 54
+141 2 2 1 1 55 56 53
+142 2 2 1 1 56 65 53
+143 2 2 1 1 54 58 57
+144 2 2 1 1 54 59 58
+145 2 2 1 1 54 118 59
+146 2 2 1 1 65 118 54
+147 2 2 1 1 55 79 56
+148 2 2 1 1 66 67 55
+149 2 2 1 1 67 79 55
+150 2 2 1 1 56 121 65
+151 2 2 1 1 79 122 56
+152 2 2 1 1 93 121 56
+153 2 2 1 1 56 122 93
+154 2 2 1 1 59 60 58
+155 2 2 1 1 60 62 58
+156 2 2 1 1 59 61 60
+157 2 2 1 1 59 63 61
+158 2 2 1 1 59 118 63
+159 2 2 1 1 61 95 60
+160 2 2 1 1 60 64 62
+161 2 2 1 1 60 95 64
+162 2 2 1 1 63 108 61
+163 2 2 1 1 61 105 95
+164 2 2 1 1 61 108 105
+165 2 2 1 1 64 110 62
+166 2 2 1 1 62 94 80
+167 2 2 1 1 62 110 94
+168 2 2 1 1 83 108 63
+169 2 2 1 1 63 109 83
+170 2 2 1 1 63 118 109
+171 2 2 1 1 95 117 64
+172 2 2 1 1 64 117 110
+173 2 2 1 1 109 118 65
+174 2 2 1 1 65 121 109
+175 2 2 1 1 66 68 67
+176 2 2 1 1 66 119 68
+177 2 2 1 1 68 69 67
+178 2 2 1 1 69 70 67
+179 2 2 1 1 70 79 67
+180 2 2 1 1 68 103 69
+181 2 2 1 1 69 71 70
+182 2 2 1 1 69 72 71
+183 2 2 1 1 69 103 72
+184 2 2 1 1 71 82 70
+185 2 2 1 1 70 107 79
+186 2 2 1 1 82 107 70
+187 2 2 1 1 72 73 71
+188 2 2 1 1 73 74 71
+189 2 2 1 1 74 82 71
+190 2 2 1 1 72 75 73
+191 2 2 1 1 72 76 75
+192 2 2 1 1 72 103 76
+193 2 2 1 1 73 77 74
+194 2 2 1 1 75 106 73
+195 2 2 1 1 73 106 77
+196 2 2 1 1 77 78 74
+197 2 2 1 1 78 104 74
+198 2 2 1 1 74 104 82
+199 2 2 1 1 76 111 75
+200 2 2 1 1 85 106 75
+201 2 2 1 1 75 111 85
+202 2 2 1 1 91 100 76
+203 2 2 1 1 100 111 76
+204 2 2 1 1 77 120 78
+205 2 2 1 1 84 120 77
+206 2 2 1 1 92 104 78
+207 2 2 1 1 78 115 92
+208 2 2 1 1 78 120 115
+209 2 2 1 1 81 107 82
+210 2 2 1 1 110 117 86
+211 2 2 1 1 87 97 88
+212 2 2 1 1 90 96 88
+213 2 2 1 1 88 105 90
+214 2 2 1 1 97 105 88
+215 2 2 1 1 89 96 90
+216 2 2 1 1 105 108 90
+217 2 2 1 1 95 105 97
+218 2 2 1 1 97 117 95
+219 2 2 2 2 23 136 2
+220 2 2 2 2 2 127 34
+221 2 2 2 2 2 136 127
+222 2 2 2 2 24 126 23
+223 2 2 2 2 126 136 23
+224 2 2 2 2 25 128 24
+225 2 2 2 2 24 128 126
+226 2 2 2 2 26 137 25
+227 2 2 2 2 25 137 128
+228 2 2 2 2 27 124 26
+229 2 2 2 2 124 137 26
+230 2 2 2 2 28 132 27
+231 2 2 2 2 27 132 124
+232 2 2 2 2 29 132 28
+233 2 2 2 2 30 125 29
+234 2 2 2 2 125 132 29
+235 2 2 2 2 31 134 30
+236 2 2 2 2 30 134 125
+237 2 2 2 2 32 134 31
+238 2 2 2 2 33 123 32
+239 2 2 2 2 123 134 32
+240 2 2 2 2 34 135 33
+241 2 2 2 2 33 135 123
+242 2 2 2 2 127 135 34
+243 2 2 2 2 127 131 123
+244 2 2 2 2 123 135 127
+245 2 2 2 2 131 133 123
+246 2 2 2 2 133 134 123
+247 2 2 2 2 124 130 129
+248 2 2 2 2 129 137 124
+249 2 2 2 2 124 132 130
+250 2 2 2 2 130 132 125
+251 2 2 2 2 125 133 130
+252 2 2 2 2 125 134 133
+253 2 2 2 2 126 131 127
+254 2 2 2 2 127 136 126
+255 2 2 2 2 128 129 126
+256 2 2 2 2 129 131 126
+257 2 2 2 2 128 137 129
+258 2 2 2 2 130 131 129
+259 2 2 2 2 130 133 131
+260 2 2 3 3 11 1 151
+261 2 2 3 3 1 22 142
+262 2 2 3 3 1 142 151
+263 2 2 3 3 12 11 141
+264 2 2 3 3 141 11 151
+265 2 2 3 3 13 12 143
+266 2 2 3 3 12 141 143
+267 2 2 3 3 14 13 152
+268 2 2 3 3 13 143 152
+269 2 2 3 3 15 14 139
+270 2 2 3 3 139 14 152
+271 2 2 3 3 16 15 147
+272 2 2 3 3 15 139 147
+273 2 2 3 3 17 16 147
+274 2 2 3 3 18 17 140
+275 2 2 3 3 140 17 147
+276 2 2 3 3 19 18 149
+277 2 2 3 3 18 140 149
+278 2 2 3 3 20 19 149
+279 2 2 3 3 21 20 138
+280 2 2 3 3 138 20 149
+281 2 2 3 3 22 21 150
+282 2 2 3 3 21 138 150
+283 2 2 3 3 142 22 150
+284 2 2 3 3 142 138 146
+285 2 2 3 3 138 142 150
+286 2 2 3 3 146 138 148
+287 2 2 3 3 148 138 149
+288 2 2 3 3 139 144 145
+289 2 2 3 3 144 139 152
+290 2 2 3 3 139 145 147
+291 2 2 3 3 145 140 147
+292 2 2 3 3 140 145 148
+293 2 2 3 3 140 148 149
+294 2 2 3 3 141 142 146
+295 2 2 3 3 142 141 151
+296 2 2 3 3 143 141 144
+297 2 2 3 3 144 141 146
+298 2 2 3 3 143 144 152
+299 2 2 3 3 145 144 146
+300 2 2 3 3 145 146 148
+301 4 2 1 1 106 161 155 171
+302 4 2 1 1 50 157 126 160
+303 4 2 1 1 56 161 156 170
+304 4 2 1 1 157 159 130 160
+305 4 2 1 1 50 96 157 160
+306 4 2 1 1 106 73 161 171
+307 4 2 1 1 106 155 75 171
+308 4 2 1 1 75 171 155 173
+309 4 2 1 1 126 129 128 160
+310 4 2 1 1 79 164 161 170
+311 4 2 1 1 55 156 56 161
+312 4 2 1 1 130 160 159 164
+313 4 2 1 1 56 79 161 170
+314 4 2 1 1 85 173 155 177
+315 4 2 1 1 126 128 89 160
+316 4 2 1 1 97 166 155 167
+317 4 2 1 1 106 75 73 171
+318 4 2 1 1 115 159 157 165
+319 4 2 1 1 50 126 89 160
+320 4 2 1 1 96 157 160 167
+321 4 2 1 1 75 155 85 173
+322 4 2 1 1 156 161 55 175
+323 4 2 1 1 50 89 96 160
+324 4 2 1 1 131 130 157 159
+325 4 2 1 1 75 106 85 155
+326 4 2 1 1 155 77 165 169
+327 4 2 1 1 115 78 159 165
+328 4 2 1 1 56 164 79 170
+329 4 2 1 1 106 77 155 169
+330 4 2 1 1 137 128 129 160
+331 4 2 1 1 106 73 77 169
+332 4 2 1 1 131 157 130 160
+333 4 2 1 1 107 161 164 169
+334 4 2 1 1 87 155 6 165
+335 4 2 1 1 87 155 165 167
+336 4 2 1 1 131 133 130 159
+337 4 2 1 1 97 155 87 167
+338 4 2 1 1 153 159 157 160
+339 4 2 1 1 161 164 153 170
+340 4 2 1 1 129 126 157 160
+341 4 2 1 1 56 122 79 164
+342 4 2 1 1 145 148 146 163
+343 4 2 1 1 79 55 56 161
+344 4 2 1 1 137 89 128 160
+345 4 2 1 1 159 160 153 164
+346 4 2 1 1 107 161 79 164
+347 4 2 1 1 127 51 135 157
+348 4 2 1 1 55 53 56 156
+349 4 2 1 1 159 165 78 169
+350 4 2 1 1 130 159 133 164
+351 4 2 1 1 107 164 159 169
+352 4 2 1 1 55 53 156 175
+353 4 2 1 1 61 166 156 168
+354 4 2 1 1 114 135 127 51
+355 4 2 1 1 67 161 171 175
+356 4 2 1 1 127 135 123 157
+357 4 2 1 1 61 95 166 168
+358 4 2 1 1 148 146 163 178
+359 4 2 1 1 156 166 155 168
+360 4 2 1 1 136 126 113 157
+361 4 2 1 1 153 155 166 167
+362 4 2 1 1 87 6 5 165
+363 4 2 1 1 153 164 161 169
+364 4 2 1 1 9 41 158 177
+365 4 2 1 1 129 157 131 160
+366 4 2 1 1 67 55 161 175
+367 4 2 1 1 101 50 96 157
+368 4 2 1 1 156 161 153 170
+369 4 2 1 1 155 171 154 173
+370 4 2 1 1 46 160 164 170
+371 4 2 1 1 59 61 156 168
+372 4 2 1 1 3 136 113 157
+373 4 2 1 1 150 49 112 178
+374 4 2 1 1 115 157 43 165
+375 4 2 1 1 158 162 146 163
+376 4 2 1 1 97 39 87 155
+377 4 2 1 1 145 146 162 163
+378 4 2 1 1 102 43 115 157
+379 4 2 1 1 117 155 97 168
+380 4 2 1 1 154 155 173 177
+381 4 2 1 1 155 156 153 166
+382 4 2 1 1 77 40 155 165
+383 4 2 1 1 129 131 130 160
+384 4 2 1 1 9 158 173 177
+385 4 2 1 1 158 163 146 178
+386 4 2 1 1 150 112 142 178
+387 4 2 1 1 154 161 156 175
+388 4 2 1 1 41 172 158 177
+389 4 2 1 1 133 131 123 159
+390 4 2 1 1 126 50 113 157
+391 4 2 1 1 117 97 95 168
+392 4 2 1 1 56 156 65 170
+393 4 2 1 1 3 127 136 157
+394 4 2 1 1 125 130 133 164
+395 4 2 1 1 101 113 50 157
+396 4 2 1 1 51 102 115 157
+397 4 2 1 1 125 159 81 164
+398 4 2 1 1 153 155 165 169
+399 4 2 1 1 153 165 155 167
+400 4 2 1 1 87 165 5 167
+401 4 2 1 1 87 39 6 155
+402 4 2 1 1 37 89 137 160
+403 4 2 1 1 107 70 161 169
+404 4 2 1 1 46 160 132 164
+405 4 2 1 1 40 106 77 155
+406 4 2 1 1 125 133 159 164
+407 4 2 1 1 67 171 163 175
+408 4 2 1 1 59 60 61 168
+409 4 2 1 1 131 157 123 159
+410 4 2 1 1 127 114 51 157
+411 4 2 1 1 118 156 59 166
+412 4 2 1 1 117 39 97 155
+413 4 2 1 1 116 141 151 158
+414 4 2 1 1 101 157 96 167
+415 4 2 1 1 72 161 73 171
+416 4 2 1 1 53 65 56 156
+417 4 2 1 1 67 55 79 161
+418 4 2 1 1 96 160 90 167
+419 4 2 1 1 126 131 129 157
+420 4 2 1 1 43 157 4 165
+421 4 2 1 1 105 166 97 167
+422 4 2 1 1 157 159 153 165
+423 4 2 1 1 153 156 155 161
+424 4 2 1 1 59 156 61 166
+425 4 2 1 1 155 161 154 171
+426 4 2 1 1 107 159 82 169
+427 4 2 1 1 72 73 75 171
+428 4 2 1 1 107 81 159 164
+429 4 2 1 1 145 140 163 175
+430 4 2 1 1 95 97 105 166
+431 4 2 1 1 153 161 155 169
+432 4 2 1 1 156 166 118 170
+433 4 2 1 1 115 78 92 159
+434 4 2 1 1 10 116 151 158
+435 4 2 1 1 63 166 160 170
+436 4 2 1 1 96 89 90 160
+437 4 2 1 1 43 102 4 157
+438 4 2 1 1 124 132 46 160
+439 4 2 1 1 102 51 114 157
+440 4 2 1 1 4 165 157 167
+441 4 2 1 1 124 46 83 160
+442 4 2 1 1 145 163 162 175
+443 4 2 1 1 130 132 160 164
+444 4 2 1 1 61 60 95 168
+445 4 2 1 1 85 106 40 155
+446 4 2 1 1 154 171 161 175
+447 4 2 1 1 151 142 10 158
+448 4 2 1 1 83 160 46 170
+449 4 2 1 1 137 124 83 160
+450 4 2 1 1 47 125 81 164
+451 4 2 1 1 136 127 126 157
+452 4 2 1 1 107 70 79 161
+453 4 2 1 1 85 155 7 177
+454 4 2 1 1 9 41 98 158
+455 4 2 1 1 77 84 40 165
+456 4 2 1 1 39 155 117 177
+457 4 2 1 1 58 162 172 176
+458 4 2 1 1 5 165 4 167
+459 4 2 1 1 104 159 78 169
+460 4 2 1 1 9 8 41 177
+461 4 2 1 1 59 168 156 176
+462 4 2 1 1 98 158 41 172
+463 4 2 1 1 155 156 154 161
+464 4 2 1 1 78 115 120 165
+465 4 2 1 1 112 158 142 178
+466 4 2 1 1 109 83 46 170
+467 4 2 1 1 112 99 158 178
+468 4 2 1 1 112 49 99 178
+469 4 2 1 1 125 134 81 159
+470 4 2 1 1 63 118 59 166
+471 4 2 1 1 101 4 157 167
+472 4 2 1 1 154 162 158 163
+473 4 2 1 1 156 175 53 176
+474 4 2 1 1 71 73 72 161
+475 4 2 1 1 123 131 127 157
+476 4 2 1 1 155 168 117 177
+477 4 2 1 1 153 165 159 169
+478 4 2 1 1 137 83 37 160
+479 4 2 1 1 73 161 71 169
+480 4 2 1 1 66 67 163 175
+481 4 2 1 1 9 173 8 177
+482 4 2 1 1 46 164 121 170
+483 4 2 1 1 153 159 164 169
+484 4 2 1 1 48 116 98 174
+485 4 2 1 1 88 105 97 167
+486 4 2 1 1 116 158 98 174
+487 4 2 1 1 139 57 52 162
+488 4 2 1 1 160 166 90 167
+489 4 2 1 1 103 163 171 178
+490 4 2 1 1 145 147 140 175
+491 4 2 1 1 153 160 157 167
+492 4 2 1 1 104 92 78 159
+493 4 2 1 1 140 66 163 175
+494 4 2 1 1 101 44 4 167
+495 4 2 1 1 124 130 132 160
+496 4 2 1 1 113 101 3 157
+497 4 2 1 1 158 172 98 174
+498 4 2 1 1 154 163 158 178
+499 4 2 1 1 58 162 35 172
+500 4 2 1 1 67 68 163 171
+501 4 2 1 1 141 158 116 174
+502 4 2 1 1 118 166 63 170
+503 4 2 1 1 152 162 144 174
+504 4 2 1 1 3 114 127 157
+505 4 2 1 1 107 82 70 169
+506 4 2 1 1 120 115 43 165
+507 4 2 1 1 107 47 81 164
+508 4 2 1 1 108 160 63 166
+509 4 2 1 1 85 40 7 155
+510 4 2 1 1 35 162 152 174
+511 4 2 1 1 172 173 158 177
+512 4 2 1 1 139 52 147 162
+513 4 2 1 1 44 5 4 167
+514 4 2 1 1 107 81 82 159
+515 4 2 1 1 78 165 120 169
+516 4 2 1 1 6 84 5 165
+517 4 2 1 1 144 152 139 162
+518 4 2 1 1 54 156 53 176
+519 4 2 1 1 35 172 162 174
+520 4 2 1 1 98 172 94 174
+521 4 2 1 1 99 9 158 173
+522 4 2 1 1 7 6 39 155
+523 4 2 1 1 140 45 66 175
+524 4 2 1 1 151 141 142 158
+525 4 2 1 1 124 129 130 160
+526 4 2 1 1 5 43 4 165
+527 4 2 1 1 54 65 53 156
+528 4 2 1 1 145 162 147 175
+529 4 2 1 1 69 67 161 171
+530 4 2 1 1 129 124 137 160
+531 4 2 1 1 86 39 117 177
+532 4 2 1 1 148 145 140 163
+533 4 2 1 1 102 114 3 157
+534 4 2 1 1 143 35 152 174
+535 4 2 1 1 154 156 155 168
+536 4 2 1 1 149 148 163 178
+537 4 2 1 1 70 67 79 161
+538 4 2 1 1 153 164 160 170
+539 4 2 1 1 54 59 118 156
+540 4 2 1 1 7 155 39 177
+541 4 2 1 1 101 4 3 157
+542 4 2 1 1 59 60 168 176
+543 4 2 1 1 152 139 57 14
+544 4 2 1 1 125 133 134 159
+545 4 2 1 1 99 173 158 178
+546 4 2 1 1 56 121 164 170
+547 4 2 1 1 142 138 150 178
+548 4 2 1 1 146 162 158 174
+549 4 2 1 1 99 42 9 173
+550 4 2 1 1 112 10 142 158
+551 4 2 1 1 58 57 162 176
+552 4 2 1 1 49 150 91 178
+553 4 2 1 1 144 162 146 174
+554 4 2 1 1 4 102 3 157
+555 4 2 1 1 46 93 121 164
+556 4 2 1 1 38 123 92 159
+557 4 2 1 1 103 36 163 178
+558 4 2 1 1 83 63 108 160
+559 4 2 1 1 65 156 118 170
+560 4 2 1 1 68 66 67 163
+561 4 2 1 1 147 45 140 175
+562 4 2 1 1 54 118 65 156
+563 4 2 1 1 154 158 173 178
+564 4 2 1 1 128 137 25 89
+565 4 2 1 1 71 161 72 171
+566 4 2 1 1 52 175 162 176
+567 4 2 1 1 48 98 94 174
+568 4 2 1 1 69 67 70 161
+569 4 2 1 1 52 162 57 176
+570 4 2 1 1 103 171 76 178
+571 4 2 1 1 123 38 134 159
+572 4 2 1 1 142 158 146 178
+573 4 2 1 1 86 117 168 177
+574 4 2 1 1 98 41 94 172
+575 4 2 1 1 131 126 127 157
+576 4 2 1 1 88 97 87 167
+577 4 2 1 1 112 99 10 158
+578 4 2 1 1 56 93 122 164
+579 4 2 1 1 9 42 8 173
+580 4 2 1 1 91 150 138 178
+581 4 2 1 1 147 162 52 175
+582 4 2 1 1 99 100 173 178
+583 4 2 1 1 75 76 171 173
+584 4 2 1 1 138 146 148 178
+585 4 2 1 1 10 99 9 158
+586 4 2 1 1 157 165 153 167
+587 4 2 1 1 144 145 146 162
+588 4 2 1 1 77 120 165 169
+589 4 2 1 1 149 138 148 178
+590 4 2 1 1 137 26 83 124
+591 4 2 1 1 149 163 36 178
+592 4 2 1 1 87 5 44 167
+593 4 2 1 1 153 166 160 167
+594 4 2 1 1 154 173 163 178
+595 4 2 1 1 71 69 161 171
+596 4 2 1 1 70 71 161 169
+597 4 2 1 1 153 160 166 170
+598 4 2 1 1 154 175 156 176
+599 4 2 1 1 61 95 105 166
+600 4 2 1 1 48 141 116 174
+601 4 2 1 1 10 98 116 158
+602 4 2 1 1 66 55 67 175
+603 4 2 1 1 90 166 105 167
+604 4 2 1 1 56 121 93 164
+605 4 2 1 1 156 153 166 170
+606 4 2 1 1 9 98 10 158
+607 4 2 1 1 7 40 6 155
+608 4 2 1 1 58 57 35 162
+609 4 2 1 1 163 173 171 178
+610 4 2 1 1 46 132 93 164
+611 4 2 1 1 111 75 85 173
+612 4 2 1 1 139 57 15 52
+613 4 2 1 1 171 173 76 178
+614 4 2 1 1 62 58 35 172
+615 4 2 1 1 29 125 47 164
+616 4 2 1 1 80 172 35 174
+617 4 2 1 1 17 66 140 45
+618 4 2 1 1 77 78 120 169
+619 4 2 1 1 138 142 146 178
+620 4 2 1 1 119 140 66 163
+621 4 2 1 1 90 89 37 160
+622 4 2 1 1 86 7 39 177
+623 4 2 1 1 73 71 74 169
+624 4 2 1 1 134 38 81 159
+625 4 2 1 1 149 36 138 178
+626 4 2 1 1 59 156 54 176
+627 4 2 1 1 154 171 163 173
+628 4 2 1 1 117 110 86 168
+629 4 2 1 1 63 59 61 166
+630 4 2 1 1 123 134 133 159
+631 4 2 1 1 141 146 158 174
+632 4 2 1 1 75 111 76 173
+633 4 2 1 1 86 168 110 177
+634 4 2 1 1 36 91 138 178
+635 4 2 1 1 82 159 104 169
+636 4 2 1 1 93 29 47 164
+637 4 2 1 1 158 172 154 173
+638 4 2 1 1 81 47 30 125
+639 4 2 1 1 37 26 83 137
+640 4 2 1 1 52 53 175 176
+641 4 2 1 1 154 173 172 177
+642 4 2 1 1 146 142 141 158
+643 4 2 1 1 90 160 108 166
+644 4 2 1 1 70 82 71 169
+645 4 2 1 1 163 171 154 175
+646 4 2 1 1 44 101 96 167
+647 4 2 1 1 73 74 77 169
+648 4 2 1 1 158 162 154 172
+649 4 2 1 1 152 57 35 14
+650 4 2 1 1 71 72 69 171
+651 4 2 1 1 143 152 144 174
+652 4 2 1 1 62 60 58 168
+653 4 2 1 1 92 51 135 33
+654 4 2 1 1 48 143 141 174
+655 4 2 1 1 91 49 21 150
+656 4 2 1 1 42 85 8 173
+657 4 2 1 1 99 49 100 178
+658 4 2 1 1 130 125 132 164
+659 4 2 1 1 41 110 172 177
+660 4 2 1 1 15 147 139 52
+661 4 2 1 1 64 117 95 168
+662 4 2 1 1 13 143 35 152
+663 4 2 1 1 136 3 2 127
+664 4 2 1 1 58 168 60 176
+665 4 2 1 1 103 76 36 178
+666 4 2 1 1 10 1 142 151
+667 4 2 1 1 64 110 168 172
+668 4 2 1 1 138 91 21 150
+669 4 2 1 1 52 54 53 176
+670 4 2 1 1 38 82 81 159
+671 4 2 1 1 67 69 68 171
+672 4 2 1 1 138 91 36 20
+673 4 2 1 1 92 135 123 33
+674 4 2 1 1 48 80 143 174
+675 4 2 1 1 8 173 85 177
+676 4 2 1 1 27 46 83 124
+677 4 2 1 1 70 71 69 161
+678 4 2 1 1 103 163 68 171
+679 4 2 1 1 119 149 140 163
+680 4 2 1 1 147 17 140 45
+681 4 2 1 1 137 37 25 89
+682 4 2 1 1 168 172 110 177
+683 4 2 1 1 46 121 109 170
+684 4 2 1 1 149 119 36 163
+685 4 2 1 1 154 168 155 177
+686 4 2 1 1 64 168 62 172
+687 4 2 1 1 38 92 104 159
+688 4 2 1 1 109 118 63 170
+689 4 2 1 1 59 58 60 176
+690 4 2 1 1 75 76 72 171
+691 4 2 1 1 38 104 82 159
+692 4 2 1 1 99 100 42 173
+693 4 2 1 1 143 80 35 174
+694 4 2 1 1 162 163 154 175
+695 4 2 1 1 138 36 149 20
+696 4 2 1 1 117 64 110 168
+697 4 2 1 1 36 68 103 163
+698 4 2 1 1 90 105 88 167
+699 4 2 1 1 80 62 35 172
+700 4 2 1 1 139 145 144 162
+701 4 2 1 1 147 52 45 175
+702 4 2 1 1 141 144 146 174
+703 4 2 1 1 56 65 121 170
+704 4 2 1 1 108 90 37 160
+705 4 2 1 1 134 81 30 125
+706 4 2 1 1 154 156 168 176
+707 4 2 1 1 148 140 149 163
+708 4 2 1 1 123 32 38 92
+709 4 2 1 1 116 11 151 141
+710 4 2 1 1 119 18 66 140
+711 4 2 1 1 113 136 23 126
+712 4 2 1 1 83 108 37 160
+713 4 2 1 1 145 139 147 162
+714 4 2 1 1 96 90 88 167
+715 4 2 1 1 68 36 119 163
+716 4 2 1 1 76 173 100 178
+717 4 2 1 1 64 62 110 172
+718 4 2 1 1 64 60 62 168
+719 4 2 1 1 64 95 60 168
+720 4 2 1 1 12 143 141 48
+721 4 2 1 1 74 104 78 169
+722 4 2 1 1 48 12 143 80
+723 4 2 1 1 154 172 168 177
+724 4 2 1 1 52 57 54 176
+725 4 2 1 1 77 74 78 169
+726 4 2 1 1 119 66 68 163
+727 4 2 1 1 43 5 84 165
+728 4 2 1 1 162 154 172 176
+729 4 2 1 1 77 120 84 165
+730 4 2 1 1 38 32 123 134
+731 4 2 1 1 47 122 93 164
+732 4 2 1 1 42 111 85 173
+733 4 2 1 1 100 76 111 173
+734 4 2 1 1 66 45 55 175
+735 4 2 1 1 127 3 2 114
+736 4 2 1 1 162 172 158 174
+737 4 2 1 1 168 172 154 176
+738 4 2 1 1 41 86 110 177
+739 4 2 1 1 109 65 118 170
+740 4 2 1 1 1 10 142 112
+741 4 2 1 1 87 44 88 167
+742 4 2 1 1 74 71 82 169
+743 4 2 1 1 41 8 86 177
+744 4 2 1 1 46 27 132 124
+745 4 2 1 1 43 84 120 165
+746 4 2 1 1 13 143 80 35
+747 4 2 1 1 8 85 7 177
+748 4 2 1 1 82 104 74 169
+749 4 2 1 1 91 36 76 178
+750 4 2 1 1 103 72 76 171
+751 4 2 1 1 80 94 172 174
+752 4 2 1 1 132 93 28 46
+753 4 2 1 1 116 11 141 48
+754 4 2 1 1 126 23 113 50
+755 4 2 1 1 94 41 110 172
+756 4 2 1 1 69 103 68 171
+757 4 2 1 1 45 147 16 52
+758 4 2 1 1 26 27 83 124
+759 4 2 1 1 80 48 94 174
+760 4 2 1 1 15 57 139 14
+761 4 2 1 1 24 23 126 50
+762 4 2 1 1 90 108 105 166
+763 4 2 1 1 91 100 49 178
+764 4 2 1 1 38 81 31 134
+765 4 2 1 1 105 108 61 166
+766 4 2 1 1 150 22 142 112
+767 4 2 1 1 138 21 91 20
+768 4 2 1 1 59 54 58 176
+769 4 2 1 1 114 127 135 34
+770 4 2 1 1 2 3 136 113
+771 4 2 1 1 1 10 116 151
+772 4 2 1 1 154 162 175 176
+773 4 2 1 1 119 149 18 140
+774 4 2 1 1 17 147 16 45
+775 4 2 1 1 61 108 63 166
+776 4 2 1 1 29 30 47 125
+777 4 2 1 1 92 123 32 33
+778 4 2 1 1 76 100 91 178
+779 4 2 1 1 93 28 29 132
+780 4 2 1 1 121 65 109 170
+781 4 2 1 1 58 54 57 176
+782 4 2 1 1 100 111 42 173
+783 4 2 1 1 140 18 66 17
+784 4 2 1 1 21 49 22 150
+785 4 2 1 1 8 7 86 177
+786 4 2 1 1 94 110 62 172
+787 4 2 1 1 12 141 11 48
+788 4 2 1 1 96 88 44 167
+789 4 2 1 1 80 94 62 172
+790 4 2 1 1 49 22 150 112
+791 4 2 1 1 45 53 55 175
+792 4 2 1 1 135 114 34 51
+793 4 2 1 1 45 52 53 175
+794 4 2 1 1 13 143 12 80
+795 4 2 1 1 22 1 142 112
+796 4 2 1 1 37 25 26 137
+797 4 2 1 1 114 2 127 34
+798 4 2 1 1 19 149 36 20
+799 4 2 1 1 81 30 31 134
+800 4 2 1 1 119 19 149 36
+801 4 2 1 1 69 72 103 171
+802 4 2 1 1 15 16 147 52
+803 4 2 1 1 128 25 24 89
+804 4 2 1 1 51 34 135 33
+805 4 2 1 1 144 141 143 174
+806 4 2 1 1 11 1 116 151
+807 4 2 1 1 38 31 32 134
+808 4 2 1 1 136 23 2 113
+809 4 2 1 1 28 27 132 46
+810 4 2 1 1 35 13 152 14
+811 4 2 1 1 149 18 19 119
+812 4 2 1 1 161 106 169 73
+813 4 2 1 1 161 169 106 155
+814 4 2 1 1 168 97 166 155
+815 4 2 1 1 168 166 97 95
+816 4 2 1 1 159 51 115 157
+817 4 2 1 1 159 115 51 92
+818 4 2 1 1 165 40 6 84
+819 4 2 1 1 165 6 40 155
+820 4 2 1 1 126 89 24 50
+821 4 2 1 1 24 89 126 128
+822 4 2 1 1 170 83 63 109
+823 4 2 1 1 170 63 83 160
+824 4 2 1 1 135 92 159 51
+825 4 2 1 1 159 92 135 123
+826 4 2 1 1 159 157 135 51
+827 4 2 1 1 135 157 159 123
+828 4 2 1 1 152 57 162 35
+829 4 2 1 1 152 162 57 139
+830 4 2 1 1 164 29 132 93
+831 4 2 1 1 164 132 29 125
+832 4 2 1 1 172 58 168 62
+833 4 2 1 1 172 168 58 176
+834 4 2 1 1 79 47 164 122
+835 4 2 1 1 79 164 47 107
+$EndElements
+$Periodic
+1
+2 3 2
+Affine 0.5000000000000001 -0.8660254037844386 0 0 0.8660254037844386 0.5000000000000001 0 0 0 0 1 0 0 0 0 1
+28
+152 137
+141 126
+147 132
+150 135
+149 134
+145 130
+139 124
+144 129
+143 128
+140 125
+138 123
+148 133
+142 127
+151 136
+146 131
+11 23
+12 24
+13 25
+16 28
+14 26
+17 29
+15 27
+18 30
+21 33
+19 31
+22 34
+20 32
+1 2
+$EndPeriodic
diff --git a/miniapps/nurbs/pipe-nurbs-2d.mesh b/data/pipe-nurbs-2d.mesh
similarity index 100%
rename from miniapps/nurbs/pipe-nurbs-2d.mesh
rename to data/pipe-nurbs-2d.mesh
diff --git a/data/square-disc-nurbs-patch.mesh b/data/square-disc-nurbs-patch.mesh
new file mode 100644
index 0000000000..4e9668a6c8
--- /dev/null
+++ b/data/square-disc-nurbs-patch.mesh
@@ -0,0 +1,155 @@
+MFEM NURBS mesh v1.0
+
+dimension
+2
+
+elements
+5
+1 3 0 3 7 4
+1 3 3 2 6 7
+1 3 2 1 5 6
+1 3 1 0 4 5
+1 3 2 8 9 1
+
+boundary
+10
+1 1 0 3
+2 1 3 2
+2 1 1 0
+2 1 2 8
+2 1 9 1
+3 1 7 4
+3 1 6 7
+3 1 5 6
+3 1 4 5
+4 1 8 9
+
+edges
+15
+0 0 4
+0 3 7
+0 1 5
+0 2 6
+1 0 3
+1 4 7
+2 3 2
+2 7 6
+2 1 0
+2 5 4
+1 2 1
+1 6 5
+1 8 9
+3 2 8
+3 1 9
+
+vertices
+10
+
+patches
+
+knotvectors
+2
+2 3 0 0 0 1 1 1
+2 4 0 0 0 0.5 1 1 1
+
+dimension
+2
+
+controlpoints_cartesian
+-5 5 1
+-5 3.92523e-16 1
+-5 -5 1
+-2.47593 2.47593 1
+-4.95187 6.06429e-16 0.707107
+-2.47593 -2.47593 1
+-0.424264 0.424264 1
+-0.848528 1.03915e-16 0.707107
+-0.424264 -0.424264 1
+-0.353553 0.353553 1
+-0.707107 8.65956e-17 0.707107
+-0.353553 -0.353553 1
+
+knotvectors
+2
+2 3 0 0 0 1 1 1
+2 4 0 0 0 0.5 1 1 1
+
+dimension
+2
+
+controlpoints_cartesian
+-5 -5 1
+-1.17757e-15 -5 1
+5 -5 1
+-2.47593 -2.47593 1
+-9.09644e-16 -4.95187 0.707107
+2.47593 -2.47593 1
+-0.424264 -0.424264 1
+-1.55872e-16 -0.848528 0.707107
+0.424264 -0.424264 1
+-0.353553 -0.353553 1
+-1.29893e-16 -0.707107 0.707107
+0.353553 -0.353553 1
+
+knotvectors
+2
+2 3 0 0 0 1 1 1
+2 4 0 0 0 0.5 1 1 1
+
+dimension
+2
+
+controlpoints_cartesian
+5 -5 1
+5 -1.17757e-15 1
+5 5 1
+2.47593 -2.47593 1
+4.95187 -1.21286e-15 0.707107
+2.47593 2.47593 1
+0.424264 -0.424264 1
+0.848528 -2.07829e-16 0.707107
+0.424264 0.424264 1
+0.353553 -0.353553 1
+0.707107 -1.73191e-16 0.707107
+0.353553 0.353553 1
+
+knotvectors
+2
+2 3 0 0 0 1 1 1
+2 4 0 0 0 0.5 1 1 1
+
+dimension
+2
+
+controlpoints_cartesian
+5 5 1
+3.92523e-16 5 1
+-5 5 1
+2.47593 2.47593 1
+3.03215e-16 4.95187 0.707107
+-2.47593 2.47593 1
+0.424264 0.424264 1
+5.19574e-17 0.848528 0.707107
+-0.424264 0.424264 1
+0.353553 0.353553 1
+4.32978e-17 0.707107 0.707107
+-0.353553 0.353553 1
+
+knotvectors
+2
+2 3 0 0 0 1 1 1
+2 3 0 0 0 1 1 1
+
+dimension
+2
+
+controlpoints_cartesian
+5 -5 1
+10 -5 1
+15 -5 1
+5 0 1
+10 0 1
+15 0 1
+5 5 1
+10 5 1
+15 5 1
diff --git a/miniapps/nurbs/square-nurbs.mesh b/data/square-nurbs.mesh
similarity index 100%
rename from miniapps/nurbs/square-nurbs.mesh
rename to data/square-nurbs.mesh
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 8a48e4045a..57ef3f97ab 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -16,36 +16,21 @@ if (DOXYGEN_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CodeDocumentation.conf.in
${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf @ONLY)
- if (UNIX)
- # Only create symlinks if UNIX operating system
- add_custom_target(doc
- COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
- COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
- COMMAND ${CMAKE_COMMAND} -E create_symlink
- ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
- ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
- BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMENT "Generating API documentation with Doxygen to CodeDocumentation.html"
- VERBATIM)
- add_custom_target(clean-doc
- COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
- COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
- COMMENT "Removing API documentation"
- VERBATIM)
+ add_custom_target(doc
+ COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
+ COMMAND echo "" > ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
+ BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating API documentation with Doxygen to CodeDocumentation.html"
+ VERBATIM)
+
+ add_custom_target(clean-doc
+ COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
+ COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/warnings.log
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
+ COMMENT "Removing API documentation"
+ VERBATIM)
- else (UNIX)
- add_custom_target(doc
- COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
- BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMENT "Generating API documentation with Doxygen to CodeDocumentation/html/index.html"
- VERBATIM)
- add_custom_target(clean-doc
- COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
- COMMENT "Removing API documentation"
- VERBATIM)
- endif (UNIX)
endif (DOXYGEN_FOUND)
diff --git a/doc/CodeDocumentation.conf.in b/doc/CodeDocumentation.conf.in
index 8b2f228406..20bd4d2b10 100644
--- a/doc/CodeDocumentation.conf.in
+++ b/doc/CodeDocumentation.conf.in
@@ -51,7 +51,7 @@ PROJECT_BRIEF = "Finite element discretization library"
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
-PROJECT_LOGO =
+PROJECT_LOGO = web/logo-small.png
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
@@ -746,7 +746,7 @@ WARN_FORMAT = "$file:$line: $text"
# messages should be written. If left blank the output is written to standard
# error (stderr).
-WARN_LOGFILE =
+WARN_LOGFILE = warnings.log
#---------------------------------------------------------------------------
# Configuration options related to the input files
@@ -1470,7 +1470,7 @@ MATHJAX_FORMAT = HTML-CSS
# The default value is: http://cdn.mathjax.org/mathjax/latest.
# This tag requires that the tag USE_MATHJAX is set to YES.
-MATHJAX_RELPATH = https://cdn.llnl.gov/mathjax/2.7.2
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
diff --git a/doc/CodeDocumentation.dox b/doc/CodeDocumentation.dox
index 6007ea7080..55d674c434 100644
--- a/doc/CodeDocumentation.dox
+++ b/doc/CodeDocumentation.dox
@@ -149,6 +149,7 @@ namespace mfem {
* - Extruder: extrude a low-dimensional mesh into a higher dimension
* - Mesh Explorer: visualize and manipulate meshes
* - Mesh Optimizer: optimize high-order meshes, serial and parallel versions
+ * - Trimmer: trim elements from existing meshes
* - Display Basis: visualize finite element basis functions
* - Get Values: extract field values via DataCollection classes
* - Load DC: visualize fields saved via DataCollection classes
diff --git a/doc/makefile b/doc/makefile
index f8e111f1f3..9a6ff29035 100644
--- a/doc/makefile
+++ b/doc/makefile
@@ -9,18 +9,25 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
+SHELL = /bin/bash
MFEM_DIR ?= ..
DOXYGEN_CONF = CodeDocumentation.conf
+
# doxygen uses: graphviz, latex
html: $(DOXYGEN_CONF)
- doxygen $(DOXYGEN_CONF)
- rm -f CodeDocumentation.html
- ln -s CodeDocumentation/html/index.html CodeDocumentation.html
+ @# Generate the html documentation
+ @doxygen $(DOXYGEN_CONF)
+ @echo "" > CodeDocumentation.html
+ @cat warnings.log
+ @# Generate the log of undocumented methods
+ @( cat $(DOXYGEN_CONF) ; echo "GENERATE_HTML=NO" ; echo "EXTRACT_ALL=NO" ; echo "WARN_LOGFILE=undoc.log" ; echo "QUIET=YES" ) | doxygen - &> /dev/null
clean:
rm -rf $(DOXYGEN_CONF) CodeDocumentation CodeDocumentation.html *~
+ rm -rf undoc.log warnings.log
$(DOXYGEN_CONF): $(MFEM_DIR)/doc/$(DOXYGEN_CONF).in
- sed -e 's%@MFEM_SOURCE_DIR@%$(MFEM_DIR)%g' $(<) \
+ @sed -e 's%@MFEM_SOURCE_DIR@%$(MFEM_DIR)%g' $(<) \
> $(DOXYGEN_CONF)
+
diff --git a/doc/web/logo-small.png b/doc/web/logo-small.png
new file mode 100644
index 0000000000..021cbcfe8a
Binary files /dev/null and b/doc/web/logo-small.png differ
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 6e7afdc1ad..6f5a1de336 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -91,7 +91,7 @@ foreach(SRC_FILE ${ALL_EXE_SRCS})
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
- add_test(NAME ${TEST_NAME}_np=4
+ add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$ ${THIS_TEST_OPTIONS}
@@ -101,13 +101,22 @@ endforeach()
# If STRUMPACK is enabled, add a test run that uses it.
if (MFEM_USE_STRUMPACK)
- add_test(NAME ex11p_strumpack_np=4
+ add_test(NAME ex11p_strumpack_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$ "-no-vis" "--strumpack"
${MPIEXEC_POSTFLAGS})
endif()
+# If SuperLU_DIST is enabled, add a test run that uses it.
+if (MFEM_USE_SUPERLU)
+ add_test(NAME ex11p_superlu_np=${MFEM_MPI_NP}
+ COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
+ ${MPIEXEC_PREFLAGS}
+ $ "-no-vis" "--superlu"
+ ${MPIEXEC_POSTFLAGS})
+endif()
+
# Include the examples/sundials directory if SUNDIALS is enabled.
if (MFEM_USE_SUNDIALS)
add_subdirectory(sundials)
diff --git a/examples/ex1.cpp b/examples/ex1.cpp
index c5e240c1b6..4f2f511b1b 100644
--- a/examples/ex1.cpp
+++ b/examples/ex1.cpp
@@ -9,6 +9,8 @@
// ex1 -m ../data/fichera.mesh
// ex1 -m ../data/fichera-mixed.mesh
// ex1 -m ../data/toroid-wedge.mesh
+// ex1 -m ../data/periodic-annulus-sector.msh
+// ex1 -m ../data/periodic-torus-sector.msh
// ex1 -m ../data/square-disc-p2.vtk -o 2
// ex1 -m ../data/square-disc-p3.mesh -o 3
// ex1 -m ../data/square-disc-nurbs.mesh -o -1
@@ -32,7 +34,8 @@
// ex1 -pa -d raja-omp
// ex1 -pa -d occa-omp
// ex1 -pa -d ceed-cpu
-// ex1 -pa -d ceed-cuda
+// * ex1 -pa -d ceed-cuda
+// ex1 -pa -d ceed-cuda:/gpu/cuda/shared
// ex1 -m ../data/beam-hex.mesh -pa -d cuda
// ex1 -m ../data/beam-tet.mesh -pa -d ceed-cpu
// ex1 -m ../data/beam-tet.mesh -pa -d ceed-cuda:/gpu/cuda/ref
diff --git a/examples/ex11p.cpp b/examples/ex11p.cpp
index 1dc807f859..de1e7ce689 100644
--- a/examples/ex11p.cpp
+++ b/examples/ex11p.cpp
@@ -8,6 +8,8 @@
// mpirun -np 4 ex11p -m ../data/escher.mesh
// mpirun -np 4 ex11p -m ../data/fichera.mesh
// mpirun -np 4 ex11p -m ../data/fichera-mixed.mesh
+// mpirun -np 4 ex11p -m ../data/periodic-annulus-sector.msh
+// mpirun -np 4 ex11p -m ../data/periodic-torus-sector.msh -rs 1
// mpirun -np 4 ex11p -m ../data/toroid-wedge.mesh -o 2
// mpirun -np 4 ex11p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex11p -m ../data/square-disc-p3.mesh -o 3
diff --git a/examples/ex18.hpp b/examples/ex18.hpp
index fe0e38ffc2..88ed7adadd 100644
--- a/examples/ex18.hpp
+++ b/examples/ex18.hpp
@@ -88,8 +88,6 @@ private:
Vector funval2;
Vector nor;
Vector fluxN;
- IntegrationPoint eip1;
- IntegrationPoint eip2;
public:
FaceIntegrator(RiemannSolver &rsolver_, const int dim);
@@ -418,27 +416,24 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
{
intorder++;
}
- const IntegrationRule *ir = &IntRules.Get(Tr.FaceGeom, intorder);
+ const IntegrationRule *ir = &IntRules.Get(Tr.GetGeometryType(), intorder);
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
- Tr.Loc1.Transform(ip, eip1);
- Tr.Loc2.Transform(ip, eip2);
+ Tr.SetAllIntPoints(&ip); // set face and element int. points
// Calculate basis functions on both elements at the face
- el1.CalcShape(eip1, shape1);
- el2.CalcShape(eip2, shape2);
+ el1.CalcShape(Tr.GetElement1IntPoint(), shape1);
+ el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
// Interpolate elfun at the point
elfun1_mat.MultTranspose(shape1, funval1);
elfun2_mat.MultTranspose(shape2, funval2);
- Tr.Face->SetIntPoint(&ip);
-
// Get the normal vector and the flux on the face
- CalcOrtho(Tr.Face->Jacobian(), nor);
+ CalcOrtho(Tr.Jacobian(), nor);
const double mcs = rsolver.Eval(funval1, funval2, nor, fluxN);
// Update max char speed
diff --git a/examples/ex1p.cpp b/examples/ex1p.cpp
index 83ede5910a..759b73cd79 100644
--- a/examples/ex1p.cpp
+++ b/examples/ex1p.cpp
@@ -9,6 +9,8 @@
// mpirun -np 4 ex1p -m ../data/fichera.mesh
// mpirun -np 4 ex1p -m ../data/fichera-mixed.mesh
// mpirun -np 4 ex1p -m ../data/toroid-wedge.mesh
+// mpirun -np 4 ex1p -m ../data/periodic-annulus-sector.msh
+// mpirun -np 4 ex1p -m ../data/periodic-torus-sector.msh
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3
// mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1
@@ -30,7 +32,8 @@
// 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 -pa -d ceed-cuda
+// mpirun -np 4 ex1p -pa -d ceed-cuda:/gpu/cuda/shared
// 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
diff --git a/examples/ex4p.cpp b/examples/ex4p.cpp
index 282ebb4fa3..afcbc23bca 100644
--- a/examples/ex4p.cpp
+++ b/examples/ex4p.cpp
@@ -16,6 +16,7 @@
// mpirun -np 4 ex4p -m ../data/periodic-square.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/periodic-cube.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/amr-quad.mesh
+// mpirun -np 3 ex4p -m ../data/amr-quad.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
diff --git a/examples/ex6.cpp b/examples/ex6.cpp
index 991d216454..e189e6f6ea 100644
--- a/examples/ex6.cpp
+++ b/examples/ex6.cpp
@@ -20,7 +20,7 @@
// ex6 -pa -d occa-cuda
// ex6 -pa -d raja-omp
// ex6 -pa -d ceed-cpu
-// * ex6 -pa -d ceed-cuda
+// * ex6 -pa -d ceed-cuda
// ex6 -pa -d ceed-cuda:/gpu/cuda/shared
//
// Description: This is a version of Example 1 with a simple adaptive mesh
diff --git a/examples/ex6p.cpp b/examples/ex6p.cpp
index 072e9a0cd6..0bbc8eec9f 100644
--- a/examples/ex6p.cpp
+++ b/examples/ex6p.cpp
@@ -20,7 +20,7 @@
// mpirun -np 4 ex6p -pa -d occa-cuda
// mpirun -np 4 ex6p -pa -d raja-omp
// mpirun -np 4 ex6p -pa -d ceed-cpu
-// * mpirun -np 4 ex6p -pa -d ceed-cuda
+// * mpirun -np 4 ex6p -pa -d ceed-cuda
// mpirun -np 4 ex6p -pa -d ceed-cuda:/gpu/cuda/shared
//
// Description: This is a version of Example 1 with a simple adaptive mesh
diff --git a/examples/ex9p.cpp b/examples/ex9p.cpp
index 68143e1861..cbbff953a2 100644
--- a/examples/ex9p.cpp
+++ b/examples/ex9p.cpp
@@ -16,6 +16,7 @@
// mpirun -np 4 ex9p -m ../data/disc-nurbs.mesh -p 2 -rp 1 -dt 0.005 -tf 9
// mpirun -np 4 ex9p -m ../data/periodic-square.mesh -p 3 -rp 2 -dt 0.0025 -tf 9 -vs 20
// mpirun -np 4 ex9p -m ../data/periodic-cube.mesh -p 0 -o 2 -rp 1 -dt 0.01 -tf 8
+// mpirun -np 3 ex9p -m ../data/amr-hex.mesh -p 1 -rs 1 -rp 0 -dt 0.005 -tf 0.5
//
// Device sample runs:
// mpirun -np 4 ex9p -pa
diff --git a/examples/makefile b/examples/makefile
index 5e677a5529..8b402a49a6 100644
--- a/examples/makefile
+++ b/examples/makefile
@@ -114,6 +114,11 @@ ex11p-test-strumpack: ex11p
@$(call mfem-test,$<, $(RUN_MPI), STRUMPACK example,--strumpack)
test-par-YES: ex11p-test-strumpack
endif
+ifeq ($(MFEM_USE_SUPERLU),YES)
+ex11p-test-superlu: ex11p
+ @$(call mfem-test,$<, $(RUN_MPI), SuperLU_DIST example,--superlu)
+test-par-YES: ex11p-test-superlu
+endif
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
diff --git a/examples/petsc/CMakeLists.txt b/examples/petsc/CMakeLists.txt
index 3318a75a83..66b8f7839c 100644
--- a/examples/petsc/CMakeLists.txt
+++ b/examples/petsc/CMakeLists.txt
@@ -34,6 +34,15 @@ if (MFEM_USE_MPI)
)
endif()
+if (MFEM_USE_SLEPC)
+ list(APPEND PETSC_EXAMPLES_SRCS
+ ex11p.cpp
+ )
+ list(APPEND PETSC_RC_FILES
+ rc_ex11p_lobpcg rc_ex11p_gd
+ )
+endif()
+
# Include the source directory where mfem.hpp and mfem-performance.hpp are.
include_directories(BEFORE ${PROJECT_BINARY_DIR})
@@ -78,12 +87,22 @@ set(EX9_E_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts
set(EX9_ES_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step)
set(EX9_IS_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5)
set(EX10_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3)
+if (MFEM_USE_SLEPC)
+ set(EX11_ARGS_SINV -m ../../data/star.mesh --useslepc)
+ set(EX11_ARGS_LOBPCG -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg)
+ set(EX11_ARGS_GD -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_gd)
+endif()
# Add the tests: one test per command-line-variable.
-foreach(TEST_OPTIONS_VAR
- EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
- EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
- EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
+set(TEST_OPTIONS_VARS
+ EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
+ EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
+ EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
+if (MFEM_USE_SLEPC)
+ list(APPEND TEST_OPTIONS_VARS EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
+endif()
+
+foreach(TEST_OPTIONS_VAR ${TEST_OPTIONS_VARS})
string(REGEX REPLACE "^(.+)_ARGS" "\\1" TEST_NAME_UC ${TEST_OPTIONS_VAR})
string(REGEX REPLACE "^([^_]+)" "\\1P" TEST_NAME_UC ${TEST_NAME_UC})
string(TOLOWER ${TEST_NAME_UC} TEST_NAME_FULL)
diff --git a/examples/petsc/ex11p.cpp b/examples/petsc/ex11p.cpp
new file mode 100644
index 0000000000..b5ed4a1acc
--- /dev/null
+++ b/examples/petsc/ex11p.cpp
@@ -0,0 +1,440 @@
+// MFEM Example 11 - Parallel Version
+// PETSc Modification
+//
+// Compile with: make ex11p
+//
+// Sample runs: mpirun -np 4 ex11p -m ../../data/star.mesh
+// mpirun -np 4 ex11p -m ../../data/star.mesh --slepcopts rc_ex11p_lobpcg
+// mpirun -np 4 ex11p -m ../../data/star.mesh --slepcopts rc_ex11p_gd
+//
+// Description: This example code demonstrates the use of MFEM to solve the
+// eigenvalue problem -Delta u = lambda u with homogeneous
+// Dirichlet boundary conditions.
+//
+// We compute a number of the lowest eigenmodes by discretizing
+// the Laplacian and Mass operators using a FE space of the
+// specified order, or an isoparametric/isogeometric space if
+// order < 1 (quadratic for quadratic curvilinear mesh, NURBS for
+// NURBS mesh, etc.)
+//
+// The example demonstrates the use of the SLEPc eigensolver as an
+// alternative to the LOBPCG eigenvalue solver. The shift and
+// invert spectral transformation is used to help the convergence
+// to the smaller eigenvalues. Alternative solver parameters can
+// be passed in a file with "-slepcopts".
+//
+// Reusing a single GLVis visualization window for multiple
+// eigenfunctions is also illustrated.
+//
+// We recommend viewing Example 1 before viewing this example.
+
+#include "mfem.hpp"
+#include
+#include
+
+#ifndef MFEM_USE_SLEPC
+#error This examples requires that MFEM is build with MFEM_USE_SLEPC=YES
+#endif
+
+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";
+ int ser_ref_levels = 2;
+ int par_ref_levels = 1;
+ int order = 1;
+ int nev = 5;
+ int seed = 75;
+ bool slu_solver = false;
+ bool sp_solver = false;
+ bool visualization = 1;
+ bool use_slepc = true;
+ const char *slepcrc_file = "";
+
+ OptionsParser args(argc, argv);
+ args.AddOption(&mesh_file, "-m", "--mesh",
+ "Mesh file to use.");
+ 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",
+ "Finite element order (polynomial degree) or -1 for"
+ " isoparametric space.");
+ args.AddOption(&nev, "-n", "--num-eigs",
+ "Number of desired eigenmodes.");
+ args.AddOption(&seed, "-s", "--seed",
+ "Random seed used to initialize LOBPCG.");
+#ifdef MFEM_USE_SUPERLU
+ args.AddOption(&slu_solver, "-slu", "--superlu", "-no-slu",
+ "--no-superlu", "Use the SuperLU Solver.");
+#endif
+#ifdef MFEM_USE_STRUMPACK
+ args.AddOption(&sp_solver, "-sp", "--strumpack", "-no-sp",
+ "--no-strumpack", "Use the STRUMPACK Solver.");
+#endif
+ args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
+ "--no-visualization",
+ "Enable or disable GLVis visualization.");
+ args.AddOption(&use_slepc, "-useslepc","--useslepc","-no-slepc",
+ "--no-slepc","Use or not SLEPc to solve the eigenvalue problem");
+ args.AddOption(&slepcrc_file, "-slepcopts", "--slepcopts",
+ "SlepcOptions file to use.");
+ args.Parse();
+ if (slu_solver && sp_solver)
+ {
+ if (myid == 0)
+ cout << "WARNING: Both SuperLU and STRUMPACK have been selected,"
+ << " please choose either one." << endl
+ << " Defaulting to SuperLU." << endl;
+ sp_solver = false;
+ }
+ // The command line options are also passed to the STRUMPACK
+ // solver. So do not exit if some options are not recognized.
+ if (!sp_solver)
+ {
+ if (!args.Good())
+ {
+ if (myid == 0)
+ {
+ args.PrintUsage(cout);
+ }
+ MPI_Finalize();
+ return 1;
+ }
+ }
+ if (myid == 0)
+ {
+ args.PrintOptions(cout);
+ }
+
+ // 2b. We initialize SLEPc. This internally initializes PETSc as well.
+ MFEMInitializeSlepc(NULL,NULL,slepcrc_file,NULL);
+
+ // 3. 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();
+
+ // 4. Refine the serial mesh on all processors to increase the resolution. In
+ // this example we do 'ref_levels' of uniform refinement (2 by default, or
+ // specified on the command line with -rs).
+ for (int lev = 0; lev < ser_ref_levels; lev++)
+ {
+ mesh->UniformRefinement();
+ }
+
+ // 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
+ // this mesh further in parallel to increase the resolution (1 time by
+ // default, or specified on the command line with -rp). 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();
+ }
+
+ // 6. 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();
+ }
+ else
+ {
+ fec = new H1_FECollection(order = 1, dim);
+ }
+ ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
+ HYPRE_Int size = fespace->GlobalTrueVSize();
+ if (myid == 0)
+ {
+ cout << "Number of unknowns: " << size << endl;
+ }
+
+ // 7. Set up the parallel bilinear forms a(.,.) and m(.,.) on the finite
+ // element space. The first corresponds to the Laplacian operator -Delta,
+ // while the second is a simple mass matrix needed on the right hand side
+ // of the generalized eigenvalue problem below. The boundary conditions
+ // are implemented by elimination with special values on the diagonal to
+ // shift the Dirichlet eigenvalues out of the computational range. After
+ // serial and parallel assembly we extract the corresponding parallel
+ // matrices A and M.
+ ConstantCoefficient one(1.0);
+ Array ess_bdr;
+ if (pmesh->bdr_attributes.Size())
+ {
+ ess_bdr.SetSize(pmesh->bdr_attributes.Max());
+ ess_bdr = 1;
+ }
+
+ ParBilinearForm *a = new ParBilinearForm(fespace);
+ a->AddDomainIntegrator(new DiffusionIntegrator(one));
+ if (pmesh->bdr_attributes.Size() == 0)
+ {
+ // Add a mass term if the mesh has no boundary, e.g. periodic mesh or
+ // closed surface.
+ a->AddDomainIntegrator(new MassIntegrator(one));
+ }
+ a->Assemble();
+ a->EliminateEssentialBCDiag(ess_bdr, 1.0);
+ a->Finalize();
+
+ ParBilinearForm *m = new ParBilinearForm(fespace);
+ m->AddDomainIntegrator(new MassIntegrator(one));
+ m->Assemble();
+ // shift the eigenvalue corresponding to eliminated dofs to a large value
+ m->EliminateEssentialBCDiag(ess_bdr, numeric_limits::min());
+ m->Finalize();
+
+ PetscParMatrix *pA = NULL, *pM = NULL;
+ HypreParMatrix *A = NULL, *M = NULL;
+ Operator::Type tid =
+ !use_slepc ? Operator::Hypre_ParCSR : Operator::PETSC_MATAIJ;
+ OperatorHandle Ah(tid), Mh(tid);
+
+ a->ParallelAssemble(Ah);
+ if (!use_slepc) { Ah.Get(A); }
+ else { Ah.Get(pA); }
+ Ah.SetOperatorOwner(false);
+
+ m->ParallelAssemble(Mh);
+ if (!use_slepc) {Mh.Get(M); }
+ else {Mh.Get(pM); }
+ Mh.SetOperatorOwner(false);
+
+#if defined(MFEM_USE_SUPERLU) || defined(MFEM_USE_STRUMPACK)
+ Operator * Arow = NULL;
+#ifdef MFEM_USE_SUPERLU
+ if (slu_solver)
+ {
+ Arow = new SuperLURowLocMatrix(*A);
+ }
+#endif
+#ifdef MFEM_USE_STRUMPACK
+ if (sp_solver)
+ {
+ Arow = new STRUMPACKRowLocMatrix(*A);
+ }
+#endif
+#endif
+
+ delete a;
+ delete m;
+
+ // 8. Define and configure the LOBPCG eigensolver and the BoomerAMG
+ // preconditioner for A to be used within the solver. Set the matrices
+ // which define the generalized eigenproblem A x = lambda M x.
+ Solver * precond = NULL;
+ if (!use_slepc)
+ {
+ if (!slu_solver && !sp_solver)
+ {
+ HypreBoomerAMG * amg = new HypreBoomerAMG(*A);
+ amg->SetPrintLevel(0);
+ precond = amg;
+ }
+ else
+ {
+#ifdef MFEM_USE_SUPERLU
+ if (slu_solver)
+ {
+ SuperLUSolver * superlu = new SuperLUSolver(MPI_COMM_WORLD);
+ superlu->SetPrintStatistics(false);
+ superlu->SetSymmetricPattern(true);
+ superlu->SetColumnPermutation(superlu::PARMETIS);
+ superlu->SetOperator(*Arow);
+ precond = superlu;
+ }
+#endif
+#ifdef MFEM_USE_STRUMPACK
+ if (sp_solver)
+ {
+ STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv, MPI_COMM_WORLD);
+ strumpack->SetPrintFactorStatistics(true);
+ strumpack->SetPrintSolveStatistics(false);
+ strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
+ strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
+ strumpack->DisableMatching();
+ strumpack->SetOperator(*Arow);
+ strumpack->SetFromCommandLine();
+ precond = strumpack;
+ }
+#endif
+ }
+ }
+
+ HypreLOBPCG * lobpcg = NULL;
+ SlepcEigenSolver * slepc = NULL;
+ if (!use_slepc)
+ {
+
+ lobpcg = new HypreLOBPCG(MPI_COMM_WORLD);
+ lobpcg->SetNumModes(nev);
+ lobpcg->SetRandomSeed(seed);
+ lobpcg->SetPreconditioner(*precond);
+ lobpcg->SetMaxIter(200);
+ lobpcg->SetTol(1e-8);
+ lobpcg->SetPrecondUsageMode(1);
+ lobpcg->SetPrintLevel(1);
+ lobpcg->SetMassMatrix(*M);
+ lobpcg->SetOperator(*A);
+ }
+ else
+ {
+ slepc = new SlepcEigenSolver(MPI_COMM_WORLD);
+ slepc->SetNumModes(nev);
+ slepc->SetWhichEigenpairs(SlepcEigenSolver::TARGET_REAL);
+ slepc->SetTarget(0.0);
+ slepc->SetSpectralTransformation(SlepcEigenSolver::SHIFT_INVERT);
+ slepc->SetOperators(*pA,*pM);
+ }
+
+ // 9. Compute the eigenmodes and extract the array of eigenvalues. Define a
+ // parallel grid function to represent each of the eigenmodes returned by
+ // the solver.
+ Array eigenvalues;
+ if (!use_slepc)
+ {
+ lobpcg->Solve();
+ lobpcg->GetEigenvalues(eigenvalues);
+ }
+ else
+ {
+ slepc->Solve();
+ eigenvalues.SetSize(nev);
+ for (int i=0; iGetEigenvalue(i,eigenvalues[i]);
+ }
+ }
+ Vector temp(fespace->GetTrueVSize());
+ ParGridFunction x(fespace);
+
+ // 10. Save the refined mesh and the modes in parallel. This output can be
+ // viewed later using GLVis: "glvis -np -m mesh -g mode".
+ {
+ ostringstream mesh_name, mode_name;
+ mesh_name << "mesh." << setfill('0') << setw(6) << myid;
+
+ ofstream mesh_ofs(mesh_name.str().c_str());
+ mesh_ofs.precision(8);
+ pmesh->Print(mesh_ofs);
+
+ for (int i=0; iGetEigenvector(i);
+ }
+ else
+ {
+ slepc->GetEigenvector(i,temp);
+ x.Distribute(temp);
+
+ }
+
+ mode_name << "mode_" << setfill('0') << setw(2) << i << "."
+ << setfill('0') << setw(6) << myid;
+
+ ofstream mode_ofs(mode_name.str().c_str());
+ mode_ofs.precision(8);
+ x.Save(mode_ofs);
+ mode_name.str("");
+ }
+ }
+
+ // 11. Send the solution by socket to a GLVis server.
+ if (visualization)
+ {
+ char vishost[] = "localhost";
+ int visport = 19916;
+ socketstream mode_sock(vishost, visport);
+ mode_sock.precision(8);
+
+ for (int i=0; i " << flush;
+ cin >> c;
+ }
+ MPI_Bcast(&c, 1, MPI_CHAR, 0, MPI_COMM_WORLD);
+
+ if (c != 'c')
+ {
+ break;
+ }
+ }
+ mode_sock.close();
+ }
+
+ // 12. Free the used memory.
+ if (!use_slepc)
+ {
+ delete lobpcg;
+ }
+ else
+ {
+ delete slepc;
+ }
+ delete precond;
+ delete M;
+ delete A;
+#if defined(MFEM_USE_SUPERLU) || defined(MFEM_USE_STRUMPACK)
+ delete Arow;
+#endif
+
+ delete fespace;
+ if (order > 0)
+ {
+ delete fec;
+ }
+ delete pmesh;
+
+ // We finalize SLEPc
+ MFEMFinalizeSlepc();
+ MPI_Finalize();
+
+ return 0;
+}
diff --git a/examples/petsc/makefile b/examples/petsc/makefile
index 55f1f89b8a..93a68188d9 100644
--- a/examples/petsc/makefile
+++ b/examples/petsc/makefile
@@ -23,6 +23,9 @@ MFEM_LIB_FILE = mfem_is_not_built
SEQ_EXAMPLES =
PAR_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex9p ex10p
+ifeq ($(MFEM_USE_SLEPC),YES)
+ PAR_EXAMPLES += ex11p
+endif
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
else
@@ -87,6 +90,9 @@ EX10_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p
EX10_MF_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mf -tf 6 -s 3 -rs 0 -dt 3
EX10_MFOP_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mfop -tf 6 -s 3 -rs 0 -dt 3
EX10_JFNK_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_jfnk --jfnk -tf 6 -s 3 -rs 0 -dt 3
+EX11_ARGS_SINV := -m ../../data/star.mesh --useslepc
+EX11_ARGS_LOBPCG := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg
+EX11_ARGS_GD := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_gd
ex1p-test-par: ex1p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_W))
@@ -114,6 +120,12 @@ ex10p-test-par: ex10p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_MF_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_MFOP_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_JFNK_ARGS))
+ifeq ($(MFEM_USE_SLEPC),YES)
+ex11p-test-par: ex11p
+ @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_SINV))
+ @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_LOBPCG))
+ @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_GD))
+endif
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
diff --git a/examples/petsc/rc_ex11p_gd b/examples/petsc/rc_ex11p_gd
new file mode 100644
index 0000000000..21a111b935
--- /dev/null
+++ b/examples/petsc/rc_ex11p_gd
@@ -0,0 +1,6 @@
+# Options for the eigenvalue solver
+-eps_view
+-eps_converged_reason
+-eps_type gd
+# Options for the spectral transform
+-st_type precond
diff --git a/examples/petsc/rc_ex11p_lobpcg b/examples/petsc/rc_ex11p_lobpcg
new file mode 100644
index 0000000000..57440caab0
--- /dev/null
+++ b/examples/petsc/rc_ex11p_lobpcg
@@ -0,0 +1,11 @@
+# Options for the eigenvalue solver
+-eps_monitor
+-eps_converged_reason
+-eps_view_values
+-eps_type lobpcg
+-eps_gen_hermitian
+-eps_smallest_real
+-eps_lobpcg_blocksize 5
+# Options for the spectral transform
+-st_type precond
+-st_pc_type gamg
diff --git a/examples/pumi/ex1.cpp b/examples/pumi/ex1.cpp
index 95def29a73..c72d5ab5ba 100644
--- a/examples/pumi/ex1.cpp
+++ b/examples/pumi/ex1.cpp
@@ -32,6 +32,13 @@
// 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
diff --git a/examples/pumi/ex1p.cpp b/examples/pumi/ex1p.cpp
index c17a9aee8d..acf6b9832f 100644
--- a/examples/pumi/ex1p.cpp
+++ b/examples/pumi/ex1p.cpp
@@ -36,6 +36,14 @@
// 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
diff --git a/examples/pumi/ex2.cpp b/examples/pumi/ex2.cpp
index f7b54c195d..e294b0e4b9 100644
--- a/examples/pumi/ex2.cpp
+++ b/examples/pumi/ex2.cpp
@@ -43,6 +43,14 @@
// 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
diff --git a/examples/pumi/ex6p.cpp b/examples/pumi/ex6p.cpp
index fc9fb5386e..70b6cd9554 100644
--- a/examples/pumi/ex6p.cpp
+++ b/examples/pumi/ex6p.cpp
@@ -1,7 +1,7 @@
// MFEM Example 6 - Parallel Version
// PUMI Modification
//
-// Compile with: make ex1p
+// Compile with: make ex6p
//
// Sample runs: mpirun -np 8 ex6p
//
@@ -18,6 +18,13 @@
// 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
@@ -332,7 +339,6 @@ 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);
diff --git a/fem/adios2datacollection.cpp b/fem/adios2datacollection.cpp
index 8c2c8e6425..51703c01cc 100644
--- a/fem/adios2datacollection.cpp
+++ b/fem/adios2datacollection.cpp
@@ -15,6 +15,8 @@
#include "adios2datacollection.hpp"
+#ifdef MFEM_USE_ADIOS2
+
namespace mfem
{
@@ -87,4 +89,4 @@ noexcept
} //end namespace mfem
-
+#endif // MFEM_USE_ADIOS2
diff --git a/fem/adios2datacollection.hpp b/fem/adios2datacollection.hpp
index c611f73675..dd05b4c478 100644
--- a/fem/adios2datacollection.hpp
+++ b/fem/adios2datacollection.hpp
@@ -17,6 +17,9 @@
#define MFEM_ADIOS2DATACOLLECTION
#include "../config/config.hpp"
+
+#ifdef MFEM_USE_ADIOS2
+
#include "../general/adios2stream.hpp"
#include "datacollection.hpp"
@@ -85,4 +88,6 @@ private:
} // namespace mfem
+#endif // MFEM_USE_ADIOS2
+
#endif /* MFEM_ADIOS2DATACOLLECTION */
diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp
index 548f221bff..179ff64f59 100644
--- a/fem/bilinearform.hpp
+++ b/fem/bilinearform.hpp
@@ -25,8 +25,8 @@
namespace mfem
{
-/// Enumeration defining the assembly level for bilinear and nonlinear form
-/// classes derived from Operator.
+/** @brief Enumeration defining the assembly level for bilinear and nonlinear
+ form classes derived from Operator. */
enum class AssemblyLevel
{
/// Fully assembled form, i.e. a global sparse matrix in MFEM, Hypre or PETSC
@@ -44,15 +44,19 @@ enum class AssemblyLevel
};
-/** Class for bilinear form - "Matrix" with associated FE space and
- BLFIntegrators. */
+/** @brief A "square matrix" operator for the associated FE space and
+ BLFIntegrators The sum of all the BLFIntegrators can be used form the matrix
+ M. This class also supports other assembly levels specified via the
+ SetAssemblyLevel() function. */
class BilinearForm : public Matrix
{
protected:
- /// Sparse matrix to be associated with the form. Owned.
+ /// Sparse matrix \f$ M \f$ to be associated with the form. Owned.
SparseMatrix *mat;
- /// Matrix used to eliminate b.c. Owned.
+ /** @brief Sparse Matrix \f$ M_e \f$ used to store the eliminations
+ from the b.c. Owned.
+ \f$ M + M_e = M_{original} \f$ */
SparseMatrix *mat_e;
/// FE space on which the form lives. Not owned.
@@ -62,12 +66,12 @@ protected:
AssemblyLevel assembly;
/// Element batch size used in the form action (1, 8, num_elems, etc.)
int batch;
- /** Extension for supporting Full Assembly (FA), Element Assembly (EA),
+ /** @brief Extension for supporting Full Assembly (FA), Element Assembly (EA),
Partial Assembly (PA), or Matrix Free assembly (MF). */
BilinearFormExtension *ext;
- /// Indicates the Mesh::sequence corresponding to the current state of the
- /// BilinearForm.
+ /** @brief Indicates the Mesh::sequence corresponding to the current state of
+ the BilinearForm. */
long sequence;
/** @brief Indicates the BilinearFormIntegrator%s stored in #dbfi, #bbfi,
@@ -147,35 +151,43 @@ public:
/// Get the size of the BilinearForm as a square matrix.
int Size() const { return height; }
- /// Set the desired assembly level. The default is AssemblyLevel::FULL.
- /** This method must be called before assembly. */
+ /// Set the desired assembly level.
+ /** Valid choices are:
+
+ - AssemblyLevel::FULL (default)
+ - AssemblyLevel::PARTIAL
+ - AssemblyLevel::ELEMENT
+ - AssemblyLevel::NONE
+
+ This method must be called before assembly. */
void SetAssemblyLevel(AssemblyLevel assembly_level);
/// Returns the assembly level
AssemblyLevel GetAssemblyLevel() const { return assembly; }
- /** Enable the use of static condensation. For details see the description
- for class StaticCondensation in fem/staticcond.hpp This method should be
- called before assembly. If the number of unknowns after static
+ /** @brief Enable the use of static condensation. For details see the
+ description for class StaticCondensation in fem/staticcond.hpp This method
+ should be called before assembly. If the number of unknowns after static
condensation is not reduced, it is not enabled. */
void EnableStaticCondensation();
- /** Check if static condensation was actually enabled by a previous call to
- EnableStaticCondensation(). */
+ /** @brief Check if static condensation was actually enabled by a previous
+ call to EnableStaticCondensation(). */
bool StaticCondensationIsEnabled() const { return static_cond; }
/// Return the trace FE space associated with static condensation.
FiniteElementSpace *SCFESpace() const
{ return static_cond ? static_cond->GetTraceFESpace() : NULL; }
- /** Enable hybridization; for details see the description for class
+ /// Enable hybridization.
+ /** For details see the description for class
Hybridization in fem/hybridization.hpp. This method should be called
before assembly. */
void EnableHybridization(FiniteElementSpace *constr_space,
BilinearFormIntegrator *constr_integ,
const Array &ess_tdof_list);
- /** For scalar FE spaces, precompute the sparsity pattern of the matrix
+ /** @brief For scalar FE spaces, precompute the sparsity pattern of the matrix
(assuming dense element matrices) based on the types of integrators
present in the bilinear form. */
void UsePrecomputedSparsity(int ps = 1) { precompute_sparsity = ps; }
@@ -194,15 +206,16 @@ public:
/// Use the sparsity of @a A to allocate the internal SparseMatrix.
void UseSparsity(SparseMatrix &A);
- /** Pre-allocate the internal SparseMatrix before assembly. If the flag
- 'precompute sparsity' is set, the matrix is allocated in CSR format (i.e.
+ /// Pre-allocate the internal SparseMatrix before assembly.
+ /** If the flag 'precompute sparsity'
+ is set, the matrix is allocated in CSR format (i.e.
finalized) and the entries are initialized with zeros. */
void AllocateMatrix() { if (mat == NULL) { AllocMat(); } }
- /// Access all integrators added with AddDomainIntegrator().
+ /// Access all the integrators added with AddDomainIntegrator().
Array *GetDBFI() { return &dbfi; }
- /// Access all integrators added with AddBoundaryIntegrator().
+ /// Access all the integrators added with AddBoundaryIntegrator().
Array *GetBBFI() { return &bbfi; }
/** @brief Access all boundary markers added with AddBoundaryIntegrator().
If no marker was specified when the integrator was added, the
@@ -219,64 +232,85 @@ public:
corresponding pointer (to Array) will be NULL. */
Array*> *GetBFBFI_Marker() { return &bfbfi_marker; }
+ /// Returns a reference to: \f$ M_{ij} \f$
const double &operator()(int i, int j) { return (*mat)(i,j); }
- /// Returns reference to a_{ij}.
+ /// Returns a reference to: \f$ M_{ij} \f$
virtual double &Elem(int i, int j);
- /// Returns constant reference to a_{ij}.
+ /// Returns constant reference to: \f$ M_{ij} \f$
virtual const double &Elem(int i, int j) const;
- /// Matrix vector multiplication.
+ /// Matrix vector multiplication: \f$ y = M x \f$
virtual void Mult(const Vector &x, Vector &y) const;
+ /** @brief Matrix vector multiplication with the original uneliminated
+ matrix. The original matrix is \f$ M + M_e \f$ so we have:
+ \f$ y = M x + M_e x \f$ */
void FullMult(const Vector &x, Vector &y) const
{ mat->Mult(x, y); mat_e->AddMult(x, y); }
+ /// Add the matrix vector multiple to a vector: \f$ y += a M x \f$
virtual void AddMult(const Vector &x, Vector &y, const double a = 1.0) const
{ mat -> AddMult (x, y, a); }
+ /** @brief Add the original uneliminated matrix vector multiple to a vector.
+ The original matrix is \f$ M + Me \f$ so we have:
+ \f$ y += M x + M_e x \f$ */
void FullAddMult(const Vector &x, Vector &y) const
{ mat->AddMult(x, y); mat_e->AddMult(x, y); }
+ /// Add the matrix transpose vector multiplication: \f$ y += a M^T x \f$
virtual void AddMultTranspose(const Vector & x, Vector & y,
const double a = 1.0) const
{ mat->AddMultTranspose(x, y, a); }
+ /** @brief Add the original uneliminated matrix transpose vector
+ multiple to a vector. The original matrix is \f$ M + M_e \f$
+ so we have: \f$ y += M^T x + {M_e}^T x \f$ */
void FullAddMultTranspose(const Vector & x, Vector & y) const
{ mat->AddMultTranspose(x, y); mat_e->AddMultTranspose(x, y); }
+ /// Matrix transpose vector multiplication: \f$ y = M^T x \f$
virtual void MultTranspose(const Vector & x, Vector & y) const
{ y = 0.0; AddMultTranspose (x, y); }
+ /// Compute \f$ y^T M x \f$
double InnerProduct(const Vector &x, const Vector &y) const
{ return mat->InnerProduct (x, y); }
- /// Returns a pointer to (approximation) of the matrix inverse.
+ /// Returns a pointer to (approximation) of the matrix inverse: \f$ M^{-1} \f$
virtual MatrixInverse *Inverse() const;
/// Finalizes the matrix initialization.
virtual void Finalize(int skip_zeros = 1);
- /// Returns a reference to the sparse matrix
+ /// Returns a const reference to the sparse matrix.
const SparseMatrix &SpMat() const
{
MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced");
return *mat;
}
+
+ /// Returns a reference to the sparse matrix: \f$ M \f$
SparseMatrix &SpMat()
{
MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced");
return *mat;
}
+
+ /** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer
+ to it. Used for transfering ownership. */
SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; }
- /// Returns a reference to the sparse matrix of eliminated b.c.
+ /// Returns a const reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$
const SparseMatrix &SpMatElim() const
{
MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced");
return *mat_e;
}
+
+ /// Returns a reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$
SparseMatrix &SpMatElim()
{
MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced");
@@ -311,6 +345,7 @@ public:
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi,
Array &bdr_marker);
+ /// Sets all sparse values of \f$ M \f$ and \f$ M_e \f$ to 'a'.
void operator=(const double a)
{
if (mat != NULL) { *mat = a; }
@@ -328,10 +363,10 @@ public:
for an AMR mesh. */
void AssembleDiagonal(Vector &diag) const;
- /// Get the finite element space prolongation matrix
+ /// Get the finite element space prolongation operator.
virtual const Operator *GetProlongation() const
{ return fes->GetConformingProlongation(); }
- /// Get the finite element space restriction matrix
+ /// Get the finite element space restriction operator
virtual const Operator *GetRestriction() const
{ return fes->GetConformingRestriction(); }
/// Get the output finite element space prolongation matrix
@@ -491,10 +526,12 @@ public:
double value);
/// Eliminate the given @a vdofs. NOTE: here, @a vdofs is a list of DOFs.
+ /** In this case the eliminations are applied to the internal \f$ M \f$
+ and @a rhs without storing the elimination matrix \f$ M_e \f$. */
void EliminateVDofs(const Array &vdofs, const Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy = DIAG_ONE);
- /// Eliminate the given @a vdofs, storing the eliminated part internally.
+ /// Eliminate the given @a vdofs, storing the eliminated part internally in \f$ M_e \f$.
/** This method works in conjunction with EliminateVDofsInRHS() and allows
elimination of boundary conditions in multiple right-hand sides. In this
method, @a vdofs is a list of DOFs. */
@@ -523,9 +560,11 @@ public:
void EliminateVDofsInRHS(const Array &vdofs, const Vector &x,
Vector &b);
+ /// Compute inner product for full uneliminated matrix \f$ y^T M x + y^T M_e x \f$
double FullInnerProduct(const Vector &x, const Vector &y) const
{ return mat->InnerProduct(x, y) + mat_e->InnerProduct(x, y); }
+ /// Update the @a FiniteElementSpace and delete all data associated with the old one.
virtual void Update(FiniteElementSpace *nfes = NULL);
/// (DEPRECATED) Return the FE space associated with the BilinearForm.
@@ -537,7 +576,13 @@ public:
/// Read-only access to the associated FiniteElementSpace.
const FiniteElementSpace *FESpace() const { return fes; }
- /// Sets diagonal policy used upon construction of the linear system
+ /// Sets diagonal policy used upon construction of the linear system.
+ /** Policies include:
+
+ - DIAG_ZERO (Set the diagonal values to zero)
+ - DIAG_ONE (Set the diagonal values to one)
+ - DIAG_KEEP (Keep the diagonal values)
+ */
void SetDiagonalPolicy(DiagonalPolicy policy);
/// Indicate that integrators are not owned by the BilinearForm
@@ -550,16 +595,16 @@ public:
/**
Class for assembling of bilinear forms `a(u,v)` defined on different
- trial and test spaces. The assembled matrix `A` is such that
+ trial and test spaces. The assembled matrix `M` is such that
- a(u,v) = V^t A U
+ a(u,v) = V^t M U
where `U` and `V` are the vectors representing the functions `u` and `v`,
respectively. The first argument, `u`, of `a(,)` is in the trial space
and the second argument, `v`, is in the test space. Thus,
- # of rows of A = dimension of the test space and
- # of cols of A = dimension of the trial space.
+ # of rows of M = dimension of the test space and
+ # of cols of M = dimension of the trial space.
Both trial and test spaces should be defined on the same mesh.
*/
@@ -628,11 +673,15 @@ public:
FiniteElementSpace *te_fes,
MixedBilinearForm *mbf);
+ /// Returns a reference to: \f$ M_{ij} \f$
virtual double &Elem(int i, int j);
+ /// Returns a reference to: \f$ M_{ij} \f$
virtual const double &Elem(int i, int j) const;
+ /// Matrix multiplication: \f$ y = M x \f$
virtual void Mult(const Vector & x, Vector & y) const;
+
virtual void AddMult(const Vector & x, Vector & y,
const double a = 1.0) const;
@@ -642,6 +691,7 @@ public:
virtual MatrixInverse *Inverse() const;
+ /// Finalizes the matrix initialization.
virtual void Finalize(int skip_zeros = 1);
/** Extract the associated matrix as SparseMatrix blocks. The number of
@@ -649,8 +699,14 @@ public:
test and trial spaces, respectively. */
void GetBlocks(Array2D &blocks) const;
+ /// Returns a const reference to the sparse matrix: \f$ M \f$
const SparseMatrix &SpMat() const { return *mat; }
+
+ /// Returns a reference to the sparse matrix: \f$ M \f$
SparseMatrix &SpMat() { return *mat; }
+
+ /** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer
+ to it. Used for transfering ownership. */
SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; }
/// Adds a domain integrator. Assumes ownership of @a bfi.
@@ -697,6 +753,7 @@ public:
corresponding pointer (to Array) will be NULL. */
Array*> *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.
diff --git a/fem/bilinearform_ext.hpp b/fem/bilinearform_ext.hpp
index d96aedfe0c..57fbc02787 100644
--- a/fem/bilinearform_ext.hpp
+++ b/fem/bilinearform_ext.hpp
@@ -22,9 +22,12 @@ namespace mfem
class BilinearForm;
class MixedBilinearForm;
-
-/** @brief Class extending the BilinearForm class to support the different
- AssemblyLevel%s. */
+/// Class extending the BilinearForm class to support different AssemblyLevels.
+/** FA - Full Assembly
+ PA - Partial Assembly
+ EA - Element Assembly
+ MF - Matrix Free
+*/
class BilinearFormExtension : public Operator
{
protected:
@@ -42,6 +45,7 @@ public:
/// Get the finite element space restriction matrix
virtual const Operator *GetRestriction() const;
+ /// Assemble at the level given for the BilinearFormExtension subclass
virtual void Assemble() = 0;
virtual void AssembleDiagonal(Vector &diag) const
@@ -58,7 +62,8 @@ public:
virtual void Update() = 0;
};
-/// Data and methods for fully-assembled bilinear forms
+/** @brief Data and methods for fully-assembled bilinear forms.
+ Not yet implemented! Use the BilinearForm Class instead. */
class FABilinearFormExtension : public BilinearFormExtension
{
public:
@@ -127,7 +132,7 @@ public:
void MultTranspose(const Vector &x, Vector &y) const;
};
-/// Data and methods for matrix-free bilinear forms
+/// Data and methods for matrix-free bilinear forms NOT YET IMPLEMENTED.
class MFBilinearFormExtension : public BilinearFormExtension
{
public:
@@ -147,8 +152,12 @@ public:
~MFBilinearFormExtension() {}
};
-/** @brief Class extending the MixedBilinearForm class to support the different
- AssemblyLevel%s. */
+/// Class extending the MixedBilinearForm class to support different AssemblyLevels.
+/** FA - Full Assembly
+ PA - Partial Assembly
+ EA - Element Assembly
+ MF - Matrix Free
+*/
class MixedBilinearFormExtension : public Operator
{
protected:
diff --git a/fem/bilininteg.cpp b/fem/bilininteg.cpp
index f5be75729f..c2f2f887ad 100644
--- a/fem/bilininteg.cpp
+++ b/fem/bilininteg.cpp
@@ -919,22 +919,25 @@ void BoundaryMassIntegrator::AssembleFaceMatrix(
{
int order = 2 * el1.GetOrder();
- ir = &IntRules.Get(Trans.FaceGeom, order);
+ ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
- IntegrationPoint eip;
- Trans.Loc1.Transform(ip, eip);
+
+ // Set the integration point in the face and the neighboring element
+ Trans.SetAllIntPoints(&ip);
+
+ // Access the neighboring element's integration point
+ const IntegrationPoint &eip = Trans.GetElement1IntPoint();
el1.CalcShape(eip, shape);
- Trans.Face->SetIntPoint(&ip);
- w = Trans.Face->Weight() * ip.weight;
+ w = Trans.Weight() * ip.weight;
if (Q)
{
- w *= Q -> Eval(*Trans.Face, ip);
+ w *= Q -> Eval(Trans, ip);
}
AddMult_a_VVt(w, shape, elmat);
@@ -2565,22 +2568,22 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
{
order++;
}
- ir = &IntRules.Get(Trans.FaceGeom, order);
+ ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
{
const IntegrationPoint &ip = ir->IntPoint(p);
- IntegrationPoint eip1, eip2;
- Trans.Loc1.Transform(ip, eip1);
- if (ndof2)
- {
- Trans.Loc2.Transform(ip, eip2);
- }
- el1.CalcShape(eip1, shape1);
- Trans.Face->SetIntPoint(&ip);
- Trans.Elem1->SetIntPoint(&eip1);
+ // Set the integration point in the face and the neighboring elements
+ Trans.SetAllIntPoints(&ip);
+
+ // Access the neighboring elements' integration points
+ // Note: eip2 will only contain valid data if Elem2 exists
+ const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
+ const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
+
+ el1.CalcShape(eip1, shape1);
u->Eval(vu, *Trans.Elem1, eip1);
@@ -2590,7 +2593,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
}
else
{
- CalcOrtho(Trans.Face->Jacobian(), nor);
+ CalcOrtho(Trans.Jacobian(), nor);
}
un = vu * nor;
@@ -2605,7 +2608,6 @@ 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
@@ -2721,7 +2723,7 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
{
order = 2*el1.GetOrder();
}
- ir = &IntRules.Get(Trans.FaceGeom, order);
+ ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
// assemble: < {(Q \nabla u).n},[v] > --> elmat
@@ -2729,22 +2731,26 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
for (int p = 0; p < ir->GetNPoints(); p++)
{
const IntegrationPoint &ip = ir->IntPoint(p);
- IntegrationPoint eip1, eip2;
- Trans.Loc1.Transform(ip, eip1);
- Trans.Face->SetIntPoint(&ip);
+ // Set the integration point in the face and the neighboring elements
+ Trans.SetAllIntPoints(&ip);
+
+ // Access the neighboring elements' integration points
+ // Note: eip2 will only contain valid data if Elem2 exists
+ const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
+ const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
+
if (dim == 1)
{
nor(0) = 2*eip1.x - 1.0;
}
else
{
- CalcOrtho(Trans.Face->Jacobian(), nor);
+ CalcOrtho(Trans.Jacobian(), nor);
}
el1.CalcShape(eip1, shape1);
el1.CalcDShape(eip1, dshape1);
- Trans.Elem1->SetIntPoint(&eip1);
w = ip.weight/Trans.Elem1->Weight();
if (ndof2)
{
@@ -2790,10 +2796,8 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
if (ndof2)
{
- 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)
{
@@ -3003,16 +3007,20 @@ 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.FaceGeom, order);
+ ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
for (int pind = 0; pind < ir->GetNPoints(); ++pind)
{
const IntegrationPoint &ip = ir->IntPoint(pind);
- IntegrationPoint eip1, eip2; // integration point in the reference space
- Trans.Loc1.Transform(ip, eip1);
- Trans.Face->SetIntPoint(&ip);
- Trans.Elem1->SetIntPoint(&eip1);
+
+ // Set the integration point in the face and the neighboring elements
+ Trans.SetAllIntPoints(&ip);
+
+ // Access the neighboring elements' integration points
+ // Note: eip2 will only contain valid data if Elem2 exists
+ const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
+ const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
el1.CalcShape(eip1, shape1);
el1.CalcDShape(eip1, dshape1);
@@ -3026,14 +3034,12 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
}
else
{
- CalcOrtho(Trans.Face->Jacobian(), nor);
+ CalcOrtho(Trans.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);
@@ -3163,33 +3169,36 @@ void TraceJumpIntegrator::AssembleFaceMatrix(
order += trial_face_fe.GetOrder();
if (trial_face_fe.GetMapType() == FiniteElement::VALUE)
{
- order += Trans.Face->OrderW();
+ order += Trans.OrderW();
}
- ir = &IntRules.Get(Trans.FaceGeom, order);
+ ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
{
const IntegrationPoint &ip = ir->IntPoint(p);
- IntegrationPoint eip1, eip2;
+
+ // Set the integration point in the face and the neighboring elements
+ Trans.SetAllIntPoints(&ip);
+
+ // Access the neighboring elements' integration points
+ // Note: eip2 will only contain valid data if Elem2 exists
+ const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
+ const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
+
// Trace finite element shape function
- 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.Face->Weight();
+ w *= Trans.Weight();
}
face_shape *= w;
for (i = 0; i < ndof1; i++)
@@ -3254,7 +3263,7 @@ void NormalTraceJumpIntegrator::AssembleFaceMatrix(
order = test_fe1.GetOrder() - 1;
}
order += trial_face_fe.GetOrder();
- ir = &IntRules.Get(Trans.FaceGeom, order);
+ ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
diff --git a/fem/bilininteg.hpp b/fem/bilininteg.hpp
index 1c6c77e5db..7c322b4ce1 100644
--- a/fem/bilininteg.hpp
+++ b/fem/bilininteg.hpp
@@ -199,6 +199,8 @@ public:
virtual ~BilinearFormIntegrator() { }
};
+/** Wraps a given @a BilinearFormIntegrator and transposes the resulting element
+ matrices. See for example ex9, ex9p. */
class TransposeIntegrator : public BilinearFormIntegrator
{
private:
@@ -1563,7 +1565,7 @@ public:
};
/** Class for integrating the bilinear form a(u,v) := (-V u, Grad v) in 2D or 3D
- and where V is a vector coefficient, u is in H1 and v is in H1. */
+ and where V is a vector coefficient, u is in H1 or L2 and v is in H1. */
class MixedScalarWeakDivergenceIntegrator : public MixedScalarVectorIntegrator
{
public:
@@ -2001,6 +2003,7 @@ public:
void SetupPA(const FiniteElementSpace &fes, const bool force = false);
};
+/** Mass integrator (u, v) restricted to the boundary of a domain */
class BoundaryMassIntegrator : public MassIntegrator
{
public:
diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp
index 1f1d306919..1e2fd0f8be 100644
--- a/fem/coefficient.cpp
+++ b/fem/coefficient.cpp
@@ -49,7 +49,7 @@ double FunctionCoefficient::Eval(ElementTransformation & T,
double GridFunctionCoefficient::Eval (ElementTransformation &T,
const IntegrationPoint &ip)
{
- return GridF -> GetValue (T.ElementNo, ip, Component);
+ return GridF -> GetValue (T, ip, Component);
}
double TransformedCoefficient::Eval(ElementTransformation &T,
@@ -160,13 +160,13 @@ void VectorArrayCoefficient::Eval(Vector &V, ElementTransformation &T,
}
VectorGridFunctionCoefficient::VectorGridFunctionCoefficient (
- GridFunction *gf)
+ const GridFunction *gf)
: VectorCoefficient ((gf) ? gf -> VectorDim() : 0)
{
GridFunc = gf;
}
-void VectorGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
+void VectorGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
{
GridFunc = gf; vdim = (gf) ? gf -> VectorDim() : 0;
}
@@ -174,24 +174,7 @@ void VectorGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
void VectorGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
- 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);
- }
+ GridFunc->GetVectorValue(T, ip, V);
}
void VectorGridFunctionCoefficient::Eval(
@@ -201,14 +184,14 @@ void VectorGridFunctionCoefficient::Eval(
}
GradientGridFunctionCoefficient::GradientGridFunctionCoefficient (
- GridFunction *gf)
+ const GridFunction *gf)
: VectorCoefficient((gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0)
{
GridFunc = gf;
}
-void GradientGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
+void GradientGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
{
GridFunc = gf; vdim = (gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0;
@@ -226,18 +209,24 @@ void GradientGridFunctionCoefficient::Eval(
GridFunc->GetGradients(T, ir, M);
}
-CurlGridFunctionCoefficient::CurlGridFunctionCoefficient (
- GridFunction *gf)
- : VectorCoefficient ((gf) ?
- gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0)
+CurlGridFunctionCoefficient::CurlGridFunctionCoefficient(
+ const GridFunction *gf)
+ : VectorCoefficient(0)
{
- GridFunc = gf;
+ SetGridFunction(gf);
}
-void CurlGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
+void CurlGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
{
- GridFunc = gf; vdim = (gf) ?
- gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0;
+ if (gf)
+ {
+ int sdim = gf -> FESpace() -> GetMesh() -> SpaceDimension();
+ MFEM_VERIFY(sdim == 2 || sdim == 3,
+ "CurlGridFunctionCoefficient "
+ "only defind for spaces of dimension 2 or 3.");
+ }
+ GridFunc = gf;
+ vdim = (gf) ? (2 * gf -> FESpace() -> GetMesh() -> SpaceDimension() - 3) : 0;
}
void CurlGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
@@ -247,7 +236,7 @@ void CurlGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
}
DivergenceGridFunctionCoefficient::DivergenceGridFunctionCoefficient (
- GridFunction *gf) : Coefficient()
+ const GridFunction *gf) : Coefficient()
{
GridFunc = gf;
}
@@ -433,13 +422,43 @@ double DeterminantCoefficient::Eval(ElementTransformation &T,
return ma.Det();
}
-VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &A,
- VectorCoefficient &B,
- double _alpha, double _beta)
- : VectorCoefficient(A.GetVDim()), a(&A), b(&B), alpha(_alpha), beta(_beta),
- va(A.GetVDim())
+VectorSumCoefficient::VectorSumCoefficient(int dim)
+ : VectorCoefficient(dim),
+ ACoef(NULL), BCoef(NULL),
+ A(dim), B(dim),
+ alphaCoef(NULL), betaCoef(NULL),
+ alpha(1.0), beta(1.0)
{
- MFEM_ASSERT(A.GetVDim() == B.GetVDim(),
+ A = 0.0; B = 0.0;
+}
+
+VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &_A,
+ VectorCoefficient &_B,
+ double _alpha, double _beta)
+ : VectorCoefficient(_A.GetVDim()),
+ ACoef(&_A), BCoef(&_B),
+ A(_A.GetVDim()), B(_A.GetVDim()),
+ alphaCoef(NULL), betaCoef(NULL),
+ alpha(_alpha), beta(_beta)
+{
+ MFEM_ASSERT(_A.GetVDim() == _B.GetVDim(),
+ "VectorSumCoefficient: "
+ "Arguments must have the same dimension.");
+}
+
+VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &_A,
+ VectorCoefficient &_B,
+ Coefficient &_alpha,
+ Coefficient &_beta)
+ : VectorCoefficient(_A.GetVDim()),
+ ACoef(&_A), BCoef(&_B),
+ A(_A.GetVDim()),
+ B(_A.GetVDim()),
+ alphaCoef(&_alpha),
+ betaCoef(&_beta),
+ alpha(0.0), beta(0.0)
+{
+ MFEM_ASSERT(_A.GetVDim() == _B.GetVDim(),
"VectorSumCoefficient: "
"Arguments must have the same dimension.");
}
@@ -447,26 +466,47 @@ VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &A,
void VectorSumCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
- b->Eval(V, T, ip);
- if ( beta != 1.0 ) { V *= beta; }
- a->Eval(va, T, ip);
- V.Add(alpha, va);
+ V.SetSize(A.Size());
+ if ( ACoef) { ACoef->Eval(A, T, ip); }
+ if ( BCoef) { BCoef->Eval(B, T, ip); }
+ if (alphaCoef) { alpha = alphaCoef->Eval(T, ip); }
+ if ( betaCoef) { beta = betaCoef->Eval(T, ip); }
+ add(alpha, A, beta, B, V);
}
+ScalarVectorProductCoefficient::ScalarVectorProductCoefficient(
+ double A,
+ VectorCoefficient &B)
+ : VectorCoefficient(B.GetVDim()), aConst(A), a(NULL), b(&B)
+{}
+
ScalarVectorProductCoefficient::ScalarVectorProductCoefficient(
Coefficient &A,
VectorCoefficient &B)
- : VectorCoefficient(B.GetVDim()), a(&A), b(&B)
+ : VectorCoefficient(B.GetVDim()), aConst(0.0), a(&A), b(&B)
{}
void ScalarVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
- double sa = a->Eval(T, ip);
+ double sa = (a == NULL) ? aConst : a->Eval(T, ip);
b->Eval(V, T, ip);
V *= sa;
}
+NormalizedVectorCoefficient::NormalizedVectorCoefficient(VectorCoefficient &A,
+ double _tol)
+ : VectorCoefficient(A.GetVDim()), a(&A), tol(_tol)
+{}
+
+void NormalizedVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
+ const IntegrationPoint &ip)
+{
+ a->Eval(V, T, ip);
+ double nv = V.Norml2();
+ V *= (nv > tol) ? (1.0/nv) : 0.0;
+}
+
VectorCrossProductCoefficient::VectorCrossProductCoefficient(
VectorCoefficient &A,
VectorCoefficient &B)
@@ -488,17 +528,18 @@ void VectorCrossProductCoefficient::Eval(Vector &V, ElementTransformation &T,
V[2] = va[0] * vb[1] - va[1] * vb[0];
}
-MatVecCoefficient::MatVecCoefficient(MatrixCoefficient &A,
- VectorCoefficient &B)
+MatrixVectorProductCoefficient::MatrixVectorProductCoefficient(
+ MatrixCoefficient &A, VectorCoefficient &B)
: VectorCoefficient(A.GetHeight()), a(&A), b(&B),
ma(A.GetHeight(), A.GetWidth()), vb(B.GetVDim())
{
MFEM_ASSERT(A.GetWidth() == B.GetVDim(),
- "MatVecCoefficient: Arguments have incompatible dimensions.");
+ "MatrixVectorProductCoefficient: "
+ "Arguments have incompatible dimensions.");
}
-void MatVecCoefficient::Eval(Vector &V, ElementTransformation &T,
- const IntegrationPoint &ip)
+void MatrixVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T,
+ const IntegrationPoint &ip)
{
a->Eval(ma, T, ip);
b->Eval(vb, T, ip);
@@ -534,17 +575,23 @@ void MatrixSumCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
M.Add(alpha, ma);
}
+ScalarMatrixProductCoefficient::ScalarMatrixProductCoefficient(
+ double A,
+ MatrixCoefficient &B)
+ : MatrixCoefficient(B.GetHeight(), B.GetWidth()), aConst(A), a(NULL), b(&B)
+{}
+
ScalarMatrixProductCoefficient::ScalarMatrixProductCoefficient(
Coefficient &A,
MatrixCoefficient &B)
- : MatrixCoefficient(B.GetHeight(), B.GetWidth()), a(&A), b(&B)
+ : MatrixCoefficient(B.GetHeight(), B.GetWidth()), aConst(0.0), a(&A), b(&B)
{}
void ScalarMatrixProductCoefficient::Eval(DenseMatrix &M,
ElementTransformation &T,
const IntegrationPoint &ip)
{
- double sa = a->Eval(T, ip);
+ double sa = (a == NULL) ? aConst : a->Eval(T, ip);
b->Eval(M, T, ip);
M *= sa;
}
@@ -598,6 +645,30 @@ void OuterProductCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
}
}
+CrossCrossCoefficient::CrossCrossCoefficient(Coefficient &A,
+ VectorCoefficient &K)
+ : MatrixCoefficient(K.GetVDim(), K.GetVDim()), aConst(0.0), a(&A), k(&K),
+ vk(K.GetVDim())
+{}
+
+void CrossCrossCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
+ const IntegrationPoint &ip)
+{
+ k->Eval(vk, T, ip);
+ M.SetSize(vk.Size(), vk.Size());
+ M = 0.0;
+ double k2 = vk*vk;
+ for (int i=0; iEval(T, ip) );
+}
+
double LpNormLoop(double p, Coefficient &coeff, Mesh &mesh,
const IntegrationRule *irs[])
{
@@ -775,4 +846,61 @@ 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];
+}
+
}
diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp
index a50b123515..55e8ebbf30 100644
--- a/fem/coefficient.hpp
+++ b/fem/coefficient.hpp
@@ -27,7 +27,10 @@ class ParMesh;
#endif
-/// Base class Coefficient that may optionally depend on time.
+/** @brief Base class Coefficients that optionally depend on space and time.
+ These are used by the BilinearFormIntegrator, LinearFormIntegrator, and
+ NonlinearFormIntegrator classes to represent the physical coefficients in
+ the PDEs that are being discretized. */
class Coefficient
{
protected:
@@ -36,7 +39,10 @@ protected:
public:
Coefficient() { time = 0.; }
+ /// Set the time for time dependent coefficients
void SetTime(double t) { time = t; }
+
+ /// Get the time for time dependent coefficients
double GetTime() { return time; }
/** @brief Evaluate the coefficient in the element described by @a T at the
@@ -63,7 +69,7 @@ public:
};
-/// Subclass constant coefficient.
+/// A coefficient that is constant across space and time
class ConstantCoefficient : public Coefficient
{
public:
@@ -72,13 +78,14 @@ public:
/// c is value of constant function
explicit ConstantCoefficient(double c = 1.0) { constant=c; }
- /// Evaluate the coefficient
+ /// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{ return (constant); }
};
-/// class for piecewise constant coefficient
+/** @brief A piecewise constant coefficient with the constants keyed
+ off the element attribute numbers. */
class PWConstCoefficient : public Coefficient
{
private:
@@ -90,30 +97,31 @@ public:
explicit PWConstCoefficient(int NumOfSubD = 0) : constants(NumOfSubD)
{ constants = 0.0; }
- /** c should be a vector defined by attributes, so for region with
- attribute i c[i-1] is the coefficient in that region */
+ /// Construct the constant coefficient using a vector of constants.
+ /** @a c should be a vector defined by attributes, so for region with
+ attribute @a i @a c[i-1] is the coefficient in that region */
PWConstCoefficient(Vector &c)
{ constants.SetSize(c.Size()); constants=c; }
- /// Update constants
+ /// Update the constants with vector @a c.
void UpdateConstants(Vector &c) { constants.SetSize(c.Size()); constants=c; }
- /// Member function to access or modify the value of the i-th constant
+ /// Return a reference to the i-th constant
double &operator()(int i) { return constants(i-1); }
- /// Set domain constants equal to the same constant c
+ /// Set the constants for all attributes to constant @a c.
void operator=(double c) { constants = c; }
- /// Returns the number of constants
+ /// Returns the number of constants representing different attributes.
int GetNConst() { return constants.Size(); }
- /// Evaluate the coefficient function
+ /// Evaluate the coefficient.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
-/// class for C-function coefficient
+/// A general C-function coefficient
class FunctionCoefficient : public Coefficient
{
protected:
@@ -121,14 +129,14 @@ protected:
double (*TDFunction)(const Vector &, double);
public:
- /// Define a time-independent coefficient from a C-function
+ /// Define a time-independent coefficient from a pointer to a C-function
FunctionCoefficient(double (*f)(const Vector &))
{
Function = f;
TDFunction = NULL;
}
- /// Define a time-dependent coefficient from a C-function
+ /// Define a time-dependent coefficient from a pointer to a C-function
FunctionCoefficient(double (*tdf)(const Vector &, double))
{
Function = NULL;
@@ -153,7 +161,7 @@ public:
TDFunction = reinterpret_cast(tdf);
}
- /// Evaluate coefficient
+ /// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
@@ -164,23 +172,34 @@ class GridFunction;
class GridFunctionCoefficient : public Coefficient
{
private:
- GridFunction *GridF;
+ const GridFunction *GridF;
int Component;
public:
GridFunctionCoefficient() : GridF(NULL), Component(1) { }
/** Construct GridFunctionCoefficient from a given GridFunction, and
optionally specify a component to use if it is a vector GridFunction. */
- GridFunctionCoefficient (GridFunction *gf, int comp = 1)
+ GridFunctionCoefficient (const GridFunction *gf, int comp = 1)
{ GridF = gf; Component = comp; }
- void SetGridFunction(GridFunction *gf) { GridF = gf; }
- GridFunction * GetGridFunction() const { return GridF; }
+ /// Set the internal GridFunction
+ void SetGridFunction(const GridFunction *gf) { GridF = gf; }
+ /// Get the internal GridFunction
+ const GridFunction * GetGridFunction() const { return GridF; }
+
+ /// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
+
+/** @brief A coefficient that depends on 1 or 2 parent coefficients and a
+ transformation rule represented by a C-function.
+
+ \f$ C(x,t) = T(Q1(x,t)) \f$ or \f$ C(x,t) = T(Q1(x,t), Q2(x,t)) \f$
+
+ where T is the transformation rule, and Q1/Q2 are the parent coefficients.*/
class TransformedCoefficient : public Coefficient
{
private:
@@ -196,10 +215,20 @@ public:
double (*F)(double,double))
: Q1(q1), Q2(q2), Transform2(F) { Transform1 = 0; }
+ /// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
};
-/// Delta function coefficient
+/** @brief Delta function coefficient optionally multiplied by a weight
+ coefficient and a scaled time dependent C-function.
+
+ \f$ F(x,t) = w(x,t) s T(t) d(x - xc) \f$
+
+ where w is the optional weight coefficient, @a s is a scale factor
+ T is an optional time-dependent function and d is a delta function.
+
+ WARNING this cannot be used as a normal coefficient. The usual Eval
+ method is disabled. */
class DeltaCoefficient : public Coefficient
{
protected:
@@ -209,34 +238,49 @@ protected:
double (*tdf)(double);
public:
+
+ /// Construct a unit delta function centered at (0.0,0.0,0.0)
DeltaCoefficient()
{
center[0] = center[1] = center[2] = 0.; scale = 1.; tol = 1e-12;
weight = NULL; sdim = 0; tdf = NULL;
}
+
+ /// Construct a delta function scaled by @a s and centered at (x,0.0,0.0)
DeltaCoefficient(double x, double s)
{
center[0] = x; center[1] = 0.; center[2] = 0.; scale = s; tol = 1e-12;
weight = NULL; sdim = 1; tdf = NULL;
}
+
+ /// Construct a delta function scaled by @a s and centered at (x,y,0.0)
DeltaCoefficient(double x, double y, double s)
{
center[0] = x; center[1] = y; center[2] = 0.; scale = s; tol = 1e-12;
weight = NULL; sdim = 2; tdf = NULL;
}
+
+ /// Construct a delta function scaled by @a s and centered at (x,y,z)
DeltaCoefficient(double x, double y, double z, double s)
{
center[0] = x; center[1] = y; center[2] = z; scale = s; tol = 1e-12;
weight = NULL; sdim = 3; tdf = NULL;
}
+
+ /// Set the center location of the delta function.
void SetDeltaCenter(const Vector& center);
+
+ /// Set the scale value multiplying the delta function.
void SetScale(double _s) { scale = _s; }
+
/// Set a time-dependent function that multiplies the Scale().
void SetFunction(double (*f)(double)) { tdf = f; }
+
/** @brief Set the tolerance used during projection onto GridFunction to
- identifying the Mesh vertex where the Center() of the delta function
- lies. */
+ identify the Mesh vertex where the Center() of the delta function
+ lies. (default 1e-12)*/
void SetTol(double _tol) { tol = _tol; }
+
/// Set a weight Coefficient that multiplies the DeltaCoefficient.
/** The weight Coefficient multiplies the value returned by EvalDelta() but
not the value returned by Scale().
@@ -244,16 +288,26 @@ public:
projecting the DeltaCoefficient onto a GridFunction, so that the weighted
integral of the projection is exactly equal to the Scale(). */
void SetWeight(Coefficient *w) { weight = w; }
+
+ /// Return a pointer to a c-array representing the center of the delta
+ /// function.
const double *Center() { return center; }
- /** @brief Return the scale set by SetScale() multiplied by the
- time-dependent function specified by SetFunction(), if set. */
+
+ /** @brief Return the scale factor times the optional time dependent
+ function. Returns \f$ s T(t) \f$ with \f$ T(t) = 1 \f$ when
+ not set by the user. */
double Scale() { return tdf ? (*tdf)(GetTime())*scale : scale; }
- /// See SetTol() for description of the tolerance parameter.
+
+ /// Return the tolerance used to identify the mesh vertices
double Tol() { return tol; }
+
/// See SetWeight() for description of the weight Coefficient.
Coefficient *Weight() { return weight; }
+
+ /// Write the center of the delta function into @a center.
void GetDeltaCenter(Vector& center);
- /// Return the Scale() multiplied by the weight Coefficient, if any.
+
+ /// The value of the function assuming we are evaluating at the delta center.
virtual double EvalDelta(ElementTransformation &T, const IntegrationPoint &ip);
/** @brief A DeltaFunction cannot be evaluated. Calling this method will
cause an MFEM error, terminating the application. */
@@ -262,7 +316,8 @@ public:
virtual ~DeltaCoefficient() { delete weight; }
};
-/// Coefficient defined on a subset of domain or boundary attributes
+/** @brief Derived coefficient that takes the value of the parent coefficient
+ for the active attributes and is zero otherwise. */
class RestrictedCoefficient : public Coefficient
{
private:
@@ -270,13 +325,18 @@ private:
Array active_attr;
public:
+ /** @brief Construct with a parent coefficient and an array with
+ ones marking the attributes on which this coefficient should be
+ active. */
RestrictedCoefficient(Coefficient &_c, Array &attr)
{ c = &_c; attr.Copy(active_attr); }
+ /// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip)
{ return active_attr[T.Attribute-1] ? c->Eval(T, ip, GetTime()) : 0.0; }
};
+/// Base class for vector Coefficients that optionally depend on time and space.
class VectorCoefficient
{
protected:
@@ -284,9 +344,13 @@ protected:
double time;
public:
+ /// Initialize the VectorCoefficient with vector dimension @a vd.
VectorCoefficient(int vd) { vdim = vd; time = 0.; }
+ /// Set the time for time dependent coefficients
void SetTime(double t) { time = t; }
+
+ /// Get the time for time dependent coefficients
double GetTime() { return time; }
/// Returns dimension of the vector.
@@ -318,19 +382,27 @@ public:
virtual ~VectorCoefficient() { }
};
+
+/// Vector coefficient that is constant in space and time.
class VectorConstantCoefficient : public VectorCoefficient
{
private:
Vector vec;
public:
+ /// Construct the coefficient with constant vector @a v.
VectorConstantCoefficient(const Vector &v)
: VectorCoefficient(v.Size()), vec(v) { }
using VectorCoefficient::Eval;
+
+ /// Evaluate the vector coefficient at @a ip.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip) { V = vec; }
+
+ /// Return a reference to the constant vector in this class.
const Vector& GetVec() { return vec; }
};
+/// A general C-function vector coefficient
class VectorFunctionCoefficient : public VectorCoefficient
{
private:
@@ -359,13 +431,17 @@ public:
}
using VectorCoefficient::Eval;
+ /// Evaluate the vector coefficient at @a ip.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
virtual ~VectorFunctionCoefficient() { }
};
-/// Vector coefficient defined by an array of scalar coefficients.
+/** @brief Vector coefficient defined by an array of scalar coefficients.
+ Coefficients that are not set will evaluate to zero in the vector. This
+ object takes ownership of the array of coefficients inside it and deletes
+ them at object destruction. */
class VectorArrayCoefficient : public VectorCoefficient
{
private:
@@ -373,22 +449,27 @@ private:
Array ownCoeff;
public:
- /// Construct vector of dim coefficients.
+ /** @brief Construct vector of dim coefficients. The actual coefficients
+ still need to be added with Set(). */
explicit VectorArrayCoefficient(int dim);
/// Returns i'th coefficient.
Coefficient* GetCoeff(int i) { return Coeff[i]; }
+ /// Returns the entire array of coefficients.
Coefficient **GetCoeffs() { return Coeff; }
/// Sets coefficient in the vector.
void Set(int i, Coefficient *c, bool own=true);
- /// Evaluates i'th component of the vector.
+ /// Evaluates i'th component of the vector of coefficients and returns the
+ /// value.
double Eval(int i, ElementTransformation &T, const IntegrationPoint &ip)
{ return Coeff[i] ? Coeff[i]->Eval(T, ip, GetTime()) : 0.0; }
using VectorCoefficient::Eval;
+ /** @brief Evaluate the coefficient. Each element of vector V comes from the
+ associated array of scalar coefficients. */
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
@@ -400,18 +481,31 @@ public:
class VectorGridFunctionCoefficient : public VectorCoefficient
{
protected:
- GridFunction *GridFunc;
+ const GridFunction *GridFunc;
public:
+ /** @brief Construct an empty coefficient. Calling Eval() before the grid
+ function is set will cause a segfault. */
VectorGridFunctionCoefficient() : VectorCoefficient(0), GridFunc(NULL) { }
- VectorGridFunctionCoefficient(GridFunction *gf);
- void SetGridFunction(GridFunction *gf);
- GridFunction * GetGridFunction() const { return GridFunc; }
+ /** @brief Construct the coefficient with grid function @a gf. The
+ grid function is not owned by the coefficient. */
+ VectorGridFunctionCoefficient(const GridFunction *gf);
+ /** @brief Set the grid function for this coefficient. Also sets the Vector
+ dimension to match that of the @a gf. */
+ void SetGridFunction(const GridFunction *gf);
+
+ /// Returns a pointer to the grid function in this Coefficient
+ const GridFunction * GetGridFunction() const { return GridFunc; }
+
+ /// Evaluate the vector coefficient at @a ip.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
+ /** @brief Evaluate the vector coefficients at all of the locations in the
+ integration rule and write the vectors into the columns of matrix @a
+ M. */
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationRule &ir);
@@ -422,17 +516,27 @@ public:
class GradientGridFunctionCoefficient : public VectorCoefficient
{
protected:
- GridFunction *GridFunc;
+ const GridFunction *GridFunc;
public:
- GradientGridFunctionCoefficient(GridFunction *gf);
- void SetGridFunction(GridFunction *gf);
- GridFunction * GetGridFunction() const { return GridFunc; }
+ /** @brief Construct the coefficient with a scalar grid function @a gf. The
+ grid function is not owned by the coefficient. */
+ GradientGridFunctionCoefficient(const GridFunction *gf);
+ ///Set the scalar grid function.
+ void SetGridFunction(const GridFunction *gf);
+
+ ///Get the scalar grid function.
+ const GridFunction * GetGridFunction() const { return GridFunc; }
+
+ /// Evaluate the gradient vector coefficient at @a ip.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
+ /** @brief Evaluate the gradient vector coefficient at all of the locations
+ in the integration rule and write the vectors into columns of matrix @a
+ M. */
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationRule &ir);
@@ -443,15 +547,21 @@ public:
class CurlGridFunctionCoefficient : public VectorCoefficient
{
protected:
- GridFunction *GridFunc;
+ const GridFunction *GridFunc;
public:
- CurlGridFunctionCoefficient(GridFunction *gf);
+ /** @brief Construct the coefficient with a vector grid function @a gf. The
+ grid function is not owned by the coefficient. */
+ CurlGridFunctionCoefficient(const GridFunction *gf);
- void SetGridFunction(GridFunction *gf);
- GridFunction * GetGridFunction() const { return GridFunc; }
+ /// Set the vector grid function.
+ void SetGridFunction(const GridFunction *gf);
+
+ /// Get the vector grid function.
+ const GridFunction * GetGridFunction() const { return GridFunc; }
using VectorCoefficient::Eval;
+ /// Evaluate the vector curl coefficient at @a ip.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
@@ -462,21 +572,31 @@ public:
class DivergenceGridFunctionCoefficient : public Coefficient
{
protected:
- GridFunction *GridFunc;
+ const GridFunction *GridFunc;
public:
- DivergenceGridFunctionCoefficient(GridFunction *gf);
+ /** @brief Construct the coefficient with a vector grid function @a gf. The
+ grid function is not owned by the coefficient. */
+ DivergenceGridFunctionCoefficient(const GridFunction *gf);
- void SetGridFunction(GridFunction *gf) { GridFunc = gf; }
- GridFunction * GetGridFunction() const { return GridFunc; }
+ /// Set the vector grid function.
+ void SetGridFunction(const GridFunction *gf) { GridFunc = gf; }
+ /// Get the vector grid function.
+ const GridFunction * GetGridFunction() const { return GridFunc; }
+
+ /// Evaluate the scalar divergence coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
virtual ~DivergenceGridFunctionCoefficient() { }
};
-/// VectorDeltaCoefficient: DeltaCoefficient with a direction
+/** @brief Vector coefficient defined by a scalar DeltaCoefficient and a
+ constant vector direction.
+
+ WARNING this cannot be used as a normal coefficient. The usual Eval method
+ is disabled. */
class VectorDeltaCoefficient : public VectorCoefficient
{
protected:
@@ -484,22 +604,36 @@ protected:
DeltaCoefficient d;
public:
+ /// Construct with a vector of dimension @a _vdim.
VectorDeltaCoefficient(int _vdim)
: VectorCoefficient(_vdim), dir(_vdim), d() { }
+
+ /** @brief Construct with a Vector object representing the direction and a
+ unit delta function centered at (0.0,0.0,0.0) */
VectorDeltaCoefficient(const Vector& _dir)
: VectorCoefficient(_dir.Size()), dir(_dir), d() { }
+
+ /** @brief Construct with a Vector object representing the direction and a
+ delta function scaled by @a s and centered at (x,0.0,0.0) */
VectorDeltaCoefficient(const Vector& _dir, double x, double s)
: VectorCoefficient(_dir.Size()), dir(_dir), d(x,s) { }
+
+ /** @brief Construct with a Vector object representing the direction and a
+ delta function scaled by @a s and centered at (x,y,0.0) */
VectorDeltaCoefficient(const Vector& _dir, double x, double y, double s)
: VectorCoefficient(_dir.Size()), dir(_dir), d(x,y,s) { }
+
+ /** @brief Construct with a Vector object representing the direction and a
+ delta function scaled by @a s and centered at (x,y,z) */
VectorDeltaCoefficient(const Vector& _dir, double x, double y, double z,
double s)
: VectorCoefficient(_dir.Size()), dir(_dir), d(x,y,z,s) { }
- /// Replace the associated DeltaCoeficient with a new DeltaCoeficient.
- /** The new DeltaCoeficient cannot have a specified weight Coefficient, i.e.
- DeltaCoeficient::Weight() should return NULL. */
+ /// Replace the associated DeltaCoefficient with a new DeltaCoefficient.
+ /** The new DeltaCoefficient cannot have a specified weight Coefficient, i.e.
+ DeltaCoefficient::Weight() should return NULL. */
void SetDeltaCoefficient(const DeltaCoefficient& _d) { d = _d; }
+
/// Return the associated scalar DeltaCoefficient.
DeltaCoefficient& GetDeltaCoefficient() { return d; }
@@ -514,6 +648,7 @@ public:
DeltaCoefficient. */
virtual void EvalDelta(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
+
using VectorCoefficient::Eval;
/** @brief A VectorDeltaFunction cannot be evaluated. Calling this method
will cause an MFEM error, terminating the application. */
@@ -523,7 +658,8 @@ public:
virtual ~VectorDeltaCoefficient() { }
};
-/// VectorCoefficient defined on a subset of domain or boundary attributes
+/** @brief Derived vector coefficient that has the value of the parent vector
+ where it is active and is zero otherwise. */
class VectorRestrictedCoefficient : public VectorCoefficient
{
private:
@@ -531,18 +667,26 @@ private:
Array active_attr;
public:
+ /** @brief Construct with a parent vector coefficient and an array of zeros
+ and ones representing the attributes for which this coefficient should be
+ active. */
VectorRestrictedCoefficient(VectorCoefficient &vc, Array &attr)
: VectorCoefficient(vc.GetVDim())
{ c = &vc; attr.Copy(active_attr); }
+ /// Evaluate the vector coefficient at @a ip.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
+ /** @brief Evaluate the vector coefficient at all of the locations in the
+ integration rule and write the vectors into the columns of matrix @a
+ M. */
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationRule &ir);
};
+/// Base class for Matrix Coefficients that optionally depend on time and space.
class MatrixCoefficient
{
protected:
@@ -550,16 +694,25 @@ protected:
double time;
public:
+ /// Construct a dim x dim matrix coefficient.
explicit MatrixCoefficient(int dim) { height = width = dim; time = 0.; }
+ /// Construct a h x w matrix coefficient.
MatrixCoefficient(int h, int w) : height(h), width(w), time(0.) { }
+ /// Set the time for time dependent coefficients
void SetTime(double t) { time = t; }
+
+ /// Get the time for time dependent coefficients
double GetTime() { return time; }
+ /// Get the height of the matrix.
int GetHeight() const { return height; }
+
+ /// Get the width of the matrix.
int GetWidth() const { return width; }
- // For backward compatibility
+
+ /// For backward compatibility get the width of the matrix.
int GetVDim() const { return width; }
/** @brief Evaluate the matrix coefficient in the element described by @a T
@@ -573,18 +726,26 @@ public:
virtual ~MatrixCoefficient() { }
};
+
+/// A matrix coefficient that is constant in space and time.
class MatrixConstantCoefficient : public MatrixCoefficient
{
private:
DenseMatrix mat;
public:
+ ///Construct using matrix @a m for the constant.
MatrixConstantCoefficient(const DenseMatrix &m)
: MatrixCoefficient(m.Height(), m.Width()), mat(m) { }
using MatrixCoefficient::Eval;
+ /// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip) { M = mat; }
};
+
+/** @brief A matrix coefficient with an optional scalar coefficient multiplier
+ \a q. The matrix function can either be represented by a C-function or a
+ constant matrix provided when constructing this object. */
class MatrixFunctionCoefficient : public MatrixCoefficient
{
private:
@@ -594,7 +755,8 @@ private:
DenseMatrix mat;
public:
- /// Construct a time-independent square matrix coefficient from a C-function
+ /// Construct a square matrix coefficient from a C-function without time
+ /// dependence.
MatrixFunctionCoefficient(int dim, void (*F)(const Vector &, DenseMatrix &),
Coefficient *q = NULL)
: MatrixCoefficient(dim), Q(q)
@@ -613,7 +775,8 @@ public:
mat = m;
}
- /// Construct a time-dependent square matrix coefficient from a C-function
+ /// Construct a square matrix coefficient from a C-function with
+ /// time-dependence.
MatrixFunctionCoefficient(int dim,
void (*TDF)(const Vector &, double, DenseMatrix &),
Coefficient *q = NULL)
@@ -624,12 +787,18 @@ public:
mat.SetSize(0);
}
+ /// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
virtual ~MatrixFunctionCoefficient() { }
};
+
+
+/** @brief Matrix coefficient defined by a matrix of scalar coefficients.
+ Coefficients that are not set will evaluate to zero in the vector. The
+ coefficient is stored as a flat Array with indexing (i,j) -> i*width+j. */
class MatrixArrayCoefficient : public MatrixCoefficient
{
private:
@@ -637,23 +806,33 @@ private:
Array ownCoeff;
public:
-
+ /** @brief Construct a coefficient matrix of dimensions @a dim * @a dim. The
+ actual coefficients still need to be added with Set(). */
explicit MatrixArrayCoefficient (int dim);
+ /// Get the coefficient located at (i,j) in the matrix.
Coefficient* GetCoeff (int i, int j) { return Coeff[i*width+j]; }
+ /** @brief Set the coefficient located at (i,j) in the matrix. By default by
+ default this will take ownership of the Coefficient passed in, but this
+ can be overridden with the @a own parameter. */
void Set(int i, int j, Coefficient * c, bool own=true);
+ /// Evaluate coefficient located at (i,j) in the matrix using integration
+ /// point @a ip.
double Eval(int i, int j, ElementTransformation &T, const IntegrationPoint &ip)
{ return Coeff[i*width+j] ? Coeff[i*width+j] -> Eval(T, ip, GetTime()) : 0.0; }
+ /// Evaluate the matrix coefficient @a ip.
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
virtual ~MatrixArrayCoefficient();
};
-/// MatrixCoefficient defined on a subset of domain or boundary attributes
+
+/** @brief Derived matrix coefficient that has the value of the parent matrix
+ coefficient where it is active and is zero otherwise. */
class MatrixRestrictedCoefficient : public MatrixCoefficient
{
private:
@@ -661,20 +840,26 @@ private:
Array active_attr;
public:
+ /** @brief Construct with a parent matrix coefficient and an array of zeros
+ and ones representing the attributes for which this coefficient should be
+ active. */
MatrixRestrictedCoefficient(MatrixCoefficient &mc, Array &attr)
: MatrixCoefficient(mc.GetHeight(), mc.GetWidth())
{ c = &mc; attr.Copy(active_attr); }
+ /// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
};
-/// Coefficients based on sums and products of other coefficients
-
-/// Scalar coefficient defined as the sum of two scalar coefficients
+/// Coefficients based on sums, products, or other functions of coefficients.
+///@{
+/** Scalar coefficient defined as the linear combination of two scalar
+ coefficients or a scalar and a scalar coefficient */
class SumCoefficient : public Coefficient
{
private:
+ double aConst;
Coefficient * a;
Coefficient * b;
@@ -682,32 +867,141 @@ private:
double beta;
public:
- // Result is _alpha * A + _beta * B
+ /// Constructor with one coefficient. Result is _alpha * A + _beta * B
+ SumCoefficient(double A, Coefficient &B,
+ double _alpha = 1.0, double _beta = 1.0)
+ : aConst(A), a(NULL), b(&B), alpha(_alpha), beta(_beta) { }
+
+ /// Constructor with two coefficients. Result is _alpha * A + _beta * B.
SumCoefficient(Coefficient &A, Coefficient &B,
double _alpha = 1.0, double _beta = 1.0)
- : a(&A), b(&B), alpha(_alpha), beta(_beta) { }
+ : aConst(0.0), a(&A), b(&B), alpha(_alpha), beta(_beta) { }
- /// Evaluate the coefficient
+ /// Reset the first term in the linear combination as a constant
+ void SetAConst(double A) { a = NULL; aConst = A; }
+ /// Return the first term in the linear combination
+ double GetAConst() const { return aConst; }
+
+ /// Reset the first term in the linear combination
+ void SetACoef(Coefficient &A) { a = &A; }
+ /// Return the first term in the linear combination
+ Coefficient * GetACoef() const { return a; }
+
+ /// Reset the second term in the linear combination
+ void SetBCoef(Coefficient &B) { b = &B; }
+ /// Return the second term in the linear combination
+ Coefficient * GetBCoef() const { return b; }
+
+ /// Reset the factor in front of the first term in the linear combination
+ void SetAlpha(double _alpha) { alpha = _alpha; }
+ /// Return the factor in front of the first term in the linear combination
+ double GetAlpha() const { return alpha; }
+
+ /// Reset the factor in front of the second term in the linear combination
+ void SetBeta(double _beta) { beta = _beta; }
+ /// Return the factor in front of the second term in the linear combination
+ double GetBeta() const { return beta; }
+
+ /// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip)
- { return alpha * a->Eval(T, ip) + beta * b->Eval(T, ip); }
+ {
+ return alpha * ((a == NULL ) ? aConst : a->Eval(T, ip) )
+ + beta * b->Eval(T, ip);
+ }
};
-/// Scalar coefficient defined as the product of two scalar coefficients
+/** Scalar coefficient defined as the product of two scalar coefficients or
+ a scalar and a scalar coefficient. */
class ProductCoefficient : public Coefficient
{
private:
+ double aConst;
Coefficient * a;
Coefficient * b;
public:
+ /// Constructor with one coefficient. Result is A * B.
+ ProductCoefficient(double A, Coefficient &B)
+ : aConst(A), a(NULL), b(&B) { }
+
+ /// Constructor with two coefficients. Result is A * B.
ProductCoefficient(Coefficient &A, Coefficient &B)
- : a(&A), b(&B) { }
+ : aConst(0.0), a(&A), b(&B) { }
+
+ /// Reset the first term in the product as a constant
+ void SetAConst(double A) { a = NULL; aConst = A; }
+ /// Return the first term in the product
+ double GetAConst() const { return aConst; }
+
+ /// Reset the first term in the product
+ void SetACoef(Coefficient &A) { a = &A; }
+ /// Return the first term in the product
+ Coefficient * GetACoef() const { return a; }
+
+ /// Reset the second term in the product
+ void SetBCoef(Coefficient &B) { b = &B; }
+ /// Return the second term in the product
+ Coefficient * GetBCoef() const { return b; }
+
+ /// Evaluate the coefficient at @a ip.
+ virtual double Eval(ElementTransformation &T,
+ const IntegrationPoint &ip)
+ { return ((a == NULL ) ? aConst : a->Eval(T, ip) ) * b->Eval(T, ip); }
+};
+
+/** Scalar coefficient defined as the ratio of two scalars where one or both
+ scalars are scalar coefficients. */
+class RatioCoefficient : public Coefficient
+{
+private:
+ double aConst;
+ double bConst;
+ Coefficient * a;
+ Coefficient * b;
+
+public:
+ /** Initialize a coefficient which returns A / B where @a A is a
+ constant and @a B is a scalar coefficient */
+ RatioCoefficient(double A, Coefficient &B)
+ : aConst(A), bConst(1.0), a(NULL), b(&B) { }
+ /** Initialize a coefficient which returns A / B where @a A and @a B are both
+ scalar coefficients */
+ RatioCoefficient(Coefficient &A, Coefficient &B)
+ : aConst(0.0), bConst(1.0), a(&A), b(&B) { }
+ /** Initialize a coefficient which returns A / B where @a A is a
+ scalar coefficient and @a B is a constant */
+ RatioCoefficient(Coefficient &A, double B)
+ : aConst(0.0), bConst(B), a(&A), b(NULL) { }
+
+ /// Reset the numerator in the ratio as a constant
+ void SetAConst(double A) { a = NULL; aConst = A; }
+ /// Return the numerator of the ratio
+ double GetAConst() const { return aConst; }
+
+ /// Reset the denominator in the ratio as a constant
+ void SetBConst(double B) { b = NULL; bConst = B; }
+ /// Return the denominator of the ratio
+ double GetBConst() const { return bConst; }
+
+ /// Reset the numerator in the ratio
+ void SetACoef(Coefficient &A) { a = &A; }
+ /// Return the numerator of the ratio
+ Coefficient * GetACoef() const { return a; }
+
+ /// Reset the denominator in the ratio
+ void SetBCoef(Coefficient &B) { b = &B; }
+ /// Return the denominator of the ratio
+ Coefficient * GetBCoef() const { return b; }
/// Evaluate the coefficient
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip)
- { return a->Eval(T, ip) * b->Eval(T, ip); }
+ {
+ double den = (b == NULL ) ? bConst : b->Eval(T, ip);
+ MFEM_ASSERT(den != 0.0, "Division by zero in RatioCoefficient");
+ return ((a == NULL ) ? aConst : a->Eval(T, ip) ) / den;
+ }
};
/// Scalar coefficient defined as a scalar raised to a power
@@ -719,16 +1013,27 @@ private:
double p;
public:
- // Result is A^p
+ /// Construct with a coefficient and a constant power @a _p. Result is A^p.
PowerCoefficient(Coefficient &A, double _p)
: a(&A), p(_p) { }
- /// Evaluate the coefficient
+ /// Reset the base coefficient
+ void SetACoef(Coefficient &A) { a = &A; }
+ /// Return the base coefficient
+ Coefficient * GetACoef() const { return a; }
+
+ /// Reset the exponent
+ void SetExponent(double _p) { p = _p; }
+ /// Return the exponent
+ double GetExponent() const { return p; }
+
+ /// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{ return pow(a->Eval(T, ip), p); }
};
+
/// Scalar coefficient defined as the inner product of two vector coefficients
class InnerProductCoefficient : public Coefficient
{
@@ -739,14 +1044,25 @@ private:
mutable Vector va;
mutable Vector vb;
public:
+ /// Construct with the two vector coefficients. Result is \f$ A \cdot B \f$.
InnerProductCoefficient(VectorCoefficient &A, VectorCoefficient &B);
- /// Evaluate the coefficient
+ /// Reset the first vector in the inner product
+ void SetACoef(VectorCoefficient &A) { a = &A; }
+ /// Return the first vector coefficient in the inner product
+ VectorCoefficient * GetACoef() const { return a; }
+
+ /// Reset the second vector in the inner product
+ void SetBCoef(VectorCoefficient &B) { b = &B; }
+ /// Return the second vector coefficient in the inner product
+ VectorCoefficient * GetBCoef() const { return b; }
+
+ /// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
-/// Scalar coefficient defined as a cross product of two vectors in 2D
+/// Scalar coefficient defined as a cross product of two vectors in the xy-plane.
class VectorRotProductCoefficient : public Coefficient
{
private:
@@ -757,8 +1073,20 @@ private:
mutable Vector vb;
public:
+ /// Constructor with two vector coefficients. Result is \f$ A_x B_y - A_y * B_x; \f$.
VectorRotProductCoefficient(VectorCoefficient &A, VectorCoefficient &B);
+ /// Reset the first vector in the product
+ void SetACoef(VectorCoefficient &A) { a = &A; }
+ /// Return the first vector of the product
+ VectorCoefficient * GetACoef() const { return a; }
+
+ /// Reset the second vector in the product
+ void SetBCoef(VectorCoefficient &B) { b = &B; }
+ /// Return the second vector of the product
+ VectorCoefficient * GetBCoef() const { return b; }
+
+ /// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
@@ -772,19 +1100,31 @@ private:
mutable DenseMatrix ma;
public:
+ /// Construct with the matrix.
DeterminantCoefficient(MatrixCoefficient &A);
- /// Evaluate the coefficient
+ /// Reset the matrix coefficient
+ void SetACoef(MatrixCoefficient &A) { a = &A; }
+ /// Return the matrix coefficient
+ MatrixCoefficient * GetACoef() const { return a; }
+
+ /// Evaluate the determinant coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
-/// Vector coefficient defined as the sum of two vector coefficients
+/// Vector coefficient defined as the linear combination of two vectors
class VectorSumCoefficient : public VectorCoefficient
{
private:
- VectorCoefficient * a;
- VectorCoefficient * b;
+ VectorCoefficient * ACoef;
+ VectorCoefficient * BCoef;
+
+ Vector A;
+ Vector B;
+
+ Coefficient * alphaCoef;
+ Coefficient * betaCoef;
double alpha;
double beta;
@@ -792,26 +1132,125 @@ private:
mutable Vector va;
public:
- // Result is _alpha * A + _beta * B
+ /** Constructor with no coefficients.
+ To be used with the various "Set" methods */
+ VectorSumCoefficient(int dim);
+
+ /** Constructor with two vector coefficients.
+ Result is _alpha * A + _beta * B */
VectorSumCoefficient(VectorCoefficient &A, VectorCoefficient &B,
double _alpha = 1.0, double _beta = 1.0);
- /// Evaluate the coefficient
+ /** Constructor with scalar coefficients.
+ Result is _alpha * _A + _beta * _B */
+ VectorSumCoefficient(VectorCoefficient &_A, VectorCoefficient &_B,
+ Coefficient &_alpha, Coefficient &_beta);
+
+ /// Reset the first vector coefficient
+ void SetACoef(VectorCoefficient &A) { ACoef = &A; }
+ /// Return the first vector coefficient
+ VectorCoefficient * GetACoef() const { return ACoef; }
+
+ /// Reset the second vector coefficient
+ void SetBCoef(VectorCoefficient &B) { BCoef = &B; }
+ /// Return the second vector coefficient
+ VectorCoefficient * GetBCoef() const { return BCoef; }
+
+ /// Reset the factor in front of the first vector coefficient
+ void SetAlphaCoef(Coefficient &A) { alphaCoef = &A; }
+ /// Return the factor in front of the first vector coefficient
+ Coefficient * GetAlphaCoef() const { return alphaCoef; }
+
+ /// Reset the factor in front of the second vector coefficient
+ void SetBetaCoef(Coefficient &B) { betaCoef = &B; }
+ /// Return the factor in front of the second vector coefficient
+ Coefficient * GetBetaCoef() const { return betaCoef; }
+
+ /// Reset the first vector as a constant
+ void SetA(const Vector &_A) { A = _A; ACoef = NULL; }
+ /// Return the first vector constant
+ const Vector & GetA() const { return A; }
+
+ /// Reset the second vector as a constant
+ void SetB(const Vector &_B) { B = _B; BCoef = NULL; }
+ /// Return the second vector constant
+ const Vector & GetB() const { return B; }
+
+ /// Reset the factor in front of the first vector coefficient as a constant
+ void SetAlpha(double _alpha) { alpha = _alpha; alphaCoef = NULL; }
+ /// Return the factor in front of the first vector coefficient
+ double GetAlpha() const { return alpha; }
+
+ /// Reset the factor in front of the second vector coefficient as a constant
+ void SetBeta(double _beta) { beta = _beta; betaCoef = NULL; }
+ /// Return the factor in front of the second vector coefficient
+ double GetBeta() const { return beta; }
+
+ /// Evaluate the coefficient at @a ip.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
using VectorCoefficient::Eval;
};
-/// Vector coefficient defined as a product of a scalar and a vector
+/// Vector coefficient defined as a product of scalar and vector coefficients.
class ScalarVectorProductCoefficient : public VectorCoefficient
{
private:
+ double aConst;
Coefficient * a;
VectorCoefficient * b;
public:
+ /// Constructor with constant and vector coefficient. Result is A * B.
+ ScalarVectorProductCoefficient(double A, VectorCoefficient &B);
+
+ /// Constructor with two coefficients. Result is A * B.
ScalarVectorProductCoefficient(Coefficient &A, VectorCoefficient &B);
+ /// Reset the scalar factor as a constant
+ void SetAConst(double A) { a = NULL; aConst = A; }
+ /// Return the scalar factor
+ double GetAConst() const { return aConst; }
+
+ /// Reset the scalar factor
+ void SetACoef(Coefficient &A) { a = &A; }
+ /// Return the scalar factor
+ Coefficient * GetACoef() const { return a; }
+
+ /// Reset the vector factor
+ void SetBCoef(VectorCoefficient &B) { b = &B; }
+ /// Return the vector factor
+ VectorCoefficient * GetBCoef() const { return b; }
+
+ /// Evaluate the coefficient at @a ip.
+ virtual void Eval(Vector &V, ElementTransformation &T,
+ const IntegrationPoint &ip);
+ using VectorCoefficient::Eval;
+};
+
+/// Vector coefficient defined as a normalized vector field (returns v/|v|)
+class NormalizedVectorCoefficient : public VectorCoefficient
+{
+private:
+ VectorCoefficient * a;
+
+ double tol;
+
+public:
+ /** @brief Return a vector normalized to a length of one
+
+ This class evaluates the vector coefficient @a A and, if |A| > @a tol,
+ returns the normalized vector A / |A|. If |A| <= @a tol, the zero
+ vector is returned.
+ */
+ NormalizedVectorCoefficient(VectorCoefficient &A, double tol = 1e-6);
+
+ /// Reset the vector coefficient
+ void SetACoef(VectorCoefficient &A) { a = &A; }
+ /// Return the vector coefficient
+ VectorCoefficient * GetACoef() const { return a; }
+
+ /// Evaluate the coefficient at @a ip.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
using VectorCoefficient::Eval;
@@ -828,15 +1267,28 @@ private:
mutable Vector vb;
public:
+ /// Construct with the two coefficients. Result is A x B.
VectorCrossProductCoefficient(VectorCoefficient &A, VectorCoefficient &B);
+ /// Reset the first term in the product
+ void SetACoef(VectorCoefficient &A) { a = &A; }
+ /// Return the first term in the product
+ VectorCoefficient * GetACoef() const { return a; }
+
+ /// Reset the second term in the product
+ void SetBCoef(VectorCoefficient &B) { b = &B; }
+ /// Return the second term in the product
+ VectorCoefficient * GetBCoef() const { return b; }
+
+ /// Evaluate the coefficient at @a ip.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
using VectorCoefficient::Eval;
};
-/// Vector coefficient defined as a matrix vector product
-class MatVecCoefficient : public VectorCoefficient
+/** @brief Vector coefficient defined as a product of a matrix coefficient and
+ a vector coefficient. */
+class MatrixVectorProductCoefficient : public VectorCoefficient
{
private:
MatrixCoefficient * a;
@@ -846,28 +1298,45 @@ private:
mutable Vector vb;
public:
- MatVecCoefficient(MatrixCoefficient &A, VectorCoefficient &B);
+ /// Constructor with two coefficients. Result is A*B.
+ MatrixVectorProductCoefficient(MatrixCoefficient &A, VectorCoefficient &B);
+ /// Reset the matrix coefficient
+ void SetACoef(MatrixCoefficient &A) { a = &A; }
+ /// Return the matrix coefficient
+ MatrixCoefficient * GetACoef() const { return a; }
+
+ /// Reset the vector coefficient
+ void SetBCoef(VectorCoefficient &B) { b = &B; }
+ /// Return the vector coefficient
+ VectorCoefficient * GetBCoef() const { return b; }
+
+ /// Evaluate the vector coefficient at @a ip.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
using VectorCoefficient::Eval;
};
-/// Matrix coefficient defined as the identity of dimension d
+/// Convenient alias for the MatrixVectorProductCoefficient
+typedef MatrixVectorProductCoefficient MatVecCoefficient;
+
+/// Constant matrix coefficient defined as the identity of dimension d
class IdentityMatrixCoefficient : public MatrixCoefficient
{
private:
int dim;
public:
+ /// Construct with the dimension of the square identity matrix.
IdentityMatrixCoefficient(int d)
: MatrixCoefficient(d, d), dim(d) { }
+ /// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip);
};
-/// Matrix coefficient defined as the sum of two matrix coefficients
+/// Matrix coefficient defined as the linear combination of two matrices
class MatrixSumCoefficient : public MatrixCoefficient
{
private:
@@ -880,56 +1349,112 @@ private:
mutable DenseMatrix ma;
public:
- // Result is _alpha * A + _beta * B
+ /// Construct with the two coefficients. Result is _alpha * A + _beta * B.
MatrixSumCoefficient(MatrixCoefficient &A, MatrixCoefficient &B,
double _alpha = 1.0, double _beta = 1.0);
- /// Evaluate the coefficient
+ /// Reset the first matrix coefficient
+ void SetACoef(MatrixCoefficient &A) { a = &A; }
+ /// Return the first matrix coefficient
+ MatrixCoefficient * GetACoef() const { return a; }
+
+ /// Reset the second matrix coefficient
+ void SetBCoef(MatrixCoefficient &B) { b = &B; }
+ /// Return the second matrix coefficient
+ MatrixCoefficient * GetBCoef() const { return b; }
+
+ /// Reset the factor in front of the first matrix coefficient
+ void SetAlpha(double _alpha) { alpha = _alpha; }
+ /// Return the factor in front of the first matrix coefficient
+ double GetAlpha() const { return alpha; }
+
+ /// Reset the factor in front of the second matrix coefficient
+ void SetBeta(double _beta) { beta = _beta; }
+ /// Return the factor in front of the second matrix coefficient
+ double GetBeta() const { return beta; }
+
+ /// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip);
};
-/// Matrix coefficient defined as a product of a scalar and a matrix
+/** @brief Matrix coefficient defined as a product of a scalar coefficient and a
+ matrix coefficient.*/
class ScalarMatrixProductCoefficient : public MatrixCoefficient
{
private:
+ double aConst;
Coefficient * a;
MatrixCoefficient * b;
public:
+ /// Constructor with one coefficient. Result is A*B.
+ ScalarMatrixProductCoefficient(double A, MatrixCoefficient &B);
+
+ /// Constructor with two coefficients. Result is A*B.
ScalarMatrixProductCoefficient(Coefficient &A, MatrixCoefficient &B);
+ /// Reset the scalar factor as a constant
+ void SetAConst(double A) { a = NULL; aConst = A; }
+ /// Return the scalar factor
+ double GetAConst() const { return aConst; }
+
+ /// Reset the scalar factor
+ void SetACoef(Coefficient &A) { a = &A; }
+ /// Return the scalar factor
+ Coefficient * GetACoef() const { return a; }
+
+ /// Reset the matrix factor
+ void SetBCoef(MatrixCoefficient &B) { b = &B; }
+ /// Return the matrix factor
+ MatrixCoefficient * GetBCoef() const { return b; }
+
+ /// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip);
};
-/// Matrix coefficient defined as the transpose a matrix
+/// Matrix coefficient defined as the transpose a matrix coefficient
class TransposeMatrixCoefficient : public MatrixCoefficient
{
private:
MatrixCoefficient * a;
public:
+ /// Construct with the matrix coefficient. Result is \f$ A^T \f$.
TransposeMatrixCoefficient(MatrixCoefficient &A);
+ /// Reset the matrix coefficient
+ void SetACoef(MatrixCoefficient &A) { a = &A; }
+ /// Return the matrix coefficient
+ MatrixCoefficient * GetACoef() const { return a; }
+
+ /// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip);
};
-/// Matrix coefficient defined as the inverse a matrix
+/// Matrix coefficient defined as the inverse a matrix coefficient.
class InverseMatrixCoefficient : public MatrixCoefficient
{
private:
MatrixCoefficient * a;
public:
+ /// Construct with the matrix coefficient. Result is \f$ A^{-1} \f$.
InverseMatrixCoefficient(MatrixCoefficient &A);
+ /// Reset the matrix coefficient
+ void SetACoef(MatrixCoefficient &A) { a = &A; }
+ /// Return the matrix coefficient
+ MatrixCoefficient * GetACoef() const { return a; }
+
+ /// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip);
};
-/// Matrix coefficient defined as the outer product of two vectors
+/// Matrix coefficient defined as the outer product of two vector coefficients.
class OuterProductCoefficient : public MatrixCoefficient
{
private:
@@ -940,29 +1465,130 @@ private:
mutable Vector vb;
public:
+ /// Construct with two vector coefficients. Result is \f$ A B^T \f$.
OuterProductCoefficient(VectorCoefficient &A, VectorCoefficient &B);
+ /// Reset the first vector in the outer product
+ void SetACoef(VectorCoefficient &A) { a = &A; }
+ /// Return the first vector coefficient in the outer product
+ VectorCoefficient * GetACoef() const { return a; }
+
+ /// Reset the second vector in the outer product
+ void SetBCoef(VectorCoefficient &B) { b = &B; }
+ /// Return the second vector coefficient in the outer product
+ VectorCoefficient * GetBCoef() const { return b; }
+
+ /// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip);
};
-/** Compute the Lp norm of a function f.
+/** @brief Matrix coefficient defined as -a k x k x, for a vector k and scalar a
+
+ This coefficient returns \f$a * (|k|^2 I - k \otimes k)\f$, where I is
+ the identity matrix and \f$\otimes\f$ indicates the outer product. This
+ can be evaluated for vectors of any dimension but in three
+ dimensions it corresponds to computing the cross product with k twice.
+*/
+class CrossCrossCoefficient : public MatrixCoefficient
+{
+private:
+ double aConst;
+ Coefficient * a;
+ VectorCoefficient * k;
+
+ mutable Vector vk;
+
+public:
+ CrossCrossCoefficient(double A, VectorCoefficient &K);
+ CrossCrossCoefficient(Coefficient &A, VectorCoefficient &K);
+
+ /// Reset the scalar factor as a constant
+ void SetAConst(double A) { a = NULL; aConst = A; }
+ /// Return the scalar factor
+ double GetAConst() const { return aConst; }
+
+ /// Reset the scalar factor
+ void SetACoef(Coefficient &A) { a = &A; }
+ /// Return the scalar factor
+ Coefficient * GetACoef() const { return a; }
+
+ /// Reset the vector factor
+ void SetKCoef(VectorCoefficient &K) { k = &K; }
+ /// Return the vector factor
+ VectorCoefficient * GetKCoef() const { return k; }
+
+ /// Evaluate the matrix coefficient at @a ip.
+ virtual void Eval(DenseMatrix &M, ElementTransformation &T,
+ const IntegrationPoint &ip);
+};
+///@}
+
+class QuadratureFunction;
+
+/** @brief Vector quadrature function coefficient which requires that the
+ quadrature rules used for this vector coefficient be the same as those that
+ live within the supplied QuadratureFunction. */
+class VectorQuadratureFunctionCoefficient : public VectorCoefficient
+{
+private:
+ const QuadratureFunction &QuadF; //do not own
+ int index;
+
+public:
+ /// Constructor with a quadrature function as input
+ VectorQuadratureFunctionCoefficient(QuadratureFunction &qf);
+
+ /** Set the starting index within the QuadFunc that'll be used to project
+ outwards as well as the corresponding length. The projected length should
+ have the bounds of 1 <= length <= (length QuadFunc - index). */
+ void SetComponent(int _index, int _length);
+
+ const QuadratureFunction& GetQuadFunction() const { return QuadF; }
+
+ using VectorCoefficient::Eval;
+ virtual void Eval(Vector &V, ElementTransformation &T,
+ const IntegrationPoint &ip);
+
+ virtual ~VectorQuadratureFunctionCoefficient() { }
+};
+
+/** @brief Quadrature function coefficient which requires that the quadrature
+ rules used for this coefficient be the same as those that live within the
+ supplied QuadratureFunction. */
+class QuadratureFunctionCoefficient : public Coefficient
+{
+private:
+ const QuadratureFunction &QuadF;
+
+public:
+ /// Constructor with a quadrature function as input
+ QuadratureFunctionCoefficient(QuadratureFunction &qf);
+
+ const QuadratureFunction& GetQuadFunction() const { return QuadF; }
+
+ virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
+
+ virtual ~QuadratureFunctionCoefficient() { }
+};
+
+/** @brief Compute the Lp norm of a function f.
\f$ \| f \|_{Lp} = ( \int_\Omega | f |^p d\Omega)^{1/p} \f$ */
double ComputeLpNorm(double p, Coefficient &coeff, Mesh &mesh,
const IntegrationRule *irs[]);
-/** Compute the Lp norm of a vector function f = {f_i}_i=1...N.
+/** @brief Compute the Lp norm of a vector function f = {f_i}_i=1...N.
\f$ \| f \|_{Lp} = ( \sum_i \| f_i \|_{Lp}^p )^{1/p} \f$ */
double ComputeLpNorm(double p, VectorCoefficient &coeff, Mesh &mesh,
const IntegrationRule *irs[]);
#ifdef MFEM_USE_MPI
-/** Compute the global Lp norm of a function f.
+/** @brief Compute the global Lp norm of a function f.
\f$ \| f \|_{Lp} = ( \int_\Omega | f |^p d\Omega)^{1/p} \f$ */
double ComputeGlobalLpNorm(double p, Coefficient &coeff, ParMesh &pmesh,
const IntegrationRule *irs[]);
-/** Compute the global Lp norm of a vector function f = {f_i}_i=1...N.
+/** @brief Compute the global Lp norm of a vector function f = {f_i}_i=1...N.
\f$ \| f \|_{Lp} = ( \sum_i \| f_i \|_{Lp}^p )^{1/p} \f$ */
double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh,
const IntegrationRule *irs[]);
diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp
index 26419b2532..ad35ed27a9 100644
--- a/fem/eltrans.cpp
+++ b/fem/eltrans.cpp
@@ -19,6 +19,7 @@ namespace mfem
ElementTransformation::ElementTransformation()
: IntPoint(static_cast(NULL)),
EvalState(0),
+ geom(Geometry::INVALID),
Attribute(-1),
ElementNo(-1)
{ }
@@ -551,4 +552,155 @@ void IntegrationPointTransformation::Transform (const IntegrationRule &ir1,
}
}
+void FaceElementTransformations::SetIntPoint(const IntegrationPoint *face_ip)
+{
+ IsoparametricTransformation::SetIntPoint(face_ip);
+
+ if (mask & 4)
+ {
+ Loc1.Transform(*face_ip, eip1);
+ if (Elem1)
+ {
+ Elem1->SetIntPoint(&eip1);
+ }
+ }
+ if (mask & 8)
+ {
+ Loc2.Transform(*face_ip, eip2);
+ if (Elem2)
+ {
+ Elem2->SetIntPoint(&eip2);
+ }
+ }
+}
+
+ElementTransformation &
+FaceElementTransformations::GetElement1Transformation()
+{
+ MFEM_VERIFY(mask & HAVE_ELEM1 && Elem1 != NULL, "The ElementTransformation "
+ "for the element has not been configured for side 1.");
+ return *Elem1;
+}
+
+ElementTransformation &
+FaceElementTransformations::GetElement2Transformation()
+{
+ MFEM_VERIFY(mask & HAVE_ELEM2 && Elem2 != NULL, "The ElementTransformation "
+ "for the element has not been configured for side 2.");
+ return *Elem2;
+}
+
+IntegrationPointTransformation &
+FaceElementTransformations::GetIntPoint1Transformation()
+{
+ MFEM_VERIFY(mask & HAVE_LOC1, "The IntegrationPointTransformation "
+ "for the element has not been configured for side 1.");
+ return Loc1;
+}
+
+IntegrationPointTransformation &
+FaceElementTransformations::GetIntPoint2Transformation()
+{
+ MFEM_VERIFY(mask & HAVE_LOC2, "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 & HAVE_FACE, "The ElementTransformation "
+ "for the face has not been configured.");
+ IsoparametricTransformation::Transform(ip, trans);
+}
+
+void FaceElementTransformations::Transform(const IntegrationRule &ir,
+ DenseMatrix &tr)
+{
+ MFEM_VERIFY(mask & HAVE_FACE, "The ElementTransformation "
+ "for the face has not been configured.");
+ IsoparametricTransformation::Transform(ir, tr);
+}
+
+void FaceElementTransformations::Transform(const DenseMatrix &matrix,
+ DenseMatrix &result)
+{
+ MFEM_VERIFY(mask & HAVE_FACE, "The ElementTransformation "
+ "for the face has not been configured.");
+ IsoparametricTransformation::Transform(matrix, result);
+}
+
+double FaceElementTransformations::CheckConsistency(int print_level,
+ std::ostream &out)
+{
+ // Check that the face vertices are mapped to the same physical location
+ // when using the following three transformations:
+ // - the face transformation, *this
+ // - Loc1 + Elem1
+ // - Loc2 + Elem2, if present.
+
+ const bool have_face = (mask & 16);
+ const bool have_el1 = (mask & 1) && (mask & 4);
+ const bool have_el2 = (mask & 2) && (mask & 8) && (Elem2No >= 0);
+ if (int(have_face) + int(have_el1) + int(have_el2) < 2)
+ {
+ // need at least two different transformations to perform a check
+ return 0.0;
+ }
+
+ const IntegrationRule &v_ir = *Geometries.GetVertices(GetGeometryType());
+
+ double max_dist = 0.0;
+ Vector dist(v_ir.GetNPoints());
+ DenseMatrix coords_base, coords_el;
+ IntegrationRule v_eir(v_ir.GetNPoints());
+ if (have_face)
+ {
+ Transform(v_ir, coords_base);
+ if (print_level > 0)
+ {
+ out << "\nface vertex coordinates (from face transform):\n"
+ << "----------------------------------------------\n";
+ coords_base.PrintT(out, coords_base.Height());
+ }
+ }
+ if (have_el1)
+ {
+ Loc1.Transform(v_ir, v_eir);
+ Elem1->Transform(v_eir, coords_el);
+ if (print_level > 0)
+ {
+ out << "\nface vertex coordinates (from element 1 transform):\n"
+ << "---------------------------------------------------\n";
+ coords_el.PrintT(out, coords_el.Height());
+ }
+ if (have_face)
+ {
+ coords_el -= coords_base;
+ coords_el.Norm2(dist);
+ max_dist = std::max(max_dist, dist.Normlinf());
+ }
+ else
+ {
+ coords_base = coords_el;
+ }
+ }
+ if (have_el2)
+ {
+ Loc2.Transform(v_ir, v_eir);
+ Elem2->Transform(v_eir, coords_el);
+ if (print_level > 0)
+ {
+ out << "\nface vertex coordinates (from element 2 transform):\n"
+ << "---------------------------------------------------\n";
+ coords_el.PrintT(out, coords_el.Height());
+ }
+ coords_el -= coords_base;
+ coords_el.Norm2(dist);
+ max_dist = std::max(max_dist, dist.Normlinf());
+ }
+
+ return max_dist;
+}
+
}
diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp
index 78daf9a733..51bac1251e 100644
--- a/fem/eltrans.hpp
+++ b/fem/eltrans.hpp
@@ -38,9 +38,12 @@ protected:
};
Geometry::Type geom;
- // Evaluate the Jacobian of the transformation at the IntPoint and store it
- // in dFdx.
+ /** @brief Evaluate the Jacobian of the transformation at the IntPoint and
+ store it in dFdx. */
virtual const DenseMatrix &EvalJacobian() = 0;
+
+ /** @brief Evaluate the Hessian of the transformation at the IntPoint and
+ store it in d2Fdx2. */
virtual const DenseMatrix &EvalHessian() = 0;
double EvalWeight();
@@ -48,18 +51,53 @@ protected:
const DenseMatrix &EvalInverseJ();
public:
- int Attribute, ElementNo;
+
+ /** 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;
ElementTransformation();
+ /** @brief Set the integration point @a ip that weights and Jacobians will
+ be evaluated at. */
void SetIntPoint(const IntegrationPoint *ip)
{ IntPoint = ip; EvalState = 0; }
+
+ /** @brief Get a const reference to the currently set integration point. This
+ will return NULL if no integration point is set. */
const IntegrationPoint &GetIntPoint() { return *IntPoint; }
+ /** @brief Transform integration point from reference coordinates to
+ physical coordinates and store them in the vector. */
virtual void Transform(const IntegrationPoint &, Vector &) = 0;
+
+ /** @brief Transform all the integration points from the integration rule
+ from reference coordinates to physical
+ coordinates and store them as column vectors in the matrix. */
virtual void Transform(const IntegrationRule &, DenseMatrix &) = 0;
- /// Transform columns of 'matrix', store result in 'result'.
+ /** @brief Transform all the integration points from the column vectors
+ of @a matrix from reference coordinates to physical
+ coordinates and store them as column vectors in @a result. */
virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result) = 0;
/** @brief Return the Jacobian matrix of the transformation at the currently
@@ -70,27 +108,44 @@ public:
const DenseMatrix &Jacobian()
{ return (EvalState & JACOBIAN_MASK) ? dFdx : EvalJacobian(); }
+
+ /** @brief Return the Hessian matrix of the transformation at the currently
+ set IntegrationPoint, using the method SetIntPoint(). */
const DenseMatrix &Hessian()
{ return (EvalState & HESSIAN_MASK) ? d2Fdx2 : EvalHessian(); }
+ /** @brief Return the weight of the Jacobian matrix of the transformation
+ at the currently set IntegrationPoint.
+ The Weight evaluates to \f$ \sqrt{\lvert J^T J \rvert} \f$. */
double Weight() { return (EvalState & WEIGHT_MASK) ? Wght : EvalWeight(); }
+ /** @brief Return the adjugate of the Jacobian matrix of the transformation
+ at the currently set IntegrationPoint. */
const DenseMatrix &AdjugateJacobian()
{ return (EvalState & ADJUGATE_MASK) ? adjJ : EvalAdjugateJ(); }
+ /** @brief Return the inverse of the Jacobian matrix of the transformation
+ at the currently set IntegrationPoint. */
const DenseMatrix &InverseJacobian()
{ return (EvalState & INVERSE_MASK) ? invJ : EvalInverseJ(); }
+ /// Return the order of the current element we are using for the transformation.
virtual int Order() const = 0;
+
+ /// Return the order of the elements of the Jacobian of the transformation.
virtual int OrderJ() const = 0;
+
+ /** @brief Return the order of the determinant of the Jacobian (weight)
+ of the transformation. */
virtual int OrderW() const = 0;
- /// Order of adj(J)^t.grad(fi)
+
+ /// Return the order of \f$ adj(J)^T \nabla fi \f$
virtual int OrderGrad(const FiniteElement *fe) const = 0;
/// Return the Geometry::Type of the reference element.
Geometry::Type GetGeometryType() const { return geom; }
- /// Return the dimension of the reference element.
+ /// Return the topological dimension of the reference element.
int GetDimension() const { return Geometry::Dimension[geom]; }
/// Get the dimension of the target (physical) space.
@@ -286,7 +341,7 @@ public:
virtual int Transform(const Vector &pt, IntegrationPoint &ip);
};
-
+/// A standard isoparametric element transformation
class IsoparametricTransformation : public ElementTransformation
{
private:
@@ -296,26 +351,29 @@ private:
const FiniteElement *FElem;
DenseMatrix PointMat; // dim x dof
- // Evaluate the Jacobian of the transformation at the IntPoint and store it
- // in dFdx.
+ /** @brief Evaluate the Jacobian of the transformation at the IntPoint and
+ store it in dFdx. */
virtual const DenseMatrix &EvalJacobian();
// Evaluate the Hessian of the transformation at the IntPoint and store it
// in d2Fdx2.
virtual const DenseMatrix &EvalHessian();
public:
+ /// Set the element that will be used to compute the transformations
void SetFE(const FiniteElement *FE) { FElem = FE; geom = FE->GetGeomType(); }
+
+ /// Get the current element used to compute the transformations
const FiniteElement* GetFE() const { return FElem; }
/// @brief Set the underlying point matrix describing the transformation.
/** The dimensions of the matrix are space-dim x dof. The transformation is
defined as
+ \f$ x = F( \hat x ) = P \phi( \hat x ) \f$
- x = F(xh) = P . phi(xh),
-
- where xh (x hat) is the reference point, x is the corresponding physical
- point, P is the point matrix, and phi(xh) is the column-vector of all
- basis functions evaluated at xh. The columns of P represent the control
- points in physical space defining the transformation. */
+ where \f$ \hat x \f$ is the reference point, @a x is the corresponding
+ physical point, @a P is the point matrix, and \f$ \phi( \hat x ) \f$ is
+ the column-vector of all basis functions evaluated at \f$ \hat x \f$ .
+ The columns of @a P represent the control points in physical space
+ defining the transformation. */
void SetPointMat(const DenseMatrix &pm) { PointMat = pm; }
/// Return the stored point matrix.
@@ -324,19 +382,44 @@ public:
/// Write access to the stored point matrix. Use with caution.
DenseMatrix &GetPointMat() { return PointMat; }
+ /// Set the FiniteElement Geometry for the reference elements being used.
void SetIdentityTransformation(Geometry::Type GeomType);
+ /** @brief Transform integration point from reference coordinates to
+ physical coordinates and store them in the vector. */
virtual void Transform(const IntegrationPoint &, Vector &);
+
+ /** @brief Transform all the integration points from the integration rule
+ from reference coordinates to physical
+ coordinates and store them as column vectors in the matrix. */
virtual void Transform(const IntegrationRule &, DenseMatrix &);
+
+ /** @brief Transform all the integration points from the column vectors
+ of @a matrix from reference coordinates to physical
+ coordinates and store them as column vectors in @a result. */
virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result);
+ /// Return the order of the current element we are using for the transformation.
virtual int Order() const { return FElem->GetOrder(); }
+
+ /// Return the order of the elements of the Jacobian of the transformation.
virtual int OrderJ() const;
+
+ /** @brief Return the order of the determinant of the Jacobian (weight)
+ of the transformation. */
virtual int OrderW() const;
+
+ /// Return the order of \f$ adj(J)^T \nabla fi \f$
virtual int OrderGrad(const FiniteElement *fe) const;
virtual int GetSpaceDim() const { return PointMat.Height(); }
+ /** @brief Transform a point @a pt from physical space to a point @a ip in
+ reference space. */
+ /** Attempt to find the IntegrationPoint that is transformed into the given
+ point in physical space. If the inversion fails a non-zero value is
+ returned. This method is not 100 percent reliable for non-linear
+ transformations. */
virtual int TransformBack(const Vector & v, IntegrationPoint & ip)
{
InverseElementTransformation inv_tr(this);
@@ -356,15 +439,157 @@ public:
void Transform (const IntegrationRule &, IntegrationRule &);
};
-class FaceElementTransformations
+/** @brief A specialized ElementTransformation class representing a face and
+ its two neighboring elements.
+
+ This class can be used as a container for the element transformation data
+ needed for integrating discontinuous fields on element interfaces in a
+ Discontinuous Galerkin (DG) context.
+
+ The secondary purpose of this class is to enable the
+ GridFunction::GetValue function, and various related functions, to properly
+ evaluate fields with limited continuity on boundary elements.
+*/
+class FaceElementTransformations : public IsoparametricTransformation
{
+private:
+
+ // Bitwise OR of ConfigMasks
+ int mask;
+
+ IntegrationPoint eip1, eip2;
+
+protected: // interface for Mesh to be able to configure this object.
+
+ friend class Mesh;
+#ifdef MFEM_USE_MPI
+ friend class ParMesh;
+#endif
+
+ /// 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
+ FaceElementTransformations 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; }
+
public:
- int Elem1No, Elem2No, FaceGeom;
- ElementTransformation *Elem1, *Elem2, *Face;
+
+ enum ConfigMasks
+ {
+ HAVE_ELEM1 = 1, ///< Element on side 1 is configured
+ HAVE_ELEM2 = 2, ///< Element on side 2 is configured
+ HAVE_LOC1 = 4, ///< Point transformation for side 1 is configured
+ HAVE_LOC2 = 8, ///< Point transformation for side 2 is configured
+ HAVE_FACE = 16 ///< Face transformation is configured
+ };
+
+ int Elem1No, Elem2No;
+ Geometry::Type &FaceGeom; ///< @deprecated Use GetGeometryType instead
+ ElementTransformation *Elem1, *Elem2;
+ ElementTransformation *Face; ///< @deprecated No longer necessary
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; }
+
+ /** @brief Return the mask defining the configuration state.
+
+ The mask value indicates which portions of FaceElementTransformations
+ 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
+ */
+ int GetConfigurationMask() const { return mask; }
+
+ /** @brief Set the integration point in the Face and the two neighboring
+ elements, if present.
+
+ The point @a face_ip must be in the reference coordinate system of the
+ face.
+ */
+ void SetIntPoint(const IntegrationPoint *face_ip);
+
+ /** @brief Set the integration point in the Face and the two neighboring
+ elements, if present.
+
+ This is a more expressive member function name than SetIntPoint, which
+ in this special case, does the same thing. This function can be used for
+ greater code clarity.
+ */
+ inline void SetAllIntPoints(const IntegrationPoint *face_ip)
+ { FaceElementTransformations::SetIntPoint(face_ip); }
+
+ /** @brief Get a const reference to the integration point in neighboring
+ element 1 corresponding to the currently set integration point on the
+ face.
+
+ This IntegrationPoint object will only contain up-to-date data if
+ SetIntPoint or SetAllIntPoints has been called with the latest
+ integration point for the face and the appropriate point transformation
+ has been configured. */
+ const IntegrationPoint &GetElement1IntPoint() { return eip1; }
+
+ /** @brief Get a const reference to the integration point in neighboring
+ element 2 corresponding to the currently set integration point on the
+ face.
+
+ This IntegrationPoint object will only contain up-to-date data if
+ SetIntPoint or SetAllIntPoints has been called with the latest
+ integration point for the face and the appropriate point transformation
+ has been configured. */
+ const IntegrationPoint &GetElement2IntPoint() { return eip2; }
+
+ 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();
+
+ /** @brief Check for self-consistency: compares the result of mapping the
+ reference face vertices to physical coordinates using the three
+ transformations: face, element 1, and element 2.
+
+ @param[in] print_level If set to a positive number, print the physical
+ coordinates of the face vertices computed through
+ all available transformations: face, element 1,
+ and/or element 2.
+ @param[in,out] out The output stream to use for printing.
+
+ @returns A maximal distance between physical coordinates of face vertices
+ that should coincide. A successful check should return a small
+ number relative to the mesh extents. If less than 2 of the three
+ transformations are set, returns 0.
+
+ @warning This check will generally fail on periodic boundary faces.
+ */
+ double CheckConsistency(int print_level = 0,
+ std::ostream &out = mfem::out);
};
-/* Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x))
+/** Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x))
Physical Space
diff --git a/fem/estimators.hpp b/fem/estimators.hpp
index 15416ae87a..16f66024de 100644
--- a/fem/estimators.hpp
+++ b/fem/estimators.hpp
@@ -45,6 +45,7 @@ public:
/// Force recomputation of the estimates on the next call to GetLocalErrors.
virtual void Reset() = 0;
+ /// Destruct the error estimator
virtual ~ErrorEstimator() { }
};
@@ -66,6 +67,14 @@ public:
/** @brief The ZienkiewiczZhuEstimator class implements the Zienkiewicz-Zhu
error estimation procedure.
+ Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery
+ and a posteriori error estimates. Part 1: The recovery technique.
+ Int. J. Num. Meth. Engng. 33, 1331-1364 (1992).
+
+ Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery
+ and a posteriori error estimates. Part 2: Error estimates and adaptivity.
+ Int. J. Num. Meth. Engng. 33, 1365-1382 (1992).
+
The required BilinearFormIntegrator must implement the methods
ComputeElementFlux() and ComputeFluxEnergy().
*/
@@ -217,6 +226,7 @@ protected:
class when needed.*/
bool own_flux_fes; ///< Ownership flag for flux_space and smooth_flux_space.
+ /// Initialize with the integrator, solution, and flux finite element spaces.
void Init(BilinearFormIntegrator &integ,
ParGridFunction &sol,
ParFiniteElementSpace *flux_fes,
diff --git a/fem/fe.cpp b/fem/fe.cpp
index d585e27f45..eec85fc10d 100644
--- a/fem/fe.cpp
+++ b/fem/fe.cpp
@@ -25,15 +25,15 @@ using namespace std;
FiniteElement::FiniteElement(int D, Geometry::Type G, int Do, int O, int F)
: Nodes(Do)
{
- Dim = D ; GeomType = G ; Dof = Do ; Order = O ; FuncSpace = F;
- RangeType = SCALAR;
- MapType = VALUE;
- DerivType = NONE;
- DerivRangeType = SCALAR;
- DerivMapType = VALUE;
- for (int i = 0; i < Geometry::MaxDim; i++) { Orders[i] = -1; }
+ dim = D ; geom_type = G ; dof = Do ; order = O ; func_space = F;
+ range_type = SCALAR;
+ map_type = VALUE;
+ deriv_type = NONE;
+ deriv_range_type = SCALAR;
+ deriv_map_type = VALUE;
+ for (int i = 0; i < Geometry::MaxDim; i++) { orders[i] = -1; }
#ifndef MFEM_THREAD_SAFE
- vshape.SetSize(Dof, Dim);
+ vshape.SetSize(dof, dim);
#endif
}
@@ -75,12 +75,12 @@ void FiniteElement::CalcCurlShape(const IntegrationPoint &ip,
void FiniteElement::CalcPhysCurlShape(ElementTransformation &Trans,
DenseMatrix &curl_shape) const
{
- switch (Dim)
+ switch (dim)
{
case 3:
{
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
+ DenseMatrix vshape(dof, dim);
#endif
CalcCurlShape(Trans.GetIntPoint(), vshape);
MultABt(vshape, Trans.Jacobian(), curl_shape);
@@ -93,7 +93,7 @@ void FiniteElement::CalcPhysCurlShape(ElementTransformation &Trans,
curl_shape *= (1.0 / Trans.Weight());
break;
default:
- MFEM_ABORT("Invalid dimension, Dim = " << Dim);
+ MFEM_ABORT("Invalid dimension, Dim = " << dim);
}
}
@@ -186,7 +186,7 @@ void FiniteElement::CalcPhysShape(ElementTransformation &Trans,
Vector &shape) const
{
CalcShape(Trans.GetIntPoint(), shape);
- if (MapType == INTEGRAL)
+ if (map_type == INTEGRAL)
{
shape /= Trans.Weight();
}
@@ -195,9 +195,9 @@ void FiniteElement::CalcPhysShape(ElementTransformation &Trans,
void FiniteElement::CalcPhysDShape(ElementTransformation &Trans,
DenseMatrix &dshape) const
{
- MFEM_ASSERT(MapType == VALUE, "");
+ MFEM_ASSERT(map_type == VALUE, "");
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
+ DenseMatrix vshape(dof, dim);
#endif
CalcDShape(Trans.GetIntPoint(), vshape);
Mult(vshape, Trans.InverseJacobian(), dshape);
@@ -206,7 +206,7 @@ void FiniteElement::CalcPhysDShape(ElementTransformation &Trans,
void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans,
Vector &Laplacian) const
{
- MFEM_ASSERT(MapType == VALUE, "");
+ MFEM_ASSERT(map_type == VALUE, "");
// Simpler routine if mapping is affine
if (Trans.Hessian().FNorm2() < 1e-20)
@@ -216,27 +216,27 @@ void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans,
}
// Compute full Hessian first if non-affine
- int size = (Dim*(Dim+1))/2;
- DenseMatrix hess(Dof, size);
+ int size = (dim*(dim+1))/2;
+ DenseMatrix hess(dof, size);
CalcPhysHessian(Trans,hess);
- if (Dim == 3)
+ if (dim == 3)
{
- for (int nd = 0; nd < Dof; nd++)
+ for (int nd = 0; nd < dof; nd++)
{
Laplacian[nd] = hess(nd,0) + hess(nd,4) + hess(nd,5);
}
}
- else if (Dim == 2)
+ else if (dim == 2)
{
- for (int nd = 0; nd < Dof; nd++)
+ for (int nd = 0; nd < dof; nd++)
{
Laplacian[nd] = hess(nd,0) + hess(nd,2);
}
}
else
{
- for (int nd = 0; nd < Dof; nd++)
+ for (int nd = 0; nd < dof; nd++)
{
Laplacian[nd] = hess(nd,0);
}
@@ -248,16 +248,16 @@ void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans,
void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
Vector &Laplacian) const
{
- MFEM_ASSERT(MapType == VALUE, "");
- int size = (Dim*(Dim+1))/2;
- DenseMatrix hess(Dof, size);
- DenseMatrix Gij(Dim,Dim);
+ MFEM_ASSERT(map_type == VALUE, "");
+ int size = (dim*(dim+1))/2;
+ DenseMatrix hess(dof, size);
+ DenseMatrix Gij(dim,dim);
Vector scale(size);
CalcHessian (Trans.GetIntPoint(), hess);
MultAAt(Trans.InverseJacobian(), Gij);
- if (Dim == 3)
+ if (dim == 3)
{
scale[0] = Gij(0,0);
scale[1] = 2*Gij(0,1);
@@ -268,7 +268,7 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
scale[5] = Gij(1,1);
}
- else if (Dim == 2)
+ else if (dim == 2)
{
scale[0] = Gij(0,0);
scale[1] = 2*Gij(0,1);
@@ -279,7 +279,7 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
scale[0] = Gij(0,0);
}
- for (int nd = 0; nd < Dof; nd++)
+ for (int nd = 0; nd < dof; nd++)
{
Laplacian[nd] = 0.0;
for (int ii = 0; ii < size; ii++)
@@ -293,11 +293,11 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
DenseMatrix& Hessian) const
{
- MFEM_ASSERT(MapType == VALUE, "");
+ MFEM_ASSERT(map_type == VALUE, "");
// Roll 2-Tensors in vectors and 4-Tensor in Matrix, exploiting symmetry
- Array map(Dim*Dim);
- if (Dim == 3)
+ Array map(dim*dim);
+ if (dim == 3)
{
map[0] = 0;
map[1] = 1;
@@ -311,7 +311,7 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
map[7] = 3;
map[8] = 4;
}
- else if (Dim == 2)
+ else if (dim == 2)
{
map[0] = 0;
map[1] = 1;
@@ -325,16 +325,16 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
}
// Hessian in ref coords
- int size = (Dim*(Dim+1))/2;
- DenseMatrix hess(Dof, size);
+ int size = (dim*(dim+1))/2;
+ DenseMatrix hess(dof, size);
CalcHessian(Trans.GetIntPoint(), hess);
// Gradient in physical coords
if (Trans.Hessian().FNorm2() > 1e-10)
{
- DenseMatrix grad(Dof, Dim);
+ DenseMatrix grad(dof, dim);
CalcPhysDShape(Trans, grad);
- DenseMatrix gmap(Dof, size);
+ DenseMatrix gmap(dof, size);
Mult(grad,Trans.Hessian(),gmap);
hess -= gmap;
}
@@ -343,15 +343,15 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
DenseMatrix lhm(size,size);
DenseMatrix invJ = Trans.Jacobian();
lhm = 0.0;
- for (int i = 0; i < Dim; i++)
+ for (int i = 0; i < dim; i++)
{
- for (int j = 0; j < Dim; j++)
+ for (int j = 0; j < dim; j++)
{
- for (int k = 0; k < Dim; k++)
+ for (int k = 0; k < dim; k++)
{
- for (int l = 0; l < Dim; l++)
+ for (int l = 0; l < dim; l++)
{
- lhm(map[i*Dim+j],map[k*Dim+l]) += invJ(i,k)*invJ(j,l);
+ lhm(map[i*dim+j],map[k*dim+l]) += invJ(i,k)*invJ(j,l);
}
}
}
@@ -359,7 +359,7 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
// Correct multiplicity
Vector mult(size);
mult = 0.0;
- for (int i = 0; i < Dim*Dim; i++) { mult[map[i]]++; }
+ for (int i = 0; i < dim*dim; i++) { mult[map[i]]++; }
lhm.InvRightScaling(mult);
// Hessian in physical coords
@@ -389,31 +389,31 @@ void ScalarFiniteElement::NodalLocalInterpolation (
const ScalarFiniteElement &fine_fe) const
{
double v[Geometry::MaxDim];
- Vector vv (v, Dim);
+ Vector vv (v, dim);
IntegrationPoint f_ip;
#ifdef MFEM_THREAD_SAFE
- Vector c_shape(Dof);
+ Vector c_shape(dof);
#endif
- MFEM_ASSERT(MapType == fine_fe.GetMapType(), "");
+ MFEM_ASSERT(map_type == fine_fe.GetMapType(), "");
- I.SetSize(fine_fe.Dof, Dof);
- for (int i = 0; i < fine_fe.Dof; i++)
+ I.SetSize(fine_fe.dof, dof);
+ for (int i = 0; i < fine_fe.dof; i++)
{
Trans.Transform(fine_fe.Nodes.IntPoint(i), vv);
- f_ip.Set(v, Dim);
+ f_ip.Set(v, dim);
CalcShape(f_ip, c_shape);
- for (int j = 0; j < Dof; j++)
+ for (int j = 0; j < dof; j++)
if (fabs(I(i,j) = c_shape(j)) < 1.0e-12)
{
I(i,j) = 0.0;
}
}
- if (MapType == INTEGRAL)
+ if (map_type == INTEGRAL)
{
// assuming Trans is linear; this should be ok for all refinement types
- Trans.SetIntPoint(&Geometries.GetCenter(GeomType));
+ Trans.SetIntPoint(&Geometries.GetCenter(geom_type));
I *= Trans.Weight();
}
}
@@ -425,11 +425,11 @@ void ScalarFiniteElement::ScalarLocalInterpolation(
// General "interpolation", defined by L2 projection
double v[Geometry::MaxDim];
- Vector vv (v, Dim);
+ Vector vv (v, dim);
IntegrationPoint f_ip;
const int fs = fine_fe.GetDof(), cs = this->GetDof();
- I.SetSize(fs, cs);
+ I.SetSize(fs, cs );
Vector fine_shape(fs), coarse_shape(cs);
DenseMatrix fine_mass(fs), fine_coarse_mass(fs, cs); // initialized with 0
const int ir_order = GetOrder() + fine_fe.GetOrder();
@@ -440,7 +440,7 @@ void ScalarFiniteElement::ScalarLocalInterpolation(
const IntegrationPoint &ip = ir.IntPoint(i);
fine_fe.CalcShape(ip, fine_shape);
Trans.Transform(ip, vv);
- f_ip.Set(v, Dim);
+ f_ip.Set(v, dim);
this->CalcShape(f_ip, coarse_shape);
AddMult_a_VVt(ip.weight, fine_shape, fine_mass);
@@ -450,10 +450,10 @@ void ScalarFiniteElement::ScalarLocalInterpolation(
DenseMatrixInverse fine_mass_inv(fine_mass);
fine_mass_inv.Mult(fine_coarse_mass, I);
- if (MapType == INTEGRAL)
+ if (map_type == INTEGRAL)
{
// assuming Trans is linear; this should be ok for all refinement types
- Trans.SetIntPoint(&Geometries.GetCenter(GeomType));
+ Trans.SetIntPoint(&Geometries.GetCenter(geom_type));
I *= Trans.Weight();
}
}
@@ -474,30 +474,30 @@ const DofToQuad &ScalarFiniteElement::GetDofToQuad(const IntegrationRule &ir,
d2q->FE = this;
d2q->IntRule = &ir;
d2q->mode = mode;
- d2q->ndof = Dof;
+ d2q->ndof = dof;
d2q->nqpt = nqpt;
- d2q->B.SetSize(nqpt*Dof);
- d2q->Bt.SetSize(Dof*nqpt);
- d2q->G.SetSize(nqpt*Dim*Dof);
- d2q->Gt.SetSize(Dof*nqpt*Dim);
+ d2q->B.SetSize(nqpt*dof);
+ d2q->Bt.SetSize(dof*nqpt);
+ d2q->G.SetSize(nqpt*dim*dof);
+ d2q->Gt.SetSize(dof*nqpt*dim);
#ifdef MFEM_THREAD_SAFE
- Vector c_shape(Dof);
- DenseMatrix vshape(Dof, Dim);
+ Vector c_shape(dof);
+ DenseMatrix vshape(dof, dim);
#endif
for (int i = 0; i < nqpt; i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
CalcShape(ip, c_shape);
- for (int j = 0; j < Dof; j++)
+ for (int j = 0; j < dof; j++)
{
- d2q->B[i+nqpt*j] = d2q->Bt[j+Dof*i] = c_shape(j);
+ d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = c_shape(j);
}
CalcDShape(ip, vshape);
- for (int d = 0; d < Dim; d++)
+ for (int d = 0; d < dim; d++)
{
- for (int j = 0; j < Dof; j++)
+ for (int j = 0; j < dof; j++)
{
- d2q->G[i+nqpt*(d+Dim*j)] = d2q->Gt[j+Dof*(i+nqpt*d)] = vshape(j,d);
+ d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j,d);
}
}
}
@@ -520,8 +520,8 @@ const DofToQuad &ScalarFiniteElement::GetTensorDofToQuad(
DofToQuad *d2q = new DofToQuad;
const Poly_1D::Basis &basis_1d = tb.GetBasis1D();
- const int ndof = Order + 1;
- const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/Dim) + 0.5);
+ const int ndof = order + 1;
+ const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5);
d2q->FE = this;
d2q->IntRule = &ir;
d2q->mode = mode;
@@ -556,8 +556,8 @@ void NodalFiniteElement::ProjectCurl_2D(
DenseMatrix curl_shape(fe.GetDof(), 1);
- curl.SetSize(Dof, fe.GetDof());
- for (int i = 0; i < Dof; i++)
+ curl.SetSize(dof, fe.GetDof());
+ for (int i = 0; i < dof; i++)
{
fe.CalcCurlShape(Nodes.IntPoint(i), curl_shape);
for (int j = 0; j < fe.GetDof(); j++)
@@ -587,18 +587,18 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans,
DenseMatrix &R) const
{
IntegrationPoint ipt;
- Vector pt(&ipt.x, Dim);
+ Vector pt(&ipt.x, dim);
#ifdef MFEM_THREAD_SAFE
- Vector c_shape(Dof);
+ Vector c_shape(dof);
#endif
Trans.SetIntPoint(&Nodes[0]);
- for (int j = 0; j < Dof; j++)
+ for (int j = 0; j < dof; j++)
{
InvertLinearTrans(Trans, Nodes[j], pt);
- if (Geometries.CheckPoint(GeomType, ipt)) // do we need an epsilon here?
+ if (Geometries.CheckPoint(geom_type, ipt)) // do we need an epsilon here?
{
CalcShape(ipt, c_shape);
R.SetRow(j, c_shape);
@@ -615,14 +615,14 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans,
void NodalFiniteElement::Project (
Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
{
- for (int i = 0; i < Dof; i++)
+ for (int i = 0; i < dof; i++)
{
const IntegrationPoint &ip = Nodes.IntPoint(i);
// some coefficients expect that Trans.IntPoint is the same
// as the second argument of Eval
Trans.SetIntPoint(&ip);
dofs(i) = coeff.Eval (Trans, ip);
- if (MapType == INTEGRAL)
+ if (map_type == INTEGRAL)
{
dofs(i) *= Trans.Weight();
}
@@ -632,21 +632,21 @@ void NodalFiniteElement::Project (
void NodalFiniteElement::Project (
VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
{
- MFEM_ASSERT(dofs.Size() == vc.GetVDim()*Dof, "");
+ MFEM_ASSERT(dofs.Size() == vc.GetVDim()*dof, "");
Vector x(vc.GetVDim());
- for (int i = 0; i < Dof; i++)
+ for (int i = 0; i < dof; i++)
{
const IntegrationPoint &ip = Nodes.IntPoint(i);
Trans.SetIntPoint(&ip);
vc.Eval (x, Trans, ip);
- if (MapType == INTEGRAL)
+ if (map_type == INTEGRAL)
{
x *= Trans.Weight();
}
for (int j = 0; j < x.Size(); j++)
{
- dofs(Dof*j+i) = x(j);
+ dofs(dof*j+i) = x(j);
}
}
}
@@ -654,20 +654,20 @@ void NodalFiniteElement::Project (
void NodalFiniteElement::ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
{
- // (mc.height x mc.width) @ DOFs -> (Dof x mc.width x mc.height) in dofs
- MFEM_ASSERT(dofs.Size() == mc.GetHeight()*mc.GetWidth()*Dof, "");
+ // (mc.height x mc.width) @ DOFs -> (dof x mc.width x mc.height) in dofs
+ MFEM_ASSERT(dofs.Size() == mc.GetHeight()*mc.GetWidth()*dof, "");
DenseMatrix MQ(mc.GetHeight(), mc.GetWidth());
- for (int k = 0; k < Dof; k++)
+ for (int k = 0; k < dof; k++)
{
T.SetIntPoint(&Nodes.IntPoint(k));
mc.Eval(MQ, T, Nodes.IntPoint(k));
- if (MapType == INTEGRAL) { MQ *= T.Weight(); }
+ if (map_type == INTEGRAL) { MQ *= T.Weight(); }
for (int r = 0; r < MQ.Height(); r++)
{
for (int d = 0; d < MQ.Width(); d++)
{
- dofs(k+Dof*(d+MQ.Width()*r)) = MQ(r,d);
+ dofs(k+dof*(d+MQ.Width()*r)) = MQ(r,d);
}
}
}
@@ -678,12 +678,12 @@ void NodalFiniteElement::Project(
{
if (fe.GetRangeType() == SCALAR)
{
- MFEM_ASSERT(MapType == fe.GetMapType(), "");
+ MFEM_ASSERT(map_type == fe.GetMapType(), "");
Vector shape(fe.GetDof());
- I.SetSize(Dof, fe.GetDof());
- for (int k = 0; k < Dof; k++)
+ I.SetSize(dof, fe.GetDof());
+ for (int k = 0; k < dof; k++)
{
fe.CalcShape(Nodes.IntPoint(k), shape);
for (int j = 0; j < shape.Size(); j++)
@@ -696,19 +696,19 @@ void NodalFiniteElement::Project(
{
DenseMatrix vshape(fe.GetDof(), Trans.GetSpaceDim());
- I.SetSize(vshape.Width()*Dof, fe.GetDof());
- for (int k = 0; k < Dof; k++)
+ I.SetSize(vshape.Width()*dof, fe.GetDof());
+ for (int k = 0; k < dof; k++)
{
Trans.SetIntPoint(&Nodes.IntPoint(k));
fe.CalcVShape(Trans, vshape);
- if (MapType == INTEGRAL)
+ if (map_type == INTEGRAL)
{
vshape *= Trans.Weight();
}
for (int j = 0; j < vshape.Height(); j++)
for (int d = 0; d < vshape.Width(); d++)
{
- I(k+d*Dof,j) = vshape(j,d);
+ I(k+d*dof,j) = vshape(j,d);
}
}
}
@@ -719,26 +719,26 @@ void NodalFiniteElement::ProjectGrad(
DenseMatrix &grad) const
{
MFEM_ASSERT(fe.GetMapType() == VALUE, "");
- MFEM_ASSERT(Trans.GetSpaceDim() == Dim, "")
+ MFEM_ASSERT(Trans.GetSpaceDim() == dim, "")
- DenseMatrix dshape(fe.GetDof(), Dim), grad_k(fe.GetDof(), Dim), Jinv(Dim);
+ DenseMatrix dshape(fe.GetDof(), dim), grad_k(fe.GetDof(), dim), Jinv(dim);
- grad.SetSize(Dim*Dof, fe.GetDof());
- for (int k = 0; k < Dof; k++)
+ grad.SetSize(dim*dof, fe.GetDof());
+ for (int k = 0; k < dof; k++)
{
const IntegrationPoint &ip = Nodes.IntPoint(k);
fe.CalcDShape(ip, dshape);
Trans.SetIntPoint(&ip);
CalcInverse(Trans.Jacobian(), Jinv);
Mult(dshape, Jinv, grad_k);
- if (MapType == INTEGRAL)
+ if (map_type == INTEGRAL)
{
grad_k *= Trans.Weight();
}
for (int j = 0; j < grad_k.Height(); j++)
- for (int d = 0; d < Dim; d++)
+ for (int d = 0; d < dim; d++)
{
- grad(k+d*Dof,j) = grad_k(j,d);
+ grad(k+d*dof,j) = grad_k(j,d);
}
}
}
@@ -750,12 +750,12 @@ void NodalFiniteElement::ProjectDiv(
double detJ;
Vector div_shape(fe.GetDof());
- div.SetSize(Dof, fe.GetDof());
- for (int k = 0; k < Dof; k++)
+ div.SetSize(dof, fe.GetDof());
+ for (int k = 0; k < dof; k++)
{
const IntegrationPoint &ip = Nodes.IntPoint(k);
fe.CalcDivShape(ip, div_shape);
- if (MapType == VALUE)
+ if (map_type == VALUE)
{
Trans.SetIntPoint(&ip);
detJ = Trans.Weight();
@@ -778,7 +778,7 @@ void NodalFiniteElement::ProjectDiv(
void PositiveFiniteElement::Project(
Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
{
- for (int i = 0; i < Dof; i++)
+ for (int i = 0; i < dof; i++)
{
const IntegrationPoint &ip = Nodes.IntPoint(i);
Trans.SetIntPoint(&ip);
@@ -789,17 +789,17 @@ void PositiveFiniteElement::Project(
void PositiveFiniteElement::Project(
VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
{
- MFEM_ASSERT(dofs.Size() == vc.GetVDim()*Dof, "");
+ MFEM_ASSERT(dofs.Size() == vc.GetVDim()*dof, "");
Vector x(vc.GetVDim());
- for (int i = 0; i < Dof; i++)
+ for (int i = 0; i < dof; i++)
{
const IntegrationPoint &ip = Nodes.IntPoint(i);
Trans.SetIntPoint(&ip);
vc.Eval (x, Trans, ip);
for (int j = 0; j < x.Size(); j++)
{
- dofs(Dof*j+i) = x(j);
+ dofs(dof*j+i) = x(j);
}
}
}
@@ -810,7 +810,7 @@ void PositiveFiniteElement::Project(
const NodalFiniteElement *nfe =
dynamic_cast(&fe);
- if (nfe && Dof == nfe->GetDof())
+ if (nfe && dof == nfe->GetDof())
{
nfe->Project(*this, Trans, I);
I.Invert();
@@ -825,7 +825,7 @@ void PositiveFiniteElement::Project(
mass_integ.AssembleElementMatrix2(fe, *this, Trans, mixed_mass);
DenseMatrixInverse pos_mass_inv(pos_mass);
- I.SetSize(Dof, fe.GetDof());
+ I.SetSize(dof, fe.GetDof());
pos_mass_inv.Mult(mixed_mass, I);
}
}
@@ -847,47 +847,47 @@ void VectorFiniteElement::CalcDShape (
void VectorFiniteElement::SetDerivMembers()
{
- switch (MapType)
+ switch (map_type)
{
case H_DIV:
- DerivType = DIV;
- DerivRangeType = SCALAR;
- DerivMapType = INTEGRAL;
+ deriv_type = DIV;
+ deriv_range_type = SCALAR;
+ deriv_map_type = INTEGRAL;
break;
case H_CURL:
- switch (Dim)
+ switch (dim)
{
case 3: // curl: 3D H_CURL -> 3D H_DIV
- DerivType = CURL;
- DerivRangeType = VECTOR;
- DerivMapType = H_DIV;
+ deriv_type = CURL;
+ deriv_range_type = VECTOR;
+ deriv_map_type = H_DIV;
break;
case 2:
// curl: 2D H_CURL -> INTEGRAL
- DerivType = CURL;
- DerivRangeType = SCALAR;
- DerivMapType = INTEGRAL;
+ deriv_type = CURL;
+ deriv_range_type = SCALAR;
+ deriv_map_type = INTEGRAL;
break;
case 1:
- DerivType = NONE;
- DerivRangeType = SCALAR;
- DerivMapType = INTEGRAL;
+ deriv_type = NONE;
+ deriv_range_type = SCALAR;
+ deriv_map_type = INTEGRAL;
break;
default:
- MFEM_ABORT("Invalid dimension, Dim = " << Dim);
+ MFEM_ABORT("Invalid dimension, Dim = " << dim);
}
break;
default:
- MFEM_ABORT("Invalid MapType = " << MapType);
+ MFEM_ABORT("Invalid MapType = " << map_type);
}
}
void VectorFiniteElement::CalcVShape_RT (
ElementTransformation &Trans, DenseMatrix &shape) const
{
- MFEM_ASSERT(MapType == H_DIV, "");
+ MFEM_ASSERT(map_type == H_DIV, "");
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
+ DenseMatrix vshape(dof, dim);
#endif
CalcVShape(Trans.GetIntPoint(), vshape);
MultABt(vshape, Trans.Jacobian(), shape);
@@ -897,9 +897,9 @@ void VectorFiniteElement::CalcVShape_RT (
void VectorFiniteElement::CalcVShape_ND (
ElementTransformation &Trans, DenseMatrix &shape) const
{
- MFEM_ASSERT(MapType == H_CURL, "");
+ MFEM_ASSERT(map_type == H_CURL, "");
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
+ DenseMatrix vshape(dof, dim);
#endif
CalcVShape(Trans.GetIntPoint(), vshape);
Mult(vshape, Trans.InverseJacobian(), shape);
@@ -913,14 +913,14 @@ void VectorFiniteElement::Project_RT(
const int sdim = Trans.GetSpaceDim();
MFEM_ASSERT(vc.GetVDim() == sdim, "");
Vector xk(vk, sdim);
- const bool square_J = (Dim == sdim);
+ const bool square_J = (dim == sdim);
- for (int k = 0; k < Dof; k++)
+ for (int k = 0; k < dof; k++)
{
Trans.SetIntPoint(&Nodes.IntPoint(k));
vc.Eval(xk, Trans, Nodes.IntPoint(k));
// dof_k = nk^t adj(J) xk
- dofs(k) = Trans.AdjugateJacobian().InnerProduct(vk, nk + d2n[k]*Dim);
+ dofs(k) = Trans.AdjugateJacobian().InnerProduct(vk, nk + d2n[k]*dim);
if (!square_J) { dofs(k) /= Trans.Weight(); }
}
}
@@ -933,22 +933,22 @@ void VectorFiniteElement::ProjectMatrixCoefficient_RT(
const int sdim = T.GetSpaceDim();
MFEM_ASSERT(mc.GetWidth() == sdim, "");
- const bool square_J = (Dim == sdim);
+ const bool square_J = (dim == sdim);
DenseMatrix MQ(mc.GetHeight(), mc.GetWidth());
Vector nk_phys(sdim), dofs_k(MQ.Height());
- MFEM_ASSERT(dofs.Size() == Dof*MQ.Height(), "");
+ MFEM_ASSERT(dofs.Size() == dof*MQ.Height(), "");
- for (int k = 0; k < Dof; k++)
+ for (int k = 0; k < dof; k++)
{
T.SetIntPoint(&Nodes.IntPoint(k));
mc.Eval(MQ, T, Nodes.IntPoint(k));
// nk_phys = adj(J)^t nk
- T.AdjugateJacobian().MultTranspose(nk + d2n[k]*Dim, nk_phys);
+ T.AdjugateJacobian().MultTranspose(nk + d2n[k]*dim, nk_phys);
if (!square_J) { nk_phys /= T.Weight(); }
MQ.Mult(nk_phys, dofs_k);
for (int r = 0; r < MQ.Height(); r++)
{
- dofs(k+Dof*r) = dofs_k(r);
+ dofs(k+dof*r) = dofs_k(r);
}
}
}
@@ -963,18 +963,18 @@ void VectorFiniteElement::Project_RT(
Vector shape(fe.GetDof());
int sdim = Trans.GetSpaceDim();
- I.SetSize(Dof, sdim*fe.GetDof());
- for (int k = 0; k < Dof; k++)
+ I.SetSize(dof, sdim*fe.GetDof());
+ for (int k = 0; k < dof; k++)
{
const IntegrationPoint &ip = Nodes.IntPoint(k);
fe.CalcShape(ip, shape);
Trans.SetIntPoint(&ip);
- Trans.AdjugateJacobian().MultTranspose(nk + d2n[k]*Dim, vk);
+ Trans.AdjugateJacobian().MultTranspose(nk + d2n[k]*dim, vk);
if (fe.GetMapType() == INTEGRAL)
{
double w = 1.0/Trans.Weight();
- for (int d = 0; d < Dim; d++)
+ for (int d = 0; d < dim; d++)
{
vk[d] *= w;
}
@@ -1004,7 +1004,7 @@ void VectorFiniteElement::ProjectGrad_RT(
const double *nk, const Array &d2n, const FiniteElement &fe,
ElementTransformation &Trans, DenseMatrix &grad) const
{
- if (Dim != 2)
+ if (dim != 2)
{
mfem_error("VectorFiniteElement::ProjectGrad_RT works only in 2D!");
}
@@ -1013,12 +1013,12 @@ void VectorFiniteElement::ProjectGrad_RT(
Vector grad_k(fe.GetDof());
double tk[2];
- grad.SetSize(Dof, fe.GetDof());
- for (int k = 0; k < Dof; k++)
+ grad.SetSize(dof, fe.GetDof());
+ for (int k = 0; k < dof; k++)
{
fe.CalcDShape(Nodes.IntPoint(k), dshape);
- tk[0] = nk[d2n[k]*Dim+1];
- tk[1] = -nk[d2n[k]*Dim];
+ tk[0] = nk[d2n[k]*dim+1];
+ tk[1] = -nk[d2n[k]*dim];
dshape.Mult(tk, grad_k);
for (int j = 0; j < grad_k.Size(); j++)
{
@@ -1032,19 +1032,19 @@ void VectorFiniteElement::ProjectCurl_ND(
ElementTransformation &Trans, DenseMatrix &curl) const
{
#ifdef MFEM_THREAD_SAFE
- DenseMatrix curlshape(fe.GetDof(), Dim);
- DenseMatrix curlshape_J(fe.GetDof(), Dim);
- DenseMatrix J(Dim, Dim);
+ DenseMatrix curlshape(fe.GetDof(), dim);
+ DenseMatrix curlshape_J(fe.GetDof(), dim);
+ DenseMatrix J(dim, dim);
#else
- curlshape.SetSize(fe.GetDof(), Dim);
- curlshape_J.SetSize(fe.GetDof(), Dim);
- J.SetSize(Dim, Dim);
+ curlshape.SetSize(fe.GetDof(), dim);
+ curlshape_J.SetSize(fe.GetDof(), dim);
+ J.SetSize(dim, dim);
#endif
Vector curl_k(fe.GetDof());
- curl.SetSize(Dof, fe.GetDof());
- for (int k = 0; k < Dof; k++)
+ curl.SetSize(dof, fe.GetDof());
+ for (int k = 0; k < dof; k++)
{
const IntegrationPoint &ip = Nodes.IntPoint(k);
@@ -1057,7 +1057,7 @@ void VectorFiniteElement::ProjectCurl_ND(
fe.CalcCurlShape(ip, curlshape);
Mult(curlshape, J, curlshape_J);
- curlshape_J.Mult(tk + d2t[k]*Dim, curl_k);
+ curlshape_J.Mult(tk + d2t[k]*dim, curl_k);
for (int j = 0; j < curl_k.Size(); j++)
{
curl(k,j) = (fabs(curl_k(j)) < 1e-12) ? 0.0 : curl_k(j);
@@ -1069,14 +1069,14 @@ void VectorFiniteElement::ProjectCurl_RT(
const double *nk, const Array &d2n, const FiniteElement &fe,
ElementTransformation &Trans, DenseMatrix &curl) const
{
- DenseMatrix curl_shape(fe.GetDof(), Dim);
+ DenseMatrix curl_shape(fe.GetDof(), dim);
Vector curl_k(fe.GetDof());
- curl.SetSize(Dof, fe.GetDof());
- for (int k = 0; k < Dof; k++)
+ curl.SetSize(dof, fe.GetDof());
+ for (int k = 0; k < dof; k++)
{
fe.CalcCurlShape(Nodes.IntPoint(k), curl_shape);
- curl_shape.Mult(nk + d2n[k]*Dim, curl_k);
+ curl_shape.Mult(nk + d2n[k]*dim, curl_k);
for (int j = 0; j < curl_k.Size(); j++)
{
curl(k,j) = (fabs(curl_k(j)) < 1e-12) ? 0.0 : curl_k(j);
@@ -1091,13 +1091,13 @@ void VectorFiniteElement::Project_ND(
double vk[Geometry::MaxDim];
Vector xk(vk, vc.GetVDim());
- for (int k = 0; k < Dof; k++)
+ for (int k = 0; k < dof; k++)
{
Trans.SetIntPoint(&Nodes.IntPoint(k));
vc.Eval(xk, Trans, Nodes.IntPoint(k));
// dof_k = xk^t J tk
- dofs(k) = Trans.Jacobian().InnerProduct(tk + d2t[k]*Dim, vk);
+ dofs(k) = Trans.Jacobian().InnerProduct(tk + d2t[k]*dim, vk);
}
}
@@ -1111,18 +1111,18 @@ void VectorFiniteElement::ProjectMatrixCoefficient_ND(
MFEM_ASSERT(mc.GetWidth() == sdim, "");
DenseMatrix MQ(mc.GetHeight(), mc.GetWidth());
Vector tk_phys(sdim), dofs_k(MQ.Height());
- MFEM_ASSERT(dofs.Size() == Dof*MQ.Height(), "");
+ MFEM_ASSERT(dofs.Size() == dof*MQ.Height(), "");
- for (int k = 0; k < Dof; k++)
+ for (int k = 0; k < dof; k++)
{
T.SetIntPoint(&Nodes.IntPoint(k));
mc.Eval(MQ, T, Nodes.IntPoint(k));
// tk_phys = J tk
- T.Jacobian().Mult(tk + d2t[k]*Dim, tk_phys);
+ T.Jacobian().Mult(tk + d2t[k]*dim, tk_phys);
MQ.Mult(tk_phys, dofs_k);
for (int r = 0; r < MQ.Height(); r++)
{
- dofs(k+Dof*r) = dofs_k(r);
+ dofs(k+dof*r) = dofs_k(r);
}
}
}
@@ -1137,14 +1137,14 @@ void VectorFiniteElement::Project_ND(
double vk[Geometry::MaxDim];
Vector shape(fe.GetDof());
- I.SetSize(Dof, sdim*fe.GetDof());
- for (int k = 0; k < Dof; k++)
+ I.SetSize(dof, sdim*fe.GetDof());
+ for (int k = 0; k < dof; k++)
{
const IntegrationPoint &ip = Nodes.IntPoint(k);
fe.CalcShape(ip, shape);
Trans.SetIntPoint(&ip);
- Trans.Jacobian().Mult(tk + d2t[k]*Dim, vk);
+ Trans.Jacobian().Mult(tk + d2t[k]*dim, vk);
if (fe.GetMapType() == INTEGRAL)
{
double w = 1.0/Trans.Weight();
@@ -1183,11 +1183,11 @@ void VectorFiniteElement::ProjectGrad_ND(
DenseMatrix dshape(fe.GetDof(), fe.GetDim());
Vector grad_k(fe.GetDof());
- grad.SetSize(Dof, fe.GetDof());
- for (int k = 0; k < Dof; k++)
+ grad.SetSize(dof, fe.GetDof());
+ for (int k = 0; k < dof; k++)
{
fe.CalcDShape(Nodes.IntPoint(k), dshape);
- dshape.Mult(tk + d2t[k]*Dim, grad_k);
+ dshape.Mult(tk + d2t[k]*dim, grad_k);
for (int j = 0; j < grad_k.Size(); j++)
{
grad(k,j) = (fabs(grad_k(j)) < 1e-12) ? 0.0 : grad_k(j);
@@ -1199,33 +1199,33 @@ void VectorFiniteElement::LocalInterpolation_RT(
const VectorFiniteElement &cfe, const double *nk, const Array &d2n,
ElementTransformation &Trans, DenseMatrix &I) const
{
- MFEM_ASSERT(MapType == cfe.GetMapType(), "");
+ MFEM_ASSERT(map_type == cfe.GetMapType(), "");
double vk[Geometry::MaxDim];
- Vector xk(vk, Dim);
+ Vector xk(vk, dim);
IntegrationPoint ip;
#ifdef MFEM_THREAD_SAFE
DenseMatrix vshape(cfe.GetDof(), cfe.GetDim());
#else
DenseMatrix vshape(cfe.vshape.Data(), cfe.GetDof(), cfe.GetDim());
#endif
- I.SetSize(Dof, vshape.Height());
+ I.SetSize(dof, vshape.Height());
// assuming Trans is linear; this should be ok for all refinement types
- Trans.SetIntPoint(&Geometries.GetCenter(GeomType));
+ Trans.SetIntPoint(&Geometries.GetCenter(geom_type));
const DenseMatrix &adjJ = Trans.AdjugateJacobian();
- for (int k = 0; k < Dof; k++)
+ for (int k = 0; k < dof; k++)
{
Trans.Transform(Nodes.IntPoint(k), xk);
ip.Set3(vk);
cfe.CalcVShape(ip, vshape);
// xk = |J| J^{-t} n_k
- adjJ.MultTranspose(nk + d2n[k]*Dim, vk);
- // I_k = vshape_k.adj(J)^t.n_k, k=1,...,Dof
+ adjJ.MultTranspose(nk + d2n[k]*dim, vk);
+ // I_k = vshape_k.adj(J)^t.n_k, k=1,...,dof
for (int j = 0; j < vshape.Height(); j++)
{
double Ikj = 0.;
- for (int i = 0; i < Dim; i++)
+ for (int i = 0; i < dim; i++)
{
Ikj += vshape(j, i) * vk[i];
}
@@ -1239,30 +1239,30 @@ void VectorFiniteElement::LocalInterpolation_ND(
ElementTransformation &Trans, DenseMatrix &I) const
{
double vk[Geometry::MaxDim];
- Vector xk(vk, Dim);
+ Vector xk(vk, dim);
IntegrationPoint ip;
#ifdef MFEM_THREAD_SAFE
DenseMatrix vshape(cfe.GetDof(), cfe.GetDim());
#else
DenseMatrix vshape(cfe.vshape.Data(), cfe.GetDof(), cfe.GetDim());
#endif
- I.SetSize(Dof, vshape.Height());
+ I.SetSize(dof, vshape.Height());
// assuming Trans is linear; this should be ok for all refinement types
- Trans.SetIntPoint(&Geometries.GetCenter(GeomType));
+ Trans.SetIntPoint(&Geometries.GetCenter(geom_type));
const DenseMatrix &J = Trans.Jacobian();
- for (int k = 0; k < Dof; k++)
+ for (int k = 0; k < dof; k++)
{
Trans.Transform(Nodes.IntPoint(k), xk);
ip.Set3(vk);
cfe.CalcVShape(ip, vshape);
// xk = J t_k
- J.Mult(tk + d2t[k]*Dim, vk);
+ J.Mult(tk + d2t[k]*dim, vk);
// I_k = vshape_k.J.t_k, k=1,...,Dof
for (int j = 0; j < vshape.Height(); j++)
{
double Ikj = 0.;
- for (int i = 0; i < Dim; i++)
+ for (int i = 0; i < dim; i++)
{
Ikj += vshape(j, i) * vk[i];
}
@@ -1277,28 +1277,28 @@ void VectorFiniteElement::LocalRestriction_RT(
{
double pt_data[Geometry::MaxDim];
IntegrationPoint ip;
- Vector pt(pt_data, Dim);
+ Vector pt(pt_data, dim);
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
+ DenseMatrix vshape(dof, dim);
#endif
- Trans.SetIntPoint(&Geometries.GetCenter(GeomType));
+ Trans.SetIntPoint(&Geometries.GetCenter(geom_type));
const DenseMatrix &J = Trans.Jacobian();
const double weight = Trans.Weight();
- for (int j = 0; j < Dof; j++)
+ for (int j = 0; j < dof; j++)
{
InvertLinearTrans(Trans, Nodes.IntPoint(j), pt);
- ip.Set(pt_data, Dim);
- if (Geometries.CheckPoint(GeomType, ip)) // do we need an epsilon here?
+ ip.Set(pt_data, dim);
+ if (Geometries.CheckPoint(geom_type, ip)) // do we need an epsilon here?
{
CalcVShape(ip, vshape);
- J.MultTranspose(nk+Dim*d2n[j], pt_data);
+ J.MultTranspose(nk+dim*d2n[j], pt_data);
pt /= weight;
- for (int k = 0; k < Dof; k++)
+ for (int k = 0; k < dof; k++)
{
double R_jk = 0.0;
- for (int d = 0; d < Dim; d++)
+ for (int d = 0; d < dim; d++)
{
R_jk += vshape(k,d)*pt_data[d];
}
@@ -1320,26 +1320,26 @@ void VectorFiniteElement::LocalRestriction_ND(
{
double pt_data[Geometry::MaxDim];
IntegrationPoint ip;
- Vector pt(pt_data, Dim);
+ Vector pt(pt_data, dim);
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
+ DenseMatrix vshape(dof, dim);
#endif
- Trans.SetIntPoint(&Geometries.GetCenter(GeomType));
+ Trans.SetIntPoint(&Geometries.GetCenter(geom_type));
const DenseMatrix &Jinv = Trans.InverseJacobian();
- for (int j = 0; j < Dof; j++)
+ for (int j = 0; j < dof; j++)
{
InvertLinearTrans(Trans, Nodes.IntPoint(j), pt);
- ip.Set(pt_data, Dim);
- if (Geometries.CheckPoint(GeomType, ip)) // do we need an epsilon here?
+ ip.Set(pt_data, dim);
+ if (Geometries.CheckPoint(geom_type, ip)) // do we need an epsilon here?
{
CalcVShape(ip, vshape);
- Jinv.Mult(tk+Dim*d2t[j], pt_data);
- for (int k = 0; k < Dof; k++)
+ Jinv.Mult(tk+dim*d2t[j], pt_data);
+ for (int k = 0; k < dof; k++)
{
double R_jk = 0.0;
- for (int d = 0; d < Dim; d++)
+ for (int d = 0; d < dim; d++)
{
R_jk += vshape(k,d)*pt_data[d];
}
@@ -2130,7 +2130,7 @@ void H1Ser_QuadrilateralElement::GetLocalInterpolation(ElementTransformation
{
// For p<=4, the basis is nodal; for p>4, the quad-interior functions are
// non-nodal.
- if (Order <= 4)
+ if (order <= 4)
{
NodalLocalInterpolation(Trans, I, *this);
}
@@ -3201,7 +3201,7 @@ void TriLinear3DFiniteElement::CalcDShape(const IntegrationPoint &ip,
P0SegmentFiniteElement::P0SegmentFiniteElement(int Ord)
- : NodalFiniteElement(1, Geometry::SEGMENT, 1, Ord) // defaul Ord = 0
+ : NodalFiniteElement(1, Geometry::SEGMENT, 1, Ord) // default Ord = 0
{
Nodes.IntPoint(0).x = 0.5;
}
@@ -3323,8 +3323,8 @@ void RT0TriangleFiniteElement::GetLocalInterpolation (
{
int k, j;
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
- DenseMatrix Jinv(Dim);
+ DenseMatrix vshape(dof, dim);
+ DenseMatrix Jinv(dim);
#endif
#ifdef MFEM_DEBUG
@@ -3377,7 +3377,7 @@ void RT0TriangleFiniteElement::Project (
double vk[2];
Vector xk (vk, 2);
#ifdef MFEM_THREAD_SAFE
- DenseMatrix Jinv(Dim);
+ DenseMatrix Jinv(dim);
#endif
for (int k = 0; k < 3; k++)
@@ -3438,8 +3438,8 @@ void RT0QuadFiniteElement::GetLocalInterpolation (
{
int k, j;
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
- DenseMatrix Jinv(Dim);
+ DenseMatrix vshape(dof, dim);
+ DenseMatrix Jinv(dim);
#endif
#ifdef MFEM_DEBUG
@@ -3492,7 +3492,7 @@ void RT0QuadFiniteElement::Project (
double vk[2];
Vector xk (vk, 2);
#ifdef MFEM_THREAD_SAFE
- DenseMatrix Jinv(Dim);
+ DenseMatrix Jinv(dim);
#endif
for (int k = 0; k < 4; k++)
@@ -3580,8 +3580,8 @@ void RT1TriangleFiniteElement::GetLocalInterpolation (
{
int k, j;
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
- DenseMatrix Jinv(Dim);
+ DenseMatrix vshape(dof, dim);
+ DenseMatrix Jinv(dim);
#endif
#ifdef MFEM_DEBUG
@@ -3633,7 +3633,7 @@ void RT1TriangleFiniteElement::Project (
double vk[2];
Vector xk (vk, 2);
#ifdef MFEM_THREAD_SAFE
- DenseMatrix Jinv(Dim);
+ DenseMatrix Jinv(dim);
#endif
for (int k = 0; k < 8; k++)
@@ -3762,8 +3762,8 @@ void RT1QuadFiniteElement::GetLocalInterpolation (
{
int k, j;
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
- DenseMatrix Jinv(Dim);
+ DenseMatrix vshape(dof, dim);
+ DenseMatrix Jinv(dim);
#endif
#ifdef MFEM_DEBUG
@@ -3815,7 +3815,7 @@ void RT1QuadFiniteElement::Project (
double vk[2];
Vector xk (vk, 2);
#ifdef MFEM_THREAD_SAFE
- DenseMatrix Jinv(Dim);
+ DenseMatrix Jinv(dim);
#endif
for (int k = 0; k < 12; k++)
@@ -4214,8 +4214,8 @@ void RT2QuadFiniteElement::GetLocalInterpolation (
{
int k, j;
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
- DenseMatrix Jinv(Dim);
+ DenseMatrix vshape(dof, dim);
+ DenseMatrix Jinv(dim);
#endif
#ifdef MFEM_DEBUG
@@ -4267,7 +4267,7 @@ void RT2QuadFiniteElement::Project (
double vk[2];
Vector xk (vk, 2);
#ifdef MFEM_THREAD_SAFE
- DenseMatrix Jinv(Dim);
+ DenseMatrix Jinv(dim);
#endif
for (int k = 0; k < 24; k++)
@@ -4574,9 +4574,9 @@ LagrangeHexFiniteElement::LagrangeHexFiniteElement (int degree)
{
if (degree == 2)
{
- I = new int[Dof];
- J = new int[Dof];
- K = new int[Dof];
+ I = new int[dof];
+ J = new int[dof];
+ K = new int[dof];
// nodes
I[ 0] = 0; J[ 0] = 0; K[ 0] = 0;
I[ 1] = 1; J[ 1] = 0; K[ 1] = 0;
@@ -4611,9 +4611,9 @@ LagrangeHexFiniteElement::LagrangeHexFiniteElement (int degree)
}
else if (degree == 3)
{
- I = new int[Dof];
- J = new int[Dof];
- K = new int[Dof];
+ I = new int[dof];
+ J = new int[dof];
+ K = new int[dof];
// nodes
I[ 0] = 0; J[ 0] = 0; K[ 0] = 0;
I[ 1] = 1; J[ 1] = 0; K[ 1] = 0;
@@ -4701,7 +4701,7 @@ LagrangeHexFiniteElement::LagrangeHexFiniteElement (int degree)
dshape1dz.SetSize(dof1d,1);
#endif
- for (int n = 0; n < Dof; n++)
+ for (int n = 0; n < dof; n++)
{
Nodes.IntPoint(n).x = fe1d -> GetNodes().IntPoint(I[n]).x;
Nodes.IntPoint(n).y = fe1d -> GetNodes().IntPoint(J[n]).x;
@@ -4724,7 +4724,7 @@ void LagrangeHexFiniteElement::CalcShape(const IntegrationPoint &ip,
fe1d -> CalcShape(ipy, shape1dy);
fe1d -> CalcShape(ipz, shape1dz);
- for (int n = 0; n < Dof; n++)
+ for (int n = 0; n < dof; n++)
{
shape(n) = shape1dx(I[n]) * shape1dy(J[n]) * shape1dz(K[n]);
}
@@ -4750,7 +4750,7 @@ void LagrangeHexFiniteElement::CalcDShape(const IntegrationPoint &ip,
fe1d -> CalcDShape(ipy, dshape1dy);
fe1d -> CalcDShape(ipz, dshape1dz);
- for (int n = 0; n < Dof; n++)
+ for (int n = 0; n < dof; n++)
{
dshape(n,0) = dshape1dx(I[n],0) * shape1dy(J[n]) * shape1dz(K[n]);
dshape(n,1) = shape1dx(I[n]) * dshape1dy(J[n],0) * shape1dz(K[n]);
@@ -5849,7 +5849,7 @@ void Nedelec1HexFiniteElement::GetLocalInterpolation (
{
int k, j;
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
+ DenseMatrix vshape(dof, dim);
#endif
#ifdef MFEM_DEBUG
@@ -6015,7 +6015,7 @@ void Nedelec1TetFiniteElement::GetLocalInterpolation (
{
int k, j;
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
+ DenseMatrix vshape(dof, dim);
#endif
#ifdef MFEM_DEBUG
@@ -6163,8 +6163,8 @@ void RT0HexFiniteElement::GetLocalInterpolation (
{
int k, j;
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
- DenseMatrix Jinv(Dim);
+ DenseMatrix vshape(dof, dim);
+ DenseMatrix Jinv(dim);
#endif
#ifdef MFEM_DEBUG
@@ -6220,7 +6220,7 @@ void RT0HexFiniteElement::Project (
double vk[3];
Vector xk (vk, 3);
#ifdef MFEM_THREAD_SAFE
- DenseMatrix Jinv(Dim);
+ DenseMatrix Jinv(dim);
#endif
for (int k = 0; k < 6; k++)
@@ -6552,8 +6552,8 @@ void RT1HexFiniteElement::GetLocalInterpolation (
{
int k, j;
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
- DenseMatrix Jinv(Dim);
+ DenseMatrix vshape(dof, dim);
+ DenseMatrix Jinv(dim);
#endif
#ifdef MFEM_DEBUG
@@ -6609,7 +6609,7 @@ void RT1HexFiniteElement::Project (
double vk[3];
Vector xk (vk, 3);
#ifdef MFEM_THREAD_SAFE
- DenseMatrix Jinv(Dim);
+ DenseMatrix Jinv(dim);
#endif
for (int k = 0; k < 36; k++)
@@ -6687,8 +6687,8 @@ void RT0TetFiniteElement::GetLocalInterpolation (
{
int k, j;
#ifdef MFEM_THREAD_SAFE
- DenseMatrix vshape(Dof, Dim);
- DenseMatrix Jinv(Dim);
+ DenseMatrix vshape(dof, dim);
+ DenseMatrix Jinv(dim);
#endif
#ifdef MFEM_DEBUG
@@ -6744,7 +6744,7 @@ void RT0TetFiniteElement::Project (
double vk[3];
Vector xk (vk, 3);
#ifdef MFEM_THREAD_SAFE
- DenseMatrix Jinv(Dim);
+ DenseMatrix Jinv(dim);
#endif
for (int k = 0; k < 4; k++)
@@ -7691,7 +7691,7 @@ H1_SegmentElement::H1_SegmentElement(const int p, const int btype)
void H1_SegmentElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1);
@@ -7710,7 +7710,7 @@ void H1_SegmentElement::CalcShape(const IntegrationPoint &ip,
void H1_SegmentElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), dshape_x(p+1);
@@ -7747,7 +7747,7 @@ void H1_SegmentElement::CalcHessian(const IntegrationPoint &ip,
void H1_SegmentElement::ProjectDelta(int vertex, Vector &dofs) const
{
- const int p = Order;
+ const int p = order;
const double *cp = poly1d.ClosedPoints(p, b_type);
switch (vertex)
@@ -7802,7 +7802,7 @@ H1_QuadrilateralElement::H1_QuadrilateralElement(const int p, const int btype)
void H1_QuadrilateralElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1);
@@ -7821,7 +7821,7 @@ void H1_QuadrilateralElement::CalcShape(const IntegrationPoint &ip,
void H1_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1);
@@ -7866,7 +7866,7 @@ void H1_QuadrilateralElement::CalcHessian(const IntegrationPoint &ip,
void H1_QuadrilateralElement::ProjectDelta(int vertex, Vector &dofs) const
{
- const int p = Order;
+ const int p = order;
const double *cp = poly1d.ClosedPoints(p, b_type);
#ifdef MFEM_THREAD_SAFE
@@ -7944,7 +7944,7 @@ H1_HexahedronElement::H1_HexahedronElement(const int p, const int btype)
void H1_HexahedronElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1), shape_z(p+1);
@@ -7965,7 +7965,7 @@ void H1_HexahedronElement::CalcShape(const IntegrationPoint &ip,
void H1_HexahedronElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1), shape_z(p+1);
@@ -8016,7 +8016,7 @@ void H1_HexahedronElement::CalcHessian(const IntegrationPoint &ip,
void H1_HexahedronElement::ProjectDelta(int vertex, Vector &dofs) const
{
- const int p = Order;
+ const int p = order;
const double *cp = poly1d.ClosedPoints(p,b_type);
#ifdef MFEM_THREAD_SAFE
@@ -8120,7 +8120,7 @@ H1Pos_SegmentElement::H1Pos_SegmentElement(const int p)
void H1Pos_SegmentElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1);
@@ -8140,7 +8140,7 @@ void H1Pos_SegmentElement::CalcShape(const IntegrationPoint &ip,
void H1Pos_SegmentElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), dshape_x(p+1);
@@ -8187,7 +8187,7 @@ H1Pos_QuadrilateralElement::H1Pos_QuadrilateralElement(const int p)
void H1Pos_QuadrilateralElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1);
@@ -8207,7 +8207,7 @@ void H1Pos_QuadrilateralElement::CalcShape(const IntegrationPoint &ip,
void H1Pos_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1);
@@ -8257,7 +8257,7 @@ H1Pos_HexahedronElement::H1Pos_HexahedronElement(const int p)
void H1Pos_HexahedronElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1), shape_z(p+1);
@@ -8278,7 +8278,7 @@ void H1Pos_HexahedronElement::CalcShape(const IntegrationPoint &ip,
void H1Pos_HexahedronElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1), shape_z(p+1);
@@ -8322,9 +8322,9 @@ H1_TriangleElement::H1_TriangleElement(const int p, const int btype)
ddshape_x.SetSize(p + 1);
ddshape_y.SetSize(p + 1);
ddshape_l.SetSize(p + 1);
- u.SetSize(Dof);
- du.SetSize(Dof, Dim);
- ddu.SetSize(Dof, (Dim * (Dim + 1)) / 2 );
+ u.SetSize(dof);
+ du.SetSize(dof, dim);
+ ddu.SetSize(dof, (dim * (dim + 1)) / 2 );
#else
Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1);
#endif
@@ -8357,8 +8357,8 @@ H1_TriangleElement::H1_TriangleElement(const int p, const int btype)
Nodes.IntPoint(o++).Set2(cp[i]/w, cp[j]/w);
}
- DenseMatrix T(Dof);
- for (int k = 0; k < Dof; k++)
+ DenseMatrix T(dof);
+ for (int k = 0; k < dof; k++)
{
IntegrationPoint &ip = Nodes.IntPoint(k);
poly1d.CalcBasis(p, ip.x, shape_x);
@@ -8380,10 +8380,10 @@ H1_TriangleElement::H1_TriangleElement(const int p, const int btype)
void H1_TriangleElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
- Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1), u(Dof);
+ Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1), u(dof);
#endif
poly1d.CalcBasis(p, ip.x, shape_x);
@@ -8402,12 +8402,12 @@ void H1_TriangleElement::CalcShape(const IntegrationPoint &ip,
void H1_TriangleElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1);
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_l(p + 1);
- DenseMatrix du(Dof, Dim);
+ DenseMatrix du(dof, dim);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
@@ -8431,12 +8431,12 @@ void H1_TriangleElement::CalcDShape(const IntegrationPoint &ip,
void H1_TriangleElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &ddshape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1);
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_l(p + 1);
Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_l(p + 1);
- DenseMatrix ddu(Dof, Dim);
+ DenseMatrix ddu(dof, dim);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x);
@@ -8480,9 +8480,9 @@ H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype)
ddshape_y.SetSize(p + 1);
ddshape_z.SetSize(p + 1);
ddshape_l.SetSize(p + 1);
- u.SetSize(Dof);
- du.SetSize(Dof, Dim);
- ddu.SetSize(Dof, (Dim * (Dim + 1)) / 2);
+ u.SetSize(dof);
+ du.SetSize(dof, dim);
+ ddu.SetSize(dof, (dim * (dim + 1)) / 2);
#else
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
#endif
@@ -8555,8 +8555,8 @@ H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype)
Nodes.IntPoint(o++).Set3(cp[i]/w, cp[j]/w, cp[k]/w);
}
- DenseMatrix T(Dof);
- for (int m = 0; m < Dof; m++)
+ DenseMatrix T(dof);
+ for (int m = 0; m < dof; m++)
{
IntegrationPoint &ip = Nodes.IntPoint(m);
poly1d.CalcBasis(p, ip.x, shape_x);
@@ -8580,11 +8580,11 @@ H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype)
void H1_TetrahedronElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
- Vector u(Dof);
+ Vector u(dof);
#endif
poly1d.CalcBasis(p, ip.x, shape_x);
@@ -8605,12 +8605,12 @@ void H1_TetrahedronElement::CalcShape(const IntegrationPoint &ip,
void H1_TetrahedronElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1);
- DenseMatrix du(Dof, Dim);
+ DenseMatrix du(dof, dim);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
@@ -8638,13 +8638,13 @@ void H1_TetrahedronElement::CalcDShape(const IntegrationPoint &ip,
void H1_TetrahedronElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &ddshape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1);
Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_z(p + 1), ddshape_l(p + 1);
- DenseMatrix ddu(Dof, ((Dim + 1) * Dim) / 2);
+ DenseMatrix ddu(dof, ((dim + 1) * dim) / 2);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x);
@@ -8686,11 +8686,11 @@ H1Pos_TriangleElement::H1Pos_TriangleElement(const int p)
FunctionSpace::Pk)
{
#ifndef MFEM_THREAD_SAFE
- m_shape.SetSize(Dof);
+ m_shape.SetSize(dof);
dshape_1d.SetSize(p + 1);
- m_dshape.SetSize(Dof, Dim);
+ m_dshape.SetSize(dof, dim);
#endif
- dof_map.SetSize(Dof);
+ dof_map.SetSize(dof);
struct Index
{
@@ -8799,10 +8799,10 @@ void H1Pos_TriangleElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
#ifdef MFEM_THREAD_SAFE
- Vector m_shape(Dof);
+ Vector m_shape(dof);
#endif
- CalcShape(Order, ip.x, ip.y, m_shape.GetData());
- for (int i = 0; i < Dof; i++)
+ CalcShape(order, ip.x, ip.y, m_shape.GetData());
+ for (int i = 0; i < dof; i++)
{
shape(dof_map[i]) = m_shape(i);
}
@@ -8812,13 +8812,13 @@ void H1Pos_TriangleElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
#ifdef MFEM_THREAD_SAFE
- Vector dshape_1d(Order + 1);
- DenseMatrix m_dshape(Dof, Dim);
+ Vector dshape_1d(order + 1);
+ DenseMatrix m_dshape(dof, dim);
#endif
- CalcDShape(Order, ip.x, ip.y, dshape_1d.GetData(), m_dshape.Data());
+ CalcDShape(order, ip.x, ip.y, dshape_1d.GetData(), m_dshape.Data());
for (int d = 0; d < 2; d++)
{
- for (int i = 0; i < Dof; i++)
+ for (int i = 0; i < dof; i++)
{
dshape(dof_map[i],d) = m_dshape(i,d);
}
@@ -8831,11 +8831,11 @@ H1Pos_TetrahedronElement::H1Pos_TetrahedronElement(const int p)
((p + 1)*(p + 2)*(p + 3))/6, p, FunctionSpace::Pk)
{
#ifndef MFEM_THREAD_SAFE
- m_shape.SetSize(Dof);
+ m_shape.SetSize(dof);
dshape_1d.SetSize(p + 1);
- m_dshape.SetSize(Dof, Dim);
+ m_dshape.SetSize(dof, dim);
#endif
- dof_map.SetSize(Dof);
+ dof_map.SetSize(dof);
struct Index
{
@@ -9051,10 +9051,10 @@ void H1Pos_TetrahedronElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
#ifdef MFEM_THREAD_SAFE
- Vector m_shape(Dof);
+ Vector m_shape(dof);
#endif
- CalcShape(Order, ip.x, ip.y, ip.z, m_shape.GetData());
- for (int i = 0; i < Dof; i++)
+ CalcShape(order, ip.x, ip.y, ip.z, m_shape.GetData());
+ for (int i = 0; i < dof; i++)
{
shape(dof_map[i]) = m_shape(i);
}
@@ -9064,13 +9064,13 @@ void H1Pos_TetrahedronElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
#ifdef MFEM_THREAD_SAFE
- Vector dshape_1d(Order + 1);
- DenseMatrix m_dshape(Dof, Dim);
+ Vector dshape_1d(order + 1);
+ DenseMatrix m_dshape(dof, dim);
#endif
- CalcDShape(Order, ip.x, ip.y, ip.z, dshape_1d.GetData(), m_dshape.Data());
+ CalcDShape(order, ip.x, ip.y, ip.z, dshape_1d.GetData(), m_dshape.Data());
for (int d = 0; d < 3; d++)
{
- for (int i = 0; i < Dof; i++)
+ for (int i = 0; i < dof; i++)
{
dshape(dof_map[i],d) = m_dshape(i,d);
}
@@ -9092,8 +9092,8 @@ H1_WedgeElement::H1_WedgeElement(const int p,
s_dshape.SetSize(SegmentFE.GetDof(), 1);
#endif
- t_dof.SetSize(Dof);
- s_dof.SetSize(Dof);
+ t_dof.SetSize(dof);
+ s_dof.SetSize(dof);
// Nodal DoFs
t_dof[0] = 0; s_dof[0] = 0;
@@ -9170,7 +9170,7 @@ H1_WedgeElement::H1_WedgeElement(const int p,
// Define Nodes
const IntegrationRule & t_Nodes = TriangleFE.GetNodes();
const IntegrationRule & s_Nodes = SegmentFE.GetNodes();
- for (int i=0; i 0) ? poly1d.OpenPoints(p - 1) : NULL;
const double *bop = poly1d.OpenPoints(p);
@@ -10988,8 +10988,8 @@ RT_TriangleElement::RT_TriangleElement(const int p)
dshape_x.SetSize(p + 1);
dshape_y.SetSize(p + 1);
dshape_l.SetSize(p + 1);
- u.SetSize(Dof, Dim);
- divu.SetSize(Dof);
+ u.SetSize(dof, dim);
+ divu.SetSize(dof);
#else
Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1);
#endif
@@ -11023,8 +11023,8 @@ RT_TriangleElement::RT_TriangleElement(const int p)
dof2nk[o++] = 2;
}
- DenseMatrix T(Dof);
- for (int k = 0; k < Dof; k++)
+ DenseMatrix T(dof);
+ for (int k = 0; k < dof; k++)
{
const IntegrationPoint &ip = Nodes.IntPoint(k);
poly1d.CalcBasis(p, ip.x, shape_x);
@@ -11054,11 +11054,11 @@ RT_TriangleElement::RT_TriangleElement(const int p)
void RT_TriangleElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
- const int p = Order - 1;
+ const int p = order - 1;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1);
- DenseMatrix u(Dof, Dim);
+ DenseMatrix u(dof, dim);
#endif
poly1d.CalcBasis(p, ip.x, shape_x);
@@ -11087,12 +11087,12 @@ void RT_TriangleElement::CalcVShape(const IntegrationPoint &ip,
void RT_TriangleElement::CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const
{
- const int p = Order - 1;
+ const int p = order - 1;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1);
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_l(p + 1);
- Vector divu(Dof);
+ Vector divu(dof);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
@@ -11129,7 +11129,7 @@ const double RT_TetrahedronElement::c = 1./4.;
RT_TetrahedronElement::RT_TetrahedronElement(const int p)
: VectorFiniteElement(3, Geometry::TETRAHEDRON, (p + 1)*(p + 2)*(p + 4)/2,
p + 1, H_DIV, FunctionSpace::Pk),
- dof2nk(Dof)
+ dof2nk(dof)
{
const double *iop = (p > 0) ? poly1d.OpenPoints(p - 1) : NULL;
const double *bop = poly1d.OpenPoints(p);
@@ -11143,8 +11143,8 @@ RT_TetrahedronElement::RT_TetrahedronElement(const int p)
dshape_y.SetSize(p + 1);
dshape_z.SetSize(p + 1);
dshape_l.SetSize(p + 1);
- u.SetSize(Dof, Dim);
- divu.SetSize(Dof);
+ u.SetSize(dof, dim);
+ divu.SetSize(dof);
#else
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
#endif
@@ -11195,8 +11195,8 @@ RT_TetrahedronElement::RT_TetrahedronElement(const int p)
dof2nk[o++] = 3;
}
- DenseMatrix T(Dof);
- for (int m = 0; m < Dof; m++)
+ DenseMatrix T(dof);
+ for (int m = 0; m < dof; m++)
{
const IntegrationPoint &ip = Nodes.IntPoint(m);
poly1d.CalcBasis(p, ip.x, shape_x);
@@ -11231,11 +11231,11 @@ RT_TetrahedronElement::RT_TetrahedronElement(const int p)
void RT_TetrahedronElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
- const int p = Order - 1;
+ const int p = order - 1;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
- DenseMatrix u(Dof, Dim);
+ DenseMatrix u(dof, dim);
#endif
poly1d.CalcBasis(p, ip.x, shape_x);
@@ -11267,12 +11267,12 @@ void RT_TetrahedronElement::CalcVShape(const IntegrationPoint &ip,
void RT_TetrahedronElement::CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const
{
- const int p = Order - 1;
+ const int p = order - 1;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1);
- Vector divu(Dof);
+ Vector divu(dof);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
@@ -11314,13 +11314,13 @@ ND_HexahedronElement::ND_HexahedronElement(const int p,
const int cb_type, const int ob_type)
: VectorTensorFiniteElement(3, 3*p*(p + 1)*(p + 1), p, cb_type, ob_type,
H_CURL, DofMapType::L2_DOF_MAP),
- dof2tk(Dof)
+ dof2tk(dof)
{
- dof_map.SetSize(Dof);
+ dof_map.SetSize(dof);
const double *cp = poly1d.ClosedPoints(p, cb_type);
const double *op = poly1d.OpenPoints(p - 1, ob_type);
- const int dof3 = Dof/3;
+ const int dof3 = dof/3;
#ifndef MFEM_THREAD_SAFE
shape_cx.SetSize(p + 1);
@@ -11531,7 +11531,7 @@ ND_HexahedronElement::ND_HexahedronElement(const int p,
void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p);
@@ -11605,7 +11605,7 @@ void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
void ND_HexahedronElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p);
@@ -11711,8 +11711,8 @@ const DofToQuad &VectorTensorFiniteElement::GetTensorDofToQuad(
}
DofToQuad *d2q = new DofToQuad;
- const int ndof = closed ? Order + 1 : Order;
- const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/Dim) + 0.5);
+ const int ndof = closed ? order + 1 : order;
+ const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5);
d2q->FE = this;
d2q->IntRule = &ir;
d2q->mode = mode;
@@ -11772,13 +11772,13 @@ ND_QuadrilateralElement::ND_QuadrilateralElement(const int p,
const int ob_type)
: VectorTensorFiniteElement(2, 2*p*(p + 1), p, cb_type, ob_type,
H_CURL, DofMapType::L2_DOF_MAP),
- dof2tk(Dof)
+ dof2tk(dof)
{
- dof_map.SetSize(Dof);
+ dof_map.SetSize(dof);
const double *cp = poly1d.ClosedPoints(p, cb_type);
const double *op = poly1d.OpenPoints(p - 1, ob_type);
- const int dof2 = Dof/2;
+ const int dof2 = dof/2;
#ifndef MFEM_THREAD_SAFE
shape_cx.SetSize(p + 1);
@@ -11859,7 +11859,7 @@ ND_QuadrilateralElement::ND_QuadrilateralElement(const int p,
void ND_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p);
@@ -11908,7 +11908,7 @@ void ND_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip,
void ND_QuadrilateralElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const
{
- const int p = Order;
+ const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p);
@@ -11961,7 +11961,7 @@ const double ND_TetrahedronElement::c = 1./4.;
ND_TetrahedronElement::ND_TetrahedronElement(const int p)
: VectorFiniteElement(3, Geometry::TETRAHEDRON, p*(p + 2)*(p + 3)/2, p,
- H_CURL, FunctionSpace::Pk), dof2tk(Dof)
+ H_CURL, FunctionSpace::Pk), dof2tk(dof)
{
const double *eop = poly1d.OpenPoints(p - 1);
const double *fop = (p > 1) ? poly1d.OpenPoints(p - 2) : NULL;
@@ -11978,7 +11978,7 @@ ND_TetrahedronElement::ND_TetrahedronElement(const int p)
dshape_y.SetSize(p);
dshape_z.SetSize(p);
dshape_l.SetSize(p);
- u.SetSize(Dof, Dim);
+ u.SetSize(dof, dim);
#else
Vector shape_x(p), shape_y(p), shape_z(p), shape_l(p);
#endif
@@ -12068,8 +12068,8 @@ ND_TetrahedronElement::ND_TetrahedronElement(const int p)
dof2tk[o++] = 2;
}
- DenseMatrix T(Dof);
- for (int m = 0; m < Dof; m++)
+ DenseMatrix T(dof);
+ for (int m = 0; m < dof; m++)
{
const IntegrationPoint &ip = Nodes.IntPoint(m);
const double *tm = tk + 3*dof2tk[m];
@@ -12110,12 +12110,12 @@ ND_TetrahedronElement::ND_TetrahedronElement(const int p)
void ND_TetrahedronElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
- const int pm1 = Order - 1;
+ const int pm1 = order - 1;
#ifdef MFEM_THREAD_SAFE
- const int p = Order;
+ const int p = order;
Vector shape_x(p), shape_y(p), shape_z(p), shape_l(p);
- DenseMatrix u(Dof, Dim);
+ DenseMatrix u(dof, dim);
#endif
poly1d.CalcBasis(pm1, ip.x, shape_x);
@@ -12152,13 +12152,13 @@ void ND_TetrahedronElement::CalcVShape(const IntegrationPoint &ip,
void ND_TetrahedronElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const
{
- const int pm1 = Order - 1;
+ const int pm1 = order - 1;
#ifdef MFEM_THREAD_SAFE
- const int p = Order;
+ const int p = order;
Vector shape_x(p), shape_y(p), shape_z(p), shape_l(p);
Vector dshape_x(p), dshape_y(p), dshape_z(p), dshape_l(p);
- DenseMatrix u(Dof, Dim);
+ DenseMatrix u(dof, dim);
#endif
poly1d.CalcBasis(pm1, ip.x, shape_x, dshape_x);
@@ -12224,7 +12224,7 @@ const double ND_TriangleElement::c = 1./3.;
ND_TriangleElement::ND_TriangleElement(const int p)
: VectorFiniteElement(2, Geometry::TRIANGLE, p*(p + 2), p,
H_CURL, FunctionSpace::Pk),
- dof2tk(Dof)
+ dof2tk(dof)
{
const double *eop = poly1d.OpenPoints(p - 1);
const double *iop = (p > 1) ? poly1d.OpenPoints(p - 2) : NULL;
@@ -12238,8 +12238,8 @@ ND_TriangleElement::ND_TriangleElement(const int p)
dshape_x.SetSize(p);
dshape_y.SetSize(p);
dshape_l.SetSize(p);
- u.SetSize(Dof, Dim);
- curlu.SetSize(Dof);
+ u.SetSize(dof, dim);
+ curlu.SetSize(dof);
#else
Vector shape_x(p), shape_y(p), shape_l(p);
#endif
@@ -12273,8 +12273,8 @@ ND_TriangleElement::ND_TriangleElement(const int p)
dof2tk[n++] = 3;
}
- DenseMatrix T(Dof);
- for (int m = 0; m < Dof; m++)
+ DenseMatrix T(dof);
+ for (int m = 0; m < dof; m++)
{
const IntegrationPoint &ip = Nodes.IntPoint(m);
const double *tm = tk + 2*dof2tk[m];
@@ -12305,12 +12305,12 @@ ND_TriangleElement::ND_TriangleElement(const int p)
void ND_TriangleElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
- const int pm1 = Order - 1;
+ const int pm1 = order - 1;
#ifdef MFEM_THREAD_SAFE
- const int p = Order;
+ const int p = order;
Vector shape_x(p), shape_y(p), shape_l(p);
- DenseMatrix u(Dof, Dim);
+ DenseMatrix u(dof, dim);
#endif
poly1d.CalcBasis(pm1, ip.x, shape_x);
@@ -12339,13 +12339,13 @@ void ND_TriangleElement::CalcVShape(const IntegrationPoint &ip,
void ND_TriangleElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const
{
- const int pm1 = Order - 1;
+ const int pm1 = order - 1;
#ifdef MFEM_THREAD_SAFE
- const int p = Order;
+ const int p = order;
Vector shape_x(p), shape_y(p), shape_l(p);
Vector dshape_x(p), dshape_y(p), dshape_l(p);
- Vector curlu(Dof);
+ Vector curlu(dof);
#endif
poly1d.CalcBasis(pm1, ip.x, shape_x, dshape_x);
@@ -12374,7 +12374,7 @@ void ND_TriangleElement::CalcCurlShape(const IntegrationPoint &ip,
(dshape_y(j)*(ip.y - c) + shape_y(j)) * shape_x(i));
}
- Vector curl2d(curl_shape.Data(),Dof);
+ Vector curl2d(curl_shape.Data(),dof);
Ti.Mult(curlu, curl2d);
}
@@ -12385,7 +12385,7 @@ ND_SegmentElement::ND_SegmentElement(const int p, const int ob_type)
: VectorFiniteElement(1, Geometry::SEGMENT, p, p - 1,
H_CURL, FunctionSpace::Pk),
obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(ob_type))),
- dof2tk(Dof)
+ dof2tk(dof)
{
const double *op = poly1d.OpenPoints(p - 1, ob_type);
@@ -12400,18 +12400,18 @@ ND_SegmentElement::ND_SegmentElement(const int p, const int ob_type)
void ND_SegmentElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
- Vector vshape(shape.Data(), Dof);
+ Vector vshape(shape.Data(), dof);
obasis1d.Eval(ip.x, vshape);
}
void NURBS1DFiniteElement::SetOrder() const
{
- Order = kv[0]->GetOrder();
- Dof = Order + 1;
+ order = kv[0]->GetOrder();
+ dof = order + 1;
- weights.SetSize(Dof);
- shape_x.SetSize(Dof);
+ weights.SetSize(dof);
+ shape_x.SetSize(dof);
}
void NURBS1DFiniteElement::CalcShape(const IntegrationPoint &ip,
@@ -12420,7 +12420,7 @@ void NURBS1DFiniteElement::CalcShape(const IntegrationPoint &ip,
kv[0]->CalcShape(shape, ijk[0], ip.x);
double sum = 0.0;
- for (int i = 0; i <= Order; i++)
+ for (int i = 0; i <= order; i++)
{
sum += (shape(i) *= weights(i));
}
@@ -12431,13 +12431,13 @@ void NURBS1DFiniteElement::CalcShape(const IntegrationPoint &ip,
void NURBS1DFiniteElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
- Vector grad(dshape.Data(), Dof);
+ Vector grad(dshape.Data(), dof);
kv[0]->CalcShape (shape_x, ijk[0], ip.x);
kv[0]->CalcDShape(grad, ijk[0], ip.x);
double sum = 0.0, dsum = 0.0;
- for (int i = 0; i <= Order; i++)
+ for (int i = 0; i <= order; i++)
{
sum += (shape_x(i) *= weights(i));
dsum += ( grad(i) *= weights(i));
@@ -12450,15 +12450,15 @@ void NURBS1DFiniteElement::CalcDShape(const IntegrationPoint &ip,
void NURBS1DFiniteElement::CalcHessian (const IntegrationPoint &ip,
DenseMatrix &hessian) const
{
- Vector grad(Dof);
- Vector hess(hessian.Data(), Dof);
+ Vector grad(dof);
+ Vector hess(hessian.Data(), dof);
kv[0]->CalcShape (shape_x, ijk[0], ip.x);
kv[0]->CalcDShape(grad, ijk[0], ip.x);
kv[0]->CalcD2Shape(hess, ijk[0], ip.x);
double sum = 0.0, dsum = 0.0, d2sum = 0.0;
- for (int i = 0; i <= Order; i++)
+ for (int i = 0; i <= order; i++)
{
sum += (shape_x(i) *= weights(i));
dsum += ( grad(i) *= weights(i));
@@ -12473,20 +12473,20 @@ void NURBS1DFiniteElement::CalcHessian (const IntegrationPoint &ip,
void NURBS2DFiniteElement::SetOrder() const
{
- Orders[0] = kv[0]->GetOrder();
- Orders[1] = kv[1]->GetOrder();
- shape_x.SetSize(Orders[0]+1);
- shape_y.SetSize(Orders[1]+1);
- dshape_x.SetSize(Orders[0]+1);
- dshape_y.SetSize(Orders[1]+1);
- d2shape_x.SetSize(Orders[0]+1);
- d2shape_y.SetSize(Orders[1]+1);
+ orders[0] = kv[0]->GetOrder();
+ orders[1] = kv[1]->GetOrder();
+ shape_x.SetSize(orders[0]+1);
+ shape_y.SetSize(orders[1]+1);
+ dshape_x.SetSize(orders[0]+1);
+ dshape_y.SetSize(orders[1]+1);
+ d2shape_x.SetSize(orders[0]+1);
+ d2shape_y.SetSize(orders[1]+1);
- Order = max(Orders[0], Orders[1]);
- Dof = (Orders[0] + 1)*(Orders[1] + 1);
- u.SetSize(Dof);
- du.SetSize(Dof);
- weights.SetSize(Dof);
+ order = max(orders[0], orders[1]);
+ dof = (orders[0] + 1)*(orders[1] + 1);
+ u.SetSize(dof);
+ du.SetSize(dof);
+ weights.SetSize(dof);
}
void NURBS2DFiniteElement::CalcShape(const IntegrationPoint &ip,
@@ -12496,10 +12496,10 @@ void NURBS2DFiniteElement::CalcShape(const IntegrationPoint &ip,
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
double sum = 0.0;
- for (int o = 0, j = 0; j <= Orders[1]; j++)
+ for (int o = 0, j = 0; j <= orders[1]; j++)
{
const double sy = shape_y(j);
- for (int i = 0; i <= Orders[0]; i++, o++)
+ for (int i = 0; i <= orders[0]; i++, o++)
{
sum += ( shape(o) = shape_x(i)*sy*weights(o) );
}
@@ -12520,10 +12520,10 @@ void NURBS2DFiniteElement::CalcDShape(const IntegrationPoint &ip,
kv[1]->CalcDShape(dshape_y, ijk[1], ip.y);
sum = dsum[0] = dsum[1] = 0.0;
- for (int o = 0, j = 0; j <= Orders[1]; j++)
+ for (int o = 0, j = 0; j <= orders[1]; j++)
{
const double sy = shape_y(j), dsy = dshape_y(j);
- for (int i = 0; i <= Orders[0]; i++, o++)
+ for (int i = 0; i <= orders[0]; i++, o++)
{
sum += ( u(o) = shape_x(i)*sy*weights(o) );
@@ -12536,7 +12536,7 @@ void NURBS2DFiniteElement::CalcDShape(const IntegrationPoint &ip,
dsum[0] *= sum*sum;
dsum[1] *= sum*sum;
- for (int o = 0; o < Dof; o++)
+ for (int o = 0; o < dof; o++)
{
dshape(o,0) = dshape(o,0)*sum - u(o)*dsum[0];
dshape(o,1) = dshape(o,1)*sum - u(o)*dsum[1];
@@ -12559,10 +12559,10 @@ void NURBS2DFiniteElement::CalcHessian (const IntegrationPoint &ip,
sum = dsum[0] = dsum[1] = 0.0;
d2sum[0] = d2sum[1] = d2sum[2] = 0.0;
- for (int o = 0, j = 0; j <= Orders[1]; j++)
+ for (int o = 0, j = 0; j <= orders[1]; j++)
{
const double sy = shape_y(j), dsy = dshape_y(j), d2sy = d2shape_y(j);
- for (int i = 0; i <= Orders[0]; i++, o++)
+ for (int i = 0; i <= orders[0]; i++, o++)
{
const double sx = shape_x(i), dsx = dshape_x(i), d2sx = d2shape_x(i);
sum += ( u(o) = sx*sy*weights(o) );
@@ -12584,7 +12584,7 @@ void NURBS2DFiniteElement::CalcHessian (const IntegrationPoint &ip,
d2sum[1] *= sum;
d2sum[2] *= sum;
- for (int o = 0; o < Dof; o++)
+ for (int o = 0; o < dof; o++)
{
hessian(o,0) = hessian(o,0)*sum
- 2*du(o,0)*sum*dsum[0]
@@ -12604,26 +12604,26 @@ void NURBS2DFiniteElement::CalcHessian (const IntegrationPoint &ip,
void NURBS3DFiniteElement::SetOrder() const
{
- Orders[0] = kv[0]->GetOrder();
- Orders[1] = kv[1]->GetOrder();
- Orders[2] = kv[2]->GetOrder();
- shape_x.SetSize(Orders[0]+1);
- shape_y.SetSize(Orders[1]+1);
- shape_z.SetSize(Orders[2]+1);
+ orders[0] = kv[0]->GetOrder();
+ orders[1] = kv[1]->GetOrder();
+ orders[2] = kv[2]->GetOrder();
+ shape_x.SetSize(orders[0]+1);
+ shape_y.SetSize(orders[1]+1);
+ shape_z.SetSize(orders[2]+1);
- dshape_x.SetSize(Orders[0]+1);
- dshape_y.SetSize(Orders[1]+1);
- dshape_z.SetSize(Orders[2]+1);
+ dshape_x.SetSize(orders[0]+1);
+ dshape_y.SetSize(orders[1]+1);
+ dshape_z.SetSize(orders[2]+1);
- d2shape_x.SetSize(Orders[0]+1);
- d2shape_y.SetSize(Orders[1]+1);
- d2shape_z.SetSize(Orders[2]+1);
+ d2shape_x.SetSize(orders[0]+1);
+ d2shape_y.SetSize(orders[1]+1);
+ d2shape_z.SetSize(orders[2]+1);
- Order = max(max(Orders[0], Orders[1]), Orders[2]);
- Dof = (Orders[0] + 1)*(Orders[1] + 1)*(Orders[2] + 1);
- u.SetSize(Dof);
- du.SetSize(Dof);
- weights.SetSize(Dof);
+ order = max(max(orders[0], orders[1]), orders[2]);
+ dof = (orders[0] + 1)*(orders[1] + 1)*(orders[2] + 1);
+ u.SetSize(dof);
+ du.SetSize(dof);
+ weights.SetSize(dof);
}
void NURBS3DFiniteElement::CalcShape(const IntegrationPoint &ip,
@@ -12634,13 +12634,13 @@ void NURBS3DFiniteElement::CalcShape(const IntegrationPoint &ip,
kv[2]->CalcShape(shape_z, ijk[2], ip.z);
double sum = 0.0;
- for (int o = 0, k = 0; k <= Orders[2]; k++)
+ for (int o = 0, k = 0; k <= orders[2]; k++)
{
const double sz = shape_z(k);
- for (int j = 0; j <= Orders[1]; j++)
+ for (int j = 0; j <= orders[1]; j++)
{
const double sy_sz = shape_y(j)*sz;
- for (int i = 0; i <= Orders[0]; i++, o++)
+ for (int i = 0; i <= orders[0]; i++, o++)
{
sum += ( shape(o) = shape_x(i)*sy_sz*weights(o) );
}
@@ -12664,15 +12664,15 @@ void NURBS3DFiniteElement::CalcDShape(const IntegrationPoint &ip,
kv[2]->CalcDShape(dshape_z, ijk[2], ip.z);
sum = dsum[0] = dsum[1] = dsum[2] = 0.0;
- for (int o = 0, k = 0; k <= Orders[2]; k++)
+ for (int o = 0, k = 0; k <= orders[2]; k++)
{
const double sz = shape_z(k), dsz = dshape_z(k);
- for (int j = 0; j <= Orders[1]; j++)
+ for (int j = 0; j <= orders[1]; j++)
{
const double sy_sz = shape_y(j)* sz;
const double dsy_sz = dshape_y(j)* sz;
const double sy_dsz = shape_y(j)*dsz;
- for (int i = 0; i <= Orders[0]; i++, o++)
+ for (int i = 0; i <= orders[0]; i++, o++)
{
sum += ( u(o) = shape_x(i)*sy_sz*weights(o) );
@@ -12688,7 +12688,7 @@ void NURBS3DFiniteElement::CalcDShape(const IntegrationPoint &ip,
dsum[1] *= sum*sum;
dsum[2] *= sum*sum;
- for (int o = 0; o < Dof; o++)
+ for (int o = 0; o < dof; o++)
{
dshape(o,0) = dshape(o,0)*sum - u(o)*dsum[0];
dshape(o,1) = dshape(o,1)*sum - u(o)*dsum[1];
@@ -12716,13 +12716,13 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip,
sum = dsum[0] = dsum[1] = dsum[2] = 0.0;
d2sum[0] = d2sum[1] = d2sum[2] = d2sum[3] = d2sum[4] = d2sum[5] = 0.0;
- for (int o = 0, k = 0; k <= Orders[2]; k++)
+ for (int o = 0, k = 0; k <= orders[2]; k++)
{
const double sz = shape_z(k), dsz = dshape_z(k), d2sz = d2shape_z(k);
- for (int j = 0; j <= Orders[1]; j++)
+ for (int j = 0; j <= orders[1]; j++)
{
const double sy = shape_y(j), dsy = dshape_y(j), d2sy = d2shape_y(j);
- for (int i = 0; i <= Orders[0]; i++, o++)
+ for (int i = 0; i <= orders[0]; i++, o++)
{
const double sx = shape_x(i), dsx = dshape_x(i), d2sx = d2shape_x(i);
sum += ( u(o) = sx*sy*sz*weights(o) );
@@ -12756,7 +12756,7 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip,
d2sum[4] *= sum;
d2sum[5] *= sum;
- for (int o = 0; o < Dof; o++)
+ for (int o = 0; o < dof; o++)
{
hessian(o,0) = hessian(o,0)*sum
- 2*du(o,0)*sum*dsum[0]
diff --git a/fem/fe.hpp b/fem/fe.hpp
index 9262ad3a35..6468561938 100644
--- a/fem/fe.hpp
+++ b/fem/fe.hpp
@@ -206,7 +206,7 @@ public:
};
-/// Describes the space on each element
+/// Describes the function space on each element
class FunctionSpace
{
public:
@@ -228,18 +228,18 @@ class KnotVector;
// Base and derived classes for finite elements
-/// Abstract class for Finite Elements
+/// Abstract class for all finite elements.
class FiniteElement
{
protected:
- int Dim; ///< Dimension of reference space
- Geometry::Type GeomType; ///< Geometry::Type of the reference element
- int FuncSpace, RangeType, MapType,
- DerivType, DerivRangeType, DerivMapType;
+ int dim; ///< Dimension of reference space
+ Geometry::Type geom_type; ///< Geometry::Type of the reference element
+ int func_space, range_type, map_type,
+ deriv_type, deriv_range_type, deriv_map_type;
mutable
- int Dof, ///< Number of degrees of freedom
- Order; ///< Order/degree of the shape functions
- mutable int Orders[Geometry::MaxDim]; ///< Anisotropic orders
+ int dof, ///< Number of degrees of freedom
+ order; ///< Order/degree of the shape functions
+ mutable int orders[Geometry::MaxDim]; ///< Anisotropic orders
IntegrationRule Nodes;
#ifndef MFEM_THREAD_SAFE
mutable DenseMatrix vshape; // Dof x Dim
@@ -250,51 +250,49 @@ protected:
mutable Array dof2quad_array;
public:
- /// Enumeration for RangeType and DerivRangeType
- enum { SCALAR, VECTOR };
+ /// Enumeration for range_type and deriv_range_type
+ enum RangeType { SCALAR, VECTOR };
/** @brief Enumeration for MapType: defines how reference functions are
mapped to physical space.
- A reference function, `uh(xh)`, can be mapped to a function, `u(x)`, on a
- general physical element in following ways:
-
- VALUE u(x) = uh(xh)
- INTEGRAL u(x) = (1/w) * uh(xh)
- H_DIV u(x) = (J/w) * uh(xh)
- H_CURL u(x) = J^{-t} * uh(xh) (square J)
- H_CURL u(x) = J*(J^t*J)^{-1} * uh(xh) (general J)
-
- where
-
- x = T(xh) is the image of the reference point xh ("x hat"),
- J = J(xh) is the Jacobian matrix of the transformation T, and
- w = w(xh) = / det(J), for square J,
- \ det(J^t*J)^{1/2}, for general J,
- is the transformation weight factor.
+ A reference function \f$ \hat u(\hat x) \f$ can be mapped to a function
+ \f$ u(x) \f$ on a general physical element in following ways:
+ - \f$ x = T(\hat x) \f$ is the image of the reference point \f$ \hat x \f$
+ - \f$ J = J(\hat x) \f$ is the Jacobian matrix of the transformation T
+ - \f$ w = w(\hat x) = det(J) \f$ is the transformation weight factor for square J
+ - \f$ w = w(\hat x) = det(J^t J)^{1/2} \f$ is the transformation weight factor in general
*/
- enum { VALUE, ///< For scalar fields; preserves point values
- INTEGRAL, ///< For scalar fields; preserves volume integrals
- H_DIV, /**< For vector fields; preserves surface integrals of the
- normal component */
- H_CURL /**< For vector fields; preserves line integrals of the
- tangential component */
- };
+ enum MapType
+ {
+ VALUE, /**< For scalar fields; preserves point values
+ \f$ u(x) = \hat u(\hat x) \f$ */
+ INTEGRAL, /**< For scalar fields; preserves volume integrals
+ \f$ u(x) = (1/w) \hat u(\hat x) \f$ */
+ H_DIV, /**< For vector fields; preserves surface integrals of the
+ normal component \f$ u(x) = (J/w) \hat u(\hat x) \f$ */
+ H_CURL /**< For vector fields; preserves line integrals of the
+ tangential component
+ \f$ u(x) = J^{-t} \hat u(\hat x) \f$ (square J),
+ \f$ u(x) = J(J^t J)^{-1} \hat u(\hat x) \f$ (general J) */
+ };
/** @brief Enumeration for DerivType: defines which derivative method
is implemented.
- Each FiniteElement class implements only one type of derivative. The
+ Each FiniteElement class implements up to one type of derivative. The
value returned by GetDerivType() indicates which derivative method is
implemented.
*/
- enum { NONE, ///< No derivatives implemented
- GRAD, ///< Implements CalcDShape methods
- DIV, ///< Implements CalcDivShape methods
- CURL ///< Implements CalcCurlShape methods
- };
+ enum DerivType
+ {
+ NONE, ///< No derivatives implemented
+ GRAD, ///< Implements CalcDShape methods
+ DIV, ///< Implements CalcDivShape methods
+ CURL ///< Implements CalcCurlShape methods
+ };
- /** Construct FiniteElement with given
+ /** @brief Construct FiniteElement with given
@param D Reference space dimension
@param G Geometry type (of type Geometry::Type)
@param Do Number of degrees of freedom in the FiniteElement
@@ -305,53 +303,66 @@ public:
int F = FunctionSpace::Pk);
/// Returns the reference space dimension for the finite element
- int GetDim() const { return Dim; }
+ int GetDim() const { return dim; }
/// Returns the Geometry::Type of the reference element
- Geometry::Type GetGeomType() const { return GeomType; }
+ Geometry::Type GetGeomType() const { return geom_type; }
/// Returns the number of degrees of freedom in the finite element
- int GetDof() const { return Dof; }
+ int GetDof() const { return dof; }
/** @brief Returns the order of the finite element. In the case of
anisotropic orders, returns the maximum order. */
- int GetOrder() const { return Order; }
+ int GetOrder() const { return order; }
/** @brief Returns true if the FiniteElement basis *may be using* different
orders/degrees in different spatial directions. */
- bool HasAnisotropicOrders() const { return Orders[0] != -1; }
+ bool HasAnisotropicOrders() const { return orders[0] != -1; }
/// Returns an array containing the anisotropic orders/degrees.
- const int *GetAnisotropicOrders() const { return Orders; }
+ const int *GetAnisotropicOrders() const { return orders; }
- /// Returns the type of space on each element
- int Space() const { return FuncSpace; }
+ /// Returns the type of FunctionSpace on the element.
+ int Space() const { return func_space; }
- int GetRangeType() const { return RangeType; }
+ /// Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}.
+ int GetRangeType() const { return range_type; }
- int GetDerivRangeType() const { return DerivRangeType; }
+ /** @brief Returns the FiniteElement::RangeType of the element derivative, either
+ SCALAR or VECTOR. */
+ int GetDerivRangeType() const { return deriv_range_type; }
- int GetMapType() const { return MapType; }
+ /** @brief Returns the FiniteElement::MapType of the element describing how reference
+ functions are mapped to physical space, one of {VALUE, INTEGRAL
+ H_DIV, H_CURL}. */
+ int GetMapType() const { return map_type; }
- int GetDerivType() const { return DerivType; }
- int GetDerivMapType() const { return DerivMapType; }
+ /** @brief Returns the FiniteElement::DerivType of the element describing the
+ spatial derivative method implemented, one of {NONE, GRAD,
+ DIV, CURL}. */
+ int GetDerivType() const { return deriv_type; }
+
+ /** @brief Returns the FiniteElement::DerivType of the element describing how
+ reference function derivatives are mapped to physical space, one of {VALUE,
+ INTEGRAL, H_DIV, H_CURL}. */
+ int GetDerivMapType() const { return deriv_map_type; }
/** @brief Evaluate the values of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
- /** The size (#Dof) of the result Vector @a shape must be set in advance. */
+ /** The size (#dof) of the result Vector @a shape must be set in advance. */
virtual void CalcShape(const IntegrationPoint &ip,
Vector &shape) const = 0;
/** @brief Evaluate the values of all shape functions of a scalar finite
element in physical space at the point described by @a Trans. */
- /** The size (#Dof) of the result Vector @a shape must be set in advance. */
+ /** The size (#dof) of the result Vector @a shape must be set in advance. */
void CalcPhysShape(ElementTransformation &Trans, Vector &shape) const;
/** @brief Evaluate the gradients of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a dshape contains the derivatives of
- one shape function. The size (#Dof x #Dim) of @a dshape must be set in
+ one shape function. The size (#dof x #dim) of @a dshape must be set in
advance. */
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const = 0;
@@ -359,11 +370,12 @@ public:
/** @brief Evaluate the gradients of all shape functions of a scalar finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a dshape contains the derivatives of
- one shape function. The size (#Dof x SDim) of @a dshape must be set in
- advance, where SDim >= #Dim is the physical space dimension as described
+ one shape function. The size (#dof x SDim) of @a dshape must be set in
+ advance, where SDim >= #dim is the physical space dimension as described
by @a Trans. */
void CalcPhysDShape(ElementTransformation &Trans, DenseMatrix &dshape) const;
+ /// Get a const reference to the nodes of the element
const IntegrationRule & GetNodes() const { return Nodes; }
// virtual functions for finite elements on vector spaces
@@ -371,7 +383,7 @@ public:
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a shape contains the components of
- one vector shape function. The size (#Dof x #Dim) of @a shape must be set
+ one vector shape function. The size (#dof x #dim) of @a shape must be set
in advance. */
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
@@ -379,8 +391,8 @@ public:
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
- one vector shape function. The size (#Dof x SDim) of @a shape must be set
- in advance, where SDim >= #Dim is the physical space dimension as
+ one vector shape function. The size (#dof x SDim) of @a shape must be set
+ in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
@@ -391,35 +403,39 @@ public:
/** @brief Evaluate the divergence of all shape functions of a *vector*
finite element in reference space at the given point @a ip. */
- /** The size (#Dof) of the result Vector @a divshape must be set in advance.
+ /** The size (#dof) of the result Vector @a divshape must be set in advance.
*/
virtual void CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const;
/** @brief Evaluate the divergence of all shape functions of a *vector*
finite element in physical space at the point described by @a Trans. */
- /** The size (#Dof) of the result Vector @a divshape must be set in advance.
+ /** The size (#dof) of the result Vector @a divshape must be set in advance.
*/
void CalcPhysDivShape(ElementTransformation &Trans, Vector &divshape) const;
/** @brief Evaluate the curl of all shape functions of a *vector* finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a curl_shape contains the components
- of the curl of one vector shape function. The size (#Dof x CDim) of
- @a curl_shape must be set in advance, where CDim = 3 for #Dim = 3 and
- CDim = 1 for #Dim = 2. */
+ of the curl of one vector shape function. The size (#dof x CDim) of
+ @a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
+ CDim = 1 for #dim = 2. */
virtual void CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const;
/** @brief Evaluate the curl of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a curl_shape contains the components
- of the curl of one vector shape function. The size (#Dof x CDim) of
- @a curl_shape must be set in advance, where CDim = 3 for #Dim = 3 and
- CDim = 1 for #Dim = 2. */
+ of the curl of one vector shape function. The size (#dof x CDim) of
+ @a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
+ CDim = 1 for #dim = 2. */
void CalcPhysCurlShape(ElementTransformation &Trans,
DenseMatrix &curl_shape) const;
+ /** @brief Get the dofs associated with the given @a face.
+ @a *dofs is set to an internal array of the local dofc on the
+ face, while *ndofs is set to the number of dofs on that face.
+ */
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
/** @brief Evaluate the Hessians of all shape functions of a scalar finite
@@ -427,19 +443,19 @@ public:
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
part of the Hessian of one shape function.
The order in 2D is {u_xx, u_xy, u_yy}.
- The size (#Dof x (#Dim (#Dim+1)/2) of @a Hessian must be set in advance.*/
+ The size (#dof x (#dim (#dim-1)/2) of @a Hessian must be set in advance.*/
virtual void CalcHessian (const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
- /** The size (#Dof, #Dim*(#Dim+1)/2) of @a Hessian must be set in advance. */
+ /** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
virtual void CalcPhysHessian(ElementTransformation &Trans,
DenseMatrix& Hessian) const;
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
- /** The size (#Dof) of @a Laplacian must be set in advance. */
+ /** The size (#dof) of @a Laplacian must be set in advance. */
virtual void CalcPhysLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
@@ -477,69 +493,71 @@ public:
allowing the "coarse" FiniteElement to be different from the "fine"
FiniteElement as when h-refinement is combined with p-refinement or
p-derefinement. It is assumed that both finite elements use the same
- MapType. */
+ FiniteElement::MapType. */
virtual void GetTransferMatrix(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &I) const;
- /** Given a coefficient and a transformation, compute its projection
+ /** @brief Given a coefficient and a transformation, compute its projection
(approximation) in the local finite dimensional space in terms
of the degrees of freedom. */
virtual void Project (Coefficient &coeff,
ElementTransformation &Trans, Vector &dofs) const;
- /** Given a vector coefficient and a transformation, compute its
+ /** @brief Given a vector coefficient and a transformation, compute its
projection (approximation) in the local finite dimensional space
in terms of the degrees of freedom. (VectorFiniteElements) */
virtual void Project (VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const;
- /** Given a matrix coefficient and a transformation, compute an approximation
- ("projection") in the local finite dimensional space in terms of the
- degrees of freedom. For VectorFiniteElements, the rows of the coefficient
- are projected in the vector space. */
+ /** @brief Given a matrix coefficient and a transformation, compute an
+ approximation ("projection") in the local finite dimensional space in
+ terms of the degrees of freedom. For VectorFiniteElements, the rows of
+ the coefficient are projected in the vector space. */
virtual void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
- /** Compute a representation (up to multiplicative constant) for
- the delta function at the vertex with the given index. */
+ /** @brief Project a delta function centered on the given @a vertex in
+ the local finite dimensional space represented by the @a dofs. */
virtual void ProjectDelta(int vertex, Vector &dofs) const;
- /** Compute the embedding/projection matrix from the given FiniteElement
- onto 'this' FiniteElement. The ElementTransformation is included to
- support cases when the projection depends on it. */
+ /** @brief Compute the embedding/projection matrix from the given
+ FiniteElement onto 'this' FiniteElement. The ElementTransformation is
+ included to support cases when the projection depends on it. */
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
DenseMatrix &I) const;
- /** Compute the discrete gradient matrix from the given FiniteElement onto
- 'this' FiniteElement. The ElementTransformation is included to support
- cases when the matrix depends on it. */
+ /** @brief Compute the discrete gradient matrix from the given FiniteElement
+ onto 'this' FiniteElement. The ElementTransformation is included to
+ support cases when the matrix depends on it. */
virtual void ProjectGrad(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &grad) const;
- /** Compute the discrete curl matrix from the given FiniteElement onto
+ /** @brief Compute the discrete curl matrix from the given FiniteElement onto
'this' FiniteElement. The ElementTransformation is included to support
cases when the matrix depends on it. */
virtual void ProjectCurl(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &curl) const;
- /** Compute the discrete divergence matrix from the given FiniteElement onto
- 'this' FiniteElement. The ElementTransformation is included to support
- cases when the matrix depends on it. */
+ /** @brief Compute the discrete divergence matrix from the given
+ FiniteElement onto 'this' FiniteElement. The ElementTransformation is
+ included to support cases when the matrix depends on it. */
virtual void ProjectDiv(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &div) const;
- /** Return a DofToQuad structure corresponding to the given IntegrationRule
- using the given DofToQuad::Mode. */
+ /** @brief Return a DofToQuad structure corresponding to the given
+ IntegrationRule using the given DofToQuad::Mode. */
/** See the documentation for DofToQuad for more details. */
virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode) const;
-
+ /// Deconstruct the FiniteElement
virtual ~FiniteElement();
+ /** @brief Return true if the BasisType of @a b_type is closed
+ (has Quadrature1D points on the boundary). */
static bool IsClosedType(int b_type)
{
const int q_type = BasisType::GetQuadrature1D(b_type);
@@ -547,6 +565,8 @@ public:
(Quadrature1D::CheckClosed(q_type) != Quadrature1D::Invalid));
}
+ /** @brief Return true if the BasisType of @a b_type is open
+ (doesn't have Quadrature1D points on the boundary). */
static bool IsOpenType(int b_type)
{
const int q_type = BasisType::GetQuadrature1D(b_type);
@@ -554,23 +574,34 @@ public:
(Quadrature1D::CheckOpen(q_type) != Quadrature1D::Invalid));
}
+ /** @brief Ensure that the BasisType of @a b_type is closed
+ (has Quadrature1D points on the boundary). */
static int VerifyClosed(int b_type)
{
MFEM_VERIFY(IsClosedType(b_type),
"invalid closed basis type: " << b_type);
return b_type;
}
+
+ /** @brief Ensure that the BasisType of @a b_type is open
+ (doesn't have Quadrature1D points on the boundary). */
static int VerifyOpen(int b_type)
{
MFEM_VERIFY(IsOpenType(b_type), "invalid open basis type: " << b_type);
return b_type;
}
+
+ /** @brief Ensure that the BasisType of @a b_type nodal
+ (satisfies the interpolation property). */
static int VerifyNodal(int b_type)
{
return BasisType::CheckNodal(b_type);
}
};
+
+/** @brief Class for finite elements with basis functions
+ that return scalar values. */
class ScalarFiniteElement : public FiniteElement
{
protected:
@@ -590,29 +621,42 @@ protected:
DofToQuad::Mode mode) const;
public:
+ /** @brief Construct ScalarFiniteElement with given
+ @param D Reference space dimension
+ @param G Geometry type (of type Geometry::Type)
+ @param Do Number of degrees of freedom in the FiniteElement
+ @param O Order/degree of the FiniteElement
+ @param F FunctionSpace type of the FiniteElement
+ */
ScalarFiniteElement(int D, Geometry::Type G, int Do, int O,
int F = FunctionSpace::Pk)
#ifdef MFEM_THREAD_SAFE
: FiniteElement(D, G, Do, O, F)
- { DerivType = GRAD; DerivRangeType = VECTOR; DerivMapType = H_CURL; }
+ { deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; }
#else
- : FiniteElement(D, G, Do, O, F), c_shape(Dof)
- { DerivType = GRAD; DerivRangeType = VECTOR; DerivMapType = H_CURL; }
+ : FiniteElement(D, G, Do, O, F), c_shape(dof)
+ { deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; }
#endif
+ /** @brief Set the FiniteElement::MapType of the element to either VALUE or
+ INTEGRAL. Also sets the FiniteElement::DerivType to GRAD if the
+ FiniteElement::MapType is VALUE. */
void SetMapType(int M)
{
MFEM_VERIFY(M == VALUE || M == INTEGRAL, "unknown MapType");
- MapType = M;
- DerivType = (M == VALUE) ? GRAD : NONE;
+ map_type = M;
+ deriv_type = (M == VALUE) ? GRAD : NONE;
}
- /// Nodal interpolation.
+
+ /** @brief Get the matrix @a I that defines nodal interpolation
+ @a between this element and the refined element @a fine_fe. */
void NodalLocalInterpolation(ElementTransformation &Trans,
DenseMatrix &I,
const ScalarFiniteElement &fine_fe) const;
- /// "Interpolation" defined through local L2-projection.
+ /** @brief Get matrix @a I "Interpolation" defined through local
+ L2-projection in the space defined by the @a fine_fe. */
/** If the "fine" elements cannot represent all basis functions of the
"coarse" element, then boundary values from different sub-elements are
generally different. */
@@ -624,6 +668,8 @@ public:
DofToQuad::Mode mode) const;
};
+
+/// Class for standard nodal finite elements.
class NodalFiniteElement : public ScalarFiniteElement
{
protected:
@@ -632,6 +678,13 @@ protected:
DenseMatrix &curl) const;
public:
+ /** @brief Construct NodalFiniteElement with given
+ @param D Reference space dimension
+ @param G Geometry type (of type Geometry::Type)
+ @param Do Number of degrees of freedom in the FiniteElement
+ @param O Order/degree of the FiniteElement
+ @param F FunctionSpace type of the FiniteElement
+ */
NodalFiniteElement(int D, Geometry::Type G, int Do, int O,
int F = FunctionSpace::Pk)
: ScalarFiniteElement(D, G, Do, O, F) { }
@@ -670,10 +723,18 @@ public:
DenseMatrix &div) const;
};
-
+/** @brief Class for finite elements utilizing the
+ always positive Bernstein basis. */
class PositiveFiniteElement : public ScalarFiniteElement
{
public:
+ /** @brief Construct PositiveFiniteElement with given
+ @param D Reference space dimension
+ @param G Geometry type (of type Geometry::Type)
+ @param Do Number of degrees of freedom in the FiniteElement
+ @param O Order/degree of the FiniteElement
+ @param F FunctionSpace type of the FiniteElement
+ */
PositiveFiniteElement(int D, Geometry::Type G, int Do, int O,
int F = FunctionSpace::Pk) :
ScalarFiniteElement(D, G, Do, O, F)
@@ -702,6 +763,8 @@ public:
DenseMatrix &I) const;
};
+/** @brief Intermediate class for finite elements whose basis functions return
+ vector values. */
class VectorFiniteElement : public FiniteElement
{
// Hide the scalar functions CalcShape and CalcDShape.
@@ -759,7 +822,7 @@ protected:
VectorCoefficient &vc, ElementTransformation &Trans,
Vector &dofs) const;
- // project the rows of the matrix coefficient in an ND space
+ /// project the rows of the matrix coefficient in an ND space
void ProjectMatrixCoefficient_ND(
const double *tk, const Array &d2t,
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
@@ -802,16 +865,18 @@ public:
int F = FunctionSpace::Pk) :
#ifdef MFEM_THREAD_SAFE
FiniteElement(D, G, Do, O, F)
- { RangeType = VECTOR; MapType = M; SetDerivMembers(); }
+ { range_type = VECTOR; map_type = M; SetDerivMembers(); }
#else
FiniteElement(D, G, Do, O, F), Jinv(D)
- { RangeType = VECTOR; MapType = M; SetDerivMembers(); }
+ { range_type = VECTOR; map_type = M; SetDerivMembers(); }
#endif
};
+/// A 0D point finite element
class PointFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the PointFiniteElement
PointFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -820,11 +885,11 @@ public:
DenseMatrix &dshape) const;
};
-/// Class for linear FE on interval
+/// A 1D linear element with nodes on the endpoints
class Linear1DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a linear FE on interval
+ /// Construct the Linear1DFiniteElement
Linear1DFiniteElement();
/** virtual function which evaluates the values of all
@@ -840,11 +905,11 @@ public:
DenseMatrix &dshape) const;
};
-/// Class for linear FE on triangle
+/// A 2D linear element on triangle with nodes at the vertices of the triangle
class Linear2DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a linear FE on triangle
+ /// Construct the Linear2DFiniteElement
Linear2DFiniteElement();
/** virtual function which evaluates the values of all
@@ -862,11 +927,11 @@ public:
{ dofs = 0.0; dofs(vertex) = 1.0; }
};
-/// Class for bilinear FE on quadrilateral
+/// A 2D bi-linear element on a square with nodes at the vertices of the square
class BiLinear2DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a bilinear FE on quadrilateral
+ /// Construct the BiLinear2DFiniteElement
BiLinear2DFiniteElement();
/** virtual function which evaluates the values of all
@@ -886,10 +951,11 @@ public:
{ dofs = 0.0; dofs(vertex) = 1.0; } // { dofs = 1.0; }
};
-/// Class for linear FE on triangle with nodes at the 3 "Gaussian" points
+/// A linear element on a triangle with nodes at the 3 "Gaussian" points
class GaussLinear2DFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the GaussLinear2DFiniteElement
GaussLinear2DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -897,13 +963,14 @@ public:
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
-/// Class for bilinear FE on quad with nodes at the 4 Gaussian points
+/// A 2D bi-linear element on a square with nodes at the "Gaussian" points
class GaussBiLinear2DFiniteElement : public NodalFiniteElement
{
private:
static const double p[2];
public:
+ /// Construct the FiniteElement
GaussBiLinear2DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -911,9 +978,12 @@ public:
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
+/** @brief A 2D linear element on a square with 3 nodes at the
+ vertices of the lower left triangle */
class P1OnQuadFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the P1OnQuadFiniteElement
P1OnQuadFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -922,11 +992,11 @@ public:
{ dofs = 1.0; }
};
-/// Class for quadratic FE on interval
+/// A 1D quadractic finite element with uniformly spaced nodes
class Quad1DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a quadratic FE on interval
+ /// Construct the Quad1DFiniteElement
Quad1DFiniteElement();
/** virtual function which evaluates the values of all
@@ -942,20 +1012,23 @@ public:
DenseMatrix &dshape) const;
};
+/// A 1D quadratic positive element utilizing the 2nd order Bernstein basis
class QuadPos1DFiniteElement : public PositiveFiniteElement
{
public:
+ /// Construct the QuadPos1DFiniteElement
QuadPos1DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
-/// Class for quadratic FE on triangle
+/** @brief A 2D quadratic element on triangle with nodes at the
+ vertices and midpoints of the triangle. */
class Quad2DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a quadratic FE on triangle
+ /// Construct the Quad2DFiniteElement
Quad2DFiniteElement();
/** virtual function which evaluates the values of all
@@ -975,7 +1048,7 @@ public:
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
-/// Class for quadratic FE on triangle with nodes at the "Gaussian" points
+/// A quadratic element on triangle with nodes at the "Gaussian" points
class GaussQuad2DFiniteElement : public NodalFiniteElement
{
private:
@@ -984,6 +1057,7 @@ private:
mutable DenseMatrix D;
mutable Vector pol;
public:
+ /// Construct the GaussQuad2DFiniteElement
GaussQuad2DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -991,11 +1065,11 @@ public:
// virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
-/// Class for bi-quadratic FE on quadrilateral
+/// A 2D bi-quadratic element on a square with uniformly spaced nodes
class BiQuad2DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a biquadratic FE on quadrilateral
+ /// Construct the BiQuad2DFiniteElement
BiQuad2DFiniteElement();
/** virtual function which evaluates the values of all
@@ -1012,9 +1086,13 @@ public:
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
+
+/// A 2D positive bi-quadratic element on a square utilizing the 2nd order
+/// Bernstein basis
class BiQuadPos2DFiniteElement : public PositiveFiniteElement
{
public:
+ /// Construct the BiQuadPos2DFiniteElement
BiQuadPos2DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -1030,10 +1108,11 @@ public:
{ dofs = 0.; dofs(vertex) = 1.; }
};
-/// Bi-quadratic element on quad with nodes at the 9 Gaussian points
+/// A 2D bi-quadratic element on a square with nodes at the 9 "Gaussian" points
class GaussBiQuad2DFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the GaussBiQuad2DFiniteElement
GaussBiQuad2DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -1041,20 +1120,27 @@ public:
// virtual void ProjectDelta(int vertex, Vector &dofs) const { dofs = 1.; }
};
+
+/// A 2D bi-cubic element on a square with uniformly spaces nodes
class BiCubic2DFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the BiCubic2DFiniteElement
BiCubic2DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
+
+ /// Compute the Hessian of second order partial derivatives at @a ip.
virtual void CalcHessian (const IntegrationPoint &ip,
DenseMatrix &h) const;
};
+/// A 1D cubic element with uniformly spaced nodes
class Cubic1DFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the Cubic1DFiniteElement
Cubic1DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -1063,9 +1149,11 @@ public:
DenseMatrix &dshape) const;
};
+/// A 2D cubic element on a triangle with uniformly spaced nodes
class Cubic2DFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the Cubic2DFiniteElement
Cubic2DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -1077,11 +1165,12 @@ public:
DenseMatrix &h) const;
};
-/// Class for cubic FE on tetrahedron
+/// A 3D cubic element on a tetrahedron with 20 nodes at the thirds of the
+/// tetrahedron
class Cubic3DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a cubic FE on tetrahedron
+ /// Construct the Cubic3DFiniteElement
Cubic3DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -1090,11 +1179,11 @@ public:
DenseMatrix &dshape) const;
};
-/// Class for constant FE on triangle
+/// A 2D constant element on a triangle
class P0TriangleFiniteElement : public NodalFiniteElement
{
public:
- /// Construct P0 triangle finite element
+ /// Construct the P0TriangleFiniteElement
P0TriangleFiniteElement();
/// evaluate shape function - constant 1
@@ -1108,9 +1197,11 @@ public:
};
+/// A 2D constant element on a square
class P0QuadFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the P0QuadFiniteElement
P0QuadFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -1120,19 +1211,20 @@ public:
};
-/// Class for linear FE on tetrahedron
+/** @brief A 3D linear element on a tetrahedron with nodes at the
+ vertices of the tetrahedron */
class Linear3DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a linear FE on tetrahedron
+ /// Construct the Linear3DFiniteElement
Linear3DFiniteElement();
- /** virtual function which evaluates the values of all
+ /** @brief virtual function which evaluates the values of all
shape functions at a given point ip and stores
them in the vector shape of dimension Dof (4) */
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
- /** virtual function which evaluates the values of all
+ /** @brief virtual function which evaluates the values of all
partial derivatives of all shape functions at a given
point ip and stores them in the matrix dshape (Dof x Dim) (4 x 3)
so that each row contains the derivatives of one shape function */
@@ -1142,14 +1234,18 @@ public:
virtual void ProjectDelta(int vertex, Vector &dofs) const
{ dofs = 0.0; dofs(vertex) = 1.0; }
+ /** @brief Get the dofs associated with the given @a face.
+ @a *dofs is set to an internal array of the local dofc on the
+ face, while *ndofs is set to the number of dofs on that face.
+ */
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
};
-/// Class for quadratic FE on tetrahedron
+/// A 3D quadratic element on a tetrahedron with uniformly spaced nodes
class Quadratic3DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a quadratic FE on tetrahedron
+ /// Construct the Quadratic3DFiniteElement
Quadratic3DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -1158,11 +1254,11 @@ public:
DenseMatrix &dshape) const;
};
-/// Class for tri-linear FE on cube
+/// A 3D tri-linear element on a cube with nodes at the vertices of the cube
class TriLinear3DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a tri-linear FE on cube
+ /// Construct the TriLinear3DFiniteElement
TriLinear3DFiniteElement();
/** virtual function which evaluates the values of all
@@ -1182,10 +1278,11 @@ public:
};
-/// Crouzeix-Raviart finite element on triangle
+/// A 2D Crouzeix-Raviart element on triangle
class CrouzeixRaviartFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the CrouzeixRaviartFiniteElement
CrouzeixRaviartFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -1194,31 +1291,37 @@ public:
{ dofs = 1.0; }
};
-/// Crouzeix-Raviart finite element on quadrilateral
+/// A 2D Crouzeix-Raviart finite element on square
class CrouzeixRaviartQuadFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the CrouzeixRaviartQuadFiniteElement
CrouzeixRaviartQuadFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
+
+/// A 1D constant element on a segment
class P0SegmentFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the P0SegmentFiniteElement with dummy order @a Ord
P0SegmentFiniteElement(int Ord = 0);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
+/** @brief A 2D 1st order Raviart-Thomas vector element on a triangle */
class RT0TriangleFiniteElement : public VectorFiniteElement
{
private:
static const double nk[3][2];
public:
+ /// Construct the RT0TriangleFiniteElement
RT0TriangleFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
@@ -1240,12 +1343,14 @@ public:
ElementTransformation &Trans, Vector &dofs) const;
};
+/** @brief A 2D 1st order Raviart-Thomas vector element on a square*/
class RT0QuadFiniteElement : public VectorFiniteElement
{
private:
static const double nk[4][2];
public:
+ /// Construct the RT0QuadFiniteElement
RT0QuadFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
@@ -1267,12 +1372,14 @@ public:
ElementTransformation &Trans, Vector &dofs) const;
};
+/** @brief A 2D 2nd order Raviart-Thomas vector element on a triangle */
class RT1TriangleFiniteElement : public VectorFiniteElement
{
private:
static const double nk[8][2];
public:
+ /// Construct the RT1TriangleFiniteElement
RT1TriangleFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
@@ -1294,12 +1401,14 @@ public:
ElementTransformation &Trans, Vector &dofs) const;
};
+/** @brief A 2D 2nd order Raviart-Thomas vector element on a square */
class RT1QuadFiniteElement : public VectorFiniteElement
{
private:
static const double nk[12][2];
public:
+ /// Construct the RT1QuadFiniteElement
RT1QuadFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
@@ -1321,11 +1430,13 @@ public:
ElementTransformation &Trans, Vector &dofs) const;
};
+/** @brief A 2D 3rd order Raviart-Thomas vector element on a triangle */
class RT2TriangleFiniteElement : public VectorFiniteElement
{
private:
static const double M[15][15];
public:
+ /// Construct the RT2TriangleFiniteElement
RT2TriangleFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
@@ -1339,6 +1450,7 @@ public:
Vector &divshape) const;
};
+/** @brief A 2D 3rd order Raviart-Thomas vector element on a square */
class RT2QuadFiniteElement : public VectorFiniteElement
{
private:
@@ -1347,6 +1459,7 @@ private:
static const double dpt[3];
public:
+ /// Construct the RT2QuadFiniteElement
RT2QuadFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
@@ -1368,26 +1481,29 @@ public:
ElementTransformation &Trans, Vector &dofs) const;
};
-/// Linear 1D element with nodes 1/3 and 2/3 (trace of RT1)
+/// A 1D linear element with nodes at 1/3 and 2/3 (trace of RT1)
class P1SegmentFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the P1SegmentFiniteElement
P1SegmentFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
-/// Quadratic 1D element with nodes the Gaussian points in [0,1] (trace of RT2)
+/// A 1D quadratic element with nodes at the Gaussian points (trace of RT2)
class P2SegmentFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the P2SegmentFiniteElement
P2SegmentFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
+/// A 1D element with uniform nodes
class Lagrange1DFiniteElement : public NodalFiniteElement
{
private:
@@ -1396,24 +1512,29 @@ private:
mutable Vector rxxk;
#endif
public:
+ /// Construct the Lagrange1DFiniteElement with the provided @a degree
Lagrange1DFiniteElement (int degree);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
+/// A 3D Crouzeix-Raviart element on the tetrahedron.
class P1TetNonConfFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the P1TetNonConfFiniteElement
P1TetNonConfFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
+/// A 3D constant element on a tetrahedron
class P0TetFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the P0TetFiniteElement
P0TetFiniteElement ();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -1422,9 +1543,11 @@ public:
{ dofs(0) = 1.0; }
};
+/// A 3D constant element on a cube
class P0HexFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the P0HexFiniteElement
P0HexFiniteElement ();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -1433,7 +1556,8 @@ public:
{ dofs(0) = 1.0; }
};
-/// Tensor products of 1D FEs (only degree 2 is functional)
+/** @brief Tensor products of 1D Lagrange1DFiniteElement
+ (only degree 2 is functional) */
class LagrangeHexFiniteElement : public NodalFiniteElement
{
private:
@@ -1446,6 +1570,7 @@ private:
#endif
public:
+ /// Construct the LagrangeHexFiniteElement with the provided @a degree
LagrangeHexFiniteElement (int degree);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -1454,11 +1579,11 @@ public:
};
-/// Class for refined linear FE on interval
+/// A 1D refined linear element
class RefinedLinear1DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a quadratic FE on interval
+ /// Construct the RefinedLinear1DFiniteElement
RefinedLinear1DFiniteElement();
/** virtual function which evaluates the values of all
@@ -1474,11 +1599,11 @@ public:
DenseMatrix &dshape) const;
};
-/// Class for refined linear FE on triangle
+/// A 2D refined linear element on a triangle
class RefinedLinear2DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a quadratic FE on triangle
+ /// Construct the RefinedLinear2DFiniteElement
RefinedLinear2DFiniteElement();
/** virtual function which evaluates the values of all
@@ -1494,11 +1619,11 @@ public:
DenseMatrix &dshape) const;
};
-/// Class for refined linear FE on tetrahedron
+/// A 2D refined linear element on a tetrahedron
class RefinedLinear3DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a quadratic FE on tetrahedron
+ /// Construct the RefinedLinear3DFiniteElement
RefinedLinear3DFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -1507,11 +1632,11 @@ public:
DenseMatrix &dshape) const;
};
-/// Class for refined bi-linear FE on quadrilateral
+/// A 2D refined bi-linear FE on a square
class RefinedBiLinear2DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a biquadratic FE on quadrilateral
+ /// Construct the RefinedBiLinear2DFiniteElement
RefinedBiLinear2DFiniteElement();
/** virtual function which evaluates the values of all
@@ -1527,11 +1652,11 @@ public:
DenseMatrix &dshape) const;
};
-/// Class for refined trilinear FE on a hexahedron
+/// A 3D refined tri-linear element on a cube
class RefinedTriLinear3DFiniteElement : public NodalFiniteElement
{
public:
- /// Construct a biquadratic FE on quadrilateral
+ /// Construct the RefinedTriLinear3DFiniteElement
RefinedTriLinear3DFiniteElement();
/** virtual function which evaluates the values of all
@@ -1548,12 +1673,14 @@ public:
};
+/// A 3D 1st order Nedelec element on a cube
class Nedelec1HexFiniteElement : public VectorFiniteElement
{
private:
static const double tk[12][3];
public:
+ /// Construct the Nedelec1HexFiniteElement
Nedelec1HexFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
@@ -1570,12 +1697,14 @@ public:
};
+/// A 3D 1st order Nedelec element on a tetrahedron
class Nedelec1TetFiniteElement : public VectorFiniteElement
{
private:
static const double tk[6][3];
public:
+ /// Construct the Nedelec1TetFiniteElement
Nedelec1TetFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
@@ -1592,12 +1721,14 @@ public:
};
+/// A 3D 0th order Raviert-Thomas element on a cube
class RT0HexFiniteElement : public VectorFiniteElement
{
private:
static const double nk[6][3];
public:
+ /// Construct the RT0HexFiniteElement
RT0HexFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
@@ -1620,12 +1751,14 @@ public:
};
+/// A 3D 1st order Raviert-Thomas element on a cube
class RT1HexFiniteElement : public VectorFiniteElement
{
private:
static const double nk[36][3];
public:
+ /// Construct the RT1HexFiniteElement
RT1HexFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
@@ -1648,12 +1781,14 @@ public:
};
+/// A 3D 0th order Raviert-Thomas element on a tetrahedron
class RT0TetFiniteElement : public VectorFiniteElement
{
private:
static const double nk[4][3];
public:
+ /// Construct the RT0TetFiniteElement
RT0TetFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
@@ -1679,6 +1814,7 @@ public:
class RotTriLinearHexFiniteElement : public NodalFiniteElement
{
public:
+ /// Construct the RotTriLinearHexFiniteElement
RotTriLinearHexFiniteElement();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -1686,6 +1822,8 @@ public:
};
+/// Class for computing 1D special polynomials and their associated basis
+/// functions
class Poly_1D
{
public:
@@ -1749,9 +1887,13 @@ public:
points. Returns NULL if the BasisType has no associated set of
points. */
const double *GetPoints(const int p, const int btype);
+
+ /// Get coordinates of an open (GaussLegendre) set of points if degree @a p
const double *OpenPoints(const int p,
const int btype = BasisType::GaussLegendre)
{ return GetPoints(p, btype); }
+
+ /// Get coordinates of a closed (GaussLegendre) set of points if degree @a p
const double *ClosedPoints(const int p,
const int btype = BasisType::GaussLobatto)
{ return GetPoints(p, btype); }
@@ -1766,8 +1908,8 @@ public:
the requested basis type. */
Basis &GetBasis(const int p, const int btype);
- // Evaluate the values of a hierarchical 1D basis at point x
- // hierarchical = k-th basis function is degree k polynomial
+ /** @brief Evaluate the values of a hierarchical 1D basis at point x
+ hierarchical = k-th basis function is degree k polynomial */
static void CalcBasis(const int p, const double x, double *u)
// { CalcMono(p, x, u); }
// Bernstein basis is not hierarchical --> does not work for triangles
@@ -1776,14 +1918,14 @@ public:
// { CalcLegendre(p, x, u); }
{ CalcChebyshev(p, x, u); }
- // Evaluate the values and derivatives of a hierarchical 1D basis at point x
+ /// Evaluate the values and derivatives of a hierarchical 1D basis at point @a x
static void CalcBasis(const int p, const double x, double *u, double *d)
// { CalcMono(p, x, u, d); }
// { CalcBernstein(p, x, u, d); }
// { CalcLegendre(p, x, u, d); }
{ CalcChebyshev(p, x, u, d); }
- // Evaluate the values, derivatives and second derivatives of a hierarchical 1D basis at point x
+ /// Evaluate the values, derivatives and second derivatives of a hierarchical 1D basis at point x
static void CalcBasis(const int p, const double x, double *u, double *d,
double *dd)
// { CalcMono(p, x, u, d); }
@@ -1791,25 +1933,38 @@ public:
// { CalcLegendre(p, x, u, d); }
{ CalcChebyshev(p, x, u, d, dd); }
- // Evaluate a representation of a Delta function at point x
+ /// Evaluate a representation of a Delta function at point x
static double CalcDelta(const int p, const double x)
{ return pow(x, (double) p); }
+ /** @brief Compute the points for the Chebyshev polynomials of order @a p
+ and place them in the already allocated @a x array. */
static void ChebyshevPoints(const int p, double *x);
- /// Compute the terms in the expansion of the binomial (x + y)^p
+ /** @brief Compute the @a p terms in the expansion of the binomial (x + y)^p
+ and store them in the already allocated @a u array. */
static void CalcBinomTerms(const int p, const double x, const double y,
double *u);
- /** Compute the terms in the expansion of the binomial (x + y)^p and their
- derivatives with respect to x assuming that dy/dx = -1. */
+ /** @brief Compute the terms in the expansion of the binomial (x + y)^p and
+ their derivatives with respect to x assuming that dy/dx = -1. Store the
+ results in the already allocated @a u and @a d arrays.*/
static void CalcBinomTerms(const int p, const double x, const double y,
double *u, double *d);
- /** Compute the derivatives (w.r.t. x) of the terms in the expansion of the
- binomial (x + y)^p assuming that dy/dx = -1. */
+ /** @brief Compute the derivatives (w.r.t. x) of the terms in the expansion
+ of the binomial (x + y)^p assuming that dy/dx = -1. Store the results
+ in the already allocated @a d array.*/
static void CalcDBinomTerms(const int p, const double x, const double y,
double *d);
+
+ /** @brief Compute the values of the Bernstein basis functions of order
+ @a p at coordinate @a x and store the results in the already allocated
+ @a u array. */
static void CalcBernstein(const int p, const double x, double *u)
{ CalcBinomTerms(p, x, 1. - x, u); }
+
+ /** @brief Compute the values and derivatives of the Bernstein basis functions
+ of order @a p at coordinate @a x and store the results in the already allocated
+ @a u and @a d arrays. */
static void CalcBernstein(const int p, const double x, double *u, double *d)
{ CalcBinomTerms(p, x, 1. - x, u, d); }
@@ -1821,6 +1976,9 @@ public:
extern Poly_1D poly1d;
+
+/// An element defined as an ND tensor product of 1D elements on a segment,
+/// square, or cube
class TensorBasisElement
{
protected:
@@ -1935,6 +2093,7 @@ public:
~VectorTensorFiniteElement();
};
+/// Arbitrary H1 elements in 1D
class H1_SegmentElement : public NodalTensorFiniteElement
{
private:
@@ -1943,6 +2102,7 @@ private:
#endif
public:
+ /// Construct the H1_SegmentElement of order @a p and BasisType @a btype
H1_SegmentElement(const int p, const int btype = BasisType::GaussLobatto);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -1953,6 +2113,7 @@ public:
};
+/// Arbitrary H1 elements in 2D on a square
class H1_QuadrilateralElement : public NodalTensorFiniteElement
{
private:
@@ -1961,6 +2122,7 @@ private:
#endif
public:
+ /// Construct the H1_QuadrilateralElement of order @a p and BasisType @a btype
H1_QuadrilateralElement(const int p,
const int btype = BasisType::GaussLobatto);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -1972,6 +2134,7 @@ public:
};
+/// Arbitrary H1 elements in 3D on a cube
class H1_HexahedronElement : public NodalTensorFiniteElement
{
private:
@@ -1981,6 +2144,7 @@ private:
#endif
public:
+ /// Construct the H1_HexahedronElement of order @a p and BasisType @a btype
H1_HexahedronElement(const int p, const int btype = BasisType::GaussLobatto);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -1990,19 +2154,21 @@ public:
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
+/// Arbitrary order H1 elements in 1D utilizing the Bernstein basis
class H1Pos_SegmentElement : public PositiveTensorFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
- // This is to share scratch space between invocations, which helps
- // speed things up, but with OpenMP, we need one copy per thread.
- // Right now, we solve this by allocating this space within each function
- // call every time we call it. Alternatively, we should do some sort
- // thread private thing. Brunner, Jan 2014
+ // This is to share scratch space between invocations, which helps speed
+ // things up, but with OpenMP, we need one copy per thread. Right now, we
+ // solve this by allocating this space within each function call every time
+ // we call it. Alternatively, we should do some sort thread private thing.
+ // Brunner, Jan 2014
mutable Vector shape_x, dshape_x;
#endif
public:
+ /// Construct the H1Pos_SegmentElement of order @a p
H1Pos_SegmentElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -2011,6 +2177,7 @@ public:
};
+/// Arbitrary order H1 elements in 2D utilizing the Bernstein basis on a square
class H1Pos_QuadrilateralElement : public PositiveTensorFiniteElement
{
private:
@@ -2020,6 +2187,7 @@ private:
#endif
public:
+ /// Construct the H1Pos_QuadrilateralElement of order @a p
H1Pos_QuadrilateralElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -2028,9 +2196,11 @@ public:
};
+/// Arbitrary order H1 serendipity elements in 2D on a quad
class H1Ser_QuadrilateralElement : public ScalarFiniteElement
{
public:
+ /// Construct the H1Ser_QuadrilateralElement of order @a p
H1Ser_QuadrilateralElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -2040,6 +2210,7 @@ public:
using FiniteElement::Project;
};
+/// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a cube
class H1Pos_HexahedronElement : public PositiveTensorFiniteElement
{
private:
@@ -2049,6 +2220,7 @@ private:
#endif
public:
+ /// Construct the H1Pos_HexahedronElement of order @a p
H1Pos_HexahedronElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -2057,6 +2229,7 @@ public:
};
+/// Arbitrary order H1 elements in 2D on a tiangle
class H1_TriangleElement : public NodalFiniteElement
{
private:
@@ -2068,6 +2241,7 @@ private:
DenseMatrixInverse Ti;
public:
+ /// Construct the H1_TriangleElement of order @a p and BasisType @a btype
H1_TriangleElement(const int p, const int btype = BasisType::GaussLobatto);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -2077,6 +2251,7 @@ public:
};
+/// Arbitrary order H1 elements in 3D on a tetrahedron
class H1_TetrahedronElement : public NodalFiniteElement
{
private:
@@ -2089,6 +2264,7 @@ private:
DenseMatrixInverse Ti;
public:
+ /// Construct the H1_TetrahedronElement of order @a p and BasisType @a btype
H1_TetrahedronElement(const int p,
const int btype = BasisType::GaussLobatto);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -2099,6 +2275,7 @@ public:
};
+/// Arbitrary order H1 elements in 2D utilizing the Bernstein basis on a triangle
class H1Pos_TriangleElement : public PositiveFiniteElement
{
protected:
@@ -2109,6 +2286,7 @@ protected:
Array dof_map;
public:
+ /// Construct the H1Pos_TriangleElement of order @a p
H1Pos_TriangleElement(const int p);
// The size of shape is (p+1)(p+2)/2 (dof).
@@ -2125,6 +2303,8 @@ public:
};
+/// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a
+/// tetrahedron
class H1Pos_TetrahedronElement : public PositiveFiniteElement
{
protected:
@@ -2135,6 +2315,7 @@ protected:
Array dof_map;
public:
+ /// Construct the H1Pos_TetrahedronElement of order @a p
H1Pos_TetrahedronElement(const int p);
// The size of shape is (p+1)(p+2)(p+3)/6 (dof).
@@ -2151,6 +2332,7 @@ public:
};
+/// Arbitrary order H1 elements in 3D on a wedge
class H1_WedgeElement : public NodalFiniteElement
{
private:
@@ -2164,6 +2346,7 @@ private:
H1_SegmentElement SegmentFE;
public:
+ /// Construct the H1_WedgeElement of order @a p and BasisType @a btype
H1_WedgeElement(const int p,
const int btype = BasisType::GaussLobatto);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -2195,6 +2378,7 @@ public:
BiCubic3DFiniteElement() : H1_WedgeElement(3) {}
};
+/// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a wedge
class H1Pos_WedgeElement : public PositiveFiniteElement
{
protected:
@@ -2208,6 +2392,7 @@ protected:
H1Pos_SegmentElement SegmentFE;
public:
+ /// Construct the H1Pos_WedgeElement of order @a p
H1Pos_WedgeElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -2216,6 +2401,7 @@ public:
};
+/// Arbitrary L2 elements in 1D on a segment
class L2_SegmentElement : public NodalTensorFiniteElement
{
private:
@@ -2224,6 +2410,7 @@ private:
#endif
public:
+ /// Construct the L2_SegmentElement of order @a p and BasisType @a btype
L2_SegmentElement(const int p, const int btype = BasisType::GaussLegendre);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -2231,7 +2418,7 @@ public:
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
-
+/// Arbitrary order L2 elements in 1D utilizing the Bernstein basis on a segment
class L2Pos_SegmentElement : public PositiveTensorFiniteElement
{
private:
@@ -2240,6 +2427,7 @@ private:
#endif
public:
+ /// Construct the L2Pos_SegmentElement of order @a p
L2Pos_SegmentElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -2248,6 +2436,7 @@ public:
};
+/// Arbitrary order L2 elements in 2D on a square
class L2_QuadrilateralElement : public NodalTensorFiniteElement
{
private:
@@ -2256,6 +2445,7 @@ private:
#endif
public:
+ /// Construct the L2_QuadrilateralElement of order @a p and BasisType @a btype
L2_QuadrilateralElement(const int p,
const int btype = BasisType::GaussLegendre);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -2268,7 +2458,7 @@ public:
{ ProjectCurl_2D(fe, Trans, curl); }
};
-
+/// Arbitrary order L2 elements in 2D utilizing the Bernstein basis on a square
class L2Pos_QuadrilateralElement : public PositiveTensorFiniteElement
{
private:
@@ -2277,6 +2467,7 @@ private:
#endif
public:
+ /// Construct the L2Pos_QuadrilateralElement of order @a p
L2Pos_QuadrilateralElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -2284,7 +2475,7 @@ public:
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
-
+/// Arbitrary order L2 elements in 3D on a cube
class L2_HexahedronElement : public NodalTensorFiniteElement
{
private:
@@ -2293,6 +2484,7 @@ private:
#endif
public:
+ /// Construct the L2_HexahedronElement of order @a p and BasisType @a btype
L2_HexahedronElement(const int p,
const int btype = BasisType::GaussLegendre);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -2302,6 +2494,7 @@ public:
};
+/// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a cube
class L2Pos_HexahedronElement : public PositiveTensorFiniteElement
{
private:
@@ -2310,6 +2503,7 @@ private:
#endif
public:
+ /// Construct the L2Pos_HexahedronElement of order @a p
L2Pos_HexahedronElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -2318,6 +2512,7 @@ public:
};
+/// Arbitrary order L2 elements in 2D on a triangle
class L2_TriangleElement : public NodalFiniteElement
{
private:
@@ -2328,6 +2523,7 @@ private:
DenseMatrixInverse Ti;
public:
+ /// Construct the L2_TriangleElement of order @a p and BasisType @a btype
L2_TriangleElement(const int p,
const int btype = BasisType::GaussLegendre);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -2340,7 +2536,7 @@ public:
{ ProjectCurl_2D(fe, Trans, curl); }
};
-
+/// Arbitrary order L2 elements in 2D utilizing the Bernstein basis on a triangle
class L2Pos_TriangleElement : public PositiveFiniteElement
{
private:
@@ -2349,6 +2545,7 @@ private:
#endif
public:
+ /// Construct the L2Pos_TriangleElement of order @a p
L2Pos_TriangleElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -2357,6 +2554,7 @@ public:
};
+/// Arbitrary order L2 elements in 3D on a tetrahedron
class L2_TetrahedronElement : public NodalFiniteElement
{
private:
@@ -2368,6 +2566,7 @@ private:
DenseMatrixInverse Ti;
public:
+ /// Construct the L2_TetrahedronElement of order @a p and BasisType @a btype
L2_TetrahedronElement(const int p,
const int btype = BasisType::GaussLegendre);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -2377,6 +2576,8 @@ public:
};
+/// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a
+/// tetrahedron
class L2Pos_TetrahedronElement : public PositiveFiniteElement
{
private:
@@ -2385,6 +2586,7 @@ private:
#endif
public:
+ /// Construct the L2Pos_TetrahedronElement of order @a p
L2Pos_TetrahedronElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
@@ -2393,6 +2595,7 @@ public:
};
+/// Arbitrary order L2 elements in 3D on a wedge
class L2_WedgeElement : public NodalFiniteElement
{
private:
@@ -2406,6 +2609,7 @@ private:
L2_SegmentElement SegmentFE;
public:
+ /// Construct the L2_WedgeElement of order @a p and BasisType @a btype
L2_WedgeElement(const int p,
const int btype = BasisType::GaussLegendre);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -2413,12 +2617,15 @@ public:
DenseMatrix &dshape) const;
};
+/// A 0th order L2 element on a Wedge
class P0WedgeFiniteElement : public L2_WedgeElement
{
public:
+ /// Construct the P0WedgeFiniteElement
P0WedgeFiniteElement () : L2_WedgeElement(0) {}
};
+/// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a wedge
class L2Pos_WedgeElement : public PositiveFiniteElement
{
protected:
@@ -2432,6 +2639,7 @@ protected:
L2Pos_SegmentElement SegmentFE;
public:
+ /// Construct the L2Pos_WedgeElement of order @a p
L2Pos_WedgeElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -2439,7 +2647,7 @@ public:
DenseMatrix &dshape) const;
};
-
+/// Arbitrary order Raviart-Thomas elements in 2D on a square
class RT_QuadrilateralElement : public VectorTensorFiniteElement
{
private:
@@ -2452,6 +2660,8 @@ private:
Array dof2nk;
public:
+ /** @brief Construct the RT_QuadrilateralElement of order @a p and closed and
+ open BasisType @a cb_type and @a ob_type */
RT_QuadrilateralElement(const int p,
const int cb_type = BasisType::GaussLobatto,
const int ob_type = BasisType::GaussLegendre);
@@ -2495,6 +2705,7 @@ public:
};
+/// Arbitrary order Raviart-Thomas elements in 3D on a cube
class RT_HexahedronElement : public VectorTensorFiniteElement
{
static const double nk[18];
@@ -2506,6 +2717,8 @@ class RT_HexahedronElement : public VectorTensorFiniteElement
Array dof2nk;
public:
+ /** @brief Construct the RT_HexahedronElement of order @a p and closed and
+ open BasisType @a cb_type and @a ob_type */
RT_HexahedronElement(const int p,
const int cb_type = BasisType::GaussLobatto,
const int ob_type = BasisType::GaussLegendre);
@@ -2544,6 +2757,7 @@ public:
};
+/// Arbitrary order Raviart-Thomas elements in 2D on a triangle
class RT_TriangleElement : public VectorFiniteElement
{
static const double nk[6], c;
@@ -2558,6 +2772,7 @@ class RT_TriangleElement : public VectorFiniteElement
DenseMatrixInverse Ti;
public:
+ /// Construct the RT_TriangleElement of order @a p
RT_TriangleElement(const int p);
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
@@ -2599,6 +2814,7 @@ public:
};
+/// Arbitrary order Raviart-Thomas elements in 3D on a tetrahedron
class RT_TetrahedronElement : public VectorFiniteElement
{
static const double nk[12], c;
@@ -2613,6 +2829,7 @@ class RT_TetrahedronElement : public VectorFiniteElement
DenseMatrixInverse Ti;
public:
+ /// Construct the RT_TetrahedronElement of order @a p
RT_TetrahedronElement(const int p);
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
@@ -2648,6 +2865,7 @@ public:
};
+/// Arbitrary order Nedelec elements in 3D on a cube
class ND_HexahedronElement : public VectorTensorFiniteElement
{
static const double tk[18];
@@ -2658,6 +2876,8 @@ class ND_HexahedronElement : public VectorTensorFiniteElement
Array dof2tk;
public:
+ /** @brief Construct the ND_HexahedronElement of order @a p and closed and
+ open BasisType @a cb_type and @a ob_type */
ND_HexahedronElement(const int p,
const int cb_type = BasisType::GaussLobatto,
const int ob_type = BasisType::GaussLegendre);
@@ -2712,6 +2932,7 @@ public:
};
+/// Arbitrary order Nedelec elements in 2D on a square
class ND_QuadrilateralElement : public VectorTensorFiniteElement
{
static const double tk[8];
@@ -2723,6 +2944,8 @@ class ND_QuadrilateralElement : public VectorTensorFiniteElement
Array dof2tk;
public:
+ /** @brief Construct the ND_QuadrilateralElement of order @a p and closed and
+ open BasisType @a cb_type and @a ob_type */
ND_QuadrilateralElement(const int p,
const int cb_type = BasisType::GaussLobatto,
const int ob_type = BasisType::GaussLegendre);
@@ -2761,6 +2984,7 @@ public:
};
+/// Arbitrary order Nedelec elements in 3D on a tetrahedron
class ND_TetrahedronElement : public VectorFiniteElement
{
static const double tk[18], c;
@@ -2774,6 +2998,7 @@ class ND_TetrahedronElement : public VectorFiniteElement
DenseMatrixInverse Ti;
public:
+ /// Construct the ND_TetrahedronElement of order @a p
ND_TetrahedronElement(const int p);
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
@@ -2814,6 +3039,7 @@ public:
{ ProjectCurl_ND(tk, dof2tk, fe, Trans, curl); }
};
+/// Arbitrary order Nedelec elements in 2D on a triangle
class ND_TriangleElement : public VectorFiniteElement
{
static const double tk[8], c;
@@ -2828,6 +3054,7 @@ class ND_TriangleElement : public VectorFiniteElement
DenseMatrixInverse Ti;
public:
+ /// Construct the ND_TriangleElement of order @a p
ND_TriangleElement(const int p);
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
@@ -2864,6 +3091,7 @@ public:
};
+/// Arbitrary order Nedelec elements in 1D on a segment
class ND_SegmentElement : public VectorFiniteElement
{
static const double tk[1];
@@ -2872,6 +3100,8 @@ class ND_SegmentElement : public VectorFiniteElement
Array dof2tk;
public:
+ /** @brief Construct the ND_SegmentElement of order @a p and open
+ BasisType @a ob_type */
ND_SegmentElement(const int p, const int ob_type = BasisType::GaussLegendre);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const
{ obasis1d.Eval(ip.x, shape); }
@@ -2910,6 +3140,7 @@ public:
};
+/// An arbitrary order and dimension NURBS element
class NURBSFiniteElement : public ScalarFiniteElement
{
protected:
@@ -2919,13 +3150,20 @@ protected:
mutable Vector weights;
public:
+ /** @brief Construct NURBSFiniteElement with given
+ @param D Reference space dimension
+ @param G Geometry type (of type Geometry::Type)
+ @param Do Number of degrees of freedom in the FiniteElement
+ @param O Order/degree of the FiniteElement
+ @param F FunctionSpace type of the FiniteElement
+ */
NURBSFiniteElement(int D, Geometry::Type G, int Do, int O, int F)
: ScalarFiniteElement(D, G, Do, O, F)
{
ijk = NULL;
patch = elem = -1;
- kv.SetSize(Dim);
- weights.SetSize(Dof);
+ kv.SetSize(dim);
+ weights.SetSize(dof);
weights = 1.0;
}
@@ -2941,12 +3179,15 @@ public:
virtual void SetOrder () const { }
};
+
+/// An arbitrary order 1D NURBS element on a segment
class NURBS1DFiniteElement : public NURBSFiniteElement
{
protected:
mutable Vector shape_x;
public:
+ /// Construct the NURBS1DFiniteElement of order @a p
NURBS1DFiniteElement(int p)
: NURBSFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk),
shape_x(p + 1) { }
@@ -2959,6 +3200,7 @@ public:
DenseMatrix &hessian) const;
};
+/// An arbitrary order 2D NURBS element on a square
class NURBS2DFiniteElement : public NURBSFiniteElement
{
protected:
@@ -2966,19 +3208,21 @@ protected:
mutable DenseMatrix du;
public:
+ /// Construct the NURBS2DFiniteElement of order @a p
NURBS2DFiniteElement(int p)
: NURBSFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p,
FunctionSpace::Qk),
- u(Dof), shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
- dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1), du(Dof,2)
- { Orders[0] = Orders[1] = p; }
+ u(dof), shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
+ dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1), du(dof,2)
+ { orders[0] = orders[1] = p; }
+ /// Construct the NURBS2DFiniteElement with x-order @a px and y-order @a py
NURBS2DFiniteElement(int px, int py)
: NURBSFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1),
std::max(px, py), FunctionSpace::Qk),
- u(Dof), shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
- dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1), du(Dof,2)
- { Orders[0] = px; Orders[1] = py; }
+ u(dof), shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
+ dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1), du(dof,2)
+ { orders[0] = px; orders[1] = py; }
virtual void SetOrder() const;
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
@@ -2988,6 +3232,7 @@ public:
DenseMatrix &hessian) const;
};
+/// An arbitrary order 3D NURBS element on a cube
class NURBS3DFiniteElement : public NURBSFiniteElement
{
protected:
@@ -2997,21 +3242,24 @@ protected:
mutable DenseMatrix du;
public:
+ /// Construct the NURBS3DFiniteElement of order @a p
NURBS3DFiniteElement(int p)
: NURBSFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p,
FunctionSpace::Qk),
- u(Dof), shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
+ u(dof), shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
- d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1), du(Dof,3)
- { Orders[0] = Orders[1] = Orders[2] = p; }
+ d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1), du(dof,3)
+ { orders[0] = orders[1] = orders[2] = p; }
+ /// Construct the NURBS3DFiniteElement with x-order @a px and y-order @a py
+ /// and z-order @a pz
NURBS3DFiniteElement(int px, int py, int pz)
: NURBSFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1),
std::max(std::max(px,py),pz), FunctionSpace::Qk),
- u(Dof), shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
+ u(dof), shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
- d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1), du(Dof,3)
- { Orders[0] = px; Orders[1] = py; Orders[2] = pz; }
+ d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1), du(dof,3)
+ { orders[0] = px; orders[1] = py; orders[2] = pz; }
virtual void SetOrder() const;
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
diff --git a/fem/fe_coll.cpp b/fem/fe_coll.cpp
index 50c541941b..017775138d 100644
--- a/fem/fe_coll.cpp
+++ b/fem/fe_coll.cpp
@@ -311,10 +311,10 @@ GetEdge(int &nv, v_t &v, int &ne, int &e, int &eo, const int edge_info)
eo = edge_info%64;
MFEM_ASSERT(0 <= e && e < g_consts::NumEdges, "");
MFEM_ASSERT(0 <= eo && eo < e_consts::NumOrient, "");
- v[0] = g_consts::Edges[e][0];
- v[1] = g_consts::Edges[e][1];
- v[0] = e_consts::Orient[eo][v[0]];
- v[1] = e_consts::Orient[eo][v[1]];
+ v[0] = e_consts::Orient[eo][0];
+ v[1] = e_consts::Orient[eo][1];
+ v[0] = g_consts::Edges[e][v[0]];
+ v[1] = g_consts::Edges[e][v[1]];
}
template &dofs) const;
};
@@ -102,6 +178,7 @@ 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; }
@@ -111,8 +188,8 @@ public:
virtual ~H1_FECollection();
};
-/** Arbitrary order H1-conforming (continuous) finite elements with positive
- basis functions. */
+/** @brief Arbitrary order H1-conforming (continuous) finite elements with
+ positive basis functions. */
class H1Pos_FECollection : public H1_FECollection
{
public:
@@ -120,6 +197,7 @@ public:
: H1_FECollection(p, dim, BasisType::Positive) { }
};
+
/** Arbitrary order H1-conforming (continuous) serendipity finite elements;
Current implementation works in 2D only; 3D version is in development. */
class H1Ser_FECollection : public H1_FECollection
@@ -129,9 +207,9 @@ public:
: H1_FECollection(p, dim, BasisType::Serendipity) { };
};
-/** Arbitrary order "H^{1/2}-conforming" trace finite elements defined on the
- interface between mesh elements (faces,edges,vertices); these are the trace
- FEs of the H1-conforming FEs. */
+/** @brief Arbitrary order "H^{1/2}-conforming" trace finite elements defined on
+ the interface between mesh elements (faces,edges,vertices); these are the
+ trace FEs of the H1-conforming FEs. */
class H1_Trace_FECollection : public H1_FECollection
{
public:
@@ -174,6 +252,8 @@ 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
{
@@ -221,14 +301,15 @@ 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();
};
-/** Arbitrary order "H^{-1/2}-conforming" face finite elements defined on the
- interface between mesh elements (faces); these are the normal trace FEs of
- the H(div)-conforming FEs. */
+/** @brief Arbitrary order "H^{-1/2}-conforming" face finite elements defined on
+ the interface between mesh elements (faces); these are the normal trace FEs
+ of the H(div)-conforming FEs. */
class RT_Trace_FECollection : public RT_FECollection
{
public:
@@ -270,14 +351,15 @@ 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();
};
-/** Arbitrary order H(curl)-trace finite elements defined on the interface
- between mesh elements (faces,edges); these are the tangential trace FEs of
- the H(curl)-conforming FEs. */
+/** @brief Arbitrary order H(curl)-trace finite elements defined on the
+ interface between mesh elements (faces,edges); these are the tangential
+ trace FEs of the H(curl)-conforming FEs. */
class ND_Trace_FECollection : public ND_FECollection
{
public:
@@ -334,13 +416,15 @@ public:
virtual const char *Name() const { return name; }
+ virtual int GetContType() const { return CONTINUOUS; }
+
FiniteElementCollection *GetTraceCollection() const;
virtual ~NURBSFECollection();
};
-/// Piecewise-(bi)linear continuous finite elements.
+/// Piecewise-(bi/tri)linear continuous finite elements.
class LinearFECollection : public FiniteElementCollection
{
private:
@@ -363,6 +447,8 @@ public:
int Or) const;
virtual const char * Name() const { return "Linear"; }
+
+ virtual int GetContType() const { return CONTINUOUS; }
};
/// Piecewise-(bi)quadratic continuous finite elements.
@@ -389,6 +475,8 @@ public:
int Or) const;
virtual const char * Name() const { return "Quadratic"; }
+
+ virtual int GetContType() const { return CONTINUOUS; }
};
/// Version of QuadraticFECollection with positive basis functions.
@@ -410,6 +498,8 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticPos"; }
+
+ virtual int GetContType() const { return CONTINUOUS; }
};
/// Piecewise-(bi)cubic continuous finite elements.
@@ -437,6 +527,8 @@ public:
int Or) const;
virtual const char * Name() const { return "Cubic"; }
+
+ virtual int GetContType() const { return CONTINUOUS; }
};
/// Crouzeix-Raviart nonconforming elements in 2D.
@@ -458,6 +550,8 @@ public:
int Or) const;
virtual const char * Name() const { return "CrouzeixRaviart"; }
+
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Piecewise-linear nonconforming finite elements in 3D.
@@ -481,11 +575,13 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearNonConf3D"; }
+
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
-/** First order Raviart-Thomas finite elements in 2D. This class is kept only
- for backward compatibility, consider using RT_FECollection instead. */
+/** @brief First order Raviart-Thomas finite elements in 2D. This class is kept
+ only for backward compatibility, consider using RT_FECollection instead. */
class RT0_2DFECollection : public FiniteElementCollection
{
private:
@@ -504,10 +600,12 @@ public:
int Or) const;
virtual const char * Name() const { return "RT0_2D"; }
+
+ virtual int GetContType() const { return NORMAL; }
};
-/** Second order Raviart-Thomas finite elements in 2D. This class is kept only
- for backward compatibility, consider using RT_FECollection instead. */
+/** @brief Second order Raviart-Thomas finite elements in 2D. This class is kept
+ only for backward compatibility, consider using RT_FECollection instead. */
class RT1_2DFECollection : public FiniteElementCollection
{
private:
@@ -526,10 +624,12 @@ public:
int Or) const;
virtual const char * Name() const { return "RT1_2D"; }
+
+ virtual int GetContType() const { return NORMAL; }
};
-/** Third order Raviart-Thomas finite elements in 2D. This class is kept only
- for backward compatibility, consider using RT_FECollection instead. */
+/** @brief Third order Raviart-Thomas finite elements in 2D. This class is kept
+ only for backward compatibility, consider using RT_FECollection instead. */
class RT2_2DFECollection : public FiniteElementCollection
{
private:
@@ -548,10 +648,13 @@ public:
int Or) const;
virtual const char * Name() const { return "RT2_2D"; }
+
+ virtual int GetContType() const { return NORMAL; }
};
-/** Piecewise-constant discontinuous finite elements in 2D. This class is kept
- only for backward compatibility, consider using L2_FECollection instead. */
+/** @brief Piecewise-constant discontinuous finite elements in 2D. This class is
+ kept only for backward compatibility, consider using L2_FECollection
+ instead. */
class Const2DFECollection : public FiniteElementCollection
{
private:
@@ -569,10 +672,13 @@ public:
int Or) const;
virtual const char * Name() const { return "Const2D"; }
+
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
-/** Piecewise-linear discontinuous finite elements in 2D. This class is kept
- only for backward compatibility, consider using L2_FECollection instead. */
+/** @brief Piecewise-linear discontinuous finite elements in 2D. This class is
+ kept only for backward compatibility, consider using L2_FECollection
+ instead. */
class LinearDiscont2DFECollection : public FiniteElementCollection
{
private:
@@ -591,6 +697,8 @@ 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.
@@ -613,6 +721,8 @@ public:
int Or) const;
virtual const char * Name() const { return "GaussLinearDiscont2D"; }
+
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Linear (P1) finite elements on quadrilaterals.
@@ -628,10 +738,12 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char * Name() const { return "P1OnQuad"; }
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
-/** Piecewise-quadratic discontinuous finite elements in 2D. This class is kept
- only for backward compatibility, consider using L2_FECollection instead. */
+/** @brief Piecewise-quadratic discontinuous finite elements in 2D. This class
+ is kept only for backward compatibility, consider using L2_FECollection
+ instead. */
class QuadraticDiscont2DFECollection : public FiniteElementCollection
{
private:
@@ -650,6 +762,7 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticDiscont2D"; }
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Version of QuadraticDiscont2DFECollection with positive basis functions.
@@ -667,6 +780,7 @@ 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.
@@ -689,10 +803,12 @@ public:
int Or) const;
virtual const char * Name() const { return "GaussQuadraticDiscont2D"; }
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
-/** Piecewise-cubic discontinuous finite elements in 2D. This class is kept
- only for backward compatibility, consider using L2_FECollection instead. */
+/** @brief Piecewise-cubic discontinuous finite elements in 2D. This class is
+ kept only for backward compatibility, consider using L2_FECollection
+ instead. */
class CubicDiscont2DFECollection : public FiniteElementCollection
{
private:
@@ -711,10 +827,12 @@ public:
int Or) const;
virtual const char * Name() const { return "CubicDiscont2D"; }
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
-/** Piecewise-constant discontinuous finite elements in 3D. This class is kept
- only for backward compatibility, consider using L2_FECollection instead. */
+/** @brief Piecewise-constant discontinuous finite elements in 3D. This class is
+ kept only for backward compatibility, consider using L2_FECollection
+ instead. */
class Const3DFECollection : public FiniteElementCollection
{
private:
@@ -734,10 +852,12 @@ public:
int Or) const;
virtual const char * Name() const { return "Const3D"; }
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
-/** Piecewise-linear discontinuous finite elements in 3D. This class is kept
- only for backward compatibility, consider using L2_FECollection instead. */
+/** @brief Piecewise-linear discontinuous finite elements in 3D. This class is
+ kept only for backward compatibility, consider using L2_FECollection
+ instead. */
class LinearDiscont3DFECollection : public FiniteElementCollection
{
private:
@@ -756,10 +876,12 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearDiscont3D"; }
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
-/** Piecewise-quadratic discontinuous finite elements in 3D. This class is kept
- only for backward compatibility, consider using L2_FECollection instead. */
+/** @brief Piecewise-quadratic discontinuous finite elements in 3D. This class
+ is kept only for backward compatibility, consider using L2_FECollection
+ instead. */
class QuadraticDiscont3DFECollection : public FiniteElementCollection
{
private:
@@ -778,6 +900,7 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticDiscont3D"; }
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Finite element collection on a macro-element.
@@ -803,10 +926,12 @@ public:
int Or) const;
virtual const char * Name() const { return "RefinedLinear"; }
+ virtual int GetContType() const { return CONTINUOUS; }
};
-/** Lowest order Nedelec finite elements in 3D. This class is kept only for
- backward compatibility, consider using the new ND_FECollection instead. */
+/** @brief Lowest order Nedelec finite elements in 3D. This class is kept only
+ for backward compatibility, consider using the new ND_FECollection
+ instead. */
class ND1_3DFECollection : public FiniteElementCollection
{
private:
@@ -825,10 +950,11 @@ public:
int Or) const;
virtual const char * Name() const { return "ND1_3D"; }
+ virtual int GetContType() const { return TANGENTIAL; }
};
-/** First order Raviart-Thomas finite elements in 3D. This class is kept only
- for backward compatibility, consider using RT_FECollection instead. */
+/** @brief First order Raviart-Thomas finite elements in 3D. This class is kept
+ only for backward compatibility, consider using RT_FECollection instead. */
class RT0_3DFECollection : public FiniteElementCollection
{
private:
@@ -848,10 +974,11 @@ public:
int Or) const;
virtual const char * Name() const { return "RT0_3D"; }
+ virtual int GetContType() const { return NORMAL; }
};
-/** Second order Raviart-Thomas finite elements in 3D. This class is kept only
- for backward compatibility, consider using RT_FECollection instead. */
+/** @brief Second order Raviart-Thomas finite elements in 3D. This class is kept
+ only for backward compatibility, consider using RT_FECollection instead. */
class RT1_3DFECollection : public FiniteElementCollection
{
private:
@@ -870,6 +997,7 @@ 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.
@@ -894,6 +1022,7 @@ public:
virtual const char *Name() const { return d_name; }
virtual ~Local_FECollection() { delete Local_Element; }
+ virtual int GetContType() const { return DISCONTINUOUS; }
};
}
diff --git a/fem/fespace.cpp b/fem/fespace.cpp
index 9ee5b86b73..2523f3ee21 100644
--- a/fem/fespace.cpp
+++ b/fem/fespace.cpp
@@ -60,7 +60,7 @@ FiniteElementSpace::FiniteElementSpace()
: mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
fdofs(NULL), bdofs(NULL),
- elem_dof(NULL), bdrElem_dof(NULL),
+ elem_dof(NULL), bdrElem_dof(NULL), face_dof(NULL),
NURBSext(NULL), own_ext(false),
cP(NULL), cR(NULL), cP_is_set(false),
Th(Operator::ANY_TYPE),
@@ -233,6 +233,54 @@ void FiniteElementSpace::BuildElementToDofTable() const
elem_dof = el_dof;
}
+void FiniteElementSpace::BuildBdrElementToDofTable() const
+{
+ if (bdrElem_dof) { return; }
+
+ Table *bel_dof = new Table;
+ Array 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 dofs;
+ fc_dof->MakeI(mesh->GetNumFaces());
+ for (int i = 0; i < fc_dof->Size(); i++)
+ {
+ GetFaceDofs(i, dofs);
+ fc_dof->AddColumnsInRow(i, dofs.Size());
+ }
+ fc_dof->MakeJ();
+ for (int i = 0; i < fc_dof->Size(); i++)
+ {
+ GetFaceDofs(i, dofs);
+ fc_dof->AddConnections(i, (int *)dofs, dofs.Size());
+ }
+ fc_dof->ShiftUpI();
+ face_dof = fc_dof;
+}
+
void FiniteElementSpace::RebuildElementToDofTable()
{
delete elem_dof;
@@ -1456,6 +1504,7 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext,
this->ordering = (Ordering::Type) ordering;
elem_dof = NULL;
+ face_dof = NULL;
sequence = mesh->GetSequence();
Th.SetType(Operator::ANY_TYPE);
@@ -1505,6 +1554,8 @@ NURBSExtension *FiniteElementSpace::StealNURBSext()
void FiniteElementSpace::UpdateNURBS()
{
+ MFEM_VERIFY(NURBSext, "NURBSExt not defined.");
+
nvdofs = 0;
nedofs = 0;
nfdofs = 0;
@@ -1512,6 +1563,10 @@ void FiniteElementSpace::UpdateNURBS()
fdofs = NULL;
bdofs = NULL;
+ delete face_dof;
+ face_dof = NULL;
+ face_to_be.DeleteAll();
+
dynamic_cast(fec)->Reset();
ndofs = NURBSext->GetNDof();
@@ -1519,6 +1574,55 @@ void FiniteElementSpace::UpdateNURBS()
bdrElem_dof = NURBSext->GetBdrElementDofTable();
}
+void FiniteElementSpace::BuildNURBSFaceToDofTable() const
+{
+ if (face_dof) { return; }
+
+ const int dim = mesh->Dimension();
+
+ // Find bdr to face mapping
+ face_to_be.SetSize(GetNF());
+ face_to_be = -1;
+ for (int b = 0; b < GetNBE(); b++)
+ {
+ int f = mesh->GetBdrElementEdgeIndex(b);
+ face_to_be[f] = b;
+ }
+
+ // Loop over faces in correct order, to prevent a sort
+ // Sort will destroy orientation info in ordering of dofs
+ Array face_dof_list;
+ Array row;
+ for (int f = 0; f < GetNF(); f++)
+ {
+ int b = face_to_be[f];
+ if (b == -1) { continue; }
+ // FIXME: this assumes the boundary element and the face element have the
+ // same orientation.
+ if (dim > 1)
+ {
+ const Element *fe = mesh->GetFace(f);
+ const Element *be = mesh->GetBdrElement(b);
+ const int nv = be->GetNVertices();
+ const int *fv = fe->GetVertices();
+ const int *bv = be->GetVertices();
+ for (int i = 0; i < nv; i++)
+ {
+ MFEM_VERIFY(fv[i] == bv[i],
+ "non-matching face and boundary elements detected!");
+ }
+ }
+ GetBdrElementDofs(b, row);
+ Connection conn(f,0);
+ for (int i = 0; i < row.Size(); i++)
+ {
+ conn.to = row[i];
+ face_dof_list.Append(conn);
+ }
+ }
+ face_dof = new Table(GetNF(), face_dof_list);
+}
+
void FiniteElementSpace::Construct()
{
// This method should be used only for non-NURBS spaces.
@@ -1526,6 +1630,7 @@ void FiniteElementSpace::Construct()
elem_dof = NULL;
bdrElem_dof = NULL;
+ face_dof = NULL;
ndofs = 0;
nedofs = nfdofs = nbdofs = 0;
@@ -1788,59 +1893,68 @@ void FiniteElementSpace::GetBdrElementDofs(int i, Array &dofs) const
void FiniteElementSpace::GetFaceDofs(int i, Array &dofs) const
{
- int j, k, nv, ne, nf, nd, dim = mesh->Dimension();
- Array V, E, Eo;
- const int *ind;
+ // If face_dof is already built, use it.
+ // If it is not and we have a NURBS space, build the face_dof and use it.
+ if (face_dof || (NURBSext && (BuildNURBSFaceToDofTable(), true)))
+ {
+ face_dof->GetRow(i, dofs);
+ }
+ else
+ {
+ int j, k, nv, ne, nf, nd, dim = mesh->Dimension();
+ Array V, E, Eo;
+ const int *ind;
- // for 1D, 2D and 3D faces
- nv = fec->DofForGeometry(Geometry::POINT);
- ne = (dim > 1) ? fec->DofForGeometry(Geometry::SEGMENT) : 0;
- if (nv > 0)
- {
- mesh->GetFaceVertices(i, V);
- }
- if (ne > 0)
- {
- mesh->GetFaceEdges(i, E, Eo);
- }
- nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0);
- nd = V.Size() * nv + E.Size() * ne + nf;
- dofs.SetSize(nd);
- if (nv > 0)
- {
- for (k = 0; k < V.Size(); k++)
+ // for 1D, 2D and 3D faces
+ nv = fec->DofForGeometry(Geometry::POINT);
+ ne = (dim > 1) ? fec->DofForGeometry(Geometry::SEGMENT) : 0;
+ if (nv > 0)
{
- for (j = 0; j < nv; j++)
- {
- dofs[k*nv+j] = V[k]*nv+j;
- }
+ mesh->GetFaceVertices(i, V);
}
- }
- nv *= V.Size();
- if (ne > 0)
- {
- for (k = 0; k < E.Size(); k++)
+ if (ne > 0)
{
- ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[k]);
- for (j = 0; j < ne; j++)
+ mesh->GetFaceEdges(i, E, Eo);
+ }
+ nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0);
+ nd = V.Size() * nv + E.Size() * ne + nf;
+ dofs.SetSize(nd);
+ if (nv > 0)
+ {
+ for (k = 0; k < V.Size(); k++)
{
- if (ind[j] < 0)
+ for (j = 0; j < nv; j++)
{
- dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) );
- }
- else
- {
- dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j];
+ dofs[k*nv+j] = V[k]*nv+j;
}
}
}
- }
- ne = nv + ne * E.Size();
- if (nf > 0)
- {
- for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++)
+ nv *= V.Size();
+ if (ne > 0)
{
- dofs[ne+k] = j;
+ for (k = 0; k < E.Size(); k++)
+ {
+ ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[k]);
+ for (j = 0; j < ne; j++)
+ {
+ if (ind[j] < 0)
+ {
+ dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) );
+ }
+ else
+ {
+ dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j];
+ }
+ }
+ }
+ }
+ ne = nv + ne * E.Size();
+ if (nf > 0)
+ {
+ for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++)
+ {
+ dofs[ne+k] = j;
+ }
}
}
}
@@ -1969,14 +2083,21 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const
fe = fec->FiniteElementForGeometry(mesh->GetFaceBaseGeometry(i));
}
- // if (NURBSext)
- // NURBSext->LoadFaceElement(i, fe);
+ if (NURBSext)
+ {
+ // Ensure 'face_to_be' is built:
+ if (!face_dof) { BuildNURBSFaceToDofTable(); }
+ MFEM_ASSERT(face_to_be[i] >= 0,
+ "NURBS mesh: only boundary faces are supported!");
+ NURBSext->LoadBE(face_to_be[i], fe);
+ }
return fe;
}
const FiniteElement *FiniteElementSpace::GetEdgeElement(int i) const
{
+ MFEM_ASSERT(mesh->Dimension() > 1, "No edges with a mesh dimension < 2");
return fec->FiniteElementForGeometry(Geometry::SEGMENT);
}
@@ -2024,11 +2145,14 @@ void FiniteElementSpace::Destroy()
if (NURBSext)
{
if (own_ext) { delete NURBSext; }
+ delete face_dof;
+ face_to_be.DeleteAll();
}
else
{
delete elem_dof;
delete bdrElem_dof;
+ delete face_dof;
delete [] bdofs;
delete [] fdofs;
diff --git a/fem/fespace.hpp b/fem/fespace.hpp
index 47044abd79..b5ae852826 100644
--- a/fem/fespace.hpp
+++ b/fem/fespace.hpp
@@ -111,7 +111,9 @@ protected:
int *fdofs, *bdofs;
mutable Table *elem_dof; // if NURBS FE space, not owned; otherwise, owned.
- Table *bdrElem_dof; // used only with NURBS FE spaces; not owned.
+ mutable Table *bdrElem_dof; // not owned only if NURBS FE space.
+ mutable Table *face_dof; // owned
+ mutable Array face_to_be; // used only with NURBS FE spaces; owned.
Array dof_elem_array, dof_ldof_array;
@@ -158,6 +160,14 @@ protected:
void Destroy();
void BuildElementToDofTable() const;
+ void BuildBdrElementToDofTable() const;
+ void BuildFaceToDofTable() const;
+
+ /** @brief Generates partial face_dof table for a NURBS space.
+
+ The table is only defined for exterior faces that coincide with a
+ boundary. */
+ void BuildNURBSFaceToDofTable() const;
/// Helpers to remove encoded sign from a DOF
static inline int DecodeDof(int dof)
@@ -206,7 +216,7 @@ protected:
virtual ~RefinementOperator();
};
- // Derefinement operator, used by the friend class InterpolationGridTransfer.
+ /// Derefinement operator, used by the friend class InterpolationGridTransfer.
class DerefinementOperator : public Operator
{
const FiniteElementSpace *fine_fes; // Not owned.
@@ -225,12 +235,12 @@ protected:
virtual ~DerefinementOperator();
};
- // This method makes the same assumptions as the method:
- // void GetLocalRefinementMatrices(
- // const FiniteElementSpace &coarse_fes, Geometry::Type geom,
- // DenseTensor &localP) const
- // which is defined below. It also assumes that the coarse fes and this have
- // the same vector dimension, vdim.
+ /** This method makes the same assumptions as the method:
+ void GetLocalRefinementMatrices(
+ const FiniteElementSpace &coarse_fes, Geometry::Type geom,
+ DenseTensor &localP) const
+ which is defined below. It also assumes that the coarse fes and this have
+ the same vector dimension, vdim. */
SparseMatrix *RefinementMatrix_main(const int coarse_ndofs,
const Table &coarse_elem_dof,
const DenseTensor localP[]) const;
@@ -248,11 +258,13 @@ protected:
/// Calculate GridFunction restriction matrix after mesh derefinement.
SparseMatrix* DerefinementMatrix(int old_ndofs, const Table* old_elem_dof);
- // This method assumes that this->mesh is a refinement of coarse_fes->mesh
- // and that the CoarseFineTransformations of this->mesh are set accordingly.
- // Another assumption is that the FEs of this use the same MapType as the FEs
- // of coarse_fes. Finally, it assumes that the spaces this and coarse_fes are
- // NOT variable-order spaces.
+ /** @brief Return in @a localP the local refinement matrices that map
+ between fespaces after mesh refinement. */
+ /** This method assumes that this->mesh is a refinement of coarse_fes->mesh
+ and that the CoarseFineTransformations of this->mesh are set accordingly.
+ Another assumption is that the FEs of this use the same MapType as the FEs
+ of coarse_fes. Finally, it assumes that the spaces this and coarse_fes are
+ NOT variable-order spaces. */
void GetLocalRefinementMatrices(const FiniteElementSpace &coarse_fes,
Geometry::Type geom,
DenseTensor &localP) const;
@@ -467,11 +479,11 @@ public:
/// Returns indexes of degrees of freedom for i'th boundary element.
virtual void GetBdrElementDofs(int i, Array &dofs) const;
- /** Returns the indexes of the degrees of freedom for i'th face
+ /** @brief eturns the indexes of the degrees of freedom for i'th face
including the dofs for the edges and the vertices of the face. */
virtual void GetFaceDofs(int i, Array &dofs) const;
- /** Returns the indexes of the degrees of freedom for i'th edge
+ /** @brief Returns the indexes of the degrees of freedom for i'th edge
including the dofs for the vertices of the edge. */
void GetEdgeDofs(int i, Array &dofs) const;
@@ -526,28 +538,59 @@ public:
is preserved. */
void ReorderElementToDofTable();
+ /** @brief Return a reference to the internal Table that stores the lists of
+ scalar dofs, for each mesh element, as returned by GetElementDofs(). */
+ const Table &GetElementToDofTable() const { return *elem_dof; }
+
+ /** @brief Return a reference to the internal Table that stores the lists of
+ scalar dofs, for each boundary mesh element, as returned by
+ GetBdrElementDofs(). */
+ const Table &GetBdrElementToDofTable() const
+ { if (!bdrElem_dof) { BuildBdrElementToDofTable(); } return *bdrElem_dof; }
+
+ /** @brief Return a reference to the internal Table that stores the lists of
+ scalar dofs, for each face in the mesh, as returned by GetFaceDofs(). In
+ this context, "face" refers to a (dim-1)-dimensional mesh entity. */
+ /** @note In the case of a NURBS space, the rows corresponding to interior
+ faces will be empty. */
+ const Table &GetFaceToDofTable() const
+ { if (!face_dof) { BuildFaceToDofTable(); } return *face_dof; }
+
+ /** @brief Initialize internal data that enables the use of the methods
+ GetElementForDof() and GetLocalDofForDof(). */
void BuildDofToArrays();
- const Table &GetElementToDofTable() const { return *elem_dof; }
- const Table &GetBdrElementToDofTable() const { return *bdrElem_dof; }
-
+ /// Return the index of the first element that contains dof @a i.
+ /** This method can be called only after setup is performed using the method
+ BuildDofToArrays(). */
int GetElementForDof(int i) const { return dof_elem_array[i]; }
+ /// Return the local dof index in the first element that contains dof @a i.
+ /** This method can be called only after setup is performed using the method
+ BuildDofToArrays(). */
int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; }
- /// Returns pointer to the FiniteElement associated with i'th element.
+ /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
+ associated with i'th element in the mesh object. */
const FiniteElement *GetFE(int i) const;
- /// Returns pointer to the FiniteElement for the i'th boundary element.
+ /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
+ associated with i'th boundary face in the mesh object. */
const FiniteElement *GetBE(int i) const;
+ /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
+ associated with i'th face in the mesh object. Faces in this case refer
+ to the MESHDIM-1 primitive so in 2D they are segments and in 1D they are
+ points.*/
const FiniteElement *GetFaceElement(int i) const;
+ /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
+ associated with i'th edge in the mesh object. */
const FiniteElement *GetEdgeElement(int i) const;
/// Return the trace element from element 'i' to the given 'geom_type'
const FiniteElement *GetTraceElement(int i, Geometry::Type geom_type) const;
- /** Mark degrees of freedom associated with boundary elements with
+ /** @brief Mark degrees of freedom associated with boundary elements with
the specified boundary attributes (marked in 'bdr_attr_is_ess').
For spaces with 'vdim' > 1, the 'component' parameter can be used
to restricts the marked vDOFs to the specified component. */
@@ -555,7 +598,7 @@ public:
Array &ess_vdofs,
int component = -1) const;
- /** Get a list of essential true dofs, ess_tdof_list, corresponding to the
+ /** @brief Get a list of essential true dofs, ess_tdof_list, corresponding to the
boundary attributes marked in the array bdr_attr_is_ess.
For spaces with 'vdim' > 1, the 'component' parameter can be used
to restricts the marked tDOFs to the specified component. */
@@ -566,19 +609,19 @@ public:
/// Convert a Boolean marker array to a list containing all marked indices.
static void MarkerToList(const Array &marker, Array &list);
- /** Convert an array of indices (list) to a Boolean marker array where all
+ /** @brief Convert an array of indices (list) to a Boolean marker array where all
indices in the list are marked with the given value and the rest are set
to zero. */
static void ListToMarker(const Array &list, int marker_size,
Array &marker, int mark_val = -1);
- /** For a partially conforming FE space, convert a marker array (nonzero
+ /** @brief For a partially conforming FE space, convert a marker array (nonzero
entries are true) on the partially conforming dofs to a marker array on
the conforming dofs. A conforming dofs is marked iff at least one of its
dependent dofs is marked. */
void ConvertToConformingVDofs(const Array &dofs, Array &cdofs);
- /** For a partially conforming FE space, convert a marker array (nonzero
+ /** @brief For a partially conforming FE space, convert a marker array (nonzero
entries are true) on the conforming dofs to a marker array on the
(partially conforming) dofs. A dof is marked iff it depends on a marked
conforming dofs, where dependency is defined by the ConformingRestriction
@@ -586,15 +629,15 @@ public:
conforming dof. */
void ConvertFromConformingVDofs(const Array &cdofs, Array &dofs);
- /** Generate the global restriction matrix from a discontinuous
+ /** @brief Generate the global restriction matrix from a discontinuous
FE space to the continuous FE space of the same polynomial degree. */
SparseMatrix *D2C_GlobalRestrictionMatrix(FiniteElementSpace *cfes);
- /** Generate the global restriction matrix from a discontinuous
+ /** @brief Generate the global restriction matrix from a discontinuous
FE space to the piecewise constant FE space. */
SparseMatrix *D2Const_GlobalRestrictionMatrix(FiniteElementSpace *cfes);
- /** Construct the restriction matrix from the FE space given by
+ /** @brief Construct the restriction matrix from the FE space given by
(*this) to the lower degree FE space given by (*lfes) which
is defined on the same mesh. */
SparseMatrix *H2L_GlobalRestrictionMatrix(FiniteElementSpace *lfes);
@@ -631,7 +674,7 @@ public:
virtual void GetTrueTransferOperator(const FiniteElementSpace &coarse_fes,
OperatorHandle &T) const;
- /** Reflect changes in the mesh: update number of DOFs, etc. Also, calculate
+ /** @brief Reflect changes in the mesh: update number of DOFs, etc. Also, calculate
GridFunction transformation operator (unless want_transform is false).
Safe to call multiple times, does nothing if space already up to date. */
virtual void Update(bool want_transform = true);
@@ -669,6 +712,7 @@ public:
return dynamic_cast(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
diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp
index eef7561099..3f1acc56be 100644
--- a/fem/gridfunc.cpp
+++ b/fem/gridfunc.cpp
@@ -236,7 +236,6 @@ void GridFunction::MakeTRef(FiniteElementSpace *f, Vector &tv, int tv_offset)
}
}
-
void GridFunction::SumFluxAndCount(BilinearFormIntegrator &blfi,
GridFunction &flux,
Array& count,
@@ -398,8 +397,16 @@ const
fes->DofsToVDofs(vdim-1, dofs);
Vector DofVal(dofs.Size()), LocVec;
const FiniteElement *fe = fes->GetFE(i);
- MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type");
- fe->CalcShape(ip, DofVal);
+ if (fe->GetMapType() == FiniteElement::VALUE)
+ {
+ fe->CalcShape(ip, DofVal);
+ }
+ else
+ {
+ ElementTransformation *Tr = fes->GetElementTransformation(i);
+ Tr->SetIntPoint(&ip);
+ fe->CalcPhysShape(*Tr, DofVal);
+ }
GetSubVector(dofs, LocVec);
return (DofVal * LocVec);
@@ -416,10 +423,17 @@ void GridFunction::GetVectorValue(int i, const IntegrationPoint &ip,
GetSubVector(vdofs, loc_data);
if (FElem->GetRangeType() == FiniteElement::SCALAR)
{
- MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
- "invalid FE map type");
Vector shape(dof);
- FElem->CalcShape(ip, shape);
+ if (FElem->GetMapType() == FiniteElement::VALUE)
+ {
+ FElem->CalcShape(ip, shape);
+ }
+ else
+ {
+ ElementTransformation *Tr = fes->GetElementTransformation(i);
+ Tr->SetIntPoint(&ip);
+ FElem->CalcPhysShape(*Tr, shape);
+ }
int vdim = fes->GetVDim();
val.SetSize(vdim);
for (int k = 0; k < vdim; k++)
@@ -617,17 +631,358 @@ 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 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);
+
+ // Compute and set the point in element 1 from fip
+ FET->SetAllIntPoints(&fip);
+ ElementTransformation & T1 = FET->GetElement1Transformation();
+ return GetValue(T1, T1.GetIntPoint(), comp);
+ }
+ }
+ break;
+ case ElementTransformation::BDR_FACE:
+ {
+ FaceElementTransformations * FET =
+ dynamic_cast(&T);
+
+ // Evaluate in neighboring element for both continuous and
+ // discontinuous fields (the integration point in T1 should have
+ // already been set).
+ 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 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);
+
+ // Compute and set the point in element 1 from fip
+ FET->SetAllIntPoints(&fip);
+ ElementTransformation & T1 = FET->GetElement1Transformation();
+ return GetVectorValue(T1, T1.GetIntPoint(), val);
+ }
+ }
+ break;
+ case ElementTransformation::BDR_FACE:
+ {
+ FaceElementTransformations * FET =
+ dynamic_cast(&T);
+
+ // Evaluate in neighboring element for both continuous and
+ // discontinuous fields (the integration point in T1 should have
+ // already been set).
+ 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) const
+ DenseMatrix &vals,
+ DenseMatrix *tr) const
{
+ if (tr)
+ {
+ T.Transform(ir, *tr);
+ }
+
const FiniteElement *FElem = fes->GetFE(T.ElementNo);
int dof = FElem->GetDof();
+
Array 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,
@@ -639,6 +994,7 @@ 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);
@@ -649,28 +1005,22 @@ 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
@@ -700,15 +1050,15 @@ int GridFunction::GetFaceVectorValues(
}
if (di == 0)
{
- Transf = fes->GetMesh()->GetFaceElementTransformations(i, 4);
+ Transf = fes->GetMesh()->GetFaceElementTransformations(i, 5);
Transf->Loc1.Transform(ir, eir);
- GetVectorValues(Transf->Elem1No, eir, vals, tr);
+ GetVectorValues(*Transf->Elem1, eir, vals, &tr);
}
else
{
- Transf = fes->GetMesh()->GetFaceElementTransformations(i, 8);
+ Transf = fes->GetMesh()->GetFaceElementTransformations(i, 10);
Transf->Loc2.Transform(ir, eir);
- GetVectorValues(Transf->Elem2No, eir, vals, tr);
+ GetVectorValues(*Transf->Elem2, eir, vals, &tr);
}
return di;
@@ -1007,107 +1357,262 @@ void GridFunction::GetVectorGradientHat(
MultAtB(loc_data_mat, dshape, gh);
}
-double GridFunction::GetDivergence(ElementTransformation &tr) const
+double GridFunction::GetDivergence(ElementTransformation &T) const
{
- double div_v;
- int elNo = tr.ElementNo;
- const FiniteElement *FElem = fes->GetFE(elNo);
- if (FElem->GetRangeType() == FiniteElement::SCALAR)
+ switch (T.ElementType)
{
- MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
- "invalid FE map type");
- DenseMatrix grad_hat;
- GetVectorGradientHat(tr, grad_hat);
- const DenseMatrix &Jinv = tr.InverseJacobian();
- div_v = 0.0;
- for (int i = 0; i < Jinv.Width(); i++)
+ case ElementTransformation::ELEMENT:
{
- for (int j = 0; j < Jinv.Height(); j++)
+ int elNo = T.ElementNo;
+ const FiniteElement *fe = fes->GetFE(elNo);
+ if (fe->GetRangeType() == FiniteElement::SCALAR)
{
- div_v += grad_hat(i, j) * Jinv(j, i);
+ MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
+ "invalid FE map type");
+ DenseMatrix grad_hat;
+ GetVectorGradientHat(T, grad_hat);
+ const DenseMatrix &Jinv = T.InverseJacobian();
+ double div_v = 0.0;
+ for (int i = 0; i < Jinv.Width(); i++)
+ {
+ for (int j = 0; j < Jinv.Height(); j++)
+ {
+ div_v += grad_hat(i, j) * Jinv(j, i);
+ }
+ }
+ return div_v;
+ }
+ else
+ {
+ // Assuming RT-type space
+ Array dofs;
+ fes->GetElementDofs(elNo, dofs);
+ Vector loc_data, divshape(fe->GetDof());
+ GetSubVector(dofs, loc_data);
+ fe->CalcDivShape(T.GetIntPoint(), divshape);
+ return (loc_data * divshape) / T.Weight();
}
}
+ break;
+ case ElementTransformation::BDR_ELEMENT:
+ {
+ // In order to properly capture the derivative of the normal component
+ // of the field (as well as the transverse divergence of the
+ // tangential compoents) we must 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, T.GetIntPoint(), fip);
+
+ // Compute and set the point in element 1 from fip
+ FET->SetAllIntPoints(&fip);
+ ElementTransformation & T1 = FET->GetElement1Transformation();
+
+ return GetDivergence(T1);
+ }
+ break;
+ case ElementTransformation::BDR_FACE:
+ {
+ // This must be a DG context so this dynamic cast must succeed.
+ FaceElementTransformations * FET =
+ dynamic_cast(&T);
+
+ // Evaluate in neighboring element (the integration point in T1 should
+ // have already been set).
+ ElementTransformation & T1 = FET->GetElement1Transformation();
+ return GetDivergence(T1);
+ }
+ break;
+ default:
+ {
+ MFEM_ABORT("GridFunction::GetDivergence: Unsupported element type \""
+ << T.ElementType << "\"");
+ }
}
- else
- {
- // Assuming RT-type space
- Array dofs;
- fes->GetElementDofs(elNo, dofs);
- Vector loc_data, divshape(FElem->GetDof());
- GetSubVector(dofs, loc_data);
- FElem->CalcDivShape(tr.GetIntPoint(), divshape);
- div_v = (loc_data * divshape) / tr.Weight();
- }
- return div_v;
+ return 0.0; // never reached
}
-void GridFunction::GetCurl(ElementTransformation &tr, Vector &curl) const
+void GridFunction::GetCurl(ElementTransformation &T, Vector &curl) const
{
- int elNo = tr.ElementNo;
- const FiniteElement *FElem = fes->GetFE(elNo);
- if (FElem->GetRangeType() == FiniteElement::SCALAR)
+ switch (T.ElementType)
{
- MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
- "invalid FE map type");
- DenseMatrix grad_hat;
- GetVectorGradientHat(tr, grad_hat);
- const DenseMatrix &Jinv = tr.InverseJacobian();
- DenseMatrix grad(grad_hat.Height(), Jinv.Width()); // vdim x FElem->Dim
- Mult(grad_hat, Jinv, grad);
- MFEM_ASSERT(grad.Height() == grad.Width(), "");
- if (grad.Height() == 3)
+ case ElementTransformation::ELEMENT:
{
- curl.SetSize(3);
- curl(0) = grad(2,1) - grad(1,2);
- curl(1) = grad(0,2) - grad(2,0);
- curl(2) = grad(1,0) - grad(0,1);
+ int elNo = T.ElementNo;
+ const FiniteElement *fe = fes->GetFE(elNo);
+ if (fe->GetRangeType() == FiniteElement::SCALAR)
+ {
+ MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
+ "invalid FE map type");
+ DenseMatrix grad_hat;
+ GetVectorGradientHat(T, grad_hat);
+ const DenseMatrix &Jinv = T.InverseJacobian();
+ // Dimensions of grad are vdim x FElem->Dim
+ DenseMatrix grad(grad_hat.Height(), Jinv.Width());
+ Mult(grad_hat, Jinv, grad);
+ MFEM_ASSERT(grad.Height() == grad.Width(), "");
+ if (grad.Height() == 3)
+ {
+ curl.SetSize(3);
+ curl(0) = grad(2,1) - grad(1,2);
+ curl(1) = grad(0,2) - grad(2,0);
+ curl(2) = grad(1,0) - grad(0,1);
+ }
+ else if (grad.Height() == 2)
+ {
+ curl.SetSize(1);
+ curl(0) = grad(1,0) - grad(0,1);
+ }
+ }
+ else
+ {
+ // Assuming ND-type space
+ Array dofs;
+ fes->GetElementDofs(elNo, dofs);
+ Vector loc_data;
+ GetSubVector(dofs, loc_data);
+ DenseMatrix curl_shape(fe->GetDof(), fe->GetDim() == 3 ? 3 : 1);
+ fe->CalcCurlShape(T.GetIntPoint(), curl_shape);
+ curl.SetSize(curl_shape.Width());
+ if (curl_shape.Width() == 3)
+ {
+ double curl_hat[3];
+ curl_shape.MultTranspose(loc_data, curl_hat);
+ T.Jacobian().Mult(curl_hat, curl);
+ }
+ else
+ {
+ curl_shape.MultTranspose(loc_data, curl);
+ }
+ curl /= T.Weight();
+ }
}
- else if (grad.Height() == 2)
+ break;
+ case ElementTransformation::BDR_ELEMENT:
{
- curl.SetSize(1);
- curl(0) = grad(1,0) - grad(0,1);
+ // In order to capture the tangential components of the curl we
+ // must 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, T.GetIntPoint(), fip);
+
+ // Compute and set the point in element 1 from fip
+ FET->SetAllIntPoints(&fip);
+ ElementTransformation & T1 = FET->GetElement1Transformation();
+
+ GetCurl(T1, curl);
}
- }
- else
- {
- // Assuming ND-type space
- Array dofs;
- fes->GetElementDofs(elNo, dofs);
- Vector loc_data;
- GetSubVector(dofs, loc_data);
- DenseMatrix curl_shape(FElem->GetDof(), FElem->GetDim() == 3 ? 3 : 1);
- FElem->CalcCurlShape(tr.GetIntPoint(), curl_shape);
- curl.SetSize(curl_shape.Width());
- if (curl_shape.Width() == 3)
+ break;
+ case ElementTransformation::BDR_FACE:
{
- double curl_hat[3];
- curl_shape.MultTranspose(loc_data, curl_hat);
- tr.Jacobian().Mult(curl_hat, curl);
+ // This must be a DG context so this dynamic cast must succeed.
+ FaceElementTransformations * FET =
+ dynamic_cast(&T);
+
+ // Evaluate in neighboring element (the integration point in T1 should
+ // have already been set).
+ ElementTransformation & T1 = FET->GetElement1Transformation();
+ GetCurl(T1, curl);
}
- else
+ break;
+ default:
{
- curl_shape.MultTranspose(loc_data, curl);
+ MFEM_ABORT("GridFunction::GetCurl: Unsupported element type \""
+ << T.ElementType << "\"");
}
- curl /= tr.Weight();
}
}
-void GridFunction::GetGradient(ElementTransformation &tr, Vector &grad) const
+void GridFunction::GetGradient(ElementTransformation &T, Vector &grad) const
{
- int elNo = tr.ElementNo;
- const FiniteElement *fe = fes->GetFE(elNo);
- MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type");
- int dim = fe->GetDim(), dof = fe->GetDof();
- DenseMatrix dshape(dof, dim);
- Vector lval, gh(dim);
- Array dofs;
+ switch (T.ElementType)
+ {
+ case ElementTransformation::ELEMENT:
+ {
+ const FiniteElement * fe = fes->GetFE(T.ElementNo);
+ MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
+ "invalid FE map type");
+ int spaceDim = fes->GetMesh()->SpaceDimension();
+ int dim = fe->GetDim(), dof = fe->GetDof();
+ DenseMatrix dshape(dof, dim);
+ Vector lval, gh(dim);
+ Array dofs;
- grad.SetSize(dim);
- fes->GetElementDofs(elNo, dofs);
- GetSubVector(dofs, lval);
- fe->CalcDShape(tr.GetIntPoint(), dshape);
- dshape.MultTranspose(lval, gh);
- tr.InverseJacobian().MultTranspose(gh, grad);
+ grad.SetSize(spaceDim);
+ fes->GetElementDofs(T.ElementNo, dofs);
+ GetSubVector(dofs, lval);
+ fe->CalcDShape(T.GetIntPoint(), dshape);
+ dshape.MultTranspose(lval, gh);
+ T.InverseJacobian().MultTranspose(gh, grad);
+ }
+ break;
+ case ElementTransformation::BDR_ELEMENT:
+ {
+ // In order to properly capture the normal component of the gradient
+ // as well as its tangential components we must 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, T.GetIntPoint(), fip);
+
+ // Compute and set the point in element 1 from fip
+ FET->SetAllIntPoints(&fip);
+ ElementTransformation & T1 = FET->GetElement1Transformation();
+
+ GetGradient(T1, grad);
+ }
+ break;
+ case ElementTransformation::BDR_FACE:
+ {
+ // This must be a DG context so this dynamic cast must succeed.
+ FaceElementTransformations * FET =
+ dynamic_cast(&T);
+
+ // Evaluate in neighboring element (the integration point in T1 should
+ // have already been set).
+ ElementTransformation & T1 = FET->GetElement1Transformation();
+ GetGradient(T1, grad);
+ }
+ break;
+ default:
+ {
+ MFEM_ABORT("GridFunction::GetGradient: Unsupported element type \""
+ << T.ElementType << "\"");
+ }
+ }
}
void GridFunction::GetGradients(ElementTransformation &tr,
@@ -1136,15 +1641,65 @@ void GridFunction::GetGradients(ElementTransformation &tr,
}
void GridFunction::GetVectorGradient(
- ElementTransformation &tr, DenseMatrix &grad) const
+ ElementTransformation &T, DenseMatrix &grad) const
{
- MFEM_ASSERT(fes->GetFE(tr.ElementNo)->GetMapType() == FiniteElement::VALUE,
- "invalid FE map type");
- DenseMatrix grad_hat;
- GetVectorGradientHat(tr, grad_hat);
- const DenseMatrix &Jinv = tr.InverseJacobian();
- grad.SetSize(grad_hat.Height(), Jinv.Width());
- Mult(grad_hat, Jinv, grad);
+ switch (T.ElementType)
+ {
+ case ElementTransformation::ELEMENT:
+ {
+ MFEM_ASSERT(fes->GetFE(T.ElementNo)->GetMapType() ==
+ FiniteElement::VALUE, "invalid FE map type");
+ DenseMatrix grad_hat;
+ GetVectorGradientHat(T, grad_hat);
+ const DenseMatrix &Jinv = T.InverseJacobian();
+ grad.SetSize(grad_hat.Height(), Jinv.Width());
+ Mult(grad_hat, Jinv, grad);
+ }
+ break;
+ case ElementTransformation::BDR_ELEMENT:
+ {
+ // In order to capture the normal component of the gradient we
+ // must 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, T.GetIntPoint(), fip);
+
+ // Compute and set the point in element 1 from fip
+ FET->SetAllIntPoints(&fip);
+ ElementTransformation & T1 = FET->GetElement1Transformation();
+
+ GetVectorGradient(T1, grad);
+ }
+ break;
+ case ElementTransformation::BDR_FACE:
+ {
+ // This must be a DG context so this dynamic cast must succeed.
+ FaceElementTransformations * FET =
+ dynamic_cast(&T);
+
+ // Evaluate in neighboring element (the integration point in T1 should
+ // have already been set).
+ ElementTransformation & T1 = FET->GetElement1Transformation();
+ GetVectorGradient(T1, grad);
+ }
+ break;
+ default:
+ {
+ MFEM_ABORT("GridFunction::GetVectorGradient: "
+ "Unsupported element type \"" << T.ElementType << "\"");
+ }
+ }
}
void GridFunction::GetElementAverages(GridFunction &avgs) const
@@ -1716,6 +2271,8 @@ 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);
@@ -1757,6 +2314,8 @@ 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);
@@ -2168,7 +2727,7 @@ double GridFunction::ComputeH1Error(
}
intorder = 2 * intorder; // <-------------
const IntegrationRule &ir =
- IntRules.Get(face_elem_transf->FaceGeom, intorder);
+ IntRules.Get(face_elem_transf->GetGeometryType(), intorder);
err_val.SetSize(ir.GetNPoints());
ell_coeff_val.SetSize(ir.GetNPoints());
// side 1
@@ -2225,7 +2784,7 @@ double GridFunction::ComputeH1Error(
}
}
face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
- transf = face_elem_transf->Face;
+ transf = face_elem_transf;
for (j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
@@ -2664,15 +3223,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;
@@ -2804,7 +3363,9 @@ 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);
+ // GetVectorValues(i, RefG->RefPts, vval, pmat);
+ ElementTransformation * T = mesh->GetElementTransformation(i);
+ GetVectorValues(*T, RefG->RefPts, vval, &pmat);
for (int j = 0; j < vval.Width(); j++)
{
diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp
index 4526f1174b..6638d93ee6 100644
--- a/fem/gridfunc.hpp
+++ b/fem/gridfunc.hpp
@@ -144,17 +144,135 @@ public:
/// Returns the values in the vertices of i'th element for dimension vdim.
void GetNodalValues(int i, Array &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;
- void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const;
+ /** Return a vector value from within the given element. */
+ virtual 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. */
+ virtual 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. */
+ virtual 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;
@@ -167,18 +285,6 @@ 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);
@@ -236,12 +342,10 @@ public:
virtual void ProjectCoefficient(Coefficient &coeff);
- // call fes -> BuildDofToArrays() before using this projection
void ProjectCoefficient(Coefficient &coeff, Array &dofs, int vd = 0);
void ProjectCoefficient(VectorCoefficient &vcoeff);
- // call fes -> BuildDofToArrays() before using this projection
void ProjectCoefficient(VectorCoefficient &vcoeff, Array &dofs);
void ProjectCoefficient(Coefficient *coeff[]);
@@ -496,11 +600,13 @@ public:
type = adios2stream::data_type::point_data) const;
#endif
- /** Write the GridFunction in VTK format. Note that Mesh::PrintVTK must be
- called first. The parameter ref > 0 must match the one used in
+ /** @brief Write the GridFunction in VTK format. Note that Mesh::PrintVTK
+ must be called first. The parameter ref > 0 must match the one used in
Mesh::PrintVTK. */
void SaveVTK(std::ostream &out, const std::string &field_name, int ref);
+ /** @brief Write the GridFunction in STL format. Note that the mesh dimension
+ must be 2 and that quad elements will be broken into two triangles.*/
void SaveSTL(std::ostream &out, int TimesToRefine = 1);
/// Destroys grid function.
@@ -633,6 +739,16 @@ 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.
@@ -737,6 +853,25 @@ 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];
diff --git a/fem/gslib.cpp b/fem/gslib.cpp
index de633f30fb..1ab15f2bdd 100644
--- a/fem/gslib.cpp
+++ b/fem/gslib.cpp
@@ -74,10 +74,7 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
dim = mesh->Dimension();
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
unsigned dof1D = fe->GetOrder() + 1;
- int NE = mesh->GetNE(),
- dof_cnt = fe->GetDof(),
- pts_cnt = NE * dof_cnt,
- gt = fe->GetGeomType();
+ const int gt = fe->GetGeomType();
if (gt == Geometry::TRIANGLE || gt == Geometry::TETRAHEDRON ||
gt == Geometry::PRISM)
@@ -93,8 +90,8 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
MFEM_ABORT("Element type not currently supported in FindPointsGSLIB.");
}
- pts_cnt = gsl_mesh.Size()/dim;
- int NEtot = pts_cnt/(int)pow(dof1D, dim);
+ const int pts_cnt = gsl_mesh.Size()/dim,
+ NEtot = pts_cnt/(int)pow(dof1D, dim);
if (dim == 2)
{
@@ -187,29 +184,41 @@ void FindPointsGSLIB::Interpolate(Array &codes,
Vector &ref_pos, const GridFunction &field_in,
Vector &field_out)
{
- Vector node_vals;
- GetNodeValues(field_in, node_vals);
- const int points_cnt = ref_pos.Size() / dim;
- MFEM_VERIFY(field_out.Size() >= points_cnt,
- " Increase size of field_out in FindPointsGSLIB::Interpolate.");
- if (dim==2)
+ FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
+ GridFunction field_in_scalar(&ind_fes);
+ Vector node_vals;
+
+ const int ncomp = field_in.FESpace()->GetVDim(),
+ points_fld = field_in.Size() / ncomp,
+ points_cnt = codes.Size();
+ field_out.SetSize(points_cnt*ncomp);
+
+ for (int i = 0; i < ncomp; i++)
{
- 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);
+ 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);
+ }
}
}
@@ -351,7 +360,7 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
const GridFunction *nodes = mesh->GetNodes();
Mesh *meshsplit = NULL;
const int NE = mesh->GetNE();
- int NEsplit;
+ int NEsplit = -1;
// Split the reference element into a reference submesh of quads or hexes.
if (gt == Geometry::TRIANGLE)
@@ -445,6 +454,7 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
}
meshsplit->FinalizeHexMesh(1, 1, true);
}
+ else { MFEM_ABORT("Unsupported geometry type."); }
// Curve the reference submesh.
H1_FECollection fec(fe->GetOrder(), dim);
diff --git a/fem/libceed/ceed.cpp b/fem/libceed/ceed.cpp
index 01f0b58a8b..e2ea93aac5 100644
--- a/fem/libceed/ceed.cpp
+++ b/fem/libceed/ceed.cpp
@@ -97,6 +97,8 @@ static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes,
Vector qweight(Q);
Vector shape_i(P);
DenseMatrix grad_i(P, dim);
+
+ CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
const Table &el_dof = fes.GetElementToDofTable();
Array tp_el_dof(el_dof.Size_of_connections());
const TensorBasisElement * tfe =
@@ -128,7 +130,15 @@ static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes,
const int el_offset = fe->GetDof() * i;
for (int j = 0; j < fe->GetDof(); j++)
{
- tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset];
+ if (compstride == 1)
+ {
+ tp_el_dof[j + el_offset] = fes.GetVDim()*
+ el_dof.GetJ()[dof_map[j] + el_offset];
+ }
+ else
+ {
+ tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset];
+ }
}
}
}
@@ -157,20 +167,23 @@ static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes,
{
for (int i = 0; i < P; i++)
{
- tp_el_dof[i + e*P] = el_dof.GetJ()[i + e*P];
+ if (compstride == 1)
+ {
+ tp_el_dof[i + e*P] = fes.GetVDim()*el_dof.GetJ()[i + e*P];
+ }
+ else
+ {
+ tp_el_dof[i + e*P] = el_dof.GetJ()[i + e*P];
+ }
}
}
}
CeedBasisCreateH1(ceed, GetCeedTopology(fe->GetGeomType()), fes.GetVDim(),
fe->GetDof(), ir.GetNPoints(), shape.GetData(),
grad.GetData(), qref.GetData(), qweight.GetData(), basis);
- CeedInterlaceMode imode = CEED_NONINTERLACED;
- if (fes.GetOrdering()==Ordering::byVDIM)
- {
- imode = CEED_INTERLACED;
- }
- CeedElemRestrictionCreate(ceed, imode, mesh->GetNE(), fe->GetDof(),
- fes.GetNDofs(), fes.GetVDim(), CEED_MEM_HOST, CEED_COPY_VALUES,
+ CeedElemRestrictionCreate(ceed, mesh->GetNE(), fe->GetDof(), fes.GetVDim(),
+ compstride, (fes.GetVDim())*(fes.GetNDofs()),
+ CEED_MEM_HOST, CEED_COPY_VALUES,
tp_el_dof.GetData(), restr);
}
@@ -215,6 +228,7 @@ static void InitCeedTensorBasisAndRestriction(const FiniteElementSpace &fes,
grad1d.GetData(), qref1d.GetData(),
qweight1d.GetData(), basis);
+ CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
const Table &el_dof = fes.GetElementToDofTable();
Array tp_el_dof(el_dof.Size_of_connections());
for (int i = 0; i < mesh->GetNE(); i++)
@@ -222,16 +236,20 @@ static void InitCeedTensorBasisAndRestriction(const FiniteElementSpace &fes,
const int el_offset = fe->GetDof() * i;
for (int j = 0; j < fe->GetDof(); j++)
{
- tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset];
+ if (compstride == 1)
+ {
+ tp_el_dof[j + el_offset] = fes.GetVDim()*
+ el_dof.GetJ()[dof_map[j] + el_offset];
+ }
+ else
+ {
+ tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset];
+ }
}
}
- CeedInterlaceMode imode = CEED_NONINTERLACED;
- if (fes.GetOrdering()==Ordering::byVDIM)
- {
- imode = CEED_INTERLACED;
- }
- CeedElemRestrictionCreate(ceed, imode, mesh->GetNE(), fe->GetDof(),
- fes.GetNDofs(), fes.GetVDim(), CEED_MEM_HOST, CEED_COPY_VALUES,
+ CeedElemRestrictionCreate(ceed, mesh->GetNE(), fe->GetDof(), fes.GetVDim(),
+ compstride, (fes.GetVDim())*(fes.GetNDofs()),
+ CEED_MEM_HOST, CEED_COPY_VALUES,
tp_el_dof.GetData(), restr);
}
@@ -298,8 +316,9 @@ void CeedPAAssemble(const CeedPAOperator& op,
CeedBasisGetNumQuadraturePoints(ceedData.basis, &nqpts);
const int qdatasize = op.qdatasize;
- CeedElemRestrictionCreateStrided(ceed, nelem, nqpts, nelem*nqpts, qdatasize,
- CEED_STRIDES_BACKEND, &ceedData.restr_i);
+ CeedElemRestrictionCreateStrided(ceed, nelem, nqpts, qdatasize,
+ nelem*nqpts*qdatasize, CEED_STRIDES_BACKEND,
+ &ceedData.restr_i);
CeedVectorCreate(ceed, mesh->GetNodes()->Size(), &ceedData.node_coords);
CeedVectorSetArray(ceedData.node_coords, CEED_MEM_HOST, CEED_USE_POINTER,
diff --git a/fem/libceed/ceed.hpp b/fem/libceed/ceed.hpp
index 53b59bd727..9fd97a114a 100644
--- a/fem/libceed/ceed.hpp
+++ b/fem/libceed/ceed.hpp
@@ -40,7 +40,7 @@ struct CeedConstCoeff
struct CeedGridCoeff
{
- GridFunction* coeff;
+ const GridFunction* coeff;
CeedBasis basis;
CeedElemRestriction restr;
CeedVector coeffVector;
diff --git a/fem/linearform.hpp b/fem/linearform.hpp
index f2d050ff29..1ab80eb3fd 100644
--- a/fem/linearform.hpp
+++ b/fem/linearform.hpp
@@ -19,7 +19,7 @@
namespace mfem
{
-/// Class for linear form - Vector with associated FE space and LFIntegrators.
+/// Vector with associated FE space and LinearFormIntegrators.
class LinearForm : public Vector
{
protected:
diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp
index adc9355d66..f9891b6bf5 100644
--- a/fem/lininteg.cpp
+++ b/fem/lininteg.cpp
@@ -63,6 +63,53 @@ void DomainLFIntegrator::AssembleDeltaElementVect(
elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
}
+void DomainLFGradIntegrator::AssembleRHSElementVect(
+ const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
+{
+ int dof = el.GetDof();
+ int spaceDim = Tr.GetSpaceDim();
+
+ dshape.SetSize(dof, spaceDim);
+
+ elvect.SetSize(dof);
+ elvect = 0.0;
+
+ const IntegrationRule *ir = IntRule;
+ if (ir == NULL)
+ {
+ int intorder = 2 * el.GetOrder();
+ ir = &IntRules.Get(el.GetGeomType(), intorder);
+ }
+
+ for (int i = 0; i < ir->GetNPoints(); i++)
+ {
+ const IntegrationPoint &ip = ir->IntPoint(i);
+
+ Tr.SetIntPoint(&ip);
+ el.CalcPhysDShape(Tr, dshape);
+
+ Q.Eval(Qvec, Tr, ip);
+ Qvec *= ip.weight * Tr.Weight();
+
+ dshape.AddMult(Qvec, elvect);
+ }
+}
+
+void DomainLFGradIntegrator::AssembleDeltaElementVect(
+ const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
+{
+ MFEM_ASSERT(vec_delta != NULL,"coefficient must be VectorDeltaCoefficient");
+ int dof = fe.GetDof();
+ int spaceDim = Trans.GetSpaceDim();
+
+ dshape.SetSize(dof, spaceDim);
+ fe.CalcPhysDShape(Trans, dshape);
+
+ vec_delta->EvalDelta(Qvec, Trans, Trans.GetIntPoint());
+
+ elvect.SetSize(dof);
+ dshape.Mult(Qvec, elvect);
+}
void BoundaryLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
@@ -112,10 +159,13 @@ void BoundaryLFIntegrator::AssembleRHSElementVect(
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
- IntegrationPoint eip;
- Tr.Loc1.Transform(ip, eip);
- Tr.Face->SetIntPoint (&ip);
+ // Set the integration point in the face and the neighboring element
+ Tr.SetAllIntPoints(&ip);
+
+ // Access the neighboring element's integration point
+ const IntegrationPoint &eip = Tr.GetElement1IntPoint();
+
double val = Tr.Face->Weight() * ip.weight * Q.Eval(*Tr.Face, ip);
el.CalcShape(eip, shape);
@@ -255,7 +305,6 @@ void VectorDomainLFIntegrator::AssembleDeltaElementVect(
MultVWt(shape, Qvec, elvec_as_mat);
}
-
void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -307,18 +356,22 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
if (ir == NULL)
{
int intorder = 2*el.GetOrder();
- ir = &IntRules.Get(Tr.FaceGeom, intorder);
+ ir = &IntRules.Get(Tr.GetGeometryType(), intorder);
}
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
- IntegrationPoint eip;
- Tr.Loc1.Transform(ip, eip);
- Tr.Face->SetIntPoint(&ip);
- Q.Eval(vec, *Tr.Face, ip);
- vec *= Tr.Face->Weight() * ip.weight;
+ // Set the integration point in the face and the neighboring element
+ Tr.SetAllIntPoints(&ip);
+
+ // Access the neighboring element's integration point
+ const IntegrationPoint &eip = Tr.GetElement1IntPoint();
+
+ // Use Tr transformation in case Q depends on boundary attribute
+ Q.Eval(vec, Tr, ip);
+ vec *= Tr.Weight() * ip.weight;
el.CalcShape(eip, shape);
for (int k = 0; k < vdim; k++)
{
@@ -330,7 +383,6 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
}
}
-
void VectorFEDomainLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -360,7 +412,6 @@ void VectorFEDomainLFIntegrator::AssembleRHSElementVect(
QF.Eval (vec, Tr, ip);
vec *= ip.weight * Tr.Weight();
-
vshape.AddMult (vec, elvect);
}
}
@@ -381,6 +432,125 @@ void VectorFEDomainLFIntegrator::AssembleDeltaElementVect(
vshape.Mult(vec, elvect);
}
+void VectorFEDomainLFCurlIntegrator::AssembleRHSElementVect(
+ const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
+{
+ int dof = el.GetDof();
+ int spaceDim = Tr.GetSpaceDim();
+ int n=(spaceDim == 3)? spaceDim : 1;
+ curlshape.SetSize(dof,n);
+ vec.SetSize(n);
+
+ elvect.SetSize(dof);
+ elvect = 0.0;
+
+ const IntegrationRule *ir = IntRule;
+ if (ir == NULL)
+ {
+ int intorder = 2*el.GetOrder();
+ ir = &IntRules.Get(el.GetGeomType(), intorder);
+ }
+
+ for (int i = 0; i < ir->GetNPoints(); i++)
+ {
+ const IntegrationPoint &ip = ir->IntPoint(i);
+
+ Tr.SetIntPoint (&ip);
+ el.CalcPhysCurlShape(Tr, curlshape);
+
+ switch (spaceDim)
+ {
+ case 3:
+ MFEM_VERIFY(QF, "VectorFunctionCoefficient not provided");
+ QF->Eval(vec, Tr, ip);
+ break;
+ case 2:
+ MFEM_VERIFY(Q, "FunctionCoefficient (Scalar) not provided");
+ vec[0] = Q->Eval(Tr, ip);
+ break;
+ default:
+ break; // This should be unreachable
+ }
+ vec *= ip.weight * Tr.Weight();
+ curlshape.AddMult (vec, elvect);
+ }
+}
+
+void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect(
+ const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
+{
+ int spaceDim = Trans.GetSpaceDim();
+ switch (spaceDim)
+ {
+ case 3:
+ MFEM_ASSERT(vec_delta != NULL,
+ "coefficient must be VectorDeltaCoefficient");
+ break;
+ case 2:
+ MFEM_ASSERT(delta != NULL,
+ "coefficient must be DeltaCoefficient");
+ break;
+ default:
+ break; // This should be unreachable
+ }
+ int dof = fe.GetDof();
+ int n=(spaceDim == 3)? spaceDim : 1;
+ curlshape.SetSize(dof, n);
+ elvect.SetSize(dof);
+ fe.CalcPhysCurlShape(Trans, curlshape);
+
+ switch (spaceDim)
+ {
+ case 3:
+ vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint());
+ curlshape.Mult(vec, elvect);
+ break;
+ case 2:
+ curlshape.GetColumn(0,elvect);
+ elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
+ break;
+ default:
+ break; // This should be unreachable
+ }
+}
+
+void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect(
+ const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
+{
+ int dof = el.GetDof();
+
+ divshape.SetSize(dof); // vector of size dof
+ elvect.SetSize(dof);
+ elvect = 0.0;
+
+ const IntegrationRule *ir = IntRule;
+ if (ir == NULL)
+ {
+ int intorder = 2 * el.GetOrder();
+ ir = &IntRules.Get(el.GetGeomType(), intorder);
+ }
+
+ for (int i = 0; i < ir->GetNPoints(); i++)
+ {
+ const IntegrationPoint &ip = ir->IntPoint(i);
+
+ Tr.SetIntPoint (&ip);
+ double val = Tr.Weight() * Q.Eval(Tr, ip);
+ el.CalcPhysDivShape(Tr, divshape);
+
+ add(elvect, ip.weight * val, divshape, elvect);
+ }
+}
+
+void VectorFEDomainLFDivIntegrator::AssembleDeltaElementVect(
+ const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
+{
+ MFEM_ASSERT(delta != NULL, "coefficient must be DeltaCoefficient");
+ elvect.SetSize(fe.GetDof());
+ fe.CalcPhysDivShape(Trans, elvect);
+ elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
+}
+
void VectorBoundaryFluxLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -446,7 +616,6 @@ void VectorFEBoundaryFluxLFIntegrator::AssembleRHSElementVect(
}
}
-
void VectorFEBoundaryTangentLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -481,7 +650,6 @@ void VectorFEBoundaryTangentLFIntegrator::AssembleRHSElementVect(
}
}
-
void BoundaryFlowIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -510,7 +678,7 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
{
order++;
}
- ir = &IntRules.Get(Tr.FaceGeom, order);
+ ir = &IntRules.Get(Tr.GetGeometryType(), order);
}
shape.SetSize(ndof);
@@ -520,12 +688,16 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
for (int p = 0; p < ir->GetNPoints(); p++)
{
const IntegrationPoint &ip = ir->IntPoint(p);
- IntegrationPoint eip;
- Tr.Loc1.Transform(ip, eip);
+
+ // Set the integration point in the face and the neighboring element
+ Tr.SetAllIntPoints(&ip);
+
+ // Access the neighboring element's integration point
+ const IntegrationPoint &eip = Tr.GetElement1IntPoint();
el.CalcShape(eip, shape);
- 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)
@@ -534,17 +706,16 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
}
else
{
- CalcOrtho(Tr.Face->Jacobian(), nor);
+ CalcOrtho(Tr.Jacobian(), nor);
}
un = vu * nor;
w = 0.5*alpha*un - beta*fabs(un);
- w *= ip.weight*f->Eval(*Tr.Elem1, eip);
+ w *= ip.weight*f->Eval(Tr, ip);
elvect.Add(w, shape);
}
}
-
void DGDirichletLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -582,30 +753,33 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect(
{
// a simple choice for the integration order; is this OK?
int order = 2*el.GetOrder();
- ir = &IntRules.Get(Tr.FaceGeom, order);
+ ir = &IntRules.Get(Tr.GetGeometryType(), order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
{
const IntegrationPoint &ip = ir->IntPoint(p);
- IntegrationPoint eip;
- Tr.Loc1.Transform(ip, eip);
- Tr.Face->SetIntPoint(&ip);
+ // Set the integration point in the face and the neighboring element
+ Tr.SetAllIntPoints(&ip);
+
+ // Access the neighboring element's integration point
+ const IntegrationPoint &eip = Tr.GetElement1IntPoint();
+
if (dim == 1)
{
nor(0) = 2*eip.x - 1.0;
}
else
{
- CalcOrtho(Tr.Face->Jacobian(), nor);
+ CalcOrtho(Tr.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.Face, ip) / Tr.Elem1->Weight();
+ w = ip.weight * uD->Eval(Tr, ip) / Tr.Elem1->Weight();
if (!MQ)
{
if (Q)
@@ -633,7 +807,6 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect(
}
}
-
void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -676,19 +849,21 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
if (ir == NULL)
{
const int order = 2*el.GetOrder(); // <-----
- ir = &IntRules.Get(Tr.FaceGeom, order);
+ ir = &IntRules.Get(Tr.GetGeometryType(), order);
}
for (int pi = 0; pi < ir->GetNPoints(); ++pi)
{
const IntegrationPoint &ip = ir->IntPoint(pi);
- IntegrationPoint eip;
- Tr.Loc1.Transform(ip, eip);
- Tr.Face->SetIntPoint(&ip);
- Tr.Elem1->SetIntPoint(&eip);
+
+ // Set the integration point in the face and the neighboring element
+ Tr.SetAllIntPoints(&ip);
+
+ // Access the neighboring element's integration point
+ const IntegrationPoint &eip = Tr.GetElement1IntPoint();
// Evaluate the Dirichlet b.c. using the face transformation.
- uD.Eval(u_dir, *Tr.Face, ip);
+ uD.Eval(u_dir, Tr, ip);
el.CalcShape(eip, shape);
el.CalcDShape(eip, dshape);
@@ -702,7 +877,7 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
}
else
{
- CalcOrtho(Tr.Face->Jacobian(), nor);
+ CalcOrtho(Tr.Jacobian(), nor);
}
double wL, wM, jcoef;
@@ -768,4 +943,58 @@ 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;
+ }
+}
+
}
diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp
index 1b8c2e19cc..43f6e980af 100644
--- a/fem/lininteg.hpp
+++ b/fem/lininteg.hpp
@@ -36,7 +36,7 @@ public:
FaceElementTransformations &Tr,
Vector &elvect);
- void SetIntRule(const IntegrationRule *ir) { IntRule = ir; }
+ virtual void SetIntRule(const IntegrationRule *ir) { IntRule = ir; }
const IntegrationRule* GetIntRule() { return IntRule; }
virtual ~LinearFormIntegrator() { }
@@ -119,6 +119,33 @@ public:
using LinearFormIntegrator::AssembleRHSElementVect;
};
+/// Class for domain integrator L(v) := (f, grad v)
+class DomainLFGradIntegrator : public DeltaLFIntegrator
+{
+private:
+ Vector shape, Qvec;
+ VectorCoefficient &Q;
+ DenseMatrix dshape;
+
+public:
+ /// Constructs the domain integrator (Q, grad v)
+ DomainLFGradIntegrator(VectorCoefficient &QF)
+ : DeltaLFIntegrator(QF), Q(QF) { }
+
+ /** Given a particular Finite Element and a transformation (Tr)
+ computes the element right hand side element vector, elvect. */
+ virtual void AssembleRHSElementVect(const FiniteElement &el,
+ ElementTransformation &Tr,
+ Vector &elvect);
+
+ virtual void AssembleDeltaElementVect(const FiniteElement &fe,
+ ElementTransformation &Trans,
+ Vector &elvect);
+
+ using LinearFormIntegrator::AssembleRHSElementVect;
+};
+
+
/// Class for boundary integration L(v) := (g, v)
class BoundaryLFIntegrator : public LinearFormIntegrator
{
@@ -252,6 +279,56 @@ public:
using LinearFormIntegrator::AssembleRHSElementVect;
};
+/// \f$ (Q, curl v)_{\Omega} \f$ for Nedelec Elements)
+class VectorFEDomainLFCurlIntegrator : public DeltaLFIntegrator
+{
+private:
+ VectorCoefficient *QF=nullptr;
+ Coefficient *Q=nullptr;
+ DenseMatrix curlshape;
+ Vector vec;
+
+public:
+ /// Constructs the domain integrator (Q, curl v)
+ VectorFEDomainLFCurlIntegrator(VectorCoefficient &F)
+ : DeltaLFIntegrator(F), QF(&F) { }
+ VectorFEDomainLFCurlIntegrator(Coefficient &F)
+ : DeltaLFIntegrator(F), Q(&F) { }
+
+ virtual void AssembleRHSElementVect(const FiniteElement &el,
+ ElementTransformation &Tr,
+ Vector &elvect);
+
+ virtual void AssembleDeltaElementVect(const FiniteElement &fe,
+ ElementTransformation &Trans,
+ Vector &elvect);
+
+ using LinearFormIntegrator::AssembleRHSElementVect;
+};
+
+/// \f$ (Q, div v)_{\Omega} \f$ for RT Elements)
+class VectorFEDomainLFDivIntegrator : public DeltaLFIntegrator
+{
+private:
+ Vector divshape;
+ Coefficient &Q;
+public:
+ /// Constructs the domain integrator (Q, div v)
+ VectorFEDomainLFDivIntegrator(Coefficient &QF)
+ : DeltaLFIntegrator(QF), Q(QF) { }
+
+ /** Given a particular Finite Element and a transformation (Tr)
+ computes the element right hand side element vector, elvect. */
+ virtual void AssembleRHSElementVect(const FiniteElement &el,
+ ElementTransformation &Tr,
+ Vector &elvect);
+
+ virtual void AssembleDeltaElementVect(const FiniteElement &fe,
+ ElementTransformation &Trans,
+ Vector &elvect);
+
+ using LinearFormIntegrator::AssembleRHSElementVect;
+};
/** \f$ (f, v \cdot n)_{\partial\Omega} \f$ for vector test function
v=(v1,...,vn) where all vi are in the same scalar FE space and f is a
@@ -283,7 +360,7 @@ class VectorFEBoundaryFluxLFIntegrator : public LinearFormIntegrator
private:
Coefficient *F;
Vector shape;
- int oa, ob; // these contol the quadrature order, see DomainLFIntegrator
+ int oa, ob; // these control the quadrature order, see DomainLFIntegrator
public:
VectorFEBoundaryFluxLFIntegrator(int a = 1, int b = -1)
@@ -426,6 +503,69 @@ 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
diff --git a/fem/nonlininteg.hpp b/fem/nonlininteg.hpp
index b6973ade7a..5c9975455d 100644
--- a/fem/nonlininteg.hpp
+++ b/fem/nonlininteg.hpp
@@ -20,10 +20,9 @@
namespace mfem
{
-/** The abstract base class NonlinearFormIntegrator is used to express the
- local action of a general nonlinear finite element operator. In addition
- it may provide the capability to assemble the local gradient operator
- and to compute the local energy. */
+/** @brief This class is used to express the local action of a general nonlinear
+ finite element operator. In addition it may provide the capability to
+ assemble the local gradient operator and to compute the local energy. */
class NonlinearFormIntegrator
{
protected:
diff --git a/fem/pbilinearform.cpp b/fem/pbilinearform.cpp
index 88bf107fa3..7c4be9fca4 100644
--- a/fem/pbilinearform.cpp
+++ b/fem/pbilinearform.cpp
@@ -198,8 +198,9 @@ void ParBilinearForm::AssembleSharedFaces(int skip_zeros)
for (int i = 0; i < nfaces; i++)
{
T = pmesh->GetSharedFaceTransformations(i);
+ int Elem2NbrNo = T->Elem2No - pmesh->GetNE();
pfes->GetElementVDofs(T->Elem1No, vdofs1);
- pfes->GetFaceNbrElementVDofs(T->Elem2No, vdofs2);
+ pfes->GetFaceNbrElementVDofs(Elem2NbrNo, vdofs2);
vdofs1.Copy(vdofs_all);
for (int j = 0; j < vdofs2.Size(); j++)
{
@@ -216,7 +217,7 @@ void ParBilinearForm::AssembleSharedFaces(int skip_zeros)
for (int k = 0; k < fbfi.Size(); k++)
{
fbfi[k]->AssembleFaceMatrix(*pfes->GetFE(T->Elem1No),
- *pfes->GetFaceNbrFE(T->Elem2No),
+ *pfes->GetFaceNbrFE(Elem2NbrNo),
*T, elemmat);
if (keep_nbr_block)
{
@@ -283,7 +284,14 @@ const
}
X.Distribute(&x);
- mat->Mult(X, Y);
+ if (ext)
+ {
+ ext->Mult(X, Y);
+ }
+ else
+ {
+ mat->Mult(X, Y);
+ }
pfes->Dof_TrueDof_Matrix()->MultTranspose(a, Y, 1.0, y);
}
diff --git a/fem/pfespace.cpp b/fem/pfespace.cpp
index 71f52e6249..1768e2bcaa 100644
--- a/fem/pfespace.cpp
+++ b/fem/pfespace.cpp
@@ -487,6 +487,11 @@ void ParFiniteElementSpace::GetBdrElementDofs(int i, Array &dofs) const
void ParFiniteElementSpace::GetFaceDofs(int i, Array &dofs) const
{
+ if (face_dof)
+ {
+ face_dof->GetRow(i, dofs);
+ return;
+ }
FiniteElementSpace::GetFaceDofs(i, dofs);
if (Conforming())
{
@@ -1167,7 +1172,7 @@ void ParFiniteElementSpace::GetFaceNbrFaceVDofs(int i, Array &vdofs) const
{
// Works for NC mesh where 'i' is an index returned by
// ParMesh::GetSharedFace() such that i >= Mesh::GetNumFaces(), i.e. 'i' is
- // the index of a ghost.
+ // the index of a ghost face.
MFEM_ASSERT(Nonconforming() && i >= pmesh->GetNumFaces(), "");
int el1, el2, inf1, inf2;
pmesh->GetFaceElements(i, &el1, &el2);
@@ -1207,11 +1212,14 @@ const FiniteElement *ParFiniteElementSpace::GetFaceNbrFE(int i) const
const FiniteElement *ParFiniteElementSpace::GetFaceNbrFaceFE(int i) const
{
+ // Works for NC mesh where 'i' is an index returned by
+ // ParMesh::GetSharedFace() such that i >= Mesh::GetNumFaces(), i.e. 'i' is
+ // the index of a ghost face.
// Works in tandem with GetFaceNbrFaceVDofs() defined above.
+
MFEM_ASSERT(Nonconforming() && !NURBSext, "");
- Geometry::Type geom = (pmesh->Dimension() == 2) ?
- Geometry::SEGMENT : Geometry::SQUARE;
- return fec->FiniteElementForGeometry(geom);
+ Geometry::Type face_geom = pmesh->GetFaceGeometryType(i);
+ return fec->FiniteElementForGeometry(face_geom);
}
void ParFiniteElementSpace::Lose_Dof_TrueDof_Matrix()
diff --git a/fem/pfespace.hpp b/fem/pfespace.hpp
index 7b030d622a..d4716260a4 100644
--- a/fem/pfespace.hpp
+++ b/fem/pfespace.hpp
@@ -347,6 +347,8 @@ public:
const FiniteElement *GetFaceNbrFE(int i) const;
const FiniteElement *GetFaceNbrFaceFE(int i) const;
const HYPRE_Int *GetFaceNbrGlobalDofMap() { return face_nbr_glob_dof_map; }
+ ElementTransformation *GetFaceNbrElementTransformation(int i) const
+ { return pmesh->GetFaceNbrElementTransformation(i); }
void Lose_Dof_TrueDof_Matrix();
void LoseDofOffsets() { dof_offsets.LoseData(); }
@@ -376,7 +378,7 @@ public:
void PrintPartitionStats();
- // Obsolete, kept for backward compatibility
+ /// Obsolete, kept for backward compatibility
int TrueVSize() const { return ltdof_size; }
};
diff --git a/fem/pgridfunc.cpp b/fem/pgridfunc.cpp
index dac6728bf2..dc8dc20237 100644
--- a/fem/pgridfunc.cpp
+++ b/fem/pgridfunc.cpp
@@ -214,7 +214,7 @@ void ParGridFunction::ExchangeFaceNbrData()
ParMesh *pmesh = pfes->GetParMesh();
face_nbr_data.SetSize(pfes->GetFaceNbrVSize());
- Vector send_data(pfes->send_face_nbr_ldof.Size_of_connections());
+ send_data.SetSize(pfes->send_face_nbr_ldof.Size_of_connections());
int *send_offset = pfes->send_face_nbr_ldof.GetI();
const int *d_send_ldof = mfem::Read(pfes->send_face_nbr_ldof.GetJMemory(),
@@ -271,6 +271,7 @@ const
{
int fes_vdim = pfes->GetVDim();
pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs);
+ const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no);
if (fes_vdim > 1)
{
int s = dofs.Size()/fes_vdim;
@@ -283,7 +284,17 @@ const
face_nbr_data.GetSubVector(dofs, LocVec);
DofVal.SetSize(dofs.Size());
}
- pfes->GetFaceNbrFE(nbr_el_no)->CalcShape(ip, DofVal);
+ if (fe->GetMapType() == FiniteElement::VALUE)
+ {
+ fe->CalcShape(ip, DofVal);
+ }
+ else
+ {
+ ElementTransformation *Tr =
+ pfes->GetFaceNbrElementTransformation(nbr_el_no);
+ Tr->SetIntPoint(&ip);
+ fe->CalcPhysShape(*Tr, DofVal);
+ }
}
else
{
@@ -291,14 +302,175 @@ const
fes->DofsToVDofs(vdim-1, dofs);
DofVal.SetSize(dofs.Size());
const FiniteElement *fe = fes->GetFE(i);
- MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type");
- fe->CalcShape(ip, DofVal);
+ if (fe->GetMapType() == FiniteElement::VALUE)
+ {
+ fe->CalcShape(ip, DofVal);
+ }
+ else
+ {
+ ElementTransformation *Tr = fes->GetElementTransformation(i);
+ Tr->SetIntPoint(&ip);
+ fe->CalcPhysShape(*Tr, DofVal);
+ }
GetSubVector(dofs, LocVec);
}
return (DofVal * LocVec);
}
+void ParGridFunction::GetVectorValue(int i, const IntegrationPoint &ip,
+ Vector &val) const
+{
+ int nbr_el_no = i - pfes->GetParMesh()->GetNE();
+ if (nbr_el_no >= 0)
+ {
+ Array dofs;
+ pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs);
+ Vector loc_data;
+ face_nbr_data.GetSubVector(dofs, loc_data);
+ const FiniteElement *FElem = pfes->GetFaceNbrFE(nbr_el_no);
+ int dof = FElem->GetDof();
+ if (FElem->GetRangeType() == FiniteElement::SCALAR)
+ {
+ Vector shape(dof);
+ if (FElem->GetMapType() == FiniteElement::VALUE)
+ {
+ FElem->CalcShape(ip, shape);
+ }
+ else
+ {
+ ElementTransformation *Tr =
+ pfes->GetParMesh()->GetFaceNbrElementTransformation(nbr_el_no);
+ Tr->SetIntPoint(&ip);
+ FElem->CalcPhysShape(*Tr, 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);
+ ElementTransformation *Tr =
+ pfes->GetParMesh()->GetFaceNbrElementTransformation(nbr_el_no);
+ Tr->SetIntPoint(&ip);
+ FElem->CalcVShape(*Tr, vshape);
+ val.SetSize(spaceDim);
+ vshape.MultTranspose(loc_data, val);
+ }
+ }
+ else
+ {
+ GridFunction::GetVectorValue(i, ip, val);
+ }
+}
+
+double ParGridFunction::GetValue(ElementTransformation &T,
+ const IntegrationPoint &ip,
+ int comp, Vector *tr) const
+{
+ // We can assume faces and edges are local
+ if (T.ElementType != ElementTransformation::ELEMENT)
+ {
+ return GridFunction::GetValue(T, ip, comp, tr);
+ }
+
+ // Check for evaluation in a local element
+ int nbr_el_no = T.ElementNo - pfes->GetParMesh()->GetNE();
+ if (nbr_el_no < 0)
+ {
+ return GridFunction::GetValue(T, ip, comp, tr);
+ }
+
+ // Evaluate using DoFs from a neighboring element
+ if (tr)
+ {
+ T.SetIntPoint(&ip);
+ T.Transform(ip, *tr);
+ }
+
+ Array dofs;
+ const FiniteElement * fe = pfes->GetFaceNbrFE(nbr_el_no);
+ pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs);
+
+ pfes->DofsToVDofs(comp-1, dofs);
+ Vector DofVal(dofs.Size()), LocVec;
+ if (fe->GetMapType() == FiniteElement::VALUE)
+ {
+ fe->CalcShape(ip, DofVal);
+ }
+ else
+ {
+ fe->CalcPhysShape(T, DofVal);
+ }
+ face_nbr_data.GetSubVector(dofs, LocVec);
+
+ return (DofVal * LocVec);
+}
+
+void ParGridFunction::GetVectorValue(ElementTransformation &T,
+ const IntegrationPoint &ip,
+ Vector &val, Vector *tr) const
+{
+ // We can assume faces and edges are local
+ if (T.ElementType != ElementTransformation::ELEMENT)
+ {
+ return GridFunction::GetVectorValue(T, ip, val, tr);
+ }
+
+ // Check for evaluation in a local element
+ int nbr_el_no = T.ElementNo - pfes->GetParMesh()->GetNE();
+ if (nbr_el_no < 0)
+ {
+ return GridFunction::GetVectorValue(T, ip, val, tr);
+ }
+
+ // Evaluate using DoFs from a neighboring element
+ if (tr)
+ {
+ T.SetIntPoint(&ip);
+ T.Transform(ip, *tr);
+ }
+
+ Array vdofs;
+ pfes->GetFaceNbrElementVDofs(nbr_el_no, vdofs);
+ const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no);
+
+ int dof = fe->GetDof();
+ Vector loc_data;
+ face_nbr_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 = pfes->GetVDim();
+ val.SetSize(vdim);
+ for (int k = 0; k < vdim; k++)
+ {
+ val(k) = shape * ((const double *)loc_data + dof * k);
+ }
+ }
+ else
+ {
+ int spaceDim = pfes->GetMesh()->SpaceDimension();
+ DenseMatrix vshape(dof, spaceDim);
+ fe->CalcVShape(T, vshape);
+ val.SetSize(spaceDim);
+ vshape.MultTranspose(loc_data, val);
+ }
+}
+
void ParGridFunction::ProjectCoefficient(Coefficient &coeff)
{
DeltaCoefficient *delta_c = dynamic_cast(&coeff);
diff --git a/fem/pgridfunc.hpp b/fem/pgridfunc.hpp
index d8f153a32e..071299325d 100644
--- a/fem/pgridfunc.hpp
+++ b/fem/pgridfunc.hpp
@@ -38,6 +38,11 @@ protected:
initialized by ExchangeFaceNbrData(). */
Vector face_nbr_data;
+ /** @brief Vector used as an MPI buffer to send face-neighbor data
+ in ExchangeFaceNbrData() to neighboring processors. */
+ //TODO: Use temporary memory to avoid CUDA malloc allocation cost.
+ Vector send_data;
+
void ProjectBdrCoefficient(Coefficient *coeff[], VectorCoefficient *vcoeff,
Array &attr);
@@ -204,6 +209,18 @@ public:
double GetValue(ElementTransformation &T)
{ return GetValue(T.ElementNo, T.GetIntPoint()); }
+ // Redefine to handle the case when T describes a face-neighbor element
+ virtual double GetValue(ElementTransformation &T, const IntegrationPoint &ip,
+ int comp = 0, Vector *tr = NULL) const;
+
+ virtual void GetVectorValue(int i, const IntegrationPoint &ip,
+ Vector &val) const;
+
+ // Redefine to handle the case when T describes a face-neighbor element
+ virtual void GetVectorValue(ElementTransformation &T,
+ const IntegrationPoint &ip,
+ Vector &val, Vector *tr = NULL) const;
+
using GridFunction::ProjectCoefficient;
virtual void ProjectCoefficient(Coefficient &coeff);
diff --git a/fem/pnonlinearform.cpp b/fem/pnonlinearform.cpp
index 75109d91d5..3ebd305ef9 100644
--- a/fem/pnonlinearform.cpp
+++ b/fem/pnonlinearform.cpp
@@ -64,12 +64,13 @@ void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
for (int i = 0; i < n_shared_faces; i++)
{
tr = pmesh->GetSharedFaceTransformations(i, true);
+ int Elem2NbrNo = tr->Elem2No - pmesh->GetNE();
fe1 = pfes->GetFE(tr->Elem1No);
- fe2 = pfes->GetFaceNbrFE(tr->Elem2No);
+ fe2 = pfes->GetFaceNbrFE(Elem2NbrNo);
pfes->GetElementVDofs(tr->Elem1No, vdofs1);
- pfes->GetFaceNbrElementVDofs(tr->Elem2No, vdofs2);
+ pfes->GetFaceNbrElementVDofs(Elem2NbrNo, vdofs2);
el_x.SetSize(vdofs1.Size() + vdofs2.Size());
X.GetSubVector(vdofs1, el_x.GetData());
diff --git a/fem/tbilinearform.hpp b/fem/tbilinearform.hpp
index 7f31a57fbd..1fa2fd896e 100644
--- a/fem/tbilinearform.hpp
+++ b/fem/tbilinearform.hpp
@@ -13,6 +13,7 @@
#define MFEM_TEMPLATE_BILINEAR_FORM
#include "../config/tconfig.hpp"
+#include "../linalg/simd.hpp"
#include "../linalg/ttensor.hpp"
#include "bilinearform.hpp"
#include "tevaluator.hpp"
@@ -23,16 +24,32 @@
namespace mfem
{
-// Templated bilinear form class, cf. bilinearform.?pp
+/** @brief Templated bilinear form class, cf. bilinearform.?pp
// complex_t - sol dof data type
+ @tparam meshType typically TMesh, which is templated on FE type
// real_t - mesh nodes, sol basis, mesh basis data type
+ @tparam solFESpace eg. H1_FiniteElementSpace
+ @tparam IR integration rule, typically TIntegrationRule, which is further
+ templated on element geometry
+ @tparam IntegratorType typically a TIntegrator, which is templated on a
+ kernel, eg. TDiffusionKernel or TMassKernel. This
+ describes what actual problem you solve.
+ @tparam solVecLayout_t describes how degrees of freedom are laid out,
+ scalar or vector, column/row major, etc.
+ @tparam complex_t data type for solution dofs
+ @tparam real_t data type for mesh nodes, solution basis, and mesh basis
+*/
template
+ typename complex_t = double, typename real_t = double,
+ typename impl_traits_t = AutoSIMDTraits >
class TBilinearForm : public Operator
{
+public:
+ typedef impl_traits_t impl_traits_type;
+
protected:
typedef complex_t complex_type;
typedef real_t real_type;
@@ -48,26 +65,47 @@ 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;
- typedef typename integ_t::template kernel::type kernel_t;
+ /// kernel_t may be TDiffusionKernel or TMassKernel
+ typedef typename integ_t::template kernel::type kernel_t;
+ /// p_assembled_t is something like a TTensor or TMatrix for partial assembly
typedef typename kernel_t::template p_asm_data::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::type f_assembled_t;
+ ///@}
+
+ typedef typename kernel_t::template
+ CoefficientEval::Type coeff_eval_t;
+
typedef TElementTransformation Trans_t;
- template struct T_result
+ struct T_result
{
static const int EvalOps =
Trans_t::template Get::EvalOps;
- typedef typename Trans_t::template Result Type;
+ typedef typename Trans_t::template Result Type;
};
typedef FieldEvaluator solFieldEval;
- template struct S_spec
+
+ /** @brief Contains matrix sizes, type of kernel (ElementMatrix is templated
+ on a kernel, e.g. ElementMatrix::Compute may be AssembleGradGrad()). */
+ struct S_spec
{
- typedef typename solFieldEval::template Spec Spec;
+ typedef typename solFieldEval::template Spec Spec;
typedef typename Spec::DataType DataType;
typedef typename Spec::ElementMatrix ElementMatrix;
};
@@ -86,7 +124,7 @@ protected:
coeff_t coeff;
- p_assembled_t *assembled_data;
+ Memory assembled_data;
const FiniteElementSpace &in_fes;
@@ -101,13 +139,17 @@ public:
solVecLayout(sol_fes),
int_rule(),
coeff(integ.coeff),
- assembled_data(NULL),
+ assembled_data(),
in_fes(sol_fes)
- { }
+ {
+ assembled_data.Reset(AB == 64 ? MemoryType::HOST_64 :
+ AB == 32 ? MemoryType::HOST_32 :
+ MemoryType::HOST);
+ }
virtual ~TBilinearForm()
{
- delete [] assembled_data;
+ assembled_data.Delete();
}
/// Get the input finite element space prolongation matrix
@@ -119,10 +161,9 @@ public:
virtual void Mult(const Vector &x, Vector &y) const
{
- if (assembled_data)
+ if (!assembled_data.Empty())
{
- const int num_elem = 1;
- MultAssembled(x, y);
+ MultAssembled(x, y);
}
else
{
@@ -135,10 +176,6 @@ public:
{
y = 0.0;
- const int BE = 1; // batch-size of elements
- typedef typename kernel_t::template
- CoefficientEval::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.
@@ -149,49 +186,49 @@ public:
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
- for (int el = 0; el < NE; el++)
+ for (int el = 0; el < NE; el += TE)
{
#if 0
- typename S_spec::DataType R;
+ typename S_spec::DataType R;
solFEval.Eval(el, R);
- typename T_result::Type F;
+ typename T_result::Type F;
T.Eval(el, F);
#else
- typename T_result::Type F;
+ typename T_result::Type F;
T.Eval(el, F);
- typename S_spec::DataType R;
+ typename S_spec::DataType R;
solFEval.Eval(el, R);
#endif
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
- kernel_t::Action(0, F, wQ, res, R);
+ for (int k = 0; k < BE; k++)
+ {
+ kernel_t::Action(k, F, wQ, res, R);
+ }
solFEval.template Assemble(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::Type coeff_eval_t;
-
Trans_t T(mesh, meshEval);
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
- if (!assembled_data)
+ if (assembled_data.Empty())
{
- assembled_data = new p_assembled_t[NE];
+ const int size = ((NE+TE-1)/TE)*BE;
+ assembled_data.New(size, assembled_data.GetMemoryType());
}
- for (int el = 0; el < NE; el++) // BE == 1
+ for (int el = 0; el < NE; el += TE)
{
- typename T_result::Type F;
+ typename T_result::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
@@ -199,28 +236,26 @@ public:
for (int k = 0; k < BE; k++)
{
- kernel_t::Assemble(k, F, wQ, res, assembled_data[el+k]);
+ kernel_t::Assemble(k, F, wQ, res, assembled_data[el/SS+k]);
}
}
}
- template
inline MFEM_ALWAYS_INLINE
void ElementAddMultAssembled(int el, solFieldEval &solFEval) const
{
- typename S_spec::DataType R;
+ typename S_spec::DataType R;
solFEval.Eval(el, R);
- for (int k = 0; k < num_elem; k++)
+ for (int k = 0; k < BE; k++)
{
- kernel_t::MultAssembled(k, assembled_data[el+k], R);
+ kernel_t::MultAssembled(k, assembled_data[el/SS+k], R);
}
solFEval.template Assemble(R);
}
// complex_t = double
- template
void MultAssembled(const Vector &x, Vector &y) const
{
y = 0.0;
@@ -229,14 +264,9 @@ public:
x.GetData(), y.GetData());
const int NE = mesh.GetNE();
- const int bNE = NE-NE%num_elem;
- for (int el = 0; el < bNE; el += num_elem)
+ for (int el = 0; el < NE; el += TE)
{
- ElementAddMultAssembled(el, solFEval);
- }
- for (int el = bNE; el < NE; el++)
- {
- ElementAddMultAssembled<1>(el, solFEval);
+ ElementAddMultAssembled(el, solFEval);
}
}
@@ -249,10 +279,10 @@ public:
solVecLayout_type solVecLayout(this->solVecLayout);
solFESpace solFES(this->solFES);
- TTensor3 xy_dof;
+ TTensor3 xy_dof;
const int NE = mesh.GetNE();
- for (int el = 0; el < NE; el++)
+ for (int el = 0; el < NE; el += TE)
{
solFES.SetElement(el);
@@ -266,98 +296,108 @@ public:
{
typedef typename meshType::FESpace_type meshFESpace;
meshFESpace meshFES(mesh.t_fes);
- typedef TTensor3 lnodes_t;
+ typedef TTensor3 lnodes_t;
const int NE = mesh.GetNE();
- sNodes.SetSize(lnodes_t::size*NE);
- real_t *lNodes = sNodes.GetData();
- for (int el = 0; el < NE; el++)
+ // 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)
{
meshFES.SetElement(el);
meshFES.VectorExtract(mesh.node_layout, mesh.Nodes,
- lnodes_t::layout, lNodes);
- lNodes += lnodes_t::size;
+ lnodes_t::layout, vsNodes);
+ vsNodes += lnodes_t::size;
}
}
- // partial assembly from "serialized" nodes
+ /// Partial assembly from "serialized" nodes
// real_t = double
void AssembleFromSerializedNodes(const Vector &sNodes)
{
- const int BE = 1; // batch-size of elements
- typedef typename kernel_t::template
- CoefficientEval::Type coeff_eval_t;
-
- Trans_t T(this->mesh, this->meshEval);
+ Trans_t T(mesh, meshEval);
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
- if (!assembled_data)
+ if (assembled_data.Empty())
{
- assembled_data = new p_assembled_t[NE];
+ const int size = ((NE+TE-1)/TE)*BE;
+ assembled_data.New(size, assembled_data.GetMemoryType());
}
- for (int el = 0; el < NE; el++)
+ const vreal_t *vsNodes = (const vreal_t*)(sNodes.GetData());
+ for (int el = 0; el < NE; el += TE)
{
- typename T_result::Type F;
- T.EvalSerialized(el, sNodes.GetData(), F);
+ typename T_result::Type F;
+ T.EvalSerialized(el, vsNodes, F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
- kernel_t::Assemble(0, F, wQ, res, assembled_data[el]);
+ for (int k = 0; k < BE; k++)
+ {
+ kernel_t::Assemble(k, F, wQ, res, assembled_data[el/SS+k]);
+ }
}
}
// complex_t = double
void Serialize(const Vector &x, Vector &sx) const
{
+ typedef TTensor3 vdof_data_t;
+
solVecLayout_t solVecLayout(this->solVecLayout);
- typedef TTensor3 vdof_data_t;
solFESpace solFES(this->solFES);
const int NE = mesh.GetNE();
- sx.SetSize(vdim*dofs*NE);
- complex_t *loc_sx = sx.GetData();
- for (int el = 0; el < NE; el++)
+ // 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)
{
solFES.SetElement(el);
- solFES.VectorExtract(solVecLayout, x, vdof_data_t::layout, loc_sx);
- loc_sx += vdim*dofs;
+ solFES.VectorExtract(solVecLayout, x, vdof_data_t::layout, vsx);
+ vsx += vdof_data_t::size;
}
}
- // 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 complex_t *loc_sx = sx.GetData();
- complex_t *loc_sy = sy.GetData();
- for (int el = 0; el < NE; el++)
+ const vreal_t *vsx = (const vreal_t*)(sx.GetData());
+ vreal_t *vsy = (vreal_t*)(sy.GetData());
+
+ for (int el = 0; el < NE; el += TE)
{
- typename S_spec<1>::DataType R;
- solFEval.EvalSerialized(loc_sx, R);
+ typename S_spec::DataType R;
+ solFEval.EvalSerialized(vsx, R);
- kernel_t::MultAssembled(0, assembled_data[el], R);
+ for (int k = 0; k < BE; k++)
+ {
+ kernel_t::MultAssembled(k, assembled_data[el/SS+k], R);
+ }
- solFEval.template AssembleSerialized(R, loc_sy);
+ solFEval.template AssembleSerialized(R, vsy);
- loc_sx += vdim*dofs;
- loc_sy += vdim*dofs;
+ vsx += vdim*dofs*BE;
+ vsy += vdim*dofs*BE;
}
}
#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::Type coeff_eval_t;
-
Trans_t T(mesh, meshEval);
solFESpace solFES(this->solFES);
solShapeEval solEval(this->solEval);
@@ -365,79 +405,100 @@ public:
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
- for (int el = 0; el < NE; el++)
+ for (int el = 0; el < NE; el += TE)
{
- f_assembled_t asm_qpt_data;
+ f_assembled_t asm_qpt_data[BE];
{
- typename T_result::Type F;
+ typename T_result::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
- kernel_t::Assemble(0, F, wQ, res, asm_qpt_data);
+ for (int k = 0; k < BE; k++)
+ {
+ kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]);
+ }
}
// For now, when vdim > 1, assume block-diagonal matrix with the same
// diagonal block for all components.
- TMatrix M_loc;
- S_spec::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++)
+ for (int k = 0; k < BE; k++)
{
- solFES.AssembleBlock(bi, bi, solVecLayout, M_loc, M);
+ const int el_k = el+SS*k;
+ if (el_k >= NE) { break; }
+
+ TMatrix 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);
+ }
}
}
}
- // 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::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++)
+ for (int el = 0; el < NE; el += TE)
{
- f_assembled_t asm_qpt_data;
+ f_assembled_t asm_qpt_data[BE];
{
- typename T_result::Type F;
+ typename T_result::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
- kernel_t::Assemble(0, F, wQ, res, asm_qpt_data);
+ for (int k = 0; k < BE; k++)
+ {
+ kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]);
+ }
}
// 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).
- TMatrix M_loc;
- S_spec::ElementMatrix::Compute(
- asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval);
+ for (int k = 0; k < BE; k++)
+ {
+ const int el_k = el+SS*k;
+ if (el_k >= NE) { break; }
- complex_t *M_data = M.GetData(el);
- M_loc.template AssignTo(M_data);
+ TMatrix 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];
+ }
+ }
+ }
+ }
}
}
- // 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::Type coeff_eval_t;
-
Trans_t T(mesh, meshEval);
solShapeEval solEval(this->solEval);
coeff_eval_t wQ(int_rule, coeff);
@@ -448,61 +509,93 @@ public:
DenseMatrix M_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros
const int NE = mesh.GetNE();
- for (int el = 0; el < NE; el++)
+ for (int el = 0; el < NE; el += TE)
{
- f_assembled_t asm_qpt_data;
+ f_assembled_t asm_qpt_data[BE];
{
- typename T_result::Type F;
+ typename T_result::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
- kernel_t::Assemble(0, F, wQ, res, asm_qpt_data);
+ for (int k = 0; k < BE; k++)
+ {
+ kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]);
+ }
}
// For now, when vdim > 1, assume block-diagonal matrix with the same
// diagonal block for all components.
- TMatrix M_loc;
- S_spec::ElementMatrix::Compute(
- asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval);
-
- if (dof_map) // switch from tensor-product ordering
+ for (int k = 0; k < BE; k++)
{
- for (int i = 0; i < dofs; i++)
+ const int el_k = el+SS*k;
+ if (el_k >= NE) { break; }
+
+ TMatrix 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 j = 0; j < dofs; j++)
+ for (int s = 0; s < SS && el_k+s < NE; s++)
{
- M_loc_perm(dof_map_[i],dof_map_[j]) = M_loc(i,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);
}
}
- for (int bi = 1; bi < vdim; bi++)
+ else if (SS == 1)
{
- 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);
+ 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);
+ }
}
else
{
- for (int bi = 0; bi < vdim; bi++)
+ for (int s = 0; s < SS && el_k+s < NE; s++)
{
- M_loc_perm.CopyMN(DM, dofs, dofs, 0, 0, bi*dofs, bi*dofs);
+ 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);
}
- 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
{
@@ -513,7 +606,7 @@ public:
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el++)
{
- TTensor3 x_dof, y_dof;
+ TTensor3 > x_dof, y_dof;
solFES.SetElement(el);
solFES.VectorExtract(solVecLayout, x, x_dof.layout, x_dof);
diff --git a/fem/tbilininteg.hpp b/fem/tbilininteg.hpp
index 4901ac25cf..177bb10e72 100644
--- a/fem/tbilininteg.hpp
+++ b/fem/tbilininteg.hpp
@@ -21,8 +21,7 @@ namespace mfem
// Templated local bilinear form integrator kernels, cf. bilininteg.?pp
-// The Integrator class combines a kernel and a coefficient
-
+/// The Integrator class combines a kernel and a coefficient
template class kernel_t>
class TIntegrator
{
@@ -38,46 +37,48 @@ public:
};
-// Mass kernel
-
+/// Mass kernel
template
struct TMassKernel
{
typedef complex_t complex_type;
- // needed for the TElementTransformation::Result class
+ /// Needed for the TElementTransformation::Result class
static const bool uses_Jacobians = true;
- // needed for the FieldEvaluator::Data class
+ /// @name Needed for the FieldEvaluator::Data class
+ ///@{
static const bool in_values = true;
static const bool in_gradients = false;
static const bool out_values = true;
static const bool out_gradients = false;
+ ///@}
- // Partially assembled data type for one element with the given number of
- // quadrature points. This type is used in partial assembly, and partially
- // assembled action.
+ /** @brief Partially assembled data type for one element with the given number of
+ quadrature points. This type is used in partial assembly, and partially
+ assembled action. */
template
struct p_asm_data { typedef TVector type; };
- // Partially assembled data type for one element with the given number of
- // quadrature points. This type is used in full element matrix assembly.
+ /** @brief Partially assembled data type for one element with the given
+ number of quadrature points. This type is used in full element matrix
+ assembly. */
template
struct f_asm_data { typedef TVector type; };
- template
+ template
struct CoefficientEval
{
- typedef typename IntRuleCoefficient::Type Type;
+ typedef typename IntRuleCoefficient::Type Type;
};
- // Method used for un-assembled (matrix free) action.
- // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
- // Q - CoefficientEval<>::Type
- // q - CoefficientEval<>::Type::result_t
- // val_qpts [M x NC x NE] - in/out data member in R
- //
- // val_qpts *= w det(J)
+ /** @brief Method used for un-assembled (matrix free) action.
+ @param k the element number
+ @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
+ @param Q CoefficientEval<>::Type
+ @param q CoefficientEval<>::Type::result_t
+ @param R val_qpts [M x NC x NE] - in/out data member in R
+ val_qpts *= w det(J) */
template
static inline MFEM_ALWAYS_INLINE
@@ -101,13 +102,16 @@ struct TMassKernel
}
}
- // Method defining partial assembly.
- // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
- // Q - CoefficientEval<>::Type
- // q - CoefficientEval<>::Type::result_t
- // A [M] - partially assembled scalars
- //
- // A = w det(J)
+ /** @brief Method defining partial assembly.
+ Result in A is the quadrature-point dependent part of element matrix
+ assembly (as opposed to part that is same for all elements),
+ A = w det(J)
+ @param k the element number
+ @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
+ @param Q CoefficientEval<>::Type
+ @param q CoefficientEval<>::Type::result_t
+ @param A [M] - partially assembled scalars
+ */
template
static inline MFEM_ALWAYS_INLINE
void Assemble(const int k, const T_result_t &F,
@@ -124,11 +128,12 @@ struct TMassKernel
}
}
- // Method for partially assembled action.
- // A [M] - partially assembled scalars
- // val_qpts [M x NC x NE] - in/out data member in R
- //
- // val_qpts *= A
+ /** @brief Method for partially assembled action.
+ @param k the element number
+ @param A [M] - partially assembled scalars
+ @param R val_qpts [M x NC x NE] - in/out data member in R
+ val_qpts *= A
+ */
template
static inline MFEM_ALWAYS_INLINE
void MultAssembled(const int k, const TVector &A, S_data_t &R)
@@ -148,51 +153,54 @@ struct TMassKernel
};
-// Diffusion kernel
-
-// complex_t - type for the assembled data
+/** @brief Diffusion kernel
+ @tparam complex_t - type for the assembled data
+*/
template
struct TDiffusionKernel;
-// Diffusion kernel in 1D
+/// Diffusion kernel in 1D
template
struct TDiffusionKernel<1,1,complex_t>
{
typedef complex_t complex_type;
- // needed for the TElementTransformation::Result class
+ /// Needed for the TElementTransformation::Result class
static const bool uses_Jacobians = true;
- // needed for the FieldEvaluator::Data class
+ /// Needed for the FieldEvaluator::Data class
+ ///@{
static const bool in_values = false;
static const bool in_gradients = true;
static const bool out_values = false;
static const bool out_gradients = true;
+ ///@}
- // Partially assembled data type for one element with the given number of
- // quadrature points. This type is used in partial assembly, and partially
- // assembled action.
+ /** @brief Partially assembled data type for one element with the given number of
+ quadrature points. This type is used in partial assembly, and partially
+ assembled action. */
template
struct p_asm_data { typedef TMatrix type; };
- // Partially assembled data type for one element with the given number of
- // quadrature points. This type is used in full element matrix assembly.
+
+ /** @brief Partially assembled data type for one element with the given number of
+ quadrature points. This type is used in full element matrix assembly. */
template
struct f_asm_data { typedef TTensor3 type; };
- template
+ template
struct CoefficientEval
{
- typedef typename IntRuleCoefficient::Type Type;
+ typedef typename IntRuleCoefficient::Type Type;
};
- // Method used for un-assembled (matrix free) action.
- // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
- // Q - CoefficientEval<>::Type
- // q - CoefficientEval<>::Type::result_t
- // grad_qpts [M x SDim x NC x NE] - in/out data member in R
- //
- // grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
+ /** @brief Method used for un-assembled (matrix free) action.
+ @param k the element number
+ @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
+ @param Q - CoefficientEval<>::Type
+ @param q - CoefficientEval<>::Type::result_t
+ @param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
+ grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts */
template
static inline MFEM_ALWAYS_INLINE
@@ -214,17 +222,20 @@ struct TDiffusionKernel<1,1,complex_t>
}
}
- // Method defining partial assembly. The pointwise Dim x Dim matrices are
- // stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2)
- // or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3)
- // matrices.
- // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
- // Q - CoefficientEval<>::Type
- // q - CoefficientEval<>::Type::result_t
- // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
- // A [M x Dim x Dim] - partially assembled Dim x Dim matrices
- //
- // A = (w/det(J)) adj(J) adj(J)^t
+
+ /** @brief Method defining partial assembly.
+ The pointwise Dim x Dim matrices are stored as symmetric (when
+ asm_type == p_asm_data, i.e. A.layout.rank == 2) or
+ non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank
+ == 3) matrices.
+ @param k the element number
+ @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
+ @param Q CoefficientEval<>::Type
+ @param q CoefficientEval<>::Type::result_t
+ @param A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
+ A [M x Dim x Dim] - partially assembled Dim x Dim matrices
+ A = (w/det(J)) adj(J) adj(J)^t
+ */
template
static inline MFEM_ALWAYS_INLINE
void Assemble(const int k, const T_result_t &F,
@@ -240,13 +251,13 @@ struct TDiffusionKernel<1,1,complex_t>
A[i] = Q.get(q,i,k) / F.Jt(i,0,0,k);
}
}
-
- // Method for partially assembled action.
- // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
- // matrices
- // grad_qpts [M x SDim x NC x NE] - in/out data member in R
- //
- // grad_qpts = A grad_qpts
+ /** @brief Method for partially assembled action.
+ @param k the element number
+ @param A [M x Dim*(Dim+1)/2] partially assembled Dim x Dim symmetric
+ matrices
+ @param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
+ grad_qpts = A grad_qpts
+ */
template
static inline MFEM_ALWAYS_INLINE
void MultAssembled(const int k, const TMatrix &A,
@@ -266,46 +277,49 @@ struct TDiffusionKernel<1,1,complex_t>
}
};
-// Diffusion kernel in 2D
+/// Diffusion kernel in 2D
template
struct TDiffusionKernel<2,2,complex_t>
{
typedef complex_t complex_type;
- // needed for the TElementTransformation::Result class
+ /// Needed for the TElementTransformation::Result class
static const bool uses_Jacobians = true;
- // needed for the FieldEvaluator::Data class
+ /// Needed for the FieldEvaluator::Data class
+ ///@{
static const bool in_values = false;
static const bool in_gradients = true;
static const bool out_values = false;
static const bool out_gradients = true;
+ ///@}
- // Partially assembled data type for one element with the given number of
- // quadrature points. This type is used in partial assembly, and partially
- // assembled action. Stores one symmetric 2 x 2 matrix per point.
+ /** @brief Partially assembled data type for one element with the given number of
+ quadrature points. This type is used in partial assembly, and partially
+ assembled action. Stores one symmetric 2 x 2 matrix per point. */
template
struct p_asm_data { typedef TMatrix type; };
- // Partially assembled data type for one element with the given number of
- // quadrature points. This type is used in full element matrix assembly.
- // Stores one general (non-symmetric) 2 x 2 matrix per point.
+ /** @brief Partially assembled data type for one element with the given number of
+ quadrature points. This type is used in full element matrix assembly.
+ Stores one general (non-symmetric) 2 x 2 matrix per point. */
template
struct f_asm_data { typedef TTensor3 type; };
- template
+ template
struct CoefficientEval
{
- typedef typename IntRuleCoefficient::Type Type;
+ typedef typename IntRuleCoefficient::Type Type;
};
- // Method used for un-assembled (matrix free) action.
- // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
- // Q - CoefficientEval<>::Type
- // q - CoefficientEval<>::Type::result_t
- // grad_qpts [M x SDim x NC x NE] - in/out data member in R
- //
- // grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
+ /** @brief Method used for un-assembled (matrix free) action.
+ @param k the element number
+ @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
+ @param Q CoefficientEval<>::Type
+ @param q CoefficientEval<>::Type::result_t
+ @param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
+ grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
+ */
template
static inline MFEM_ALWAYS_INLINE
@@ -338,17 +352,18 @@ struct TDiffusionKernel<2,2,complex_t>
}
}
- // Method defining partial assembly. The pointwise Dim x Dim matrices are
- // stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2)
- // or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3)
- // matrices.
- // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
- // Q - CoefficientEval<>::Type
- // q - CoefficientEval<>::Type::result_t
- // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
- // A [M x Dim x Dim] - partially assembled Dim x Dim matrices
- //
- // A = (w/det(J)) adj(J) adj(J)^t
+ /** @brief Method defining partial assembly.
+ The pointwise Dim x Dim matrices are stored as symmetric (when
+ asm_type == p_asm_data, i.e. A.layout.rank == 2) or non-symmetric
+ (when asm_type == f_asm_data, i.e. A.layout.rank == 3) matrices.
+ A = (w/det(J)) adj(J) adj(J)^t
+ @param k the element number
+ @param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
+ @param Q CoefficientEval<>::Type
+ @param q CoefficientEval<>::Type::result_t
+ @param A [M x Dim*(Dim+1)/2] partially assembled Dim x Dim symm. matrices
+ @param A [M x Dim x Dim] partially assembled Dim x Dim matrices
+ */
template
static inline MFEM_ALWAYS_INLINE
void Assemble(const int k, const T_result_t &F,
@@ -376,12 +391,13 @@ struct TDiffusionKernel<2,2,complex_t>
}
}
- // Method for partially assembled action.
- // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
- // matrices
- // grad_qpts [M x SDim x NC x NE] - in/out data member in R
- //
- // grad_qpts = A grad_qpts
+ /** @brief Method for partially assembled action.
+ @param k the element number
+ @param A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
+ matrices
+ @param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
+ grad_qpts = A grad_qpts
+ */
template
static inline MFEM_ALWAYS_INLINE
void MultAssembled(const int k, const TMatrix &A,
@@ -407,46 +423,48 @@ struct TDiffusionKernel<2,2,complex_t>
}
};
-// Diffusion kernel in 3D
+/// Diffusion kernel in 3D
template
struct TDiffusionKernel<3,3,complex_t>
{
typedef complex_t complex_type;
- // needed for the TElementTransformation::Result class
+ /// Needed for the TElementTransformation::Result class
static const bool uses_Jacobians = true;
- // needed for the FieldEvaluator::Data class
+ /// Needed for the FieldEvaluator::Data class
+ ///@{
static const bool in_values = false;
static const bool in_gradients = true;
static const bool out_values = false;
static const bool out_gradients = true;
+ ///@}
- // Partially assembled data type for one element with the given number of
- // quadrature points. This type is used in partial assembly, and partially
- // assembled action. Stores one symmetric 3 x 3 matrix per point.
+ /** @brief Partially assembled data type for one element with the given number of
+ quadrature points. This type is used in partial assembly, and partially
+ assembled action. Stores one symmetric 3 x 3 matrix per point. */
template
struct p_asm_data { typedef TMatrix type; };
- // Partially assembled data type for one element with the given number of
- // quadrature points. This type is used in full element matrix assembly.
- // Stores one general (non-symmetric) 3 x 3 matrix per point.
+ /** @brief Partially assembled data type for one element with the given number of
+ quadrature points. This type is used in full element matrix assembly.
+ Stores one general (non-symmetric) 3 x 3 matrix per point. */
template
struct f_asm_data { typedef TTensor3 type; };
- template
+ template
struct CoefficientEval
{
- typedef typename IntRuleCoefficient::Type Type;
+ typedef typename IntRuleCoefficient::Type Type;
};
- // Method used for un-assembled (matrix free) action.
- // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
- // Q - CoefficientEval<>::Type
- // q - CoefficientEval<>::Type::result_t
- // grad_qpts [M x SDim x NC x NE] - in/out data member in R
- //
- // grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
+ /** @brief Method used for un-assembled (matrix free) action.
+ grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
+ Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
+ Q - CoefficientEval<>::Type
+ q - CoefficientEval<>::Type::result_t
+ grad_qpts [M x SDim x NC x NE] - in/out data member in R
+ */
template
static inline MFEM_ALWAYS_INLINE
@@ -477,17 +495,18 @@ struct TDiffusionKernel<3,3,complex_t>
}
}
- // Method defining partial assembly. The pointwise Dim x Dim matrices are
- // stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2)
- // or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3)
- // matrices.
- // Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
- // Q - CoefficientEval<>::Type
- // q - CoefficientEval<>::Type::result_t
- // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
- // A [M x Dim x Dim] - partially assembled Dim x Dim matrices
- //
- // A = (w/det(J)) adj(J) adj(J)^t
+ /** @brief Method defining partial assembly.
+ The pointwise Dim x Dim matrices are stored as symmetric (when
+ asm_type == p_asm_data, i.e. A.layout.rank == 2) or
+ non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank
+ == 3) matrices.
+ A = (w/det(J)) adj(J) adj(J)^t
+ Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
+ Q - CoefficientEval<>::Type
+ q - CoefficientEval<>::Type::result_t
+ A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
+ A [M x Dim x Dim] - partially assembled Dim x Dim matrices
+ */
template
static inline MFEM_ALWAYS_INLINE
void Assemble(const int k, const T_result_t &F,
@@ -518,12 +537,12 @@ struct TDiffusionKernel<3,3,complex_t>
}
}
- // Method for partially assembled action.
- // A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
- // matrices
- // grad_qpts [M x SDim x NC x NE] - in/out data member in R
- //
- // grad_qpts = A grad_qpts
+ /** @brief Method for partially assembled action.
+ A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
+ matrices
+ grad_qpts [M x SDim x NC x NE] - in/out data member in R
+ grad_qpts = A grad_qpts
+ */
template
static inline MFEM_ALWAYS_INLINE
void MultAssembled(const int k, const TMatrix &A,
diff --git a/fem/tcoefficient.hpp b/fem/tcoefficient.hpp
index 19c14cb054..06e6ff0024 100644
--- a/fem/tcoefficient.hpp
+++ b/fem/tcoefficient.hpp
@@ -21,7 +21,7 @@
namespace mfem
{
-// Templated coefficient classes, cf. coefficient.?pp
+/// Templated coefficient classes, cf. coefficient.?pp
class TCoefficient
{
@@ -56,12 +56,13 @@ public:
};
-// Function coefficient. The template class 'Func' has to implement at least one
-// of the following methods, depending on the dimension that will be used:
-// complex_t Eval1D(real_t);
-// complex_t Eval2D(real_t,real_t);
-// complex_t Eval3D(real_t,real_t,real_t);
-// Use MFEM_FLOPS_ADD() to count flops inside Eval*D.
+/** @brief Function coefficient.
+ @tparam Func has to implement at least one of the following methods,
+ depending on the dimension that will be used:
+ complex_t Eval1D(real_t);
+ complex_t Eval2D(real_t,real_t);
+ complex_t Eval3D(real_t,real_t,real_t);
+ Use MFEM_FLOPS_ADD() to count flops inside Eval*D. */
template
class TFunctionCoefficient : public TCoefficient
{
@@ -81,11 +82,15 @@ 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++)
{
- c[l.ind(i,k)] = F.Eval1D(T.x(i,0,k));
+ for (int s = 0; s < vs; s++)
+ {
+ c[l.ind(i,k)][s] = F.Eval1D(T.x(i,0,k)[s]);
+ }
}
}
}
@@ -98,11 +103,15 @@ 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++)
{
- c[l.ind(i,k)] = F.Eval2D(T.x(i,0,k), T.x(i,1,k));
+ 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]);
+ }
}
}
}
@@ -115,20 +124,25 @@ 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++)
{
- c[l.ind(i,k)] = F.Eval3D(T.x(i,0,k), T.x(i,1,k), T.x(i,2,k));
+ 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]);
+ }
}
}
}
};
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.
@@ -170,14 +184,21 @@ 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++)
{
- TAssign(l.ind2(i), c, constants(T.attrib[i]-1));
+ typename c_data_t::data_type ci;
+ for (int s = 0; s < vs; s++)
+ {
+ ci[s] = constants(T.attrib[i][s]-1);
+ }
+ TAssign(l.ind2(i), c, ci);
}
}
};
-
+/// GridFunction coefficient class.
template
class TGridFunctionCoefficient : public TCoefficient
{
@@ -243,12 +264,13 @@ public:
/// Auxiliary class that is used to simplify the evaluation of a coefficient and
/// scaling it by the weights of a quadrature rule.
-template
+template
struct IntRuleCoefficient
{
static const int qpts = IR::qpts;
- static const int ne = NE;
+ static const int ne = impl_traits_t::batch_size;
typedef typename coeff_t::complex_type complex_type;
+ typedef typename impl_traits_t::vcomplex_t vcomplex_t;
template struct Aux;
@@ -277,7 +299,7 @@ struct IntRuleCoefficient
// non-constant coefficient
template struct Aux
{
- typedef TMatrix result_t;
+ typedef TMatrix result_t;
#ifdef MFEM_TEMPLATE_INTRULE_COEFF_PRECOMP
TMatrix w;
#else
@@ -312,7 +334,7 @@ struct IntRuleCoefficient
}
inline MFEM_ALWAYS_INLINE
- const complex_type &get(const result_t &res, int i, int k) const
+ const vcomplex_t &get(const result_t &res, int i, int k) const
{
return res(i,k);
}
diff --git a/fem/teltrans.hpp b/fem/teltrans.hpp
index 5cdfb9e86f..c0f3cb41ec 100644
--- a/fem/teltrans.hpp
+++ b/fem/teltrans.hpp
@@ -21,12 +21,14 @@ namespace mfem
// Templated element transformation classes, cf. eltrans.?pp
-// Element transformation class, templated on a mesh type and an integration
-// rule. It is constructed from a mesh (e.g. class TMesh) and shape evaluator
-// (e.g. class ShapeEvaluator) objects. Allows computation of physical
-// coordinates and Jacobian matrices corresponding to the reference integration
-// points. The desired result is specified through the template subclass Result
-// and stored in an object of the same type.
+/** @brief Element transformation class, templated on a mesh type and an
+ integration rule.
+ It is constructed from a mesh (e.g. class TMesh) and shape evaluator
+ (e.g. class ShapeEvaluator) objects. Allows computation of physical
+ coordinates and Jacobian matrices corresponding to the reference integration
+ points. The desired result is specified through the template subclass Result
+ and stored in an object of the same type.
+*/
template
class TElementTransformation
{
@@ -39,9 +41,9 @@ public:
typedef TElementTransformation T_type;
- // Enumeration for the result type of the TElementTransformation::Eval()
- // method. The types can obtained by summing constants from this enumeration
- // and used as a template parameter in struct Result.
+ /// Enumeration for the result type of the TElementTransformation::Eval()
+ /// method. The types can obtained by summing constants from this enumeration
+ /// and used as a template parameter in struct Result.
enum EvalOperations
{
EvalNone = 0,
@@ -51,6 +53,8 @@ public:
LoadElementIdxs = 8
};
+ /// Determines at compile-time the operations needed for given coefficient
+ /// and kernel
template struct Get
{
static const int EvalOps =
@@ -61,12 +65,14 @@ public:
(EvalJacobians * kernel_t::uses_Jacobians);
};
- // Templated struct Result, used to specify the type result that is computed
- // by the TElementTransformation::Eval() method and stored in this structure.
- // The template parameter EvalOps is a sum (bitwise or) of constants from
- // the enum EvalOperations. The parameter NE is the number of elements to be
- // processed in the Eval() method.
- template struct Result;
+ /** @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 struct Result;
static const int dim = Mesh_t::dim;
static const int sdim = Mesh_t::space_dim;
@@ -85,13 +91,17 @@ protected:
const Element* const *elements;
- template
+ template
inline MFEM_ALWAYS_INLINE
- void SetAttributes(int el, int (&attrib)[NE]) const
+ void SetAttributes(int el, vint_t (&attrib)[NE]) const
{
+ const int vsize = sizeof(vint_t)/sizeof(attrib[0][0]);
for (int i = 0; i < NE; i++)
{
- attrib[i] = elements[el+i]->GetAttribute();
+ for (int j = 0; j < vsize; i++)
+ {
+ attrib[i][j] = elements[el+j+i*vsize]->GetAttribute();
+ }
}
}
@@ -105,26 +115,31 @@ public:
elements(mesh.m_mesh.GetElementsArray())
{ }
- // Evaluate coordinates and/or Jacobian matrices at quadrature points.
- template
+ /// Evaluate coordinates and/or Jacobian matrices at quadrature points.
+ template
inline MFEM_ALWAYS_INLINE
- void Eval(int el, Result &F)
+ void Eval(int el, Result &F)
{
F.Eval(el, *this);
}
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
- template
+ template
inline MFEM_ALWAYS_INLINE
- void EvalSerialized(int el, const real_t *nodeData, Result &F)
+ void EvalSerialized(int el, const typename impl_traits_t::vreal_t *nodeData,
+ Result &F)
{
F.EvalSerialized(el, *this, nodeData);
}
#endif
- template struct Result<0,NE> // 0 = EvalNone
+ // Specialization of the Result<> class
+
+ // Case EvalOps = 0 = EvalNone
+ template struct Result<0,it_t>
{
- static const int ne = NE;
+ static const int ne = it_t::batch_size;
+ typedef typename it_t::vreal_t vreal_t;
// x_type x;
// Jt_type Jt;
// int attrib[NE];
@@ -137,20 +152,23 @@ public:
}
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
- void EvalSerialized(int el, T_type &T, const real_t *nodeData) { }
+ void EvalSerialized(int el, T_type &T, const vreal_t *nodeData) { }
#endif
};
- template struct Result<1,NE> // 1 = EvalCoordinates
+
+ // Case EvalOps = 1 = EvalCoordinates
+ template struct Result<1,it_t>
{
- static const int ne = NE;
+ static const int ne = it_t::batch_size;
+ typedef typename it_t::vreal_t vreal_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
- typedef TTensor3 x_type;
+ typedef TTensor3