Compare commits

..
266 changed files with 6089 additions and 36171 deletions
-18
View File
@@ -29,8 +29,6 @@ config/sample-runs-build.log
doc/CodeDocumentation.conf
doc/CodeDocumentation.html
doc/CodeDocumentation
doc/undoc.log
doc/warnings.log
# Temporary files created by the tests.
*.stderr
@@ -74,10 +72,6 @@ examples/deformed.*
examples/velocity.*
examples/elastic_energy.*
examples/mode_*
examples/ex5-p-*.bp
examples/ex9-p-*.bp
examples/ex12-p-*.bp
examples/ex16-p-*.bp
examples/ex16.mesh
examples/ex16-mesh.*
examples/ex16-init.*
@@ -169,11 +163,8 @@ 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
miniapps/meshing/pminimal-surface
miniapps/meshing/mobius-strip.mesh
miniapps/meshing/klein-bottle.mesh
@@ -183,7 +174,6 @@ miniapps/meshing/mesh-explorer.mesh
miniapps/meshing/partitioning.txt
miniapps/meshing/shaper.mesh
miniapps/meshing/extruder.mesh
miniapps/meshing/trimmer.mesh
miniapps/meshing/optimized*
miniapps/meshing/perturbed*
@@ -235,14 +225,6 @@ miniapps/gslib/field-diff
miniapps/gslib/findpts
miniapps/gslib/pfindpts
miniapps/navier/navier_mms
miniapps/navier/navier_kovasznay
miniapps/navier/navier_tgv
miniapps/navier/navier_shear
miniapps/navier/navier_3dfoc
miniapps/navier/tgv_out*.txt
miniapps/navier/*_output
# Unit test binary and outputs
tests/unit/output_meshes
tests/unit/unit_tests
+6 -3
View File
@@ -11,6 +11,8 @@
language: cpp
sudo: false
stages:
- checks
- tests
@@ -368,10 +370,8 @@ script:
# Compiler
- if [ $MPI == "YES" ]; then
export MYCXX=mpic++;
export MAKE_CXX_FLAG=MPICXX=$MYCXX;
else
export MYCXX="$CXX";
export MAKE_CXX_FLAG=CXX=$MYCXX;
fi
# Print the compiler version
@@ -384,9 +384,12 @@ script:
if [ "$CODECOV" == "YES" ]; then
CPPFLAGS="--coverage -g";
fi;
if [ "$CXX" == "clang++" ]; then
export MFEM_PERF_SW=clang;
fi
# Configure the library
- make config MFEM_USE_MPI=$MPI MFEM_DEBUG=$DEBUG $MAKE_CXX_FLAG
- make config MFEM_USE_MPI=$MPI MFEM_DEBUG=$DEBUG MFEM_CXX="$MYCXX"
MFEM_MPI_NP=$NPROCS CPPFLAGS="$CPPFLAGS"
# Show the configuration
- make info
+9 -108
View File
@@ -23,110 +23,19 @@ 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.
Discretization improvements
---------------------------
- Added support for matrix-free interpolation and restriction operators between
continuous H1 finite element spaces of different order on the same mesh or
with the same order on uniformly refined meshes.
- Added support for simplices in GSLIB-FindPoints.
- Added support for H1 and L2 element matrix assembly in the mass, convection,
diffusion, transpose, and the face DG trace integrators. This is compatible
with GPU device execution and is illustrated in Example 9/9p, see the option
'-ea'. When enabled, this level of assembly stores independent dense matrices
for the elements, and independent dense matrices for the faces in the DG case.
- Added new partial assembly kernels for H(div) bilinear forms, as well as
VectorFEDivergenceIntegrator.
- Improved the documentation of the GridFunction GetValue and GetVectorValue
methods. Expanded the GetValue and GetVectorValue methods which accept an
ElementTransformation argument to support evaluation on boundary elements
and, in the continuous field case, arbitrary mesh edges and faces.
- Added new coefficient and vector coefficient classes for QuadratureFunctions.
Additionaly, new LinearForm integrators were also added which make use of
these new QuadratureFunction coefficient classes.
- Added support face integrals on the boundaries of NURBS meshes.
Linear and nonlinear solvers
----------------------------
- Added power method to iteratively estimate the largest eigenvalue and the
corresponding eigenvector of an operator.
- Added initial support for h- and p-multigrid solvers and preconditioners for
matrix-based and matrix-free discretizations with basic GPU capability.
- Added a new IterativeSolverMonitor class that allows to monitor the residual
and solution during the solving process of an IterativeSolver after every
iteration.
- Block arrays of parallel matrices can now be merged into a single parallel
matrix with the function HypreParMatrixFromBlocks. This could be useful for
solving block systems with parallel direct solvers such as STRUMPACK.
- In SLISolver, changed the residual inner product from (Br,r) to (Br,Br) so the
solver can work with non-SPD preconditioner B.
New and updated examples and miniapps
-------------------------------------
- Adding a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of
stitching together opposite surfaces of a mesh to create a topologically
periodic mesh.
- Added a new example, Example 25/25p, to demonstrate the use of a Perfectly
Matched Layer (PML) for the simulation of electromagnetic wave propagation.
The example defines and solves several indefinite Maxwell problems.
- Added a new Example 26/26p to demonstrate the construction of a matrix-free
geometric and p-multigrid preconditioner for the Laplace problem.
- Added a new example, Example 27/27p, to demonstrate the enforcement of various
boundary conditions with the Laplace operator. The example shows the procedure
for applying Dirichlet, Neumann (both homogeneous and inhomogeneous), Robin,
and periodic boundary conditions with either H1 or DG discretizations.
- Added a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of
stitching together opposite surfaces of a mesh to create a topologically
periodic mesh.
- Added a new meshing miniapp, Minimal Surface, which solves Plateau's problem:
the Dirichlet problem for the minimal surface equation.
- Added partial assembly support to examples 4/4p and 5/5p, with diagonal
preconditioning.
- Added a new test problem in example 24/24p, demonstrating a mixed bilinear
form for H(div) and L_2, with partial assembly support.
- Added weak Dirichlet boundary conditions (Nitsche) to the NURBS miniapp.
- Added a simple mesh editing miniapp, Trimmer, which trims away portions of a
mesh based on element attributes. Any newly exposed boundary elements are
assigned attribute numbers related to the trimmed element attributes.
Discretization improvements
---------------------------
- Added support for simplices in GSLIB-FindPoints.
Improved testing
----------------
@@ -137,16 +46,8 @@ Improved testing
Miscellaneous
-------------
- Added support for ADIOS2 for parallel I/O with ParaView visualization. The
classes adios2stream and ADIOS2DataCollection are introduced in mfem as the
interfaces to generate ADIOS2 Binary Pack (BP4) directory datasets for the
entire spatial and temporal data. In addition, ADIOS2 allows for setting a
user-defined number of data substreams/subfiles. See examples 5, 9, 12, 16.
- The integration order used in the ComputeLpError and ComputeElementLpError
methods of class GridFunction has been increased.
- Various other simplifications, extensions, and bugfixes in the code.
- In SLISolver, changed the residual inner product from (Br,r) to (Br,Br) so the
solver can work with non-SPD preconditioner B.
Version 4.1, released on March 10, 2020
+1 -6
View File
@@ -323,11 +323,6 @@ if (MFEM_USE_UMPIRE)
find_package(UMPIRE REQUIRED)
endif()
# ADIOS2 for parallel I/O
if (MFEM_USE_ADIOS2)
find_package(ADIOS2 REQUIRED)
endif()
# MFEM_TIMER_TYPE
if (NOT DEFINED MFEM_TIMER_TYPE)
if (APPLE)
@@ -353,7 +348,7 @@ endif()
# 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
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2)
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
set(TPL_INCLUDE_DIRS "")
+1 -9
View File
@@ -383,13 +383,9 @@ Before a PR can be merged, it should satisfy the following:
- [ ] Is this a new feature users need to be aware of? New or updated example or miniapp?
- [ ] Does it make sense to create a new section in the `CHANGELOG` to group with other related features?
- [ ] Update `INSTALL`:
- [ ] Had a new optional library been added? If so, what range of versions of this library are required? (*Make sure the external library is compatible with our BSD license, e.g. it is not licensed under GPL!*)
- [ ] Have the version ranges for any required or optional libraries changed?
- [ ] Had a new optional library been added? (*Make sure the external library is compatible with our BSD license, e.g. it is not licensed under GPL!*)
- [ ] Does `make` or `cmake` have a new target?
- [ ] Did the requirements or the installation process change? *(rare)*
- [ ] Update continuous integration server configurations if necessary (e.g. with new version requirements for each of MFEM's dependencies)
- [ ] `.travis.yml`
- [ ] `.appveyor.yml`
- [ ] Update `.gitignore`:
- [ ] Check if `make distclean; git status` shows any files that were generated from the source by the project (not an IDE) but we don't want to track in the repository.
- [ ] Add new patterns (just for the new files above) and re-run the above test.
@@ -503,10 +499,6 @@ MFEM uses a `master`/`next`-branch workflow as described below:
- [ ] `makefile`
- [ ] `CMakeLists.txt`
- [ ] `doc/CodeDocumentation.conf.in`
- [ ] Check that version requirements for each of MFEM's dependencies are documented in `INSTALL` and up-to-date
- [ ] Check that continuous integration server configurations reflect the dependency version requirements of the new release
- [ ] `.travis.yml`
- [ ] `.appveyor.yml`
- [ ] (LLNL only) Make sure all `README.html` files in the source repo are up to date.
- [ ] Tag the repository:
-35
View File
@@ -396,12 +396,6 @@ MFEM_USE_SIDRE = YES/NO
blueprint specification. When enabled, this option requires installation of
HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project.
MFEM_USE_SIMD = YES/NO
Enables the high performance templated classes to use architecture dependent
SIMD intrinsics instead of the generic implementation of class AutoSIMD in
linalg/simd/auto.hpp. This option should be combined with suitable
compiler options, such as -march=native, to enable optimal vectorization.
MFEM_USE_CONDUIT = YES/NO
Enables support for converting MFEM Mesh and Grid Function objects to and
from Conduit Mesh Blueprint Descriptions (https://github.com/LLNL/conduit/)
@@ -409,11 +403,6 @@ MFEM_USE_CONDUIT = YES/NO
an installation of Conduit. If Conduit was built with HDF5 support, it also
requires an installation of HDF5 (see also MFEM_USE_NETCDF).
MFEM_USE_ADIOS2 = YES/NO
Enables support for ADIOS2, version 2 of the adaptable input output system
for scientific data management. In MFEM, ADIOS2 provides parallel I/O with
ParaView visualization.
MFEM_USE_ZLIB = YES/NO
Enables use of on-the-fly gzip compressed streams. With this feature enabled
(YES), MFEM can compress its output files on-the-fly. In addition, it can
@@ -432,8 +421,6 @@ MFEM_USE_PUMI = YES/NO
data management system that is capable of handling general non-manifold
models and effectively supports automated adaptive analysis. PUMI enables
support for parallel unstructured mesh modifications in MFEM.
The develop branch of PUMI repository (https://github.com/SCOREC/core)
should be used for most updated features.
MFEM_USE_UMPIRE = YES/NO
Enables support for Umpire, a resource management library that allows the
@@ -505,13 +492,11 @@ The specific libraries and their options are:
- HYPRE, required for the parallel build, i.e. when MFEM_USE_MPI = YES.
URL: https://github.com/hypre-space/hypre and https://www.llnl.gov/casc/hypre
Options: HYPRE_OPT, HYPRE_LIB.
Versions: HYPRE >= 2.10.0b.
- METIS, used when MFEM_USE_METIS = YES. If using METIS 5, set
MFEM_USE_METIS_5 = YES (default is to use METIS 4).
URL: http://glaros.dtc.umn.edu/gkhome/metis/metis/overview
Options: METIS_OPT, METIS_LIB.
Versions: METIS 4.0.3 or 5.1.0.
- LAPACK (optional), used when MFEM_USE_LAPACK = YES. Alternative, optimized
implementations can also be used, e.g. the ATLAS project.
@@ -535,7 +520,6 @@ The specific libraries and their options are:
both MPI and hypre.
URL: http://computation.llnl.gov/projects/sundials/sundials-software
Options: SUNDIALS_OPT, SUNDIALS_LIB.
Versions: SUNDIALS >= 5.0.0.
- Mesquite (optional), used when MFEM_USE_MESQUITE = YES.
URL: http://trilinos.org/oldsite/packages/mesquite
@@ -544,7 +528,6 @@ The specific libraries and their options are:
- SuiteSparse (optional), used when MFEM_USE_SUITESPARSE = YES.
URL: http://faculty.cse.tamu.edu/davis/suitesparse.html
Options: SUITESPARSE_OPT, SUITESPARSE_LIB.
Versions: SuiteSparse >= 4.5.4, older versions may work too.
- SuperLU_DIST (optional), used when MFEM_USE_SUPERLU = YES. Note that
SuperLU_DIST requires ParMETIS, which includes METIS 5 in its distribution.
@@ -552,7 +535,6 @@ The specific libraries and their options are:
same location.
URL: http://crd-legacy.lbl.gov/~xiaoye/SuperLU
Options: SUPERLU_OPT, SUPERLU_LIB.
Versions: SuperLU_DIST >= 5.1.0.
- STRUMPACK (optional), used when MFEM_USE_STRUMPACK = YES. Note that STRUMPACK
requires the PT-Scotch and Scalapack libraries as well as ParMETIS, which
@@ -562,7 +544,6 @@ The specific libraries and their options are:
2.0.0 or later.
URL: http://portal.nersc.gov/project/sparse/strumpack
Options: STRUMPACK_OPT, STRUMPACK_LIB.
Versions: STRUMPACK >= 3.0.0, requires HYPRE < 2.16.0.
- Ginkgo (optional), used when MFEM_USE_GINKGO = YES. Note that Ginkgo needs a
C++ compiler that supports the C++-11 standard. For additional requirements
@@ -575,7 +556,6 @@ The specific libraries and their options are:
one can get the library through the Homebrew package manager (http://brew.sh).
URL: http://gnutls.org
Options: GNUTLS_OPT, GNUTLS_LIB.
Versions: GnuTLS >= 2.12.0, older versions may work too.
- NetCDF (optional), used when MFEM_USE_NETCDF = YES, required for reading Cubit
mesh files. Also requires installation of HDF5 and ZLIB, as explained at the
@@ -583,7 +563,6 @@ The specific libraries and their options are:
don't need the C++ or parallel versions.
URL: www.unidata.ucar.edu/software/netcdf
Options: NETCDF_OPT, NETCDF_LIB.
Versions: NetCDF >= 4.4.0.
- PETSc (optional), used when MFEM_USE_PETSC = YES. Version 3.8 or higher of
the PETSC dev branch is required. The MFEM and PETSc builds can share common
@@ -595,7 +574,6 @@ The specific libraries and their options are:
--with-shared-libraries=0
URL: https://www.mcs.anl.gov/petsc
Options: PETSC_OPT, PETSC_LIB.
Versions: PETSc >= 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.
@@ -603,23 +581,16 @@ The specific libraries and their options are:
https://github.com/LLNL/conduit (Conduit)
https://support.hdfgroup.org/HDF5 (HDF5)
Options: SIDRE_OPT, SIDRE_LIB.
Versions: Axom >= 0.3.1.
- Conduit (optional), used when MFEM_USE_CONDUIT = YES. Conduit Mesh Blueprint
support requires Conduit >= v0.3.1 and VisIt >= v2.13.1 to read the output.
URL: https://github.com/LLNL/conduit (Conduit)
https://support.hdfgroup.org/HDF5 (HDF5)
Options: CONDUIT_OPT, CONDUIT_LIB.
Versions: Conduit >= 0.3.1.
- ADIOS2 (optional) used when MFEM_USE_ADIOS2 = YES.
URL: https://adios2.readthedocs.io/
- PUMI (optional), used when MFEM_USE_PUMI = YES.
URL: https://scorec.rpi.edu/pumi
https://github.com/SCOREC/core
Options: PUMI_OPT, PUMI_LIB.
Versions: PUMI >= 2.2.3.
- HiOp (optional), used when MFEM_USE_HIOP = YES.
URL: https://github.com/LLNL/hiop
@@ -633,12 +604,10 @@ The specific libraries and their options are:
MFEM_USE_GSLIB=YES.
URL: https://github.com/gslib/gslib/archive/v1.0.5.tar.gz
Options: GSLIB_OPT, GSLIB_LIB.
Versions: GSLIB >= 1.0.5.
- CUDA (optional), used when MFEM_USE_CUDA = YES.
URL: https://developer.nvidia.com/cuda-toolkit
Options: CUDA_CXX, CUDA_ARCH, CUDA_OPT, CUDA_LIB.
Versions: CUDA >= 9.1, older versions may work too.
- HIP (optional), used when MFEM_USE_HIP = YES.
URL: https://rocm.github.io/ROCmInstall.html
@@ -647,25 +616,21 @@ The specific libraries and their options are:
- OCCA (optional), used when MFEM_USE_OCCA = YES.
URL: https://libocca.org
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.
URL: https://github.com/CEED/libCEED
https://ceed.exascaleproject.org/libceed
Options: CEED_DIR, CEED_OPT, CEED_LIB.
Versions: libCEED >= 0.6.
- RAJA (optional), used when MFEM_USE_RAJA = YES.
Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported.
URL: https://github.com/LLNL/RAJA
Options: RAJA_DIR, RAJA_OPT, RAJA_LIB.
Versions: RAJA >= 0.10.0.
- Umpire, used when MFEM_USE_UMPIRE = YES.
URL: https://github.com/LLNL/Umpire
Options: UMPIRE_DIR, UMPIRE_OPT, UMPIRE_LIB.
Versions: Umpire >= 2.0.0.
- MPFR (optional), used when MFEM_USE_MPFR = YES.
URL: http://mpfr.org, it depends on the GMP library: https://gmplib.org
-2
View File
@@ -47,8 +47,6 @@ set(MFEM_USE_OCCA @MFEM_USE_OCCA@)
set(MFEM_USE_RAJA @MFEM_USE_RAJA@)
set(MFEM_USE_CEED @MFEM_USE_CEED@)
set(MFEM_USE_UMPIRE @MFEM_USE_UMPIRE@)
set(MFEM_USE_SIMD @MFEM_USE_SIMD@)
set(MFEM_USE_ADIOS2 @MFEM_USE_ADIOS2@)
set(MFEM_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
set(MFEM_CXX_FLAGS "@CMAKE_CXX_FLAGS@")
-6
View File
@@ -107,9 +107,6 @@
// Enable MFEM functionality based on the Sidre library
#cmakedefine MFEM_USE_SIDRE
// Enable the use of SIMD in the high performance templated classes
#cmakedefine MFEM_USE_SIMD
// Enable MFEM functionality based on Conduit
#cmakedefine MFEM_USE_CONDUIT
@@ -135,9 +132,6 @@
// Enable MFEM functionality based on the Umpire library
#cmakedefine MFEM_USE_UMPIRE
// Enable MFEM functionality based on the ADIOS2 library
#cmakedefine MFEM_USE_ADIOS2
// Which library functions to use in class StopWatch for measuring time.
// For a list of the available options, see INSTALL.
// If not defined, an option is selected automatically.
-52
View File
@@ -1,52 +0,0 @@
#------------------------------------------------------------------------------#
# Distributed under the OSI-approved Apache License, Version 2.0. See
# accompanying file Copyright.txt for details.
#------------------------------------------------------------------------------#
#
# FindADIOS2
# -----------
#
# Try to find the ADIOS2 library
#
# This module defines the following variables:
#
# ADIOS2_FOUND - System has ADIOS2
# ADIOS2_INCLUDE_DIRS - The ADIOS2 include directory
# ADIOS2_LIBRARIES - Link these to use ADIOS2
#
# and the following imported targets:
# ADIOS2::ADIOS2 - The ADIOS2 compression library target
#
# You can also set the following variable to help guide the search:
# ADIOS2_DIR - The install prefix for ADIOS2 containing the
# include and lib folders
# Note: this can be set as a CMake variable or an
# environment variable. If specified as a CMake
# variable, it will override any setting specified
# as an environment variable.
if(NOT ADIOS2_FOUND)
if((NOT ADIOS2_DIR) AND (NOT (ENV{ADIOS2_DIR} STREQUAL "")))
set(ADIOS2_DIR "$ENV{ADIOS2_DIR}")
endif()
if(ADIOS2_DIR)
set(ADIOS2_INCLUDE_OPTS HINTS ${ADIOS2_DIR}/include NO_DEFAULT_PATHS)
set(ADIOS2_LIBRARY_OPTS
HINTS ${ADIOS2_DIR}/lib ${ADIOS2_DIR}/lib64
NO_DEFAULT_PATHS
)
endif()
find_path(ADIOS2_INCLUDE_DIR adios2.h ${ADIOS2_INCLUDE_OPTS})
find_library(ADIOS2_LIBRARY NAMES adios2 ${ADIOS2_LIBRARY_OPTS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ADIOS2
FOUND_VAR ADIOS2_FOUND
REQUIRED_VARS ADIOS2_LIBRARY ADIOS2_INCLUDE_DIR
)
if(ADIOS2_FOUND)
set(ADIOS2_INCLUDE_DIRS ${ADIOS2_INCLUDE_DIR})
set(ADIOS2_LIBRARIES ${ADIOS2_LIBRARY})
endif()
endif()
@@ -733,7 +733,7 @@ function(mfem_export_mk_files)
MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS
MFEM_USE_GSLIB MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_CUDA MFEM_USE_OCCA MFEM_USE_RAJA
MFEM_USE_UMPIRE MFEM_USE_SIMD MFEM_USE_ADIOS2)
MFEM_USE_UMPIRE)
foreach(var ${CONFIG_MK_BOOL_VARS})
if (${var})
set(${var} YES)
@@ -743,7 +743,6 @@ function(mfem_export_mk_files)
endforeach()
# TODO: Add support for MFEM_USE_CUDA=YES
set(MFEM_CXX ${CMAKE_CXX_COMPILER})
set(MFEM_HOST_CXX ${MFEM_CXX})
set(MFEM_CPPFLAGS "")
string(STRIP "${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}"
MFEM_CXXFLAGS)
-6
View File
@@ -106,9 +106,6 @@
// Enable Sidre support
// #define MFEM_USE_SIDRE
// Enable the use of SIMD in the high performance templated classes
// #define MFEM_USE_SIMD
// Enable Conduit support
// #define MFEM_USE_CONDUIT
@@ -150,9 +147,6 @@
// Enable functionality based on the Umpire library.
// #define MFEM_USE_UMPIRE
// Enable IO functionality based on the ADIOS2 library.
// #define MFEM_USE_ADIOS2
// Version of HYPRE used for building MFEM.
// #define MFEM_HYPRE_VERSION @MFEM_HYPRE_VERSION@
-3
View File
@@ -49,12 +49,9 @@ 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@
-2
View File
@@ -49,8 +49,6 @@ option(MFEM_USE_OCCA "Enable OCCA" OFF)
option(MFEM_USE_RAJA "Enable RAJA" OFF)
option(MFEM_USE_CEED "Enable CEED" OFF)
option(MFEM_USE_UMPIRE "Enable Umpire" OFF)
option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" ON)
option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
+2 -19
View File
@@ -125,7 +125,6 @@ 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
@@ -138,8 +137,6 @@ MFEM_USE_RAJA = NO
MFEM_USE_OCCA = NO
MFEM_USE_CEED = NO
MFEM_USE_UMPIRE = NO
MFEM_USE_SIMD = YES
MFEM_USE_ADIOS2 = NO
# Compile and link options for zlib.
ZLIB_DIR =
@@ -277,20 +274,6 @@ 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
@@ -339,9 +322,9 @@ GSLIB_DIR = @MFEM_DIR@/../gslib/build
GSLIB_OPT = -I$(GSLIB_DIR)/include
GSLIB_LIB = -L$(GSLIB_DIR)/lib -lgs
# CUDA library configuration
# CUDA library configuration (currently not needed)
CUDA_OPT =
CUDA_LIB = -lcusparse
CUDA_LIB =
# HIP library configuration (currently not needed)
HIP_OPT =
+3 -3
View File
@@ -47,7 +47,7 @@ groups_serial=(
"Meshing miniapps:"
"miniapps/meshing"
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
mesh-optimizer.cpp minimal-surface.cpp"'
mesh-optimizer.cpp"'
)
# Parallel groups
groups_parallel=(
@@ -72,7 +72,7 @@ groups_parallel=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"pmesh-optimizer.cpp pminimal-surface.cpp"'
"pmesh-optimizer.cpp"'
'"electromagnetics"
"Electromagnetics miniapps:"
"miniapps/electromagnetics"
@@ -101,7 +101,7 @@ groups_all=(
"Meshing miniapps:"
"miniapps/meshing"
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
{,p}mesh-optimizer.cpp {,p}minimal-surface.cpp"'
{,p}mesh-optimizer.cpp"'
'"electromagnetics"
"Electromagnetics miniapps:"
"miniapps/electromagnetics"
+6 -13
View File
@@ -29,20 +29,8 @@
#define MFEM_ALWAYS_INLINE
#endif
// --- MFEM_VECTORIZE_LOOP (disabled)
#if (__cplusplus >= 201103L) && !defined(MFEM_DEBUG) && defined(__GNUC__)
//#define MFEM_VECTORIZE_LOOP _Pragma("GCC ivdep")
#define MFEM_VECTORIZE_LOOP
#else
#define MFEM_VECTORIZE_LOOP
#endif
// MFEM_TEMPLATE_BLOCK_SIZE is the block size used by the template matrix-matrix
// multiply, Mult_AB, defined in tmatrix.hpp. This parameter will generally
// require tuning to determine good value. It is probably highly influenced by
// the SIMD width when Mult_AB is used with a SIMD type like AutoSIMD.
#define MFEM_TEMPLATE_BLOCK_SIZE 4
#define MFEM_SIMD_SIZE 32
#define MFEM_TEMPLATE_ENABLE_SERIALIZE
// #define MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
@@ -50,6 +38,11 @@
// #define MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS
#define MFEM_TEMPLATE_INTRULE_COEFF_PRECOMP
// derived macros
#define MFEM_ROUNDUP(val,base) ((((val)+(base)-1)/(base))*(base))
#define MFEM_ALIGN_SIZE(size,type) \
MFEM_ROUNDUP(size,(MFEM_SIMD_SIZE)/sizeof(type))
#ifdef MFEM_COUNT_FLOPS
namespace mfem
{
-37
View File
@@ -1,37 +0,0 @@
SetFactory("OpenCASCADE");
R1 = 1.0;
R2 = 2.0;
Point(1) = {0.0, 0, 0, 1.0};
Point(2) = {R1, 0, 0, 1.0};
Point(3) = {R2, 0, 0, 1.0};
Point(4) = {R1*Cos(Pi/3), R1*Sin(Pi/3), 0, 1.0};
Point(5) = {R2*Cos(Pi/3), R2*Sin(Pi/3), 0, 1.0};
Line(1) = {2, 3};
Line(2) = {4, 5};
Circle(3) = {2, 1, 4};
Circle(4) = {3, 1, 5};
Curve Loop(5) = {1, 4, -2, -3};
Plane Surface(1) = {5};
Transfinite Curve{1} = 7;
Transfinite Curve{2} = 7;
Transfinite Curve{3} = 4;
Transfinite Curve{4} = 10;
// Set a rotation periodicity constraint:
Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Pi/3};
// Tag surfaces and volumes with positive integers
Physical Curve(1) = {3};
Physical Curve(2) = {4};
Physical Curve(3) = {1};
Physical Curve(4) = {2};
Physical Surface(1) = {1};
// Generate 2D mesh
Mesh 2;
Mesh.MshFileVersion = 2.2;
Save "periodic-annulus-sector.msh";
-185
View File
@@ -1,185 +0,0 @@
$MeshFormat
2.2 0 8
$EndMeshFormat
$Nodes
55
1 1 0 0
2 2 0 0
3 0.5000000000000001 0.8660254037844386 0
4 1 1.732050807568877 0
5 1.166666666666667 0 0
6 1.333333333333333 0 0
7 1.5 0 0
8 1.666666666666667 0 0
9 1.833333333333333 0 0
10 0.5833333333333335 1.010362971081845 0
11 0.6666666666666667 1.154700538379251 0
12 0.7500000000000002 1.299038105676658 0
13 0.8333333333333335 1.443375672974064 0
14 0.9166666666666669 1.587713240271471 0
15 0.9396926207859085 0.3420201433256683 0
16 0.7660444431189786 0.6427876096865386 0
17 1.986476715483886 0.2321858282504602 0
18 1.946089741159648 0.4612317414848793 0
19 1.879385241571817 0.6840402866513365 0
20 1.787265280646825 0.8975983604009234 0
21 1.670975622825874 1.09901795614161 0
22 1.532088886237958 1.285575219373077 0
23 1.372483275737469 1.454747283146095 0
24 1.194317183405575 1.604246385510085 0
25 1.425989114816062 0.1915326920916892 0
26 0.8788667344146573 1.13917645290495 0
27 1.630372059110754 0.7154531062316609 0
28 1.436395769298814 1.053728612482506 0
29 1.081023776188756 0.6241293681829633 0
30 1.168737372335971 1.428012728596308 0
31 1.821063986059922 0.298149890497067 0
32 1.234707097211386 0.3469796339295647 0
33 1.377747393186519 0.6200150626754309 0
34 1.457047681210906 0.3890895843559762 0
35 0.917846726184522 0.8957978954532204 0
36 1.218335619030348 0.9017812086952638 0
37 1.066623110765233 1.061857005744772 0
38 1.587029716281926 0.1355955181472859 0
39 1.744445799211916 0.1441515753740107 0
40 1.25 0.1443375672974065 0
41 1.453660070628011 0.8435769396609902 0
42 1.741367044061892 0.499612708014486 0
43 1.30550638526547 1.257610469847477 0
44 1.118213276932792 0.1666674689105279 0
45 0.9109440214958271 1.306610291787315 0
46 0.9970618258753989 1.438658589955562 0
47 0.7499999999999998 1.010362971081845 0
48 0.7034449005273667 0.8850673702175776 0
49 1.605449512513618 0.9269067082200894 0
50 1.561654019115059 0.5298592532912715 0
51 1.229782222487711 1.096820457143683 0
52 1.617066998712459 0.3090202662210922 0
53 1.079645953234324 1.246963713711438 0
54 1.877063966817811 0.1348974588243076 0
55 1.055356609656722 1.558136350380461 0
$EndNodes
$Elements
108
1 1 2 3 1 1 5
2 1 2 3 1 5 6
3 1 2 3 1 6 7
4 1 2 3 1 7 8
5 1 2 3 1 8 9
6 1 2 3 1 9 2
7 1 2 4 2 3 10
8 1 2 4 2 10 11
9 1 2 4 2 11 12
10 1 2 4 2 12 13
11 1 2 4 2 13 14
12 1 2 4 2 14 4
13 1 2 1 3 1 15
14 1 2 1 3 15 16
15 1 2 1 3 16 3
16 1 2 2 4 2 17
17 1 2 2 4 17 18
18 1 2 2 4 18 19
19 1 2 2 4 19 20
20 1 2 2 4 20 21
21 1 2 2 4 21 22
22 1 2 2 4 22 23
23 1 2 2 4 23 24
24 1 2 2 4 24 4
25 2 2 1 1 32 40 25
26 2 2 1 1 25 34 32
27 2 2 1 1 33 41 36
28 2 2 1 1 38 52 25
29 2 2 1 1 33 36 29
30 2 2 1 1 26 47 35
31 2 2 1 1 35 37 26
32 2 2 1 1 25 52 34
33 2 2 1 1 32 44 40
34 2 2 1 1 15 32 29
35 2 2 1 1 15 29 16
36 2 2 1 1 36 41 28
37 2 2 1 1 32 33 29
38 2 2 1 1 50 52 42
39 2 2 1 1 32 34 33
40 2 2 1 1 42 52 31
41 2 2 1 1 43 53 51
42 2 2 1 1 27 41 33
43 2 2 1 1 26 53 45
44 2 2 1 1 18 31 17
45 2 2 1 1 29 35 16
46 2 2 1 1 29 36 35
47 2 2 1 1 24 30 23
48 2 2 1 1 30 53 43
49 2 2 1 1 17 54 2
50 2 2 1 1 4 55 24
51 2 2 1 1 28 51 36
52 2 2 1 1 47 48 35
53 2 2 1 1 36 37 35
54 2 2 1 1 37 53 26
55 2 2 1 1 22 28 21
56 2 2 1 1 20 27 19
57 2 2 1 1 33 50 27
58 2 2 1 1 15 44 32
59 2 2 1 1 18 42 31
60 2 2 1 1 30 43 23
61 2 2 1 1 35 48 16
62 2 2 1 1 31 54 17
63 2 2 1 1 9 39 8
64 2 2 1 1 8 38 7
65 2 2 1 1 7 25 6
66 2 2 1 1 22 43 28
67 2 2 1 1 23 43 22
68 2 2 1 1 39 54 31
69 2 2 1 1 19 42 18
70 2 2 1 1 24 55 30
71 2 2 1 1 27 42 19
72 2 2 1 1 13 46 14
73 2 2 1 1 51 53 37
74 2 2 1 1 39 52 38
75 2 2 1 1 6 40 5
76 2 2 1 1 34 52 50
77 2 2 1 1 12 45 13
78 2 2 1 1 30 55 46
79 2 2 1 1 10 47 11
80 2 2 1 1 8 39 38
81 2 2 1 1 28 49 21
82 2 2 1 1 7 38 25
83 2 2 1 1 41 49 28
84 2 2 1 1 20 49 27
85 2 2 1 1 11 26 12
86 2 2 1 1 27 49 41
87 2 2 1 1 31 52 39
88 2 2 1 1 25 40 6
89 2 2 1 1 2 54 9
90 2 2 1 1 14 55 4
91 2 2 1 1 45 53 46
92 2 2 1 1 45 46 13
93 2 2 1 1 5 44 1
94 2 2 1 1 21 49 20
95 2 2 1 1 46 53 30
96 2 2 1 1 3 48 10
97 2 2 1 1 34 50 33
98 2 2 1 1 36 51 37
99 2 2 1 1 26 45 12
100 2 2 1 1 11 47 26
101 2 2 1 1 27 50 42
102 2 2 1 1 40 44 5
103 2 2 1 1 43 51 28
104 2 2 1 1 10 48 47
105 2 2 1 1 9 54 39
106 2 2 1 1 46 55 14
107 2 2 1 1 1 44 15
108 2 2 1 1 16 48 3
$EndElements
$Periodic
1
1 1 2
Affine 0.5000000000000001 0.8660254037844386 0 0 -0.8660254037844386 0.5000000000000001 0 0 0 0 1 0 0 0 0 1
7
9 14
6 11
8 13
5 10
7 12
2 4
1 3
$EndPeriodic
-25
View File
@@ -1,25 +0,0 @@
SetFactory("OpenCASCADE");
R = 1.5;
r = 0.5;
Torus(1) = {0,0,0, R, r, Pi/3};
pts() = PointsOf{ Volume{1}; };
Characteristic Length{ pts() } = 0.25;
// Set a rotation periodicity constraint:
Periodic Surface{3} = {2} Rotate{{0,0,1}, {0,0,0}, Pi/3};
// Tag surfaces and volumes with positive integers
Physical Surface(1) = {1};
Physical Surface(2) = {2};
Physical Surface(3) = {3};
Physical Volume(1) = {1};
// Generate 3D mesh
Mesh 3;
Mesh.MshFileVersion = 2.2;
Save "periodic-torus-sector.msh";
File diff suppressed because it is too large Load Diff
-155
View File
@@ -1,155 +0,0 @@
MFEM NURBS mesh v1.0
dimension
2
elements
5
1 3 0 3 7 4
1 3 3 2 6 7
1 3 2 1 5 6
1 3 1 0 4 5
1 3 2 8 9 1
boundary
10
1 1 0 3
2 1 3 2
2 1 1 0
2 1 2 8
2 1 9 1
3 1 7 4
3 1 6 7
3 1 5 6
3 1 4 5
4 1 8 9
edges
15
0 0 4
0 3 7
0 1 5
0 2 6
1 0 3
1 4 7
2 3 2
2 7 6
2 1 0
2 5 4
1 2 1
1 6 5
1 8 9
3 2 8
3 1 9
vertices
10
patches
knotvectors
2
2 3 0 0 0 1 1 1
2 4 0 0 0 0.5 1 1 1
dimension
2
controlpoints_cartesian
-5 5 1
-5 3.92523e-16 1
-5 -5 1
-2.47593 2.47593 1
-4.95187 6.06429e-16 0.707107
-2.47593 -2.47593 1
-0.424264 0.424264 1
-0.848528 1.03915e-16 0.707107
-0.424264 -0.424264 1
-0.353553 0.353553 1
-0.707107 8.65956e-17 0.707107
-0.353553 -0.353553 1
knotvectors
2
2 3 0 0 0 1 1 1
2 4 0 0 0 0.5 1 1 1
dimension
2
controlpoints_cartesian
-5 -5 1
-1.17757e-15 -5 1
5 -5 1
-2.47593 -2.47593 1
-9.09644e-16 -4.95187 0.707107
2.47593 -2.47593 1
-0.424264 -0.424264 1
-1.55872e-16 -0.848528 0.707107
0.424264 -0.424264 1
-0.353553 -0.353553 1
-1.29893e-16 -0.707107 0.707107
0.353553 -0.353553 1
knotvectors
2
2 3 0 0 0 1 1 1
2 4 0 0 0 0.5 1 1 1
dimension
2
controlpoints_cartesian
5 -5 1
5 -1.17757e-15 1
5 5 1
2.47593 -2.47593 1
4.95187 -1.21286e-15 0.707107
2.47593 2.47593 1
0.424264 -0.424264 1
0.848528 -2.07829e-16 0.707107
0.424264 0.424264 1
0.353553 -0.353553 1
0.707107 -1.73191e-16 0.707107
0.353553 0.353553 1
knotvectors
2
2 3 0 0 0 1 1 1
2 4 0 0 0 0.5 1 1 1
dimension
2
controlpoints_cartesian
5 5 1
3.92523e-16 5 1
-5 5 1
2.47593 2.47593 1
3.03215e-16 4.95187 0.707107
-2.47593 2.47593 1
0.424264 0.424264 1
5.19574e-17 0.848528 0.707107
-0.424264 0.424264 1
0.353553 0.353553 1
4.32978e-17 0.707107 0.707107
-0.353553 0.353553 1
knotvectors
2
2 3 0 0 0 1 1 1
2 3 0 0 0 1 1 1
dimension
2
controlpoints_cartesian
5 -5 1
10 -5 1
15 -5 1
5 0 1
10 0 1
15 0 1
5 5 1
10 5 1
15 5 1
+29 -14
View File
@@ -16,21 +16,36 @@ if (DOXYGEN_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CodeDocumentation.conf.in
${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf @ONLY)
if (UNIX)
# Only create symlinks if UNIX operating system
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen to CodeDocumentation.html"
VERBATIM)
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
COMMAND echo "<meta http-equiv=\"REFRESH\" content=\"0;URL=CodeDocumentation/html/index.html\">" > ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen to CodeDocumentation.html"
VERBATIM)
add_custom_target(clean-doc
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/warnings.log
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
COMMENT "Removing API documentation"
VERBATIM)
add_custom_target(clean-doc
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
COMMENT "Removing API documentation"
VERBATIM)
else (UNIX)
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen to CodeDocumentation/html/index.html"
VERBATIM)
add_custom_target(clean-doc
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
COMMENT "Removing API documentation"
VERBATIM)
endif (UNIX)
endif (DOXYGEN_FOUND)
+3 -4
View File
@@ -51,7 +51,7 @@ PROJECT_BRIEF = "Finite element discretization library"
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO = web/logo-small.png
PROJECT_LOGO =
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
@@ -746,7 +746,7 @@ WARN_FORMAT = "$file:$line: $text"
# messages should be written. If left blank the output is written to standard
# error (stderr).
WARN_LOGFILE = warnings.log
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
@@ -774,7 +774,6 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/miniapps/electromagnetics \
@MFEM_SOURCE_DIR@/miniapps/gslib \
@MFEM_SOURCE_DIR@/miniapps/meshing \
@MFEM_SOURCE_DIR@/miniapps/navier \
@MFEM_SOURCE_DIR@/miniapps/nurbs \
@MFEM_SOURCE_DIR@/miniapps/performance \
@MFEM_SOURCE_DIR@/miniapps/tools \
@@ -1470,7 +1469,7 @@ MATHJAX_FORMAT = HTML-CSS
# The default value is: http://cdn.mathjax.org/mathjax/latest.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
MATHJAX_RELPATH = https://cdn.llnl.gov/mathjax/2.7.2
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
-5
View File
@@ -88,8 +88,6 @@ namespace mfem {
* - <a class="el" href="ex24p_8cpp_source.html">Example 24p</a>: parallel mixed finite element spaces and interpolators
* - <a class="el" href="ex25_8cpp_source.html">Example 25</a>: simulation of electromagnetic wave propagation using a Perfectly Matched Layer (PML)
* - <a class="el" href="ex25p_8cpp_source.html">Example 25p</a>: parallel simulation of electromagnetic wave propagation using a Perfectly Matched Layer (PML)
* - <a class="el" href="ex26_8cpp_source.html">Example 26</a>: multigrid preconditioner for the Laplace problem using nodal H1 FEM
* - <a class="el" href="ex26p_8cpp_source.html">Example 26p</a>: parallel multigrid preconditioner for the Laplace problem using nodal H1 FEM
*
* <H4>SUNDIALS Examples</H4>
* - Variants of Examples
@@ -144,12 +142,10 @@ namespace mfem {
* - <a class="el" href="klein-bottle_8cpp_source.html">Klein Bottle</a>: generate three types of Klein bottle surfaces
* - <a class="el" href="toroid_8cpp_source.html">Toroid</a>: generate simple toroidal meshes
* - <a class="el" href="twist_8cpp_source.html">Twist</a>: generate simple periodic meshes
* - <a class="el" href="minimal-surface_8cpp_source.html">Minimal Surface</a>: compute minimal surfaces, <a class="el" href="minimal-surface_8cpp_source.html">serial</a> and <a class="el" href="pminimal-surface_8cpp_source.html">parallel</a> versions
* - <a class="el" href="shaper_8cpp_source.html">Shaper</a>: resolve material interfaces by mesh refinement
* - <a class="el" href="extruder_8cpp_source.html">Extruder</a>: extrude a low-dimensional mesh into a higher dimension
* - <a class="el" href="mesh-explorer_8cpp_source.html">Mesh Explorer</a>: visualize and manipulate meshes
* - <a class="el" href="mesh-optimizer_8cpp_source.html">Mesh Optimizer</a>: optimize high-order meshes, <a class="el" href="mesh-optimizer_8cpp_source.html">serial</a> and <a class="el" href="pmesh-optimizer_8cpp_source.html">parallel</a> versions
* - <a class="el" href="trimmer_8cpp_source.html">Trimmer</a>: trim elements from existing meshes
* - <a class="el" href="display-basis_8cpp_source.html">Display Basis</a>: visualize finite element basis functions
* - <a class="el" href="get-values_8cpp_source.html">Get Values</a>: extract field values via DataCollection classes
* - <a class="el" href="load-dc_8cpp_source.html">Load DC</a>: visualize fields saved via DataCollection classes
@@ -157,7 +153,6 @@ namespace mfem {
* - <a class="el" href="lor-transfer_8cpp_source.html">LOR Transfer</a>: map functions between high-order and low-order refined spaces
* - <a class="el" href="findpts_8cpp_source.html">Find Points</a>: evaluate grid function in physical space, <a class="el" href="findpts_8cpp_source.html">serial</a> and <a class="el" href="pfindpts_8cpp_source.html">parallel</a> versions
* - <a class="el" href="field-diff_8cpp_source.html">Field Diff</a>: compare grid functions on different meshes
* - <a class="el" href="classmfem_1_1navier_1_1NavierSolver.html">Navier</a>: solve the transient incompressible Navier-Stokes equations
* - <a class="el" href="miniapps_2performance_2ex1_8cpp_source.html">HPC Example 1</a>: high-performance nodal H1 FEM for the Laplace problem
* - <a class="el" href="miniapps_2performance_2ex1p_8cpp_source.html">HPC Example 1p</a>: high-performance parallel nodal H1 FEM for the Laplace problem
*
+4 -11
View File
@@ -9,25 +9,18 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
SHELL = /bin/bash
MFEM_DIR ?= ..
DOXYGEN_CONF = CodeDocumentation.conf
# doxygen uses: graphviz, latex
html: $(DOXYGEN_CONF)
@# Generate the html documentation
@doxygen $(DOXYGEN_CONF)
@echo "<meta http-equiv=\"REFRESH\" content=\"0;URL=CodeDocumentation/html/index.html\">" > CodeDocumentation.html
@cat warnings.log
@# Generate the log of undocumented methods
@( cat $(DOXYGEN_CONF) ; echo "GENERATE_HTML=NO" ; echo "EXTRACT_ALL=NO" ; echo "WARN_LOGFILE=undoc.log" ; echo "QUIET=YES" ) | doxygen - &> /dev/null
doxygen $(DOXYGEN_CONF)
rm -f CodeDocumentation.html
ln -s CodeDocumentation/html/index.html CodeDocumentation.html
clean:
rm -rf $(DOXYGEN_CONF) CodeDocumentation CodeDocumentation.html *~
rm -rf undoc.log warnings.log
$(DOXYGEN_CONF): $(MFEM_DIR)/doc/$(DOXYGEN_CONF).in
@sed -e 's%@MFEM_SOURCE_DIR@%$(MFEM_DIR)%g' $(<) \
sed -e 's%@MFEM_SOURCE_DIR@%$(MFEM_DIR)%g' $(<) \
> $(DOXYGEN_CONF)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

-6
View File
@@ -32,8 +32,6 @@ list(APPEND ALL_EXE_SRCS
ex23.cpp
ex24.cpp
ex25.cpp
ex26.cpp
ex27.cpp
)
if (MFEM_USE_MPI)
@@ -62,8 +60,6 @@ if (MFEM_USE_MPI)
ex22p.cpp
ex24p.cpp
ex25p.cpp
ex26p.cpp
ex27p.cpp
)
endif()
@@ -83,8 +79,6 @@ foreach(SRC_FILE ${ALL_EXE_SRCS})
list(APPEND THIS_TEST_OPTIONS "-tf" "5")
elseif(${TEST_NAME} MATCHES "ex15p*")
list(APPEND THIS_TEST_OPTIONS "-e" "1")
elseif(${TEST_NAME} MATCHES "ex27p*")
list(APPEND THIS_TEST_OPTIONS "-dg")
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
-2
View File
@@ -9,8 +9,6 @@
// ex1 -m ../data/fichera.mesh
// ex1 -m ../data/fichera-mixed.mesh
// ex1 -m ../data/toroid-wedge.mesh
// ex1 -m ../data/periodic-annulus-sector.msh
// ex1 -m ../data/periodic-torus-sector.msh
// ex1 -m ../data/square-disc-p2.vtk -o 2
// ex1 -m ../data/square-disc-p3.mesh -o 3
// ex1 -m ../data/square-disc-nurbs.mesh -o -1
-2
View File
@@ -8,8 +8,6 @@
// mpirun -np 4 ex11p -m ../data/escher.mesh
// mpirun -np 4 ex11p -m ../data/fichera.mesh
// mpirun -np 4 ex11p -m ../data/fichera-mixed.mesh
// mpirun -np 4 ex11p -m ../data/periodic-annulus-sector.msh
// mpirun -np 4 ex11p -m ../data/periodic-torus-sector.msh -rs 1
// mpirun -np 4 ex11p -m ../data/toroid-wedge.mesh -o 2
// mpirun -np 4 ex11p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex11p -m ../data/square-disc-p3.mesh -o 3
+3 -29
View File
@@ -33,8 +33,7 @@
// The example highlights the use of the LOBPCG eigenvalue solver
// together with the BoomerAMG preconditioner in HYPRE. Reusing a
// single GLVis visualization window for multiple eigenfunctions
// and optional saving with ADIOS2 (adios2.readthedocs.io) streams
// are also illustrated.
// is also illustrated.
//
// We recommend viewing examples 2 and 11 before viewing this
// example.
@@ -61,7 +60,6 @@ int main(int argc, char *argv[])
int seed = 66;
bool visualization = 1;
bool amg_elast = 0;
bool adios2 = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -79,9 +77,6 @@ int main(int argc, char *argv[])
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&adios2, "-adios2", "--adios2-streams", "-no-adios2",
"--no-adios2-streams",
"Save data using adios2 streams.");
args.Parse();
if (!args.Good())
{
@@ -291,28 +286,7 @@ int main(int argc, char *argv[])
}
}
// 13. Optionally output a BP (binary pack) file using ADIOS2. This can be
// visualized with the ParaView VTX reader.
#ifdef MFEM_USE_ADIOS2
if (adios2)
{
std::string postfix(mesh_file);
postfix.erase(0, std::string("../data/").size() );
postfix += "_o" + std::to_string(order);
adios2stream adios2output("ex12-p-" + postfix + ".bp",
adios2stream::openmode::out, MPI_COMM_WORLD);
pmesh->Print(adios2output);
for (int i=0; i<nev; i++)
{
x = lobpcg->GetEigenvector(i);
// x is a temporary that must be saved immediately
x.Save(adios2output, "mode_" + std::to_string(i));
}
}
#endif
// 14. Send the above data by socket to a GLVis server. Use the "n" and "b"
// 13. Send the above data by socket to a GLVis server. Use the "n" and "b"
// keys in GLVis to visualize the displacements.
if (visualization)
{
@@ -352,7 +326,7 @@ int main(int argc, char *argv[])
mode_sock.close();
}
// 15. Free the used memory.
// 14. Free the used memory.
delete lobpcg;
delete amg;
delete M;
-34
View File
@@ -35,38 +35,6 @@
using namespace std;
using namespace mfem;
class CustomSolverMonitor : public IterativeSolverMonitor
{
public:
CustomSolverMonitor(const ParMesh *m,
ParGridFunction *f) :
pmesh(m),
pgf(f) {}
void MonitorSolution(int i, double norm, const Vector &x, bool final)
{
char vishost[] = "localhost";
int visport = 19916;
int num_procs, myid;
MPI_Comm_size(pmesh->GetComm(),&num_procs);
MPI_Comm_rank(pmesh->GetComm(),&myid);
pgf->SetFromTrueDofs(x);
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << *pgf
<< "window_title 'Iteration no " << i << "'"
<< "keys rRjlc\n" << flush;
}
private:
const ParMesh *pmesh;
ParGridFunction *pgf;
};
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
@@ -220,7 +188,6 @@ int main(int argc, char *argv[])
}
else
{
CustomSolverMonitor monitor(pmesh, &x);
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetAbsTol(0.0);
gmres.SetRelTol(1e-12);
@@ -229,7 +196,6 @@ int main(int argc, char *argv[])
gmres.SetPrintLevel(1);
gmres.SetOperator(*A);
gmres.SetPreconditioner(*amg);
gmres.SetMonitor(monitor);
gmres.Mult(*B, *X);
}
delete amg;
+1 -43
View File
@@ -24,8 +24,7 @@
// class ConductionOperator defining C(u)), as well as their
// implicit time integration. Note that implementing the method
// ConductionOperator::ImplicitSolve is the only requirement for
// high-order implicit (SDIRK) time integration. Optional saving
// with ADIOS2 (adios2.readthedocs.io) is also illustrated.
// high-order implicit (SDIRK) time integration.
//
// We recommend viewing examples 2, 9 and 10 before viewing this
// example.
@@ -109,7 +108,6 @@ int main(int argc, char *argv[])
bool visualization = true;
bool visit = false;
int vis_steps = 5;
bool adios2 = false;
int precision = 8;
cout.precision(precision);
@@ -142,9 +140,6 @@ int main(int argc, char *argv[])
"Save data files for VisIt (visit.llnl.gov) visualization.");
args.AddOption(&vis_steps, "-vs", "--visualization-steps",
"Visualize every n-th timestep.");
args.AddOption(&adios2, "-adios2", "--adios2-streams", "-no-adios2",
"--no-adios2-streams",
"Save data using adios2 streams.");
args.Parse();
if (!args.Good())
{
@@ -253,27 +248,6 @@ int main(int argc, char *argv[])
visit_dc.Save();
}
// Optionally output a BP (binary pack) file using ADIOS2. This can be
// visualized with the ParaView VTX reader.
#ifdef MFEM_USE_ADIOS2
ADIOS2DataCollection* adios2_dc = NULL;
if (adios2)
{
std::string postfix(mesh_file);
postfix.erase(0, std::string("../data/").size() );
postfix += "_o" + std::to_string(order);
postfix += "_solver" + std::to_string(ode_solver_type);
const std::string collection_name = "ex16-p-" + postfix + ".bp";
adios2_dc = new ADIOS2DataCollection(MPI_COMM_WORLD, collection_name, pmesh);
adios2_dc->SetParameter("SubStreams", std::to_string(num_procs/2) );
adios2_dc->RegisterField("temperature", &u_gf);
adios2_dc->SetCycle(0);
adios2_dc->SetTime(0.0);
adios2_dc->Save();
}
#endif
socketstream sout;
if (visualization)
{
@@ -343,26 +317,10 @@ int main(int argc, char *argv[])
visit_dc.SetTime(t);
visit_dc.Save();
}
#ifdef MFEM_USE_ADIOS2
if (adios2)
{
adios2_dc->SetCycle(ti);
adios2_dc->SetTime(t);
adios2_dc->Save();
}
#endif
}
oper.SetParameters(u);
}
#ifdef MFEM_USE_ADIOS2
if (adios2)
{
delete adios2_dc;
}
#endif
// 11. Save the final solution in parallel. This output can be viewed later
// using GLVis: "glvis -np <np> -m ex16-mesh -g ex16-final".
{
+3 -3
View File
@@ -418,7 +418,7 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
{
intorder++;
}
const IntegrationRule *ir = &IntRules.Get(Tr.GetGeometryType(), intorder);
const IntegrationRule *ir = &IntRules.Get(Tr.FaceGeom, intorder);
for (int i = 0; i < ir->GetNPoints(); i++)
{
@@ -435,10 +435,10 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
elfun1_mat.MultTranspose(shape1, funval1);
elfun2_mat.MultTranspose(shape2, funval2);
Tr.SetIntPoint(&ip);
Tr.Face->SetIntPoint(&ip);
// Get the normal vector and the flux on the face
CalcOrtho(Tr.Jacobian(), nor);
CalcOrtho(Tr.Face->Jacobian(), nor);
const double mcs = rsolver.Eval(funval1, funval2, nor, fluxN);
// Update max char speed
+3 -44
View File
@@ -38,42 +38,6 @@
using namespace std;
using namespace mfem;
class GeneralResidualMonitor : public IterativeSolverMonitor
{
public:
GeneralResidualMonitor(const std::string& prefix_, int print_lvl)
: prefix(prefix_)
{
print_level = print_lvl;
}
virtual void MonitorResidual(int it, double norm, const Vector &r, bool final);
private:
const std::string prefix;
int print_level;
mutable double norm0;
};
void GeneralResidualMonitor::MonitorResidual(int it, double norm,
const Vector &r, bool final)
{
if (print_level == 1 || (print_level == 3 && (final || it == 0)))
{
mfem::out << prefix << " iteration " << setw(2) << it
<< " : ||r|| = " << norm;
if (it > 0)
{
mfem::out << ", ||r||/||r_0|| = " << norm/norm0;
}
else
{
norm0 = norm;
}
mfem::out << '\n';
}
}
// Custom block preconditioner for the Jacobian of the incompressible nonlinear
// elasticity operator. It has the form
//
@@ -139,11 +103,9 @@ protected:
// Newton solver for the hyperelastic operator
NewtonSolver newton_solver;
GeneralResidualMonitor newton_monitor;
// Solver for the Jacobian solve in the Newton method
Solver *j_solver;
GeneralResidualMonitor j_monitor;
// Preconditioner for the Jacobian
Solver *j_prec;
@@ -448,8 +410,7 @@ RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
int iter,
Coefficient &c_mu)
: Operator(fes[0]->GetVSize() + fes[1]->GetVSize()),
newton_solver(), newton_monitor("Newton", 1),
j_monitor(" GMRES", 3), mu(c_mu), block_offsets(offsets)
newton_solver(), mu(c_mu), block_offsets(offsets)
{
Array<Vector *> rhs(2);
rhs = NULL; // Set all entries in the array
@@ -485,8 +446,7 @@ RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
j_gmres->SetRelTol(1e-12);
j_gmres->SetAbsTol(1e-12);
j_gmres->SetMaxIter(300);
j_gmres->SetPrintLevel(-1);
j_gmres->SetMonitor(j_monitor);
j_gmres->SetPrintLevel(0);
j_gmres->SetPreconditioner(*j_prec);
j_solver = j_gmres;
@@ -494,8 +454,7 @@ RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
newton_solver.iterative_mode = true;
newton_solver.SetSolver(*j_solver);
newton_solver.SetOperator(*this);
newton_solver.SetPrintLevel(-1);
newton_solver.SetMonitor(newton_monitor);
newton_solver.SetPrintLevel(1);
newton_solver.SetRelTol(rel_tol);
newton_solver.SetAbsTol(abs_tol);
newton_solver.SetMaxIter(iter);
+3 -60
View File
@@ -38,56 +38,6 @@
using namespace std;
using namespace mfem;
class GeneralResidualMonitor : public IterativeSolverMonitor
{
public:
GeneralResidualMonitor(MPI_Comm comm, const std::string& prefix_,
int print_lvl)
: prefix(prefix_)
{
#ifndef MFEM_USE_MPI
print_level = print_lvl;
#else
int rank;
MPI_Comm_rank(comm, &rank);
if (rank == 0)
{
print_level = print_lvl;
}
else
{
print_level = -1;
}
#endif
}
virtual void MonitorResidual(int it, double norm, const Vector &r, bool final);
private:
const std::string prefix;
int print_level;
mutable double norm0;
};
void GeneralResidualMonitor::MonitorResidual(int it, double norm,
const Vector &r, bool final)
{
if (print_level == 1 || (print_level == 3 && (final || it == 0)))
{
mfem::out << prefix << " iteration " << setw(2) << it
<< " : ||r|| = " << norm;
if (it > 0)
{
mfem::out << ", ||r||/||r_0|| = " << norm/norm0;
}
else
{
norm0 = norm;
}
mfem::out << '\n';
}
}
// Custom block preconditioner for the Jacobian of the incompressible nonlinear
// elasticity operator. It has the form
//
@@ -153,11 +103,9 @@ protected:
// Newton solver for the hyperelastic operator
NewtonSolver newton_solver;
GeneralResidualMonitor newton_monitor;
// Solver for the Jacobian solve in the Newton method
Solver *j_solver;
GeneralResidualMonitor j_monitor;
// Preconditioner for the Jacobian
Solver *j_prec;
@@ -511,10 +459,7 @@ RubberOperator::RubberOperator(Array<ParFiniteElementSpace *> &fes,
int iter,
Coefficient &c_mu)
: Operator(fes[0]->TrueVSize() + fes[1]->TrueVSize()),
newton_solver(fes[0]->GetComm()),
newton_monitor(fes[0]->GetComm(), "Newton", 1),
j_monitor(fes[0]->GetComm(), " GMRES", 3),
mu(c_mu), block_trueOffsets(trueOffsets)
newton_solver(fes[0]->GetComm()), mu(c_mu), block_trueOffsets(trueOffsets)
{
Array<Vector *> rhs(2);
rhs = NULL; // Set all entries in the array
@@ -554,8 +499,7 @@ RubberOperator::RubberOperator(Array<ParFiniteElementSpace *> &fes,
j_gmres->SetRelTol(1e-12);
j_gmres->SetAbsTol(1e-12);
j_gmres->SetMaxIter(300);
j_gmres->SetPrintLevel(-1);
j_gmres->SetMonitor(j_monitor);
j_gmres->SetPrintLevel(0);
j_gmres->SetPreconditioner(*j_prec);
j_solver = j_gmres;
@@ -563,8 +507,7 @@ RubberOperator::RubberOperator(Array<ParFiniteElementSpace *> &fes,
newton_solver.iterative_mode = true;
newton_solver.SetSolver(*j_solver);
newton_solver.SetOperator(*this);
newton_solver.SetPrintLevel(-1);
newton_solver.SetMonitor(newton_monitor);
newton_solver.SetPrintLevel(1);
newton_solver.SetRelTol(rel_tol);
newton_solver.SetAbsTol(abs_tol);
newton_solver.SetMaxIter(iter);
-2
View File
@@ -9,8 +9,6 @@
// mpirun -np 4 ex1p -m ../data/fichera.mesh
// mpirun -np 4 ex1p -m ../data/fichera-mixed.mesh
// mpirun -np 4 ex1p -m ../data/toroid-wedge.mesh
// mpirun -np 4 ex1p -m ../data/periodic-annulus-sector.msh
// mpirun -np 4 ex1p -m ../data/periodic-torus-sector.msh
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3
// mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1
+77 -164
View File
@@ -6,7 +6,6 @@
// ex24 -m ../data/square-disc.mesh -o 2
// ex24 -m ../data/beam-tet.mesh
// ex24 -m ../data/beam-hex.mesh -o 2 -pa
// ex24 -m ../data/beam-hex.mesh -o 2 -pa -p 1
// ex24 -m ../data/escher.mesh
// ex24 -m ../data/escher.mesh -o 2
// ex24 -m ../data/fichera.mesh
@@ -24,15 +23,11 @@
// ex24 -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code illustrates usage of mixed finite element
// spaces, with two variants:
// spaces. Using two different approaches, we project a gradient
// of a function in H^1 to H(curl). Other spaces and example
// computations are to be added in the future.
//
// 1) (grad p, u) for p in H^1 tested against u in H(curl)
// 2) (div v, q) for v in H(div) tested against q in L_2
//
// Using different approaches, we project the gradient or
// divergence to the appropriate space.
//
// We recommend viewing examples 1, 3, and 5 before viewing this
// We recommend viewing examples 1 and 3 before viewing this
// example.
#include "mfem.hpp"
@@ -44,7 +39,6 @@ using namespace mfem;
double p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
double div_gradp_exact(const Vector &x);
int dim;
@@ -53,7 +47,6 @@ int main(int argc, char *argv[])
// 1. Parse command-line options.
const char *mesh_file = "../data/beam-hex.mesh";
int order = 1;
int prob = 0;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
@@ -64,8 +57,6 @@ int main(int argc, char *argv[])
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: H(Curl) or 1: H(Div)");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
@@ -109,107 +100,72 @@ int main(int argc, char *argv[])
}
mesh->ReorientTetMesh();
// 5. Define a finite element space on the mesh. Here we use Nedelec or
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *trial_fec = NULL;
FiniteElementCollection *test_fec = NULL;
// 5. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
FiniteElementCollection *H1fec = new H1_FECollection(order, dim);
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
FiniteElementSpace *H1fespace = new FiniteElementSpace(mesh, H1fec);
if (prob == 0)
{
trial_fec = new H1_FECollection(order, dim);
test_fec = new ND_FECollection(order, dim);
}
else
{
trial_fec = new RT_FECollection(order - 1, dim);
test_fec = new L2_FECollection(order - 1, dim);
}
int size = fespace->GetTrueVSize();
int H1size = H1fespace->GetTrueVSize();
cout << "Number of Nedelec finite element unknowns: " << size << endl;
cout << "Number of H1 finite element unknowns: " << H1size << endl;
FiniteElementSpace trial_fes(mesh, trial_fec);
FiniteElementSpace test_fes(mesh, test_fec);
int trial_size = trial_fes.GetTrueVSize();
int test_size = test_fes.GetTrueVSize();
if (prob == 0)
{
cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
cout << "Number of H1 finite element unknowns: " << trial_size << endl;
}
else
{
cout << "Number of Raviart-Thomas finite element unknowns: "
<< trial_size << endl;
cout << "Number of L2 finite element unknowns: " << test_size << endl;
}
// 6. Define the solution vector as a finite element grid function
// corresponding to the trial fespace.
GridFunction gftest(&test_fes);
GridFunction gftrial(&trial_fes);
GridFunction x(&test_fes);
// 6. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
GridFunction x(fespace);
FunctionCoefficient p_coef(p_exact);
GridFunction p(H1fespace);
p.ProjectCoefficient(p_coef);
p.SetTrueVector();
p.SetFromTrueVector();
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
FunctionCoefficient divgradp_coef(div_gradp_exact);
if (prob == 0)
{
gftrial.ProjectCoefficient(p_coef);
}
else
{
gftrial.ProjectCoefficient(gradp_coef);
}
gftrial.SetTrueVector();
gftrial.SetFromTrueVector();
// 7. Set up the bilinear forms for L2 projection.
ConstantCoefficient one(1.0);
BilinearForm a(&test_fes);
MixedBilinearForm a_mixed(&trial_fes, &test_fes);
// 7. Set up the bilinear forms.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
BilinearForm *a = new BilinearForm(fespace);
MixedBilinearForm *a_NDH1 = new MixedBilinearForm(H1fespace, fespace);
if (pa)
{
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_mixed.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a->SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_NDH1->SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
if (prob == 0)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorGradientIntegrator(one));
}
else
{
a.AddDomainIntegrator(new MassIntegrator(one));
a_mixed.AddDomainIntegrator(new VectorFEDivergenceIntegrator(one));
}
// First approach: L2 projection
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
a_NDH1->AddDomainIntegrator(new MixedVectorGradientIntegrator(*muinv));
// 8. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a.EnableStaticCondensation(); }
// 8. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a.Assemble();
if (!pa) { a.Finalize(); }
a->Assemble();
if (!pa) { a->Finalize(); }
a_mixed.Assemble();
if (!pa) { a_mixed.Finalize(); }
a_NDH1->Assemble();
if (!pa) { a_NDH1->Finalize(); }
if (pa)
{
a_mixed.Mult(gftrial, x);
a_NDH1->Mult(p, x);
}
else
{
SparseMatrix& mixed = a_mixed.SpMat();
mixed.Mult(gftrial, x);
SparseMatrix& NDH1 = a_NDH1->SpMat();
NDH1.Mult(p, x);
}
// 9. Define and apply a PCG solver for Ax = b with Jacobi preconditioner.
{
GridFunction rhs(&test_fes);
GridFunction rhs(fespace);
rhs = x;
x = 0.0;
@@ -220,15 +176,15 @@ int main(int argc, char *argv[])
if (pa)
{
Array<int> ess_tdof_list; // empty
OperatorJacobiSmoother Jacobi(a, ess_tdof_list);
OperatorJacobiSmoother Jacobi(*a, ess_tdof_list);
cg.SetOperator(a);
cg.SetOperator(*a);
cg.SetPreconditioner(Jacobi);
cg.Mult(rhs, x);
}
else
{
SparseMatrix& Amat = a.SpMat();
SparseMatrix& Amat = a->SpMat();
DSmoother Jacobi(Amat);
cg.SetOperator(Amat);
@@ -237,68 +193,33 @@ int main(int argc, char *argv[])
}
}
// 10. Compute the same field by applying a DiscreteInterpolator.
GridFunction discreteInterpolant(&test_fes);
DiscreteLinearOperator dlo(&trial_fes, &test_fes);
if (prob == 0)
{
dlo.AddDomainInterpolator(new GradientInterpolator());
}
else
{
dlo.AddDomainInterpolator(new DivergenceInterpolator());
}
// 10. Second approach: compute the same solution by applying
// GradientInterpolator in H(curl).
DiscreteLinearOperator grad(H1fespace, fespace);
grad.AddDomainInterpolator(new GradientInterpolator());
grad.Assemble();
dlo.Assemble();
dlo.Mult(gftrial, discreteInterpolant);
GridFunction gradp(fespace);
grad.Mult(p, gradp);
// 11. Compute the projection of the exact field.
GridFunction exact_proj(&test_fes);
if (prob == 0)
{
exact_proj.ProjectCoefficient(gradp_coef);
}
else
{
exact_proj.ProjectCoefficient(divgradp_coef);
}
// 11. Compute the projection of the exact grad p.
GridFunction exact_gradp(fespace);
exact_gradp.ProjectCoefficient(gradp_coef);
exact_gradp.SetTrueVector();
exact_gradp.SetFromTrueVector();
exact_proj.SetTrueVector();
exact_proj.SetFromTrueVector();
// 12. Compute and print the L_2 norm of the error.
if (prob == 0)
// 12. Compute and print the L^2 norm of the error.
{
double errSol = x.ComputeL2Error(gradp_coef);
double errInterp = discreteInterpolant.ComputeL2Error(gradp_coef);
double errProj = exact_proj.ComputeL2Error(gradp_coef);
double errInterp = gradp.ComputeL2Error(gradp_coef);
double errProj = exact_gradp.ComputeL2Error(gradp_coef);
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in H(curl): "
"|| E_h - grad p ||_{L_2} = " << errSol << '\n' << endl;
"|| E_h - grad p ||_{L^2} = " << errSol << '\n' << endl;
cout << " Gradient interpolant E_h = grad p_h in H(curl): || E_h - grad p"
"||_{L_2} = " << errInterp << '\n' << endl;
"||_{L^2} = " << errInterp << '\n' << endl;
cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
"||_{L_2} = " << errProj << '\n' << endl;
}
else
{
int order_quad = max(2, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
double errSol = x.ComputeL2Error(divgradp_coef, irs);
double errInterp = discreteInterpolant.ComputeL2Error(divgradp_coef, irs);
double errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
cout << "\n Solution of (f_h,q) = (div v_h,q) for f_h and q in L_2: "
"|| f_h - div v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Divergence interpolant f_h = div v_h in L_2: || f_h - div v"
"||_{L_2} = " << errInterp << '\n' << endl;
cout << " Projection f_h of exact div v in L_2: || f_h - div v "
"||_{L_2} = " << errProj << '\n' << endl;
"||_{L^2} = " << errProj << '\n' << endl;
}
// 13. Save the refined mesh and the solution. This output can be viewed
@@ -321,8 +242,14 @@ int main(int argc, char *argv[])
}
// 15. Free the used memory.
delete trial_fec;
delete test_fec;
delete a;
delete a_NDH1;
delete sigma;
delete muinv;
delete fespace;
delete H1fespace;
delete fec;
delete H1fec;
delete mesh;
return 0;
@@ -357,17 +284,3 @@ void gradp_exact(const Vector &x, Vector &f)
if (x.Size() == 3) { f(2) = 0.0; }
}
}
double div_gradp_exact(const Vector &x)
{
if (dim == 3)
{
return -3.0 * sin(x(0)) * sin(x(1)) * sin(x(2));
}
else if (dim == 2)
{
return -2.0 * sin(x(0)) * sin(x(1));
}
return 0.0;
}
+81 -171
View File
@@ -6,7 +6,6 @@
// mpirun -np 4 ex24p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex24p -m ../data/beam-tet.mesh
// mpirun -np 4 ex24p -m ../data/beam-hex.mesh -o 2 -pa
// mpirun -np 4 ex24p -m ../data/beam-hex.mesh -o 2 -p 1 -pa
// mpirun -np 4 ex24p -m ../data/escher.mesh
// mpirun -np 4 ex24p -m ../data/escher.mesh -o 2
// mpirun -np 4 ex24p -m ../data/fichera.mesh
@@ -24,15 +23,11 @@
// mpirun -np 4 ex24p -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code illustrates usage of mixed finite element
// spaces, with two variants:
// spaces. Using two different approaches, we project a gradient
// of a function in H^1 to H(curl). Other spaces and example
// computations are to be added in the future.
//
// 1) (grad p, u) for p in H^1 tested against u in H(curl)
// 2) (div v, q) for v in H(div) tested against q in L_2
//
// Using different approaches, we project the gradient or
// divergence to the appropriate space.
//
// We recommend viewing examples 1, 3, and 5 before viewing this
// We recommend viewing examples 1 and 3 before viewing this
// example.
#include "mfem.hpp"
@@ -44,7 +39,6 @@ using namespace mfem;
double p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
double div_gradp_exact(const Vector &x);
int dim;
@@ -59,7 +53,6 @@ int main(int argc, char *argv[])
// 2. Parse command-line options.
const char *mesh_file = "../data/beam-hex.mesh";
int order = 1;
int prob = 0;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
@@ -70,8 +63,6 @@ int main(int argc, char *argv[])
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: H(Curl) or 1: H(Div)");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
@@ -138,115 +129,80 @@ int main(int argc, char *argv[])
pmesh->ReorientTetMesh();
// 7. Define a parallel finite element space on the parallel mesh. Here we
// use Nedelec or Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *trial_fec = NULL;
FiniteElementCollection *test_fec = NULL;
if (prob == 0)
{
trial_fec = new H1_FECollection(order, dim);
test_fec = new ND_FECollection(order, dim);
}
else
{
trial_fec = new RT_FECollection(order - 1, dim);
test_fec = new L2_FECollection(order - 1, dim);
}
ParFiniteElementSpace trial_fes(pmesh, trial_fec);
ParFiniteElementSpace test_fes(pmesh, test_fec);
HYPRE_Int trial_size = trial_fes.GlobalTrueVSize();
HYPRE_Int test_size = test_fes.GlobalTrueVSize();
// use the Nedelec finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
FiniteElementCollection *H1fec = new H1_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
ParFiniteElementSpace *H1fespace = new ParFiniteElementSpace(pmesh, H1fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
HYPRE_Int H1size = H1fespace->GlobalTrueVSize();
if (myid == 0)
{
if (prob == 0)
{
cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
cout << "Number of H1 finite element unknowns: " << trial_size << endl;
}
else
{
cout << "Number of Raviart-Thomas finite element unknowns: "
<< trial_size << endl;
cout << "Number of L2 finite element unknowns: " << test_size << endl;
}
cout << "Number of Nedelec finite element unknowns: " << size << endl;
cout << "Number of H1 finite element unknowns: " << H1size << endl;
}
// 8. Define the solution vector as a parallel finite element grid function
// corresponding to the trial fespace.
ParGridFunction gftest(&test_fes);
ParGridFunction gftrial(&trial_fes);
ParGridFunction x(&test_fes);
// 8. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
FunctionCoefficient p_coef(p_exact);
ParGridFunction p(H1fespace);
p.ProjectCoefficient(p_coef);
p.SetTrueVector();
p.SetFromTrueVector();
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
FunctionCoefficient divgradp_coef(div_gradp_exact);
if (prob == 0)
{
gftrial.ProjectCoefficient(p_coef);
}
else
{
gftrial.ProjectCoefficient(gradp_coef);
}
gftrial.SetTrueVector();
gftrial.SetFromTrueVector();
// 9. Set up the parallel bilinear forms for L2 projection.
ConstantCoefficient one(1.0);
ParBilinearForm a(&test_fes);
ParMixedBilinearForm a_mixed(&trial_fes, &test_fes);
// 9. Set up the parallel bilinear forms.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
ParMixedBilinearForm *a_NDH1 = new ParMixedBilinearForm(H1fespace, fespace);
if (pa)
{
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_mixed.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a->SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_NDH1->SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
if (prob == 0)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorGradientIntegrator(one));
}
else
{
a.AddDomainIntegrator(new MassIntegrator(one));
a_mixed.AddDomainIntegrator(new VectorFEDivergenceIntegrator(one));
}
// First approach: L2 projection
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
a_NDH1->AddDomainIntegrator(new MixedVectorGradientIntegrator(*muinv));
// 10. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a.EnableStaticCondensation(); }
if (static_cond) { a->EnableStaticCondensation(); }
a.Assemble();
if (!pa) { a.Finalize(); }
a->Assemble();
if (!pa) { a->Finalize(); }
a_mixed.Assemble();
if (!pa) { a_mixed.Finalize(); }
a_NDH1->Assemble();
if (!pa) { a_NDH1->Finalize(); }
Vector B(test_fes.GetTrueVSize());
Vector X(test_fes.GetTrueVSize());
Vector B(fespace->GetTrueVSize());
Vector X(fespace->GetTrueVSize());
if (pa)
{
ParLinearForm b(&test_fes); // used as a vector
a_mixed.Mult(gftrial, b); // process-local multiplication
b.ParallelAssemble(B);
ParLinearForm *b = new ParLinearForm(fespace); // used as a vector
a_NDH1->Mult(p, *b); // process-local multiplication
b->ParallelAssemble(B);
delete b;
}
else
{
HypreParMatrix *mixed = a_mixed.ParallelAssemble();
HypreParMatrix *NDH1 = a_NDH1->ParallelAssemble();
Vector P(trial_fes.GetTrueVSize());
gftrial.GetTrueDofs(P);
Vector P(H1fespace->GetTrueVSize());
p.GetTrueDofs(P);
mixed->Mult(P,B);
NDH1->Mult(P,B);
delete mixed;
delete NDH1;
}
// 11. Define and apply a parallel PCG solver for AX=B with Jacobi
@@ -256,9 +212,9 @@ int main(int argc, char *argv[])
Array<int> ess_tdof_list; // empty
OperatorPtr A;
a.FormSystemMatrix(ess_tdof_list, A);
a->FormSystemMatrix(ess_tdof_list, A);
OperatorJacobiSmoother Jacobi(a, ess_tdof_list);
OperatorJacobiSmoother Jacobi(*a, ess_tdof_list);
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
@@ -271,7 +227,7 @@ int main(int argc, char *argv[])
}
else
{
HypreParMatrix *Amat = a.ParallelAssemble();
HypreParMatrix *Amat = a->ParallelAssemble();
HypreDiagScale Jacobi(*Amat);
HyprePCG pcg(*Amat);
pcg.SetTol(1e-12);
@@ -286,73 +242,35 @@ int main(int argc, char *argv[])
x.SetFromTrueDofs(X);
// 12. Compute the same field by applying a DiscreteInterpolator.
ParGridFunction discreteInterpolant(&test_fes);
ParDiscreteLinearOperator dlo(&trial_fes, &test_fes);
if (prob == 0)
{
dlo.AddDomainInterpolator(new GradientInterpolator());
}
else
{
dlo.AddDomainInterpolator(new DivergenceInterpolator());
}
// 12. Second approach: compute the same solution by applying
// GradientInterpolator in H(curl).
ParDiscreteLinearOperator grad(H1fespace, fespace);
grad.AddDomainInterpolator(new GradientInterpolator());
grad.Assemble();
dlo.Assemble();
dlo.Mult(gftrial, discreteInterpolant);
ParGridFunction gradp(fespace);
grad.Mult(p, gradp);
// 13. Compute the projection of the exact field.
ParGridFunction exact_proj(&test_fes);
if (prob == 0)
{
exact_proj.ProjectCoefficient(gradp_coef);
}
else
{
exact_proj.ProjectCoefficient(divgradp_coef);
}
// 13. Compute the projection of the exact grad p.
ParGridFunction exact_gradp(fespace);
exact_gradp.ProjectCoefficient(gradp_coef);
exact_gradp.SetTrueVector();
exact_gradp.SetFromTrueVector();
exact_proj.SetTrueVector();
exact_proj.SetFromTrueVector();
// 14. Compute and print the L_2 norm of the error.
if (prob == 0)
// 14. Compute and print the L^2 norm of the error.
{
double errSol = x.ComputeL2Error(gradp_coef);
double errInterp = discreteInterpolant.ComputeL2Error(gradp_coef);
double errProj = exact_proj.ComputeL2Error(gradp_coef);
double errInterp = gradp.ComputeL2Error(gradp_coef);
double errProj = exact_gradp.ComputeL2Error(gradp_coef);
if (myid == 0)
{
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in H(curl): "
"|| E_h - grad p ||_{L_2} = " << errSol << '\n' << endl;
cout << " Gradient interpolant E_h = grad p_h in H(curl): || E_h - grad p"
"||_{L_2} = " << errInterp << '\n' << endl;
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in "
"H(curl): || E_h - grad p ||_{L^2} = " << errSol << '\n' << endl;
cout << " Gradient interpolant E_h = grad p_h in H(curl): || E_h - "
"grad p ||_{L^2} = " << errInterp << '\n' << endl;
cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
"||_{L_2} = " << errProj << '\n' << endl;
}
}
else
{
int order_quad = max(2, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
double errSol = x.ComputeL2Error(divgradp_coef, irs);
double errInterp = discreteInterpolant.ComputeL2Error(divgradp_coef, irs);
double errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
if (myid == 0)
{
cout << "\n Solution of (f_h,q) = (div v_h,q) for f_h and q in L_2: "
"|| f_h - div v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Divergence interpolant f_h = div v_h in L_2: || f_h - div v"
"||_{L_2} = " << errInterp << '\n' << endl;
cout << " Projection f_h of exact div v in L_2: || f_h - div v "
"||_{L_2} = " << errProj << '\n' << endl;
"||_{L^2} = " << errProj << '\n' << endl;
}
}
@@ -384,8 +302,14 @@ int main(int argc, char *argv[])
}
// 17. Free the used memory.
delete trial_fec;
delete test_fec;
delete a;
delete a_NDH1;
delete sigma;
delete muinv;
delete fespace;
delete H1fespace;
delete fec;
delete H1fec;
delete pmesh;
MPI_Finalize();
@@ -422,17 +346,3 @@ void gradp_exact(const Vector &x, Vector &f)
if (x.Size() == 3) { f(2) = 0.0; }
}
}
double div_gradp_exact(const Vector &x)
{
if (dim == 3)
{
return -3.0 * sin(x(0)) * sin(x(1)) * sin(x(2));
}
else if (dim == 2)
{
return -2.0 * sin(x(0)) * sin(x(1));
}
return 0.0;
}
-255
View File
@@ -1,255 +0,0 @@
// MFEM Example 26
//
// Compile with: make ex26
//
// Sample runs: ex26 -m ../data/star.mesh
// ex26 -m ../data/fichera.mesh
// ex26 -m ../data/beam-hex.mesh
//
// Device sample runs:
// ex26 -d cuda
// ex26 -d raja-cuda
// ex26 -d occa-cuda
// ex26 -d raja-omp
// ex26 -d occa-omp
// ex26 -d ceed-cpu
// ex26 -d ceed-cuda
// ex26 -m ../data/beam-hex.mesh -d cuda
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions
// as in Example 1.
//
// It highlights on the creation of a hierarchy of discretization
// spaces with partial assembly and the construction of an
// efficient multigrid preconditioner for the iterative solver.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Class for constructing a multigrid preconditioner for the diffusion operator.
// This example multigrid preconditioner class demonstrates the creation of the
// diffusion bilinear forms and operators using partial assembly for all spaces
// in the FiniteElementSpaceHierarchy. The preconditioner uses a CG solver on
// the coarsest level and second order Chebyshev accelerated smoothers on the
// other levels.
class DiffusionMultigrid : public Multigrid
{
private:
ConstantCoefficient one;
public:
// Constructs a diffusion multigrid for the given FiniteElementSpaceHierarchy
// and the array of essential boundaries
DiffusionMultigrid(FiniteElementSpaceHierarchy& fespaces, Array<int>& ess_bdr)
: Multigrid(fespaces), one(1.0)
{
ConstructCoarseOperatorAndSolver(fespaces.GetFESpaceAtLevel(0), ess_bdr);
for (int level = 1; level < fespaces.GetNumLevels(); ++level)
{
ConstructOperatorAndSmoother(fespaces.GetFESpaceAtLevel(level), ess_bdr);
}
}
private:
void ConstructBilinearForm(FiniteElementSpace& fespace, Array<int>& ess_bdr)
{
BilinearForm* form = new BilinearForm(&fespace);
form->SetAssemblyLevel(AssemblyLevel::PARTIAL);
form->AddDomainIntegrator(new DiffusionIntegrator(one));
form->Assemble();
bfs.Append(form);
essentialTrueDofs.Append(new Array<int>());
fespace.GetEssentialTrueDofs(ess_bdr, *essentialTrueDofs.Last());
}
void ConstructCoarseOperatorAndSolver(FiniteElementSpace& coarse_fespace,
Array<int>& ess_bdr)
{
ConstructBilinearForm(coarse_fespace, ess_bdr);
OperatorPtr opr;
opr.SetType(Operator::ANY_TYPE);
bfs.Last()->FormSystemMatrix(*essentialTrueDofs.Last(), opr);
opr.SetOperatorOwner(false);
CGSolver* pcg = new CGSolver();
pcg->SetPrintLevel(-1);
pcg->SetMaxIter(200);
pcg->SetRelTol(sqrt(1e-4));
pcg->SetAbsTol(0.0);
pcg->SetOperator(*opr.Ptr());
AddLevel(opr.Ptr(), pcg, true, true);
}
void ConstructOperatorAndSmoother(FiniteElementSpace& fespace,
Array<int>& ess_bdr)
{
ConstructBilinearForm(fespace, ess_bdr);
OperatorPtr opr;
opr.SetType(Operator::ANY_TYPE);
bfs.Last()->FormSystemMatrix(*essentialTrueDofs.Last(), opr);
opr.SetOperatorOwner(false);
Vector diag(fespace.GetTrueVSize());
bfs.Last()->AssembleDiagonal(diag);
Solver* smoother = new OperatorChebyshevSmoother(opr.Ptr(), diag,
*essentialTrueDofs.Last(), 2);
AddLevel(opr.Ptr(), smoother, true, true);
}
};
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int geometric_refinements = 0;
int order_refinements = 2;
const char *device_config = "cpu";
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&geometric_refinements, "-gr", "--geometric-refinements",
"Number of geometric refinements done prior to order refinements.");
args.AddOption(&order_refinements, "-or", "--order-refinements",
"Number of order refinements. Finest level in the hierarchy has order 2^{or}.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// 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 mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 50,000
// elements.
{
int ref_levels =
(int)floor(log(5000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a finite element space hierarchy on the mesh. Here we use
// continuous Lagrange finite elements. We start with order 1 on the
// coarse level and geometrically refine the spaces by the specified
// amount. Afterwards, we increase the order of the finite elements
// by a factor of 2 for each additional level.
FiniteElementCollection *fec = new H1_FECollection(1, dim);
FiniteElementSpace *coarse_fespace = new FiniteElementSpace(mesh, fec);
FiniteElementSpaceHierarchy fespaces(mesh, coarse_fespace, true, true);
Array<FiniteElementCollection*> collections;
collections.Append(fec);
for (int level = 0; level < geometric_refinements; ++level)
{
fespaces.AddUniformlyRefinedLevel();
}
for (int level = 0; level < order_refinements; ++level)
{
collections.Append(new H1_FECollection(std::pow(2, level+1), dim));
fespaces.AddOrderRefinedLevel(collections.Last());
}
cout << "Number of finite element unknowns: "
<< fespaces.GetFinestFESpace().GetTrueVSize() << endl;
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
LinearForm *b = new LinearForm(&fespaces.GetFinestFESpace());
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 7. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
GridFunction x(&fespaces.GetFinestFESpace());
x = 0.0;
// 8. Create the multigrid operator using the previously created
// FiniteElementSpaceHierarchy and additional boundary information. This operator
// is then used to create the MultigridSolver as a preconditioner in the
// iterative solver.
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
DiffusionMultigrid M(fespaces, ess_bdr);
M.SetCycleType(Multigrid::CycleType::VCYCLE, 1, 1);
OperatorPtr A;
Vector B, X;
M.FormFineLinearSystem(x, *b, A, X, B);
cout << "Size of linear system: " << A->Height() << endl;
// 9. Solve the linear system A X = B.
PCG(*A, M, B, X, 1, 2000, 1e-12, 0.0);
// 10. Recover the solution as a finite element grid function.
M.RecoverFineFEMSolution(X, *b, x);
// 11. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
fespaces.GetFinestFESpace().GetMesh()->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
// 12. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *fespaces.GetFinestFESpace().GetMesh() << x <<
flush;
}
// 13. Free the used memory.
delete b;
for (int level = 0; level < collections.Size(); ++level)
{
delete collections[level];
}
return 0;
}
-317
View File
@@ -1,317 +0,0 @@
// MFEM Example 26 - Parallel Version
//
// Compile with: make ex26p
//
// Sample runs: mpirun -np 4 ex26p -m ../data/star.mesh
// mpirun -np 4 ex26p -m ../data/fichera.mesh
// mpirun -np 4 ex26p -m ../data/beam-hex.mesh
//
// Device sample runs:
// mpirun -np 4 ex26p -d cuda
// mpirun -np 4 ex26p -d occa-cuda
// mpirun -np 4 ex26p -d raja-omp
// mpirun -np 4 ex26p -d ceed-cpu
// mpirun -np 4 ex26p -d ceed-cuda
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions
// as in Example 1.
//
// It highlights on the creation of a hierarchy of discretization
// spaces with partial assembly and the construction of an
// efficient multigrid preconditioner for the iterative solver.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Class for constructing a multigrid preconditioner for the diffusion operator.
// This example multigrid preconditioner class demonstrates the creation of the
// parallel diffusion bilinear forms and operators using partial assembly for
// all spaces except the coarsest one in the ParFiniteElementSpaceHierarchy.
// The multigrid uses a PCG solver preconditioned with AMG on the coarsest level
// and second order Chebyshev accelerated smoothers on the other levels.
class DiffusionMultigrid : public Multigrid
{
private:
ConstantCoefficient one;
HypreBoomerAMG* amg;
public:
// Constructs a diffusion multigrid for the ParFiniteElementSpaceHierarchy
// and the array of essential boundaries
DiffusionMultigrid(ParFiniteElementSpaceHierarchy& fespaces,
Array<int>& ess_bdr)
: Multigrid(fespaces), one(1.0)
{
ConstructCoarseOperatorAndSolver(fespaces.GetFESpaceAtLevel(0), ess_bdr);
for (int level = 1; level < fespaces.GetNumLevels(); ++level)
{
ConstructOperatorAndSmoother(fespaces.GetFESpaceAtLevel(level), ess_bdr);
}
}
virtual ~DiffusionMultigrid()
{
delete amg;
}
private:
void ConstructBilinearForm(ParFiniteElementSpace& fespace, Array<int>& ess_bdr,
bool partial_assembly)
{
ParBilinearForm* form = new ParBilinearForm(&fespace);
if (partial_assembly)
{
form->SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
form->AddDomainIntegrator(new DiffusionIntegrator(one));
form->Assemble();
bfs.Append(form);
essentialTrueDofs.Append(new Array<int>());
fespace.GetEssentialTrueDofs(ess_bdr, *essentialTrueDofs.Last());
}
void ConstructCoarseOperatorAndSolver(ParFiniteElementSpace& coarse_fespace,
Array<int>& ess_bdr)
{
ConstructBilinearForm(coarse_fespace, ess_bdr, false);
HypreParMatrix* hypreCoarseMat = new HypreParMatrix();
bfs.Last()->FormSystemMatrix(*essentialTrueDofs.Last(), *hypreCoarseMat);
amg = new HypreBoomerAMG(*hypreCoarseMat);
amg->SetPrintLevel(-1);
CGSolver* pcg = new CGSolver(MPI_COMM_WORLD);
pcg->SetPrintLevel(-1);
pcg->SetMaxIter(10);
pcg->SetRelTol(sqrt(1e-4));
pcg->SetAbsTol(0.0);
pcg->SetOperator(*hypreCoarseMat);
pcg->SetPreconditioner(*amg);
AddLevel(hypreCoarseMat, pcg, true, true);
}
void ConstructOperatorAndSmoother(ParFiniteElementSpace& fespace,
Array<int>& ess_bdr)
{
ConstructBilinearForm(fespace, ess_bdr, true);
OperatorPtr opr;
opr.SetType(Operator::ANY_TYPE);
bfs.Last()->FormSystemMatrix(*essentialTrueDofs.Last(), opr);
opr.SetOperatorOwner(false);
Vector diag(fespace.GetTrueVSize());
bfs.Last()->AssembleDiagonal(diag);
Solver* smoother = new OperatorChebyshevSmoother(opr.Ptr(), diag,
*essentialTrueDofs.Last(), 2, fespace.GetParMesh()->GetComm());
AddLevel(opr.Ptr(), smoother, true, true);
}
};
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 geometric_refinements = 0;
int order_refinements = 2;
const char *device_config = "cpu";
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&geometric_refinements, "-gr", "--geometric-refinements",
"Number of geometric refinements done prior to order refinements.");
args.AddOption(&order_refinements, "-or", "--order-refinements",
"Number of order refinements. Finest level in the hierarchy has order 2^{or}.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 5. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
{
int ref_levels =
(int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
{
int par_ref_levels = 2;
for (int l = 0; l < par_ref_levels; l++)
{
pmesh->UniformRefinement();
}
}
// 7. Define a parallel finite element space hierarchy on the parallel mesh.
// Here we use continuous Lagrange finite elements. We start with order 1
// on the coarse level and geometrically refine the spaces by the specified
// amount. Afterwards, we increase the order of the finite elements by a
// factor of 2 for each additional level.
FiniteElementCollection *fec = new H1_FECollection(1, dim);
ParFiniteElementSpace *coarse_fespace = new ParFiniteElementSpace(pmesh, fec);
Array<FiniteElementCollection*> collections;
collections.Append(fec);
ParFiniteElementSpaceHierarchy* fespaces = new ParFiniteElementSpaceHierarchy(
pmesh, coarse_fespace, true, true);
for (int level = 0; level < geometric_refinements; ++level)
{
fespaces->AddUniformlyRefinedLevel();
}
for (int level = 0; level < order_refinements; ++level)
{
collections.Append(new H1_FECollection(std::pow(2, level+1), dim));
fespaces->AddOrderRefinedLevel(collections.Last());
}
HYPRE_Int size = fespaces->GetFinestFESpace().GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (1,phi_i) where phi_i are the basis functions in fespace.
ParLinearForm *b = new ParLinearForm(&fespaces->GetFinestFESpace());
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(&fespaces->GetFinestFESpace());
x = 0.0;
// 10. Create the multigrid operator using the previously created parallel
// FiniteElementSpaceHierarchy and additional boundary information. This operator
// is then used to create the MultigridSolver as a preconditioner in the
// iterative solver.
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
if (pmesh->bdr_attributes.Size())
{
ess_bdr = 1;
}
DiffusionMultigrid* M = new DiffusionMultigrid(*fespaces, ess_bdr);
M->SetCycleType(Multigrid::CycleType::VCYCLE, 1, 1);
OperatorPtr A;
Vector X, B;
M->FormFineLinearSystem(x, *b, A, X, B);
// 11. Solve the linear system A X = B.
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
cg.SetOperator(*A);
cg.SetPreconditioner(*M);
cg.Mult(B, X);
// 12. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
M->RecoverFineFEMSolution(X, *b, x);
// 13. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
fespaces->GetFinestFESpace().GetParMesh()->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 14. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *fespaces->GetFinestFESpace().GetParMesh()
<< x << flush;
}
// 15. Free the used memory.
delete M;
delete b;
delete fespaces;
for (int level = 0; level < collections.Size(); ++level)
{
delete collections[level];
}
MPI_Finalize();
return 0;
}
-736
View File
@@ -1,736 +0,0 @@
// MFEM Example 27 - Serial Version
//
// Compile with: make ex27
//
// Sample runs: ex27
// ex27 -dg
// ex27 -dg -dbc 8 -nbc -2
// ex27 -rbc-a 1 -rbc-b 8
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 0 with a variety of boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order using a continuous or discontinuous space. We then
// apply Dirichlet, Neumann (both homogeneous and inhomogeneous),
// Robin, and Periodic boundary conditions on different portions
// of a predefined mesh.
//
// The predefined mesh consists of a rectangle with two
// holes removed (see below). The narrow ends of the
// mesh are connected to form a Periodic boundary
// condition. The lower edge (tagged with attribute 1)
// receives an inhomogeneous Neumann boundary condition.
// A Robin boundary condition is applied to upper edge
// (attribute 2). The circular hole on the left
// (attribute 3) enforces a Dirichlet boundary
// condition. Finally, a natural boundary condition, or
// homogeneous Neumann BC, is applied to the circular
// hole on the right (attribute 4).
//
// Attribute 3 ^ y Attribute 2
// \ | /
// +-----------+-----------+
// | \_ | _ |
// | / \ | / \ |
// <--+---+---+---+---+---+---+--> x
// | \_/ | \_/ |
// | | \ |
// +-----------+-----------+ (hole radii are
// / | \ adjustable)
// Attribute 1 v Attribute 4
//
// The boundary conditions are defined as (where u is
// the solution field):
// Dirichlet: u = d
// Neumann: n.Grad(u) = g
// Robin: n.Grad(u) + a u = b
//
// The user can adjust the values of 'd', 'g', 'a', and
// 'b' with command line options.
//
// This example highlights the differing implementations of
// boundary conditions with continuous and discontinuous Galerkin
// formulations of the Laplace problem.
//
// We recommend viewing examples 1 and 14 before viewing this
// example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
static double a_ = 0.2;
// Normal to hole with boundary attribute 4
void n4Vec(const Vector &x, Vector &n) { n = x; n[0] -= 0.5; n /= -n.Norml2(); }
Mesh * GenerateSerialMesh(int ref);
// Compute the average value of alpha*n.Grad(sol) + beta*sol over the boundary
// attributes marked in bdr_marker. Also computes the L2 norm of
// alpha*n.Grad(sol) + beta*sol - gamma over the same boundary.
double IntegrateBC(const GridFunction &sol, const Array<int> &bdr_marker,
double alpha, double beta, double gamma,
double &err);
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
int ser_ref_levels = 2;
int order = 1;
double sigma = -1.0;
double kappa = -1.0;
bool h1 = true;
bool visualization = true;
double mat_val = 1.0;
double dbc_val = 0.0;
double nbc_val = 1.0;
double rbc_a_val = 1.0; // du/dn + a * u = b
double rbc_b_val = 1.0;
OptionsParser args(argc, argv);
args.AddOption(&h1, "-h1", "--continuous", "-dg", "--discontinuous",
"Select continuous \"H1\" or discontinuous \"DG\" basis.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&sigma, "-s", "--sigma",
"One of the two DG penalty parameters, typically +1/-1."
" See the documentation of class DGDiffusionIntegrator.");
args.AddOption(&kappa, "-k", "--kappa",
"One of the two DG penalty parameters, should be positive."
" Negative values are replaced with (order+1)^2.");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&mat_val, "-mat", "--material-value",
"Constant value for material coefficient "
"in the Laplace operator.");
args.AddOption(&dbc_val, "-dbc", "--dirichlet-value",
"Constant value for Dirichlet Boundary Condition.");
args.AddOption(&nbc_val, "-nbc", "--neumann-value",
"Constant value for Neumann Boundary Condition.");
args.AddOption(&rbc_a_val, "-rbc-a", "--robin-a-value",
"Constant 'a' value for Robin Boundary Condition: "
"du/dn + a * u = b.");
args.AddOption(&rbc_b_val, "-rbc-b", "--robin-b-value",
"Constant 'b' value for Robin Boundary Condition: "
"du/dn + a * u = b.");
args.AddOption(&a_, "-a", "--radius",
"Radius of holes in the mesh.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(mfem::out);
return 1;
}
if (kappa < 0 && !h1)
{
kappa = (order+1)*(order+1);
}
args.PrintOptions(mfem::out);
if (a_ < 0.01)
{
mfem::out << "Hole radius too small, resetting to 0.01.\n";
a_ = 0.01;
}
if (a_ > 0.49)
{
mfem::out << "Hole radius too large, resetting to 0.49.\n";
a_ = 0.49;
}
// 2. Construct the (serial) mesh and refine it if requested.
Mesh *mesh = GenerateSerialMesh(ser_ref_levels);
int dim = mesh->Dimension();
// 3. Define a finite element space on the serial mesh. Here we
// use either continuous Lagrange finite elements or discontinuous
// Galerkin finite elements of the specified order.
FiniteElementCollection *fec =
h1 ? (FiniteElementCollection*)new H1_FECollection(order, dim) :
(FiniteElementCollection*)new DG_FECollection(order, dim);
FiniteElementSpace fespace(mesh, fec);
int size = fespace.GetTrueVSize();
mfem::out << "Number of finite element unknowns: " << size << endl;
// 4. Create "marker arrays" to define the portions of the boundary
// associated with each type of boundary condition. These arrays
// have an entry corresponding to each boundary attribute.
// Placing a '1' in entry i marks attribute i+1 as being
// active, '0' is inactive.
Array<int> nbc_bdr(mesh->bdr_attributes.Max());
Array<int> rbc_bdr(mesh->bdr_attributes.Max());
Array<int> dbc_bdr(mesh->bdr_attributes.Max());
nbc_bdr = 0; nbc_bdr[0] = 1;
rbc_bdr = 0; rbc_bdr[1] = 1;
dbc_bdr = 0; dbc_bdr[2] = 1;
Array<int> ess_tdof_list(0);
if (h1 && mesh->bdr_attributes.Size())
{
// For a continuous basis the linear system must be modifed to enforce
// an essential (Dirichlet) boundary condition. In the DG case this is
// not necessary as the boundary condition will only be enforced weakly.
fespace.GetEssentialTrueDofs(dbc_bdr, ess_tdof_list);
}
// 5. Setup the various coefficients needed for the Laplace operator and
// the various boundary conditions. In general these coefficients could
// be functions of position but here we use only constants.
ConstantCoefficient matCoef(mat_val);
ConstantCoefficient dbcCoef(dbc_val);
ConstantCoefficient nbcCoef(nbc_val);
ConstantCoefficient rbcACoef(rbc_a_val);
ConstantCoefficient rbcBCoef(rbc_b_val);
// Since the n.Grad(u) terms arise by integrating -Div(m Grad(u)) by parts
// we must introduce the coefficient 'm' into the boundary conditions.
// Therefore, in the case of the Neumann BC, we actually enforce
// m n.Grad(u) = m g rather than simply n.Grad(u) = g.
ProductCoefficient m_nbcCoef(matCoef, nbcCoef);
ProductCoefficient m_rbcACoef(matCoef, rbcACoef);
ProductCoefficient m_rbcBCoef(matCoef, rbcBCoef);
// 6. Define the solution vector u as a finite element grid function
// corresponding to fespace. Initialize u with initial guess of zero.
GridFunction u(&fespace);
u = 0.0;
// 7. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
BilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator(matCoef));
if (h1)
{
// Add a Mass integrator on the Robin boundary
a.AddBoundaryIntegrator(new MassIntegrator(m_rbcACoef), rbc_bdr);
}
else
{
// Add the interfacial portion of the Lapalce operator
a.AddInteriorFaceIntegrator(new DGDiffusionIntegrator(matCoef,
sigma, kappa));
// Counteract the n.Grad(u) term on the Dirichlet portion of the boundary
a.AddBdrFaceIntegrator(new DGDiffusionIntegrator(matCoef, sigma, kappa),
dbc_bdr);
// Augment the n.Grad(u) term with a*u on the Robin portion of boundary
a.AddBdrFaceIntegrator(new BoundaryMassIntegrator(m_rbcACoef),
rbc_bdr);
}
a.Assemble();
// 8. Assemble the linear form for the right hand side vector.
LinearForm b(&fespace);
if (h1)
{
// Set the Dirchlet values in the solution vector
u.ProjectBdrCoefficient(dbcCoef, dbc_bdr);
// Add the desired value for n.Grad(u) on the Neumann boundary
b.AddBoundaryIntegrator(new BoundaryLFIntegrator(m_nbcCoef), nbc_bdr);
// Add the desired value for n.Grad(u) + a*u on the Robin boundary
b.AddBoundaryIntegrator(new BoundaryLFIntegrator(m_rbcBCoef), rbc_bdr);
}
else
{
// Add the desired value for the Dirchlet boundary
b.AddBdrFaceIntegrator(new DGDirichletLFIntegrator(dbcCoef, matCoef,
sigma, kappa),
dbc_bdr);
// Add the desired value for n.Grad(u) on the Neumann boundary
b.AddBdrFaceIntegrator(new BoundaryLFIntegrator(m_nbcCoef),
nbc_bdr);
// Add the desired value for n.Grad(u) + a*u on the Robin boundary
b.AddBdrFaceIntegrator(new BoundaryLFIntegrator(m_rbcBCoef),
rbc_bdr);
}
b.Assemble();
// 9. Construct the linear system.
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, u, b, A, X, B);
#ifndef MFEM_USE_SUITESPARSE
// 10. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system AX=B with PCG in the symmetric case, and GMRES in the
// non-symmetric one.
{
GSSmoother M((SparseMatrix&)(*A));
if (sigma == -1.0)
{
PCG(*A, M, B, X, 1, 500, 1e-12, 0.0);
}
else
{
GMRES(*A, M, B, X, 1, 500, 10, 1e-12, 0.0);
}
}
#else
// 11. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the
// system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(*A);
umf_solver.Mult(B, X);
#endif
// 12. Recover the grid function corresponding to U. This is the
// local finite element solution.
a.RecoverFEMSolution(X, b, u);
// 13. Build a mass matrix to help solve for n.Grad(u) where 'n' is
// a surface normal.
BilinearForm m(&fespace);
m.AddDomainIntegrator(new MassIntegrator);
m.Assemble();
ess_tdof_list.SetSize(0);
OperatorPtr M;
m.FormSystemMatrix(ess_tdof_list, M);
// 14. Compute the various boundary integrals.
mfem::out << endl
<< "Verifying boundary conditions" << endl
<< "=============================" << endl;
{
// Integrate the solution on the Dirichlet boundary and compare
// to the expected value.
double err, avg = IntegrateBC(u, dbc_bdr, 0.0, 1.0, dbc_val, err);
bool hom_dbc = (dbc_val == 0.0);
err /= hom_dbc ? 1.0 : fabs(dbc_val);
mfem::out << "Average of solution on Gamma_dbc:\t"
<< avg << ", \t"
<< (hom_dbc ? "absolute" : "relative")
<< " error " << err << endl;
}
{
// Integrate n.Grad(u) on the inhomogeneous Neumann boundary and
// compare to the expected value.
double err, avg = IntegrateBC(u, nbc_bdr, 1.0, 0.0, nbc_val, err);
bool hom_nbc = (nbc_val == 0.0);
err /= hom_nbc ? 1.0 : fabs(nbc_val);
mfem::out << "Average of n.Grad(u) on Gamma_nbc:\t"
<< avg << ", \t"
<< (hom_nbc ? "absolute" : "relative")
<< " error " << err << endl;
}
{
// Integrate n.Grad(u) on the homogeneous Neumann boundary and compare
// to the expected value of zero.
Array<int> nbc0_bdr(mesh->bdr_attributes.Max());
nbc0_bdr = 0;
nbc0_bdr[3] = 1;
double err, avg = IntegrateBC(u, nbc0_bdr, 1.0, 0.0, 0.0, err);
bool hom_nbc = true;
mfem::out << "Average of n.Grad(u) on Gamma_nbc0:\t"
<< avg << ", \t"
<< (hom_nbc ? "absolute" : "relative")
<< " error " << err << endl;
}
{
// Integrate n.Grad(u) + a * u on the Robin boundary and compare to
// the expected value.
double err, avg = IntegrateBC(u, rbc_bdr, 1.0, rbc_a_val, rbc_b_val, err);
bool hom_rbc = (rbc_b_val == 0.0);
err /= hom_rbc ? 1.0 : fabs(rbc_b_val);
mfem::out << "Average of n.Grad(u)+a*u on Gamma_rbc:\t"
<< avg << ", \t"
<< (hom_rbc ? "absolute" : "relative")
<< " error " << err << endl;
}
// 15. Save the refined mesh and the solution. This output can be viewed
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
{
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
u.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
string title_str = h1 ? "H1" : "DG";
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << u
<< "window_title '" << title_str << " Solution'"
<< " keys 'mmc'" << flush;
}
// 17. Free the used memory.
delete fec;
delete mesh;
return 0;
}
void quad_trans(double u, double v, double &x, double &y, bool log = false)
{
double a = a_; // Radius of disc
double d = 4.0 * a * (M_SQRT2 - 2.0 * a) * (1.0 - 2.0 * v);
double v0 = (1.0 + M_SQRT2) * (M_SQRT2 * a - 2.0 * v) *
((4.0 - 3 * M_SQRT2) * a +
(8.0 * (M_SQRT2 - 1.0) * a - 2.0) * v) / d;
double r = 2.0 * ((M_SQRT2 - 1.0) * a * a * (1.0 - 4.0 *v) +
2.0 * (1.0 + M_SQRT2 *
(1.0 + 2.0 * (2.0 * a - M_SQRT2 - 1.0) * a)) * v * v
) / d;
double t = asin(v / r) * u / v;
if (log)
{
mfem::out << "u, v, r, v0, t "
<< u << " " << v << " " << r << " " << v0 << " " << t
<< endl;
}
x = r * sin(t);
y = r * cos(t) - v0;
}
void trans(const Vector &u, Vector &x)
{
double tol = 1e-4;
if (u[1] > 0.5 - tol || u[1] < -0.5 + tol)
{
x = u;
return;
}
if (u[0] > 1.0 - tol || u[0] < -1.0 + tol || fabs(u[0]) < tol)
{
x = u;
return;
}
if (u[0] > 0.0)
{
if (u[1] > fabs(u[0] - 0.5))
{
quad_trans(u[0] - 0.5, u[1], x[0], x[1]);
x[0] += 0.5;
return;
}
if (u[1] < -fabs(u[0] - 0.5))
{
quad_trans(u[0] - 0.5, -u[1], x[0], x[1]);
x[0] += 0.5;
x[1] *= -1.0;
return;
}
if (u[0] - 0.5 > fabs(u[1]))
{
quad_trans(u[1], u[0] - 0.5, x[1], x[0]);
x[0] += 0.5;
return;
}
if (u[0] - 0.5 < -fabs(u[1]))
{
quad_trans(u[1], 0.5 - u[0], x[1], x[0]);
x[0] *= -1.0;
x[0] += 0.5;
return;
}
}
else
{
if (u[1] > fabs(u[0] + 0.5))
{
quad_trans(u[0] + 0.5, u[1], x[0], x[1]);
x[0] -= 0.5;
return;
}
if (u[1] < -fabs(u[0] + 0.5))
{
quad_trans(u[0] + 0.5, -u[1], x[0], x[1]);
x[0] -= 0.5;
x[1] *= -1.0;
return;
}
if (u[0] + 0.5 > fabs(u[1]))
{
quad_trans(u[1], u[0] + 0.5, x[1], x[0]);
x[0] -= 0.5;
return;
}
if (u[0] + 0.5 < -fabs(u[1]))
{
quad_trans(u[1], -0.5 - u[0], x[1], x[0]);
x[0] *= -1.0;
x[0] -= 0.5;
return;
}
}
x = u;
}
Mesh * GenerateSerialMesh(int ref)
{
Mesh * mesh = new Mesh(2, 29, 16, 24, 2);
int vi[4];
for (int i=0; i<2; i++)
{
int o = 13 * i;
vi[0] = o + 0; vi[1] = o + 3; vi[2] = o + 4; vi[3] = o + 1;
mesh->AddQuad(vi);
vi[0] = o + 1; vi[1] = o + 4; vi[2] = o + 5; vi[3] = o + 2;
mesh->AddQuad(vi);
vi[0] = o + 5; vi[1] = o + 8; vi[2] = o + 9; vi[3] = o + 2;
mesh->AddQuad(vi);
vi[0] = o + 8; vi[1] = o + 12; vi[2] = o + 15; vi[3] = o + 9;
mesh->AddQuad(vi);
vi[0] = o + 11; vi[1] = o + 14; vi[2] = o + 15; vi[3] = o + 12;
mesh->AddQuad(vi);
vi[0] = o + 10; vi[1] = o + 13; vi[2] = o + 14; vi[3] = o + 11;
mesh->AddQuad(vi);
vi[0] = o + 6; vi[1] = o + 13; vi[2] = o + 10; vi[3] = o + 7;
mesh->AddQuad(vi);
vi[0] = o + 0; vi[1] = o + 6; vi[2] = o + 7; vi[3] = o + 3;
mesh->AddQuad(vi);
}
vi[0] = 0; vi[1] = 6; mesh->AddBdrSegment(vi, 1);
vi[0] = 6; vi[1] = 13; mesh->AddBdrSegment(vi, 1);
vi[0] = 13; vi[1] = 19; mesh->AddBdrSegment(vi, 1);
vi[0] = 19; vi[1] = 26; mesh->AddBdrSegment(vi, 1);
vi[0] = 28; vi[1] = 22; mesh->AddBdrSegment(vi, 2);
vi[0] = 22; vi[1] = 15; mesh->AddBdrSegment(vi, 2);
vi[0] = 15; vi[1] = 9; mesh->AddBdrSegment(vi, 2);
vi[0] = 9; vi[1] = 2; mesh->AddBdrSegment(vi, 2);
for (int i=0; i<2; i++)
{
int o = 13 * i;
vi[0] = o + 7; vi[1] = o + 3; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 10; vi[1] = o + 7; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 11; vi[1] = o + 10; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 12; vi[1] = o + 11; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 8; vi[1] = o + 12; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 5; vi[1] = o + 8; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 4; vi[1] = o + 5; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 3; vi[1] = o + 4; mesh->AddBdrSegment(vi, 3 + i);
}
double d[2];
double a = a_ / M_SQRT2;
d[0] = -1.0; d[1] = -0.5; mesh->AddVertex(d);
d[0] = -1.0; d[1] = 0.0; mesh->AddVertex(d);
d[0] = -1.0; d[1] = 0.5; mesh->AddVertex(d);
d[0] = -0.5 - a; d[1] = -a; mesh->AddVertex(d);
d[0] = -0.5 - a; d[1] = 0.0; mesh->AddVertex(d);
d[0] = -0.5 - a; d[1] = a; mesh->AddVertex(d);
d[0] = -0.5; d[1] = -0.5; mesh->AddVertex(d);
d[0] = -0.5; d[1] = -a; mesh->AddVertex(d);
d[0] = -0.5; d[1] = a; mesh->AddVertex(d);
d[0] = -0.5; d[1] = 0.5; mesh->AddVertex(d);
d[0] = -0.5 + a; d[1] = -a; mesh->AddVertex(d);
d[0] = -0.5 + a; d[1] = 0.0; mesh->AddVertex(d);
d[0] = -0.5 + a; d[1] = a; mesh->AddVertex(d);
d[0] = 0.0; d[1] = -0.5; mesh->AddVertex(d);
d[0] = 0.0; d[1] = 0.0; mesh->AddVertex(d);
d[0] = 0.0; d[1] = 0.5; mesh->AddVertex(d);
d[0] = 0.5 - a; d[1] = -a; mesh->AddVertex(d);
d[0] = 0.5 - a; d[1] = 0.0; mesh->AddVertex(d);
d[0] = 0.5 - a; d[1] = a; mesh->AddVertex(d);
d[0] = 0.5; d[1] = -0.5; mesh->AddVertex(d);
d[0] = 0.5; d[1] = -a; mesh->AddVertex(d);
d[0] = 0.5; d[1] = a; mesh->AddVertex(d);
d[0] = 0.5; d[1] = 0.5; mesh->AddVertex(d);
d[0] = 0.5 + a; d[1] = -a; mesh->AddVertex(d);
d[0] = 0.5 + a; d[1] = 0.0; mesh->AddVertex(d);
d[0] = 0.5 + a; d[1] = a; mesh->AddVertex(d);
d[0] = 1.0; d[1] = -0.5; mesh->AddVertex(d);
d[0] = 1.0; d[1] = 0.0; mesh->AddVertex(d);
d[0] = 1.0; d[1] = 0.5; mesh->AddVertex(d);
mesh->FinalizeTopology();
mesh->SetCurvature(1, true);
// Stitch the ends of the stack together
{
Array<int> v2v(mesh->GetNV());
for (int i = 0; i < v2v.Size() - 3; i++)
{
v2v[i] = i;
}
// identify vertices on the narrow ends of the rectangle
v2v[v2v.Size() - 3] = 0;
v2v[v2v.Size() - 2] = 1;
v2v[v2v.Size() - 1] = 2;
// renumber elements
for (int i = 0; i < mesh->GetNE(); i++)
{
Element *el = mesh->GetElement(i);
int *v = el->GetVertices();
int nv = el->GetNVertices();
for (int j = 0; j < nv; j++)
{
v[j] = v2v[v[j]];
}
}
// renumber boundary elements
for (int i = 0; i < mesh->GetNBE(); i++)
{
Element *el = mesh->GetBdrElement(i);
int *v = el->GetVertices();
int nv = el->GetNVertices();
for (int j = 0; j < nv; j++)
{
v[j] = v2v[v[j]];
}
}
mesh->RemoveUnusedVertices();
mesh->RemoveInternalBoundaries();
}
mesh->SetCurvature(3, true);
for (int l = 0; l < ref; l++)
{
mesh->UniformRefinement();
}
mesh->Transform(trans);
return mesh;
}
double IntegrateBC(const GridFunction &x, const Array<int> &bdr,
double alpha, double beta, double gamma,
double &err)
{
double nrm = 0.0;
double avg = 0.0;
err = 0.0;
const bool a_is_zero = alpha == 0.0;
const bool b_is_zero = beta == 0.0;
const FiniteElementSpace &fes = *x.FESpace();
MFEM_ASSERT(fes.GetVDim() == 1, "");
Mesh &mesh = *fes.GetMesh();
Vector shape, loc_dofs, w_nor;
DenseMatrix dshape;
Array<int> dof_ids;
for (int i = 0; i < mesh.GetNBE(); i++)
{
if (bdr[mesh.GetBdrAttribute(i)-1] == 0) { continue; }
FaceElementTransformations *FTr = mesh.GetBdrFaceTransformations(i);
if (FTr == nullptr) { continue; }
const FiniteElement &fe = *fes.GetFE(FTr->Elem1No);
MFEM_ASSERT(fe.GetMapType() == FiniteElement::VALUE, "");
const int int_order = 2*fe.GetOrder() + 3;
const IntegrationRule &ir = IntRules.Get(FTr->FaceGeom, int_order);
fes.GetElementDofs(FTr->Elem1No, dof_ids);
x.GetSubVector(dof_ids, loc_dofs);
if (!a_is_zero)
{
const int sdim = FTr->Face->GetSpaceDim();
w_nor.SetSize(sdim);
dshape.SetSize(fe.GetDof(), sdim);
}
if (!b_is_zero)
{
shape.SetSize(fe.GetDof());
}
for (int j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
IntegrationPoint eip;
FTr->Loc1.Transform(ip, eip);
FTr->Face->SetIntPoint(&ip);
double face_weight = FTr->Face->Weight();
double val = 0.0;
if (!a_is_zero)
{
FTr->Elem1->SetIntPoint(&eip);
fe.CalcPhysDShape(*FTr->Elem1, dshape);
CalcOrtho(FTr->Face->Jacobian(), w_nor);
val += alpha * dshape.InnerProduct(w_nor, loc_dofs) / face_weight;
}
if (!b_is_zero)
{
fe.CalcShape(eip, shape);
val += beta * (shape * loc_dofs);
}
// Measure the length of the boundary
nrm += ip.weight * face_weight;
// Integrate alpha * n.Grad(x) + beta * x
avg += val * ip.weight * face_weight;
// Integrate |alpha * n.Grad(x) + beta * x - gamma|^2
val -= gamma;
err += (val*val) * ip.weight * face_weight;
}
}
// Normalize by the length of the boundary
if (std::abs(nrm) > 0.0)
{
err /= nrm;
avg /= nrm;
}
// Compute l2 norm of the error in the boundary condition
// (negative quadrature weights may produce negative 'err')
err = (err >= 0.0) ? sqrt(err) : -sqrt(-err);
// Return the average value of alpha * n.Grad(x) + beta * x
return avg;
}
-773
View File
@@ -1,773 +0,0 @@
// MFEM Example 27 - Parallel Version
//
// Compile with: make ex27p
//
// Sample runs: mpirun -np 4 ex27p
// mpirun -np 4 ex27p -dg
// mpirun -np 4 ex27p -dg -dbc 8 -nbc -2
// mpirun -np 4 ex27p -rbc-a 1 -rbc-b 8
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 0 with a variety of boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order using a continuous or discontinuous space. We then
// apply Dirichlet, Neumann (both homogeneous and inhomogeneous),
// Robin, and Periodic boundary conditions on different portions
// of a predefined mesh.
//
// The predefined mesh consists of a rectangle with two
// holes removed (see below). The narrow ends of the
// mesh are connected to form a Periodic boundary
// condition. The lower edge (tagged with attribute 1)
// receives an inhomogeneous Neumann boundary condition.
// A Robin boundary condition is applied to upper edge
// (attribute 2). The circular hole on the left
// (attribute 3) enforces a Dirichlet boundary
// condition. Finally, a natural boundary condition, or
// homogeneous Neumann BC, is applied to the circular
// hole on the right (attribute 4).
//
// Attribute 3 ^ y Attribute 2
// \ | /
// +-----------+-----------+
// | \_ | _ |
// | / \ | / \ |
// <--+---+---+---+---+---+---+--> x
// | \_/ | \_/ |
// | | \ |
// +-----------+-----------+ (hole radii are
// / | \ adjustable)
// Attribute 1 v Attribute 4
//
// The boundary conditions are defined as (where u is
// the solution field):
// Dirichlet: u = d
// Neumann: n.Grad(u) = g
// Robin: n.Grad(u) + a u = b
//
// The user can adjust the values of 'd', 'g', 'a', and
// 'b' with command line options.
//
// This example highlights the differing implementations of
// boundary conditions with continuous and discontinuous Galerkin
// formulations of the Laplace problem.
//
// We recommend viewing examples 1 and 14 before viewing this
// example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
static double a_ = 0.2;
// Normal to hole with boundary attribute 4
void n4Vec(const Vector &x, Vector &n) { n = x; n[0] -= 0.5; n /= -n.Norml2(); }
Mesh * GenerateSerialMesh(int ref);
// Compute the average value of alpha*n.Grad(sol) + beta*sol over the boundary
// attributes marked in bdr_marker. Also computes the L2 norm of
// alpha*n.Grad(sol) + beta*sol - gamma over the same boundary.
double IntegrateBC(const ParGridFunction &sol, const Array<int> &bdr_marker,
double alpha, double beta, double gamma,
double &err);
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
MPI_Session mpi;
if (!mpi.Root()) { mfem::out.Disable(); mfem::err.Disable(); }
// 2. Parse command-line options.
int ser_ref_levels = 2;
int par_ref_levels = 1;
int order = 1;
double sigma = -1.0;
double kappa = -1.0;
bool h1 = true;
bool visualization = true;
double mat_val = 1.0;
double dbc_val = 0.0;
double nbc_val = 1.0;
double rbc_a_val = 1.0; // du/dn + a * u = b
double rbc_b_val = 1.0;
OptionsParser args(argc, argv);
args.AddOption(&h1, "-h1", "--continuous", "-dg", "--discontinuous",
"Select continuous \"H1\" or discontinuous \"DG\" basis.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&sigma, "-s", "--sigma",
"One of the two DG penalty parameters, typically +1/-1."
" See the documentation of class DGDiffusionIntegrator.");
args.AddOption(&kappa, "-k", "--kappa",
"One of the two DG penalty parameters, should be positive."
" Negative values are replaced with (order+1)^2.");
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(&mat_val, "-mat", "--material-value",
"Constant value for material coefficient "
"in the Laplace operator.");
args.AddOption(&dbc_val, "-dbc", "--dirichlet-value",
"Constant value for Dirichlet Boundary Condition.");
args.AddOption(&nbc_val, "-nbc", "--neumann-value",
"Constant value for Neumann Boundary Condition.");
args.AddOption(&rbc_a_val, "-rbc-a", "--robin-a-value",
"Constant 'a' value for Robin Boundary Condition: "
"du/dn + a * u = b.");
args.AddOption(&rbc_b_val, "-rbc-b", "--robin-b-value",
"Constant 'b' value for Robin Boundary Condition: "
"du/dn + a * u = b.");
args.AddOption(&a_, "-a", "--radius",
"Radius of holes in the mesh.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(mfem::out);
return 1;
}
if (kappa < 0 && !h1)
{
kappa = (order+1)*(order+1);
}
args.PrintOptions(mfem::out);
if (a_ < 0.01)
{
mfem::out << "Hole radius too small, resetting to 0.01.\n";
a_ = 0.01;
}
if (a_ > 0.49)
{
mfem::out << "Hole radius too large, resetting to 0.49.\n";
a_ = 0.49;
}
// 3. Construct the (serial) mesh and refine it if requested.
Mesh *mesh = GenerateSerialMesh(ser_ref_levels);
int dim = mesh->Dimension();
// 4. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
delete mesh;
for (int l = 0; l < par_ref_levels; l++)
{
pmesh.UniformRefinement();
}
// 5. Define a parallel finite element space on the parallel mesh. Here we
// use either continuous Lagrange finite elements or discontinuous
// Galerkin finite elements of the specified order.
FiniteElementCollection *fec =
h1 ? (FiniteElementCollection*)new H1_FECollection(order, dim) :
(FiniteElementCollection*)new DG_FECollection(order, dim);
ParFiniteElementSpace fespace(&pmesh, fec);
HYPRE_Int size = fespace.GlobalTrueVSize();
mfem::out << "Number of finite element unknowns: " << size << endl;
// 6. Create "marker arrays" to define the portions of the boundary
// associated with each type of boundary condition. These arrays
// have an entry corresponding to each boundary attribute.
// Placing a '1' in entry i marks attribute i+1 as being
// active, '0' is inactive.
Array<int> nbc_bdr(pmesh.bdr_attributes.Max());
Array<int> rbc_bdr(pmesh.bdr_attributes.Max());
Array<int> dbc_bdr(pmesh.bdr_attributes.Max());
nbc_bdr = 0; nbc_bdr[0] = 1;
rbc_bdr = 0; rbc_bdr[1] = 1;
dbc_bdr = 0; dbc_bdr[2] = 1;
Array<int> ess_tdof_list(0);
if (h1 && pmesh.bdr_attributes.Size())
{
// For a continuous basis the linear system must be modifed to enforce
// an essential (Dirichlet) boundary condition. In the DG case this is
// not necessary as the boundary condition will only be enforced weakly.
fespace.GetEssentialTrueDofs(dbc_bdr, ess_tdof_list);
}
// 7. Setup the various coefficients needed for the Laplace operator and
// the various boundary conditions. In general these coefficients could
// be functions of position but here we use only constants.
ConstantCoefficient matCoef(mat_val);
ConstantCoefficient dbcCoef(dbc_val);
ConstantCoefficient nbcCoef(nbc_val);
ConstantCoefficient rbcACoef(rbc_a_val);
ConstantCoefficient rbcBCoef(rbc_b_val);
// Since the n.Grad(u) terms arise by integrating -Div(m Grad(u)) by parts
// we must introduce the coefficient 'm' into the boundary conditions.
// Therefore, in the case of the Neumann BC, we actually enforce
// m n.Grad(u) = m g rather than simply n.Grad(u) = g.
ProductCoefficient m_nbcCoef(matCoef, nbcCoef);
ProductCoefficient m_rbcACoef(matCoef, rbcACoef);
ProductCoefficient m_rbcBCoef(matCoef, rbcBCoef);
// 8. Define the solution vector u as a parallel finite element grid function
// corresponding to fespace. Initialize u with initial guess of zero.
ParGridFunction u(&fespace);
u = 0.0;
// 9. Set up the parallel bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
ParBilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator(matCoef));
if (h1)
{
// Add a Mass integrator on the Robin boundary
a.AddBoundaryIntegrator(new MassIntegrator(m_rbcACoef), rbc_bdr);
}
else
{
// Add the interfacial portion of the Lapalce operator
a.AddInteriorFaceIntegrator(new DGDiffusionIntegrator(matCoef,
sigma, kappa));
// Counteract the n.Grad(u) term on the Dirichlet portion of the boundary
a.AddBdrFaceIntegrator(new DGDiffusionIntegrator(matCoef, sigma, kappa),
dbc_bdr);
// Augment the n.Grad(u) term with a*u on the Robin portion of boundary
a.AddBdrFaceIntegrator(new BoundaryMassIntegrator(m_rbcACoef),
rbc_bdr);
}
a.Assemble();
// 10. Assemble the parallel linear form for the right hand side vector.
ParLinearForm b(&fespace);
if (h1)
{
// Set the Dirchlet values in the solution vector
u.ProjectBdrCoefficient(dbcCoef, dbc_bdr);
// Add the desired value for n.Grad(u) on the Neumann boundary
b.AddBoundaryIntegrator(new BoundaryLFIntegrator(m_nbcCoef), nbc_bdr);
// Add the desired value for n.Grad(u) + a*u on the Robin boundary
b.AddBoundaryIntegrator(new BoundaryLFIntegrator(m_rbcBCoef), rbc_bdr);
}
else
{
// Add the desired value for the Dirchlet boundary
b.AddBdrFaceIntegrator(new DGDirichletLFIntegrator(dbcCoef, matCoef,
sigma, kappa),
dbc_bdr);
// Add the desired value for n.Grad(u) on the Neumann boundary
b.AddBdrFaceIntegrator(new BoundaryLFIntegrator(m_nbcCoef),
nbc_bdr);
// Add the desired value for n.Grad(u) + a*u on the Robin boundary
b.AddBdrFaceIntegrator(new BoundaryLFIntegrator(m_rbcBCoef),
rbc_bdr);
}
b.Assemble();
// 11. Construct the linear system.
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, u, b, A, X, B);
// 12. Solve the linear system A X = B.
HypreSolver *amg = new HypreBoomerAMG;
if (h1 || sigma == -1.0)
{
HyprePCG pcg(MPI_COMM_WORLD);
pcg.SetTol(1e-12);
pcg.SetMaxIter(200);
pcg.SetPrintLevel(2);
pcg.SetPreconditioner(*amg);
pcg.SetOperator(*A);
pcg.Mult(B, X);
}
else
{
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetAbsTol(0.0);
gmres.SetRelTol(1e-12);
gmres.SetMaxIter(200);
gmres.SetKDim(10);
gmres.SetPrintLevel(1);
gmres.SetPreconditioner(*amg);
gmres.SetOperator(*A);
gmres.Mult(B, X);
}
delete amg;
// 13. Recover the parallel grid function corresponding to U. This is the
// local finite element solution on each processor.
a.RecoverFEMSolution(X, b, u);
// 14. Build a mass matrix to help solve for n.Grad(u) where 'n' is
// a surface normal.
ParBilinearForm m(&fespace);
m.AddDomainIntegrator(new MassIntegrator);
m.Assemble();
ess_tdof_list.SetSize(0);
OperatorPtr M;
m.FormSystemMatrix(ess_tdof_list, M);
// 15. Compute the various boundary integrals.
mfem::out << endl
<< "Verifying boundary conditions" << endl
<< "=============================" << endl;
{
// Integrate the solution on the Dirichlet boundary and compare
// to the expected value.
double err, avg = IntegrateBC(u, dbc_bdr, 0.0, 1.0, dbc_val, err);
bool hom_dbc = (dbc_val == 0.0);
err /= hom_dbc ? 1.0 : fabs(dbc_val);
mfem::out << "Average of solution on Gamma_dbc:\t"
<< avg << ", \t"
<< (hom_dbc ? "absolute" : "relative")
<< " error " << err << endl;
}
{
// Integrate n.Grad(u) on the inhomogeneous Neumann boundary and
// compare to the expected value.
double err, avg = IntegrateBC(u, nbc_bdr, 1.0, 0.0, nbc_val, err);
bool hom_nbc = (nbc_val == 0.0);
err /= hom_nbc ? 1.0 : fabs(nbc_val);
mfem::out << "Average of n.Grad(u) on Gamma_nbc:\t"
<< avg << ", \t"
<< (hom_nbc ? "absolute" : "relative")
<< " error " << err << endl;
}
{
// Integrate n.Grad(u) on the homogeneous Neumann boundary and compare
// to the expected value of zero.
Array<int> nbc0_bdr(pmesh.bdr_attributes.Max());
nbc0_bdr = 0;
nbc0_bdr[3] = 1;
double err, avg = IntegrateBC(u, nbc0_bdr, 1.0, 0.0, 0.0, err);
bool hom_nbc = true;
mfem::out << "Average of n.Grad(u) on Gamma_nbc0:\t"
<< avg << ", \t"
<< (hom_nbc ? "absolute" : "relative")
<< " error " << err << endl;
}
{
// Integrate n.Grad(u) + a * u on the Robin boundary and compare to
// the expected value.
double err, avg = IntegrateBC(u, rbc_bdr, 1.0, rbc_a_val, rbc_b_val, err);
bool hom_rbc = (rbc_b_val == 0.0);
err /= hom_rbc ? 1.0 : fabs(rbc_b_val);
mfem::out << "Average of n.Grad(u)+a*u on Gamma_rbc:\t"
<< avg << ", \t"
<< (hom_rbc ? "absolute" : "relative")
<< " error " << err << endl;
}
// 16. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << mpi.WorldRank();
sol_name << "sol." << setfill('0') << setw(6) << mpi.WorldRank();
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh.Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
u.Save(sol_ofs);
}
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
string title_str = h1 ? "H1" : "DG";
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << mpi.WorldSize()
<< " " << mpi.WorldRank() << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << u
<< "window_title '" << title_str << " Solution'"
<< " keys 'mmc'" << flush;
}
// 18. Free the used memory.
delete fec;
return 0;
}
void quad_trans(double u, double v, double &x, double &y, bool log = false)
{
double a = a_; // Radius of disc
double d = 4.0 * a * (M_SQRT2 - 2.0 * a) * (1.0 - 2.0 * v);
double v0 = (1.0 + M_SQRT2) * (M_SQRT2 * a - 2.0 * v) *
((4.0 - 3 * M_SQRT2) * a +
(8.0 * (M_SQRT2 - 1.0) * a - 2.0) * v) / d;
double r = 2.0 * ((M_SQRT2 - 1.0) * a * a * (1.0 - 4.0 *v) +
2.0 * (1.0 + M_SQRT2 *
(1.0 + 2.0 * (2.0 * a - M_SQRT2 - 1.0) * a)) * v * v
) / d;
double t = asin(v / r) * u / v;
if (log)
{
mfem::out << "u, v, r, v0, t "
<< u << " " << v << " " << r << " " << v0 << " " << t
<< endl;
}
x = r * sin(t);
y = r * cos(t) - v0;
}
void trans(const Vector &u, Vector &x)
{
double tol = 1e-4;
if (u[1] > 0.5 - tol || u[1] < -0.5 + tol)
{
x = u;
return;
}
if (u[0] > 1.0 - tol || u[0] < -1.0 + tol || fabs(u[0]) < tol)
{
x = u;
return;
}
if (u[0] > 0.0)
{
if (u[1] > fabs(u[0] - 0.5))
{
quad_trans(u[0] - 0.5, u[1], x[0], x[1]);
x[0] += 0.5;
return;
}
if (u[1] < -fabs(u[0] - 0.5))
{
quad_trans(u[0] - 0.5, -u[1], x[0], x[1]);
x[0] += 0.5;
x[1] *= -1.0;
return;
}
if (u[0] - 0.5 > fabs(u[1]))
{
quad_trans(u[1], u[0] - 0.5, x[1], x[0]);
x[0] += 0.5;
return;
}
if (u[0] - 0.5 < -fabs(u[1]))
{
quad_trans(u[1], 0.5 - u[0], x[1], x[0]);
x[0] *= -1.0;
x[0] += 0.5;
return;
}
}
else
{
if (u[1] > fabs(u[0] + 0.5))
{
quad_trans(u[0] + 0.5, u[1], x[0], x[1]);
x[0] -= 0.5;
return;
}
if (u[1] < -fabs(u[0] + 0.5))
{
quad_trans(u[0] + 0.5, -u[1], x[0], x[1]);
x[0] -= 0.5;
x[1] *= -1.0;
return;
}
if (u[0] + 0.5 > fabs(u[1]))
{
quad_trans(u[1], u[0] + 0.5, x[1], x[0]);
x[0] -= 0.5;
return;
}
if (u[0] + 0.5 < -fabs(u[1]))
{
quad_trans(u[1], -0.5 - u[0], x[1], x[0]);
x[0] *= -1.0;
x[0] -= 0.5;
return;
}
}
x = u;
}
Mesh * GenerateSerialMesh(int ref)
{
Mesh * mesh = new Mesh(2, 29, 16, 24, 2);
int vi[4];
for (int i=0; i<2; i++)
{
int o = 13 * i;
vi[0] = o + 0; vi[1] = o + 3; vi[2] = o + 4; vi[3] = o + 1;
mesh->AddQuad(vi);
vi[0] = o + 1; vi[1] = o + 4; vi[2] = o + 5; vi[3] = o + 2;
mesh->AddQuad(vi);
vi[0] = o + 5; vi[1] = o + 8; vi[2] = o + 9; vi[3] = o + 2;
mesh->AddQuad(vi);
vi[0] = o + 8; vi[1] = o + 12; vi[2] = o + 15; vi[3] = o + 9;
mesh->AddQuad(vi);
vi[0] = o + 11; vi[1] = o + 14; vi[2] = o + 15; vi[3] = o + 12;
mesh->AddQuad(vi);
vi[0] = o + 10; vi[1] = o + 13; vi[2] = o + 14; vi[3] = o + 11;
mesh->AddQuad(vi);
vi[0] = o + 6; vi[1] = o + 13; vi[2] = o + 10; vi[3] = o + 7;
mesh->AddQuad(vi);
vi[0] = o + 0; vi[1] = o + 6; vi[2] = o + 7; vi[3] = o + 3;
mesh->AddQuad(vi);
}
vi[0] = 0; vi[1] = 6; mesh->AddBdrSegment(vi, 1);
vi[0] = 6; vi[1] = 13; mesh->AddBdrSegment(vi, 1);
vi[0] = 13; vi[1] = 19; mesh->AddBdrSegment(vi, 1);
vi[0] = 19; vi[1] = 26; mesh->AddBdrSegment(vi, 1);
vi[0] = 28; vi[1] = 22; mesh->AddBdrSegment(vi, 2);
vi[0] = 22; vi[1] = 15; mesh->AddBdrSegment(vi, 2);
vi[0] = 15; vi[1] = 9; mesh->AddBdrSegment(vi, 2);
vi[0] = 9; vi[1] = 2; mesh->AddBdrSegment(vi, 2);
for (int i=0; i<2; i++)
{
int o = 13 * i;
vi[0] = o + 7; vi[1] = o + 3; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 10; vi[1] = o + 7; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 11; vi[1] = o + 10; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 12; vi[1] = o + 11; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 8; vi[1] = o + 12; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 5; vi[1] = o + 8; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 4; vi[1] = o + 5; mesh->AddBdrSegment(vi, 3 + i);
vi[0] = o + 3; vi[1] = o + 4; mesh->AddBdrSegment(vi, 3 + i);
}
double d[2];
double a = a_ / M_SQRT2;
d[0] = -1.0; d[1] = -0.5; mesh->AddVertex(d);
d[0] = -1.0; d[1] = 0.0; mesh->AddVertex(d);
d[0] = -1.0; d[1] = 0.5; mesh->AddVertex(d);
d[0] = -0.5 - a; d[1] = -a; mesh->AddVertex(d);
d[0] = -0.5 - a; d[1] = 0.0; mesh->AddVertex(d);
d[0] = -0.5 - a; d[1] = a; mesh->AddVertex(d);
d[0] = -0.5; d[1] = -0.5; mesh->AddVertex(d);
d[0] = -0.5; d[1] = -a; mesh->AddVertex(d);
d[0] = -0.5; d[1] = a; mesh->AddVertex(d);
d[0] = -0.5; d[1] = 0.5; mesh->AddVertex(d);
d[0] = -0.5 + a; d[1] = -a; mesh->AddVertex(d);
d[0] = -0.5 + a; d[1] = 0.0; mesh->AddVertex(d);
d[0] = -0.5 + a; d[1] = a; mesh->AddVertex(d);
d[0] = 0.0; d[1] = -0.5; mesh->AddVertex(d);
d[0] = 0.0; d[1] = 0.0; mesh->AddVertex(d);
d[0] = 0.0; d[1] = 0.5; mesh->AddVertex(d);
d[0] = 0.5 - a; d[1] = -a; mesh->AddVertex(d);
d[0] = 0.5 - a; d[1] = 0.0; mesh->AddVertex(d);
d[0] = 0.5 - a; d[1] = a; mesh->AddVertex(d);
d[0] = 0.5; d[1] = -0.5; mesh->AddVertex(d);
d[0] = 0.5; d[1] = -a; mesh->AddVertex(d);
d[0] = 0.5; d[1] = a; mesh->AddVertex(d);
d[0] = 0.5; d[1] = 0.5; mesh->AddVertex(d);
d[0] = 0.5 + a; d[1] = -a; mesh->AddVertex(d);
d[0] = 0.5 + a; d[1] = 0.0; mesh->AddVertex(d);
d[0] = 0.5 + a; d[1] = a; mesh->AddVertex(d);
d[0] = 1.0; d[1] = -0.5; mesh->AddVertex(d);
d[0] = 1.0; d[1] = 0.0; mesh->AddVertex(d);
d[0] = 1.0; d[1] = 0.5; mesh->AddVertex(d);
mesh->FinalizeTopology();
mesh->SetCurvature(1, true);
// Stitch the ends of the stack together
{
Array<int> v2v(mesh->GetNV());
for (int i = 0; i < v2v.Size() - 3; i++)
{
v2v[i] = i;
}
// identify vertices on the narrow ends of the rectangle
v2v[v2v.Size() - 3] = 0;
v2v[v2v.Size() - 2] = 1;
v2v[v2v.Size() - 1] = 2;
// renumber elements
for (int i = 0; i < mesh->GetNE(); i++)
{
Element *el = mesh->GetElement(i);
int *v = el->GetVertices();
int nv = el->GetNVertices();
for (int j = 0; j < nv; j++)
{
v[j] = v2v[v[j]];
}
}
// renumber boundary elements
for (int i = 0; i < mesh->GetNBE(); i++)
{
Element *el = mesh->GetBdrElement(i);
int *v = el->GetVertices();
int nv = el->GetNVertices();
for (int j = 0; j < nv; j++)
{
v[j] = v2v[v[j]];
}
}
mesh->RemoveUnusedVertices();
mesh->RemoveInternalBoundaries();
}
mesh->SetCurvature(3, true);
for (int l = 0; l < ref; l++)
{
mesh->UniformRefinement();
}
mesh->Transform(trans);
return mesh;
}
double IntegrateBC(const ParGridFunction &x, const Array<int> &bdr,
double alpha, double beta, double gamma,
double &glb_err)
{
double loc_vals[3];
double &nrm = loc_vals[0];
double &avg = loc_vals[1];
double &err = loc_vals[2];
nrm = 0.0;
avg = 0.0;
err = 0.0;
const bool a_is_zero = alpha == 0.0;
const bool b_is_zero = beta == 0.0;
const ParFiniteElementSpace &fes = *x.ParFESpace();
MFEM_ASSERT(fes.GetVDim() == 1, "");
ParMesh &mesh = *fes.GetParMesh();
Vector shape, loc_dofs, w_nor;
DenseMatrix dshape;
Array<int> dof_ids;
for (int i = 0; i < mesh.GetNBE(); i++)
{
if (bdr[mesh.GetBdrAttribute(i)-1] == 0) { continue; }
FaceElementTransformations *FTr = mesh.GetBdrFaceTransformations(i);
if (FTr == nullptr) { continue; }
const FiniteElement &fe = *fes.GetFE(FTr->Elem1No);
MFEM_ASSERT(fe.GetMapType() == FiniteElement::VALUE, "");
const int int_order = 2*fe.GetOrder() + 3;
const IntegrationRule &ir = IntRules.Get(FTr->FaceGeom, int_order);
fes.GetElementDofs(FTr->Elem1No, dof_ids);
x.GetSubVector(dof_ids, loc_dofs);
if (!a_is_zero)
{
const int sdim = FTr->Face->GetSpaceDim();
w_nor.SetSize(sdim);
dshape.SetSize(fe.GetDof(), sdim);
}
if (!b_is_zero)
{
shape.SetSize(fe.GetDof());
}
for (int j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
IntegrationPoint eip;
FTr->Loc1.Transform(ip, eip);
FTr->Face->SetIntPoint(&ip);
double face_weight = FTr->Face->Weight();
double val = 0.0;
if (!a_is_zero)
{
FTr->Elem1->SetIntPoint(&eip);
fe.CalcPhysDShape(*FTr->Elem1, dshape);
CalcOrtho(FTr->Face->Jacobian(), w_nor);
val += alpha * dshape.InnerProduct(w_nor, loc_dofs) / face_weight;
}
if (!b_is_zero)
{
fe.CalcShape(eip, shape);
val += beta * (shape * loc_dofs);
}
// Measure the length of the boundary
nrm += ip.weight * face_weight;
// Integrate alpha * n.Grad(x) + beta * x
avg += val * ip.weight * face_weight;
// Integrate |alpha * n.Grad(x) + beta * x - gamma|^2
val -= gamma;
err += (val*val) * ip.weight * face_weight;
}
}
double glb_vals[3];
MPI_Allreduce(loc_vals, glb_vals, 3, MPI_DOUBLE, MPI_SUM, fes.GetComm());
double glb_nrm = glb_vals[0];
double glb_avg = glb_vals[1];
glb_err = glb_vals[2];
// Normalize by the length of the boundary
if (std::abs(glb_nrm) > 0.0)
{
glb_err /= glb_nrm;
glb_avg /= glb_nrm;
}
// Compute l2 norm of the error in the boundary condition
// (negative quadrature weights may produce negative 'err')
glb_err = (glb_err >= 0.0) ? sqrt(glb_err) : -sqrt(-glb_err);
// Return the average value of alpha * n.Grad(x) + beta * x
return glb_avg;
}
+26 -60
View File
@@ -6,7 +6,6 @@
// ex4 -m ../data/star.mesh
// ex4 -m ../data/beam-tet.mesh
// ex4 -m ../data/beam-hex.mesh
// ex4 -m ../data/beam-hex.mesh -o 2 -pa
// ex4 -m ../data/escher.mesh
// ex4 -m ../data/fichera.mesh -o 2 -hb
// ex4 -m ../data/fichera-q2.vtk
@@ -21,12 +20,6 @@
// ex4 -m ../data/fichera-amr.mesh -o 2 -sc
// ex4 -m ../data/star-surf.mesh -o 1
//
// Device sample runs:
// ex4 -m ../data/star.mesh -pa -d cuda
// ex4 -m ../data/star.mesh -pa -d raja-cuda
// ex4 -m ../data/star.mesh -pa -d raja-omp
// ex4 -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code solves a simple 2D/3D H(div) diffusion
// problem corresponding to the second order definite equation
// -grad(alpha div F) + beta F = f with boundary condition F dot n
@@ -62,8 +55,6 @@ int main(int argc, char *argv[])
bool set_bc = true;
bool static_cond = false;
bool hybridization = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -79,10 +70,6 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
"--no-hybridization", "Enable hybridization.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -95,19 +82,14 @@ int main(int argc, char *argv[])
args.PrintOptions(cout);
kappa = freq * M_PI;
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume, as well as
// periodic meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the mesh to increase the resolution. In this example we do
// 3. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 25,000
// elements.
@@ -120,14 +102,14 @@ int main(int argc, char *argv[])
}
}
// 5. Define a finite element space on the mesh. Here we use the
// 4. Define a finite element space on the mesh. Here we use the
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *fec = new RT_FECollection(order-1, dim);
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
cout << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
@@ -139,7 +121,7 @@ int main(int argc, char *argv[])
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 7. Set up the linear form b(.) which corresponds to the right-hand side
// 6. Set up the linear form b(.) which corresponds to the right-hand side
// of the FEM linear system, which in this case is (f,phi_i) where f is
// given by the function f_exact and phi_i are the basis functions in the
// finite element fespace.
@@ -148,7 +130,7 @@ int main(int argc, char *argv[])
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 8. Define the solution vector x as a finite element grid function
// 7. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary faces will be used
// when eliminating the non-homogeneous boundary condition to modify the
@@ -157,17 +139,16 @@ int main(int argc, char *argv[])
VectorFunctionCoefficient F(sdim, F_exact);
x.ProjectCoefficient(F);
// 9. Set up the bilinear form corresponding to the H(div) diffusion operator
// 8. Set up the bilinear form corresponding to the H(div) diffusion operator
// grad alpha div + beta I, by adding the div-div and the mass domain
// integrators.
Coefficient *alpha = new ConstantCoefficient(1.0);
Coefficient *beta = new ConstantCoefficient(1.0);
BilinearForm *a = new BilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
// 10. Assemble the bilinear form and the corresponding linear system,
// 9. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, hybridization, etc.
@@ -186,47 +167,32 @@ int main(int argc, char *argv[])
}
a->Assemble();
OperatorPtr A;
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A->Height() << endl;
cout << "Size of linear system: " << A.Height() << endl;
// 11. Solve the linear system A X = B.
if (!pa)
{
#ifndef MFEM_USE_SUITESPARSE
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 1, 10000, 1e-20, 0.0);
// 10. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
PCG(A, M, B, X, 1, 10000, 1e-20, 0.0);
#else
// If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(*A);
umf_solver.Mult(B, X);
// 10. If compiled with SuiteSparse support, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
#endif
}
else // Jacobi preconditioning in partial assembly mode
{
if (UsesTensorBasis(*fespace))
{
OperatorJacobiSmoother M(*a, ess_tdof_list);
PCG(*A, M, B, X, 1, 10000, 1e-20, 0.0);
}
else
{
CG(*A, B, X, 1, 10000, 1e-20, 0.0);
}
}
// 12. Recover the solution as a finite element grid function.
// 11. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 13. Compute and print the L^2 norm of the error.
// 12. Compute and print the L^2 norm of the error.
cout << "\n|| F_h - F ||_{L^2} = " << x.ComputeL2Error(F) << '\n' << endl;
// 14. Save the refined mesh and the solution. This output can be viewed
// 13. Save the refined mesh and the solution. This output can be viewed
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
{
ofstream mesh_ofs("refined.mesh");
@@ -237,7 +203,7 @@ int main(int argc, char *argv[])
x.Save(sol_ofs);
}
// 15. Send the solution by socket to a GLVis server.
// 14. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
@@ -247,7 +213,7 @@ int main(int argc, char *argv[])
sol_sock << "solution\n" << *mesh << x << flush;
}
// 16. Free the used memory.
// 15. Free the used memory.
delete hfes;
delete hfec;
delete a;
@@ -269,7 +235,7 @@ void F_exact(const Vector &p, Vector &F)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if F is changed to depend on z
// double z = (dim == 3) ? p(2) : 0.0;
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
@@ -286,7 +252,7 @@ void f_exact(const Vector &p, Vector &f)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if f is changed to depend on z
// double z = (dim == 3) ? p(2) : 0.0;
double temp = 1 + 2*kappa*kappa;
+29 -51
View File
@@ -6,7 +6,6 @@
// mpirun -np 4 ex4p -m ../data/star.mesh
// mpirun -np 4 ex4p -m ../data/beam-tet.mesh
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh -o 2 -pa
// mpirun -np 4 ex4p -m ../data/escher.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/fichera.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/fichera-q2.vtk
@@ -16,17 +15,10 @@
// 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
//
// Device sample runs:
// mpirun -np 4 ex4p -m ../data/star.mesh -pa -d cuda
// mpirun -np 4 ex4p -m ../data/star.mesh -pa -d raja-cuda
// mpirun -np 4 ex4p -m ../data/star.mesh -pa -d raja-omp
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code solves a simple 2D/3D H(div) diffusion
// problem corresponding to the second order definite equation
// -grad(alpha div F) + beta F = f with boundary condition F dot n
@@ -68,8 +60,6 @@ int main(int argc, char *argv[])
bool set_bc = true;
bool static_cond = false;
bool hybridization = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -85,10 +75,6 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
"--no-hybridization", "Enable hybridization.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -108,19 +94,14 @@ int main(int argc, char *argv[])
}
kappa = freq * M_PI;
// 3. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume, as well as periodic meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 5. Refine the serial mesh on all processors to increase the resolution. In
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
@@ -133,7 +114,7 @@ int main(int argc, char *argv[])
}
}
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
@@ -149,7 +130,7 @@ int main(int argc, char *argv[])
}
pmesh->ReorientTetMesh();
// 7. Define a parallel finite element space on the parallel mesh. Here we
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *fec = new RT_FECollection(order-1, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
@@ -159,7 +140,7 @@ int main(int argc, char *argv[])
cout << "Number of finite element unknowns: " << size << endl;
}
// 8. Determine the list of true (i.e. parallel conforming) essential
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
@@ -171,7 +152,7 @@ int main(int argc, char *argv[])
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 9. Set up the parallel linear form b(.) which corresponds to the
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
@@ -180,7 +161,7 @@ int main(int argc, char *argv[])
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 10. Define the solution vector x as a parallel finite element grid function
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary faces will be used
// when eliminating the non-homogeneous boundary condition to modify the
@@ -189,17 +170,16 @@ int main(int argc, char *argv[])
VectorFunctionCoefficient F(sdim, F_exact);
x.ProjectCoefficient(F);
// 11. Set up the parallel bilinear form corresponding to the H(div)
// 10. Set up the parallel bilinear form corresponding to the H(div)
// diffusion operator grad alpha div + beta I, by adding the div-div and
// the mass domain integrators.
Coefficient *alpha = new ConstantCoefficient(1.0);
Coefficient *beta = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
// 12. Assemble the parallel bilinear form and the corresponding linear
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation,
@@ -219,43 +199,41 @@ int main(int argc, char *argv[])
}
a->Assemble();
OperatorPtr A;
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0 && !pa)
HYPRE_Int glob_size = A.GetGlobalNumRows();
if (myid == 0)
{
cout << "Size of linear system: "
<< A.As<HypreParMatrix>()->GetGlobalNumRows() << endl;
cout << "Size of linear system: " << glob_size << endl;
}
// 13. Define and apply a parallel PCG solver for A X = B with the 2D AMS or
// 12. Define and apply a parallel PCG solver for A X = B with the 2D AMS or
// the 3D ADS preconditioners from hypre. If using hybridization, the
// system is preconditioned with hypre's BoomerAMG. In the partial
// assembly case, use Jacobi preconditioning.
Solver *prec = NULL;
CGSolver *pcg = new CGSolver(MPI_COMM_WORLD);
pcg->SetOperator(*A);
// system is preconditioned with hypre's BoomerAMG.
HypreSolver *prec = NULL;
CGSolver *pcg = new CGSolver(A.GetComm());
pcg->SetOperator(A);
pcg->SetRelTol(1e-12);
pcg->SetMaxIter(2000);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(1);
if (hybridization) { prec = new HypreBoomerAMG(*A.As<HypreParMatrix>()); }
else if (pa) { prec = new OperatorJacobiSmoother(*a, ess_tdof_list); }
if (hybridization) { prec = new HypreBoomerAMG(A); }
else
{
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
if (dim == 2) { prec = new HypreAMS(*A.As<HypreParMatrix>(), prec_fespace); }
else { prec = new HypreADS(*A.As<HypreParMatrix>(), prec_fespace); }
if (dim == 2) { prec = new HypreAMS(A, prec_fespace); }
else { prec = new HypreADS(A, prec_fespace); }
}
pcg->SetPreconditioner(*prec);
pcg->Mult(B, X);
// 14. Recover the parallel grid function corresponding to X. This is the
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// 15. Compute and print the L^2 norm of the error.
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(F);
if (myid == 0)
@@ -264,7 +242,7 @@ int main(int argc, char *argv[])
}
}
// 16. Save the refined mesh and the solution in parallel. This output can
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
@@ -280,7 +258,7 @@ int main(int argc, char *argv[])
x.Save(sol_ofs);
}
// 17. Send the solution by socket to a GLVis server.
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
@@ -291,7 +269,7 @@ int main(int argc, char *argv[])
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 18. Free the used memory.
// 17. Free the used memory.
delete pcg;
delete prec;
delete hfes;
@@ -317,7 +295,7 @@ void F_exact(const Vector &p, Vector &F)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if F is changed to depend on z
// double z = (dim == 3) ? p(2) : 0.0;
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
@@ -334,7 +312,7 @@ void f_exact(const Vector &p, Vector &f)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if f is changed to depend on z
// double z = (dim == 3) ? p(2) : 0.0;
double temp = 1 + 2*kappa*kappa;
+24 -76
View File
@@ -4,10 +4,8 @@
//
// Sample runs: ex5 -m ../data/square-disc.mesh
// ex5 -m ../data/star.mesh
// ex5 -m ../data/star.mesh -pa
// ex5 -m ../data/beam-tet.mesh
// ex5 -m ../data/beam-hex.mesh
// ex5 -m ../data/beam-hex.mesh -pa
// ex5 -m ../data/escher.mesh
// ex5 -m ../data/fichera.mesh
//
@@ -49,7 +47,6 @@ int main(int argc, char *argv[])
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
bool pa = false;
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -57,8 +54,6 @@ int main(int argc, char *argv[])
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -151,39 +146,22 @@ int main(int argc, char *argv[])
BilinearForm *mVarf(new BilinearForm(R_space));
MixedBilinearForm *bVarf(new MixedBilinearForm(R_space, W_space));
if (pa) { mVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(k));
mVarf->Assemble();
if (!pa) { mVarf->Finalize(); }
mVarf->Finalize();
SparseMatrix &M(mVarf->SpMat());
if (pa) { bVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
bVarf->Assemble();
if (!pa) { bVarf->Finalize(); }
bVarf->Finalize();
SparseMatrix & B(bVarf->SpMat());
B *= -1.;
SparseMatrix *BT = Transpose(B);
BlockOperator darcyOp(block_offsets);
TransposeOperator *Bt = NULL;
if (pa)
{
Bt = new TransposeOperator(bVarf);
darcyOp.SetBlock(0,0, mVarf);
darcyOp.SetBlock(0,1, Bt, -1.0);
darcyOp.SetBlock(1,0, bVarf, -1.0);
}
else
{
SparseMatrix &M(mVarf->SpMat());
SparseMatrix &B(bVarf->SpMat());
B *= -1.;
Bt = new TransposeOperator(&B);
darcyOp.SetBlock(0,0, &M);
darcyOp.SetBlock(0,1, Bt);
darcyOp.SetBlock(1,0, &B);
}
BlockMatrix darcyMatrix(block_offsets);
darcyMatrix.SetBlock(0,0, &M);
darcyMatrix.SetBlock(0,1, BT);
darcyMatrix.SetBlock(1,0, &B);
// 9. Construct the operators for preconditioner
//
@@ -192,57 +170,27 @@ int main(int argc, char *argv[])
//
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
// pressure Schur Complement
SparseMatrix *MinvBt = NULL;
Vector Md(mVarf->Height());
SparseMatrix *MinvBt = Transpose(B);
Vector Md(M.Height());
M.GetDiag(Md);
for (int i = 0; i < Md.Size(); i++)
{
MinvBt->ScaleRow(i, 1./Md(i));
}
SparseMatrix *S = Mult(B, *MinvBt);
BlockDiagonalPreconditioner darcyPrec(block_offsets);
Solver *invM, *invS;
SparseMatrix *S = NULL;
if (pa)
{
mVarf->AssembleDiagonal(Md);
Vector invMd(mVarf->Height());
for (int i=0; i<mVarf->Height(); ++i)
{
invMd(i) = 1.0 / Md(i);
}
Vector BMBt_diag(bVarf->Height());
bVarf->AssembleDiagonal_ADAt(invMd, BMBt_diag);
Array<int> ess_tdof_list; // empty
invM = new OperatorJacobiSmoother(Md, ess_tdof_list);
invS = new OperatorJacobiSmoother(BMBt_diag, ess_tdof_list);
}
else
{
SparseMatrix &M(mVarf->SpMat());
M.GetDiag(Md);
SparseMatrix &B(bVarf->SpMat());
MinvBt = Transpose(B);
for (int i = 0; i < Md.Size(); i++)
{
MinvBt->ScaleRow(i, 1./Md(i));
}
S = Mult(B, *MinvBt);
invM = new DSmoother(M);
invM = new DSmoother(M);
#ifndef MFEM_USE_SUITESPARSE
invS = new GSSmoother(*S);
invS = new GSSmoother(*S);
#else
invS = new UMFPackSolver(*S);
invS = new UMFPackSolver(*S);
#endif
}
invM->iterative_mode = false;
invS->iterative_mode = false;
BlockDiagonalPreconditioner darcyPrec(block_offsets);
darcyPrec.SetDiagonalBlock(0, invM);
darcyPrec.SetDiagonalBlock(1, invS);
@@ -258,7 +206,7 @@ int main(int argc, char *argv[])
solver.SetAbsTol(atol);
solver.SetRelTol(rtol);
solver.SetMaxIter(maxIter);
solver.SetOperator(darcyOp);
solver.SetOperator(darcyMatrix);
solver.SetPreconditioner(darcyPrec);
solver.SetPrintLevel(1);
x = 0.0;
@@ -347,8 +295,8 @@ int main(int argc, char *argv[])
delete invM;
delete invS;
delete S;
delete Bt;
delete MinvBt;
delete BT;
delete mVarf;
delete bVarf;
delete W_space;
+27 -112
View File
@@ -4,10 +4,8 @@
//
// Sample runs: mpirun -np 4 ex5p -m ../data/square-disc.mesh
// mpirun -np 4 ex5p -m ../data/star.mesh
// mpirun -np 4 ex5p -m ../data/star.mesh -r 2 -pa
// mpirun -np 4 ex5p -m ../data/beam-tet.mesh
// mpirun -np 4 ex5p -m ../data/beam-hex.mesh
// mpirun -np 4 ex5p -m ../data/beam-hex.mesh -pa
// mpirun -np 4 ex5p -m ../data/escher.mesh
// mpirun -np 4 ex5p -m ../data/fichera.mesh
//
@@ -24,8 +22,6 @@
// The example demonstrates the use of the BlockMatrix class, as
// well as the collective saving of several grid functions in
// VisIt (visit.llnl.gov) and ParaView (paraview.org) formats.
// Optional saving with ADIOS2 (adios2.readthedocs.io) streams is
// also illustrated.
//
// We recommend viewing examples 1-4 before viewing this example.
@@ -56,31 +52,21 @@ int main(int argc, char *argv[])
// 2. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int ref_levels = -1;
int order = 1;
bool par_format = false;
bool pa = false;
bool visualization = 1;
bool adios2 = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&par_format, "-pf", "--parallel-format", "-sf",
"--serial-format",
"Format to use when saving the results for VisIt.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&adios2, "-adios2", "--adios2-streams", "-no-adios2",
"--no-adios2-streams",
"Save data using adios2 streams.");
args.Parse();
if (!args.Good())
{
@@ -105,13 +91,10 @@ int main(int argc, char *argv[])
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 10,000 elements, unless the user specifies it as input.
// more than 10,000 elements.
{
if (ref_levels == -1)
{
ref_levels = (int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
}
int ref_levels =
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
@@ -207,47 +190,25 @@ int main(int argc, char *argv[])
ParBilinearForm *mVarf(new ParBilinearForm(R_space));
ParMixedBilinearForm *bVarf(new ParMixedBilinearForm(R_space, W_space));
HypreParMatrix *M = NULL;
HypreParMatrix *B = NULL;
HypreParMatrix *M, *B;
if (pa) { mVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(k));
mVarf->Assemble();
if (!pa) { mVarf->Finalize(); }
mVarf->Finalize();
M = mVarf->ParallelAssemble();
if (pa) { bVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
bVarf->Assemble();
if (!pa) { bVarf->Finalize(); }
bVarf->Finalize();
B = bVarf->ParallelAssemble();
(*B) *= -1;
HypreParMatrix *BT = B->Transpose();
BlockOperator *darcyOp = new BlockOperator(block_trueOffsets);
Array<int> empty_tdof_list; // empty
OperatorPtr opM, opB;
TransposeOperator *Bt = NULL;
if (pa)
{
mVarf->FormSystemMatrix(empty_tdof_list, opM);
bVarf->FormRectangularSystemMatrix(empty_tdof_list, empty_tdof_list, opB);
Bt = new TransposeOperator(opB.Ptr());
darcyOp->SetBlock(0,0, opM.Ptr());
darcyOp->SetBlock(0,1, Bt, -1.0);
darcyOp->SetBlock(1,0, opB.Ptr(), -1.0);
}
else
{
M = mVarf->ParallelAssemble();
B = bVarf->ParallelAssemble();
(*B) *= -1;
Bt = new TransposeOperator(B);
darcyOp->SetBlock(0,0, M);
darcyOp->SetBlock(0,1, Bt);
darcyOp->SetBlock(1,0, B);
}
darcyOp->SetBlock(0,0, M);
darcyOp->SetBlock(0,1, BT);
darcyOp->SetBlock(1,0, B);
// 11. Construct the operators for preconditioner
//
@@ -256,43 +217,17 @@ int main(int argc, char *argv[])
//
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
// pressure Schur Complement.
HypreParMatrix *MinvBt = NULL;
HypreParVector *Md = NULL;
HypreParMatrix *S = NULL;
Vector Md_PA;
Solver *invM, *invS;
HypreParMatrix *MinvBt = B->Transpose();
HypreParVector *Md = new HypreParVector(MPI_COMM_WORLD, M->GetGlobalNumRows(),
M->GetRowStarts());
M->GetDiag(*Md);
if (pa)
{
Md_PA.SetSize(R_space->GetTrueVSize());
mVarf->AssembleDiagonal(Md_PA);
Vector invMd(Md_PA.Size());
for (int i=0; i<Md_PA.Size(); ++i)
{
invMd(i) = 1.0 / Md_PA(i);
}
MinvBt->InvScaleRows(*Md);
HypreParMatrix *S = ParMult(B, MinvBt);
Vector BMBt_diag(W_space->GetTrueVSize());
bVarf->AssembleDiagonal_ADAt(invMd, BMBt_diag);
Array<int> ess_tdof_list; // empty
invM = new OperatorJacobiSmoother(Md_PA, ess_tdof_list);
invS = new OperatorJacobiSmoother(BMBt_diag, ess_tdof_list);
}
else
{
Md = new HypreParVector(MPI_COMM_WORLD, M->GetGlobalNumRows(),
M->GetRowStarts());
M->GetDiag(*Md);
MinvBt = B->Transpose();
MinvBt->InvScaleRows(*Md);
S = ParMult(B, MinvBt);
invM = new HypreDiagScale(*M);
invS = new HypreBoomerAMG(*S);
}
HypreSolver *invM, *invS;
invM = new HypreDiagScale(*M);
invS = new HypreBoomerAMG(*S);
invM->iterative_mode = false;
invS->iterative_mode = false;
@@ -304,7 +239,7 @@ int main(int argc, char *argv[])
// 12. Solve the linear system with MINRES.
// Check the norm of the unpreconditioned residual.
int maxIter(pa ? 1000 : 500);
int maxIter(500);
double rtol(1.e-6);
double atol(1.e-10);
@@ -402,27 +337,7 @@ int main(int argc, char *argv[])
paraview_dc.RegisterField("pressure",p);
paraview_dc.Save();
// 17. Optionally output a BP (binary pack) file using ADIOS2. This can be
// visualized with the ParaView VTX reader.
#ifdef MFEM_USE_ADIOS2
if (adios2)
{
std::string postfix(mesh_file);
postfix.erase(0, std::string("../data/").size() );
postfix += "_o" + std::to_string(order);
const std::string collection_name = "ex5-p_" + postfix + ".bp";
ADIOS2DataCollection adios2_dc(MPI_COMM_WORLD, collection_name, pmesh);
adios2_dc.SetLevelsOfDetail(1);
adios2_dc.SetCycle(1);
adios2_dc.SetTime(0.0);
adios2_dc.RegisterField("velocity",u);
adios2_dc.RegisterField("pressure",p);
adios2_dc.Save();
}
#endif
// 18. Send the solution by socket to a GLVis server.
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
@@ -442,7 +357,7 @@ int main(int argc, char *argv[])
<< endl;
}
// 19. Free the used memory.
// 18. Free the used memory.
delete fform;
delete gform;
delete u;
@@ -454,7 +369,7 @@ int main(int argc, char *argv[])
delete S;
delete Md;
delete MinvBt;
delete Bt;
delete BT;
delete B;
delete M;
delete mVarf;
-7
View File
@@ -279,11 +279,4 @@ void SnapNodes(Mesh &mesh)
nodes(nodes.FESpace()->DofToVDof(i, d)) = node(d);
}
}
if (mesh.Nonconforming())
{
// Snap hanging nodes to the master side.
Vector tnodes;
nodes.GetTrueDofs(tnodes);
nodes.SetFromTrueDofs(tnodes);
}
}
-7
View File
@@ -348,11 +348,4 @@ void SnapNodes(Mesh &mesh)
nodes(nodes.FESpace()->DofToVDof(i, d)) = node(d);
}
}
if (mesh.Nonconforming())
{
// Snap hanging nodes to the master side.
Vector tnodes;
nodes.GetTrueDofs(tnodes);
nodes.SetFromTrueDofs(tnodes);
}
}
+1 -11
View File
@@ -19,7 +19,6 @@
//
// Device sample runs:
// ex9 -pa
// ex9 -ea
// ex9 -pa -m ../data/periodic-cube.mesh
// ex9 -pa -m ../data/periodic-cube.mesh -d cuda
//
@@ -143,7 +142,6 @@ int main(int argc, char *argv[])
int ref_levels = 2;
int order = 3;
bool pa = false;
bool ea = false;
const char *device_config = "cpu";
int ode_solver_type = 4;
double t_final = 10.0;
@@ -168,8 +166,6 @@ int main(int argc, char *argv[])
"Order (degree) of the finite elements.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
@@ -273,11 +269,6 @@ int main(int argc, char *argv[])
m.SetAssemblyLevel(AssemblyLevel::PARTIAL);
k.SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
else if (ea)
{
m.SetAssemblyLevel(AssemblyLevel::ELEMENT);
k.SetAssemblyLevel(AssemblyLevel::ELEMENT);
}
m.AddDomainIntegrator(new MassIntegrator);
k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
k.AddInteriorFaceIntegrator(
@@ -438,9 +429,8 @@ FE_Evolution::FE_Evolution(BilinearForm &_M, BilinearForm &_K, const Vector &_b)
: TimeDependentOperator(_M.Height()), M(_M), K(_K), b(_b), z(_M.Height())
{
bool pa = M.GetAssemblyLevel() == AssemblyLevel::PARTIAL;
bool ea = M.GetAssemblyLevel() == AssemblyLevel::ELEMENT;
Array<int> ess_tdof_list;
if (pa || ea)
if (pa)
{
M_prec = new OperatorJacobiSmoother(M, ess_tdof_list);
M_solver.SetOperator(M);
+5 -59
View File
@@ -16,11 +16,9 @@
// 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
// mpirun -np 4 ex9p -ea
// mpirun -np 4 ex9p -pa -m ../data/periodic-cube.mesh
// mpirun -np 4 ex9p -pa -m ../data/periodic-cube.mesh -d cuda
//
@@ -33,10 +31,9 @@
// and explicit ODE time integrators, the definition of periodic
// boundary conditions through periodic meshes, as well as the use
// of GLVis for persistent visualization of a time-evolving
// solution. Saving of time-dependent data files for visualization
// with VisIt (visit.llnl.gov) and ParaView (paraview.org), as
// well as the optional saving with ADIOS2 (adios2.readthedocs.io)
// are also illustrated.
// solution. The saving of time-dependent data files for external
// visualization with VisIt (visit.llnl.gov) and ParaView
// (paraview.org) is also illustrated.
#include "mfem.hpp"
#include <fstream>
@@ -163,7 +160,6 @@ int main(int argc, char *argv[])
int par_ref_levels = 0;
int order = 3;
bool pa = false;
bool ea = false;
const char *device_config = "cpu";
int ode_solver_type = 4;
double t_final = 10.0;
@@ -171,7 +167,6 @@ int main(int argc, char *argv[])
bool visualization = true;
bool visit = false;
bool paraview = false;
bool adios2 = false;
bool binary = false;
int vis_steps = 5;
@@ -191,8 +186,6 @@ int main(int argc, char *argv[])
"Order (degree) of the finite elements.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
@@ -215,9 +208,6 @@ int main(int argc, char *argv[])
args.AddOption(&paraview, "-paraview", "--paraview-datafiles", "-no-paraview",
"--no-paraview-datafiles",
"Save data files for ParaView (paraview.org) visualization.");
args.AddOption(&adios2, "-adios2", "--adios2-streams", "-no-adios2",
"--no-adios2-streams",
"Save data using adios2 streams.");
args.AddOption(&binary, "-binary", "--binary-datafiles", "-ascii",
"--ascii-datafiles",
"Use binary (Sidre) or ascii format for VisIt data files.");
@@ -324,11 +314,6 @@ int main(int argc, char *argv[])
m->SetAssemblyLevel(AssemblyLevel::PARTIAL);
k->SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
else if (ea)
{
m->SetAssemblyLevel(AssemblyLevel::ELEMENT);
k->SetAssemblyLevel(AssemblyLevel::ELEMENT);
}
m->AddDomainIntegrator(new MassIntegrator);
k->AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
k->AddInteriorFaceIntegrator(
@@ -409,28 +394,6 @@ int main(int argc, char *argv[])
pd->Save();
}
// Optionally output a BP (binary pack) file using ADIOS2. This can be
// visualized with the ParaView VTX reader.
#ifdef MFEM_USE_ADIOS2
ADIOS2DataCollection *adios2_dc = NULL;
if (adios2)
{
std::string postfix(mesh_file);
postfix.erase(0, std::string("../data/").size() );
postfix += "_o" + std::to_string(order);
const std::string collection_name = "ex9-p-" + postfix + ".bp";
adios2_dc = new ADIOS2DataCollection(MPI_COMM_WORLD, collection_name, pmesh);
// output data substreams are half the number of mpi processes
adios2_dc->SetParameter("SubStreams", std::to_string(num_procs/2) );
// adios2_dc->SetLevelsOfDetail(2);
adios2_dc->RegisterField("solution", u);
adios2_dc->SetCycle(0);
adios2_dc->SetTime(0.0);
adios2_dc->Save();
}
#endif
socketstream sout;
if (visualization)
{
@@ -509,16 +472,6 @@ int main(int argc, char *argv[])
pd->SetTime(t);
pd->Save();
}
#ifdef MFEM_USE_ADIOS2
// transient solutions can be visualized with ParaView
if (adios2)
{
adios2_dc->SetCycle(ti);
adios2_dc->SetTime(t);
adios2_dc->Save();
}
#endif
}
}
@@ -544,12 +497,6 @@ int main(int argc, char *argv[])
delete pmesh;
delete ode_solver;
delete pd;
#ifdef MFEM_USE_ADIOS2
if (adios2)
{
delete adios2_dc;
}
#endif
delete dc;
MPI_Finalize();
@@ -566,9 +513,8 @@ FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K,
z(_M.Height())
{
bool pa = _M.GetAssemblyLevel()==AssemblyLevel::PARTIAL;
bool ea = _M.GetAssemblyLevel()==AssemblyLevel::ELEMENT;
if (pa || ea)
if (pa)
{
M.Reset(&_M, false);
K.Reset(&_K, false);
@@ -582,7 +528,7 @@ FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K,
M_solver.SetOperator(*M);
Array<int> ess_tdof_list;
if (pa || ea)
if (pa)
{
M_prec = new OperatorJacobiSmoother(_M, ess_tdof_list);
dg_solver = NULL;
+2 -8
View File
@@ -22,10 +22,9 @@ MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_EXAMPLES = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 ex17\
ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27
ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25
PAR_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p ex12p\
ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p ex25p\
ex26p ex27p
ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p ex25p
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
@@ -104,10 +103,6 @@ ex15-test-seq: ex15
@$(call mfem-test,$<,, Serial example,-e 1)
ex15p-test-par: ex15p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-e 1)
ex27-test-seq: ex27
@$(call mfem-test,$<,, Serial example,-dg)
ex27p-test-par: ex27p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-dg)
# Testing: optional tests
ifeq ($(MFEM_USE_STRUMPACK),YES)
ex11p-test-strumpack: ex11p
@@ -133,7 +128,6 @@ clean-exec:
@rm -f sphere_refined.* sol.* sol_u.* sol_p.* sol_r.* sol_i.*
@rm -f ex9.mesh ex9-mesh.* ex9-init.* ex9-final.*
@rm -f deformed.* velocity.* elastic_energy.* mode_*
@rm -f ex5-p-*.bp ex9-p-*.bp ex12-p-*.bp ex16-p-*.bp
@rm -f ex16.mesh ex16-mesh.* ex16-init.* ex16-final.*
@rm -f vortex-mesh.* vortex.mesh vortex-?-init.* vortex-?-final.*
@rm -f deformation.* pressure.*
-7
View File
@@ -32,13 +32,6 @@
// is used for the Finite Element order and "-go" is used for the
// geometry order. Note that they can be used independently, i.e.
// "-o 8 -go 3" solves for 8th order FE on a third order geometry.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
-8
View File
@@ -36,14 +36,6 @@
// option "-o" is used for the Finite Element order and "-go" for
// the geometry order. Note that they can be used independently:
// "-o 8 -go 3" solves for 8th order FE on third order geometry.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
-8
View File
@@ -43,14 +43,6 @@
// also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
+2 -8
View File
@@ -1,7 +1,7 @@
// MFEM Example 6 - Parallel Version
// PUMI Modification
//
// Compile with: make ex6p
// Compile with: make ex1p
//
// Sample runs: mpirun -np 8 ex6p
//
@@ -18,13 +18,6 @@
// is added to modify the "adapt_ratio" which is the fraction of
// allowable error that scales the output size field of the error
// estimator.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
@@ -339,6 +332,7 @@ int main(int argc, char *argv[])
apf::destroyField(Tmag_field);
apf::destroyField(ipfield);
apf::destroyNumbering(pumi_mesh->findNumbering("LocalVertexNumbering"));
// 18. Perform MesAdapt.
ma::Input* erinput = ma::configure(pumi_mesh, sizefield);
+4 -22
View File
@@ -13,20 +13,13 @@ set(SRCS
bilinearform.cpp
bilinearform_ext.cpp
bilininteg.cpp
bilininteg_convection_pa.cpp
bilininteg_convection_ea.cpp
bilininteg_dgtrace_pa.cpp
bilininteg_dgtrace_ea.cpp
bilininteg_diffusion_pa.cpp
bilininteg_diffusion_ea.cpp
bilininteg_convection.cpp
bilininteg_dgtrace.cpp
bilininteg_diffusion.cpp
bilininteg_divergence.cpp
bilininteg_hcurl.cpp
bilininteg_hdiv.cpp
bilininteg_vectorfe.cpp
bilininteg_gradient.cpp
bilininteg_mass_pa.cpp
bilininteg_mass_ea.cpp
bilininteg_transpose_ea.cpp
bilininteg_mass.cpp
bilininteg_vecdiffusion.cpp
bilininteg_vecmass.cpp
coefficient.cpp
@@ -43,11 +36,9 @@ set(SRCS
intrules.cpp
linearform.cpp
lininteg.cpp
multigrid.cpp
nonlinearform.cpp
nonlinearform_ext.cpp
nonlininteg.cpp
fespacehierarchy.cpp
nonlininteg_vectorconvection.cpp
quadinterpolator.cpp
quadinterpolator_face.cpp
@@ -56,7 +47,6 @@ set(SRCS
tmop.cpp
tmop_tools.cpp
gslib.cpp
transfer.cpp
)
set(HDRS
@@ -78,14 +68,12 @@ set(HDRS
intrules.hpp
linearform.hpp
lininteg.hpp
multigrid.hpp
nonlinearform.hpp
nonlinearform_ext.hpp
nonlininteg.hpp
quadinterpolator.hpp
quadinterpolator_face.hpp
restriction.hpp
fespacehierarchy.hpp
staticcond.hpp
tbilinearform.hpp
tbilininteg.hpp
@@ -98,7 +86,6 @@ set(HDRS
tmop.hpp
tmop_tools.hpp
gslib.hpp
transfer.hpp
)
if (MFEM_USE_SIDRE)
@@ -111,11 +98,6 @@ if (MFEM_USE_CONDUIT)
list(APPEND HDRS conduitdatacollection.hpp)
endif()
if (MFEM_USE_ADIOS2)
list(APPEND SRCS adios2datacollection.cpp)
list(APPEND HDRS adios2datacollection.hpp)
endif()
if (MFEM_USE_MPI)
list(APPEND SRCS
pbilinearform.cpp
-92
View File
@@ -1,92 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
//
// Created on: Jan 7, 2020
// Author: William F Godoy godoywf@ornl.gov
// adios2: Adaptable Input/Output System https://github.com/ornladios/ADIOS2
#include "adios2datacollection.hpp"
#ifdef MFEM_USE_ADIOS2
namespace mfem
{
#ifdef MFEM_USE_MPI
ADIOS2DataCollection::ADIOS2DataCollection(MPI_Comm comm,
const std::string& collection_name, Mesh* mesh,
const std::string engine_type) : DataCollection(collection_name, mesh),
stream( new adios2stream(name, adios2stream::openmode::out, comm, engine_type) )
{
SetMesh(mesh);
}
#else
ADIOS2DataCollection::ADIOS2DataCollection(
const std::string& collection_name, Mesh* mesh,
const std::string engine_type): DataCollection(collection_name, mesh),
stream( new adios2stream(name, adios2stream::openmode::out, engine_type) )
{
SetMesh(mesh);
}
#endif
ADIOS2DataCollection::~ADIOS2DataCollection()
{
stream->Close();
}
void ADIOS2DataCollection::Save()
{
stream->BeginStep();
// only save mesh once (moving mesh, not yet supported)
if (stream->CurrentStep() == 0)
{
if (mesh == nullptr)
{
const std::string error_message =
"MFEM ADIOS2DataCollection Save error: Mesh is null. Please call SetMesh before Save\n";
mfem_error(error_message.c_str());
}
stream->Print(*mesh);
}
// reduce footprint
if (myid == 0)
{
stream->SetTime(time);
stream->SetCycle(cycle);
}
for (const auto& field : field_map)
{
const std::string& variable_name = field.first;
field.second->Save(*stream.get(), variable_name);
}
stream->EndStep();
}
void ADIOS2DataCollection::SetParameter(const std::string key,
const std::string value) noexcept
{
stream->SetParameter(key, value);
}
void ADIOS2DataCollection::SetLevelsOfDetail(const int levels_of_detail)
noexcept
{
stream->SetRefinementLevel(levels_of_detail);
}
} //end namespace mfem
#endif // MFEM_USE_ADIOS2
-93
View File
@@ -1,93 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
//
// Created on: Jan 7, 2020
// Author: William F Godoy godoywf@ornl.gov
// adios2: Adaptable Input/Output System https://github.com/ornladios/ADIOS2
#ifndef MFEM_ADIOS2DATACOLLECTION
#define MFEM_ADIOS2DATACOLLECTION
#include "../config/config.hpp"
#ifdef MFEM_USE_ADIOS2
#include "../general/adios2stream.hpp"
#include "datacollection.hpp"
#include <memory> // std::unique_ptr
#include <string>
namespace mfem
{
class ADIOS2DataCollection : public DataCollection
{
public:
#ifdef MFEM_USE_MPI
/**
* Parallel constructor. Important: scope of this object must be within
* MPI_Init and MPI_Finalize otherwise. The destructor will call the Close
* function. Either object must live in a try/catch block (inside try) or use
* raw pointers calling delete before MPI_Finalize.
* @param comm MPI communicator setting the datacollection domain
* @param collection_name unique name for saving data
* @param mesh can be set at the constructor level or later by calling
* SetMesh()
* @param engine_type adios2 engine type
*/
ADIOS2DataCollection(MPI_Comm comm, const std::string& collection_name,
Mesh* mesh = nullptr,
const std::string engine_type = "BPFile");
#else
/**
* Serial constructor
* @param collection_name unique name for saving data
* @param mesh can be set at the constructor level or later by calling
* SetMesh()
* @param engine_type adios2 engine type
* @throws std::invalid_argument (user input error) or std::runtime_error
* (system error)
*/
ADIOS2DataCollection(const std::string& collection_name, Mesh* mesh = nullptr,
const std::string engine_type = "BPFile");
#endif
virtual ~ADIOS2DataCollection();
/** Save the collection */
virtual void Save();
/**
* Pass a parameter unique to adios2datacollection
* For available parameters:
* See https://adios2.readthedocs.io/en/latest/engines/engines.html
* The most common is: key=SubStreams value=1 to nprocs (MPI processes)
* @param key parameter key
* @param value parameter value
*/
void SetParameter(const std::string key, const std::string value) noexcept;
/**
* Sets the levels of detail for the global grid refinement
* @param levels_of_detail (default = 1)
*/
void SetLevelsOfDetail(const int levels_of_detail) noexcept;
private:
std::unique_ptr<adios2stream> stream;
};
} // namespace mfem
#endif // MFEM_USE_ADIOS2
#endif /* MFEM_ADIOS2DATACOLLECTION */
+4 -60
View File
@@ -126,7 +126,8 @@ void BilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
// Use the original BilinearForm implementation for now
break;
case AssemblyLevel::ELEMENT:
ext = new EABilinearFormExtension(this);
mfem_error("Element assembly not supported yet... stay tuned!");
// ext = new EABilinearFormExtension(this);
break;
case AssemblyLevel::PARTIAL:
ext = new PABilinearFormExtension(this);
@@ -466,17 +467,8 @@ void BilinearForm::Assemble(int skip_zeros)
const FiniteElement &be = *fes->GetBE(i);
fes -> GetBdrElementVDofs (i, vdofs);
eltrans = fes -> GetBdrElementTransformation (i);
int k = 0;
for (; k < bbfi.Size(); k++)
{
if (bbfi_marker[k] &&
(*bbfi_marker[k])[bdr_attr-1] == 0) { continue; }
bbfi[k]->AssembleElementMatrix(be, *eltrans, elmat);
k++;
break;
}
for (; k < bbfi.Size(); k++)
bbfi[0]->AssembleElementMatrix(be, *eltrans, elmat);
for (int k = 1; k < bbfi.Size(); k++)
{
if (bbfi_marker[k] &&
(*bbfi_marker[k])[bdr_attr-1] == 0) { continue; }
@@ -1431,54 +1423,6 @@ void MixedBilinearForm::Assemble (int skip_zeros)
}
}
void MixedBilinearForm::AssembleDiagonal_ADAt(const Vector &D,
Vector &diag) const
{
if (ext)
{
MFEM_ASSERT(diag.Size() == test_fes->GetTrueVSize(),
"Vector for holding diagonal has wrong size!");
MFEM_ASSERT(D.Size() == trial_fes->GetTrueVSize(),
"Vector for holding diagonal has wrong size!");
const Operator *P_trial = trial_fes->GetProlongationMatrix();
const Operator *P_test = test_fes->GetProlongationMatrix();
if (!IsIdentityProlongation(P_trial))
{
Vector local_D(P_trial->Height());
P_trial->Mult(D, local_D);
if (!IsIdentityProlongation(P_test))
{
Vector local_diag(P_test->Height());
ext->AssembleDiagonal_ADAt(local_D, local_diag);
P_test->MultTranspose(local_diag, diag);
}
else
{
ext->AssembleDiagonal_ADAt(local_D, diag);
}
}
else
{
if (!IsIdentityProlongation(P_test))
{
Vector local_diag(P_test->Height());
ext->AssembleDiagonal_ADAt(D, local_diag);
P_test->MultTranspose(local_diag, diag);
}
else
{
ext->AssembleDiagonal_ADAt(D, diag);
}
}
}
else
{
MFEM_ABORT("Not implemented. Maybe assemble your bilinear form into a "
"matrix and use SparseMatrix functions?");
}
}
void MixedBilinearForm::ConformingAssemble()
{
if (assembly != AssemblyLevel::FULL)
+39 -100
View File
@@ -25,8 +25,8 @@
namespace mfem
{
/** @brief Enumeration defining the assembly level for bilinear and nonlinear
form classes derived from Operator. */
/// Enumeration defining the assembly level for bilinear and nonlinear form
/// classes derived from Operator.
enum class AssemblyLevel
{
/// Fully assembled form, i.e. a global sparse matrix in MFEM, Hypre or PETSC
@@ -44,19 +44,15 @@ enum class AssemblyLevel
};
/** @brief A "square matrix" operator for the associated FE space and
BLFIntegrators The sum of all the BLFIntegrators can be used form the matrix
M. This class also supports other assembly levels specified via the
SetAssemblyLevel() function. */
/** Class for bilinear form - "Matrix" with associated FE space and
BLFIntegrators. */
class BilinearForm : public Matrix
{
protected:
/// Sparse matrix \f$ M \f$ to be associated with the form. Owned.
/// Sparse matrix to be associated with the form. Owned.
SparseMatrix *mat;
/** @brief Sparse Matrix \f$ M_e \f$ used to store the eliminations
from the b.c. Owned.
\f$ M + M_e = M_{original} \f$ */
/// Matrix used to eliminate b.c. Owned.
SparseMatrix *mat_e;
/// FE space on which the form lives. Not owned.
@@ -66,12 +62,12 @@ protected:
AssemblyLevel assembly;
/// Element batch size used in the form action (1, 8, num_elems, etc.)
int batch;
/** @brief Extension for supporting Full Assembly (FA), Element Assembly (EA),
/** Extension for supporting Full Assembly (FA), Element Assembly (EA),
Partial Assembly (PA), or Matrix Free assembly (MF). */
BilinearFormExtension *ext;
/** @brief Indicates the Mesh::sequence corresponding to the current state of
the BilinearForm. */
/// Indicates the Mesh::sequence corresponding to the current state of the
/// BilinearForm.
long sequence;
/** @brief Indicates the BilinearFormIntegrator%s stored in #dbfi, #bbfi,
@@ -151,43 +147,35 @@ public:
/// Get the size of the BilinearForm as a square matrix.
int Size() const { return height; }
/// Set the desired assembly level.
/** Valid choices are:
- AssemblyLevel::FULL (default)
- AssemblyLevel::PARTIAL
- AssemblyLevel::ELEMENT
- AssemblyLevel::NONE
This method must be called before assembly. */
/// Set the desired assembly level. The default is AssemblyLevel::FULL.
/** This method must be called before assembly. */
void SetAssemblyLevel(AssemblyLevel assembly_level);
/// Returns the assembly level
AssemblyLevel GetAssemblyLevel() const { return assembly; }
/// Get the assembly level
AssemblyLevel GetAssemblyLevel() {return assembly;}
/** @brief Enable the use of static condensation. For details see the
description for class StaticCondensation in fem/staticcond.hpp This method
should be called before assembly. If the number of unknowns after static
/** Enable the use of static condensation. For details see the description
for class StaticCondensation in fem/staticcond.hpp This method should be
called before assembly. If the number of unknowns after static
condensation is not reduced, it is not enabled. */
void EnableStaticCondensation();
/** @brief Check if static condensation was actually enabled by a previous
call to EnableStaticCondensation(). */
/** Check if static condensation was actually enabled by a previous call to
EnableStaticCondensation(). */
bool StaticCondensationIsEnabled() const { return static_cond; }
/// Return the trace FE space associated with static condensation.
FiniteElementSpace *SCFESpace() const
{ return static_cond ? static_cond->GetTraceFESpace() : NULL; }
/// Enable hybridization.
/** For details see the description for class
/** Enable hybridization; for details see the description for class
Hybridization in fem/hybridization.hpp. This method should be called
before assembly. */
void EnableHybridization(FiniteElementSpace *constr_space,
BilinearFormIntegrator *constr_integ,
const Array<int> &ess_tdof_list);
/** @brief For scalar FE spaces, precompute the sparsity pattern of the matrix
/** For scalar FE spaces, precompute the sparsity pattern of the matrix
(assuming dense element matrices) based on the types of integrators
present in the bilinear form. */
void UsePrecomputedSparsity(int ps = 1) { precompute_sparsity = ps; }
@@ -206,16 +194,15 @@ public:
/// Use the sparsity of @a A to allocate the internal SparseMatrix.
void UseSparsity(SparseMatrix &A);
/// Pre-allocate the internal SparseMatrix before assembly.
/** If the flag 'precompute sparsity'
is set, the matrix is allocated in CSR format (i.e.
/** Pre-allocate the internal SparseMatrix before assembly. If the flag
'precompute sparsity' is set, the matrix is allocated in CSR format (i.e.
finalized) and the entries are initialized with zeros. */
void AllocateMatrix() { if (mat == NULL) { AllocMat(); } }
/// Access all the integrators added with AddDomainIntegrator().
/// Access all integrators added with AddDomainIntegrator().
Array<BilinearFormIntegrator*> *GetDBFI() { return &dbfi; }
/// Access all the integrators added with AddBoundaryIntegrator().
/// Access all integrators added with AddBoundaryIntegrator().
Array<BilinearFormIntegrator*> *GetBBFI() { return &bbfi; }
/** @brief Access all boundary markers added with AddBoundaryIntegrator().
If no marker was specified when the integrator was added, the
@@ -232,85 +219,64 @@ public:
corresponding pointer (to Array<int>) will be NULL. */
Array<Array<int>*> *GetBFBFI_Marker() { return &bfbfi_marker; }
/// Returns a reference to: \f$ M_{ij} \f$
const double &operator()(int i, int j) { return (*mat)(i,j); }
/// Returns a reference to: \f$ M_{ij} \f$
/// Returns reference to a_{ij}.
virtual double &Elem(int i, int j);
/// Returns constant reference to: \f$ M_{ij} \f$
/// Returns constant reference to a_{ij}.
virtual const double &Elem(int i, int j) const;
/// Matrix vector multiplication: \f$ y = M x \f$
/// Matrix vector multiplication.
virtual void Mult(const Vector &x, Vector &y) const;
/** @brief Matrix vector multiplication with the original uneliminated
matrix. The original matrix is \f$ M + M_e \f$ so we have:
\f$ y = M x + M_e x \f$ */
void FullMult(const Vector &x, Vector &y) const
{ mat->Mult(x, y); mat_e->AddMult(x, y); }
/// Add the matrix vector multiple to a vector: \f$ y += a M x \f$
virtual void AddMult(const Vector &x, Vector &y, const double a = 1.0) const
{ mat -> AddMult (x, y, a); }
/** @brief Add the original uneliminated matrix vector multiple to a vector.
The original matrix is \f$ M + Me \f$ so we have:
\f$ y += M x + M_e x \f$ */
void FullAddMult(const Vector &x, Vector &y) const
{ mat->AddMult(x, y); mat_e->AddMult(x, y); }
/// Add the matrix transpose vector multiplication: \f$ y += a M^T x \f$
virtual void AddMultTranspose(const Vector & x, Vector & y,
const double a = 1.0) const
{ mat->AddMultTranspose(x, y, a); }
/** @brief Add the original uneliminated matrix transpose vector
multiple to a vector. The original matrix is \f$ M + M_e \f$
so we have: \f$ y += M^T x + {M_e}^T x \f$ */
void FullAddMultTranspose(const Vector & x, Vector & y) const
{ mat->AddMultTranspose(x, y); mat_e->AddMultTranspose(x, y); }
/// Matrix transpose vector multiplication: \f$ y = M^T x \f$
virtual void MultTranspose(const Vector & x, Vector & y) const
{ y = 0.0; AddMultTranspose (x, y); }
/// Compute \f$ y^T M x \f$
double InnerProduct(const Vector &x, const Vector &y) const
{ return mat->InnerProduct (x, y); }
/// Returns a pointer to (approximation) of the matrix inverse: \f$ M^{-1} \f$
/// Returns a pointer to (approximation) of the matrix inverse.
virtual MatrixInverse *Inverse() const;
/// Finalizes the matrix initialization.
virtual void Finalize(int skip_zeros = 1);
/// Returns a const reference to the sparse matrix.
/// Returns a reference to the sparse matrix
const SparseMatrix &SpMat() const
{
MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced");
return *mat;
}
/// Returns a reference to the sparse matrix: \f$ M \f$
SparseMatrix &SpMat()
{
MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced");
return *mat;
}
/** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer
to it. Used for transfering ownership. */
SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; }
/// Returns a const reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$
/// Returns a reference to the sparse matrix of eliminated b.c.
const SparseMatrix &SpMatElim() const
{
MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced");
return *mat_e;
}
/// Returns a reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$
SparseMatrix &SpMatElim()
{
MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced");
@@ -345,7 +311,6 @@ public:
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi,
Array<int> &bdr_marker);
/// Sets all sparse values of \f$ M \f$ and \f$ M_e \f$ to 'a'.
void operator=(const double a)
{
if (mat != NULL) { *mat = a; }
@@ -363,10 +328,10 @@ public:
for an AMR mesh. */
void AssembleDiagonal(Vector &diag) const;
/// Get the finite element space prolongation operator.
/// Get the finite element space prolongation matrix
virtual const Operator *GetProlongation() const
{ return fes->GetConformingProlongation(); }
/// Get the finite element space restriction operator
/// Get the finite element space restriction matrix
virtual const Operator *GetRestriction() const
{ return fes->GetConformingRestriction(); }
/// Get the output finite element space prolongation matrix
@@ -526,12 +491,10 @@ public:
double value);
/// Eliminate the given @a vdofs. NOTE: here, @a vdofs is a list of DOFs.
/** In this case the eliminations are applied to the internal \f$ M \f$
and @a rhs without storing the elimination matrix \f$ M_e \f$. */
void EliminateVDofs(const Array<int> &vdofs, const Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy = DIAG_ONE);
/// Eliminate the given @a vdofs, storing the eliminated part internally in \f$ M_e \f$.
/// Eliminate the given @a vdofs, storing the eliminated part internally.
/** This method works in conjunction with EliminateVDofsInRHS() and allows
elimination of boundary conditions in multiple right-hand sides. In this
method, @a vdofs is a list of DOFs. */
@@ -560,29 +523,21 @@ public:
void EliminateVDofsInRHS(const Array<int> &vdofs, const Vector &x,
Vector &b);
/// Compute inner product for full uneliminated matrix \f$ y^T M x + y^T M_e x \f$
double FullInnerProduct(const Vector &x, const Vector &y) const
{ return mat->InnerProduct(x, y) + mat_e->InnerProduct(x, y); }
/// Update the @a FiniteElementSpace and delete all data associated with the old one.
virtual void Update(FiniteElementSpace *nfes = NULL);
/// (DEPRECATED) Return the FE space associated with the BilinearForm.
/** @deprecated Use FESpace() instead. */
MFEM_DEPRECATED FiniteElementSpace *GetFES() { return fes; }
FiniteElementSpace *GetFES() { return fes; }
/// Return the FE space associated with the BilinearForm.
FiniteElementSpace *FESpace() { return fes; }
/// Read-only access to the associated FiniteElementSpace.
const FiniteElementSpace *FESpace() const { return fes; }
/// Sets diagonal policy used upon construction of the linear system.
/** Policies include:
- DIAG_ZERO (Set the diagonal values to zero)
- DIAG_ONE (Set the diagonal values to one)
- DIAG_KEEP (Keep the diagonal values)
*/
/// Sets diagonal policy used upon construction of the linear system
void SetDiagonalPolicy(DiagonalPolicy policy);
/// Indicate that integrators are not owned by the BilinearForm
@@ -595,16 +550,16 @@ public:
/**
Class for assembling of bilinear forms `a(u,v)` defined on different
trial and test spaces. The assembled matrix `M` is such that
trial and test spaces. The assembled matrix `A` is such that
a(u,v) = V^t M U
a(u,v) = V^t A U
where `U` and `V` are the vectors representing the functions `u` and `v`,
respectively. The first argument, `u`, of `a(,)` is in the trial space
and the second argument, `v`, is in the test space. Thus,
# of rows of M = dimension of the test space and
# of cols of M = dimension of the trial space.
# of rows of A = dimension of the test space and
# of cols of A = dimension of the trial space.
Both trial and test spaces should be defined on the same mesh.
*/
@@ -673,15 +628,11 @@ public:
FiniteElementSpace *te_fes,
MixedBilinearForm *mbf);
/// Returns a reference to: \f$ M_{ij} \f$
virtual double &Elem(int i, int j);
/// Returns a reference to: \f$ M_{ij} \f$
virtual const double &Elem(int i, int j) const;
/// Matrix multiplication: \f$ y = M x \f$
virtual void Mult(const Vector & x, Vector & y) const;
virtual void AddMult(const Vector & x, Vector & y,
const double a = 1.0) const;
@@ -691,7 +642,6 @@ public:
virtual MatrixInverse *Inverse() const;
/// Finalizes the matrix initialization.
virtual void Finalize(int skip_zeros = 1);
/** Extract the associated matrix as SparseMatrix blocks. The number of
@@ -699,14 +649,8 @@ public:
test and trial spaces, respectively. */
void GetBlocks(Array2D<SparseMatrix *> &blocks) const;
/// Returns a const reference to the sparse matrix: \f$ M \f$
const SparseMatrix &SpMat() const { return *mat; }
/// Returns a reference to the sparse matrix: \f$ M \f$
SparseMatrix &SpMat() { return *mat; }
/** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer
to it. Used for transfering ownership. */
SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; }
/// Adds a domain integrator. Assumes ownership of @a bfi.
@@ -753,7 +697,6 @@ public:
corresponding pointer (to Array<int>) will be NULL. */
Array<Array<int>*> *GetBTFBFI_Marker() { return &btfbfi_marker; }
/// Sets all sparse values of \f$ M \f$ to @a a.
void operator=(const double a) { *mat = a; }
/// Set the desired assembly level. The default is AssemblyLevel::FULL.
@@ -762,10 +705,6 @@ public:
void Assemble(int skip_zeros = 1);
/** @brief Assemble the diagonal of ADA^T into diag, where A is this mixed
bilinear form and D is a diagonal. */
void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const;
/// Get the input finite element space prolongation matrix
virtual const Operator *GetProlongation() const
{ return trial_fes->GetProlongationMatrix(); }
+4 -376
View File
@@ -47,7 +47,7 @@ PABilinearFormExtension::PABilinearFormExtension(BilinearForm *form)
bdr_face_restrict_lex = NULL;
}
void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
void PABilinearFormExtension::SetupRestrictionOperators()
{
ElementDofOrdering ordering = UsesTensorBasis(*a->FESpace())?
ElementDofOrdering::LEXICOGRAPHIC:
@@ -65,8 +65,7 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
if (int_face_restrict_lex == NULL && a->GetFBFI()->Size() > 0)
{
int_face_restrict_lex = trialFes->GetFaceRestriction(
ElementDofOrdering::LEXICOGRAPHIC,
FaceType::Interior);
ElementDofOrdering::LEXICOGRAPHIC, FaceType::Interior);
faceIntX.SetSize(int_face_restrict_lex->Height(), Device::GetMemoryType());
faceIntY.SetSize(int_face_restrict_lex->Height(), Device::GetMemoryType());
faceIntY.UseDevice(true); // ensure 'faceIntY = 0.0' is done on device
@@ -75,9 +74,7 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
if (bdr_face_restrict_lex == NULL && a->GetBFBFI()->Size() > 0)
{
bdr_face_restrict_lex = trialFes->GetFaceRestriction(
ElementDofOrdering::LEXICOGRAPHIC,
FaceType::Boundary,
m);
ElementDofOrdering::LEXICOGRAPHIC, FaceType::Boundary);
faceBdrX.SetSize(bdr_face_restrict_lex->Height(), Device::GetMemoryType());
faceBdrY.SetSize(bdr_face_restrict_lex->Height(), Device::GetMemoryType());
faceBdrY.UseDevice(true); // ensure 'faceBoundY = 0.0' is done on device
@@ -86,7 +83,7 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
void PABilinearFormExtension::Assemble()
{
SetupRestrictionOperators(L2FaceValues::DoubleValued);
SetupRestrictionOperators();
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int integratorCount = integrators.Size();
@@ -290,311 +287,6 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
}
}
// Data and methods for element-assembled bilinear forms
EABilinearFormExtension::EABilinearFormExtension(BilinearForm *form)
: PABilinearFormExtension(form)
{
}
void EABilinearFormExtension::Assemble()
{
SetupRestrictionOperators(L2FaceValues::SingleValued);
ne = trialFes->GetMesh()->GetNE();
elemDofs = trialFes->GetFE(0)->GetDof();
ea_data.SetSize(ne*elemDofs*elemDofs, Device::GetMemoryType());
ea_data.UseDevice(true);
ea_data = 0.0;
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int integratorCount = integrators.Size();
for (int i = 0; i < integratorCount; ++i)
{
integrators[i]->AssembleEA(*a->FESpace(), ea_data);
}
faceDofs = trialFes ->
GetTraceElement(0, trialFes->GetMesh()->GetFaceBaseGeometry(0)) ->
GetDof();
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int intFaceIntegratorCount = intFaceIntegrators.Size();
if (intFaceIntegratorCount>0)
{
nf_int = trialFes->GetNFbyType(FaceType::Interior);
ea_data_int.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_ext.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_int = 0.0;
ea_data_ext = 0.0;
}
for (int i = 0; i < intFaceIntegratorCount; ++i)
{
intFaceIntegrators[i]->AssembleEAInteriorFaces(*a->FESpace(),
ea_data_int,
ea_data_ext);
}
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int boundFaceIntegratorCount = bdrFaceIntegrators.Size();
if (boundFaceIntegratorCount>0)
{
nf_bdr = trialFes->GetNFbyType(FaceType::Boundary);
ea_data_bdr.SetSize(nf_bdr*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_bdr = 0.0;
}
for (int i = 0; i < boundFaceIntegratorCount; ++i)
{
bdrFaceIntegrators[i]->AssembleEABoundaryFaces(*a->FESpace(),ea_data_bdr);
}
}
void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
{
// Apply the Element Restriction
const bool useRestrict = !DeviceCanUseCeed() && elem_restrict;
if (!useRestrict)
{
y.UseDevice(true); // typically this is a large vector, so store on device
y = 0.0;
}
else
{
elem_restrict->Mult(x, localX);
localY = 0.0;
}
// Apply the Element Matrices
const int NDOFS = elemDofs;
auto X = Reshape(useRestrict?localX.Read():x.Read(), NDOFS, ne);
auto Y = Reshape(useRestrict?localY.ReadWrite():y.ReadWrite(), NDOFS, ne);
auto A = Reshape(ea_data.Read(), NDOFS, NDOFS, ne);
MFEM_FORALL(glob_j, ne*NDOFS,
{
const int e = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(i, j, e)*X(i, e);
}
Y(j, e) += res;
});
// Apply the Element Restriction transposed
if (useRestrict)
{
elem_restrict->MultTranspose(localY, y);
}
// Treatment of interior faces
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int iFISz = intFaceIntegrators.Size();
if (int_face_restrict_lex && iFISz>0)
{
// Apply the Interior Face Restriction
int_face_restrict_lex->Mult(x, faceIntX);
if (faceIntX.Size()>0)
{
faceIntY = 0.0;
// Apply the interior face matrices
const int NDOFS = faceDofs;
auto X = Reshape(faceIntX.Read(), NDOFS, 2, nf_int);
auto Y = Reshape(faceIntY.ReadWrite(), NDOFS, 2, nf_int);
auto A_int = Reshape(ea_data_int.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(i, j, 0, f)*X(i, 0, f);
}
Y(j, 0, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(i, j, 1, f)*X(i, 1, f);
}
Y(j, 1, f) += res;
});
auto A_ext = Reshape(ea_data_ext.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(i, j, 0, f)*X(i, 0, f);
}
Y(j, 1, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(i, j, 1, f)*X(i, 1, f);
}
Y(j, 0, f) += res;
});
// Apply the Interior Face Restriction transposed
int_face_restrict_lex->MultTranspose(faceIntY, y);
}
}
// Treatment of boundary faces
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (bdr_face_restrict_lex && bFISz>0)
{
// Apply the Boundary Face Restriction
bdr_face_restrict_lex->Mult(x, faceBdrX);
if (faceBdrX.Size()>0)
{
faceBdrY = 0.0;
// Apply the boundary face matrices
const int NDOFS = faceDofs;
auto X = Reshape(faceBdrX.Read(), NDOFS, nf_bdr);
auto Y = Reshape(faceBdrY.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
MFEM_FORALL(glob_j, nf_bdr*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(i, j, f)*X(i, f);
}
Y(j, f) += res;
});
// Apply the Boundary Face Restriction transposed
bdr_face_restrict_lex->MultTranspose(faceBdrY, y);
}
}
}
void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
{
// Apply the Element Restriction
const bool useRestrict = DeviceCanUseCeed() || !elem_restrict;
if (!useRestrict)
{
y.UseDevice(true); // typically this is a large vector, so store on device
y = 0.0;
}
else
{
elem_restrict->Mult(x, localX);
localY = 0.0;
}
// Apply the Element Matrices transposed
const int NDOFS = elemDofs;
auto X = Reshape(useRestrict?localX.Read():x.Read(), NDOFS, ne);
auto Y = Reshape(useRestrict?localY.ReadWrite():y.ReadWrite(), NDOFS, ne);
auto A = Reshape(ea_data.Read(), NDOFS, NDOFS, ne);
MFEM_FORALL(glob_j, ne*NDOFS,
{
const int e = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(j, i, e)*X(i, e);
}
Y(j, e) += res;
});
// Apply the Element Restriction transposed
if (useRestrict)
{
elem_restrict->MultTranspose(localY, y);
}
// Treatment of interior faces
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int iFISz = intFaceIntegrators.Size();
if (int_face_restrict_lex && iFISz>0)
{
// Apply the Interior Face Restriction
int_face_restrict_lex->Mult(x, faceIntX);
if (faceIntX.Size()>0)
{
faceIntY = 0.0;
// Apply the interior face matrices transposed
const int NDOFS = faceDofs;
auto X = Reshape(faceIntX.Read(), NDOFS, 2, nf_int);
auto Y = Reshape(faceIntY.ReadWrite(), NDOFS, 2, nf_int);
auto A_int = Reshape(ea_data_int.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(j, i, 0, f)*X(i, 0, f);
}
Y(j, 0, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(j, i, 1, f)*X(i, 1, f);
}
Y(j, 1, f) += res;
});
auto A_ext = Reshape(ea_data_ext.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(j, i, 0, f)*X(i, 0, f);
}
Y(j, 1, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(j, i, 1, f)*X(i, 1, f);
}
Y(j, 0, f) += res;
});
// Apply the Interior Face Restriction transposed
int_face_restrict_lex->MultTranspose(faceIntY, y);
}
}
// Treatment of boundary faces
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (bdr_face_restrict_lex && bFISz>0)
{
// Apply the Boundary Face Restriction
bdr_face_restrict_lex->Mult(x, faceBdrX);
if (faceBdrX.Size()>0)
{
faceBdrY = 0.0;
// Apply the boundary face matrices transposed
const int NDOFS = faceDofs;
auto X = Reshape(faceBdrX.Read(), NDOFS, nf_bdr);
auto Y = Reshape(faceBdrY.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
MFEM_FORALL(glob_j, nf_bdr*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(j, i, f)*X(i, f);
}
Y(j, f) += res;
});
// Apply the Boundary Face Restriction transposed
bdr_face_restrict_lex->MultTranspose(faceBdrY, y);
}
}
}
MixedBilinearFormExtension::MixedBilinearFormExtension(MixedBilinearForm *form)
: Operator(form->Height(), form->Width()), a(form)
{
@@ -795,68 +487,4 @@ void PAMixedBilinearFormExtension::AddMultTranspose(const Vector &x, Vector &y,
}
}
void PAMixedBilinearFormExtension::AssembleDiagonal_ADAt(const Vector &D,
Vector &diag) const
{
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int iSz = integrators.Size();
if (elem_restrict_trial)
{
const ElementRestriction* H1elem_restrict_trial =
dynamic_cast<const ElementRestriction*>(elem_restrict_trial);
if (H1elem_restrict_trial)
{
H1elem_restrict_trial->MultUnsigned(D, localTrial);
}
else
{
elem_restrict_trial->Mult(D, localTrial);
}
}
if (elem_restrict_test)
{
localTest = 0.0;
for (int i = 0; i < iSz; ++i)
{
if (elem_restrict_trial)
{
integrators[i]->AssembleDiagonalPA_ADAt(localTrial, localTest);
}
else
{
integrators[i]->AssembleDiagonalPA_ADAt(D, localTest);
}
}
const ElementRestriction* H1elem_restrict_test =
dynamic_cast<const ElementRestriction*>(elem_restrict_test);
if (H1elem_restrict_test)
{
H1elem_restrict_test->MultTransposeUnsigned(localTest, diag);
}
else
{
elem_restrict_test->MultTranspose(localTest, diag);
}
}
else
{
diag.UseDevice(true); // typically this is a large vector, so store on device
diag = 0.0;
for (int i = 0; i < iSz; ++i)
{
if (elem_restrict_trial)
{
integrators[i]->AssembleDiagonalPA_ADAt(localTrial, diag);
}
else
{
integrators[i]->AssembleDiagonalPA_ADAt(D, diag);
}
}
}
}
} // namespace mfem
+29 -42
View File
@@ -22,12 +22,9 @@ namespace mfem
class BilinearForm;
class MixedBilinearForm;
/// Class extending the BilinearForm class to support different AssemblyLevels.
/** FA - Full Assembly
PA - Partial Assembly
EA - Element Assembly
MF - Matrix Free
*/
/** @brief Class extending the BilinearForm class to support the different
AssemblyLevel%s. */
class BilinearFormExtension : public Operator
{
protected:
@@ -45,7 +42,6 @@ public:
/// Get the finite element space restriction matrix
virtual const Operator *GetRestriction() const;
/// Assemble at the level given for the BilinearFormExtension subclass
virtual void Assemble() = 0;
virtual void AssembleDiagonal(Vector &diag) const
@@ -62,8 +58,7 @@ public:
virtual void Update() = 0;
};
/** @brief Data and methods for fully-assembled bilinear forms.
Not yet implemented! Use the BilinearForm Class instead. */
/// Data and methods for fully-assembled bilinear forms
class FABilinearFormExtension : public BilinearFormExtension
{
public:
@@ -83,6 +78,26 @@ public:
~FABilinearFormExtension() {}
};
/// Data and methods for element-assembled bilinear forms
class EABilinearFormExtension : public BilinearFormExtension
{
public:
EABilinearFormExtension(BilinearForm *form)
: BilinearFormExtension(form) { }
/// TODO
void Assemble() {}
void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A) {}
void FormLinearSystem(const Array<int> &ess_tdof_list,
Vector &x, Vector &b,
OperatorHandle &A, Vector &X, Vector &B,
int copy_interior = 0) {}
void Mult(const Vector &x, Vector &y) const {}
void MultTranspose(const Vector &x, Vector &y) const {}
void Update() {}
~EABilinearFormExtension() {}
};
/// Data and methods for partially-assembled bilinear forms
class PABilinearFormExtension : public BilinearFormExtension
{
@@ -98,6 +113,7 @@ protected:
public:
PABilinearFormExtension(BilinearForm*);
void SetupRestrictionOperators();
void Assemble();
void AssembleDiagonal(Vector &diag) const;
void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A);
@@ -105,34 +121,14 @@ public:
Vector &x, Vector &b,
OperatorHandle &A, Vector &X, Vector &B,
int copy_interior = 0);
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const;
void Update();
protected:
void SetupRestrictionOperators(const L2FaceValues m);
};
/// Data and methods for element-assembled bilinear forms
class EABilinearFormExtension : public PABilinearFormExtension
{
protected:
int ne;
int elemDofs;
Vector ea_data;
int nf_int, nf_bdr;
int faceDofs;
Vector ea_data_int, ea_data_ext, ea_data_bdr;
public:
EABilinearFormExtension(BilinearForm *form);
void Assemble();
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const;
};
/// Data and methods for matrix-free bilinear forms NOT YET IMPLEMENTED.
/// Data and methods for matrix-free bilinear forms
class MFBilinearFormExtension : public BilinearFormExtension
{
public:
@@ -152,12 +148,8 @@ public:
~MFBilinearFormExtension() {}
};
/// Class extending the MixedBilinearForm class to support different AssemblyLevels.
/** FA - Full Assembly
PA - Partial Assembly
EA - Element Assembly
MF - Matrix Free
*/
/** @brief Class extending the MixedBilinearForm class to support the different
AssemblyLevel%s. */
class MixedBilinearFormExtension : public Operator
{
protected:
@@ -194,8 +186,6 @@ public:
virtual void AddMultTranspose(const Vector &x, Vector &y,
const double c=1.0) const = 0;
virtual void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const = 0;
virtual void Update() = 0;
};
@@ -246,9 +236,6 @@ public:
void MultTranspose(const Vector &x, Vector &y) const;
/// y += c*A^T*x
void AddMultTranspose(const Vector &x, Vector &y, const double c=1.0) const;
/// Assemble the diagonal of ADA^T for a diagonal vector D.
void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const;
/// Update internals for when a new MixedBilinearForm is given to this class
void Update();
};
+59 -75
View File
@@ -47,37 +47,7 @@ void BilinearFormIntegrator::AssemblePABoundaryFaces(const FiniteElementSpace&)
void BilinearFormIntegrator::AssembleDiagonalPA(Vector &)
{
mfem_error ("BilinearFormIntegrator::AssembleDiagonalPA(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &emat)
{
mfem_error ("BilinearFormIntegrator::AssembleEA(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
&fes,
Vector &ea_data_int,
Vector &ea_data_ext)
{
mfem_error ("BilinearFormIntegrator::AssembleEAInteriorFaces(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace
&fes,
Vector &ea_data_bdr)
{
mfem_error ("BilinearFormIntegrator::AssembleEABoundaryFaces(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleDiagonalPA_ADAt(const Vector &, Vector &)
{
MFEM_ABORT("BilinearFormIntegrator::AssembleDiagonalPA_ADAt(...)\n"
MFEM_ABORT("BilinearFormIntegrator::AssembleDiagonalPA(...)\n"
" is not implemented for this class.");
}
@@ -919,7 +889,7 @@ void BoundaryMassIntegrator::AssembleFaceMatrix(
{
int order = 2 * el1.GetOrder();
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
elmat = 0.0;
@@ -930,11 +900,11 @@ void BoundaryMassIntegrator::AssembleFaceMatrix(
Trans.Loc1.Transform(ip, eip);
el1.CalcShape(eip, shape);
Trans.SetIntPoint(&ip);
w = Trans.Weight() * ip.weight;
Trans.Face->SetIntPoint(&ip);
w = Trans.Face->Weight() * ip.weight;
if (Q)
{
w *= Q -> Eval(Trans, ip);
w *= Q -> Eval(*Trans.Face, ip);
}
AddMult_a_VVt(w, shape, elmat);
@@ -2004,7 +1974,7 @@ void VectorFEMassIntegrator::AssembleElementMatrix2(
D.SetSize(VQ ? VQ->GetVDim() : 0);
K.SetSize(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0);
#endif
DenseMatrix tmp(test_vshape.Height(), K.Width());
DenseMatrix tmp(trial_vshape.Height(), K.Width());
elmat.SetSize (test_dof, trial_dof);
@@ -2165,17 +2135,17 @@ void VectorDiffusionIntegrator::AssembleElementMatrix(
ElementTransformation &Trans,
DenseMatrix &elmat)
{
const int dim = el.GetDim();
const int dof = el.GetDof();
const int sdim = Trans.GetSpaceDim();
const bool square = (dim == sdim);
double w;
int dim = el.GetDim();
int dof = el.GetDof();
elmat.SetSize(sdim * dof);
double norm;
dshape.SetSize(dof, dim);
dshapedxt.SetSize(dof, sdim);
pelmat.SetSize(dof);
elmat.SetSize (dim * dof);
Jinv. SetSize (dim);
dshape.SetSize (dof, dim);
gshape.SetSize (dof, dim);
pelmat.SetSize (dof);
const IntegrationRule *ir = IntRule;
if (ir == NULL)
@@ -2193,29 +2163,35 @@ void VectorDiffusionIntegrator::AssembleElementMatrix(
}
elmat = 0.0;
pelmat = 0.0;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
el.CalcDShape (ip, dshape);
Trans.SetIntPoint (&ip);
w = Trans.Weight();
w = ip.weight / (square ? w : w*w*w);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
Mult(dshape, Trans.AdjugateJacobian(), dshapedxt);
if (Q) { w *= Q -> Eval (Trans, ip); }
AddMult_a_AAt(w, dshapedxt, pelmat);
}
for (int d = 0; d < sdim; d++)
{
for (int k = 0; k < dof; k++)
norm = ip.weight * Trans.Weight();
CalcInverse (Trans.Jacobian(), Jinv);
Mult (dshape, Jinv, gshape);
MultAAt (gshape, pelmat);
if (Q)
{
for (int l = 0; l < dof; l++)
{
elmat(dof*d+k, dof*d+l) = pelmat(k, l);
}
norm *= Q -> Eval (Trans, ip);
}
pelmat *= norm;
for (int d = 0; d < dim; d++)
{
for (int k = 0; k < dof; k++)
for (int l = 0; l < dof; l++)
{
elmat (dof*d+k, dof*d+l) += pelmat (k, l);
}
}
}
}
@@ -2565,7 +2541,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
{
order++;
}
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
@@ -2579,7 +2555,8 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
}
el1.CalcShape(eip1, shape1);
Trans.SetIntPoint(&ip);
Trans.Face->SetIntPoint(&ip);
Trans.Elem1->SetIntPoint(&eip1);
u->Eval(vu, *Trans.Elem1, eip1);
@@ -2589,7 +2566,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
}
else
{
CalcOrtho(Trans.Jacobian(), nor);
CalcOrtho(Trans.Face->Jacobian(), nor);
}
un = vu * nor;
@@ -2604,6 +2581,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
double rho_p;
if (un >= 0.0 && ndof2)
{
Trans.Elem2->SetIntPoint(&eip2);
rho_p = rho->Eval(*Trans.Elem2, eip2);
}
else
@@ -2719,7 +2697,7 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
{
order = 2*el1.GetOrder();
}
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
// assemble: < {(Q \nabla u).n},[v] > --> elmat
@@ -2730,18 +2708,19 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
IntegrationPoint eip1, eip2;
Trans.Loc1.Transform(ip, eip1);
Trans.SetIntPoint(&ip);
Trans.Face->SetIntPoint(&ip);
if (dim == 1)
{
nor(0) = 2*eip1.x - 1.0;
}
else
{
CalcOrtho(Trans.Jacobian(), nor);
CalcOrtho(Trans.Face->Jacobian(), nor);
}
el1.CalcShape(eip1, shape1);
el1.CalcDShape(eip1, dshape1);
Trans.Elem1->SetIntPoint(&eip1);
w = ip.weight/Trans.Elem1->Weight();
if (ndof2)
{
@@ -2790,6 +2769,7 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
Trans.Loc2.Transform(ip, eip2);
el2.CalcShape(eip2, shape2);
el2.CalcDShape(eip2, dshape2);
Trans.Elem2->SetIntPoint(&eip2);
w = ip.weight/2/Trans.Elem2->Weight();
if (!MQ)
{
@@ -2999,7 +2979,7 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
{
// a simple choice for the integration order; is this OK?
const int order = 2 * max(el1.GetOrder(), ndofs2 ? el2.GetOrder() : 0);
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
for (int pind = 0; pind < ir->GetNPoints(); ++pind)
@@ -3007,7 +2987,8 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
const IntegrationPoint &ip = ir->IntPoint(pind);
IntegrationPoint eip1, eip2; // integration point in the reference space
Trans.Loc1.Transform(ip, eip1);
Trans.SetIntPoint(&ip);
Trans.Face->SetIntPoint(&ip);
Trans.Elem1->SetIntPoint(&eip1);
el1.CalcShape(eip1, shape1);
el1.CalcDShape(eip1, dshape1);
@@ -3021,13 +3002,14 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
}
else
{
CalcOrtho(Trans.Jacobian(), nor);
CalcOrtho(Trans.Face->Jacobian(), nor);
}
double w, wLM;
if (ndofs2)
{
Trans.Loc2.Transform(ip, eip2);
Trans.Elem2->SetIntPoint(&eip2);
el2.CalcShape(eip2, shape2);
el2.CalcDShape(eip2, dshape2);
CalcAdjugate(Trans.Elem2->Jacobian(), adjJ);
@@ -3157,9 +3139,9 @@ void TraceJumpIntegrator::AssembleFaceMatrix(
order += trial_face_fe.GetOrder();
if (trial_face_fe.GetMapType() == FiniteElement::VALUE)
{
order += Trans.OrderW();
order += Trans.Face->OrderW();
}
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
@@ -3167,21 +3149,23 @@ void TraceJumpIntegrator::AssembleFaceMatrix(
const IntegrationPoint &ip = ir->IntPoint(p);
IntegrationPoint eip1, eip2;
// Trace finite element shape function
Trans.SetIntPoint(&ip);
Trans.Face->SetIntPoint(&ip);
trial_face_fe.CalcShape(ip, face_shape);
// Side 1 finite element shape function
Trans.Loc1.Transform(ip, eip1);
test_fe1.CalcShape(eip1, shape1);
Trans.Elem1->SetIntPoint(&eip1);
if (ndof2)
{
// Side 2 finite element shape function
Trans.Loc2.Transform(ip, eip2);
test_fe2.CalcShape(eip2, shape2);
Trans.Elem2->SetIntPoint(&eip2);
}
w = ip.weight;
if (trial_face_fe.GetMapType() == FiniteElement::VALUE)
{
w *= Trans.Weight();
w *= Trans.Face->Weight();
}
face_shape *= w;
for (i = 0; i < ndof1; i++)
@@ -3246,7 +3230,7 @@ void NormalTraceJumpIntegrator::AssembleFaceMatrix(
order = test_fe1.GetOrder() - 1;
}
order += trial_face_fe.GetOrder();
ir = &IntRules.Get(Trans.GetGeometryType(), order);
ir = &IntRules.Get(Trans.FaceGeom, order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
+33 -87
View File
@@ -57,9 +57,6 @@ public:
/// Assemble diagonal and add it to Vector @a diag.
virtual void AssembleDiagonalPA(Vector &diag);
/// Assemble diagonal of ADA^T (A is this integrator) and add it to @a diag.
virtual void AssembleDiagonalPA_ADAt(const Vector &D, Vector &diag);
/// Method for partially assembled action.
/** Perform the action of integrator on the input @a x and add the result to
the output @a y. Both @a x and @a y are E-vectors, i.e. they represent
@@ -78,22 +75,6 @@ public:
called. */
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
/// Method defining element assembly.
/** The result of the element assembly is added and stored in the @a emat
Vector. */
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
/** Used with BilinearFormIntegrators that have different spaces. */
// virtual void AssembleEA(const FiniteElementSpace &trial_fes,
// const FiniteElementSpace &test_fes,
// Vector &emat);
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
Vector &ea_data_bdr);
/// Given a particular Finite Element computes the element matrix elmat.
virtual void AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
@@ -199,8 +180,6 @@ public:
virtual ~BilinearFormIntegrator() { }
};
/** Wraps a given @a BilinearFormIntegrator and transposes the resulting element
matrices. See for example ex9, ex9p. */
class TransposeIntegrator : public BilinearFormIntegrator
{
private:
@@ -255,15 +234,6 @@ public:
bfi->AddMultTransposePA(x, y);
}
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
Vector &ea_data_bdr);
virtual ~TransposeIntegrator() { if (own_bfi) { delete bfi; } }
};
@@ -483,16 +453,6 @@ public:
ElementTransformation &Trans,
DenseMatrix &elmat);
/// Support for use in BilinearForm. Can be used only when appropriate.
/** Appropriate use cases are classes derived from
MixedScalarVectorIntegrator where the trial and test spaces can be the
same. Examples of such classes are: MixedVectorDivergenceIntegrator,
MixedScalarWeakDivergenceIntegrator, etc. */
virtual void AssembleElementMatrix(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &elmat)
{ AssembleElementMatrix2(fe, fe, Trans, elmat); }
protected:
MixedScalarVectorIntegrator(VectorCoefficient &vq, bool _transpose = false,
@@ -1565,7 +1525,7 @@ public:
};
/** Class for integrating the bilinear form a(u,v) := (-V u, Grad v) in 2D or 3D
and where V is a vector coefficient, u is in H1 or L2 and v is in H1. */
and where V is a vector coefficient, u is in H1 and v is in H1. */
class MixedScalarWeakDivergenceIntegrator : public MixedScalarVectorIntegrator
{
public:
@@ -1685,6 +1645,19 @@ protected:
{
trial_fe.CalcPhysCurlShape(Trans, shape);
}
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes);
virtual void AddMultPA(const Vector&, Vector&) const;
private:
// PA extension
Vector pa_data;
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
const GeometricFactors *geom; ///< Not owned
int dim, ne, dofs1D, quad1D, testType, trialType, coeffDim;
};
/** Class for integrating the bilinear form a(u,v) := (Q u, curl v) in 3D and
@@ -1724,6 +1697,19 @@ protected:
{
test_fe.CalcPhysCurlShape(Trans, shape);
}
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes);
virtual void AddMultPA(const Vector&, Vector&) const;
private:
// PA extension
Vector pa_data;
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
const GeometricFactors *geom; ///< Not owned
int dim, ne, dofs1D, quad1D, testType, trialType, coeffDim;
};
/** Class for integrating the bilinear form a(u,v) := - (Q u, grad v) in either
@@ -1915,8 +1901,6 @@ public:
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleDiagonalPA(Vector &diag);
virtual void AddMultPA(const Vector&, Vector&) const;
@@ -1990,8 +1974,6 @@ public:
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleDiagonalPA(Vector &diag);
virtual void AddMultPA(const Vector&, Vector&) const;
@@ -2003,7 +1985,6 @@ public:
void SetupPA(const FiniteElementSpace &fes, const bool force = false);
};
/** Mass integrator (u, v) restricted to the boundary of a domain */
class BoundaryMassIntegrator : public MassIntegrator
{
public:
@@ -2046,8 +2027,6 @@ public:
virtual void AssemblePA(const FiniteElementSpace&);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AddMultPA(const Vector&, Vector&) const;
static const IntegrationRule &GetRule(const FiniteElement &el,
@@ -2147,25 +2126,11 @@ class VectorFEDivergenceIntegrator : public BilinearFormIntegrator
protected:
Coefficient *Q;
using BilinearFormIntegrator::AssemblePA;
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes);
virtual void AddMultPA(const Vector&, Vector&) const;
virtual void AddMultTransposePA(const Vector&, Vector&) const;
private:
#ifndef MFEM_THREAD_SAFE
Vector divshape, shape;
#endif
// PA extension
Vector pa_data;
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *L2mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
int dim, ne, dofs1D, L2dofs1D, quad1D;
public:
VectorFEDivergenceIntegrator() { Q = NULL; }
VectorFEDivergenceIntegrator(Coefficient &q) { Q = &q; }
@@ -2176,8 +2141,6 @@ public:
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
virtual void AssembleDiagonalPA_ADAt(const Vector &D, Vector &diag);
};
@@ -2361,7 +2324,7 @@ protected:
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
const GeometricFactors *geom; ///< Not owned
int dim, ne, nq, dofs1D, quad1D, fetype;
int dim, ne, nq, dofs1D, quad1D;
public:
VectorFEMassIntegrator() { Init(NULL, NULL, NULL); }
@@ -2440,23 +2403,11 @@ class DivDivIntegrator: public BilinearFormIntegrator
protected:
Coefficient *Q;
using BilinearFormIntegrator::AssemblePA;
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AddMultPA(const Vector &x, Vector &y) const;
virtual void AssembleDiagonalPA(Vector& diag);
private:
#ifndef MFEM_THREAD_SAFE
Vector divshape;
#endif
// PA extension
Vector pa_data;
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
const GeometricFactors *geom; ///< Not owned
int dim, ne, dofs1D, quad1D;
public:
DivDivIntegrator() { Q = NULL; }
DivDivIntegrator(Coefficient &q) : Q(&q) { }
@@ -2480,12 +2431,14 @@ protected:
// PA extension
const DofToQuad *maps; ///< Not owned
const GeometricFactors *geom; ///< Not owned
int dim, sdim, ne, dofs1D, quad1D;
int dim, ne, dofs1D, quad1D;
Vector pa_data;
private:
DenseMatrix dshape, dshapedxt, pelmat;
DenseMatrix Jinv, gshape;
DenseMatrix Jinv;
DenseMatrix dshape;
DenseMatrix gshape;
DenseMatrix pelmat;
public:
VectorDiffusionIntegrator() { Q = NULL; }
@@ -2609,13 +2562,6 @@ public:
virtual void AddMultPA(const Vector&, Vector&) const;
virtual void AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr);
static const IntegrationRule &GetRule(Geometry::Type geom, int order,
FaceElementTransformations &T);
-258
View File
@@ -1,258 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
template<int T_D1D = 0, int T_Q1D = 0>
static void EAConvectionAssemble1D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_Gi[MQ1];
double r_Bj[MQ1];
for (int q = 0; q < Q1D; q++)
{
r_Gi[q] = G(q,MFEM_THREAD_ID(x));
r_Bj[q] = B(q,MFEM_THREAD_ID(y));
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val += r_Bj[k1] * D(k1, e) * r_Gi[k1];
}
A(i1, j1, e) = val;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAConvectionAssemble2D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][2];
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2][0] = D(k1,k2,0,e);
s_D[k1][k2][1] = D(k1,k2,1,e);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val += (r_G[k1][i1] * r_B[k2][i2] * s_D[k1][k2][0]
+ r_B[k1][i1] * r_G[k2][i2] * s_D[k1][k2][1])
* r_B[k1][j1]* r_B[k2][j2];
}
}
A(i1, i2, j1, j2, e) = val;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAConvectionAssemble3D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 3, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
MFEM_FOREACH_THREAD(i3,z,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
for (int j3 = 0; j3 < D1D; ++j3)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
for (int k3 = 0; k3 < Q1D; ++k3)
{
double D0 = D(k1,k2,k3,0,e);
double D1 = D(k1,k2,k3,1,e);
double D2 = D(k1,k2,k3,2,e);
val += (r_G[k1][i1] * r_B[k2][i2] * r_B[k3][i3] * D0
+ r_B[k1][i1] * r_G[k2][i2] * r_B[k3][i3] * D1
+ r_B[k1][i1] * r_B[k2][i2] * r_G[k3][i3] * D2)
* r_B[k1][j1] * r_B[k2][j2] * r_B[k3][j3];
}
}
}
A(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
}
}
}
});
}
void ConvectionIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
const Array<double> &B = maps->B;
const Array<double> &G = maps->G;
if (dim == 1)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAConvectionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EAConvectionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EAConvectionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EAConvectionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EAConvectionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EAConvectionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EAConvectionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EAConvectionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAConvectionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EAConvectionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EAConvectionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EAConvectionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EAConvectionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EAConvectionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EAConvectionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EAConvectionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EAConvectionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
case 0x34: return EAConvectionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
case 0x45: return EAConvectionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
case 0x56: return EAConvectionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
case 0x67: return EAConvectionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
case 0x78: return EAConvectionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
case 0x89: return EAConvectionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
-414
View File
@@ -1,414 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
static void EADGTraceAssemble1DInt(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext)
{
auto D = Reshape(padata.Read(), 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), 2, NF);
MFEM_FORALL(f, NF,
{
double val_int0, val_int1, val_ext01, val_ext10;
val_int0 = D(0, 0, f);
val_ext10 = D(1, 0, f);
val_ext01 = D(0, 1, f);
val_int1 = D(1, 1, f);
A_int(0, f) += val_int0;
A_int(1, f) += val_int1;
A_ext(0, f) += val_ext01;
A_ext(1, f) += val_ext10;
});
}
static void EADGTraceAssemble1DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr)
{
auto D = Reshape(padata.Read(), 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), NF);
MFEM_FORALL(f, NF,
{
A_bdr(f) += D(0, 0, f);
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble2DInt(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), D1D, D1D, 2, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val_int0 = 0.0;
double val_int1 = 0.0;
double val_ext01 = 0.0;
double val_ext10 = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val_int0 += B(k1,i1) * B(k1,j1) * D(k1, 0, 0, f);
val_ext01 += B(k1,i1) * B(k1,j1) * D(k1, 0, 1, f);
val_ext10 += B(k1,i1) * B(k1,j1) * D(k1, 1, 0, f);
val_int1 += B(k1,i1) * B(k1,j1) * D(k1, 1, 1, f);
}
A_int(i1, j1, 0, f) += val_int0;
A_int(i1, j1, 1, f) += val_int1;
A_ext(i1, j1, 0, f) += val_ext01;
A_ext(i1, j1, 1, f) += val_ext10;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble2DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), D1D, D1D, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val_bdr = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val_bdr += B(k1,i1) * B(k1,j1) * D(k1, 0, 0, f);
}
A_bdr(i1, j1, f) += val_bdr;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble3DInt(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, D1D, D1D, 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), D1D, D1D, D1D, D1D, 2, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][2][2];
for (int i=0; i < 2; i++)
{
for (int j=0; j < 2; j++)
{
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2][i][j] = D(k1,k2,i,j,f);
}
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val_int0 = 0.0;
double val_int1 = 0.0;
double val_ext01 = 0.0;
double val_ext10 = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val_int0 += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][0][0];
val_int1 += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][1][1];
val_ext01+= r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][0][1];
val_ext10+= r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][1][0];
}
}
A_int(i1, i2, j1, j2, 0, f) += val_int0;
A_int(i1, i2, j1, j2, 1, f) += val_int1;
A_ext(i1, i2, j1, j2, 0, f) += val_ext01;
A_ext(i1, i2, j1, j2, 1, f) += val_ext10;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble3DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), D1D, D1D, D1D, D1D, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][2][2];
for (int i=0; i < 2; i++)
{
for (int j=0; j < 2; j++)
{
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2][i][j] = D(k1,k2,i,j,f);
}
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val_bdr = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val_bdr += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][0][0];
}
}
A_bdr(i1, i2, j1, j2, f) += val_bdr;
}
}
}
}
});
}
void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext)
{
SetupPA(fes, FaceType::Interior);
nf = fes.GetNFbyType(FaceType::Interior);
if (nf==0) { return; }
const Array<double> &B = maps->B;
if (dim == 1)
{
return EADGTraceAssemble1DInt(nf,B,pa_data,ea_data_int,ea_data_ext);
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22:
return EADGTraceAssemble2DInt<2,2>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x33:
return EADGTraceAssemble2DInt<3,3>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x44:
return EADGTraceAssemble2DInt<4,4>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x55:
return EADGTraceAssemble2DInt<5,5>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x66:
return EADGTraceAssemble2DInt<6,6>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x77:
return EADGTraceAssemble2DInt<7,7>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x88:
return EADGTraceAssemble2DInt<8,8>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x99:
return EADGTraceAssemble2DInt<9,9>(nf,B,pa_data,ea_data_int,
ea_data_ext);
default:
return EADGTraceAssemble2DInt(nf,B,pa_data,ea_data_int,
ea_data_ext,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23:
return EADGTraceAssemble3DInt<2,3>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x34:
return EADGTraceAssemble3DInt<3,4>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x45:
return EADGTraceAssemble3DInt<4,5>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x56:
return EADGTraceAssemble3DInt<5,6>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x67:
return EADGTraceAssemble3DInt<6,7>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x78:
return EADGTraceAssemble3DInt<7,8>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x89:
return EADGTraceAssemble3DInt<8,9>(nf,B,pa_data,ea_data_int,
ea_data_ext);
default:
return EADGTraceAssemble3DInt(nf,B,pa_data,ea_data_int,
ea_data_ext,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
void DGTraceIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr)
{
SetupPA(fes, FaceType::Boundary);
nf = fes.GetNFbyType(FaceType::Boundary);
if (nf==0) { return; }
const Array<double> &B = maps->B;
if (dim == 1)
{
return EADGTraceAssemble1DBdr(nf,B,pa_data,ea_data_bdr);
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADGTraceAssemble2DBdr<2,2>(nf,B,pa_data,ea_data_bdr);
case 0x33: return EADGTraceAssemble2DBdr<3,3>(nf,B,pa_data,ea_data_bdr);
case 0x44: return EADGTraceAssemble2DBdr<4,4>(nf,B,pa_data,ea_data_bdr);
case 0x55: return EADGTraceAssemble2DBdr<5,5>(nf,B,pa_data,ea_data_bdr);
case 0x66: return EADGTraceAssemble2DBdr<6,6>(nf,B,pa_data,ea_data_bdr);
case 0x77: return EADGTraceAssemble2DBdr<7,7>(nf,B,pa_data,ea_data_bdr);
case 0x88: return EADGTraceAssemble2DBdr<8,8>(nf,B,pa_data,ea_data_bdr);
case 0x99: return EADGTraceAssemble2DBdr<9,9>(nf,B,pa_data,ea_data_bdr);
default:
return EADGTraceAssemble2DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EADGTraceAssemble3DBdr<2,3>(nf,B,pa_data,ea_data_bdr);
case 0x34: return EADGTraceAssemble3DBdr<3,4>(nf,B,pa_data,ea_data_bdr);
case 0x45: return EADGTraceAssemble3DBdr<4,5>(nf,B,pa_data,ea_data_bdr);
case 0x56: return EADGTraceAssemble3DBdr<5,6>(nf,B,pa_data,ea_data_bdr);
case 0x67: return EADGTraceAssemble3DBdr<6,7>(nf,B,pa_data,ea_data_bdr);
case 0x78: return EADGTraceAssemble3DBdr<7,8>(nf,B,pa_data,ea_data_bdr);
case 0x89: return EADGTraceAssemble3DBdr<8,9>(nf,B,pa_data,ea_data_bdr);
default:
return EADGTraceAssemble3DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
@@ -81,20 +81,12 @@ static void OccaPADiffusionSetup3D(const int D1D,
#endif // MFEM_USE_OCCA
// PA Diffusion Assemble 2D kernel
template<const int T_SDIM>
static void PADiffusionSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d);
template<>
void PADiffusionSetup2D<2>(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
Vector &d)
{
const int NQ = Q1D*Q1D;
const bool const_c = c.Size() == 1;
@@ -120,48 +112,6 @@ void PADiffusionSetup2D<2>(const int Q1D,
});
}
// PA Diffusion Assemble 2D kernel with 3D node coords
template<>
void PADiffusionSetup2D<3>(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
{
constexpr int DIM = 2;
constexpr int SDIM = 3;
const int NQ = Q1D*Q1D;
const bool const_c = c.Size() == 1;
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, SDIM, DIM, NE);
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
auto D = Reshape(d.Write(), NQ, 3, NE);
MFEM_FORALL(e, NE,
{
for (int q = 0; q < NQ; ++q)
{
const double wq = W[q];
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J31 = J(q,2,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double J32 = J(q,2,1,e);
const double E = J11*J11 + J21*J21 + J31*J31;
const double G = J12*J12 + J22*J22 + J32*J32;
const double F = J11*J12 + J21*J22 + J31*J32;
const double iw = 1.0 / sqrt(E*G - F*F);
const double coeff = const_c ? C(0,0) : C(q,e);
const double alpha = wq * coeff * iw;
D(q,0,e) = alpha * G; // 1,1
D(q,1,e) = -alpha * F; // 1,2
D(q,2,e) = alpha * E; // 2,2
}
});
}
// PA Diffusion Assemble 3D kernel
static void PADiffusionSetup3D(const int Q1D,
const int NE,
@@ -176,46 +126,46 @@ static void PADiffusionSetup3D(const int Q1D,
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
auto D = Reshape(d.Write(), NQ, 6, NE);
MFEM_FORALL(eq, NE*NQ,
MFEM_FORALL(e, NE,
{
const int e = eq / NQ;
const int q = eq % NQ;
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J31 = J(q,2,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double J32 = J(q,2,1,e);
const double J13 = J(q,0,2,e);
const double J23 = J(q,1,2,e);
const double J33 = J(q,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double coeff = const_c ? C(0,0) : C(q,e);
const double c_detJ = W[q] * coeff / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
D(q,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
D(q,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
D(q,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
D(q,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
D(q,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
D(q,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
for (int q = 0; q < NQ; ++q)
{
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J31 = J(q,2,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double J32 = J(q,2,1,e);
const double J13 = J(q,0,2,e);
const double J23 = J(q,1,2,e);
const double J33 = J(q,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double coeff = const_c ? C(0,0) : C(q,e);
const double c_detJ = W[q] * coeff / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
D(q,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
D(q,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
D(q,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
D(q,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
D(q,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
D(q,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
}
});
}
static void PADiffusionSetup(const int dim,
const int sdim,
const int D1D,
const int Q1D,
const int NE,
@@ -233,11 +183,8 @@ static void PADiffusionSetup(const int dim,
OccaPADiffusionSetup2D(D1D, Q1D, NE, W, J, C, D);
return;
}
#else
MFEM_CONTRACT_VAR(D1D);
#endif // MFEM_USE_OCCA
if (sdim == 2) { PADiffusionSetup2D<2>(Q1D, NE, W, J, C, D); }
if (sdim == 3) { PADiffusionSetup2D<3>(Q1D, NE, W, J, C, D); }
PADiffusionSetup2D(Q1D, NE, W, J, C, D);
}
if (dim == 3)
{
@@ -270,8 +217,6 @@ void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
InitCeedCoeff(Q, ptr);
return CeedPADiffusionAssemble(fes, *ir, *ptr);
}
#else
MFEM_CONTRACT_VAR(force);
#endif
const int dims = el.GetDim();
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
@@ -279,7 +224,6 @@ void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
dim = mesh->Dimension();
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
const int sdim = mesh->SpaceDimension();
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
@@ -308,8 +252,8 @@ void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
}
}
}
PADiffusionSetup(dim, sdim, dofs1D, quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
PADiffusionSetup(dim, dofs1D, quad1D, ne, ir->GetWeights(), geom->J, coeff,
pa_data);
}
void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
@@ -966,6 +910,8 @@ template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
static void SmemPADiffusionApply2D(const int NE,
const Array<double> &b_,
const Array<double> &g_,
const Array<double> &bt_,
const Array<double> &gt_,
const Vector &d_,
const Vector &x_,
Vector &y_,
@@ -1311,6 +1257,8 @@ template<int T_D1D = 0, int T_Q1D = 0>
static void SmemPADiffusionApply3D(const int NE,
const Array<double> &b_,
const Array<double> &g_,
const Array<double> &bt_,
const Array<double> &gt_,
const Vector &d_,
const Vector &x_,
Vector &y_,
@@ -1577,14 +1525,14 @@ static void PADiffusionApply(const int dim,
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPADiffusionApply2D<2,2,16>(NE,B,G,D,X,Y);
case 0x33: return SmemPADiffusionApply2D<3,3,16>(NE,B,G,D,X,Y);
case 0x44: return SmemPADiffusionApply2D<4,4,8>(NE,B,G,D,X,Y);
case 0x55: return SmemPADiffusionApply2D<5,5,8>(NE,B,G,D,X,Y);
case 0x66: return SmemPADiffusionApply2D<6,6,4>(NE,B,G,D,X,Y);
case 0x77: return SmemPADiffusionApply2D<7,7,4>(NE,B,G,D,X,Y);
case 0x88: return SmemPADiffusionApply2D<8,8,2>(NE,B,G,D,X,Y);
case 0x99: return SmemPADiffusionApply2D<9,9,2>(NE,B,G,D,X,Y);
case 0x22: return SmemPADiffusionApply2D<2,2,16>(NE,B,G,Bt,Gt,D,X,Y);
case 0x33: return SmemPADiffusionApply2D<3,3,16>(NE,B,G,Bt,Gt,D,X,Y);
case 0x44: return SmemPADiffusionApply2D<4,4,8>(NE,B,G,Bt,Gt,D,X,Y);
case 0x55: return SmemPADiffusionApply2D<5,5,8>(NE,B,G,Bt,Gt,D,X,Y);
case 0x66: return SmemPADiffusionApply2D<6,6,4>(NE,B,G,Bt,Gt,D,X,Y);
case 0x77: return SmemPADiffusionApply2D<7,7,4>(NE,B,G,Bt,Gt,D,X,Y);
case 0x88: return SmemPADiffusionApply2D<8,8,2>(NE,B,G,Bt,Gt,D,X,Y);
case 0x99: return SmemPADiffusionApply2D<9,9,2>(NE,B,G,Bt,Gt,D,X,Y);
default: return PADiffusionApply2D(NE,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
}
}
@@ -1592,15 +1540,15 @@ static void PADiffusionApply(const int dim,
{
switch ((D1D << 4 ) | Q1D)
{
case 0x23: return SmemPADiffusionApply3D<2,3>(NE,B,G,D,X,Y);
case 0x34: return SmemPADiffusionApply3D<3,4>(NE,B,G,D,X,Y);
case 0x45: return SmemPADiffusionApply3D<4,5>(NE,B,G,D,X,Y);
case 0x46: return SmemPADiffusionApply3D<4,6>(NE,B,G,D,X,Y);
case 0x56: return SmemPADiffusionApply3D<5,6>(NE,B,G,D,X,Y);
case 0x58: return SmemPADiffusionApply3D<5,8>(NE,B,G,D,X,Y);
case 0x67: return SmemPADiffusionApply3D<6,7>(NE,B,G,D,X,Y);
case 0x78: return SmemPADiffusionApply3D<7,8>(NE,B,G,D,X,Y);
case 0x89: return SmemPADiffusionApply3D<8,9>(NE,B,G,D,X,Y);
case 0x23: return SmemPADiffusionApply3D<2,3>(NE,B,G,Bt,Gt,D,X,Y);
case 0x34: return SmemPADiffusionApply3D<3,4>(NE,B,G,Bt,Gt,D,X,Y);
case 0x45: return SmemPADiffusionApply3D<4,5>(NE,B,G,Bt,Gt,D,X,Y);
case 0x46: return SmemPADiffusionApply3D<4,6>(NE,B,G,Bt,Gt,D,X,Y);
case 0x56: return SmemPADiffusionApply3D<5,6>(NE,B,G,Bt,Gt,D,X,Y);
case 0x58: return SmemPADiffusionApply3D<5,8>(NE,B,G,Bt,Gt,D,X,Y);
case 0x67: return SmemPADiffusionApply3D<6,7>(NE,B,G,Bt,Gt,D,X,Y);
case 0x78: return SmemPADiffusionApply3D<7,8>(NE,B,G,Bt,Gt,D,X,Y);
case 0x89: return SmemPADiffusionApply3D<8,9>(NE,B,G,Bt,Gt,D,X,Y);
default: return PADiffusionApply3D(NE,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
}
}
-275
View File
@@ -1,275 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
template<int T_D1D = 0, int T_Q1D = 0>
static void EADiffusionAssemble1D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_Gi[MQ1];
double r_Gj[MQ1];
for (int q = 0; q < Q1D; q++)
{
r_Gi[q] = G(q,MFEM_THREAD_ID(x));
r_Gj[q] = G(q,MFEM_THREAD_ID(y));
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val += r_Gj[k1] * D(k1, e) * r_Gi[k1];
}
A(i1, j1, e) = val;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADiffusionAssemble2D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 3, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
double bgi = r_G[k1][i1] * r_B[k2][i2];
double gbi = r_B[k1][i1] * r_G[k2][i2];
double bgj = r_G[k1][j1] * r_B[k2][j2];
double gbj = r_B[k1][j1] * r_G[k2][j2];
double D00 = D(k1,k2,0,e);
double D10 = D(k1,k2,1,e);
double D01 = D10;
double D11 = D(k1,k2,2,e);
val += bgi * D00 * bgj
+ gbi * D01 * bgj
+ bgi * D10 * gbj
+ gbi * D11 * gbj;
}
}
A(i1, i2, j1, j2, e) = val;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADiffusionAssemble3D(const int NE,
const Array<double> &g,
const Array<double> &b,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 6, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
MFEM_FOREACH_THREAD(i3,z,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
for (int j3 = 0; j3 < D1D; ++j3)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
for (int k3 = 0; k3 < Q1D; ++k3)
{
double bbgi = r_G[k1][i1] * r_B[k2][i2] * r_B[k3][i3];
double bgbi = r_B[k1][i1] * r_G[k2][i2] * r_B[k3][i3];
double gbbi = r_B[k1][i1] * r_B[k2][i2] * r_G[k3][i3];
double bbgj = r_G[k1][j1] * r_B[k2][j2] * r_B[k3][j3];
double bgbj = r_B[k1][j1] * r_G[k2][j2] * r_B[k3][j3];
double gbbj = r_B[k1][j1] * r_B[k2][j2] * r_G[k3][j3];
double D00 = D(k1,k2,k3,0,e);
double D10 = D(k1,k2,k3,1,e);
double D20 = D(k1,k2,k3,2,e);
double D01 = D10;
double D11 = D(k1,k2,k3,3,e);
double D21 = D(k1,k2,k3,4,e);
double D02 = D20;
double D12 = D21;
double D22 = D(k1,k2,k3,5,e);
val += bbgi * D00 * bbgj
+ bgbi * D10 * bbgj
+ gbbi * D20 * bbgj
+ bbgi * D01 * bgbj
+ bgbi * D11 * bgbj
+ gbbi * D21 * bgbj
+ bbgi * D02 * gbbj
+ bgbi * D12 * gbbj
+ gbbi * D22 * gbbj;
}
}
}
A(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
}
}
}
});
}
void DiffusionIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
const Array<double> &B = maps->B;
const Array<double> &G = maps->G;
if (dim == 1)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADiffusionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EADiffusionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EADiffusionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EADiffusionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EADiffusionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EADiffusionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EADiffusionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EADiffusionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADiffusionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EADiffusionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EADiffusionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EADiffusionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EADiffusionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EADiffusionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EADiffusionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EADiffusionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EADiffusionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
case 0x34: return EADiffusionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
case 0x45: return EADiffusionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
case 0x56: return EADiffusionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
case 0x67: return EADiffusionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
case 0x78: return EADiffusionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
case 0x89: return EADiffusionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
+1187 -91
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -25,7 +25,6 @@ namespace mfem
void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
{
// Assuming the same element type
fespace = &fes;
Mesh *mesh = fes.GetMesh();
@@ -52,30 +51,21 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(ne*nq, Device::GetDeviceMemoryType());
Vector *coeff{nullptr};
bool own_coeff{true};
Vector coeff;
if (Q == nullptr)
{
coeff = new Vector;
coeff->SetSize(1);
(*coeff)(0) = 1.0;
coeff.SetSize(1);
coeff(0) = 1.0;
}
else if (ConstantCoefficient* cQ = dynamic_cast<ConstantCoefficient*>(Q))
{
coeff = new Vector;
coeff->SetSize(1);
(*coeff)(0) = 1.0;
}
else if (QuadratureCoefficient* cQ = dynamic_cast<QuadratureCoefficient*>(Q))
{
coeff = cQ->Data();
own_coeff = false;
coeff.SetSize(1);
coeff(0) = cQ->constant;
}
else
{
coeff = new Vector;
coeff->SetSize(nq * ne);
auto C = Reshape(coeff->HostWrite(), nq, ne);
coeff.SetSize(nq * ne);
auto C = Reshape(coeff.HostWrite(), nq, ne);
for (int e = 0; e < ne; ++e)
{
ElementTransformation& T = *fes.GetElementTransformation(e);
@@ -90,11 +80,11 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
{
const int NE = ne;
const int NQ = nq;
const bool const_c = coeff->Size() == 1;
const bool const_c = coeff.Size() == 1;
auto w = ir->GetWeights().Read();
auto J = Reshape(geom->J.Read(), NQ,2,2,NE);
auto C =
const_c ? Reshape(coeff->Read(), 1,1) : Reshape(coeff->Read(), NQ,NE);
const_c ? Reshape(coeff.Read(), 1,1) : Reshape(coeff.Read(), NQ,NE);
auto v = Reshape(pa_data.Write(), NQ, NE);
MFEM_FORALL(e, NE,
{
@@ -114,11 +104,11 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
{
const int NE = ne;
const int NQ = nq;
const bool const_c = coeff->Size() == 1;
const bool const_c = coeff.Size() == 1;
auto W = ir->GetWeights().Read();
auto J = Reshape(geom->J.Read(), NQ,3,3,NE);
auto C =
const_c ? Reshape(coeff->Read(), 1,1) : Reshape(coeff->Read(), NQ,NE);
const_c ? Reshape(coeff.Read(), 1,1) : Reshape(coeff.Read(), NQ,NE);
auto v = Reshape(pa_data.Write(), NQ,NE);
MFEM_FORALL(e, NE,
{
@@ -135,8 +125,6 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
}
});
}
if (own_coeff) { delete coeff; }
}
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
-255
View File
@@ -1,255 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
template<int T_D1D = 0, int T_Q1D = 0>
static void EAMassAssemble1D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto M = Reshape(eadata.Write(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_Bi[MQ1];
double r_Bj[MQ1];
for (int q = 0; q < Q1D; q++)
{
r_Bi[q] = B(q,MFEM_THREAD_ID(x));
r_Bj[q] = B(q,MFEM_THREAD_ID(y));
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val += r_Bi[k1] * r_Bj[k1] * D(k1, e);
}
M(i1, j1, e) = val;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAMassAssemble2D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, NE);
auto M = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1];
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2] = D(k1,k2,e);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2];
}
}
M(i1, i2, j1, j2, e) = val;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAMassAssemble3D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, NE);
auto M = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][MQ1];
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
MFEM_FOREACH_THREAD(k3,z,Q1D)
{
s_D[k1][k2][k3] = D(k1,k2,k3,e);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
MFEM_FOREACH_THREAD(i3,z,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
for (int j3 = 0; j3 < D1D; ++j3)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
for (int k3 = 0; k3 < Q1D; ++k3)
{
val += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* r_B[k3][i3] * r_B[k3][j3]
* s_D[k1][k2][k3];
}
}
}
M(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
}
}
}
});
}
void MassIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
const Array<double> &B = maps->B;
if (dim == 1)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAMassAssemble1D<2,2>(ne,B,pa_data,ea_data);
case 0x33: return EAMassAssemble1D<3,3>(ne,B,pa_data,ea_data);
case 0x44: return EAMassAssemble1D<4,4>(ne,B,pa_data,ea_data);
case 0x55: return EAMassAssemble1D<5,5>(ne,B,pa_data,ea_data);
case 0x66: return EAMassAssemble1D<6,6>(ne,B,pa_data,ea_data);
case 0x77: return EAMassAssemble1D<7,7>(ne,B,pa_data,ea_data);
case 0x88: return EAMassAssemble1D<8,8>(ne,B,pa_data,ea_data);
case 0x99: return EAMassAssemble1D<9,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble1D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAMassAssemble2D<2,2>(ne,B,pa_data,ea_data);
case 0x33: return EAMassAssemble2D<3,3>(ne,B,pa_data,ea_data);
case 0x44: return EAMassAssemble2D<4,4>(ne,B,pa_data,ea_data);
case 0x55: return EAMassAssemble2D<5,5>(ne,B,pa_data,ea_data);
case 0x66: return EAMassAssemble2D<6,6>(ne,B,pa_data,ea_data);
case 0x77: return EAMassAssemble2D<7,7>(ne,B,pa_data,ea_data);
case 0x88: return EAMassAssemble2D<8,8>(ne,B,pa_data,ea_data);
case 0x99: return EAMassAssemble2D<9,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble2D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EAMassAssemble3D<2,3>(ne,B,pa_data,ea_data);
case 0x34: return EAMassAssemble3D<3,4>(ne,B,pa_data,ea_data);
case 0x45: return EAMassAssemble3D<4,5>(ne,B,pa_data,ea_data);
case 0x56: return EAMassAssemble3D<5,6>(ne,B,pa_data,ea_data);
case 0x67: return EAMassAssemble3D<6,7>(ne,B,pa_data,ea_data);
case 0x78: return EAMassAssemble3D<7,8>(ne,B,pa_data,ea_data);
case 0x89: return EAMassAssemble3D<8,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble3D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
-103
View File
@@ -1,103 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
namespace mfem
{
void TransposeIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
Vector ea_data_tmp(ea_data.Size());
ea_data_tmp = 0.0;
bfi->AssembleEA(fes, ea_data_tmp);
const int ne = fes.GetNE();
if (ne == 0) { return; }
const int dofs = fes.GetFE(0)->GetDof();
auto A = Reshape(ea_data_tmp.Write(), dofs, dofs, ne);
auto AT = Reshape(ea_data.Write(), dofs, dofs, ne);
MFEM_FORALL(e, ne,
{
for (int i = 0; i < dofs; i++)
{
for (int j = 0; j < dofs; j++)
{
const double a = A(i, j, e);
AT(j, i, e) += a;
}
}
});
}
void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext)
{
const int nf = fes.GetNFbyType(FaceType::Interior);
if (nf == 0) { return; }
Vector ea_data_int_tmp(ea_data_int.Size());
Vector ea_data_ext_tmp(ea_data_ext.Size());
ea_data_int_tmp = 0.0;
ea_data_ext_tmp = 0.0;
bfi->AssembleEAInteriorFaces(fes, ea_data_int_tmp, ea_data_ext_tmp);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_int = Reshape(ea_data_int_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
auto AT_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
MFEM_FORALL(f, nf,
{
for (int i = 0; i < faceDofs; i++)
{
for (int j = 0; j < faceDofs; j++)
{
const double a_int0 = A_int(i, j, 0, f);
const double a_int1 = A_int(i, j, 1, f);
const double a_ext0 = A_ext(i, j, 0, f);
const double a_ext1 = A_ext(i, j, 1, f);
AT_int(j, i, 0, f) += a_int0;
AT_int(j, i, 1, f) += a_int1;
AT_ext(j, i, 0, f) += a_ext1;
AT_ext(j, i, 1, f) += a_ext0;
}
}
});
}
void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr)
{
const int nf = fes.GetNFbyType(FaceType::Boundary);
if (nf == 0) { return; }
Vector ea_data_bdr_tmp(ea_data_bdr.Size());
ea_data_bdr_tmp = 0.0;
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr_tmp);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
MFEM_FORALL(f, nf,
{
for (int i = 0; i < faceDofs; i++)
{
for (int j = 0; j < faceDofs; j++)
{
const double a_bdr = A_bdr(i, j, f);
AT_bdr(j, i, f) += a_bdr;
}
}
});
}
}
+49 -84
View File
@@ -101,6 +101,7 @@ static void PAVectorDiffusionSetup3D(const int Q1D,
}
static void PAVectorDiffusionSetup(const int dim,
const int D1D,
const int Q1D,
const int NE,
const Array<double> &W,
@@ -133,7 +134,6 @@ void VectorDiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
sdim = mesh->SpaceDimension();
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
@@ -147,83 +147,46 @@ void VectorDiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
MFEM_VERIFY(cQ != NULL, "only ConstantCoefficient is supported!");
coeff = cQ->constant;
}
const Array<double> &w = ir->GetWeights();
const Vector &j = geom->J;
Vector &d = pa_data;
if (dim == 1) { MFEM_ABORT("dim==1 not supported in PAVectorDiffusionSetup"); }
if (dim == 2 && sdim == 3)
{
constexpr int DIM = 2;
constexpr int SDIM = 3;
const int NQ = quad1D*quad1D;
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, SDIM, DIM, ne);
auto D = Reshape(d.Write(), NQ, SDIM, ne);
MFEM_FORALL(e, ne,
{
for (int q = 0; q < NQ; ++q)
{
const double wq = W[q];
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J31 = J(q,2,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double J32 = J(q,2,1,e);
const double E = J11*J11 + J21*J21 + J31*J31;
const double G = J12*J12 + J22*J22 + J32*J32;
const double F = J11*J12 + J21*J22 + J31*J32;
const double iw = 1.0 / sqrt(E*G - F*F);
const double alpha = wq * coeff * iw;
D(q,0,e) = alpha * G; // 1,1
D(q,1,e) = -alpha * F; // 1,2
D(q,2,e) = alpha * E; // 2,2
}
});
}
else
{
PAVectorDiffusionSetup(dim, quad1D, ne, w, j, coeff, d);
}
PAVectorDiffusionSetup(dim, dofs1D, quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
// PA Diffusion Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0, int T_VDIM = 0> static
template<int T_D1D = 0, int T_Q1D = 0> static
void PAVectorDiffusionApply2D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Array<double> &bt,
const Array<double> &gt,
const Vector &d_,
const Vector &x_,
Vector &y_,
const Vector &_op,
const Vector &_x,
Vector &_y,
const int d1d = 0,
const int q1d = 0,
const int vdim = 0)
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
constexpr int VDIM = 2;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto Gt = Reshape(gt.Read(), D1D, Q1D);
auto D = Reshape(d_.Read(), Q1D*Q1D, 3, NE);
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, NE);
auto op = Reshape(_op.Read(), Q1D*Q1D, 3, NE);
auto x = Reshape(_x.Read(), D1D, D1D, VDIM, NE);
auto y = Reshape(_y.ReadWrite(), D1D, D1D, VDIM, NE);
MFEM_FORALL(e, NE,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
double grad[max_Q1D][max_Q1D][2];
for (int c = 0; c < VDIM; c++)
for (int c = 0; c < VDIM; ++ c)
{
double grad[max_Q1D][max_Q1D][2];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
@@ -266,11 +229,14 @@ void PAVectorDiffusionApply2D(const int NE,
for (int qx = 0; qx < Q1D; ++qx)
{
const int q = qx + qy * Q1D;
const double O11 = D(q,0,e);
const double O12 = D(q,1,e);
const double O22 = D(q,2,e);
const double O11 = op(q,0,e);
const double O12 = op(q,1,e);
const double O22 = op(q,2,e);
const double gradX = grad[qy][qx][0];
const double gradY = grad[qy][qx][1];
grad[qy][qx][0] = (O11 * gradX) + (O12 * gradY);
grad[qy][qx][1] = (O12 * gradX) + (O22 * gradY);
}
@@ -280,8 +246,8 @@ void PAVectorDiffusionApply2D(const int NE,
double gradX[max_D1D][2];
for (int dx = 0; dx < D1D; ++dx)
{
gradX[dx][0] = 0.0;
gradX[dx][1] = 0.0;
gradX[dx][0] = 0;
gradX[dx][1] = 0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
@@ -503,36 +469,35 @@ void PAVectorDiffusionApply3D(const int NE,
});
}
static void PAVectorDiffusionApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &G,
const Array<double> &Bt,
const Array<double> &Gt,
const Vector &op,
const Vector &x,
Vector &y)
{
if (dim == 2)
{
return PAVectorDiffusionApply2D(NE,B,G,Bt,Gt,op,x,y,D1D,Q1D);
}
if (dim == 3)
{
return PAVectorDiffusionApply3D(NE,B,G,Bt,Gt,op,x,y,D1D,Q1D);
}
MFEM_ABORT("Unknown kernel.");
}
// PA Diffusion Apply kernel
void VectorDiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
const int D1D = dofs1D;
const int Q1D = quad1D;
const Array<double> &B = maps->B;
const Array<double> &G = maps->G;
const Array<double> &Bt = maps->Bt;
const Array<double> &Gt = maps->Gt;
const Vector &D = pa_data;
if (dim == 2 && sdim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return PAVectorDiffusionApply2D<2,2,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x33: return PAVectorDiffusionApply2D<3,3,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x44: return PAVectorDiffusionApply2D<4,4,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x55: return PAVectorDiffusionApply2D<5,5,3>(ne,B,G,Bt,Gt,D,x,y);
default:
return PAVectorDiffusionApply2D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D,sdim);
}
}
if (dim == 2 && sdim == 2)
{ return PAVectorDiffusionApply2D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D,sdim); }
if (dim == 3 && sdim == 3)
{ return PAVectorDiffusionApply3D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D); }
MFEM_ABORT("Unknown kernel.");
PAVectorDiffusionApply(dim, dofs1D, quad1D, ne,
maps->B, maps->G, maps->Bt, maps->Gt,
pa_data, x, y);
}
template<int T_D1D = 0, int T_Q1D = 0>
-379
View File
@@ -1,379 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "bilininteg.hpp"
namespace mfem
{
void PAHcurlSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHcurlSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHcurlMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHcurlMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHdivSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHdivSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHcurlH1Apply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHcurlH1Apply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHdivMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHdivMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHdivMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHdivMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement *fel = fes.GetFE(0);
const VectorTensorFiniteElement *el =
dynamic_cast<const VectorTensorFiniteElement*>(fel);
MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*el, *el,
*mesh->GetElementTransformation(0));
const int dims = el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
Vector coeff(ne * nq);
coeff = 1.0;
if (Q)
{
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
fetype = el->GetDerivType();
if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 3)
{
PAHdivSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 2)
{
PAHdivSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
{
if (dim == 3)
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassAssembleDiagonal3D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
else
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
}
void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
else
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
}
void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
&trial_fes,
const FiniteElementSpace &test_fes)
{
// Assumes tensor-product elements, with a vector test space and H^1 trial space.
Mesh *mesh = trial_fes.GetMesh();
const FiniteElement *trial_fel = trial_fes.GetFE(0);
const FiniteElement *test_fel = test_fes.GetFE(0);
const NodalTensorFiniteElement *trial_el =
dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
MFEM_VERIFY(trial_el != NULL, "Only NodalTensorFiniteElement is supported!");
const VectorTensorFiniteElement *test_el =
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
*mesh->GetElementTransformation(0));
const int dims = trial_el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
ne = trial_fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
Vector coeff(ne * nq);
coeff = 1.0;
if (Q)
{
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
// Use the same setup functions as VectorFEMassIntegrator.
if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
void MixedVectorGradientIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
PAHcurlH1Apply3D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
else if (dim == 2)
PAHcurlH1Apply2D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
} // namespace mfem
+27 -174
View File
@@ -12,7 +12,6 @@
// Implementation of Coefficient class
#include "fem.hpp"
#include "../linalg/dtensor.hpp"
#include <cmath>
#include <limits>
@@ -22,13 +21,6 @@ namespace mfem
using namespace std;
double QuadratureCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
auto coeff = mfem::Reshape(qData->HostRead(), nip, NE);
return coeff(ip.index, T.ElementNo);
}
double PWConstCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
@@ -57,7 +49,7 @@ double FunctionCoefficient::Eval(ElementTransformation & T,
double GridFunctionCoefficient::Eval (ElementTransformation &T,
const IntegrationPoint &ip)
{
return GridF -> GetValue (T, ip, Component);
return GridF -> GetValue (T.ElementNo, ip, Component);
}
double TransformedCoefficient::Eval(ElementTransformation &T,
@@ -168,13 +160,13 @@ void VectorArrayCoefficient::Eval(Vector &V, ElementTransformation &T,
}
VectorGridFunctionCoefficient::VectorGridFunctionCoefficient (
const GridFunction *gf)
GridFunction *gf)
: VectorCoefficient ((gf) ? gf -> VectorDim() : 0)
{
GridFunc = gf;
}
void VectorGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
void VectorGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
{
GridFunc = gf; vdim = (gf) ? gf -> VectorDim() : 0;
}
@@ -182,7 +174,7 @@ void VectorGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
void VectorGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
GridFunc->GetVectorValue(T, ip, V);
GridFunc->GetVectorValue(T.ElementNo, ip, V);
}
void VectorGridFunctionCoefficient::Eval(
@@ -192,14 +184,14 @@ void VectorGridFunctionCoefficient::Eval(
}
GradientGridFunctionCoefficient::GradientGridFunctionCoefficient (
const GridFunction *gf)
GridFunction *gf)
: VectorCoefficient((gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0)
{
GridFunc = gf;
}
void GradientGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
void GradientGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
{
GridFunc = gf; vdim = (gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0;
@@ -218,14 +210,14 @@ void GradientGridFunctionCoefficient::Eval(
}
CurlGridFunctionCoefficient::CurlGridFunctionCoefficient (
const GridFunction *gf)
GridFunction *gf)
: VectorCoefficient ((gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0)
{
GridFunc = gf;
}
void CurlGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
void CurlGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
{
GridFunc = gf; vdim = (gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0;
@@ -238,7 +230,7 @@ void CurlGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
}
DivergenceGridFunctionCoefficient::DivergenceGridFunctionCoefficient (
const GridFunction *gf) : Coefficient()
GridFunction *gf) : Coefficient()
{
GridFunc = gf;
}
@@ -424,43 +416,13 @@ double DeterminantCoefficient::Eval(ElementTransformation &T,
return ma.Det();
}
VectorSumCoefficient::VectorSumCoefficient(int dim)
: VectorCoefficient(dim),
ACoef(NULL), BCoef(NULL),
A(dim), B(dim),
alphaCoef(NULL), betaCoef(NULL),
alpha(1.0), beta(1.0)
{
A = 0.0; B = 0.0;
}
VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &_A,
VectorCoefficient &_B,
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)
: VectorCoefficient(A.GetVDim()), a(&A), b(&B), alpha(_alpha), beta(_beta),
va(A.GetVDim())
{
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(),
MFEM_ASSERT(A.GetVDim() == B.GetVDim(),
"VectorSumCoefficient: "
"Arguments must have the same dimension.");
}
@@ -468,47 +430,26 @@ VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &_A,
void VectorSumCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
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);
b->Eval(V, T, ip);
if ( beta != 1.0 ) { V *= beta; }
a->Eval(va, T, ip);
V.Add(alpha, va);
}
ScalarVectorProductCoefficient::ScalarVectorProductCoefficient(
double A,
VectorCoefficient &B)
: VectorCoefficient(B.GetVDim()), aConst(A), a(NULL), b(&B)
{}
ScalarVectorProductCoefficient::ScalarVectorProductCoefficient(
Coefficient &A,
VectorCoefficient &B)
: VectorCoefficient(B.GetVDim()), aConst(0.0), a(&A), b(&B)
: VectorCoefficient(B.GetVDim()), a(&A), b(&B)
{}
void ScalarVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
double sa = (a == NULL) ? aConst : a->Eval(T, ip);
double sa = 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)
@@ -530,18 +471,17 @@ void VectorCrossProductCoefficient::Eval(Vector &V, ElementTransformation &T,
V[2] = va[0] * vb[1] - va[1] * vb[0];
}
MatrixVectorProductCoefficient::MatrixVectorProductCoefficient(
MatrixCoefficient &A, VectorCoefficient &B)
MatVecCoefficient::MatVecCoefficient(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(),
"MatrixVectorProductCoefficient: "
"Arguments have incompatible dimensions.");
"MatVecCoefficient: Arguments have incompatible dimensions.");
}
void MatrixVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
void MatVecCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
a->Eval(ma, T, ip);
b->Eval(vb, T, ip);
@@ -577,23 +517,17 @@ 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()), aConst(0.0), a(&A), b(&B)
: MatrixCoefficient(B.GetHeight(), B.GetWidth()), a(&A), b(&B)
{}
void ScalarMatrixProductCoefficient::Eval(DenseMatrix &M,
ElementTransformation &T,
const IntegrationPoint &ip)
{
double sa = (a == NULL) ? aConst : a->Eval(T, ip);
double sa = a->Eval(T, ip);
b->Eval(M, T, ip);
M *= sa;
}
@@ -647,30 +581,6 @@ void OuterProductCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
}
}
CrossCrossCoefficient::CrossCrossCoefficient(Coefficient &A,
VectorCoefficient &K)
: MatrixCoefficient(K.GetVDim(), K.GetVDim()), aConst(0.0), a(&A), k(&K),
vk(K.GetVDim())
{}
void CrossCrossCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip)
{
k->Eval(vk, T, ip);
M.SetSize(vk.Size(), vk.Size());
M = 0.0;
double k2 = vk*vk;
for (int i=0; i<vk.Size(); i++)
{
M(i, i) = k2;
for (int j=0; j<vk.Size(); j++)
{
M(i, j) -= vk[i] * vk[j];
}
}
M *= ((a == NULL ) ? aConst : a->Eval(T, ip) );
}
double LpNormLoop(double p, Coefficient &coeff, Mesh &mesh,
const IntegrationRule *irs[])
{
@@ -848,61 +758,4 @@ double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh,
}
#endif
VectorQuadratureFunctionCoefficient::VectorQuadratureFunctionCoefficient(
QuadratureFunction &qf)
: VectorCoefficient(qf.GetVDim()), QuadF(qf), index(0) { }
void VectorQuadratureFunctionCoefficient::SetComponent(int _index, int _length)
{
MFEM_VERIFY(_index >= 0, "Index must be >= 0");
MFEM_VERIFY(_index < QuadF.GetVDim(),
"Index must be < QuadratureFunction length");
index = _index;
MFEM_VERIFY(_length > 0, "Length must be > 0");
MFEM_VERIFY(_length <= QuadF.GetVDim() - index,
"Length must be <= (QuadratureFunction length - index)");
vdim = _length;
}
void VectorQuadratureFunctionCoefficient::Eval(Vector &V,
ElementTransformation &T,
const IntegrationPoint &ip)
{
QuadF.HostRead();
if (index == 0 && vdim == QuadF.GetVDim())
{
QuadF.GetElementValues(T.ElementNo, ip.index, V);
}
else
{
Vector temp;
QuadF.GetElementValues(T.ElementNo, ip.index, temp);
V.SetSize(vdim);
for (int i = 0; i < vdim; i++)
{
V(i) = temp(index + i);
}
}
return;
}
QuadratureFunctionCoefficient::QuadratureFunctionCoefficient(
QuadratureFunction &qf) : QuadF(qf)
{
MFEM_VERIFY(qf.GetVDim() == 1, "QuadratureFunction's vdim must be 1");
}
double QuadratureFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
QuadF.HostRead();
Vector temp(1);
QuadF.GetElementValues(T.ElementNo, ip.index, temp);
return temp[0];
}
}
+106 -759
View File
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -739,6 +739,12 @@ ParaViewDataCollection::ParaViewDataCollection(const std::string&
#endif
}
void ParaViewDataCollection::RegisterField(const std::string& field_name,
mfem::GridFunction *gf)
{
DataCollection::RegisterField(field_name,gf);
}
void ParaViewDataCollection::SetLevelsOfDetail(int levels_of_detail_)
{
levels_of_detail = levels_of_detail_;
@@ -809,7 +815,7 @@ void ParaViewDataCollection::Save()
// the directory is created
// create pvd file if needed
if (myid == 0 && !pvd_stream.is_open())
if (!pvd_stream.is_open())
{
std::string dpath=GenerateCollectionPath();
std::string pvdname=dpath+"/"+GeneratePVDFileName();
+4
View File
@@ -501,6 +501,10 @@ public:
ParaViewDataCollection(const std::string& collection_name,
mfem::Mesh *mesh_ = NULL);
/// Add a grid function to the collection
virtual void RegisterField(const std::string& field_name,
mfem::GridFunction *gf) override;
/// Set refinement levels - every element is uniformly split based on
/// levels_of_detail_
void SetLevelsOfDetail(int levels_of_detail_);
+13 -154
View File
@@ -19,7 +19,6 @@ namespace mfem
ElementTransformation::ElementTransformation()
: IntPoint(static_cast<IntegrationPoint *>(NULL)),
EvalState(0),
geom(Geometry::INVALID),
Attribute(-1),
ElementNo(-1)
{ }
@@ -392,10 +391,14 @@ void IsoparametricTransformation::SetIdentityTransformation(
nodes.IntPoint(j).Get(&PointMat(0,j), dim);
}
geom = GeomType;
space_dim = dim;
}
const DenseMatrix &IsoparametricTransformation::EvalJacobian()
{
MFEM_ASSERT(space_dim == PointMat.Height(),
"the IsoparametricTransformation has not been finalized;"
" call FinilizeTransformation() after setup");
MFEM_ASSERT((EvalState & JACOBIAN_MASK) == 0, "");
dshape.SetSize(FElem->GetDof(), FElem->GetDim());
@@ -412,6 +415,9 @@ const DenseMatrix &IsoparametricTransformation::EvalJacobian()
const DenseMatrix &IsoparametricTransformation::EvalHessian()
{
MFEM_ASSERT(space_dim == PointMat.Height(),
"the IsoparametricTransformation has not been finalized;"
" call FinilizeTransformation() after setup");
MFEM_ASSERT((EvalState & HESSIAN_MASK) == 0, "");
int Dim = FElem->GetDim();
@@ -427,7 +433,7 @@ const DenseMatrix &IsoparametricTransformation::EvalHessian()
return d2Fdx2;
}
int IsoparametricTransformation::OrderJ() const
int IsoparametricTransformation::OrderJ()
{
switch (FElem->Space())
{
@@ -436,12 +442,12 @@ int IsoparametricTransformation::OrderJ() const
case FunctionSpace::Qk:
return (FElem->GetOrder());
default:
MFEM_ABORT("unsupported finite element");
mfem_error("IsoparametricTransformation::OrderJ()");
}
return 0;
}
int IsoparametricTransformation::OrderW() const
int IsoparametricTransformation::OrderW()
{
switch (FElem->Space())
{
@@ -450,12 +456,12 @@ int IsoparametricTransformation::OrderW() const
case FunctionSpace::Qk:
return (FElem->GetOrder() * FElem->GetDim() - 1);
default:
MFEM_ABORT("unsupported finite element");
mfem_error("IsoparametricTransformation::OrderW()");
}
return 0;
}
int IsoparametricTransformation::OrderGrad(const FiniteElement *fe) const
int IsoparametricTransformation::OrderGrad(const FiniteElement *fe)
{
if (FElem->Space() == fe->Space())
{
@@ -468,11 +474,9 @@ int IsoparametricTransformation::OrderGrad(const FiniteElement *fe) const
return ((k-1)*(d-1)+(l-1));
case FunctionSpace::Qk:
return (k*(d-1)+(l-1));
default:
MFEM_ABORT("unsupported finite element");
}
}
MFEM_ABORT("incompatible finite elements");
mfem_error("IsoparametricTransformation::OrderGrad(...)");
return 0;
}
@@ -552,149 +556,4 @@ void IntegrationPointTransformation::Transform (const IntegrationRule &ir1,
}
}
void FaceElementTransformations::SetIntPoint(const IntegrationPoint *ip)
{
IsoparametricTransformation::SetIntPoint(ip);
if (Elem1)
{
Loc1.Transform(*ip, eip1);
Elem1->SetIntPoint(&eip1);
}
if (Elem2)
{
Loc2.Transform(*ip, eip2);
Elem2->SetIntPoint(&eip2);
}
}
ElementTransformation &
FaceElementTransformations::GetElement1Transformation()
{
MFEM_VERIFY(mask & 1 && Elem1 != NULL, "The ElementTransformation "
"for the element has not been configured for side 1.");
return *Elem1;
}
ElementTransformation &
FaceElementTransformations::GetElement2Transformation()
{
MFEM_VERIFY(mask & 2 && Elem2 != NULL, "The ElementTransformation "
"for the element has not been configured for side 2.");
return *Elem2;
}
IntegrationPointTransformation &
FaceElementTransformations::GetIntPoint1Transformation()
{
MFEM_VERIFY(mask & 4, "The IntegrationPointTransformation "
"for the element has not been configured for side 1.");
return Loc1;
}
IntegrationPointTransformation &
FaceElementTransformations::GetIntPoint2Transformation()
{
MFEM_VERIFY(mask & 8, "The IntegrationPointTransformation "
"for the element has not been configured for side 2.");
return Loc2;
}
void FaceElementTransformations::Transform(const IntegrationPoint &ip,
Vector &trans)
{
MFEM_VERIFY(mask & 16, "The ElementTransformation "
"for the face has not been configured.");
IsoparametricTransformation::Transform(ip, trans);
}
void FaceElementTransformations::Transform(const IntegrationRule &ir,
DenseMatrix &tr)
{
MFEM_VERIFY(mask & 16, "The ElementTransformation "
"for the face has not been configured.");
IsoparametricTransformation::Transform(ir, tr);
}
void FaceElementTransformations::Transform(const DenseMatrix &matrix,
DenseMatrix &result)
{
MFEM_VERIFY(mask & 16, "The ElementTransformation "
"for the face has not been configured.");
IsoparametricTransformation::Transform(matrix, result);
}
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;
}
}
+31 -188
View File
@@ -37,13 +37,11 @@ protected:
HESSIAN_MASK = 16
};
Geometry::Type geom;
int space_dim;
/** @brief Evaluate the Jacobian of the transformation at the IntPoint and
store it in dFdx. */
// Evaluate the Jacobian of the transformation at the IntPoint and store it
// in dFdx.
virtual const DenseMatrix &EvalJacobian() = 0;
/** @brief Evaluate the Hessian of the transformation at the IntPoint and
store it in d2Fdx2. */
virtual const DenseMatrix &EvalHessian() = 0;
double EvalWeight();
@@ -51,53 +49,18 @@ protected:
const DenseMatrix &EvalInverseJ();
public:
/** This enumeration declares the values stored in
ElementTransformation::ElementType and indicates which group of objects
the index stored in ElementTransformation::ElementNo refers:
| ElementType | Range of ElementNo
+-------------+-------------------------
| ELEMENT | [0, Mesh::GetNE() )
| BDR_ELEMENT | [0, Mesh::GetNBE() )
| EDGE | [0, Mesh::GetNEdges() )
| FACE | [0, Mesh::GetNFaces() )
| BDR_FACE | [0, Mesh::GetNBE() )
*/
enum
{
ELEMENT = 1,
BDR_ELEMENT = 2,
EDGE = 3,
FACE = 4,
BDR_FACE = 5
};
int Attribute, ElementNo, ElementType;
int Attribute, ElementNo;
ElementTransformation();
/** @brief Set the integration point @a ip that weights and Jacobians will
be evaluated at. */
void SetIntPoint(const IntegrationPoint *ip)
{ IntPoint = ip; EvalState = 0; }
/** @brief Get a const reference to the currently set integration point. This
will return NULL if no integration point is set. */
const IntegrationPoint &GetIntPoint() { return *IntPoint; }
/** @brief Transform integration point from reference coordinates to
physical coordinates and store them in the vector. */
virtual void Transform(const IntegrationPoint &, Vector &) = 0;
/** @brief Transform all the integration points from the integration rule
from reference coordinates to physical
coordinates and store them as column vectors in the matrix. */
virtual void Transform(const IntegrationRule &, DenseMatrix &) = 0;
/** @brief Transform all the integration points from the column vectors
of @a matrix from reference coordinates to physical
coordinates and store them as column vectors in @a result. */
/// Transform columns of 'matrix', store result in 'result'.
virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result) = 0;
/** @brief Return the Jacobian matrix of the transformation at the currently
@@ -108,50 +71,33 @@ public:
const DenseMatrix &Jacobian()
{ return (EvalState & JACOBIAN_MASK) ? dFdx : EvalJacobian(); }
/** @brief Return the Hessian matrix of the transformation at the currently
set IntegrationPoint, using the method SetIntPoint(). */
const DenseMatrix &Hessian()
{ return (EvalState & HESSIAN_MASK) ? d2Fdx2 : EvalHessian(); }
/** @brief Return the weight of the Jacobian matrix of the transformation
at the currently set IntegrationPoint.
The Weight evaluates to \f$ \sqrt{\lvert J^T J \rvert} \f$. */
double Weight() { return (EvalState & WEIGHT_MASK) ? Wght : EvalWeight(); }
/** @brief Return the adjugate of the Jacobian matrix of the transformation
at the currently set IntegrationPoint. */
const DenseMatrix &AdjugateJacobian()
{ return (EvalState & ADJUGATE_MASK) ? adjJ : EvalAdjugateJ(); }
/** @brief Return the inverse of the Jacobian matrix of the transformation
at the currently set IntegrationPoint. */
const DenseMatrix &InverseJacobian()
{ return (EvalState & INVERSE_MASK) ? invJ : EvalInverseJ(); }
/// Return the order of the current element we are using for the transformation.
virtual int Order() const = 0;
/// Return the order of the elements of the Jacobian of the transformation.
virtual int OrderJ() const = 0;
/** @brief Return the order of the determinant of the Jacobian (weight)
of the transformation. */
virtual int OrderW() const = 0;
/// Return the order of \f$ adj(J)^T \nabla fi \f$
virtual int OrderGrad(const FiniteElement *fe) const = 0;
virtual int Order() = 0;
virtual int OrderJ() = 0;
virtual int OrderW() = 0;
/// Order of adj(J)^t.grad(fi)
virtual int OrderGrad(const FiniteElement *fe) = 0;
/// Return the Geometry::Type of the reference element.
Geometry::Type GetGeometryType() const { return geom; }
/// Return the topological dimension of the reference element.
/// Return the dimension of the reference element.
int GetDimension() const { return Geometry::Dimension[geom]; }
/// Get the dimension of the target (physical) space.
/** We support 2D meshes embedded in 3D; in this case the function will
return "3". */
virtual int GetSpaceDim() const = 0;
int GetSpaceDim() const { return space_dim; }
/** @brief Transform a point @a pt from physical space to a point @a ip in
reference space. */
@@ -341,7 +287,7 @@ public:
virtual int Transform(const Vector &pt, IntegrationPoint &ip);
};
/// A standard isoparametric element transformation
class IsoparametricTransformation : public ElementTransformation
{
private:
@@ -351,75 +297,41 @@ private:
const FiniteElement *FElem;
DenseMatrix PointMat; // dim x dof
/** @brief Evaluate the Jacobian of the transformation at the IntPoint and
store it in dFdx. */
// Evaluate the Jacobian of the transformation at the IntPoint and store it
// in dFdx.
virtual const DenseMatrix &EvalJacobian();
// Evaluate the Hessian of the transformation at the IntPoint and store it
// in d2Fdx2.
virtual const DenseMatrix &EvalHessian();
public:
/// Set the element that will be used to compute the transformations
void SetFE(const FiniteElement *FE) { FElem = FE; geom = FE->GetGeomType(); }
/// Get the current element used to compute the transformations
const FiniteElement* GetFE() const { return FElem; }
/// @brief Set the underlying point matrix describing the transformation.
/** @brief Read and write access to the underlying point matrix describing
the transformation. */
/** The dimensions of the matrix are space-dim x dof. The transformation is
defined as
\f$ x = F( \hat x ) = P \phi( \hat x ) \f$
where \f$ \hat x \f$ is the reference point, @a x is the corresponding
physical point, @a P is the point matrix, and \f$ \phi( \hat x ) \f$ is
the column-vector of all basis functions evaluated at \f$ \hat x \f$ .
The columns of @a P represent the control points in physical space
defining the transformation. */
void SetPointMat(const DenseMatrix &pm) { PointMat = pm; }
x=F(xh)=P.phi(xh),
/// Return the stored point matrix.
const DenseMatrix &GetPointMat() const { return PointMat; }
/// Write access to the stored point matrix. Use with caution.
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. */
DenseMatrix &GetPointMat() { return PointMat; }
void FinalizeTransformation() { space_dim = PointMat.Height(); }
/// 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(); }
virtual int Order() { return FElem->GetOrder(); }
virtual int OrderJ();
virtual int OrderW();
virtual int OrderGrad(const FiniteElement *fe);
/// 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);
@@ -427,8 +339,6 @@ public:
}
virtual ~IsoparametricTransformation() { }
MFEM_DEPRECATED void FinalizeTransformation() {}
};
class IntegrationPointTransformation
@@ -439,82 +349,15 @@ public:
void Transform (const IntegrationRule &, IntegrationRule &);
};
class FaceElementTransformations : public IsoparametricTransformation
class FaceElementTransformations
{
private:
int mask;
IntegrationPoint eip1, eip2;
public:
int Elem1No, Elem2No;
Geometry::Type &FaceGeom; ///< @deprecated Use GetGeometryType instead
ElementTransformation *Elem1, *Elem2;
ElementTransformation *Face; ///< @deprecated No longer necessary
int Elem1No, Elem2No, FaceGeom;
ElementTransformation *Elem1, *Elem2, *Face;
IntegrationPointTransformation Loc1, Loc2;
FaceElementTransformations() : FaceGeom(geom), Face(this) {}
/** @brief Method to set the geometry type of the face.
@note This method is designed to be used when
[Par]Mesh::GetFaceTransformation will not be called i.e. when the face
transformation will not be needed but the neighboring element
transformations will be. Using this method to override the GeometryType
should only be done with great care.
*/
void SetGeometryType(Geometry::Type g) { geom = g; }
/// Set the mask indicating which portions of the object have been setup
/** The argument @a m is a bitmask used in
Mesh::GetFaceElementTransformations to indicate which portions of the
FaceElement Transformations object have been configured.
mask & 1: Elem1 is configured
mask & 2: Elem2 is configured
mask & 4: Loc1 is configured
mask & 8: Loc2 is configured
mask & 16: The Face transformation itself is configured
*/
void SetConfigurationMask(int m) { mask = m; }
int GetConfigurationMask() const { return mask; }
/** @brief Set the integration point in the Face and the two neighboring
elements, if present. */
void SetIntPoint(const IntegrationPoint *ip);
virtual void Transform(const IntegrationPoint &, Vector &);
virtual void Transform(const IntegrationRule &, DenseMatrix &);
virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result);
ElementTransformation & GetElement1Transformation();
ElementTransformation & GetElement2Transformation();
IntegrationPointTransformation & GetIntPoint1Transformation();
IntegrationPointTransformation & GetIntPoint2Transformation();
/** @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
-17
View File
@@ -50,21 +50,4 @@ void L2ZienkiewiczZhuEstimator::ComputeEstimates()
#endif // MFEM_USE_MPI
void LpErrorEstimator::ComputeEstimates()
{
MFEM_VERIFY(coef != NULL || vcoef != NULL,
"LpErrorEstimator has no coefficient! Call SetCoef first.");
error_estimates.SetSize(sol->FESpace()->GetMesh()->GetNE());
if (coef)
{
sol->ComputeElementLpErrors(local_norm_p, *coef, error_estimates);
}
else
{
sol->ComputeElementLpErrors(local_norm_p, *vcoef, error_estimates);
}
current_sequence = sol->FESpace()->GetMesh()->GetSequence();
}
} // namespace mfem
-92
View File
@@ -45,7 +45,6 @@ public:
/// Force recomputation of the estimates on the next call to GetLocalErrors.
virtual void Reset() = 0;
/// Destruct the error estimator
virtual ~ErrorEstimator() { }
};
@@ -67,14 +66,6 @@ public:
/** @brief The ZienkiewiczZhuEstimator class implements the Zienkiewicz-Zhu
error estimation procedure.
Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery
and a posteriori error estimates. Part 1: The recovery technique.
Int. J. Num. Meth. Engng. 33, 1331-1364 (1992).
Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery
and a posteriori error estimates. Part 2: Error estimates and adaptivity.
Int. J. Num. Meth. Engng. 33, 1365-1382 (1992).
The required BilinearFormIntegrator must implement the methods
ComputeElementFlux() and ComputeFluxEnergy().
*/
@@ -226,7 +217,6 @@ protected:
class when needed.*/
bool own_flux_fes; ///< Ownership flag for flux_space and smooth_flux_space.
/// Initialize with the integrator, solution, and flux finite element spaces.
void Init(BilinearFormIntegrator &integ,
ParGridFunction &sol,
ParFiniteElementSpace *flux_fes,
@@ -314,88 +304,6 @@ public:
#endif // MFEM_USE_MPI
/** @brief The LpErrorEstimator class compares the solution to a known
coefficient.
This class can be used, for example, to adapt a mesh to a non-trivial
initial condition in a time-dependent simulation. It can also be used to
force refinement in the neighborhood of small features before switching to a
more traditional error estimator.
The LpErrorEstimator supports either scalar or vector coefficients and works
both in serial and in parallel.
*/
class LpErrorEstimator : public ErrorEstimator
{
protected:
long current_sequence;
int local_norm_p;
Vector error_estimates;
Coefficient * coef;
VectorCoefficient * vcoef;
GridFunction * sol;
/// Check if the mesh of the solution was modified.
bool MeshIsModified()
{
long mesh_sequence = sol->FESpace()->GetMesh()->GetSequence();
MFEM_ASSERT(mesh_sequence >= current_sequence, "");
return (mesh_sequence > current_sequence);
}
/// Compute the element error estimates.
void ComputeEstimates();
public:
/** @brief Construct a new LpErrorEstimator object for a scalar field.
@param p Integer which selects which Lp norm to use.
@param sol The GridFunction representation of the scalar field.
Note: the coefficient must be set before use with the SetCoef method.
*/
LpErrorEstimator(int p, GridFunction &sol)
: current_sequence(-1), local_norm_p(p),
error_estimates(0), coef(NULL), vcoef(NULL), sol(&sol) { }
/** @brief Construct a new LpErrorEstimator object for a scalar field.
@param p Integer which selects which Lp norm to use.
@param coef The scalar Coefficient to compare to the solution.
@param sol The GridFunction representation of the scalar field.
*/
LpErrorEstimator(int p, Coefficient &coef, GridFunction &sol)
: current_sequence(-1), local_norm_p(p),
error_estimates(0), coef(&coef), vcoef(NULL), sol(&sol) { }
/** @brief Construct a new LpErrorEstimator object for a vector field.
@param p Integer which selects which Lp norm to use.
@param coef The vector VectorCoefficient to compare to the solution.
@param sol The GridFunction representation of the vector field.
*/
LpErrorEstimator(int p, VectorCoefficient &coef, GridFunction &sol)
: current_sequence(-1), local_norm_p(p),
error_estimates(0), coef(NULL), vcoef(&coef), sol(&sol) { }
/** @brief Set the exponent, p, of the Lp norm used for computing the local
element errors. */
void SetLocalErrorNormP(int p) { local_norm_p = p; }
void SetCoef(Coefficient &A) { coef = &A; }
void SetCoef(VectorCoefficient &A) { vcoef = &A; }
/// Reset the error estimator.
virtual void Reset() { current_sequence = -1; }
/// Get a Vector with all element errors.
virtual const Vector &GetLocalErrors()
{
if (MeshIsModified()) { ComputeEstimates(); }
return error_estimates;
}
/// Destructor
virtual ~LpErrorEstimator() {}
};
} // namespace mfem
#endif // MFEM_ERROR_ESTIMATORS
+510 -519
View File
File diff suppressed because it is too large Load Diff
+189 -437
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -311,10 +311,10 @@ GetEdge(int &nv, v_t &v, int &ne, int &e, int &eo, const int edge_info)
eo = edge_info%64;
MFEM_ASSERT(0 <= e && e < g_consts::NumEdges, "");
MFEM_ASSERT(0 <= eo && eo < e_consts::NumOrient, "");
v[0] = e_consts::Orient[eo][0];
v[1] = e_consts::Orient[eo][1];
v[0] = g_consts::Edges[e][v[0]];
v[1] = g_consts::Edges[e][v[1]];
v[0] = g_consts::Edges[e][0];
v[1] = g_consts::Edges[e][1];
v[0] = e_consts::Orient[eo][v[0]];
v[1] = e_consts::Orient[eo][v[1]];
}
template <Geometry::Type geom, Geometry::Type f_geom,
+47 -176
View File
@@ -19,10 +19,10 @@
namespace mfem
{
/** @brief Collection of finite elements from the same family in multiple
dimensions. This class is used to match the degrees of freedom of a
FiniteElementSpace between elements, and to provide the finite element
restriction from an element to its boundary. */
/** Collection of finite elements from the same family in multiple dimensions.
This class is used to match the degrees of freedom of a FiniteElementSpace
between elements, and to provide the finite element restriction from an
element to its boundary. */
class FiniteElementCollection
{
protected:
@@ -40,14 +40,6 @@ protected:
const int face_info);
public:
/** @brief Enumeration for ContType: defines the continuity of the field
across element interfaces. */
enum { CONTINUOUS, ///< Field is continuous across element interfaces
TANGENTIAL, ///< Tangential components of vector field
NORMAL, ///< Normal component of vector field
DISCONTINUOUS ///< Field is discontinuous across element interfaces
};
virtual const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const = 0;
@@ -60,8 +52,6 @@ public:
virtual const char * Name() const { return "Undefined"; }
virtual int GetContType() const = 0;
int HasFaceDofs(Geometry::Type GeomType) const;
virtual const FiniteElement *TraceFiniteElementForGeometry(
@@ -76,81 +66,15 @@ public:
/** @brief Factory method: return a newly allocated FiniteElementCollection
according to the given name. */
/**
| FEC Name | Space | Order | BasisType | FiniteElement::MapT | Notes |
| :------: | :---: | :---: | :-------: | :-----: | :---: |
| H1_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements |
| H1@[BTYPE]_[DIM]_[ORDER] | H1 | * | * | VALUE | H1 nodal elements |
| H1Pos_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements |
| H1Pos_Trace_[DIM]_[ORDER] | H^{1/2} | * | 2 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) |
| H1_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) |
| H1_Trace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) |
| ND_[DIM]_[ORDER] | H(curl) | * | 1 / 0 | H_CURL | Nedelec vector elements |
| ND@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H(curl) | * | * / * | H_CURL | Nedelec vector elements |
| ND_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | H_CURL | H^{1/2}-conforming trace elements for H(curl) defined on the interface between mesh elements (faces) |
| ND_Trace@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | H_CURL | H^{1/2}-conforming trace elements for H(curl) defined on the interface between mesh elements (faces) |
| RT_[DIM]_[ORDER] | H(div) | * | 1 / 0 | H_DIV | Raviart-Thomas vector elements |
| RT@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H(div) | * | * / * | H_DIV | Raviart-Thomas vector elements |
| RT_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | INTEGRAL | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
| RT_ValTrace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | VALUE | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
| RT_Trace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | INTEGRAL | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
| RT_ValTrace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | VALUE | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
| L2_[DIM]_[ORDER] | L2 | * | 0 | VALUE | Discontinous L2 elements |
| L2_T[BTYPE]_[DIM]_[ORDER] | L2 | * | 0 | VALUE | Discontinous L2 elements |
| L2Int_[DIM]_[ORDER] | L2 | * | 0 | INTEGRAL | Discontinous L2 elements |
| L2Int_T[BTYPE]_[DIM]_[ORDER] | L2 | * | 0 | INTEGRAL | Discontinous L2 elements |
| DG_Iface_[DIM]_[ORDER] | - | * | 0 | VALUE | Discontinuous elements on the interface between mesh elements (faces) |
| DG_Iface@[BTYPE]_[DIM]_[ORDER] | - | * | 0 | VALUE | Discontinuous elements on the interface between mesh elements (faces) |
| DG_IntIface_[DIM]_[ORDER] | - | * | 0 | INTEGRAL | Discontinuous elements on the interface between mesh elements (faces) |
| DG_IntIface@[BTYPE]_[DIM]_[ORDER] | - | * | 0 | INTEGRAL | Discontinuous elements on the interface between mesh elements (faces) |
| NURBS[ORDER] | - | * | - | VALUE | Non-Uniform Rational B-Splines (NURBS) elements |
| LinearNonConf3D | - | 1 | 1 | VALUE | Piecewise-linear nonconforming finite elements in 3D |
| CrouzeixRaviart | - | - | - | - | Crouzeix-Raviart nonconforming elements in 2D |
| Local_[FENAME] | - | - | - | - | Special collection that builds a local version out of the FENAME collection |
|-|-|-|-|-|-|
| Linear | H1 | 1 | 1 | VALUE | Left in for backward compatibility, consider using H1_ |
| Quadratic | H1 | 2 | 1 | VALUE | Left in for backward compatibility, consider using H1_ |
| QuadraticPos | H1 | 2 | 2 | VALUE | Left in for backward compatibility, consider using H1_ |
| Cubic | H1 | 2 | 1 | VALUE | Left in for backward compatibility, consider using H1_ |
| Const2D | L2 | 0 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| Const3D | L2 | 0 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| LinearDiscont2D | L2 | 1 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| GaussLinearDiscont2D | L2 | 1 | 0 | VALUE | Left in for backward compatibility, consider using L2_ |
| P1OnQuad | H1 | 1 | 1 | VALUE | Linear P1 element with 3 nodes on a square |
| QuadraticDiscont2D | L2 | 2 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| QuadraticPosDiscont2D | L2 | 2 | 2 | VALUE | Left in for backward compatibility, consider using L2_ |
| GaussQuadraticDiscont2D | L2 | 2 | 0 | VALUE | Left in for backward compatibility, consider using L2_ |
| CubicDiscont2D | L2 | 3 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| LinearDiscont3D | L2 | 1 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| QuadraticDiscont3D | L2 | 2 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| ND1_3D | H(Curl) | 1 | 1 / 0 | H_CURL | Left in for backward compatibility, consider using ND_ |
| RT0_2D | H(Div) | 1 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
| RT1_2D | H(Div) | 2 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
| RT2_2D | H(Div) | 3 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
| RT0_3D | H(Div) | 1 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
| RT1_3D | H(Div) | 2 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
| Tag | Description |
| :------: | :--------: |
| [DIM] | Dimension of the elements (1D, 2D, 3D) |
| [ORDER] | Approximation order of the elements (P0, P1, P2, ...) |
| [BTYPE] | BasisType of the element (0-GaussLegendre, 1 - GaussLobatto, 2-Bernstein, 3-OpenUniform, 4-CloseUniform, 5-OpenHalfUniform) |
| [OBTYPE] | Open BasisType of the element for elements which have both types |
| [CBTYPE] | Closed BasisType of the element for elements which have both types |
[FENAME] Is a special case for the Local FEC which generates a local version of a given
FEC. It is selected from one of (BiCubic2DFiniteElement, Quad_Q3, Nedelec1HexFiniteElement,
Hex_ND1, H1_[DIM]_[ORDER],H1Pos_[DIM]_[ORDER], L2_[DIM]_[ORDER] )
*/
static FiniteElementCollection *New(const char *name);
/** @brief Get the local dofs for a given sub-manifold.
Return the local dofs for a SDim-dimensional sub-manifold (0D - vertex, 1D
- edge, 2D - face) including those on its boundary. The local index of the
sub-manifold (inside Geom) and its orientation are given by the parameter
Info = 64 * SubIndex + SubOrientation. Naturally, it is assumed that 0 <=
SDim <= Dim(Geom). */
Return the local dofs for a SDim-dimensional sub-manifold (0D - vertex,
1D - edge, 2D - face) including those on its boundary. The local index of
the sub-manifold (inside Geom) and its orientation are given by the
parameter Info = 64 * SubIndex + SubOrientation. Naturally, it is assumed
that 0 <= SDim <= Dim(Geom). */
void SubDofOrder(Geometry::Type Geom, int SDim, int Info,
Array<int> &dofs) const;
};
@@ -178,7 +102,6 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char *Name() const { return h1_name; }
virtual int GetContType() const { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const;
int GetBasisType() const { return b_type; }
@@ -188,8 +111,8 @@ public:
virtual ~H1_FECollection();
};
/** @brief Arbitrary order H1-conforming (continuous) finite elements with
positive basis functions. */
/** Arbitrary order H1-conforming (continuous) finite elements with positive
basis functions. */
class H1Pos_FECollection : public H1_FECollection
{
public:
@@ -197,7 +120,6 @@ public:
: H1_FECollection(p, dim, BasisType::Positive) { }
};
/** Arbitrary order H1-conforming (continuous) serendipity finite elements;
Current implementation works in 2D only; 3D version is in development. */
class H1Ser_FECollection : public H1_FECollection
@@ -207,9 +129,9 @@ public:
: H1_FECollection(p, dim, BasisType::Serendipity) { };
};
/** @brief Arbitrary order "H^{1/2}-conforming" trace finite elements defined on
the interface between mesh elements (faces,edges,vertices); these are the
trace FEs of the H1-conforming FEs. */
/** Arbitrary order "H^{1/2}-conforming" trace finite elements defined on the
interface between mesh elements (faces,edges,vertices); these are the trace
FEs of the H1-conforming FEs. */
class H1_Trace_FECollection : public H1_FECollection
{
public:
@@ -252,8 +174,6 @@ public:
int Or) const;
virtual const char *Name() const { return d_name; }
virtual int GetContType() const { return DISCONTINUOUS; }
virtual const FiniteElement *TraceFiniteElementForGeometry(
Geometry::Type GeomType) const
{
@@ -301,15 +221,14 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char *Name() const { return rt_name; }
virtual int GetContType() const { return NORMAL; }
FiniteElementCollection *GetTraceCollection() const;
virtual ~RT_FECollection();
};
/** @brief Arbitrary order "H^{-1/2}-conforming" face finite elements defined on
the interface between mesh elements (faces); these are the normal trace FEs
of the H(div)-conforming FEs. */
/** Arbitrary order "H^{-1/2}-conforming" face finite elements defined on the
interface between mesh elements (faces); these are the normal trace FEs of
the H(div)-conforming FEs. */
class RT_Trace_FECollection : public RT_FECollection
{
public:
@@ -351,15 +270,14 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char *Name() const { return nd_name; }
virtual int GetContType() const { return TANGENTIAL; }
FiniteElementCollection *GetTraceCollection() const;
virtual ~ND_FECollection();
};
/** @brief Arbitrary order H(curl)-trace finite elements defined on the
interface between mesh elements (faces,edges); these are the tangential
trace FEs of the H(curl)-conforming FEs. */
/** Arbitrary order H(curl)-trace finite elements defined on the interface
between mesh elements (faces,edges); these are the tangential trace FEs of
the H(curl)-conforming FEs. */
class ND_Trace_FECollection : public ND_FECollection
{
public:
@@ -416,15 +334,13 @@ public:
virtual const char *Name() const { return name; }
virtual int GetContType() const { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const;
virtual ~NURBSFECollection();
};
/// Piecewise-(bi/tri)linear continuous finite elements.
/// Piecewise-(bi)linear continuous finite elements.
class LinearFECollection : public FiniteElementCollection
{
private:
@@ -447,8 +363,6 @@ public:
int Or) const;
virtual const char * Name() const { return "Linear"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Piecewise-(bi)quadratic continuous finite elements.
@@ -475,8 +389,6 @@ public:
int Or) const;
virtual const char * Name() const { return "Quadratic"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Version of QuadraticFECollection with positive basis functions.
@@ -498,8 +410,6 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticPos"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Piecewise-(bi)cubic continuous finite elements.
@@ -527,8 +437,6 @@ public:
int Or) const;
virtual const char * Name() const { return "Cubic"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Crouzeix-Raviart nonconforming elements in 2D.
@@ -550,8 +458,6 @@ public:
int Or) const;
virtual const char * Name() const { return "CrouzeixRaviart"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Piecewise-linear nonconforming finite elements in 3D.
@@ -575,13 +481,11 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearNonConf3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief First order Raviart-Thomas finite elements in 2D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
/** First order Raviart-Thomas finite elements in 2D. This class is kept only
for backward compatibility, consider using RT_FECollection instead. */
class RT0_2DFECollection : public FiniteElementCollection
{
private:
@@ -600,12 +504,10 @@ public:
int Or) const;
virtual const char * Name() const { return "RT0_2D"; }
virtual int GetContType() const { return NORMAL; }
};
/** @brief Second order Raviart-Thomas finite elements in 2D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
/** Second order Raviart-Thomas finite elements in 2D. This class is kept only
for backward compatibility, consider using RT_FECollection instead. */
class RT1_2DFECollection : public FiniteElementCollection
{
private:
@@ -624,12 +526,10 @@ public:
int Or) const;
virtual const char * Name() const { return "RT1_2D"; }
virtual int GetContType() const { return NORMAL; }
};
/** @brief Third order Raviart-Thomas finite elements in 2D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
/** Third order Raviart-Thomas finite elements in 2D. This class is kept only
for backward compatibility, consider using RT_FECollection instead. */
class RT2_2DFECollection : public FiniteElementCollection
{
private:
@@ -648,13 +548,10 @@ public:
int Or) const;
virtual const char * Name() const { return "RT2_2D"; }
virtual int GetContType() const { return NORMAL; }
};
/** @brief Piecewise-constant discontinuous finite elements in 2D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
/** Piecewise-constant discontinuous finite elements in 2D. This class is kept
only for backward compatibility, consider using L2_FECollection instead. */
class Const2DFECollection : public FiniteElementCollection
{
private:
@@ -672,13 +569,10 @@ public:
int Or) const;
virtual const char * Name() const { return "Const2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-linear discontinuous finite elements in 2D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
/** Piecewise-linear discontinuous finite elements in 2D. This class is kept
only for backward compatibility, consider using L2_FECollection instead. */
class LinearDiscont2DFECollection : public FiniteElementCollection
{
private:
@@ -697,8 +591,6 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Version of LinearDiscont2DFECollection with dofs in the Gaussian points.
@@ -721,8 +613,6 @@ public:
int Or) const;
virtual const char * Name() const { return "GaussLinearDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Linear (P1) finite elements on quadrilaterals.
@@ -738,12 +628,10 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char * Name() const { return "P1OnQuad"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-quadratic discontinuous finite elements in 2D. This class
is kept only for backward compatibility, consider using L2_FECollection
instead. */
/** Piecewise-quadratic discontinuous finite elements in 2D. This class is kept
only for backward compatibility, consider using L2_FECollection instead. */
class QuadraticDiscont2DFECollection : public FiniteElementCollection
{
private:
@@ -762,7 +650,6 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Version of QuadraticDiscont2DFECollection with positive basis functions.
@@ -780,7 +667,6 @@ public:
int Or) const
{ return NULL; }
virtual const char * Name() const { return "QuadraticPosDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Version of QuadraticDiscont2DFECollection with dofs in the Gaussian points.
@@ -803,12 +689,10 @@ public:
int Or) const;
virtual const char * Name() const { return "GaussQuadraticDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-cubic discontinuous finite elements in 2D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
/** Piecewise-cubic discontinuous finite elements in 2D. This class is kept
only for backward compatibility, consider using L2_FECollection instead. */
class CubicDiscont2DFECollection : public FiniteElementCollection
{
private:
@@ -827,12 +711,10 @@ public:
int Or) const;
virtual const char * Name() const { return "CubicDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-constant discontinuous finite elements in 3D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
/** Piecewise-constant discontinuous finite elements in 3D. This class is kept
only for backward compatibility, consider using L2_FECollection instead. */
class Const3DFECollection : public FiniteElementCollection
{
private:
@@ -852,12 +734,10 @@ public:
int Or) const;
virtual const char * Name() const { return "Const3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-linear discontinuous finite elements in 3D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
/** Piecewise-linear discontinuous finite elements in 3D. This class is kept
only for backward compatibility, consider using L2_FECollection instead. */
class LinearDiscont3DFECollection : public FiniteElementCollection
{
private:
@@ -876,12 +756,10 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearDiscont3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** @brief Piecewise-quadratic discontinuous finite elements in 3D. This class
is kept only for backward compatibility, consider using L2_FECollection
instead. */
/** Piecewise-quadratic discontinuous finite elements in 3D. This class is kept
only for backward compatibility, consider using L2_FECollection instead. */
class QuadraticDiscont3DFECollection : public FiniteElementCollection
{
private:
@@ -900,7 +778,6 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticDiscont3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Finite element collection on a macro-element.
@@ -926,12 +803,10 @@ public:
int Or) const;
virtual const char * Name() const { return "RefinedLinear"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/** @brief Lowest order Nedelec finite elements in 3D. This class is kept only
for backward compatibility, consider using the new ND_FECollection
instead. */
/** Lowest order Nedelec finite elements in 3D. This class is kept only for
backward compatibility, consider using the new ND_FECollection instead. */
class ND1_3DFECollection : public FiniteElementCollection
{
private:
@@ -950,11 +825,10 @@ public:
int Or) const;
virtual const char * Name() const { return "ND1_3D"; }
virtual int GetContType() const { return TANGENTIAL; }
};
/** @brief First order Raviart-Thomas finite elements in 3D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
/** First order Raviart-Thomas finite elements in 3D. This class is kept only
for backward compatibility, consider using RT_FECollection instead. */
class RT0_3DFECollection : public FiniteElementCollection
{
private:
@@ -974,11 +848,10 @@ public:
int Or) const;
virtual const char * Name() const { return "RT0_3D"; }
virtual int GetContType() const { return NORMAL; }
};
/** @brief Second order Raviart-Thomas finite elements in 3D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
/** Second order Raviart-Thomas finite elements in 3D. This class is kept only
for backward compatibility, consider using RT_FECollection instead. */
class RT1_3DFECollection : public FiniteElementCollection
{
private:
@@ -997,7 +870,6 @@ public:
int Or) const;
virtual const char * Name() const { return "RT1_3D"; }
virtual int GetContType() const { return NORMAL; }
};
/// Discontinuous collection defined locally by a given finite element.
@@ -1022,7 +894,6 @@ public:
virtual const char *Name() const { return d_name; }
virtual ~Local_FECollection() { delete Local_Element; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
}
-7
View File
@@ -37,9 +37,6 @@
#include "restriction.hpp"
#include "quadinterpolator.hpp"
#include "quadinterpolator_face.hpp"
#include "transfer.hpp"
#include "fespacehierarchy.hpp"
#include "multigrid.hpp"
#ifdef MFEM_USE_MPI
#include "pfespace.hpp"
@@ -57,8 +54,4 @@
#include "conduitdatacollection.hpp"
#endif
#ifdef MFEM_USE_ADIOS2
#include "adios2datacollection.hpp"
#endif
#endif
+82 -255
View File
@@ -60,7 +60,7 @@ FiniteElementSpace::FiniteElementSpace()
: mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
fdofs(NULL), bdofs(NULL),
elem_dof(NULL), bdrElem_dof(NULL), face_dof(NULL),
elem_dof(NULL), bdrElem_dof(NULL),
NURBSext(NULL), own_ext(false),
cP(NULL), cR(NULL), cP_is_set(false),
Th(Operator::ANY_TYPE),
@@ -233,54 +233,6 @@ void FiniteElementSpace::BuildElementToDofTable() const
elem_dof = el_dof;
}
void FiniteElementSpace::BuildBdrElementToDofTable() const
{
if (bdrElem_dof) { return; }
Table *bel_dof = new Table;
Array<int> dofs;
bel_dof->MakeI(mesh->GetNBE());
for (int i = 0; i < mesh->GetNBE(); i++)
{
GetBdrElementDofs(i, dofs);
bel_dof->AddColumnsInRow(i, dofs.Size());
}
bel_dof->MakeJ();
for (int i = 0; i < mesh->GetNBE(); i++)
{
GetBdrElementDofs(i, dofs);
bel_dof->AddConnections(i, (int *)dofs, dofs.Size());
}
bel_dof->ShiftUpI();
bdrElem_dof = bel_dof;
}
void FiniteElementSpace::BuildFaceToDofTable() const
{
// Here, "face" == (dim-1)-dimensional mesh entity.
if (face_dof) { return; }
if (NURBSext) { BuildNURBSFaceToDofTable(); return; }
Table *fc_dof = new Table;
Array<int> dofs;
fc_dof->MakeI(mesh->GetNumFaces());
for (int i = 0; i < fc_dof->Size(); i++)
{
GetFaceDofs(i, dofs);
fc_dof->AddColumnsInRow(i, dofs.Size());
}
fc_dof->MakeJ();
for (int i = 0; i < fc_dof->Size(); i++)
{
GetFaceDofs(i, dofs);
fc_dof->AddConnections(i, (int *)dofs, dofs.Size());
}
fc_dof->ShiftUpI();
face_dof = fc_dof;
}
void FiniteElementSpace::RebuildElementToDofTable()
{
delete elem_dof;
@@ -543,10 +495,9 @@ FiniteElementSpace::H2L_GlobalRestrictionMatrix (FiniteElementSpace *lfes)
{
SparseMatrix *R;
DenseMatrix loc_restr;
Array<int> l_dofs, h_dofs, l_vdofs, h_vdofs;
Array<int> l_dofs, h_dofs;
int vdim = lfes->GetVDim();
R = new SparseMatrix (vdim * lfes -> GetNDofs(), vdim * ndofs);
R = new SparseMatrix (lfes -> GetNDofs(), ndofs);
Geometry::Type cached_geom = Geometry::INVALID;
const FiniteElement *h_fe = NULL;
@@ -569,16 +520,7 @@ FiniteElementSpace::H2L_GlobalRestrictionMatrix (FiniteElementSpace *lfes)
cached_geom = geom;
}
for (int vd = 0; vd < vdim; vd++)
{
l_dofs.Copy(l_vdofs);
lfes->DofsToVDofs(vd, l_vdofs);
h_dofs.Copy(h_vdofs);
this->DofsToVDofs(vd, h_vdofs);
R -> SetSubMatrix (l_vdofs, h_vdofs, loc_restr, 1);
}
R -> SetSubMatrix (l_dofs, h_dofs, loc_restr, 1);
}
R -> Finalize();
@@ -728,6 +670,7 @@ void FiniteElementSpace::BuildConformingInterpolation() const
if (!slave_dofs.Size()) { continue; }
slave.OrientedPointMatrix(T.GetPointMat());
T.FinalizeTransformation();
fe->GetLocalInterpolation(T, I);
// make each slave DOF dependent on all master DOFs
@@ -1083,7 +1026,8 @@ void FiniteElementSpace::GetLocalRefinementMatrices(
localP.SetSize(ldof, ldof, nmat);
for (int i = 0; i < nmat; i++)
{
isotr.SetPointMat(pmats(i));
isotr.GetPointMat() = pmats(i);
isotr.FinalizeTransformation();
fe->GetLocalInterpolation(isotr, localP(i));
}
}
@@ -1152,90 +1096,46 @@ void FiniteElementSpace::RefinementOperator
Mesh* mesh = fespace->GetMesh();
const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
Array<int> dofs, vdofs, old_dofs, old_vdofs;
Array<int> dofs, old_dofs, old_vdofs;
Array<char> processed(fespace->GetVSize());
processed = 0;
int vdim = fespace->GetVDim();
int old_ndofs = width / vdim;
Vector subY, subX;
for (int k = 0; k < mesh->GetNE(); k++)
{
const Embedding &emb = rtrans.embeddings[k];
const Geometry::Type geom = mesh->GetElementBaseGeometry(k);
const DenseMatrix &lP = localP[geom](emb.matrix);
subY.SetSize(lP.Height());
fespace->GetElementDofs(k, dofs);
old_elem_dof->GetRow(emb.parent, old_dofs);
for (int vd = 0; vd < vdim; vd++)
{
dofs.Copy(vdofs);
fespace->DofsToVDofs(vd, vdofs);
old_dofs.Copy(old_vdofs);
fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
x.GetSubVector(old_vdofs, subX);
lP.Mult(subX, subY);
y.SetSubVector(vdofs, subY);
}
}
}
void FiniteElementSpace::RefinementOperator
::MultTranspose(const Vector &x, Vector &y) const
{
y = 0.0;
Mesh* mesh = fespace->GetMesh();
const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
Array<char> processed(fespace->GetVSize());
processed = 0;
Array<int> f_dofs, c_dofs, f_vdofs, c_vdofs;
int vdim = fespace->GetVDim();
int old_ndofs = width / vdim;
Vector subY, subX;
for (int k = 0; k < mesh->GetNE(); k++)
{
const Embedding &emb = rtrans.embeddings[k];
const Geometry::Type geom = mesh->GetElementBaseGeometry(k);
const DenseMatrix &lP = localP[geom](emb.matrix);
fespace->GetElementDofs(k, f_dofs);
old_elem_dof->GetRow(emb.parent, c_dofs);
subY.SetSize(lP.Width());
for (int vd = 0; vd < vdim; vd++)
{
f_dofs.Copy(f_vdofs);
fespace->DofsToVDofs(vd, f_vdofs);
c_dofs.Copy(c_vdofs);
fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
x.GetSubVector(f_vdofs, subX);
for (int p = 0; p < f_dofs.Size(); ++p)
for (int i = 0; i < dofs.Size(); i++)
{
if (processed[DecodeDof(f_dofs[p])])
double rsign, osign;
int r = fespace->DofToVDof(dofs[i], vd);
r = DecodeDof(r, rsign);
if (!processed[r])
{
subX[p] = 0.0;
double value = 0.0;
for (int j = 0; j < old_vdofs.Size(); j++)
{
int o = DecodeDof(old_vdofs[j], osign);
value += x[o] * lP(i, j) * osign;
}
y[r] = value * rsign;
processed[r] = 1;
}
}
lP.MultTranspose(subX, subY);
y.AddElementVector(c_vdofs, subY);
}
for (int p = 0; p < f_dofs.Size(); ++p)
{
processed[DecodeDof(f_dofs[p])] = 1;
}
}
}
@@ -1271,7 +1171,8 @@ FiniteElementSpace::DerefinementOperator::DerefinementOperator(
emb_tr.SetIdentityTransformation(geom);
for (int i = 0; i < pmats.SizeK(); i++)
{
emb_tr.SetPointMat(pmats(i));
emb_tr.GetPointMat() = pmats(i);
emb_tr.FinalizeTransformation();
// Get the local interpolation matrix for this refinement type
fine_fe->GetTransferMatrix(*coarse_fe, emb_tr, lP(i));
// Get the local mass matrix for this refinement type
@@ -1391,7 +1292,9 @@ void FiniteElementSpace::GetLocalDerefinementMatrices(Geometry::Type geom,
localR.SetSize(ldof, ldof, nmat);
for (int i = 0; i < nmat; i++)
{
isotr.SetPointMat(pmats(i));
isotr.GetPointMat() = pmats(i);
isotr.FinalizeTransformation();
fe->GetLocalRestriction(isotr, localR(i));
}
}
@@ -1489,7 +1392,8 @@ void FiniteElementSpace::GetLocalRefinementMatrices(
localP.SetSize(fine_fe->GetDof(), coarse_fe->GetDof(), nmat);
for (int i = 0; i < nmat; i++)
{
isotr.SetPointMat(pmats(i));
isotr.GetPointMat() = pmats(i);
isotr.FinalizeTransformation();
fine_fe->GetTransferMatrix(*coarse_fe, isotr, localP(i));
}
}
@@ -1504,7 +1408,6 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext,
this->ordering = (Ordering::Type) ordering;
elem_dof = NULL;
face_dof = NULL;
sequence = mesh->GetSequence();
Th.SetType(Operator::ANY_TYPE);
@@ -1554,8 +1457,6 @@ NURBSExtension *FiniteElementSpace::StealNURBSext()
void FiniteElementSpace::UpdateNURBS()
{
MFEM_VERIFY(NURBSext, "NURBSExt not defined.");
nvdofs = 0;
nedofs = 0;
nfdofs = 0;
@@ -1563,10 +1464,6 @@ void FiniteElementSpace::UpdateNURBS()
fdofs = NULL;
bdofs = NULL;
delete face_dof;
face_dof = NULL;
face_to_be.DeleteAll();
dynamic_cast<const NURBSFECollection *>(fec)->Reset();
ndofs = NURBSext->GetNDof();
@@ -1574,55 +1471,6 @@ void FiniteElementSpace::UpdateNURBS()
bdrElem_dof = NURBSext->GetBdrElementDofTable();
}
void FiniteElementSpace::BuildNURBSFaceToDofTable() const
{
if (face_dof) { return; }
const int dim = mesh->Dimension();
// Find bdr to face mapping
face_to_be.SetSize(GetNF());
face_to_be = -1;
for (int b = 0; b < GetNBE(); b++)
{
int f = mesh->GetBdrElementEdgeIndex(b);
face_to_be[f] = b;
}
// Loop over faces in correct order, to prevent a sort
// Sort will destroy orientation info in ordering of dofs
Array<Connection> face_dof_list;
Array<int> row;
for (int f = 0; f < GetNF(); f++)
{
int b = face_to_be[f];
if (b == -1) { continue; }
// FIXME: this assumes the boundary element and the face element have the
// same orientation.
if (dim > 1)
{
const Element *fe = mesh->GetFace(f);
const Element *be = mesh->GetBdrElement(b);
const int nv = be->GetNVertices();
const int *fv = fe->GetVertices();
const int *bv = be->GetVertices();
for (int i = 0; i < nv; i++)
{
MFEM_VERIFY(fv[i] == bv[i],
"non-matching face and boundary elements detected!");
}
}
GetBdrElementDofs(b, row);
Connection conn(f,0);
for (int i = 0; i < row.Size(); i++)
{
conn.to = row[i];
face_dof_list.Append(conn);
}
}
face_dof = new Table(GetNF(), face_dof_list);
}
void FiniteElementSpace::Construct()
{
// This method should be used only for non-NURBS spaces.
@@ -1630,7 +1478,6 @@ void FiniteElementSpace::Construct()
elem_dof = NULL;
bdrElem_dof = NULL;
face_dof = NULL;
ndofs = 0;
nedofs = nfdofs = nbdofs = 0;
@@ -1893,68 +1740,59 @@ void FiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
void FiniteElementSpace::GetFaceDofs(int i, Array<int> &dofs) const
{
// If face_dof is already built, use it.
// If it is not and we have a NURBS space, build the face_dof and use it.
if (face_dof || (NURBSext && (BuildNURBSFaceToDofTable(), true)))
{
face_dof->GetRow(i, dofs);
}
else
{
int j, k, nv, ne, nf, nd, dim = mesh->Dimension();
Array<int> V, E, Eo;
const int *ind;
int j, k, nv, ne, nf, nd, dim = mesh->Dimension();
Array<int> V, E, Eo;
const int *ind;
// for 1D, 2D and 3D faces
nv = fec->DofForGeometry(Geometry::POINT);
ne = (dim > 1) ? fec->DofForGeometry(Geometry::SEGMENT) : 0;
if (nv > 0)
// for 1D, 2D and 3D faces
nv = fec->DofForGeometry(Geometry::POINT);
ne = (dim > 1) ? fec->DofForGeometry(Geometry::SEGMENT) : 0;
if (nv > 0)
{
mesh->GetFaceVertices(i, V);
}
if (ne > 0)
{
mesh->GetFaceEdges(i, E, Eo);
}
nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0);
nd = V.Size() * nv + E.Size() * ne + nf;
dofs.SetSize(nd);
if (nv > 0)
{
for (k = 0; k < V.Size(); k++)
{
mesh->GetFaceVertices(i, V);
}
if (ne > 0)
{
mesh->GetFaceEdges(i, E, Eo);
}
nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0);
nd = V.Size() * nv + E.Size() * ne + nf;
dofs.SetSize(nd);
if (nv > 0)
{
for (k = 0; k < V.Size(); k++)
for (j = 0; j < nv; j++)
{
for (j = 0; j < nv; j++)
dofs[k*nv+j] = V[k]*nv+j;
}
}
}
nv *= V.Size();
if (ne > 0)
{
for (k = 0; k < E.Size(); k++)
{
ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[k]);
for (j = 0; j < ne; j++)
{
if (ind[j] < 0)
{
dofs[k*nv+j] = V[k]*nv+j;
dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) );
}
else
{
dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j];
}
}
}
nv *= V.Size();
if (ne > 0)
}
ne = nv + ne * E.Size();
if (nf > 0)
{
for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++)
{
for (k = 0; k < E.Size(); k++)
{
ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[k]);
for (j = 0; j < ne; j++)
{
if (ind[j] < 0)
{
dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) );
}
else
{
dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j];
}
}
}
}
ne = nv + ne * E.Size();
if (nf > 0)
{
for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++)
{
dofs[ne+k] = j;
}
dofs[ne+k] = j;
}
}
}
@@ -2083,21 +1921,14 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const
fe = fec->FiniteElementForGeometry(mesh->GetFaceBaseGeometry(i));
}
if (NURBSext)
{
// Ensure 'face_to_be' is built:
if (!face_dof) { BuildNURBSFaceToDofTable(); }
MFEM_ASSERT(face_to_be[i] >= 0,
"NURBS mesh: only boundary faces are supported!");
NURBSext->LoadBE(face_to_be[i], fe);
}
// if (NURBSext)
// NURBSext->LoadFaceElement(i, fe);
return fe;
}
const FiniteElement *FiniteElementSpace::GetEdgeElement(int i) const
{
MFEM_ASSERT(mesh->Dimension() > 1, "No edges with a mesh dimension < 2");
return fec->FiniteElementForGeometry(Geometry::SEGMENT);
}
@@ -2145,14 +1976,11 @@ void FiniteElementSpace::Destroy()
if (NURBSext)
{
if (own_ext) { delete NURBSext; }
delete face_dof;
face_to_be.DeleteAll();
}
else
{
delete elem_dof;
delete bdrElem_dof;
delete face_dof;
delete [] bdofs;
delete [] fdofs;
@@ -2739,9 +2567,7 @@ const Operator &InterpolationGridTransfer::BackwardOperator()
L2ProjectionGridTransfer::L2Projection::L2Projection(
const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_)
: Operator(fes_lor_.GetVSize(), fes_ho_.GetVSize()),
fes_ho(fes_ho_),
fes_lor(fes_lor_)
: fes_ho(fes_ho_), fes_lor(fes_lor_)
{
Mesh *mesh_ho = fes_ho.GetMesh();
MFEM_VERIFY(mesh_ho->GetNumGeometries(mesh_ho->Dimension()) <= 1,
@@ -2824,7 +2650,8 @@ L2ProjectionGridTransfer::L2Projection::L2Projection(
// Create the transformation that embeds the fine low-order element
// within the coarse high-order element in reference space
emb_tr.SetPointMat(pmats(cf_tr.embeddings[ilor].matrix));
emb_tr.GetPointMat() = pmats(cf_tr.embeddings[ilor].matrix);
emb_tr.FinalizeTransformation();
int order = fe_lor->GetOrder() + fe_ho->GetOrder() + el_tr->OrderW();
const IntegrationRule *ir = &IntRules.Get(geom, order);
+31 -83
View File
@@ -87,7 +87,6 @@ class FaceQuadratureInterpolator;
class FiniteElementSpace
{
friend class InterpolationGridTransfer;
friend class PRefinementTransferOperator;
protected:
/// The mesh that FE space lives on (not owned).
@@ -111,9 +110,7 @@ protected:
int *fdofs, *bdofs;
mutable Table *elem_dof; // if NURBS FE space, not owned; otherwise, owned.
mutable Table *bdrElem_dof; // not owned only if NURBS FE space.
mutable Table *face_dof; // owned
mutable Array<int> face_to_be; // used only with NURBS FE spaces; owned.
Table *bdrElem_dof; // used only with NURBS FE spaces; not owned.
Array<int> dof_elem_array, dof_ldof_array;
@@ -160,21 +157,8 @@ 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)
{
return (dof >= 0) ? dof : (-1 - dof);
}
/// Helper to remove encoded sign from a DOF
static inline int DecodeDof(int dof, double& sign)
{ return (dof >= 0) ? (sign = 1, dof) : (sign = -1, (-1 - dof)); }
@@ -212,11 +196,10 @@ protected:
RefinementOperator(const FiniteElementSpace *fespace,
const FiniteElementSpace *coarse_fes);
virtual void Mult(const Vector &x, Vector &y) const;
virtual void MultTranspose(const Vector &x, Vector &y) const;
virtual ~RefinementOperator();
};
/// Derefinement operator, used by the friend class InterpolationGridTransfer.
// Derefinement operator, used by the friend class InterpolationGridTransfer.
class DerefinementOperator : public Operator
{
const FiniteElementSpace *fine_fes; // Not owned.
@@ -235,12 +218,12 @@ protected:
virtual ~DerefinementOperator();
};
/** This method makes the same assumptions as the method:
void GetLocalRefinementMatrices(
const FiniteElementSpace &coarse_fes, Geometry::Type geom,
DenseTensor &localP) const
which is defined below. It also assumes that the coarse fes and this have
the same vector dimension, vdim. */
// This method makes the same assumptions as the method:
// void GetLocalRefinementMatrices(
// const FiniteElementSpace &coarse_fes, Geometry::Type geom,
// DenseTensor &localP) const
// which is defined below. It also assumes that the coarse fes and this have
// the same vector dimension, vdim.
SparseMatrix *RefinementMatrix_main(const int coarse_ndofs,
const Table &coarse_elem_dof,
const DenseTensor localP[]) const;
@@ -258,13 +241,11 @@ protected:
/// Calculate GridFunction restriction matrix after mesh derefinement.
SparseMatrix* DerefinementMatrix(int old_ndofs, const Table* old_elem_dof);
/** @brief Return in @a localP the local refinement matrices that map
between fespaces after mesh refinement. */
/** This method assumes that this->mesh is a refinement of coarse_fes->mesh
and that the CoarseFineTransformations of this->mesh are set accordingly.
Another assumption is that the FEs of this use the same MapType as the FEs
of coarse_fes. Finally, it assumes that the spaces this and coarse_fes are
NOT variable-order spaces. */
// This method assumes that this->mesh is a refinement of coarse_fes->mesh
// and that the CoarseFineTransformations of this->mesh are set accordingly.
// Another assumption is that the FEs of this use the same MapType as the FEs
// of coarse_fes. Finally, it assumes that the spaces this and coarse_fes are
// NOT variable-order spaces.
void GetLocalRefinementMatrices(const FiniteElementSpace &coarse_fes,
Geometry::Type geom,
DenseTensor &localP) const;
@@ -479,11 +460,11 @@ public:
/// Returns indexes of degrees of freedom for i'th boundary element.
virtual void GetBdrElementDofs(int i, Array<int> &dofs) const;
/** @brief eturns the indexes of the degrees of freedom for i'th face
/** Returns the indexes of the degrees of freedom for i'th face
including the dofs for the edges and the vertices of the face. */
virtual void GetFaceDofs(int i, Array<int> &dofs) const;
/** @brief Returns the indexes of the degrees of freedom for i'th edge
/** Returns the indexes of the degrees of freedom for i'th edge
including the dofs for the vertices of the edge. */
void GetEdgeDofs(int i, Array<int> &dofs) const;
@@ -538,59 +519,28 @@ public:
is preserved. */
void ReorderElementToDofTable();
/** @brief Return a reference to the internal Table that stores the lists of
scalar dofs, for each mesh element, as returned by GetElementDofs(). */
const Table &GetElementToDofTable() const { return *elem_dof; }
/** @brief Return a reference to the internal Table that stores the lists of
scalar dofs, for each boundary mesh element, as returned by
GetBdrElementDofs(). */
const Table &GetBdrElementToDofTable() const
{ if (!bdrElem_dof) { BuildBdrElementToDofTable(); } return *bdrElem_dof; }
/** @brief Return a reference to the internal Table that stores the lists of
scalar dofs, for each face in the mesh, as returned by GetFaceDofs(). In
this context, "face" refers to a (dim-1)-dimensional mesh entity. */
/** @note In the case of a NURBS space, the rows corresponding to interior
faces will be empty. */
const Table &GetFaceToDofTable() const
{ if (!face_dof) { BuildFaceToDofTable(); } return *face_dof; }
/** @brief Initialize internal data that enables the use of the methods
GetElementForDof() and GetLocalDofForDof(). */
void BuildDofToArrays();
/// Return the index of the first element that contains dof @a i.
/** This method can be called only after setup is performed using the method
BuildDofToArrays(). */
const Table &GetElementToDofTable() const { return *elem_dof; }
const Table &GetBdrElementToDofTable() const { return *bdrElem_dof; }
int GetElementForDof(int i) const { return dof_elem_array[i]; }
/// Return the local dof index in the first element that contains dof @a i.
/** This method can be called only after setup is performed using the method
BuildDofToArrays(). */
int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; }
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th element in the mesh object. */
/// Returns pointer to the FiniteElement associated with i'th element.
const FiniteElement *GetFE(int i) const;
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th boundary face in the mesh object. */
/// Returns pointer to the FiniteElement for the i'th boundary element.
const FiniteElement *GetBE(int i) const;
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th face in the mesh object. Faces in this case refer
to the MESHDIM-1 primitive so in 2D they are segments and in 1D they are
points.*/
const FiniteElement *GetFaceElement(int i) const;
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th edge in the mesh object. */
const FiniteElement *GetEdgeElement(int i) const;
/// Return the trace element from element 'i' to the given 'geom_type'
const FiniteElement *GetTraceElement(int i, Geometry::Type geom_type) const;
/** @brief Mark degrees of freedom associated with boundary elements with
/** Mark degrees of freedom associated with boundary elements with
the specified boundary attributes (marked in 'bdr_attr_is_ess').
For spaces with 'vdim' > 1, the 'component' parameter can be used
to restricts the marked vDOFs to the specified component. */
@@ -598,7 +548,7 @@ public:
Array<int> &ess_vdofs,
int component = -1) const;
/** @brief Get a list of essential true dofs, ess_tdof_list, corresponding to the
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
boundary attributes marked in the array bdr_attr_is_ess.
For spaces with 'vdim' > 1, the 'component' parameter can be used
to restricts the marked tDOFs to the specified component. */
@@ -609,19 +559,19 @@ public:
/// Convert a Boolean marker array to a list containing all marked indices.
static void MarkerToList(const Array<int> &marker, Array<int> &list);
/** @brief Convert an array of indices (list) to a Boolean marker array where all
/** Convert an array of indices (list) to a Boolean marker array where all
indices in the list are marked with the given value and the rest are set
to zero. */
static void ListToMarker(const Array<int> &list, int marker_size,
Array<int> &marker, int mark_val = -1);
/** @brief For a partially conforming FE space, convert a marker array (nonzero
/** For a partially conforming FE space, convert a marker array (nonzero
entries are true) on the partially conforming dofs to a marker array on
the conforming dofs. A conforming dofs is marked iff at least one of its
dependent dofs is marked. */
void ConvertToConformingVDofs(const Array<int> &dofs, Array<int> &cdofs);
/** @brief For a partially conforming FE space, convert a marker array (nonzero
/** For a partially conforming FE space, convert a marker array (nonzero
entries are true) on the conforming dofs to a marker array on the
(partially conforming) dofs. A dof is marked iff it depends on a marked
conforming dofs, where dependency is defined by the ConformingRestriction
@@ -629,15 +579,15 @@ public:
conforming dof. */
void ConvertFromConformingVDofs(const Array<int> &cdofs, Array<int> &dofs);
/** @brief Generate the global restriction matrix from a discontinuous
/** Generate the global restriction matrix from a discontinuous
FE space to the continuous FE space of the same polynomial degree. */
SparseMatrix *D2C_GlobalRestrictionMatrix(FiniteElementSpace *cfes);
/** @brief Generate the global restriction matrix from a discontinuous
/** Generate the global restriction matrix from a discontinuous
FE space to the piecewise constant FE space. */
SparseMatrix *D2Const_GlobalRestrictionMatrix(FiniteElementSpace *cfes);
/** @brief Construct the restriction matrix from the FE space given by
/** Construct the restriction matrix from the FE space given by
(*this) to the lower degree FE space given by (*lfes) which
is defined on the same mesh. */
SparseMatrix *H2L_GlobalRestrictionMatrix(FiniteElementSpace *lfes);
@@ -674,7 +624,7 @@ public:
virtual void GetTrueTransferOperator(const FiniteElementSpace &coarse_fes,
OperatorHandle &T) const;
/** @brief Reflect changes in the mesh: update number of DOFs, etc. Also, calculate
/** Reflect changes in the mesh: update number of DOFs, etc. Also, calculate
GridFunction transformation operator (unless want_transform is false).
Safe to call multiple times, does nothing if space already up to date. */
virtual void Update(bool want_transform = true);
@@ -712,7 +662,6 @@ public:
return dynamic_cast<const L2_FECollection*>(fec) != NULL;
}
/// Save finite element space to output stream @a out.
void Save(std::ostream &out) const;
/** @brief Read a FiniteElementSpace from a stream. The returned
@@ -950,8 +899,7 @@ protected:
const L2Projection &l2proj;
public:
L2Prolongation(const L2Projection &l2proj_)
: Operator(l2proj_.Width(), l2proj_.Height()), l2proj(l2proj_) { }
L2Prolongation(const L2Projection &l2proj_) : l2proj(l2proj_) { }
void Mult(const Vector &x, Vector &y) const
{
l2proj.Prolongate(x, y);
-189
View File
@@ -1,189 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "fespacehierarchy.hpp"
#include "transfer.hpp"
namespace mfem
{
FiniteElementSpaceHierarchy::FiniteElementSpaceHierarchy(Mesh* mesh,
FiniteElementSpace* fespace,
bool ownM, bool ownFES)
{
meshes.Append(mesh);
fespaces.Append(fespace);
ownedMeshes.Append(ownM);
ownedFES.Append(ownFES);
}
FiniteElementSpaceHierarchy::~FiniteElementSpaceHierarchy()
{
for (int i = 0; i < meshes.Size(); ++i)
{
if (ownedFES[i])
{
delete fespaces[i];
}
if (ownedMeshes[i])
{
delete meshes[i];
}
}
for (int i = 0; i < prolongations.Size(); ++i)
{
if (ownedProlongations[i])
{
delete prolongations[i];
}
}
fespaces.DeleteAll();
meshes.DeleteAll();
prolongations.DeleteAll();
}
int FiniteElementSpaceHierarchy::GetNumLevels() const { return meshes.Size(); }
int FiniteElementSpaceHierarchy::GetFinestLevelIndex() const { return GetNumLevels() - 1; }
void FiniteElementSpaceHierarchy::AddLevel(Mesh* mesh,
FiniteElementSpace* fespace,
Operator* prolongation,
bool ownM, bool ownFES,
bool ownP)
{
meshes.Append(mesh);
fespaces.Append(fespace);
prolongations.Append(prolongation);
ownedMeshes.Append(ownM);
ownedFES.Append(ownFES);
ownedProlongations.Append(ownP);
}
void FiniteElementSpaceHierarchy::AddUniformlyRefinedLevel(int dim,
int ordering)
{
MFEM_VERIFY(GetNumLevels() > 0, "There is no level which can be refined");
Mesh* mesh = new Mesh(*GetFinestFESpace().GetMesh());
mesh->UniformRefinement();
FiniteElementSpace& coarseFEspace = GetFinestFESpace();
FiniteElementSpace* fineFEspace =
new FiniteElementSpace(mesh, coarseFEspace.FEColl(), dim, ordering);
Operator* P = new TransferOperator(coarseFEspace, *fineFEspace);
AddLevel(mesh, fineFEspace, P, true, true, true);
}
void FiniteElementSpaceHierarchy::AddOrderRefinedLevel(FiniteElementCollection*
fec, int dim,
int ordering)
{
MFEM_VERIFY(GetNumLevels() > 0, "There is no level which can be refined");
Mesh* mesh = GetFinestFESpace().GetMesh();
FiniteElementSpace* newFEspace =
new FiniteElementSpace(mesh, fec, dim, ordering);
Operator* P = new TransferOperator(GetFinestFESpace(), *newFEspace);
AddLevel(mesh, newFEspace, P, false, true, true);
}
const FiniteElementSpace& FiniteElementSpaceHierarchy::GetFESpaceAtLevel(
int level) const
{
MFEM_ASSERT(level < fespaces.Size(),
"FE space at given level does not exist.");
return *fespaces[level];
}
FiniteElementSpace& FiniteElementSpaceHierarchy::GetFESpaceAtLevel(int level)
{
MFEM_ASSERT(level < fespaces.Size(),
"FE space at given level does not exist.");
return *fespaces[level];
}
const FiniteElementSpace& FiniteElementSpaceHierarchy::GetFinestFESpace() const
{
return GetFESpaceAtLevel(GetFinestLevelIndex());
}
FiniteElementSpace& FiniteElementSpaceHierarchy::GetFinestFESpace()
{
return GetFESpaceAtLevel(GetFinestLevelIndex());
}
Operator* FiniteElementSpaceHierarchy::GetProlongationAtLevel(int level) const
{
MFEM_ASSERT(level < prolongations.Size(),
"Prolongation at given level does not exist.");
return prolongations[level];
}
#ifdef MFEM_USE_MPI
ParFiniteElementSpaceHierarchy::ParFiniteElementSpaceHierarchy(ParMesh* mesh,
ParFiniteElementSpace* fespace,
bool ownM,
bool ownFES)
: FiniteElementSpaceHierarchy(mesh, fespace, ownM, ownFES)
{
}
void ParFiniteElementSpaceHierarchy::AddUniformlyRefinedLevel(int dim,
int ordering)
{
ParMesh* mesh = new ParMesh(*GetFinestFESpace().GetParMesh());
mesh->UniformRefinement();
ParFiniteElementSpace& coarseFEspace = GetFinestFESpace();
ParFiniteElementSpace* fineFEspace =
new ParFiniteElementSpace(mesh, coarseFEspace.FEColl(), dim, ordering);
Operator* P = new TrueTransferOperator(coarseFEspace, *fineFEspace);
AddLevel(mesh, fineFEspace, P, true, true, true);
}
void ParFiniteElementSpaceHierarchy::AddOrderRefinedLevel(
FiniteElementCollection* fec,
int dim, int ordering)
{
ParMesh* mesh = GetFinestFESpace().GetParMesh();
ParFiniteElementSpace* newFEspace =
new ParFiniteElementSpace(mesh, fec, dim, ordering);
Operator* P = new TrueTransferOperator(GetFinestFESpace(), *newFEspace);
AddLevel(mesh, newFEspace, P, false, true, true);
}
const ParFiniteElementSpace&
ParFiniteElementSpaceHierarchy::GetFESpaceAtLevel(int level) const
{
return static_cast<const ParFiniteElementSpace&>(
FiniteElementSpaceHierarchy::GetFESpaceAtLevel(level));
}
ParFiniteElementSpace& ParFiniteElementSpaceHierarchy::GetFESpaceAtLevel(
int level)
{
return static_cast<ParFiniteElementSpace&>(
FiniteElementSpaceHierarchy::GetFESpaceAtLevel(level));
}
const ParFiniteElementSpace& ParFiniteElementSpaceHierarchy::GetFinestFESpace()
const
{
return GetFESpaceAtLevel(GetFinestLevelIndex());
}
ParFiniteElementSpace& ParFiniteElementSpaceHierarchy::GetFinestFESpace()
{
return GetFESpaceAtLevel(GetFinestLevelIndex());
}
#endif
} // namespace mfem
-123
View File
@@ -1,123 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_FESPACEHIERARCHY
#define MFEM_FESPACEHIERARCHY
#include "fespace.hpp"
#ifdef MFEM_USE_MPI
#include "pfespace.hpp"
#endif
namespace mfem
{
/// Class bundling a hierarchy finite element spaces together with the
/// corresponding prolongation operators
class FiniteElementSpaceHierarchy
{
protected:
Array<Mesh*> meshes;
Array<FiniteElementSpace*> fespaces;
Array<Operator*> prolongations;
Array<bool> ownedMeshes;
Array<bool> ownedFES;
Array<bool> ownedProlongations;
public:
/// @brief Constructs a space hierarchy with the given mesh and space on the
/// coarsest level.
/** The ownership of the mesh and space may be transferred to the
FiniteElementSpaceHierarchy by setting the according boolean variables. */
FiniteElementSpaceHierarchy(Mesh* mesh, FiniteElementSpace* fespace, bool ownM,
bool ownFES);
/// Destructor deleting all meshes and spaces that are owned
virtual ~FiniteElementSpaceHierarchy();
/// Returns the number of levels in the hierarchy
int GetNumLevels() const;
/// Returns the index of the finest level
int GetFinestLevelIndex() const;
/// Adds one level to the hierarchy
void AddLevel(Mesh* mesh, FiniteElementSpace* fespace, Operator* prolongation,
bool ownM, bool ownFES, bool ownP);
/// @brief Adds one level to the hierarchy by uniformly refining the mesh on the
/// previous level
virtual void AddUniformlyRefinedLevel(int dim = 1,
int ordering = Ordering::byVDIM);
/// @brief Adds one level to the hierarchy by using a different finite element
/// order defined through FiniteElementCollection
virtual void AddOrderRefinedLevel(FiniteElementCollection* fec, int dim = 1,
int ordering = Ordering::byVDIM);
/// Returns the finite element space at the given level
virtual const FiniteElementSpace& GetFESpaceAtLevel(int level) const;
/// Returns the finite element space at the given level
virtual FiniteElementSpace& GetFESpaceAtLevel(int level);
/// Returns the finite element space at the finest level
virtual const FiniteElementSpace& GetFinestFESpace() const;
/// Returns the finite element space at the finest level
virtual FiniteElementSpace& GetFinestFESpace();
/// @brief Returns the prolongation operator from the finite element space at
/// level to the finite element space at level + 1
Operator* GetProlongationAtLevel(int level) const;
};
#ifdef MFEM_USE_MPI
class ParFiniteElementSpaceHierarchy : public FiniteElementSpaceHierarchy
{
public:
/// @brief Constructs a parallel space hierarchy with the given mesh and spaces
/// on level zero.
/** The ownership of the mesh and space may be transferred to the
ParFiniteElementSpaceHierarchy by setting the according boolean variables. */
ParFiniteElementSpaceHierarchy(ParMesh* mesh, ParFiniteElementSpace* fespace,
bool ownM,
bool ownFES);
/// @brief Adds one level to the hierarchy by uniformly refining the mesh on the
/// previous level
void AddUniformlyRefinedLevel(int dim = 1,
int ordering = Ordering::byVDIM) override;
/// @brief Adds one level to the hierarchy by using a different finite element
/// order defined through FiniteElementCollection
void AddOrderRefinedLevel(FiniteElementCollection* fec, int dim = 1,
int ordering = Ordering::byVDIM) override;
/// Returns the finite element space at the given level
const ParFiniteElementSpace& GetFESpaceAtLevel(int level) const override;
/// Returns the finite element space at the given level
ParFiniteElementSpace& GetFESpaceAtLevel(int level) override;
/// Returns the finite element space at the finest level
const ParFiniteElementSpace& GetFinestFESpace() const override;
/// Returns the finite element space at the finest level
ParFiniteElementSpace& GetFinestFESpace() override;
};
#endif
} // namespace mfem
#endif
+3
View File
@@ -188,6 +188,7 @@ Geometry::Geometry()
IsoparametricTransformation tri_T;
tri_T.SetFE(&TriangleFE);
GetPerfPointMat (TRIANGLE, tri_T.GetPointMat());
tri_T.FinalizeTransformation();
tri_T.SetIntPoint(&GeomCenter[TRIANGLE]);
*GeomToPerfGeomJac[TRIANGLE] = tri_T.Jacobian();
CalcInverse(tri_T.Jacobian(), *PerfGeomToGeomJac[TRIANGLE]);
@@ -197,6 +198,7 @@ Geometry::Geometry()
IsoparametricTransformation tet_T;
tet_T.SetFE(&TetrahedronFE);
GetPerfPointMat (TETRAHEDRON, tet_T.GetPointMat());
tet_T.FinalizeTransformation();
tet_T.SetIntPoint(&GeomCenter[TETRAHEDRON]);
*GeomToPerfGeomJac[TETRAHEDRON] = tet_T.Jacobian();
CalcInverse(tet_T.Jacobian(), *PerfGeomToGeomJac[TETRAHEDRON]);
@@ -206,6 +208,7 @@ Geometry::Geometry()
IsoparametricTransformation pri_T;
pri_T.SetFE(&WedgeFE);
GetPerfPointMat (PRISM, pri_T.GetPointMat());
pri_T.FinalizeTransformation();
pri_T.SetIntPoint(&GeomCenter[PRISM]);
*GeomToPerfGeomJac[PRISM] = pri_T.Jacobian();
CalcInverse(pri_T.Jacobian(), *PerfGeomToGeomJac[PRISM]);
+31 -383
View File
@@ -236,6 +236,7 @@ void GridFunction::MakeTRef(FiniteElementSpace *f, Vector &tv, int tv_offset)
}
}
void GridFunction::SumFluxAndCount(BilinearFormIntegrator &blfi,
GridFunction &flux,
Array<int>& count,
@@ -616,354 +617,17 @@ int GridFunction::GetFaceValues(int i, int side, const IntegrationRule &ir,
return dir;
}
void GridFunction::GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
Tr->Transform(ir, tr);
GetVectorValues(*Tr, ir, vals);
}
void be_to_bfe(Geometry::Type geom, int o, const IntegrationPoint &ip,
IntegrationPoint &fip)
{
if (geom == Geometry::TRIANGLE)
{
if (o == 2)
{
fip.x = 1.0 - ip.x - ip.y;
fip.y = ip.x;
}
else if (o == 4)
{
fip.x = ip.y;
fip.y = 1.0 - ip.x - ip.y;
}
else
{
fip.x = ip.x;
fip.y = ip.y;
}
fip.z = ip.z;
}
else
{
if (o == 2)
{
fip.x = ip.y;
fip.y = 1.0 - ip.x;
}
else if (o == 4)
{
fip.x = 1.0 - ip.x;
fip.y = 1.0 - ip.y;
}
else if (o == 6)
{
fip.x = 1.0 - ip.y;
fip.y = ip.x;
}
else
{
fip.x = ip.x;
fip.y = ip.y;
}
fip.z = ip.z;
}
fip.weight = ip.weight;
fip.index = ip.index;
}
double GridFunction::GetValue(ElementTransformation &T,
const IntegrationPoint &ip,
int comp, Vector *tr) const
{
if (tr)
{
T.SetIntPoint(&ip);
T.Transform(ip, *tr);
}
const FiniteElement * fe = NULL;
Array<int> dofs;
switch (T.ElementType)
{
case ElementTransformation::ELEMENT:
fe = fes->GetFE(T.ElementNo);
fes->GetElementDofs(T.ElementNo, dofs);
break;
case ElementTransformation::EDGE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetEdgeElement(T.ElementNo);
fes->GetEdgeDofs(T.ElementNo, dofs);
}
else
{
MFEM_ABORT("GridFunction::GetValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh edges.");
return NAN;
}
break;
case ElementTransformation::FACE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetFaceElement(T.ElementNo);
fes->GetFaceDofs(T.ElementNo, dofs);
}
else
{
MFEM_ABORT("GridFunction::GetValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh faces.");
return NAN;
}
break;
case ElementTransformation::BDR_ELEMENT:
{
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
// This is a continuous field so we can evaluate it on the boundary.
fe = fes->GetBE(T.ElementNo);
fes->GetBdrElementDofs(T.ElementNo, dofs);
}
else
{
// This is a discontinuous field which cannot be evaluated on the
// boundary so we'll evaluate it in the neighboring element.
FaceElementTransformations * FET =
fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo);
// Boundary elements and Boundary Faces may have different
// orientations so adjust the integration point if necessary.
int o = 0;
if (fes->GetMesh()->Dimension() == 3)
{
int f;
fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
}
IntegrationPoint fip;
be_to_bfe(FET->GetGeometryType(), o, ip, fip);
FET->SetIntPoint(&fip);
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetValue(T1, T1.GetIntPoint(), comp);
}
break;
}
case ElementTransformation::BDR_FACE:
{
FaceElementTransformations * FET =
dynamic_cast<FaceElementTransformations *>(&T);
// Evaluate in neighboring element for both continuous and
// discontinuous fields.
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetValue(T1, T1.GetIntPoint(), comp);
}
default:
{
MFEM_ABORT("GridFunction::GetValue: Unsupported element type \""
<< T.ElementType << "\"");
return NAN;
}
}
fes->DofsToVDofs(comp-1, dofs);
Vector DofVal(dofs.Size()), LocVec;
if (fe->GetMapType() == FiniteElement::VALUE)
{
fe->CalcShape(ip, DofVal);
}
else
{
fe->CalcPhysShape(T, DofVal);
}
GetSubVector(dofs, LocVec);
return (DofVal * LocVec);
}
void GridFunction::GetValues(ElementTransformation &T,
const IntegrationRule &ir,
Vector &vals, int comp,
DenseMatrix *tr) const
{
if (tr)
{
T.Transform(ir, *tr);
}
int nip = ir.GetNPoints();
vals.SetSize(nip);
for (int j = 0; j < nip; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
T.SetIntPoint(&ip);
vals[j] = GetValue(T, ip, comp);
}
}
void GridFunction::GetVectorValue(ElementTransformation &T,
const IntegrationPoint &ip,
Vector &val, Vector *tr) const
{
if (tr)
{
T.SetIntPoint(&ip);
T.Transform(ip, *tr);
}
Array<int> vdofs;
const FiniteElement *fe = NULL;
switch (T.ElementType)
{
case ElementTransformation::ELEMENT:
fes->GetElementVDofs(T.ElementNo, vdofs);
fe = fes->GetFE(T.ElementNo);
break;
case ElementTransformation::EDGE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetEdgeElement(T.ElementNo);
fes->GetEdgeVDofs(T.ElementNo, vdofs);
}
else
{
MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh edges.");
return;
}
break;
case ElementTransformation::FACE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetFaceElement(T.ElementNo);
fes->GetFaceVDofs(T.ElementNo, vdofs);
}
else
{
MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh faces.");
return;
}
break;
case ElementTransformation::BDR_ELEMENT:
{
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
// This is a continuous field so we can evaluate it on the boundary.
fes->GetBdrElementVDofs(T.ElementNo, vdofs);
fe = fes->GetBE(T.ElementNo);
}
else
{
// This is a discontinuous vector field which cannot be evaluated on
// the boundary so we'll evaluate it in the neighboring element.
FaceElementTransformations * FET =
fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo);
// Boundary elements and Boundary Faces may have different
// orientations so adjust the integration point if necessary.
int o = 0;
if (fes->GetMesh()->Dimension() == 3)
{
int f;
fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
}
IntegrationPoint fip;
be_to_bfe(FET->GetGeometryType(), o, ip, fip);
FET->SetIntPoint(&fip);
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetVectorValue(T1, T1.GetIntPoint(), val);
}
break;
}
case ElementTransformation::BDR_FACE:
{
FaceElementTransformations * FET =
dynamic_cast<FaceElementTransformations *>(&T);
// Evaluate in neighboring element for both continuous and
// discontinuous fields.
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetVectorValue(T1, T1.GetIntPoint(), val);
}
default:
{
MFEM_ABORT("GridFunction::GetVectorValue: Unsupported element type \""
<< T.ElementType << "\"");
if (val.Size() > 0) { val = NAN; }
return;
}
}
int dof = fe->GetDof();
Vector loc_data;
GetSubVector(vdofs, loc_data);
if (fe->GetRangeType() == FiniteElement::SCALAR)
{
Vector shape(dof);
if (fe->GetMapType() == FiniteElement::VALUE)
{
fe->CalcShape(ip, shape);
}
else
{
fe->CalcPhysShape(T, shape);
}
int vdim = fes->GetVDim();
val.SetSize(vdim);
for (int k = 0; k < vdim; k++)
{
val(k) = shape * ((const double *)loc_data + dof * k);
}
}
else
{
int spaceDim = fes->GetMesh()->SpaceDimension();
DenseMatrix vshape(dof, spaceDim);
fe->CalcVShape(T, vshape);
val.SetSize(spaceDim);
vshape.MultTranspose(loc_data, val);
}
}
void GridFunction::GetVectorValues(ElementTransformation &T,
const IntegrationRule &ir,
DenseMatrix &vals,
DenseMatrix *tr) const
DenseMatrix &vals) const
{
if (tr)
{
T.Transform(ir, *tr);
}
const FiniteElement *FElem = fes->GetFE(T.ElementNo);
int dof = FElem->GetDof();
Array<int> vdofs;
fes->GetElementVDofs(T.ElementNo, vdofs);
Vector loc_data;
GetSubVector(vdofs, loc_data);
int nip = ir.GetNPoints();
if (FElem->GetRangeType() == FiniteElement::SCALAR)
{
MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
@@ -975,7 +639,6 @@ void GridFunction::GetVectorValues(ElementTransformation &T,
{
const IntegrationPoint &ip = ir.IntPoint(j);
FElem->CalcShape(ip, shape);
for (int k = 0; k < vdim; k++)
{
vals(k,j) = shape * ((const double *)loc_data + dof * k);
@@ -986,22 +649,28 @@ void GridFunction::GetVectorValues(ElementTransformation &T,
{
int spaceDim = fes->GetMesh()->SpaceDimension();
DenseMatrix vshape(dof, spaceDim);
vals.SetSize(spaceDim, nip);
Vector val_j;
for (int j = 0; j < nip; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
T.SetIntPoint(&ip);
FElem->CalcVShape(T, vshape);
vals.GetColumnReference(j, val_j);
vshape.MultTranspose(loc_data, val_j);
}
}
}
void GridFunction::GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
Tr->Transform(ir, tr);
GetVectorValues(*Tr, ir, vals);
}
int GridFunction::GetFaceVectorValues(
int i, int side, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const
@@ -1031,15 +700,15 @@ int GridFunction::GetFaceVectorValues(
}
if (di == 0)
{
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 5);
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 4);
Transf->Loc1.Transform(ir, eir);
GetVectorValues(*Transf->Elem1, eir, vals, &tr);
GetVectorValues(Transf->Elem1No, eir, vals, tr);
}
else
{
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 10);
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 8);
Transf->Loc2.Transform(ir, eir);
GetVectorValues(*Transf->Elem2, eir, vals, &tr);
GetVectorValues(Transf->Elem2No, eir, vals, tr);
}
return di;
@@ -2047,8 +1716,6 @@ void GridFunction::ProjectCoefficient(
ElementTransformation *T = NULL;
const FiniteElement *fe = NULL;
fes->BuildDofToArrays(); // ensures GetElementForDof(), GetLocalDofForDof() initialized.
for (int i = 0; i < dofs.Size(); i++)
{
int dof = dofs[i], j = fes->GetElementForDof(dof);
@@ -2090,8 +1757,6 @@ void GridFunction::ProjectCoefficient(
Vector val;
fes->BuildDofToArrays(); // ensures GetElementForDof(), GetLocalDofForDof() initialized.
for (int i = 0; i < dofs.Size(); i++)
{
int dof = dofs[i], j = fes->GetElementForDof(dof);
@@ -2344,7 +2009,7 @@ double GridFunction::ComputeL2Error(
fdof = fe->GetDof();
transf = fes->GetElementTransformation(i);
shape.SetSize(fdof);
intorder = 2*fe->GetOrder() + 3; // <----------
intorder = 2*fe->GetOrder() + 1; // <----------
const IntegrationRule *ir;
if (irs)
{
@@ -2399,7 +2064,7 @@ double GridFunction::ComputeL2Error(
{
if (elems != NULL && (*elems)[i] == 0) { continue; }
fe = fes->GetFE(i);
int intorder = 2*fe->GetOrder() + 3; // <----------
int intorder = 2*fe->GetOrder() + 1; // <----------
const IntegrationRule *ir;
if (irs)
{
@@ -2503,7 +2168,7 @@ double GridFunction::ComputeH1Error(
}
intorder = 2 * intorder; // <-------------
const IntegrationRule &ir =
IntRules.Get(face_elem_transf->GetGeometryType(), intorder);
IntRules.Get(face_elem_transf->FaceGeom, intorder);
err_val.SetSize(ir.GetNPoints());
ell_coeff_val.SetSize(ir.GetNPoints());
// side 1
@@ -2560,7 +2225,7 @@ double GridFunction::ComputeH1Error(
}
}
face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
transf = face_elem_transf;
transf = face_elem_transf->Face;
for (j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
@@ -2594,7 +2259,7 @@ double GridFunction::ComputeMaxError(
fdof = fe->GetDof();
transf = fes->GetElementTransformation(i);
shape.SetSize(fdof);
intorder = 2*fe->GetOrder() + 3; // <----------
intorder = 2*fe->GetOrder() + 1; // <----------
const IntegrationRule *ir;
if (irs)
{
@@ -2760,7 +2425,7 @@ double GridFunction::ComputeLpError(const double p, Coefficient &exsol,
}
else
{
int intorder = 2*fe->GetOrder() + 3; // <----------
int intorder = 2*fe->GetOrder() + 1; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
GetValues(i, *ir, vals);
@@ -2807,13 +2472,10 @@ double GridFunction::ComputeLpError(const double p, Coefficient &exsol,
}
void GridFunction::ComputeElementLpErrors(const double p, Coefficient &exsol,
Vector &error,
GridFunction &error,
Coefficient *weight,
const IntegrationRule *irs[]) const
{
MFEM_ASSERT(error.Size() == fes->GetNE(),
"Incorrect size for result vector");
error = 0.0;
const FiniteElement *fe;
ElementTransformation *T;
@@ -2829,7 +2491,7 @@ void GridFunction::ComputeElementLpErrors(const double p, Coefficient &exsol,
}
else
{
int intorder = 2*fe->GetOrder() + 3; // <----------
int intorder = 2*fe->GetOrder() + 1; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
GetValues(i, *ir, vals);
@@ -2893,7 +2555,7 @@ double GridFunction::ComputeLpError(const double p, VectorCoefficient &exsol,
}
else
{
int intorder = 2*fe->GetOrder() + 3; // <----------
int intorder = 2*fe->GetOrder() + 1; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
T = fes->GetElementTransformation(i);
@@ -2965,14 +2627,11 @@ double GridFunction::ComputeLpError(const double p, VectorCoefficient &exsol,
void GridFunction::ComputeElementLpErrors(const double p,
VectorCoefficient &exsol,
Vector &error,
GridFunction &error,
Coefficient *weight,
VectorCoefficient *v_weight,
const IntegrationRule *irs[]) const
{
MFEM_ASSERT(error.Size() == fes->GetNE(),
"Incorrect size for result vector");
error = 0.0;
const FiniteElement *fe;
ElementTransformation *T;
@@ -2989,7 +2648,7 @@ void GridFunction::ComputeElementLpErrors(const double p,
}
else
{
int intorder = 2*fe->GetOrder() + 3; // <----------
int intorder = 2*fe->GetOrder() + 1; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
T = fes->GetElementTransformation(i);
@@ -2999,15 +2658,15 @@ void GridFunction::ComputeElementLpErrors(const double p,
loc_errs.SetSize(vals.Width());
if (!v_weight)
{
// compute the lengths of the errors at the integration points thus the
// vector norm is rotationally invariant
// compute the lengths of the errors at the integration points
// thus the vector norm is rotationally invariant
vals.Norm2(loc_errs);
}
else
{
v_weight->Eval(exact_vals, *T, *ir);
// column-wise dot product of the vector error (in vals) and the vector
// weight (in exact_vals)
// column-wise dot product of the vector error (in vals) and the
// vector weight (in exact_vals)
for (int j = 0; j < vals.Width(); j++)
{
double err = 0.0;
@@ -3094,15 +2753,6 @@ void GridFunction::Save(std::ostream &out) const
out.flush();
}
#ifdef MFEM_USE_ADIOS2
void GridFunction::Save(adios2stream &out,
const std::string& variable_name,
const adios2stream::data_type type) const
{
out.Save(*this, variable_name, type);
}
#endif
void GridFunction::SaveVTK(std::ostream &out, const std::string &field_name,
int ref)
{
@@ -3139,9 +2789,7 @@ void GridFunction::SaveVTK(std::ostream &out, const std::string &field_name,
RefG = GlobGeometryRefiner.Refine(
mesh->GetElementBaseGeometry(i), ref, 1);
// GetVectorValues(i, RefG->RefPts, vval, pmat);
ElementTransformation * T = mesh->GetElementTransformation(i);
GetVectorValues(*T, RefG->RefPts, vval, &pmat);
GetVectorValues(i, RefG->RefPts, vval, pmat);
for (int j = 0; j < vval.Width(); j++)
{
+28 -171
View File
@@ -16,9 +16,6 @@
#include "fespace.hpp"
#include "coefficient.hpp"
#include "bilininteg.hpp"
#ifdef MFEM_USE_ADIOS2
#include "../general/adios2stream.hpp"
#endif
#include <limits>
#include <ostream>
#include <string>
@@ -144,133 +141,17 @@ public:
/// Returns the values in the vertices of i'th element for dimension vdim.
void GetNodalValues(int i, Array<double> &nval, int vdim = 1) const;
/** @name Element index Get Value Methods
These methods take an element index and return the interpolated value of
the field at a given reference point within the element.
@warning These methods retrieve and use the ElementTransformation object
from the mfem::Mesh. This can alter the state of the element
transformation object and can also lead to unexpected results when the
ElementTransformation object is already in use such as when these methods
are called from within an integration loop. Consider using
GetValue(ElementTransformation &T, ...) instead.
*/
///@{
/** Return a scalar value from within the given element. */
virtual double GetValue(int i, const IntegrationPoint &ip,
int vdim = 1) const;
/** Return a vector value from within the given element. */
void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const;
///@}
/** @name Element Index Get Values Methods
These are convenience methods for repeatedly calling GetValue for
multiple points within a given element. The GetValues methods are
optimized and should perform better than repeatedly calling GetValue. The
GetVectorValues method simply calls GetVectorValue repeatedly.
@warning These methods retrieve and use the ElementTransformation object
from the mfem::Mesh. This can alter the state of the element
transformation object and can also lead to unexpected results when the
ElementTransformation object is already in use such as when these methods
are called from within an integration loop. Consider using
GetValues(ElementTransformation &T, ...) instead.
*/
///@{
/** Compute a collection of scalar values from within the element indicated
by the index i. */
void GetValues(int i, const IntegrationRule &ir, Vector &vals,
int vdim = 1) const;
/** Compute a collection of vector values from within the element indicated
by the index i. */
void GetValues(int i, const IntegrationRule &ir, Vector &vals,
DenseMatrix &tr, int vdim = 1) const;
void GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
///@}
/** @name ElementTransformation Get Value Methods
These member functions are designed for use within
GridFunctionCoefficient objects. These can be used with
ElementTransformation objects coming from either
Mesh::GetElementTransformation() or Mesh::GetBdrElementTransformation().
@note These methods do not reset the ElementTransformation object so they
should be safe to use within integration loops or other contexts where
the ElementTransformation is already in use.
*/
///@{
/** Return a scalar value from within the element indicated by the
ElementTransformation Object. */
double GetValue(ElementTransformation &T, const IntegrationPoint &ip,
int comp = 0, Vector *tr = NULL) const;
/** Return a vector value from within the element indicated by the
ElementTransformation Object. */
void GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip,
Vector &val, Vector *tr = NULL) const;
///@}
/** @name ElementTransformation Get Values Methods
These are convenience methods for repeatedly calling GetValue for
multiple points within a given element. They work by calling either the
ElementTransformation or FaceElementTransformations versions described
above. Consequently, these methods should not be expected to run faster
than calling the above methods in an external loop.
@note These methods do not reset the ElementTransformation object so they
should be safe to use within integration loops or other contexts where
the ElementTransformation is already in use.
@note These methods can also be used with FaceElementTransformations
objects.
*/
///@{
/** Compute a collection of scalar values from within the element indicated
by the ElementTransformation object. */
void GetValues(ElementTransformation &T, const IntegrationRule &ir,
Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const;
/** Compute a collection of vector values from within the element indicated
by the ElementTransformation object. */
void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix *tr = NULL) const;
///@}
/** @name Face Index Get Values Methods
These methods are designed to work with Discontinuous Galerkin basis
functions. They compute field values on the interface between elements,
or on boundary elements, by interpolating the field in a neighboring
element. The \a side argument indices which neighboring element should be
used: 0, 1, or 2 (automatically chosen).
@warning These methods retrieve and use the FaceElementTransformations
object from the mfem::Mesh. This can alter the state of the face element
transformations object and can also lead to unexpected results when the
FaceElementTransformations object is already in use such as when these
methods are called from within an integration loop. Consider using
GetValues(ElementTransformation &T, ...) instead.
*/
///@{
/** Compute a collection of scalar values from within the face
indicated by the index i. */
int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals,
DenseMatrix &tr, int vdim = 1) const;
/** Compute a collection of vector values from within the face
indicated by the index i. */
int GetFaceVectorValues(int i, int side, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
///@}
void GetLaplacians(int i, const IntegrationRule &ir, Vector &laps,
int vdim = 1) const;
@@ -283,6 +164,18 @@ public:
void GetHessians(int i, const IntegrationRule &ir, DenseMatrix &hess,
DenseMatrix &tr, int vdim = 1) const;
int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals,
DenseMatrix &tr, int vdim = 1) const;
void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir,
DenseMatrix &vals) const;
void GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
int GetFaceVectorValues(int i, int side, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
void GetValuesFrom(const GridFunction &orig_func);
void GetBdrValuesFrom(const GridFunction &orig_func);
@@ -340,10 +233,12 @@ public:
virtual void ProjectCoefficient(Coefficient &coeff);
// call fes -> BuildDofToArrays() before using this projection
void ProjectCoefficient(Coefficient &coeff, Array<int> &dofs, int vd = 0);
void ProjectCoefficient(VectorCoefficient &vcoeff);
// call fes -> BuildDofToArrays() before using this projection
void ProjectCoefficient(VectorCoefficient &vcoeff, Array<int> &dofs);
void ProjectCoefficient(Coefficient *coeff[]);
@@ -467,28 +362,28 @@ public:
const IntegrationRule *irs[] = NULL) const;
/** Compute the Lp error in each element of the mesh and store the results in
the Vector @a error. The result should be of length number of elements,
for example an L2 GridFunction of order zero using map type VALUE. */
the GridFunction @a error. The result should be an L2 GridFunction of
order zero using map type VALUE. */
virtual void ComputeElementLpErrors(const double p, Coefficient &exsol,
Vector &error,
GridFunction &error,
Coefficient *weight = NULL,
const IntegrationRule *irs[] = NULL
) const;
virtual void ComputeElementL1Errors(Coefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(1.0, exsol, error, NULL, irs); }
virtual void ComputeElementL2Errors(Coefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(2.0, exsol, error, NULL, irs); }
virtual void ComputeElementMaxErrors(Coefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(infinity(), exsol, error, NULL, irs); }
@@ -502,29 +397,29 @@ public:
const IntegrationRule *irs[] = NULL) const;
/** Compute the Lp error in each element of the mesh and store the results in
the Vector @ error. The result should be of length number of elements,
for example an L2 GridFunction of order zero using map type VALUE. */
the GridFunction @ error. The result should be an L2 GridFunction of
order zero using map type VALUE. */
virtual void ComputeElementLpErrors(const double p, VectorCoefficient &exsol,
Vector &error,
GridFunction &error,
Coefficient *weight = NULL,
VectorCoefficient *v_weight = NULL,
const IntegrationRule *irs[] = NULL
) const;
virtual void ComputeElementL1Errors(VectorCoefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(1.0, exsol, error, NULL, NULL, irs); }
virtual void ComputeElementL2Errors(VectorCoefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(2.0, exsol, error, NULL, NULL, irs); }
virtual void ComputeElementMaxErrors(VectorCoefficient &exsol,
Vector &error,
GridFunction &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(infinity(), exsol, error, NULL, NULL, irs); }
@@ -591,20 +486,11 @@ public:
/// Save the GridFunction to an output stream.
virtual void Save(std::ostream &out) const;
#ifdef MFEM_USE_ADIOS2
/// Save the GridFunction to a binary output stream using adios2 bp format.
virtual void Save(adios2stream &out, const std::string& variable_name,
const adios2stream::data_type
type = adios2stream::data_type::point_data) const;
#endif
/** @brief Write the GridFunction in VTK format. Note that Mesh::PrintVTK
must be called first. The parameter ref > 0 must match the one used in
/** Write the GridFunction in VTK format. Note that Mesh::PrintVTK must be
called first. The parameter ref > 0 must match the one used in
Mesh::PrintVTK. */
void SaveVTK(std::ostream &out, const std::string &field_name, int ref);
/** @brief Write the GridFunction in STL format. Note that the mesh dimension
must be 2 and that quad elements will be broken into two triangles.*/
void SaveSTL(std::ostream &out, int TimesToRefine = 1);
/// Destroys grid function.
@@ -737,16 +623,6 @@ public:
*/
inline void GetElementValues(int idx, Vector &values) const;
/// Return the quadrature function values at an integration point.
/** The result is stored in the Vector @a values as a reference to the
global values. */
inline void GetElementValues(int idx, const int ip_num, Vector &values);
/// Return the quadrature function values at an integration point.
/** The result is stored in the Vector @a values as a copy to the
global values. */
inline void GetElementValues(int idx, const int ip_num, Vector &values) const;
/// Return all values associated with mesh element @a idx in a DenseMatrix.
/** The result is stored in the DenseMatrix @a values as a reference to the
global values.
@@ -851,25 +727,6 @@ inline void QuadratureFunction::GetElementValues(int idx, Vector &values) const
}
}
inline void QuadratureFunction::GetElementValues(int idx, const int ip_num,
Vector &values)
{
const int s_offset = qspace->element_offsets[idx] * vdim + ip_num * vdim;
values.NewDataAndSize(data + s_offset, vdim);
}
inline void QuadratureFunction::GetElementValues(int idx, const int ip_num,
Vector &values) const
{
const int s_offset = qspace->element_offsets[idx] * vdim + ip_num * vdim;
values.SetSize(vdim);
const double *q = data + s_offset;
for (int i = 0; i < values.Size(); i++)
{
values(i) = *(q++);
}
}
inline void QuadratureFunction::GetElementValues(int idx, DenseMatrix &values)
{
const int s_offset = qspace->element_offsets[idx];
+31 -99
View File
@@ -29,14 +29,12 @@ namespace mfem
{
FindPointsGSLIB::FindPointsGSLIB()
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
: mesh(NULL), ir_simplex(NULL), gsl_mesh(), fdata2D(NULL), fdata3D(NULL),
dim(-1)
{
gsl_comm = new comm;
#ifdef MFEM_USE_MPI
int initialized;
MPI_Initialized(&initialized);
if (!initialized) { MPI_Init(NULL, NULL); }
MPI_Init(NULL, NULL);
MPI_Comm comm = MPI_COMM_WORLD;;
comm_init(gsl_comm, comm);
#else
@@ -52,29 +50,28 @@ FindPointsGSLIB::~FindPointsGSLIB()
#ifdef MFEM_USE_MPI
FindPointsGSLIB::FindPointsGSLIB(MPI_Comm _comm)
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
: mesh(NULL), ir_simplex(NULL), gsl_mesh(), fdata2D(NULL), fdata3D(NULL),
dim(-1)
{
gsl_comm = new comm;
comm_init(gsl_comm, _comm);
}
#endif
void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
const int npt_max)
void FindPointsGSLIB::Setup(Mesh &m, double bb_t, double newt_tol, int npt_max)
{
MFEM_VERIFY(m.GetNodes() != NULL, "Mesh nodes are required.");
MFEM_VERIFY(m.GetNumGeometries(m.Dimension()) == 1,
"Mixed meshes are not currently supported in FindPointsGSLIB.");
// call FreeData if FindPointsGSLIB::Setup has been called already
if (setupflag) { FreeData(); }
mesh = &m;
dim = mesh->Dimension();
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
unsigned dof1D = fe->GetOrder() + 1;
const int gt = fe->GetGeomType();
int NE = mesh->GetNE(),
dof_cnt = fe->GetDof(),
pts_cnt = NE * dof_cnt,
gt = fe->GetGeomType();
if (gt == Geometry::TRIANGLE || gt == Geometry::TETRAHEDRON ||
gt == Geometry::PRISM)
@@ -90,8 +87,8 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
MFEM_ABORT("Element type not currently supported in FindPointsGSLIB.");
}
const int pts_cnt = gsl_mesh.Size()/dim,
NEtot = pts_cnt/(int)pow(dof1D, dim);
pts_cnt = gsl_mesh.Size()/dim;
int NEtot = pts_cnt/(int)pow(dof1D, dim);
if (dim == 2)
{
@@ -110,7 +107,6 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
fdata3D = findpts_setup_3(gsl_comm, elx, nr, NEtot, mr, bb_t,
pts_cnt, pts_cnt, npt_max, newt_tol);
}
setupflag = true;
}
void FindPointsGSLIB::FindPoints(const Vector &point_pos,
@@ -119,7 +115,6 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos,
Array<unsigned int> &elem_ids,
Vector &ref_pos, Vector &dist)
{
MFEM_VERIFY(setupflag, "Use FindPointsGSLIB::Setup before finding points.");
const int points_cnt = point_pos.Size() / dim;
if (dim == 2)
{
@@ -155,90 +150,34 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos,
}
}
void FindPointsGSLIB::FindPoints(const Vector &point_pos)
{
const int points_cnt = point_pos.Size() / dim;
gsl_code.SetSize(points_cnt);
gsl_proc.SetSize(points_cnt);
gsl_elem.SetSize(points_cnt);
gsl_ref.SetSize(points_cnt * dim);
gsl_dist.SetSize(points_cnt);
FindPoints(point_pos, gsl_code, gsl_proc, gsl_elem, gsl_ref, gsl_dist);
}
void FindPointsGSLIB::FindPoints(Mesh &m, const Vector &point_pos,
const double bb_t, const double newt_tol,
const int npt_max)
{
if (!setupflag || (mesh != &m) )
{
Setup(m, bb_t, newt_tol, npt_max);
}
FindPoints(point_pos);
}
void FindPointsGSLIB::Interpolate(Array<unsigned int> &codes,
Array<unsigned int> &proc_ids,
Array<unsigned int> &elem_ids,
Vector &ref_pos, const GridFunction &field_in,
Vector &field_out)
{
FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
GridFunction field_in_scalar(&ind_fes);
Vector node_vals;
GetNodeValues(field_in, node_vals);
const int ncomp = field_in.FESpace()->GetVDim(),
points_fld = field_in.Size() / ncomp,
points_cnt = codes.Size();
for (int i = 0; i < ncomp; i++)
const int points_cnt = ref_pos.Size() / dim;
if (dim==2)
{
const int dataptrin = i*points_fld,
dataptrout = i*points_cnt;
field_in_scalar.NewDataAndSize(field_in.GetData()+dataptrin, points_fld);
GetNodeValues(field_in_scalar, node_vals);
if (dim==2)
{
findpts_eval_2(field_out.GetData()+dataptrout, sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata2D);
}
else
{
findpts_eval_3(field_out.GetData()+dataptrout, sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata3D);
}
findpts_eval_2(field_out.GetData(), sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata2D);
}
else
{
findpts_eval_3(field_out.GetData(), sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata3D);
}
}
void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
Vector &field_out)
{
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::Interpolate(const Vector &point_pos,
const GridFunction &field_in, Vector &field_out)
{
FindPoints(point_pos);
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::Interpolate(Mesh &m, const Vector &point_pos,
const GridFunction &field_in, Vector &field_out)
{
FindPoints(m, point_pos);
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::FreeData()
@@ -251,13 +190,7 @@ void FindPointsGSLIB::FreeData()
{
findpts_free_3(fdata3D);
}
setupflag = false;
gsl_code.DeleteAll();
gsl_proc.DeleteAll();
gsl_elem.DeleteAll();
gsl_mesh.Destroy();
gsl_ref.Destroy();
gsl_dist.Destroy();
}
void FindPointsGSLIB::GetNodeValues(const GridFunction &gf_in,
@@ -359,7 +292,7 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
const GridFunction *nodes = mesh->GetNodes();
Mesh *meshsplit = NULL;
const int NE = mesh->GetNE();
int NEsplit = -1;
int NEsplit;
// Split the reference element into a reference submesh of quads or hexes.
if (gt == Geometry::TRIANGLE)
@@ -453,7 +386,6 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
}
meshsplit->FinalizeHexMesh(1, 1, true);
}
else { MFEM_ABORT("Unsupported geometry type."); }
// Curve the reference submesh.
H1_FECollection fec(fe->GetOrder(), dim);
+3 -30
View File
@@ -29,12 +29,10 @@ class FindPointsGSLIB
protected:
Mesh *mesh;
IntegrationRule *ir_simplex;
Vector gsl_mesh;
struct findpts_data_2 *fdata2D;
struct findpts_data_3 *fdata3D;
int dim;
Array<unsigned int> gsl_code, gsl_proc, gsl_elem;
Vector gsl_mesh, gsl_ref, gsl_dist;
bool setupflag;
struct comm *gsl_comm;
@@ -61,8 +59,7 @@ public:
@param[in] newt_tol Newton tolerance for the gslib search methods.
@param[in] npt_max Number of points for simultaneous iteration. This
alters performance and memory footprint. */
void Setup(Mesh &m, const double bb_t = 0.1, const double newt_tol = 1.0e-12,
const int npt_max = 256);
void Setup(Mesh &m, double bb_t, double newt_tol, int npt_max);
/** Searches positions given in physical space by @a point_pos. All output
Arrays and Vectors are expected to have the correct size.
@@ -76,15 +73,11 @@ public:
@param[out] ref_pos Reference coordinates of the found point. Ordered
by vdim (XYZ,XYZ,XYZ...).
Note: the gslib reference frame is [-1,1].
@param[out] dist Distance between the sought and the found point
@param[out] dist Distance between the seeked and the found point
in physical space. */
void FindPoints(const Vector &point_pos, Array<unsigned int> &codes,
Array<unsigned int> &proc_ids, Array<unsigned int> &elem_ids,
Vector &ref_pos, Vector &dist);
void FindPoints(const Vector &point_pos);
/// Setup FindPoints and search positions
void FindPoints(Mesh &m, const Vector &point_pos, const double bb_t = 0.1,
const double newt_tol = 1.0e-12, const int npt_max = 256);
/** Interpolation of field values at prescribed reference space positions.
@@ -103,31 +96,11 @@ public:
void Interpolate(Array<unsigned int> &codes, Array<unsigned int> &proc_ids,
Array<unsigned int> &elem_ids, Vector &ref_pos,
const GridFunction &field_in, Vector &field_out);
void Interpolate(const GridFunction &field_in, Vector &field_out);
/** Search positions and interpolate */
void Interpolate(const Vector &point_pos, const GridFunction &field_in,
Vector &field_out);
/** Setup FindPoints, search positions and interpolate */
void Interpolate(Mesh &m, const Vector &point_pos,
const GridFunction &field_in, Vector &field_out);
/** Cleans up memory allocated internally by gslib.
Note that in parallel, this must be called before MPI_Finalize(), as
it calls MPI_Comm_free() for internal gslib communicators. */
void FreeData();
/// Return code for each point searched by FindPoints: inside element (0), on
/// element boundary (1), or not found (2).
const Array<unsigned int> &GetCode() const { return gsl_code; }
/// Return element number for each point found by FindPoints.
const Array<unsigned int> &GetElem() const { return gsl_elem; }
/// Return MPI rank on which each point was found by FindPoints.
const Array<unsigned int> &GetProc() const { return gsl_proc; }
/// Return reference coordinates for each point found by FindPoints.
const Vector &GetReferencePosition() const { return gsl_ref; }
/// Return distance Distance between the sought and the found point
/// in physical space, for each point found by FindPoints.
const Vector &GetDist() const { return gsl_dist; }
};
} // namespace mfem
+1 -1
View File
@@ -40,7 +40,7 @@ struct CeedConstCoeff
struct CeedGridCoeff
{
const GridFunction* coeff;
GridFunction* coeff;
CeedBasis basis;
CeedElemRestriction restr;
CeedVector coeffVector;

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