Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b51732c827 | ||
|
|
d838c6b33b |
-18
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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@")
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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@
|
||||
|
||||
|
||||
@@ -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@
|
||||
|
||||
@@ -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
@@ -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 =
|
||||
|
||||
@@ -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
@@ -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
|
||||
{
|
||||
|
||||
@@ -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";
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 |
@@ -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$"))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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(¶view, "-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
@@ -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.*
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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> >_,
|
||||
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> >_,
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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
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)
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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> >,
|
||||
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>
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+189
-437
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -311,10 +311,10 @@ GetEdge(int &nv, v_t &v, int &ne, int &e, int &eo, const int edge_info)
|
||||
eo = edge_info%64;
|
||||
MFEM_ASSERT(0 <= e && e < g_consts::NumEdges, "");
|
||||
MFEM_ASSERT(0 <= eo && eo < e_consts::NumOrient, "");
|
||||
v[0] = 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
@@ -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; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user