Compare commits

..
14 Commits
Author SHA1 Message Date
lazarov 28a6c1f96c changes in the configuration files 2020-07-18 13:29:18 -07:00
lazarov cda243493a New descriptions for ex71 and ex71p 2020-07-08 19:13:23 -07:00
lazarov 85e140bfcf Serial example 2020-07-08 18:32:30 -07:00
lazarov 53ff1a2bf8 Merge branch 'master' into fad 2020-07-08 16:07:25 -07:00
lazarov 4b47d0eb63 Added support for FADBAD++ 2020-07-08 16:04:37 -07:00
lazarov 72aeb54227 The name of ADQIntegratorJ/H class is changed to ADQFunctionJ/H 2020-06-30 22:37:07 -07:00
lazarov 22c33cbdf6 Added:
*AD integrator for pLaplacian
*Select between AD integrator and hond coded integrator
2020-06-26 10:13:24 -07:00
lazarov 5287c9f509 Added configuration for CODIPACK 2020-06-18 18:13:09 -07:00
lazarov fa2db9abf2 Intermediate updates 2020-06-18 18:12:22 -07:00
lazarov a8a7bc4e40 Native implementation before adding adept 2020-06-18 16:20:59 -07:00
lazarov 1e04cf7798 Merge branch 'master' into fad 2020-06-12 19:30:04 -07:00
bslazarov fa718bab9a modified: ../../examples/CMakeLists.txt
new file:   ../../examples/ex23.cpp
	modified:   ../../fem/CMakeLists.txt
	new file:   ../../fem/adnonlininteg.cpp
	new file:   ../../fem/adnonlininteg.hpp
	modified:   ../../fem/fem.hpp
	modified:   ../../linalg/fdual.hpp
	new file:   ../../linalg/taddensemat.hpp
	new file:   ../../linalg/tadvector.hpp
2020-02-25 20:27:28 -08:00
bslazarov 84209babd2 modified: fdual.hpp
modified:   ../tests/unit/linalg/test_fdual.cpp
2020-02-16 23:34:17 -08:00
bslazarov e940331e39 new file: ../../linalg/fdual.hpp
modified:   ../../linalg/linalg.hpp
	modified:   ../../tests/unit/CMakeLists.txt
	new file:   ../../tests/unit/linalg/test_fdual.cpp
2020-02-14 17:48:25 -08:00
239 changed files with 9168 additions and 23174 deletions
+8 -10
View File
@@ -15,10 +15,8 @@ install:
- msmpisdk.msi /passive
- set PATH=C:\Program Files\Microsoft MPI\Bin;%PATH%
# Install METIS, use a mirror because the original source server is not always
# up. Original url:
# http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-5.1.0.tar.gz
- ps: Start-FileDownload 'https://mfem.github.io/tpls/metis-5.1.0.tar.gz'
# Install METIS
- ps: Start-FileDownload 'http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-5.1.0.tar.gz'
- 7z x metis-5.1.0.tar.gz -so | 7z x -si -ttar > nul
- cd metis-5.1.0
- ps: ( get-content "GKlib\gk_arch.h") | % { If ($_.ReadCount -ge 52) {$_ -replace "#ifdef __MSC__","#ifdef DISABLE_THIS_ANCIENT_MSC_CHECK"} Else {$_} } | set-content "GKlib\gk_arch.h"
@@ -28,17 +26,17 @@ install:
- cd ..
# Install hypre
- ps: Start-FileDownload 'https://github.com/hypre-space/hypre/archive/v2.19.0.tar.gz'
- 7z x v2.19.0.tar.gz -so | 7z x -si -ttar > nul
- cd hypre-2.19.0/src
- cmake -H. -Bbuild -DMPI_C_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DMPI_C_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include"
- ps: Start-FileDownload 'https://github.com/hypre-space/hypre/archive/V2-10-0b.tar.gz'
- 7z x V2-10-0b.tar.gz -so | 7z x -si -ttar > nul
- cd hypre-2-10-0b
- cmake -H. -Bbuild -DHYPRE_USING_FEI=OFF -DMPI_C_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DMPI_C_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include"
- cmake --build build
- cmake --build build --target install
- cd ../..
- cd ..
# MFEM
before_build:
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_parallel -DMFEM_USE_MPI=TRUE -DMFEM_USE_METIS_5=TRUE -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DHYPRE_DIR=%cd%\hypre-2.19.0\src\hypre -DMETIS_LIBRARIES=%cd%\metis-5.1.0\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%cd%\metis-5.1.0\include
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_parallel -DMFEM_USE_MPI=TRUE -DMFEM_USE_METIS_5=TRUE -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DHYPRE_LIBRARIES=%cd%\hypre-2-10-0b\hypre\lib\HYPRE.lib -DHYPRE_INCLUDE_DIRS=%cd%\hypre-2-10-0b\hypre\include -DHYPRE_VERSION=21000 -DMETIS_LIBRARIES=%cd%\metis-5.1.0\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%cd%\metis-5.1.0\include
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_serial -DMFEM_USE_MPI=FALSE
build_script:
+1 -14
View File
@@ -122,7 +122,7 @@ examples/sundials/ex16-final.*
examples/sundials/Example16*
examples/petsc/ex[1-69]p
examples/petsc/ex1[0-1]p
examples/petsc/ex10p
examples/petsc/mesh.*
examples/petsc/sol.*
@@ -137,7 +137,6 @@ examples/petsc/Example9*
examples/petsc/deformed.*
examples/petsc/velocity.*
examples/petsc/elastic_energy.*
examples/petsc/mode_*
examples/pumi/ex1
examples/pumi/ex[126]p
@@ -244,24 +243,12 @@ miniapps/navier/navier_3dfoc
miniapps/navier/tgv_out*.txt
miniapps/navier/*_output
miniapps/adjoint/cvsRoberts_ASAi_dns
miniapps/adjoint/adjoint_advection_diffusion
# Unit test binary and outputs
tests/unit/output_meshes
tests/unit/unit_tests
tests/unit/punit_tests
tests/unit/sedov_tests_*
tests/unit/psedov_tests_*
tests/unit/tmop_tests_*
tests/unit/ptmop_tests_*
tests/unit/cube.mesh
tests/unit/star.mesh
tests/unit/blade.mesh
tests/unit/square01.mesh
tests/unit/toroid-hex.mesh
tests/unit/beam-hex-nurbs.mesh
tests/unit/square-disc-nurbs.mesh
# Test script output
tests/scripts/*.err
+33 -98
View File
@@ -11,20 +11,11 @@
language: cpp
os: linux
dist: bionic
stages:
- checks
- tests
- optional
env:
global:
- HYPRE_ARCHIVE=v2.19.0.tar.gz
HYPRE_URL=https://github.com/hypre-space/hypre/archive/$HYPRE_ARCHIVE
HYPRE_TOP_DIR=hypre-2.19.0
jobs:
include:
@@ -37,7 +28,6 @@ jobs:
- stage: checks
os: linux
dist: xenial
name: "code-style"
addons:
apt:
@@ -56,6 +46,9 @@ jobs:
packages:
- doxygen
- graphviz
- mpich
- libmpich-dev
env: MPI=YES
script:
- cd ${TRAVIS_BUILD_DIR}
- cd tests/scripts
@@ -70,24 +63,13 @@ jobs:
- mpich
- libmpich-dev
env: MPI=YES
before_script:
script:
- cd ${TRAVIS_BUILD_DIR}
- mpicxx -v
- make config MFEM_USE_MPI=YES MFEM_MPI_NP=2
- make all -j3
- make test-noclean
script:
- cd tests/scripts
- ./runtest gitignore
cache:
ccache: true
directories:
- $TRAVIS_BUILD_DIR/../$HYPRE_TOP_DIR/src/hypre
- $TRAVIS_BUILD_DIR/../metis-4.0
before_cache:
- cd $TRAVIS_BUILD_DIR/../metis-4.0;
mv libmetis.a Lib ..; rm -rf * ; mv ../libmetis.a ../Lib .;
rm -f Lib/*.{c,o}
# ========================
# Optional Checks/Tests
@@ -96,7 +78,6 @@ jobs:
- stage: optional
name: "branch-history"
if: branch != next
# need full git history for the binary/big files check
git:
depth: false
@@ -125,8 +106,6 @@ jobs:
MPI=NO
CODECOV=NO
MFEM_TEST_TARGET=check
cache:
ccache: true
- os: linux
compiler: gcc
@@ -135,8 +114,6 @@ jobs:
MPI=NO
CODECOV=NO
MFEM_TEST_TARGET=test
cache:
ccache: true
- os: linux
compiler: gcc
@@ -160,9 +137,9 @@ jobs:
MFEM_TEST_TARGET=check
NPROCS=2
cache:
ccache: true
directories:
- $TRAVIS_BUILD_DIR/../$HYPRE_TOP_DIR/src/hypre
- $TRAVIS_BUILD_DIR/../hypre-2.10.0b/src/hypre/lib
- $TRAVIS_BUILD_DIR/../hypre-2.10.0b/src/hypre/include
- $TRAVIS_BUILD_DIR/../metis-4.0
before_cache:
- cd $TRAVIS_BUILD_DIR/../metis-4.0;
@@ -191,9 +168,9 @@ jobs:
MFEM_TEST_TARGET=test
NPROCS=2
cache:
ccache: true
directories:
- $TRAVIS_BUILD_DIR/../$HYPRE_TOP_DIR/src/hypre
- $TRAVIS_BUILD_DIR/../hypre-2.10.0b/src/hypre/lib
- $TRAVIS_BUILD_DIR/../hypre-2.10.0b/src/hypre/include
- $TRAVIS_BUILD_DIR/../metis-4.0
before_cache:
- cd $TRAVIS_BUILD_DIR/../metis-4.0;
@@ -216,16 +193,16 @@ jobs:
- cd ${TRAVIS_BUILD_DIR}/build
- cmake ..
-DMFEM_USE_MPI=ON
-DHYPRE_DIR=${TRAVIS_BUILD_DIR}/../$HYPRE_TOP_DIR/src/hypre
-DHYPRE_DIR=${TRAVIS_BUILD_DIR}/../hypre-2.10.0b/src/hypre
-DMFEM_MPI_NP=$NPROCS
- make -j3 mfem examples
- cd ${TRAVIS_BUILD_DIR}/build/tests/unit
- make -j3
- ctest --output-on-failure
cache:
ccache: true
directories:
- $TRAVIS_BUILD_DIR/../$HYPRE_TOP_DIR/src/hypre
- $TRAVIS_BUILD_DIR/../hypre-2.10.0b/src/hypre/lib
- $TRAVIS_BUILD_DIR/../hypre-2.10.0b/src/hypre/include
- $TRAVIS_BUILD_DIR/../metis-4.0
before_cache:
- cd $TRAVIS_BUILD_DIR/../metis-4.0;
@@ -241,43 +218,27 @@ jobs:
# - parallel
- os: osx
osx_image: xcode11.2
# osx_image: xcode7.3
compiler: clang
name: "Mac: Serial + Debug"
addons:
homebrew:
packages:
- ccache
env: DEBUG=YES
MPI=NO
CODECOV=NO
MFEM_TEST_TARGET=check
cache:
ccache: true
- os: osx
osx_image: xcode11.2
# osx_image: xcode7.3
compiler: clang
name: "Mac: Serial"
addons:
homebrew:
packages:
- ccache
env: DEBUG=NO
MPI=NO
CODECOV=NO
MFEM_TEST_TARGET=test
cache:
ccache: true
- os: osx
osx_image: xcode11.2
# osx_image: xcode7.3
compiler: clang
name: "Mac: Parallel + Debug"
addons:
homebrew:
packages:
- ccache
env: DEBUG=YES
MPI=YES
CODECOV=NO
@@ -285,9 +246,9 @@ jobs:
NPROCS=4
TMPDIR=/tmp
cache:
ccache: true
directories:
- $TRAVIS_BUILD_DIR/../$HYPRE_TOP_DIR/src/hypre
- $TRAVIS_BUILD_DIR/../hypre-2.10.0b/src/hypre/lib
- $TRAVIS_BUILD_DIR/../hypre-2.10.0b/src/hypre/include
- $TRAVIS_BUILD_DIR/../metis-4.0
- $HOME/local-cached
before_cache:
@@ -296,13 +257,9 @@ jobs:
rm -f Lib/*.{c,o}
- os: osx
osx_image: xcode11.2
# osx_image: xcode7.3
compiler: clang
name: "Mac: Parallel"
addons:
homebrew:
packages:
- ccache
env: DEBUG=NO
MPI=YES
CODECOV=YES
@@ -310,9 +267,9 @@ jobs:
NPROCS=4
TMPDIR=/tmp
cache:
ccache: true
directories:
- $TRAVIS_BUILD_DIR/../$HYPRE_TOP_DIR/src/hypre
- $TRAVIS_BUILD_DIR/../hypre-2.10.0b/src/hypre/lib
- $TRAVIS_BUILD_DIR/../hypre-2.10.0b/src/hypre/include
- $TRAVIS_BUILD_DIR/../metis-4.0
- $HOME/local-cached
before_cache:
@@ -326,19 +283,14 @@ before_install:
# brew install open-mpi;
# fi
# Disable ccache while building dependencies that are cached:
- echo "before \$PATH = $PATH";
export PATH=${PATH//\/usr\/lib\/ccache:/};
echo "after \$PATH = $PATH"
# On Mac OS X, build and cache OpenMPI 2.1.6:
# On Mac OS X, build and cache OpenMPI 2.1.1:
- if [ $TRAVIS_OS_NAME == "osx" ] && [ $MPI == "YES" ]; then
if [ ! -e $HOME/local-cached/bin/mpicc ]; then
mkdir -p $HOME/builds && cd $HOME/builds &&
wget https://download.open-mpi.org/release/open-mpi/v2.1/openmpi-2.1.6.tar.bz2 &&
tar jxf openmpi-2.1.6.tar.bz2 &&
wget https://www.open-mpi.org/software/ompi/v2.1/downloads/openmpi-2.1.1.tar.bz2 &&
tar jxf openmpi-2.1.1.tar.bz2 &&
mkdir openmpi-build && cd openmpi-build &&
../openmpi-2.1.6/configure --prefix=$HOME/local-cached &&
../openmpi-2.1.1/configure --prefix=$HOME/local-cached &&
make -j3 all && make install;
fi;
PATH=$HOME/local-cached/bin:$PATH;
@@ -383,28 +335,26 @@ install:
# hypre
- if [ $MPI == "YES" ]; then
if [ ! -e $HYPRE_TOP_DIR/src/hypre/lib/libHYPRE.a ]; then
wget $HYPRE_URL;
rm -rf $HYPRE_TOP_DIR;
tar xvzf $HYPRE_ARCHIVE;
cd $HYPRE_TOP_DIR/src;
./configure --disable-fortran CC=mpicc CXX=mpic++;
if [ ! -e hypre-2.10.0b/src/hypre/lib/libHYPRE.a ]; then
wget https://computation.llnl.gov/project/linear_solvers/download/hypre-2.10.0b.tar.gz --no-check-certificate;
rm -rf hypre-2.10.0b;
tar xvzf hypre-2.10.0b.tar.gz;
cd hypre-2.10.0b/src;
./configure --disable-fortran --without-fei CC=mpicc CXX=mpic++;
make -j3;
cd ../..;
else
echo "Reusing cached $HYPRE_TOP_DIR/";
echo "Reusing cached hypre-2.10.0b/";
fi;
ln -s $HYPRE_TOP_DIR hypre;
ln -s hypre-2.10.0b hypre;
else
echo "Serial build, not using hypre";
fi
# METIS, use a mirror because the original source server is not always up.
# Original url:
# http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/OLD/metis-4.0.3.tar.gz
# METIS
- if [ $MPI == "YES" ]; then
if [ ! -e metis-4.0/libmetis.a ]; then
wget https://mfem.github.io/tpls/metis-4.0.3.tar.gz;
wget http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/OLD/metis-4.0.3.tar.gz;
tar xvzf metis-4.0.3.tar.gz;
make -j3 -C metis-4.0.3/Lib CC="$CC" OPTFLAGS="-O2";
rm -rf metis-4.0;
@@ -414,18 +364,6 @@ install:
fi;
fi
# Re-enable ccache on linux; enable ccache on mac os:
- if [ $TRAVIS_OS_NAME == "linux" ]; then
export PATH="/usr/lib/ccache:$PATH";
else
if [ $TRAVIS_OS_NAME == "osx" ]; then
export PATH="/usr/local/opt/ccache/libexec:$PATH";
fi;
fi
- printf "which \$CC = "; which $CC;
printf "which \$CXX = "; which $CXX
script:
# Compiler
- if [ $MPI == "YES" ]; then
@@ -446,9 +384,6 @@ script:
if [ "$CODECOV" == "YES" ]; then
CPPFLAGS="--coverage -g";
fi;
if [ "$TRAVIS_OS_NAME" != "linux" ] || [ "$DEBUG" == "YES" ]; then
CPPFLAGS+=" -pedantic -Wall -Werror";
fi
# Configure the library
- make config MFEM_USE_MPI=$MPI MFEM_DEBUG=$DEBUG $MAKE_CXX_FLAG
+5 -43
View File
@@ -33,9 +33,6 @@ Meshing improvements
for example the periodic-annulus-sector and periodic-torus-sector files in
the data directory.
- Added complete action of the TMOP Integrator to account for the spatial
derivatives of discrete and analytic targets.
Performance improvements
------------------------
- Added support for explicit vectorization in the high-performance templated
@@ -44,26 +41,12 @@ Performance improvements
- x86 (SSE/AVX/AVX2/AVX512),
- Power8 & Power9 (VSX),
- BG/Q (QPX).
These are disabled by default, and can be enabled with MFEM_USE_SIMD=YES.
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.
- The TMOP mesh optimization algorithms were extended to GPU:
- QualityMetric #1, #2 and #7 are available in 2D, #302, #303 and #321 in 3D
- Both AnalyticAdaptTC and DiscreteAdaptTC TargetConstructor are available
- Kernels for normalization and limiting have been added
- The AdvectorCG now also support AssemblyLevel::PARTIAL
- Optimized AMD/HIP kernel support.
- Added a Full Assembly mode compatible with Device kernel execution. This
assembly level builds on top of the current Element Assembly kernels to
compute a global sparse matrix. All integrators supported by element assembly
are also supported by full assembly. See the '-fa' option in Example 9.
- Added support for BlockOperator on GPU. See the updated Example 5.
Discretization improvements
---------------------------
@@ -88,7 +71,7 @@ Discretization improvements
and, in the continuous field case, arbitrary mesh edges and faces.
- Added new coefficient and vector coefficient classes for QuadratureFunctions.
Additionally, new LinearForm integrators were also added which make use of
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.
@@ -105,10 +88,6 @@ Linear and nonlinear solvers
and solution during the solving process of an IterativeSolver after every
iteration.
- Added support for the CVODES package in SUNDIALS which provides ODE
solvers with sensitivity analysis capabilities. See the CVODESSolver
class and the new adjoint miniapps below.
- 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.
@@ -116,8 +95,6 @@ Linear and nonlinear solvers
- In SLISolver, changed the residual inner product from (Br,r) to (Br,Br) so the
solver can work with non-SPD preconditioner B.
- Added support for the SLEPc eigensolver package.
New and updated examples and miniapps
-------------------------------------
- Added a new example, Example 25/25p, to demonstrate the use of a Perfectly
@@ -136,17 +113,6 @@ New and updated examples and miniapps
equations of incompressible fluid dynamics. See the miniapps/navier directory
for more details.
- Added a new miniapps/adjoint directory with two miniapps demonstrating how to
solve adjoint problems in MFEM using the CVODES package in SUNDIALS. Both of
these miniapps require the MFEM_USE_SUNDIALS configuration option.
* The cvsRoberts_ASAi_dns miniapp solves a backward adjoint problem for a
system of ODEs, evaluating both forward and adjoint quadratures in serial.
* The adjoint_advection_diffusion miniapp solves a backward adjoint problem
for an advection diffusion PDE, evaluating adjoint quadratures in parallel.
- Ported Example 11p to SLEPc, to demonstrate solving the Laplace eigenvalue
equation with the shift-and-invert spectral transformation method.
- Added a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of
stitching together opposite surfaces of a mesh to create a topologically
periodic mesh.
@@ -154,13 +120,11 @@ New and updated examples and miniapps
- Added a new meshing miniapp, Minimal Surface, which solves Plateau's problem:
the Dirichlet problem for the minimal surface equation.
- Added partial assembly support to Example 4/4p and Example 5/5p, with diagonal
- Added partial assembly support to examples 4/4p and 5/5p, with diagonal
preconditioning.
- Added full assembly support in Example 9/9p.
- Added a new test problem in Example 24/24p, demonstrating a mixed bilinear
form for H1, H(curl), H(div) and L_2, with partial assembly support.
- 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.
@@ -168,8 +132,6 @@ New and updated examples and miniapps
mesh based on element attributes. Any newly exposed boundary elements are
assigned attribute numbers related to the trimmed element attributes.
- Added device support in Example 5/5p.
Improved testing
----------------
- Added a GitLab pipeline that automates PR testing on supercomputing systems
+24 -9
View File
@@ -149,13 +149,9 @@ if (MFEM_USE_MPI)
message(FATAL_ERROR "PETSc version >= 3.8.0 is required")
endif()
set(PETSC_INCLUDE_DIRS ${PETSC_INCLUDES})
if (MFEM_USE_SLEPC)
find_package(SLEPc REQUIRED config)
message(STATUS "Found SLEPc version ${SLEPC_VERSION}")
endif()
endif()
else()
set(PKGS_NEED_MPI SUPERLU PETSC SLEPC STRUMPACK PUMI)
set(PKGS_NEED_MPI SUPERLU PETSC STRUMPACK PUMI)
foreach(PKG IN LISTS PKGS_NEED_MPI)
if (MFEM_USE_${PKG})
message(STATUS "Disabling package ${PKG} - requires MPI")
@@ -211,10 +207,10 @@ endif()
# SUNDIALS
if (MFEM_USE_SUNDIALS)
if (NOT MFEM_USE_MPI)
find_package(SUNDIALS REQUIRED NVector_Serial CVODES ARKODE KINSOL)
find_package(SUNDIALS REQUIRED NVector_Serial CVODE ARKODE KINSOL)
else()
find_package(SUNDIALS REQUIRED
NVector_Serial NVector_Parallel NVector_ParHyp CVODES ARKODE KINSOL)
NVector_Serial NVector_Parallel NVector_ParHyp CVODE ARKODE KINSOL)
endif()
endif()
@@ -296,6 +292,25 @@ if (MFEM_USE_HIOP)
# find_package updates HIOP_FOUND, HIOP_INCLUDE_DIRS, HIOP_LIBRARIES
endif()
# ADEPT package
if (MFEM_USE_ADEPT)
find_package(ADEPT REQUIRED)
# find_package updates ADEPT_FOUND, ADEPT_INCLUDE_DIRS, ADEPT_LIBRARIES
endif()
# CODIPACK package
if (MFEM_USE_CODIPACK)
find_package(CODIPACK REQUIRED)
# find_package updates CODIPACK_FOUND, CODIPACK_INCLUDE_DIRS, CODIPACK_LIBRARIES
endif()
# FADBAD++ package
if (MFEM_USE_FADBADPP)
find_package(FADBADPP REQUIRED)
# find_package updates FADBADPP_FOUND, FADBADPP_INCLUDE_DIRS, FADBADPP_LIBRARIES
endif()
# CUDA
if (MFEM_USE_CUDA)
set(CMAKE_CUDA_STANDARD 11)
@@ -356,8 +371,8 @@ endif()
# integers, the METIS header (with 32-bit indices, as used by mfem) needs to
# be before SuiteSparse.
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
SLEPC MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2)
MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2 ADEPT CODIPACK FADBADPP)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
set(TPL_INCLUDE_DIRS "")
-1
View File
@@ -109,7 +109,6 @@ The MFEM source code has the following structure:
├── linalg
├── mesh
├── miniapps
│ ├── adjoint
│ ├── common
│ ├── electromagnetics
│ ├── gslib
+3 -12
View File
@@ -383,10 +383,6 @@ MFEM_USE_PETSC = YES/NO
and other features based on the PETSc package. When enabled, this option uses
the PETSC_* library options, see below.
MFEM_USE_SLEPC = YES/NO
Enable MFEM eigensolvers based on the SLEPc package. When enabled, this
option uses the SLEPC_* library options, see below.
MFEM_USE_MPFR = YES/NO
MPFR is a library for multiple-precision floating-point computations. This
option enables the use of MPFR in MFEM, e.g. for precise computation of 1D
@@ -601,12 +597,6 @@ The specific libraries and their options are:
Options: PETSC_OPT, PETSC_LIB.
Versions: PETSc >= 3.8.0.
- SLEPc (optional), used when MFEM_USE_SLEPC = YES. SLEPc depends on PETSc and
uses some of the PETSc options when compiled.
URL: https://slepc.upv.es/
Options: SLEPC_OPT, SLEPC_LIB.
Versions: SLEPc >= 3.8.0.
- Sidre (optional), part of LLNL's axom project, used when MFEM_USE_SIDRE = YES.
Starting with MFEM v4.1, Axom version 0.3.1 or later is required.
URL: https://github.com/LLNL/axom
@@ -659,11 +649,12 @@ The specific libraries and their options are:
Options: OCCA_DIR, OCCA_OPT, OCCA_LIB.
Versions: OCCA >= 1.0.9.
- libCEED (optional), used when MFEM_USE_CEED = YES.
- 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, git-hash a970f63.
Versions: libCEED >= 0.6.
- RAJA (optional), used when MFEM_USE_RAJA = YES.
Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported.
-4
View File
@@ -244,10 +244,6 @@ IF (DEFINED TPL_ENABLE_PETSC)
SET(MFEM_USE_PETSC ${TPL_ENABLE_PETSC} CACHE BOOL "Enable PETSc support." FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_SLEPC)
SET(MFEM_USE_SLEPC ${TPL_ENABLE_SLEPC} CACHE BOOL "Enable SLEPc support." FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_MPFR)
SET(MFEM_USE_MPFR ${TPL_ENABLE_MPFR} CACHE BOOL "Enable MPFR usage." FORCE)
ENDIF()
-1
View File
@@ -38,7 +38,6 @@ set(MFEM_USE_GNUTLS @MFEM_USE_GNUTLS@)
set(MFEM_USE_GSLIB @MFEM_USE_GSLIB@)
set(MFEM_USE_NETCDF @MFEM_USE_NETCDF@)
set(MFEM_USE_PETSC @MFEM_USE_PETSC@)
set(MFEM_USE_SLEPC @MFEM_USE_SLEPC@)
set(MFEM_USE_MPFR @MFEM_USE_MPFR@)
set(MFEM_USE_SIDRE @MFEM_USE_SIDRE@)
set(MFEM_USE_CONDUIT @MFEM_USE_CONDUIT@)
+7 -3
View File
@@ -104,9 +104,6 @@
// Enable MFEM functionality based on the PETSc library
#cmakedefine MFEM_USE_PETSC
// Enable MFEM functionality based on the SLEPc library
#cmakedefine MFEM_USE_SLEPC
// Enable MFEM functionality based on the Sidre library
#cmakedefine MFEM_USE_SIDRE
@@ -156,4 +153,11 @@
// library.
#cmakedefine MFEM_USE_SIMMETRIX
#cmakedefine MFEM_USE_ADEPT
#cmakedefine MFEM_USE_CODIPACK
#cmakedefine MFEM_USE_FADBADPP
#endif // MFEM_CONFIG_HEADER
+23
View File
@@ -0,0 +1,23 @@
# Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at the
# Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights reserved.
# See file COPYRIGHT for details.
#
# This file is part of the MFEM library. For more information and source code
# availability see http://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License (as published by the Free
# Software Foundation) version 2.1 dated February 1999.
# Sets the following variables:
# - ADEPT_FOUND
# - ADEPT_INCLUDE_DIRS
# - ADEPT_LIBRARIES
include(MfemCmakeUtilities)
mfem_find_package(ADEPT ADEPT ADEPT_DIR
"include" "adept.hpp"
"lib" "libadept.so"
"Paths to headers required by ADEPT."
"Libraries required by ADEPT.")
+23
View File
@@ -0,0 +1,23 @@
# Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at the
# Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights reserved.
# See file COPYRIGHT for details.
#
# This file is part of the MFEM library. For more information and source code
# availability see http://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License (as published by the Free
# Software Foundation) version 2.1 dated February 1999.
# Sets the following variables:
# - CODIPACK_FOUND
# - CODIPACK_INCLUDE_DIRS
# - CODIPACK_LIBRARIES
include(MfemCmakeUtilities)
mfem_find_package(CODIPACK CODIPACK CODIPACK_DIR
"include" "codi.hpp"
"lib" ""
"Paths to headers required by CODIPACK."
"Libraries required by CODIPACK.")
+23
View File
@@ -0,0 +1,23 @@
# Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at the
# Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights reserved.
# See file COPYRIGHT for details.
#
# This file is part of the MFEM library. For more information and source code
# availability see http://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License (as published by the Free
# Software Foundation) version 2.1 dated February 1999.
# Sets the following variables:
# - FADBADPP_FOUND
# - FADBADPP_INCLUDE_DIRS
# - FADBADPP_LIBRARIES
include(MfemCmakeUtilities)
mfem_find_package(FADBADPP FADBADPP FADBADPP_DIR
"include" "fadiff.h"
"lib" ""
"Paths to headers required by FADBADPP."
"Libraries required by FADBADPP.")
-44
View File
@@ -1,44 +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.
# Sets the following variables:
# - SLEPC_FOUND
# - SLEPC_INCLUDE_DIRS
# - SLEPC_LIBRARIES
set(SLEPc_REQUIRED_PACKAGES "PETSC" CACHE STRING
"Additional packages required by SLEPc")
include(MfemCmakeUtilities)
mfem_find_package(SLEPc SLEPC SLEPC_DIR
"include" "slepceps.h"
"${PETSC_ARCH}/lib" "slepc" # add NAMES_PER_DIR?
"Paths to headers required by SLEPc."
"Libraries required by SLEPc."
ADD_COMPONENT "config" "${PETSC_ARCH}/include" "slepcconf.h" "" ""
CHECK_BUILD SLEPC_VERSION_OK TRUE
"
#include \"petsc.h\"
#include \"slepceps.h\"
int main()
{
PetscErrorCode ierr;
int argc = 0;
char** argv = NULL;
ierr = SlepcInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL);
EPS eps;
ierr = EPSCreate(PETSC_COMM_SELF, &eps); CHKERRQ(ierr);
ierr = EPSDestroy(&eps); CHKERRQ(ierr);
ierr = SlepcFinalize(); CHKERRQ(ierr);
return 0;
}
"
)
-1
View File
@@ -25,6 +25,5 @@ mfem_find_package(SUNDIALS SUNDIALS SUNDIALS_DIR
ADD_COMPONENT NVector_ParHyp
"include" nvector/nvector_parhyp.h "lib" sundials_nvecparhyp
ADD_COMPONENT CVODE "include" cvode/cvode.h "lib" sundials_cvode
ADD_COMPONENT CVODES "include" cvodes/cvodes.h "lib" sundials_cvodes
ADD_COMPONENT ARKODE "include" arkode/arkode.h "lib" sundials_arkode
ADD_COMPONENT KINSOL "include" kinsol/kinsol.h "lib" sundials_kinsol)
@@ -731,7 +731,7 @@ function(mfem_export_mk_files)
MFEM_USE_LAPACK MFEM_THREAD_SAFE MFEM_USE_OPENMP MFEM_USE_LEGACY_OPENMP
MFEM_USE_MEMALLOC MFEM_USE_SUNDIALS MFEM_USE_MESQUITE MFEM_USE_SUITESPARSE
MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS
MFEM_USE_GSLIB MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE
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)
foreach(var ${CONFIG_MK_BOOL_VARS})
-3
View File
@@ -48,9 +48,6 @@
#ifdef MFEM_USE_PETSC
#error Building with PETSc (MFEM_USE_PETSC=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
#ifdef MFEM_USE_SLEPC
#error Building with SLEPc (MFEM_USE_SLEPC=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
#ifdef MFEM_USE_PUMI
#error Building with PUMI (MFEM_USE_PUMI=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
-3
View File
@@ -118,9 +118,6 @@
// Enable functionality based on the PETSc library
// #define MFEM_USE_PETSC
// Enable functionality based on the SLEPc library
// #define MFEM_USE_SLEPC
// Enable functionality based on the MPFR library.
// #define MFEM_USE_MPFR
-1
View File
@@ -37,7 +37,6 @@ MFEM_USE_GINKGO = @MFEM_USE_GINKGO@
MFEM_USE_GNUTLS = @MFEM_USE_GNUTLS@
MFEM_USE_NETCDF = @MFEM_USE_NETCDF@
MFEM_USE_PETSC = @MFEM_USE_PETSC@
MFEM_USE_SLEPC = @MFEM_USE_SLEPC@
MFEM_USE_MPFR = @MFEM_USE_MPFR@
MFEM_USE_SIDRE = @MFEM_USE_SIDRE@
MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@
+14 -8
View File
@@ -39,7 +39,6 @@ option(MFEM_USE_GNUTLS "Enable GNUTLS usage" OFF)
option(MFEM_USE_GSLIB "Enable GSLIB usage" OFF)
option(MFEM_USE_NETCDF "Enable NETCDF usage" OFF)
option(MFEM_USE_PETSC "Enable PETSc support." OFF)
option(MFEM_USE_SLEPC "Enable SLEPc support." OFF)
option(MFEM_USE_MPFR "Enable MPFR usage." OFF)
option(MFEM_USE_SIDRE "Enable Axom/Sidre usage" OFF)
option(MFEM_USE_CONDUIT "Enable Conduit usage" OFF)
@@ -50,8 +49,11 @@ 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" OFF)
option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" ON)
option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
option(MFEM_USE_ADEPT "Enable AD using ADEPT" OFF)
option(MFEM_USE_CODIPACK "Enable AD using CoDiPack" OFF)
option(MFEM_USE_FADBADPP "Enable AD using FADBAD++" OFF)
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
@@ -88,8 +90,6 @@ set(METIS_DIR "${MFEM_DIR}/../metis-4.0" CACHE PATH "Path to the METIS library."
set(LIBUNWIND_DIR "" CACHE PATH "Path to Libunwind.")
# For sundials_nvecparhyp and nvecparallel remember to build with MPI_ENABLED=ON
# and modify cmake variables for hypre for sundials
set(SUNDIALS_DIR "${MFEM_DIR}/../sundials-5.0.0/instdir" CACHE PATH
"Path to the SUNDIALS library.")
# The following may be necessary, if SUNDIALS was built with KLU:
@@ -158,10 +158,6 @@ set(PETSC_DIR "${MFEM_DIR}/../petsc" CACHE PATH
"Path to the PETSc main directory.")
set(PETSC_ARCH "arch-linux2-c-debug" CACHE STRING "PETSc build architecture.")
set(SLEPC_DIR "${MFEM_DIR}/../slepc" CACHE PATH
"Path to the SLEPc main directory.")
set(SLEPC_ARCH "arch-linux2-c-debug" CACHE STRING "SLEPC build architecture.")
set(MPFR_DIR "" CACHE PATH "Path to the MPFR library.")
set(CONDUIT_DIR "${MFEM_DIR}/../conduit" CACHE PATH
@@ -190,6 +186,16 @@ set(BLAS_LIBRARIES "" CACHE STRING "The BLAS library.")
set(LAPACK_INCLUDE_DIRS "" CACHE STRING "Path to LAPACK headers.")
set(LAPACK_LIBRARIES "" CACHE STRING "The LAPACK library.")
set(ADEPT_INCLUDE_DIRS "${MFEM_DIR}/../adept-1.1/include" CACHE STRING "Path to ADEPT headers.")
set(ADEPT_LIBRARIES "-L${MFEM_DIR}/../adept-1.1/lib -ladept" CACHE STRING "The ADEPT library.")
set(CODIPACK_INCLUDE_DIRS "${MFEM_DIR}/../CoDiPack/include" CACHE STRING "Path to CoDiPack headers.")
set(CODIPACK_LIBRARIES "")
set(FADBADPP_INCLUDE_DIRS "${MFEM_DIR}/../FADBAD++" CACHE STRING "Path to FADBAD++ headers.")
set(FADBADPP_LIBRARIES "")
# Some useful variables:
set(CMAKE_SKIP_PREPROCESSED_SOURCE_RULES ON) # Skip *.i rules
set(CMAKE_SKIP_ASSEMBLY_SOURCE_RULES ON) # Skip *.s rules
+4 -27
View File
@@ -125,7 +125,6 @@ MFEM_USE_GINKGO = NO
MFEM_USE_GNUTLS = NO
MFEM_USE_NETCDF = NO
MFEM_USE_PETSC = NO
MFEM_USE_SLEPC = NO
MFEM_USE_MPFR = NO
MFEM_USE_SIDRE = NO
MFEM_USE_CONDUIT = NO
@@ -138,8 +137,7 @@ MFEM_USE_RAJA = NO
MFEM_USE_OCCA = NO
MFEM_USE_CEED = NO
MFEM_USE_UMPIRE = NO
MFEM_USE_CAMP = NO
MFEM_USE_SIMD = NO
MFEM_USE_SIMD = YES
MFEM_USE_ADIOS2 = NO
# Compile and link options for zlib.
@@ -190,12 +188,10 @@ OPENMP_LIB =
POSIX_CLOCKS_LIB = -lrt
# SUNDIALS library configuration
# For sundials_nvecparhyp and nvecparallel remember to build with MPI_ENABLED=ON
# and modify cmake variables for hypre for sundials
SUNDIALS_DIR = @MFEM_DIR@/../sundials-5.0.0/instdir
SUNDIALS_OPT = -I$(SUNDIALS_DIR)/include
SUNDIALS_LIB = -Wl,-rpath,$(SUNDIALS_DIR)/lib64 -L$(SUNDIALS_DIR)/lib64\
-lsundials_arkode -lsundials_cvodes -lsundials_nvecserial -lsundials_kinsol
-lsundials_arkode -lsundials_cvode -lsundials_nvecserial -lsundials_kinsol
ifeq ($(MFEM_USE_MPI),YES)
SUNDIALS_LIB += -lsundials_nvecparhyp -lsundials_nvecparallel
@@ -280,20 +276,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
@@ -342,9 +324,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 =
@@ -373,11 +355,6 @@ UMPIRE_DIR = @MFEM_DIR@/../umpire
UMPIRE_OPT = -I$(UMPIRE_DIR)/include
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -lumpire
# CAMP library configuration
CAMP_DIR = @MFEM_DIR@/../camp
CAMP_OPT = -I$(CAMP_DIR)/include
CAMP_LIB = -L$(CAMP_DIR)/lib
# If YES, enable some informational messages
VERBOSE = NO
+204
View File
@@ -0,0 +1,204 @@
# 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.
# See the file INSTALL for description of the configuration options.
# Default options. To replace these, copy this file to user.cmake and modify it.
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING
"Build type: Debug, Release, RelWithDebInfo, or MinSizeRel." FORCE)
endif()
# MFEM options. Set to mimic the default "defaults.mk" file.
option(MFEM_USE_MPI "Enable MPI parallel build" ON)
option(MFEM_USE_METIS "Enable METIS usage" ${MFEM_USE_MPI})
option(MFEM_USE_EXCEPTIONS "Enable the use of exceptions" OFF)
option(MFEM_USE_ZLIB "Enable zlib for compressed data streams." OFF)
option(MFEM_USE_LIBUNWIND "Enable backtrace for errors." ON)
option(MFEM_USE_LAPACK "Enable LAPACK usage" ON)
option(MFEM_THREAD_SAFE "Enable thread safety" OFF)
option(MFEM_USE_OPENMP "Enable the OpenMP backend" OFF)
option(MFEM_USE_LEGACY_OPENMP "Enable legacy OpenMP usage" OFF)
option(MFEM_USE_MEMALLOC "Enable the internal MEMALLOC option." ON)
option(MFEM_USE_SUNDIALS "Enable SUNDIALS usage" OFF)
option(MFEM_USE_MESQUITE "Enable MESQUITE usage" OFF)
option(MFEM_USE_SUITESPARSE "Enable SuiteSparse usage" ON)
option(MFEM_USE_SUPERLU "Enable SuperLU_DIST usage" OFF)
option(MFEM_USE_STRUMPACK "Enable STRUMPACK usage" OFF)
option(MFEM_USE_GINKGO "Enable Ginkgo usage" OFF)
option(MFEM_USE_GNUTLS "Enable GNUTLS usage" OFF)
option(MFEM_USE_GSLIB "Enable GSLIB usage" OFF)
option(MFEM_USE_NETCDF "Enable NETCDF usage" OFF)
option(MFEM_USE_PETSC "Enable PETSc support." ON)
option(MFEM_USE_MPFR "Enable MPFR usage." OFF)
option(MFEM_USE_SIDRE "Enable Axom/Sidre usage" OFF)
option(MFEM_USE_CONDUIT "Enable Conduit usage" OFF)
option(MFEM_USE_PUMI "Enable PUMI" OFF)
option(MFEM_USE_HIOP "Enable HiOp" OFF)
option(MFEM_USE_CUDA "Enable CUDA" OFF)
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)
option(MFEM_USE_ADEPT "Enable AD using ADEPT" OFF)
option(MFEM_USE_CODIPACK "Enable AD using CoDiPack" ON)
option(MFEM_USE_FADBADPP "Enable AD using FADBAD++" OFF)
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
# Allow a user to disable testing, examples, and/or miniapps at CONFIGURE TIME
# if they don't want/need them (e.g. if MFEM is "just a dependency" and all they
# need is the library, building all that stuff adds unnecessary overhead). Note
# that the examples or miniapps can always be built using the targets 'examples'
# or 'miniapps', respectively.
option(MFEM_ENABLE_TESTING "Enable the ctest framework for testing" ON)
option(MFEM_ENABLE_EXAMPLES "Build all of the examples" OFF)
option(MFEM_ENABLE_MINIAPPS "Build all of the miniapps" OFF)
# Setting CXX/MPICXX on the command line or in user.cmake will overwrite the
# autodetected C++ compiler.
# set(CXX g++)
# set(MPICXX mpicxx)
# Set the target CUDA architecture
set(CUDA_ARCH "sm_60" CACHE STRING "Target CUDA architecture.")
set(MFEM_DIR ${CMAKE_CURRENT_SOURCE_DIR})
# The *_DIR paths below will be the first place searched for the corresponding
# headers and library. If these fail, then standard cmake search is performed.
# Note: if the variables are already in the cache, they are not overwritten.
set(HYPRE_DIR "/home/blaz/develop/common/dbg/petsc_3.12.5/" CACHE PATH
"Path to the hypre library.")
# If hypre was compiled to depend on BLAS and LAPACK:
# set(HYPRE_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
# "Packages that HYPRE depends on.")
set(METIS_DIR "/home/blaz/develop/common/dbg/petsc_3.12.5/" CACHE PATH "Path to the METIS library.")
set(LIBUNWIND_DIR "" CACHE PATH "Path to Libunwind.")
set(SUNDIALS_DIR "/home/blaz/develop/common/dbg/SUNDIALS_5.2.0/" CACHE PATH
"Path to the SUNDIALS library.")
# The following may be necessary, if SUNDIALS was built with KLU:
# set(SUNDIALS_REQUIRED_PACKAGES "SuiteSparse/KLU/AMD/BTF/COLAMD/config"
# CACHE STRING "Additional packages required by SUNDIALS.")
set(MESQUITE_DIR "${MFEM_DIR}/../mesquite-2.99" CACHE PATH
"Path to the Mesquite library.")
set(SuiteSparse_DIR "/home/blaz/develop/common/dbg/petsc_3.12.5/" CACHE PATH
"Path to the SuiteSparse library.")
set(SuiteSparse_REQUIRED_PACKAGES "BLAS" "METIS"
CACHE STRING "Additional packages required by SuiteSparse.")
set(ParMETIS_DIR "/home/blaz/develop/common/dbg/petsc_3.12.5/" CACHE PATH
"Path to the ParMETIS library.")
set(ParMETIS_REQUIRED_PACKAGES "METIS" CACHE STRING
"Additional packages required by ParMETIS.")
set(SuperLUDist_DIR "${MFEM_DIR}/../SuperLU_DIST_5.1.0" CACHE PATH
"Path to the SuperLU_DIST library.")
# SuperLU_DIST may also depend on "OpenMP", depending on how it was compiled.
set(SuperLUDist_REQUIRED_PACKAGES "MPI" "BLAS" "ParMETIS" CACHE STRING
"Additional packages required by SuperLU_DIST.")
set(STRUMPACK_DIR "/home/blaz/develop/common/dbg/petsc_3.12.5/" CACHE PATH
"Path to the STRUMPACK library.")
# STRUMPACK may also depend on "OpenMP", depending on how it was compiled.
# Starting with v2.2.0 of STRUMPACK, ParMETIS and Scotch are optional.
set(STRUMPACK_REQUIRED_PACKAGES "MPI" "MPI_Fortran" "ParMETIS" "METIS"
"ScaLAPACK" "Scotch/ptscotch/ptscotcherr/scotch/scotcherr" CACHE STRING
"Additional packages required by STRUMPACK.")
# If the MPI package does not find all required Fortran libraries:
# set(STRUMPACK_REQUIRED_LIBRARIES "gfortran" "mpi_mpifh" CACHE STRING
# "Additional libraries required by STRUMPACK.")
# The Scotch library, required by STRUMPACK <= v2.1.0, optional in STRUMPACK >=
# v2.2.0.
set(Scotch_DIR "${MFEM_DIR}/../scotch_6.0.4" CACHE PATH
"Path to the Scotch and PT-Scotch libraries.")
set(Scotch_REQUIRED_PACKAGES "Threads" CACHE STRING
"Additional packages required by Scotch.")
# Tell the "Threads" package/module to prefer pthreads.
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(Threads_LIB_VARS CMAKE_THREAD_LIBS_INIT)
# The ScaLAPACK library, required by STRUMPACK
set(ScaLAPACK_DIR "/home/blaz/develop/common/dbg/petsc_3.12.5/"
CACHE PATH "Path to the configuration file scalapack-config.cmake")
set(ScaLAPACK_TARGET_NAMES scalapack)
# set(ScaLAPACK_TARGET_FORCE)
# set(ScaLAPACK_IMPORT_CONFIG DEBUG)
set(Ginkgo_DIR "${MFEM_DIR}/../ginkgo" CACHE PATH "Path to the Ginkgo library.")
set(GNUTLS_DIR "" CACHE PATH "Path to the GnuTLS library.")
set(GSLIB_DIR "" CACHE PATH "Path to the GSLIB library.")
set(NETCDF_DIR "" CACHE PATH "Path to the NetCDF library.")
# May need to add "HDF5" as requirement.
set(NetCDF_REQUIRED_PACKAGES "" CACHE STRING
"Additional packages required by NetCDF.")
set(PETSC_DIR "/home/blaz/develop/common/dbg/petsc_3.12.5/" CACHE PATH
"Path to the PETSc main directory.")
set(PETSC_ARCH "" CACHE STRING "PETSc build architecture.")
set(MPFR_DIR "" CACHE PATH "Path to the MPFR library.")
set(CONDUIT_DIR "${MFEM_DIR}/../conduit" CACHE PATH
"Path to the Conduit library.")
set(AXOM_DIR "${MFEM_DIR}/../axom" CACHE PATH "Path to the Axom library.")
# May need to add "Boost" as requirement.
set(Axom_REQUIRED_PACKAGES "Conduit/relay/blueprint" CACHE STRING
"Additional packages required by Axom.")
set(PUMI_DIR "${MFEM_DIR}/../pumi-2.1.0" CACHE STRING
"Directory where PUMI is installed")
set(HIOP_DIR "${MFEM_DIR}/../hiop/install" CACHE STRING
"Directory where HiOp is installed")
set(HIOP_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
"Packages that HiOp depends on.")
set(OCCA_DIR "${MFEM_DIR}/../occa" CACHE PATH "Path to OCCA")
set(RAJA_DIR "${MFEM_DIR}/../raja" CACHE PATH "Path to RAJA")
set(CEED_DIR "${MFEM_DIR}/../libCEED" CACHE PATH "Path to libCEED")
set(UMPIRE_DIR "${MFEM_DIR}/../umpire" CACHE PATH "Path to Umpire")
set(BLAS_INCLUDE_DIRS "" CACHE STRING "Path to BLAS headers.")
set(BLAS_LIBRARIES "-L/home/blaz/develop/common/lib -lblas" CACHE STRING "The BLAS library.")
set(LAPACK_INCLUDE_DIRS "" CACHE STRING "Path to LAPACK headers.")
set(LAPACK_LIBRARIES "-L/home/blaz/develop/common/lib -llapack" CACHE STRING "The LAPACK library.")
set(ADEPT_INCLUDE_DIRS "/home/blaz/develop/common/dbg/adept-1.1/include" CACHE STRING "Path to ADEPT headers.")
set(ADEPT_LIBRARIES "/home/blaz/develop/common/dbg/adept-1.1/lib/libadept.so" CACHE STRING "The ADEPT library.")
set(CODIPACK_INCLUDE_DIRS "/home/blaz/develop/common/CoDiPack/include" CACHE STRING "Path to CoDiPack headers.")
set(CODIPACK_LIBRARIES "")
set(FADBADPP_INCLUDE_DIRS "/home/blaz/develop/common/FADBAD++" CACHE STRING "Path to FADBAD++ headers.")
set(FADBADPP_LIBRARIES "")
# Some useful variables:
set(CMAKE_SKIP_PREPROCESSED_SOURCE_RULES ON) # Skip *.i rules
set(CMAKE_SKIP_ASSEMBLY_SOURCE_RULES ON) # Skip *.s rules
# set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "Verbose makefiles.")
-1
View File
@@ -770,7 +770,6 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/examples/pumi \
@MFEM_SOURCE_DIR@/examples/hiop \
@MFEM_SOURCE_DIR@/examples/sundials \
@MFEM_SOURCE_DIR@/miniapps/adjoint \
@MFEM_SOURCE_DIR@/miniapps/common \
@MFEM_SOURCE_DIR@/miniapps/electromagnetics \
@MFEM_SOURCE_DIR@/miniapps/gslib \
+4 -8
View File
@@ -88,8 +88,8 @@ 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
* - <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
@@ -101,9 +101,6 @@ namespace mfem {
* and
* <a class="el" href="sundials_2ex16p_8cpp_source.html">16p</a>
* demonstrating the use of MFEM's \link sundials.hpp SUNDIALS classes\endlink
* - CVODES adjoint examples:
* <a class="el" href="cvsRoberts__ASAi__dns_8cpp_source.html">serial ODE system</a>,
* <a class="el" href="adjoint__advection__diffusion_8cpp_source.html">parallel advection-diffusion</a>
*
* <H4>PETSc Examples</H4>
* - Variants of Examples
@@ -143,9 +140,7 @@ namespace mfem {
* - <a class="el" href="tesla_8cpp_source.html">Tesla</a>: simple magnetostatics simulation code
* - <a class="el" href="maxwell_8cpp_source.html">Maxwell</a>: simple transient full-wave electromagnetics simulation code
* - <a class="el" href="joule_8cpp_source.html">Joule</a>: transient magnetics and Joule heating miniapp
* - <a class="el" href="classmfem_1_1navier_1_1NavierSolver.html">Navier</a>: solve the transient incompressible Navier-Stokes equations
* - <a class="el" href="mobius-strip_8cpp_source.html">Mobius Strip</a>: generate various Mobius strip-like meshes
* - <a class="el" href="mobius-strip_8cpp_source.html">Mobius Strip</a>: generate various Mobius strip-like meshes
* - <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
@@ -162,6 +157,7 @@ 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
*
+5 -11
View File
@@ -34,6 +34,8 @@ list(APPEND ALL_EXE_SRCS
ex25.cpp
ex26.cpp
ex27.cpp
ex51.cpp
ex71.cpp
)
if (MFEM_USE_MPI)
@@ -64,6 +66,7 @@ if (MFEM_USE_MPI)
ex25p.cpp
ex26p.cpp
ex27p.cpp
ex71p.cpp
)
endif()
@@ -91,7 +94,7 @@ foreach(SRC_FILE ${ALL_EXE_SRCS})
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
@@ -101,22 +104,13 @@ endforeach()
# If STRUMPACK is enabled, add a test run that uses it.
if (MFEM_USE_STRUMPACK)
add_test(NAME ex11p_strumpack_np=${MFEM_MPI_NP}
add_test(NAME ex11p_strumpack_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--strumpack"
${MPIEXEC_POSTFLAGS})
endif()
# If SuperLU_DIST is enabled, add a test run that uses it.
if (MFEM_USE_SUPERLU)
add_test(NAME ex11p_superlu_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--superlu"
${MPIEXEC_POSTFLAGS})
endif()
# Include the examples/sundials directory if SUNDIALS is enabled.
if (MFEM_USE_SUNDIALS)
add_subdirectory(sundials)
+32 -36
View File
@@ -34,8 +34,7 @@
// ex1 -pa -d raja-omp
// ex1 -pa -d occa-omp
// ex1 -pa -d ceed-cpu
// * ex1 -pa -d ceed-cuda
// ex1 -pa -d ceed-cuda:/gpu/cuda/shared
// ex1 -pa -d ceed-cuda
// ex1 -m ../data/beam-hex.mesh -pa -d cuda
// ex1 -m ../data/beam-tet.mesh -pa -d ceed-cpu
// ex1 -m ../data/beam-tet.mesh -pa -d ceed-cuda:/gpu/cuda/ref
@@ -103,8 +102,8 @@ int main(int argc, char *argv[])
// 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(mesh_file, 1, 1);
int dim = mesh.Dimension();
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
@@ -112,10 +111,10 @@ int main(int argc, char *argv[])
// elements.
{
int ref_levels =
(int)floor(log(50000./mesh.GetNE())/log(2.)/dim);
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
mesh->UniformRefinement();
}
}
@@ -123,70 +122,66 @@ int main(int argc, char *argv[])
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
bool delete_fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
delete_fec = true;
}
else if (mesh.GetNodes())
else if (mesh->GetNodes())
{
fec = mesh.GetNodes()->OwnFEC();
delete_fec = false;
fec = mesh->GetNodes()->OwnFEC();
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
fec = new H1_FECollection(order = 1, dim);
delete_fec = true;
}
FiniteElementSpace fespace(&mesh, fec);
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
cout << "Number of finite element unknowns: "
<< fespace.GetTrueVSize() << endl;
<< fespace->GetTrueVSize() << endl;
// 6. 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.
Array<int> ess_tdof_list;
if (mesh.bdr_attributes.Size())
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh.bdr_attributes.Max());
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 7. 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(&fespace);
LinearForm *b = new LinearForm(fespace);
ConstantCoefficient one(1.0);
b.AddDomainIntegrator(new DomainLFIntegrator(one));
b.Assemble();
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 8. 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(&fespace);
GridFunction x(fespace);
x = 0.0;
// 9. 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);
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a.AddDomainIntegrator(new DiffusionIntegrator(one));
BilinearForm *a = new BilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 10. 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(); }
a.Assemble();
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A->Height() << endl;
@@ -207,9 +202,9 @@ int main(int argc, char *argv[])
}
else // Jacobi preconditioning in partial assembly mode
{
if (UsesTensorBasis(fespace))
if (UsesTensorBasis(*fespace))
{
OperatorJacobiSmoother M(a, ess_tdof_list);
OperatorJacobiSmoother M(*a, ess_tdof_list);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
else
@@ -219,13 +214,13 @@ int main(int argc, char *argv[])
}
// 12. Recover the solution as a finite element grid function.
a.RecoverFEMSolution(X, b, x);
a->RecoverFEMSolution(X, *b, x);
// 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");
mesh_ofs.precision(8);
mesh.Print(mesh_ofs);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
@@ -237,14 +232,15 @@ int main(int argc, char *argv[])
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << mesh << x << flush;
sol_sock << "solution\n" << *mesh << x << flush;
}
// 15. Free the used memory.
if (delete_fec)
{
delete fec;
}
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete mesh;
return 0;
}
+36 -39
View File
@@ -32,8 +32,7 @@
// mpirun -np 4 ex1p -pa -d occa-cuda
// mpirun -np 4 ex1p -pa -d raja-omp
// mpirun -np 4 ex1p -pa -d ceed-cpu
// * mpirun -np 4 ex1p -pa -d ceed-cuda
// mpirun -np 4 ex1p -pa -d ceed-cuda:/gpu/cuda/shared
// mpirun -np 4 ex1p -pa -d ceed-cuda
// mpirun -np 4 ex1p -m ../data/beam-tet.mesh -pa -d ceed-cpu
//
// Description: This example code demonstrates the use of MFEM to define a
@@ -112,8 +111,8 @@ int main(int argc, char *argv[])
// 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(mesh_file, 1, 1);
int dim = mesh.Dimension();
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
@@ -121,23 +120,23 @@ int main(int argc, char *argv[])
// more than 10,000 elements.
{
int ref_levels =
(int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
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(MPI_COMM_WORLD, mesh);
mesh.Clear();
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();
pmesh->UniformRefinement();
}
}
@@ -145,16 +144,13 @@ int main(int argc, char *argv[])
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
bool delete_fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
delete_fec = true;
}
else if (pmesh.GetNodes())
else if (pmesh->GetNodes())
{
fec = pmesh.GetNodes()->OwnFEC();
delete_fec = false;
fec = pmesh->GetNodes()->OwnFEC();
if (myid == 0)
{
cout << "Using isoparametric FEs: " << fec->Name() << endl;
@@ -163,10 +159,9 @@ int main(int argc, char *argv[])
else
{
fec = new H1_FECollection(order = 1, dim);
delete_fec = true;
}
ParFiniteElementSpace fespace(&pmesh, fec);
HYPRE_Int size = fespace.GlobalTrueVSize();
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
@@ -177,44 +172,44 @@ int main(int argc, char *argv[])
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (pmesh.bdr_attributes.Size())
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 9. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (1,phi_i) where phi_i are the basis functions in fespace.
ParLinearForm b(&fespace);
ParLinearForm *b = new ParLinearForm(fespace);
ConstantCoefficient one(1.0);
b.AddDomainIntegrator(new DomainLFIntegrator(one));
b.Assemble();
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 10. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(&fespace);
ParGridFunction x(fespace);
x = 0.0;
// 11. Set up the parallel bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
ParBilinearForm a(&fespace);
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a.AddDomainIntegrator(new DiffusionIntegrator(one));
ParBilinearForm *a = new ParBilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 12. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a.EnableStaticCondensation(); }
a.Assemble();
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
// 13. Solve the linear system A X = B.
// * With full assembly, use the BoomerAMG preconditioner from hypre.
@@ -222,9 +217,9 @@ int main(int argc, char *argv[])
Solver *prec = NULL;
if (pa)
{
if (UsesTensorBasis(fespace))
if (UsesTensorBasis(*fespace))
{
prec = new OperatorJacobiSmoother(a, ess_tdof_list);
prec = new OperatorJacobiSmoother(*a, ess_tdof_list);
}
}
else
@@ -242,7 +237,7 @@ int main(int argc, char *argv[])
// 14. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a.RecoverFEMSolution(X, b, x);
a->RecoverFEMSolution(X, *b, x);
// 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".
@@ -253,7 +248,7 @@ int main(int argc, char *argv[])
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh.Print(mesh_ofs);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
@@ -268,14 +263,16 @@ int main(int argc, char *argv[])
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << x << flush;
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
if (delete_fec)
{
delete fec;
}
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete pmesh;
MPI_Finalize();
return 0;
+28 -37
View File
@@ -13,11 +13,6 @@
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2
// ex22 -m ../data/star.mesh -r 1 -o 2 -sigma 10.0
//
// With partial assembly:
// ex22 -m ../data/inline-quad.mesh -o 3 -p 1 -pa
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2 -pa
// ex22 -m ../data/star.mesh -r 1 -o 2 -sigma 10.0 -pa
//
// Description: This example code demonstrates the use of MFEM to define and
// solve simple complex-valued linear systems. It implements three
// variants of a damped harmonic oscillator:
@@ -81,7 +76,6 @@ int main(int argc, char *argv[])
bool visualization = 1;
bool herm_conv = true;
bool exact_sol = true;
bool pa = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -112,8 +106,6 @@ int main(int argc, char *argv[])
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.Parse();
if (!args.Good())
{
@@ -290,7 +282,6 @@ int main(int argc, char *argv[])
ConstantCoefficient negMassCoef(omega_ * omega_ * epsilon_);
SesquilinearForm *a = new SesquilinearForm(fespace, conv);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
switch (prob)
{
case 0:
@@ -327,8 +318,6 @@ int main(int argc, char *argv[])
// -Grad(a Div) - omega^2 b + omega c
//
BilinearForm *pcOp = new BilinearForm(fespace);
if (pa) { pcOp->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
switch (prob)
{
case 0:
@@ -359,8 +348,19 @@ int main(int argc, char *argv[])
Vector B, U;
a->FormLinearSystem(ess_tdof_list, u, b, A, U, B);
u = 0.0;
U = 0.0;
cout << "Size of linear system: " << A->Width() << endl << endl;
OperatorHandle PCOp;
pcOp->FormSystemMatrix(ess_tdof_list, PCOp);
{
ComplexSparseMatrix * Asp =
dynamic_cast<ComplexSparseMatrix*>(A.Ptr());
cout << "Size of linear system: "
<< 2 * Asp->real().Width() << endl << endl;
}
// 10. Define and apply a GMRES solver for AU=B with a block diagonal
// preconditioner based on the appropriate sparse smoother.
@@ -368,8 +368,8 @@ int main(int argc, char *argv[])
Array<int> blockOffsets;
blockOffsets.SetSize(3);
blockOffsets[0] = 0;
blockOffsets[1] = A->Height() / 2;
blockOffsets[2] = A->Height() / 2;
blockOffsets[1] = PCOp.Ptr()->Height();
blockOffsets[2] = PCOp.Ptr()->Height();
blockOffsets.PartialSum();
BlockDiagonalPreconditioner BDP(blockOffsets);
@@ -377,31 +377,22 @@ int main(int argc, char *argv[])
Operator * pc_r = NULL;
Operator * pc_i = NULL;
if (pa)
double s = 1.0;
switch (prob)
{
pc_r = new OperatorJacobiSmoother(*pcOp, ess_tdof_list);
case 0:
pc_r = new DSmoother(*PCOp.As<SparseMatrix>());
break;
case 1:
pc_r = new GSSmoother(*PCOp.As<SparseMatrix>());
s = -1.0;
break;
case 2:
pc_r = new DSmoother(*PCOp.As<SparseMatrix>());
break;
default: break; // This should be unreachable
}
else
{
OperatorHandle PCOp;
pcOp->SetDiagonalPolicy(mfem::Operator::DIAG_ONE);
pcOp->FormSystemMatrix(ess_tdof_list, PCOp);
switch (prob)
{
case 0:
pc_r = new DSmoother(*PCOp.As<SparseMatrix>());
break;
case 1:
pc_r = new GSSmoother(*PCOp.As<SparseMatrix>());
break;
case 2:
pc_r = new DSmoother(*PCOp.As<SparseMatrix>());
break;
default:
break; // This should be unreachable
}
}
double s = (prob != 1) ? 1.0 : -1.0;
pc_i = new ScaledOperator(pc_r,
(conv == ComplexOperator::HERMITIAN) ?
s:-s);
+28 -39
View File
@@ -13,11 +13,6 @@
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2 -p 2
// mpirun -np 4 ex22p -m ../data/star.mesh -o 2 -sigma 10.0
//
// With partial assembly:
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 1 -p 1 -pa
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 1 -p 2 -pa
// mpirun -np 4 ex22p -m ../data/star.mesh -o 2 -sigma 10.0 -pa
//
// Description: This example code demonstrates the use of MFEM to define and
// solve simple complex-valued linear systems. It implements three
// variants of a damped harmonic oscillator:
@@ -89,7 +84,6 @@ int main(int argc, char *argv[])
bool visualization = 1;
bool herm_conv = true;
bool exact_sol = true;
bool pa = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -122,8 +116,6 @@ int main(int argc, char *argv[])
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.Parse();
if (!args.Good())
{
@@ -323,7 +315,6 @@ int main(int argc, char *argv[])
ConstantCoefficient negMassCoef(omega_ * omega_ * epsilon_);
ParSesquilinearForm *a = new ParSesquilinearForm(fespace, conv);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
switch (prob)
{
case 0:
@@ -360,7 +351,6 @@ int main(int argc, char *argv[])
// -Grad(a Div) - omega^2 b + omega c
//
ParBilinearForm *pcOp = new ParBilinearForm(fespace);
if (pa) { pcOp->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
switch (prob)
{
case 0:
@@ -392,11 +382,19 @@ int main(int argc, char *argv[])
Vector B, U;
a->FormLinearSystem(ess_tdof_list, u, b, A, U, B);
u = 0.0;
U = 0.0;
OperatorHandle PCOp;
pcOp->FormSystemMatrix(ess_tdof_list, PCOp);
if (myid == 0)
{
ComplexHypreParMatrix * Ahyp =
dynamic_cast<ComplexHypreParMatrix*>(A.Ptr());
cout << "Size of linear system: "
<< 2 * fespace->GlobalTrueVSize() << endl << endl;
<< 2 * Ahyp->real().GetGlobalNumRows() << endl << endl;
}
// 12. Define and apply a parallel FGMRES solver for AU=B with a block
@@ -406,8 +404,8 @@ int main(int argc, char *argv[])
Array<int> blockTrueOffsets;
blockTrueOffsets.SetSize(3);
blockTrueOffsets[0] = 0;
blockTrueOffsets[1] = A->Height() / 2;
blockTrueOffsets[2] = A->Height() / 2;
blockTrueOffsets[1] = PCOp.Ptr()->Height();
blockTrueOffsets[2] = PCOp.Ptr()->Height();
blockTrueOffsets.PartialSum();
BlockDiagonalPreconditioner BDP(blockTrueOffsets);
@@ -415,34 +413,25 @@ int main(int argc, char *argv[])
Operator * pc_r = NULL;
Operator * pc_i = NULL;
if (pa)
switch (prob)
{
pc_r = new OperatorJacobiSmoother(*pcOp, ess_tdof_list);
}
else
{
OperatorHandle PCOp;
pcOp->FormSystemMatrix(ess_tdof_list, PCOp);
switch (prob)
{
case 0:
pc_r = new HypreBoomerAMG(*PCOp.As<HypreParMatrix>());
break;
case 1:
case 0:
pc_r = new HypreBoomerAMG(*PCOp.As<HypreParMatrix>());
break;
case 1:
pc_r = new HypreAMS(*PCOp.As<HypreParMatrix>(), fespace);
break;
case 2:
if (dim == 2 )
{
pc_r = new HypreAMS(*PCOp.As<HypreParMatrix>(), fespace);
break;
case 2:
if (dim == 2 )
{
pc_r = new HypreAMS(*PCOp.As<HypreParMatrix>(), fespace);
}
else
{
pc_r = new HypreADS(*PCOp.As<HypreParMatrix>(), fespace);
}
break;
default: break; // This should be unreachable
}
}
else
{
pc_r = new HypreADS(*PCOp.As<HypreParMatrix>(), fespace);
}
break;
default: break; // This should be unreachable
}
pc_i = new ScaledOperator(pc_r,
(conv == ComplexOperator::HERMITIAN) ?
+7 -86
View File
@@ -7,7 +7,6 @@
// 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/beam-hex.mesh -o 2 -pa -p 2
// ex24 -m ../data/escher.mesh
// ex24 -m ../data/escher.mesh -o 2
// ex24 -m ../data/fichera.mesh
@@ -25,13 +24,12 @@
// ex24 -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code illustrates usage of mixed finite element
// spaces, with three variants:
// spaces, with two variants:
//
// 1) (grad p, u) for p in H^1 tested against u in H(curl)
// 2) (curl v, u) for v in H(curl) tested against u in H(div), 3D
// 3) (div v, q) for v in H(div) tested against q in L_2
// 2) (div v, q) for v in H(div) tested against q in L_2
//
// Using different approaches, we project the gradient, curl, or
// Using different approaches, we project the gradient or
// divergence to the appropriate space.
//
// We recommend viewing examples 1, 3, and 5 before viewing this
@@ -47,11 +45,8 @@ using namespace mfem;
double p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
double div_gradp_exact(const Vector &x);
void v_exact(const Vector &x, Vector &v);
void curlv_exact(const Vector &x, Vector &cv);
int dim;
double freq = 1.0, kappa;
int main(int argc, char *argv[])
{
@@ -88,7 +83,6 @@ int main(int argc, char *argv[])
return 1;
}
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.
@@ -125,15 +119,10 @@ int main(int argc, char *argv[])
trial_fec = new H1_FECollection(order, dim);
test_fec = new ND_FECollection(order, dim);
}
else if (prob == 1)
{
trial_fec = new ND_FECollection(order, dim);
test_fec = new RT_FECollection(order-1, dim);
}
else
{
trial_fec = new RT_FECollection(order-1, dim);
test_fec = new L2_FECollection(order-1, dim);
trial_fec = new RT_FECollection(order - 1, dim);
test_fec = new L2_FECollection(order - 1, dim);
}
FiniteElementSpace trial_fes(mesh, trial_fec);
@@ -147,12 +136,6 @@ int main(int argc, char *argv[])
cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
cout << "Number of H1 finite element unknowns: " << trial_size << endl;
}
else if (prob == 1)
{
cout << "Number of Nedelec finite element unknowns: " << trial_size << endl;
cout << "Number of Raviart-Thomas finite element unknowns: " << test_size <<
endl;
}
else
{
cout << "Number of Raviart-Thomas finite element unknowns: "
@@ -167,18 +150,12 @@ int main(int argc, char *argv[])
GridFunction x(&test_fes);
FunctionCoefficient p_coef(p_exact);
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
VectorFunctionCoefficient v_coef(sdim, v_exact);
VectorFunctionCoefficient curlv_coef(sdim, curlv_exact);
FunctionCoefficient divgradp_coef(div_gradp_exact);
if (prob == 0)
{
gftrial.ProjectCoefficient(p_coef);
}
else if (prob == 1)
{
gftrial.ProjectCoefficient(v_coef);
}
else
{
gftrial.ProjectCoefficient(gradp_coef);
@@ -202,11 +179,6 @@ int main(int argc, char *argv[])
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorGradientIntegrator(one));
}
else if (prob == 1)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorCurlIntegrator(one));
}
else
{
a.AddDomainIntegrator(new MassIntegrator(one));
@@ -272,10 +244,6 @@ int main(int argc, char *argv[])
{
dlo.AddDomainInterpolator(new GradientInterpolator());
}
else if (prob == 1)
{
dlo.AddDomainInterpolator(new CurlInterpolator());
}
else
{
dlo.AddDomainInterpolator(new DivergenceInterpolator());
@@ -290,10 +258,6 @@ int main(int argc, char *argv[])
{
exact_proj.ProjectCoefficient(gradp_coef);
}
else if (prob == 1)
{
exact_proj.ProjectCoefficient(curlv_coef);
}
else
{
exact_proj.ProjectCoefficient(divgradp_coef);
@@ -312,21 +276,8 @@ int main(int argc, char *argv[])
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 if (prob == 1)
{
double errSol = x.ComputeL2Error(curlv_coef);
double errInterp = discreteInterpolant.ComputeL2Error(curlv_coef);
double errProj = exact_proj.ComputeL2Error(curlv_coef);
cout << "\n Solution of (E_h,w) = (curl v_h,w) for E_h and w in H(div): "
"|| E_h - curl v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Curl interpolant E_h = curl v_h in H(div): || E_h - curl v "
"||_{L_2} = " << errInterp << '\n' << endl;
cout << " Projection E_h of exact curl v in H(div): || E_h - curl v "
cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
"||_{L_2} = " << errProj << '\n' << endl;
}
else
@@ -344,7 +295,7 @@ int main(int argc, char *argv[])
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 "
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;
@@ -420,33 +371,3 @@ double div_gradp_exact(const Vector &x)
return 0.0;
}
void v_exact(const Vector &x, Vector &v)
{
if (dim == 3)
{
v(0) = sin(kappa * x(1));
v(1) = sin(kappa * x(2));
v(2) = sin(kappa * x(0));
}
else
{
v(0) = sin(kappa * x(1));
v(1) = sin(kappa * x(0));
if (x.Size() == 3) { v(2) = 0.0; }
}
}
void curlv_exact(const Vector &x, Vector &cv)
{
if (dim == 3)
{
cv(0) = -kappa * cos(kappa * x(2));
cv(1) = -kappa * cos(kappa * x(0));
cv(2) = -kappa * cos(kappa * x(1));
}
else
{
cv = 0.0;
}
}
+11 -93
View File
@@ -6,8 +6,7 @@
// 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 -pa -p 1
// mpirun -np 4 ex24p -m ../data/beam-hex.mesh -o 2 -pa -p 2
// 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
@@ -25,13 +24,12 @@
// mpirun -np 4 ex24p -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code illustrates usage of mixed finite element
// spaces, with three variants:
// spaces, with two variants:
//
// 1) (grad p, u) for p in H^1 tested against u in H(curl)
// 2) (curl v, u) for v in H(curl) tested against u in H(div), 3D
// 3) (div v, q) for v in H(div) tested against q in L_2
// 2) (div v, q) for v in H(div) tested against q in L_2
//
// Using different approaches, we project the gradient, curl, or
// Using different approaches, we project the gradient or
// divergence to the appropriate space.
//
// We recommend viewing examples 1, 3, and 5 before viewing this
@@ -47,11 +45,8 @@ using namespace mfem;
double p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
double div_gradp_exact(const Vector &x);
void v_exact(const Vector &x, Vector &v);
void curlv_exact(const Vector &x, Vector &cv);
int dim;
double freq = 1.0, kappa;
int main(int argc, char *argv[])
{
@@ -101,7 +96,6 @@ int main(int argc, char *argv[])
{
args.PrintOptions(cout);
}
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.
@@ -153,15 +147,10 @@ int main(int argc, char *argv[])
trial_fec = new H1_FECollection(order, dim);
test_fec = new ND_FECollection(order, dim);
}
else if (prob == 1)
{
trial_fec = new ND_FECollection(order, dim);
test_fec = new RT_FECollection(order-1, dim);
}
else
{
trial_fec = new RT_FECollection(order-1, dim);
test_fec = new L2_FECollection(order-1, dim);
trial_fec = new RT_FECollection(order - 1, dim);
test_fec = new L2_FECollection(order - 1, dim);
}
ParFiniteElementSpace trial_fes(pmesh, trial_fec);
@@ -177,12 +166,6 @@ int main(int argc, char *argv[])
cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
cout << "Number of H1 finite element unknowns: " << trial_size << endl;
}
else if (prob == 1)
{
cout << "Number of Nedelec finite element unknowns: " << trial_size << endl;
cout << "Number of Raviart-Thomas finite element unknowns: " << test_size <<
endl;
}
else
{
cout << "Number of Raviart-Thomas finite element unknowns: "
@@ -198,18 +181,12 @@ int main(int argc, char *argv[])
ParGridFunction x(&test_fes);
FunctionCoefficient p_coef(p_exact);
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
VectorFunctionCoefficient v_coef(sdim, v_exact);
VectorFunctionCoefficient curlv_coef(sdim, curlv_exact);
FunctionCoefficient divgradp_coef(div_gradp_exact);
if (prob == 0)
{
gftrial.ProjectCoefficient(p_coef);
}
else if (prob == 1)
{
gftrial.ProjectCoefficient(v_coef);
}
else
{
gftrial.ProjectCoefficient(gradp_coef);
@@ -233,11 +210,6 @@ int main(int argc, char *argv[])
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorGradientIntegrator(one));
}
else if (prob == 1)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorCurlIntegrator(one));
}
else
{
a.AddDomainIntegrator(new MassIntegrator(one));
@@ -321,10 +293,6 @@ int main(int argc, char *argv[])
{
dlo.AddDomainInterpolator(new GradientInterpolator());
}
else if (prob == 1)
{
dlo.AddDomainInterpolator(new CurlInterpolator());
}
else
{
dlo.AddDomainInterpolator(new DivergenceInterpolator());
@@ -339,10 +307,6 @@ int main(int argc, char *argv[])
{
exact_proj.ProjectCoefficient(gradp_coef);
}
else if (prob == 1)
{
exact_proj.ProjectCoefficient(curlv_coef);
}
else
{
exact_proj.ProjectCoefficient(divgradp_coef);
@@ -360,27 +324,11 @@ int main(int argc, char *argv[])
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 << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
"||_{L_2} = " << errProj << '\n' << endl;
}
}
else if (prob == 1)
{
double errSol = x.ComputeL2Error(curlv_coef);
double errInterp = discreteInterpolant.ComputeL2Error(curlv_coef);
double errProj = exact_proj.ComputeL2Error(curlv_coef);
if (myid == 0)
{
cout << "\n Solution of (E_h,w) = (curl v_h,w) for E_h and w in "
"H(div): || E_h - curl v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Curl interpolant E_h = curl v_h in H(div): || E_h - curl v "
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 curl v in H(div): || E_h - curl v "
cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
"||_{L_2} = " << errProj << '\n' << endl;
}
}
@@ -402,7 +350,7 @@ int main(int argc, char *argv[])
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;
"||_{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;
}
@@ -488,33 +436,3 @@ double div_gradp_exact(const Vector &x)
return 0.0;
}
void v_exact(const Vector &x, Vector &v)
{
if (dim == 3)
{
v(0) = sin(kappa * x(1));
v(1) = sin(kappa * x(2));
v(2) = sin(kappa * x(0));
}
else
{
v(0) = sin(kappa * x(1));
v(1) = sin(kappa * x(0));
if (x.Size() == 3) { v(2) = 0.0; }
}
}
void curlv_exact(const Vector &x, Vector &cv)
{
if (dim == 3)
{
cv(0) = -kappa * cos(kappa * x(2));
cv(1) = -kappa * cos(kappa * x(0));
cv(2) = -kappa * cos(kappa * x(1));
}
else
{
cv = 0.0;
}
}
+23 -15
View File
@@ -389,22 +389,27 @@ int main(int argc, char *argv[])
// applying any necessary transformations such as: assembly, eliminating
// boundary conditions, applying conforming constraints for
// non-conforming AMR, etc.
a.Assemble(0);
a.Assemble();
OperatorPtr A;
OperatorHandle Ah;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
a.FormLinearSystem(ess_tdof_list, x, b, Ah, X, B);
// 13. Solve using a direct or an iterative solver
// 13. Transform to monolithic SparseMatrix
SparseMatrix *A = Ah.As<ComplexSparseMatrix>()->GetSystemMatrix();
cout << "Size of linear system: " << A->Height() << endl;
// 14. Solve using a direct or an iterative solver
#ifdef MFEM_USE_SUITESPARSE
{
ComplexUMFPackSolver csolver(*A.As<ComplexSparseMatrix>());
csolver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
csolver.SetPrintLevel(1);
csolver.Mult(B, X);
UMFPackSolver solver(*A);
solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
solver.Mult(B, X);
}
#else
// 13a. Set up the Bilinear form a(.,.) for the preconditioner
// 14a. Set up the Bilinear form a(.,.) for the preconditioner
//
// In Comp
// Domain: 1/mu (Curl E, Curl F) + omega^2 * epsilon (E,F)
@@ -432,10 +437,10 @@ int main(int argc, char *argv[])
prec.Assemble();
OperatorPtr PCOpAh;
OperatorHandle PCOpAh;
prec.FormSystemMatrix(ess_tdof_list, PCOpAh);
// 13b. Define and apply a GMRES solver for AU=B with a block diagonal
// 14b. Define and apply a GMRES solver for AU=B with a block diagonal
// preconditioner based on the Gauss-Seidel sparse smoother.
Array<int> offsets(3);
offsets[0] = 0;
@@ -462,15 +467,17 @@ int main(int argc, char *argv[])
}
#endif
// 14. Recover the solution as a finite element grid function and compute the
// 15. Recover the solution as a finite element grid function and compute the
// errors if the exact solution is known.
a.RecoverFEMSolution(X, b, x);
// If exact is known compute the error
if (exact_known)
{
ComplexGridFunction x_gf(fespace);
VectorFunctionCoefficient E_ex_Re(dim, E_exact_Re);
VectorFunctionCoefficient E_ex_Im(dim, E_exact_Im);
x_gf.ProjectCoefficient(E_ex_Re, E_ex_Im);
int order_quad = max(2, 2 * order + 1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i = 0; i < Geometry::NumGeom; ++i)
@@ -499,7 +506,7 @@ int main(int argc, char *argv[])
<< sqrt(L2Error_Re*L2Error_Re + L2Error_Im*L2Error_Im) << "\n\n";
}
// 15. Save the refined mesh and the solution. This output can be viewed
// 16. Save the refined mesh and the solution. This output can be viewed
// later using GLVis: "glvis -m mesh -g sol".
{
ofstream mesh_ofs("ex25.mesh");
@@ -514,7 +521,7 @@ int main(int argc, char *argv[])
x.imag().Save(sol_i_ofs);
}
// 16. Send the solution by socket to a GLVis server.
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
// Define visualization keys for GLVis (see GLVis documentation)
@@ -565,7 +572,8 @@ int main(int argc, char *argv[])
}
}
// 17. Free the used memory.
// 18. Free the used memory.
delete A;
delete pml;
delete fespace;
delete fec;
+16 -7
View File
@@ -419,15 +419,21 @@ int main(int argc, char *argv[])
// constraints for non-conforming AMR, etc.
a.Assemble();
OperatorPtr Ah;
OperatorHandle Ah;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, Ah, X, B);
// 15. Solve using a direct or an iterative solver
// 15. Transform to monolithic HypreParMatrix
HypreParMatrix *A = Ah.As<ComplexHypreParMatrix>()->GetSystemMatrix();
if (myid == 0)
{
cout << "Size of linear system: " << A->GetGlobalNumRows() << endl;
}
// 16. Solve using a direct or an iterative solver
#ifdef MFEM_USE_SUPERLU
{
// Transform to monolithic HypreParMatrix
HypreParMatrix *A = Ah.As<ComplexHypreParMatrix>()->GetSystemMatrix();
SuperLURowLocMatrix SA(*A);
SuperLUSolver superlu(MPI_COMM_WORLD);
superlu.SetPrintStatistics(false);
@@ -435,9 +441,9 @@ int main(int argc, char *argv[])
superlu.SetColumnPermutation(superlu::PARMETIS);
superlu.SetOperator(SA);
superlu.Mult(B, X);
delete A;
}
#else
// 16a. Set up the parallel Bilinear form a(.,.) for the preconditioner
//
// In Comp
@@ -466,7 +472,7 @@ int main(int argc, char *argv[])
prec.Assemble();
OperatorPtr PCOpAh;
OperatorHandle PCOpAh;
prec.FormSystemMatrix(ess_tdof_list, PCOpAh);
// 16b. Define and apply a parallel GMRES solver for AU=B with a block
@@ -490,7 +496,7 @@ int main(int argc, char *argv[])
gmres.SetMaxIter(2000);
gmres.SetRelTol(1e-5);
gmres.SetAbsTol(0.0);
gmres.SetOperator(*Ah);
gmres.SetOperator(*A);
gmres.SetPreconditioner(BlockAMS);
gmres.Mult(B, X);
}
@@ -503,8 +509,10 @@ int main(int argc, char *argv[])
// If exact is known compute the error
if (exact_known)
{
ParComplexGridFunction x_gf(fespace);
VectorFunctionCoefficient E_ex_Re(dim, E_exact_Re);
VectorFunctionCoefficient E_ex_Im(dim, E_exact_Im);
x_gf.ProjectCoefficient(E_ex_Re, E_ex_Im);
int order_quad = max(2, 2 * order + 1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i = 0; i < Geometry::NumGeom; ++i)
@@ -621,6 +629,7 @@ int main(int argc, char *argv[])
}
// 20. Free the used memory.
delete A;
delete pml;
delete fespace;
delete fec;
+17 -36
View File
@@ -11,12 +11,6 @@
// ex5 -m ../data/escher.mesh
// ex5 -m ../data/fichera.mesh
//
// Device sample runs:
// ex5 -m ../data/star.mesh -pa -d cuda
// ex5 -m ../data/star.mesh -pa -d raja-cuda
// ex5 -m ../data/star.mesh -pa -d raja-omp
// ex5 -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code solves a simple 2D/3D mixed Darcy problem
// corresponding to the saddle point system
// k*u + grad p = f
@@ -56,7 +50,6 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/star.mesh";
int order = 1;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -66,8 +59,6 @@ int main(int argc, char *argv[])
"Finite element order (polynomial degree).");
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.");
@@ -79,18 +70,13 @@ int main(int argc, char *argv[])
}
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,
// 2. 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
// 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 10,000
// elements.
@@ -103,7 +89,7 @@ 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 *hdiv_coll(new RT_FECollection(order, dim));
FiniteElementCollection *l2_coll(new L2_FECollection(order, dim));
@@ -111,7 +97,7 @@ int main(int argc, char *argv[])
FiniteElementSpace *R_space = new FiniteElementSpace(mesh, hdiv_coll);
FiniteElementSpace *W_space = new FiniteElementSpace(mesh, l2_coll);
// 6. Define the BlockStructure of the problem, i.e. define the array of
// 5. Define the BlockStructure of the problem, i.e. define the array of
// offsets for each variable. The last component of the Array is the sum
// of the dimensions of each block.
Array<int> block_offsets(3); // number of variables + 1
@@ -126,7 +112,7 @@ int main(int argc, char *argv[])
std::cout << "dim(R+W) = " << block_offsets.Last() << "\n";
std::cout << "***********************************************************\n";
// 7. Define the coefficients, analytical solution, and rhs of the PDE.
// 6. Define the coefficients, analytical solution, and rhs of the PDE.
ConstantCoefficient k(1.0);
VectorFunctionCoefficient fcoeff(dim, fFun);
@@ -136,28 +122,25 @@ int main(int argc, char *argv[])
VectorFunctionCoefficient ucoeff(dim, uFun_ex);
FunctionCoefficient pcoeff(pFun_ex);
// 8. Allocate memory (x, rhs) for the analytical solution and the right hand
// 7. Allocate memory (x, rhs) for the analytical solution and the right hand
// side. Define the GridFunction u,p for the finite element solution and
// linear forms fform and gform for the right hand side. The data
// allocated by x and rhs are passed as a reference to the grid functions
// (u,p) and the linear forms (fform, gform).
MemoryType mt = device.GetMemoryType();
BlockVector x(block_offsets, mt), rhs(block_offsets, mt);
BlockVector x(block_offsets), rhs(block_offsets);
LinearForm *fform(new LinearForm);
fform->Update(R_space, rhs.GetBlock(0), 0);
fform->AddDomainIntegrator(new VectorFEDomainLFIntegrator(fcoeff));
fform->AddBoundaryIntegrator(new VectorFEBoundaryFluxLFIntegrator(fnatcoeff));
fform->Assemble();
fform->SyncAliasMemory(rhs);
LinearForm *gform(new LinearForm);
gform->Update(W_space, rhs.GetBlock(1), 0);
gform->AddDomainIntegrator(new DomainLFIntegrator(gcoeff));
gform->Assemble();
gform->SyncAliasMemory(rhs);
// 9. Assemble the finite element matrices for the Darcy operator
// 8. Assemble the finite element matrices for the Darcy operator
//
// D = [ M B^T ]
// [ B 0 ]
@@ -202,7 +185,7 @@ int main(int argc, char *argv[])
darcyOp.SetBlock(1,0, &B);
}
// 10. Construct the operators for preconditioner
// 9. Construct the operators for preconditioner
//
// P = [ diag(M) 0 ]
// [ 0 B diag(M)^-1 B^T ]
@@ -219,11 +202,10 @@ int main(int argc, char *argv[])
if (pa)
{
mVarf->AssembleDiagonal(Md);
auto Md_host = Md.HostRead();
Vector invMd(mVarf->Height());
for (int i=0; i<mVarf->Height(); ++i)
{
invMd(i) = 1.0 / Md_host[i];
invMd(i) = 1.0 / Md(i);
}
Vector BMBt_diag(bVarf->Height());
@@ -264,7 +246,7 @@ int main(int argc, char *argv[])
darcyPrec.SetDiagonalBlock(0, invM);
darcyPrec.SetDiagonalBlock(1, invS);
// 11. Solve the linear system with MINRES.
// 10. Solve the linear system with MINRES.
// Check the norm of the unpreconditioned residual.
int maxIter(1000);
double rtol(1.e-6);
@@ -281,7 +263,6 @@ int main(int argc, char *argv[])
solver.SetPrintLevel(1);
x = 0.0;
solver.Mult(rhs, x);
if (device.IsEnabled()) { x.HostRead(); }
chrono.Stop();
if (solver.GetConverged())
@@ -292,7 +273,7 @@ int main(int argc, char *argv[])
<< " iterations. Residual norm is " << solver.GetFinalNorm() << ".\n";
std::cout << "MINRES solver took " << chrono.RealTime() << "s. \n";
// 12. Create the grid functions u and p. Compute the L2 error norms.
// 11. Create the grid functions u and p. Compute the L2 error norms.
GridFunction u, p;
u.MakeRef(R_space, x.GetBlock(0), 0);
p.MakeRef(W_space, x.GetBlock(1), 0);
@@ -312,7 +293,7 @@ int main(int argc, char *argv[])
std::cout << "|| u_h - u_ex || / || u_ex || = " << err_u / norm_u << "\n";
std::cout << "|| p_h - p_ex || / || p_ex || = " << err_p / norm_p << "\n";
// 13. Save the mesh and the solution. This output can be viewed later using
// 12. Save the mesh and the solution. This output can be viewed later using
// GLVis: "glvis -m ex5.mesh -g sol_u.gf" or "glvis -m ex5.mesh -g
// sol_p.gf".
{
@@ -329,13 +310,13 @@ int main(int argc, char *argv[])
p.Save(p_ofs);
}
// 14. Save data in the VisIt format
// 13. Save data in the VisIt format
VisItDataCollection visit_dc("Example5", mesh);
visit_dc.RegisterField("velocity", &u);
visit_dc.RegisterField("pressure", &p);
visit_dc.Save();
// 15. Save data in the ParaView format
// 14. Save data in the ParaView format
ParaViewDataCollection paraview_dc("Example5", mesh);
paraview_dc.SetPrefixPath("ParaView");
paraview_dc.SetLevelsOfDetail(order);
@@ -347,7 +328,7 @@ int main(int argc, char *argv[])
paraview_dc.RegisterField("pressure",&p);
paraview_dc.Save();
// 16. Send the solution by socket to a GLVis server.
// 15. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
@@ -360,7 +341,7 @@ int main(int argc, char *argv[])
p_sock << "solution\n" << *mesh << p << "window_title 'Pressure'" << endl;
}
// 17. Free the used memory.
// 16. Free the used memory.
delete fform;
delete gform;
delete invM;
+629
View File
@@ -0,0 +1,629 @@
// MFEM Example 1
//
// Compile with: make ex1
//
// Sample runs: ex1 -m ../data/square-disc.mesh
// ex1 -m ../data/star.mesh
// ex1 -m ../data/star-mixed.mesh
// ex1 -m ../data/escher.mesh
// ex1 -m ../data/fichera.mesh
// ex1 -m ../data/fichera-mixed.mesh
// ex1 -m ../data/toroid-wedge.mesh
// 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
// ex1 -m ../data/star-mixed-p2.mesh -o 2
// ex1 -m ../data/disc-nurbs.mesh -o -1
// ex1 -m ../data/pipe-nurbs.mesh -o -1
// ex1 -m ../data/fichera-mixed-p2.mesh -o 2
// ex1 -m ../data/star-surf.mesh
// ex1 -m ../data/square-disc-surf.mesh
// ex1 -m ../data/inline-segment.mesh
// ex1 -m ../data/amr-quad.mesh
// ex1 -m ../data/amr-hex.mesh
// ex1 -m ../data/fichera-amr.mesh
// ex1 -m ../data/mobius-strip.mesh
// ex1 -m ../data/mobius-strip.mesh -o -1 -sc
//
// Device sample runs:
// ex1 -pa -d cuda
// ex1 -pa -d raja-cuda
// ex1 -pa -d occa-cuda
// ex1 -pa -d raja-omp
// ex1 -pa -d occa-omp
// ex1 -pa -d ceed-cpu
// ex1 -pa -d ceed-cuda
// ex1 -m ../data/beam-hex.mesh -pa -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.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include "../fem/adnonlininteg.hpp"
using namespace std;
namespace mfem{
class VolNonlinearForm: public NonlinearFormIntegrator
{
protected:
double eta;
double beta;
public:
VolNonlinearForm(double eta_, double beta_){
eta=eta_;
beta=beta_;}
virtual ~VolNonlinearForm(){ }
double Project(double inp)
{
// tanh projection - Wang&Lazarov&Sigmund2011
double a=std::tanh(eta*beta);
double b=std::tanh(beta*(1.0-eta));
double c=std::tanh(beta*(inp-eta));
double rez=(a+c)/(a+b);
return rez;
}
double ProjGrad(double inp)
{
double c=std::tanh(beta*(inp-eta));
double a=std::tanh(eta*beta);
double b=std::tanh(beta*(1.0-eta));
double rez=beta*(1.0-c*c)/(a+b);
return rez;
}
double ProjSec(double inp)
{
double c=std::tanh(beta*(inp-eta));
double a=std::tanh(eta*beta);
double b=std::tanh(beta*(1.0-eta));
double rez=-2.0*beta*beta*c*(1.0-c*c)/(a+b);
return rez;
}
virtual double GetElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const mfem::Vector & elfun) override
{
double energy=0.0;
int ndof = el.GetDof();
int ndim = el.GetDim();
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
mfem::Vector shapef(ndof);
double w;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
el.CalcShape(ip,shapef);
w= Project(shapef*elfun);
w= ip.weight * trans.Weight() * w;
energy = energy + w;
}
return energy;
}
virtual void AssembleElementVector(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const mfem::Vector & elfun,
mfem::Vector & elvect) override
{
int ndof = el.GetDof();
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
elvect.SetSize(ndof);
elvect=0.0;
mfem::Vector shapef(ndof);
double w;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
el.CalcShape(ip,shapef);
w= ProjGrad(shapef*elfun);
w= ip.weight * trans.Weight() * w;
elvect.Add(w,shapef);
}
}
virtual void AssembleElementGrad(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const mfem::Vector & elfun,
mfem::DenseMatrix & elmat) override
{
int ndof = el.GetDof();
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
elmat.SetSize(ndof);
elmat=0.0;
mfem::Vector shapef(ndof);
double w;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
el.CalcShape(ip,shapef);
w= ProjSec(shapef*elfun);
w= ip.weight * trans.Weight() * w;
AddMult_a_VVt(w, shapef, elmat);
}
}
};
class VolNonlinearFormADH:public ADNonlinearFormIntegratorH
{
private:
double eta;
double beta;
template<typename DType>
DType Project(DType inp)
{
// tanh projection - Wang&Lazarov&Sigmund2011
double a=std::tanh(eta*beta);
double b=std::tanh(beta*(1.0-eta));
DType c=tanh(beta*(inp-eta));
DType rez=(a+c)/(a+b);
return rez;
}
public:
VolNonlinearFormADH(double eta_, double beta_){
eta=eta_;
beta=beta_;
}
virtual ADFType ElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const ADFVector & elfun) override
{
ADFType rez=MyElementEnergy<ADFType,ADFVector>(el,trans,elfun);
return rez;
}
virtual ADSType ElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const ADSVector & elfun) override
{
return MyElementEnergy<ADSType,ADSVector>(el,trans,elfun);
}
template<typename MDType, typename MVType>
MDType MyElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const MVType & elfun)
{
MDType energy=MDType();
int ndof = el.GetDof();
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
mfem::Vector shapef(ndof);
MDType w;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
el.CalcShape(ip,shapef);
w= Project(elfun*shapef);
w= ip.weight * trans.Weight() * w;
energy = energy + w;
}
return energy;
}
virtual double ElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & Tr,
const mfem::Vector & elfun) override
{
return GetElementEnergy(el,Tr,elfun);
}
virtual double GetElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const mfem::Vector & elfun) override
{
double rez;
rez=MyElementEnergy<double,mfem::Vector>(el,trans,elfun);
return rez;
}
};
class VolQIntegratorJ: public ADQIntegratorJ
{
private:
template<typename DType>
DType Project(double eta, double beta, DType inp)
{
// tanh projection - Wang&Lazarov&Sigmund2011
double a=std::tanh(eta*beta);
double b=std::tanh(beta*(1.0-eta));
DType c=tanh(beta*(inp-eta));
DType rez=(a+c)/(a+b);
return rez;
}
template<typename DType>
DType ProjGrad(double eta, double beta, DType inp)
{
DType c=tanh(beta*(inp-eta));
DType a=tanh(eta*beta);
DType b=tanh(beta*(1.0-eta));
DType rez=beta*(1.0-c*c)/(a+b);
return rez;
}
public:
VolQIntegratorJ(){}
virtual ~VolQIntegratorJ(){}
template<typename MVType>
void MyQIntegratorDU(const mfem::Vector& vparam, MVType& uu, MVType& rr)
{
//implement all evaluations executed at integration point
double eta=vparam[0];
double beta=vparam[1];
rr.SetSize(1); //return the derivative of the projected value
rr[0]=ProjGrad(eta,beta,uu[0]);
return;
}
virtual void QIntegratorDU(const mfem::Vector& vparam, mfem::Vector& uu, mfem::Vector& rr) override
{
MyQIntegratorDU<mfem::Vector>(vparam,uu,rr);
}
virtual void QIntegratorDU(const mfem::Vector& vparam, ADFVector& uu, ADFVector& rr) override
{
MyQIntegratorDU<ADFVector>(vparam,uu,rr);
}
virtual double QIntegrator(const Vector &vparam, const Vector &uu) override
{
//implement all evaluations executed at integration point
double eta=vparam[0];
double beta=vparam[1];
double rez=Project(eta,beta,uu[0]);
return rez;
}
};
class VolNonlinearFormQJ: public NonlinearFormIntegrator
{
protected:
double eta;
double beta;
mfem::Vector vparam;
VolQIntegratorJ qint;
public:
VolNonlinearFormQJ(double eta_, double beta_){
eta=eta_;
beta=beta_;
vparam.SetSize(2);
vparam[0]=eta;
vparam[1]=beta;
}
virtual ~VolNonlinearFormQJ(){ }
virtual double GetElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const mfem::Vector & elfun) override
{
double energy=0.0;
int ndof = el.GetDof();
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
mfem::Vector shapef(ndof);
mfem::Vector uu(1);
double w;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
el.CalcShape(ip,shapef);
uu[0]= shapef*elfun;
w= qint.QIntegrator(vparam,uu);
w= ip.weight * trans.Weight() * w;
energy = energy + w;
}
return energy;
}
virtual void AssembleElementVector(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const mfem::Vector & elfun,
mfem::Vector & elvect) override
{
int ndof = el.GetDof();
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
elvect.SetSize(ndof);
elvect=0.0;
mfem::Vector shapef(ndof);
mfem::Vector uu(1);
mfem::Vector rr(1);
double w;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
el.CalcShape(ip,shapef);
uu[0]=shapef*elfun;
qint.QIntegratorDU(vparam,uu,rr);
w= ip.weight * trans.Weight() * rr[0];
elvect.Add(w,shapef);
}
}
virtual void AssembleElementGrad(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const mfem::Vector & elfun,
mfem::DenseMatrix & elmat) override
{
int ndof = el.GetDof();
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
elmat.SetSize(ndof);
elmat=0.0;
mfem::DenseMatrix jac(1,1);
mfem::Vector shapef(ndof);
mfem::Vector uu(1);
double w;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
el.CalcShape(ip,shapef);
uu[0]=shapef*elfun;
qint.QIntegratorDD(vparam,uu,jac);
w= ip.weight * trans.Weight() * jac(0,0);
AddMult_a_VVt(w, shapef, elmat);
}
}
};
}
double TFunc(const mfem::Vector& a){
double sca=4.0;
double rez=(std::sin(sca*a[0])*std::sin(sca*a[1])*std::sin(sca*a[2]))*0.5+0.5;
return rez;
}
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
mfem::OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.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.
mfem::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.
mfem::Mesh *mesh = new mfem::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(50000./mesh->GetNE())/log(2.)/dim);
ref_levels=1;
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a finite element space on the mesh. Here we use continuous
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
mfem::FiniteElementCollection *fec;
if (order > 0)
{
fec = new mfem::H1_FECollection(order, dim);
}
else if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
fec = new mfem::H1_FECollection(order = 1, dim);
}
mfem::FiniteElementSpace *fespace = new mfem::FiniteElementSpace(mesh, fec);
cout << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
mfem::NonlinearForm* nf0=new mfem::NonlinearForm(fespace);
mfem::NonlinearForm* nf1=new mfem::NonlinearForm(fespace);
mfem::FunctionCoefficient ifun(TFunc);
//create an input for the NonlinearForm
mfem::GridFunction* igf = new mfem::GridFunction(fespace);
igf->ProjectCoefficient(ifun);
std::cout << "Size of the grid function igf:"<<igf->Size()<<std::endl;
mfem::Vector* resv0=new mfem::Vector(fespace->GetTrueVSize());
mfem::Vector* resv1=new mfem::Vector(fespace->GetTrueVSize());
mfem::Vector* stat=new mfem::Vector(fespace->GetTrueVSize());
igf->GetTrueDofs(*stat);
//compute the energy - the total volume above 0.5
nf0->AddDomainIntegrator(new mfem::VolNonlinearForm(0.5,8.0));
//nf1->AddDomainIntegrator(new mfem::VolNonlinearFormADH(0.5,8.0));
nf1->AddDomainIntegrator(new mfem::VolNonlinearFormQJ(0.5,8.0));
double vol0=nf0->GetEnergy(*stat);
double vol1=nf1->GetEnergy(*stat);
std::cout<<"The total volume is:("<<vol0<<","<<vol1<<")"<<std::endl;
nf0->Mult(*stat,*resv0);
nf1->Mult(*stat,*resv1);
//project back the gradients to a grid function
mfem::GridFunction* ggf0=new mfem::GridFunction(fespace);
ggf0->SetFromTrueDofs(*resv0);
mfem::GridFunction* ggf1=new mfem::GridFunction(fespace);
ggf1->SetFromTrueDofs(*resv1);
resv0->Add(-1.0,*resv1);
std::cout<<"Norm|v_1-v_0|="<<resv0->Norml2()<<std::endl;
mfem::Operator& grad0(nf0->GetGradient(*stat));
mfem::SparseMatrix* spmat0=dynamic_cast<mfem::SparseMatrix*>(&grad0);
mfem::Operator& grad1(nf1->GetGradient(*stat));
mfem::SparseMatrix* spmat1=dynamic_cast<mfem::SparseMatrix*>(&grad1);
std::cout<<"Norm mat1="<<spmat0->MaxNorm()<<" mat2="<<spmat1->MaxNorm()<<std::endl;
spmat0->Add(-1.0,*spmat1);
std::cout<<"Norm diff"<<spmat0->MaxNorm()<<std::endl;
{
std::fstream mstr;
mstr.open("mat.dat",std::ios::out);
spmat0->PrintMatlab(mstr);
mstr.close();
}
mfem::ParaViewDataCollection *dacol=new mfem::ParaViewDataCollection("IGF_OUT",mesh);
dacol->SetLevelsOfDetail(2);
dacol->SetCycle(1);
dacol->SetTime(0.0); // set the time
dacol->RegisterField("density",igf);
dacol->RegisterField("grads0",ggf0);
dacol->RegisterField("grads1",ggf1);
dacol->Save();
delete dacol;
delete ggf0;
delete ggf1;
delete stat;
delete resv0;
delete resv1;
delete igf;
delete nf0;
delete nf1;
delete fespace;
delete fec;
delete mesh;
return 0;
}
+21 -42
View File
@@ -11,12 +11,6 @@
// mpirun -np 4 ex5p -m ../data/escher.mesh
// mpirun -np 4 ex5p -m ../data/fichera.mesh
//
// Device sample runs:
// mpirun -np 4 ex5p -m ../data/star.mesh -r 2 -pa -d cuda
// mpirun -np 4 ex5p -m ../data/star.mesh -r 2 -pa -d raja-cuda
// mpirun -np 4 ex5p -m ../data/star.mesh -r 2 -pa -d raja-omp
// mpirun -np 4 ex5p -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code solves a simple 2D/3D mixed Darcy problem
// corresponding to the saddle point system
// k*u + grad p = f
@@ -66,7 +60,6 @@ int main(int argc, char *argv[])
int order = 1;
bool par_format = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
bool adios2 = false;
@@ -82,8 +75,6 @@ int main(int argc, char *argv[])
"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(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -105,18 +96,13 @@ int main(int argc, char *argv[])
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
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 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 10,000 elements, unless the user specifies it as input.
@@ -132,7 +118,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.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
@@ -145,7 +131,7 @@ int main(int argc, char *argv[])
}
}
// 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 *hdiv_coll(new RT_FECollection(order, dim));
FiniteElementCollection *l2_coll(new L2_FECollection(order, dim));
@@ -165,7 +151,7 @@ int main(int argc, char *argv[])
std::cout << "***********************************************************\n";
}
// 8. Define the two BlockStructure of the problem. block_offsets is used
// 7. Define the two BlockStructure of the problem. block_offsets is used
// for Vector based on dof (like ParGridFunction or ParLinearForm),
// block_trueOffstes is used for Vector based on trueDof (HypreParVector
// for the rhs and solution of the linear system). The offsets computed
@@ -182,7 +168,7 @@ int main(int argc, char *argv[])
block_trueOffsets[2] = W_space->TrueVSize();
block_trueOffsets.PartialSum();
// 9. Define the coefficients, analytical solution, and rhs of the PDE.
// 8. Define the coefficients, analytical solution, and rhs of the PDE.
ConstantCoefficient k(1.0);
VectorFunctionCoefficient fcoeff(dim, fFun);
@@ -192,30 +178,25 @@ int main(int argc, char *argv[])
VectorFunctionCoefficient ucoeff(dim, uFun_ex);
FunctionCoefficient pcoeff(pFun_ex);
// 10. Define the parallel grid function and parallel linear forms, solution
// vector and rhs.
MemoryType mt = device.GetMemoryType();
BlockVector x(block_offsets, mt), rhs(block_offsets, mt);
BlockVector trueX(block_trueOffsets, mt), trueRhs(block_trueOffsets, mt);
// 9. Define the parallel grid function and parallel linear forms, solution
// vector and rhs.
BlockVector x(block_offsets), rhs(block_offsets);
BlockVector trueX(block_trueOffsets), trueRhs(block_trueOffsets);
ParLinearForm *fform(new ParLinearForm);
fform->Update(R_space, rhs.GetBlock(0), 0);
fform->AddDomainIntegrator(new VectorFEDomainLFIntegrator(fcoeff));
fform->AddBoundaryIntegrator(new VectorFEBoundaryFluxLFIntegrator(fnatcoeff));
fform->Assemble();
fform->SyncAliasMemory(rhs);
fform->ParallelAssemble(trueRhs.GetBlock(0));
trueRhs.GetBlock(0).SyncAliasMemory(trueRhs);
ParLinearForm *gform(new ParLinearForm);
gform->Update(W_space, rhs.GetBlock(1), 0);
gform->AddDomainIntegrator(new DomainLFIntegrator(gcoeff));
gform->Assemble();
gform->SyncAliasMemory(rhs);
gform->ParallelAssemble(trueRhs.GetBlock(1));
trueRhs.GetBlock(1).SyncAliasMemory(trueRhs);
// 11. Assemble the finite element matrices for the Darcy operator
// 10. Assemble the finite element matrices for the Darcy operator
//
// D = [ M B^T ]
// [ B 0 ]
@@ -268,7 +249,7 @@ int main(int argc, char *argv[])
darcyOp->SetBlock(1,0, B);
}
// 12. Construct the operators for preconditioner
// 11. Construct the operators for preconditioner
//
// P = [ diag(M) 0 ]
// [ 0 B diag(M)^-1 B^T ]
@@ -285,11 +266,10 @@ int main(int argc, char *argv[])
{
Md_PA.SetSize(R_space->GetTrueVSize());
mVarf->AssembleDiagonal(Md_PA);
auto Md_host = Md_PA.HostRead();
Vector invMd(Md_PA.Size());
for (int i=0; i<Md_PA.Size(); ++i)
{
invMd(i) = 1.0 / Md_host[i];
invMd(i) = 1.0 / Md_PA(i);
}
Vector BMBt_diag(W_space->GetTrueVSize());
@@ -322,7 +302,7 @@ int main(int argc, char *argv[])
darcyPr->SetDiagonalBlock(0, invM);
darcyPr->SetDiagonalBlock(1, invS);
// 13. Solve the linear system with MINRES.
// 12. Solve the linear system with MINRES.
// Check the norm of the unpreconditioned residual.
int maxIter(pa ? 1000 : 500);
double rtol(1.e-6);
@@ -339,7 +319,6 @@ int main(int argc, char *argv[])
solver.SetPrintLevel(verbose);
trueX = 0.0;
solver.Mult(trueRhs, trueX);
if (device.IsEnabled()) { trueX.HostRead(); }
chrono.Stop();
if (verbose)
@@ -353,7 +332,7 @@ int main(int argc, char *argv[])
std::cout << "MINRES solver took " << chrono.RealTime() << "s. \n";
}
// 14. Extract the parallel grid function corresponding to the finite element
// 13. Extract the parallel grid function corresponding to the finite element
// approximation X. This is the local solution on each processor. Compute
// L2 error norms.
ParGridFunction *u(new ParGridFunction);
@@ -381,7 +360,7 @@ int main(int argc, char *argv[])
std::cout << "|| p_h - p_ex || / || p_ex || = " << err_p / norm_p << "\n";
}
// 15. Save the refined mesh and the solution in parallel. This output can be
// 14. 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, u_name, p_name;
@@ -402,7 +381,7 @@ int main(int argc, char *argv[])
p->Save(p_ofs);
}
// 16. Save data in the VisIt format
// 15. Save data in the VisIt format
VisItDataCollection visit_dc("Example5-Parallel", pmesh);
visit_dc.RegisterField("velocity", u);
visit_dc.RegisterField("pressure", p);
@@ -411,7 +390,7 @@ int main(int argc, char *argv[])
DataCollection::PARALLEL_FORMAT);
visit_dc.Save();
// 17. Save data in the ParaView format
// 16. Save data in the ParaView format
ParaViewDataCollection paraview_dc("Example5P", pmesh);
paraview_dc.SetPrefixPath("ParaView");
paraview_dc.SetLevelsOfDetail(order);
@@ -423,7 +402,7 @@ int main(int argc, char *argv[])
paraview_dc.RegisterField("pressure",p);
paraview_dc.Save();
// 18. Optionally output a BP (binary pack) file using ADIOS2. This can be
// 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)
@@ -443,7 +422,7 @@ int main(int argc, char *argv[])
}
#endif
// 19. Send the solution by socket to a GLVis server.
// 18. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
@@ -463,7 +442,7 @@ int main(int argc, char *argv[])
<< endl;
}
// 20. Free the used memory.
// 19. Free the used memory.
delete fform;
delete gform;
delete u;
+1 -1
View File
@@ -20,7 +20,7 @@
// ex6 -pa -d occa-cuda
// ex6 -pa -d raja-omp
// ex6 -pa -d ceed-cpu
// * ex6 -pa -d ceed-cuda
// * ex6 -pa -d ceed-cuda
// ex6 -pa -d ceed-cuda:/gpu/cuda/shared
//
// Description: This is a version of Example 1 with a simple adaptive mesh
+1 -1
View File
@@ -20,7 +20,7 @@
// mpirun -np 4 ex6p -pa -d occa-cuda
// mpirun -np 4 ex6p -pa -d raja-omp
// mpirun -np 4 ex6p -pa -d ceed-cpu
// * mpirun -np 4 ex6p -pa -d ceed-cuda
// * mpirun -np 4 ex6p -pa -d ceed-cuda
// mpirun -np 4 ex6p -pa -d ceed-cuda:/gpu/cuda/shared
//
// Description: This is a version of Example 1 with a simple adaptive mesh
+349
View File
@@ -0,0 +1,349 @@
// MFEM Example 71 - Serial Version
//
// Compile with: make ex71
//
// Sample runs:
// ex71 -m ../data/beam-quad.mesh
// ex71 -m ../data/beam-tri.mesh
// ex71 -m ../data/beam-hex.mesh
// ex71 -m ../data/beam-tet.mesh
// ex71 -m ../data/beam-wedge.mesh
//
// Description: This examples solves a quasi-static nonlinear
// pLaplacian problem with zero Dirichlet boundary
// conditions applied on all defined boundaries
//
// The example demonstrates the use of nonlinear operators
// combined with automatic differentiation (AD). The definitions
// of the integrators are written in the ex71.hpp.
// Selecting integrator=0 will use handcoded integrator.
// Selecting integrator=1 will utilize AD integrator.
// The AD integrator can be modifief to use ADQFunctionJ
// or ADQFunctionH by overwritting the class type of qint,
// i.e., pLapIntegrandJ or pLapIntegrandH.
//
// qint (the integrand) is a function which is evaluated
// at every integration point. For implementations utilizing
// ADQFunctionJ, the user has to implement the function and the
// residual evaluation - all virtual methods. The Jacobian of
// the residual is evaluated using AD
//
// For implementations utilizing ADQFunctionH, the user has
// to implement only the function evaluation (preferebaly as
// a template) and the first derivative (the residual) and the
// second derivatives (the Hessian) are evaluated using AD.
//
// We recommend viewing examples 1 and 19, before viewing this
// example.
#include "ex71.hpp"
#undef MFEM_USE_SUITESPARSE
int main(int argc, char *argv[])
{
// 1. Parse command-line options
const char *mesh_file = "../data/beam-tet.mesh";
int ser_ref_levels = 3;
int order = 1;
bool visualization = true;
double newton_rel_tol = 1e-4;
double newton_abs_tol = 1e-6;
int newton_iter = 500;
int print_level = 0;
double pp = 2.0;
int integrator=0;
mfem::StopWatch* timer=new mfem::StopWatch();
mfem::OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&newton_rel_tol, "-rel", "--relative-tolerance",
"Relative tolerance for the Newton solve.");
args.AddOption(&newton_abs_tol, "-abs", "--absolute-tolerance",
"Absolute tolerance for the Newton solve.");
args.AddOption(&newton_iter, "-it", "--newton-iterations",
"Maximum iterations for the Newton solve.");
args.AddOption(&pp, "-pp", "--power-parameter",
"Power parameter (>=2.0) for the p-Laplacian.");
args.AddOption((&print_level),"-prt","--print-level",
"Print level.");
args.AddOption(&integrator, "-int","--integrator",
"Integrator 0: standard; 1: AD uaing energy; 2: AD using gradients");
args.Parse();
if (!args.Good())
{
args.PrintUsage(std::cout);
return 1;
}
args.PrintOptions(std::cout);
// 2. Read the (serial) mesh from the given mesh file.
mfem::Mesh *mesh = new mfem::Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Refine the mesh in serial to increase the resolution. In this example
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
// a command-line parameter.
for (int lev = 0; lev < ser_ref_levels; lev++)
{
mesh->UniformRefinement();
}
// 4. Define the power parameter for the p-Laplacian and all other
// coefficients
mfem::ConstantCoefficient c_pp(pp);
mfem::ConstantCoefficient load(1.000000000);
mfem::ConstantCoefficient c_ee(0.000000001);
// 5. Define the finite element spaces for the solution
mfem::H1_FECollection fec(order,dim);
mfem::FiniteElementSpace fespace(mesh,&fec,1,mfem::Ordering::byVDIM);
int glob_size=fespace.GetTrueVSize();
std::cout << "Number of finite element unknowns: " << glob_size << std::endl;
// 6. Define the Dirichlet conditions
mfem::Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
// 7. Define the nonlinear form
mfem::NonlinearForm* nf=new mfem::NonlinearForm(&fespace);
// 8. Define the solution vector x
mfem::GridFunction x(&fespace);
x = 0.0;
mfem::Vector tv(fespace.GetTrueVSize());
mfem::Vector sv(fespace.GetTrueVSize());
tv=0.0;
sv=0.0;
// 9. Define ParaView DataCollection
mfem::ParaViewDataCollection *dacol=new mfem::ParaViewDataCollection("pLap",mesh);
dacol->SetLevelsOfDetail(order);
dacol->RegisterField("sol",&x);
// 11. Set domain integrators - start with linear diffusion
{
// the default power coefficient is 2.0
mfem::ConstantCoefficient lpp(2.0);
if(integrator==0)
{
nf->AddDomainIntegrator(new mfem::pLaplace(lpp,c_ee,load));
}else
if(integrator==1)
{
nf->AddDomainIntegrator(new mfem::pLaplaceAD(lpp,c_ee,load));
}
nf->SetEssentialBC(ess_bdr);
// compute the energy
double energy=nf->GetEnergy(tv);
std::cout<<"[2] The total energy of the system is E="<<energy<<std::endl;
// time the assembly
timer->Clear();
timer->Start();
mfem::Operator &op=nf->GetGradient(sv);
timer->Stop();
std::cout<<"[2] The assembly time is: "<<timer->RealTime()<<std::endl;
mfem::Solver *prec;
#ifdef MFEM_USE_SUITESPARSE
prec=new mfem::UMFPackSolver();
#else
prec=new mfem::GSSmoother();
#endif
mfem::CGSolver *j_pcg = new mfem::CGSolver();
j_pcg->SetRelTol(1e-7);
j_pcg->SetAbsTol(1e-15);
j_pcg->SetMaxIter(500);
j_pcg->SetPrintLevel(print_level);
j_pcg->SetPreconditioner(*prec);
mfem::NewtonSolver* ns;
ns=new mfem::NewtonSolver();
ns->iterative_mode = true;
ns->SetSolver(*j_pcg);
ns->SetOperator(*nf);
ns->SetPrintLevel(print_level);
ns->SetRelTol(1e-6);
ns->SetAbsTol(1e-12);
ns->SetMaxIter(10);
//solve the problem
timer->Clear();
timer->Start();
ns->Mult(tv, sv);
timer->Stop();
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;
energy=nf->GetEnergy(sv);
std::cout<<"[pp=2] The total energy of the system is E="<<energy<<std::endl;
delete ns;
delete j_pcg;
delete prec;
x.SetFromTrueDofs(sv);
dacol->SetTime(2.0);
dacol->SetCycle(2);
dacol->Save();
}
// 12. Continue with powers higher than 2
for(int i=3;i<pp;i++)
{
delete nf;
nf=new mfem::NonlinearForm(&fespace);
mfem::ConstantCoefficient lpp((double)i);
if(integrator==0)
{
nf->AddDomainIntegrator(new mfem::pLaplace(lpp,c_ee,load));
}else
if(integrator==1)
{
nf->AddDomainIntegrator(new mfem::pLaplaceAD(lpp,c_ee,load));
}
nf->SetEssentialBC(ess_bdr);
// compute the energy
double energy=nf->GetEnergy(sv);
std::cout<<"[pp="<<i<<"] The total energy of the system is E="<<energy<<std::endl;
// time the assembly
timer->Clear();
timer->Start();
mfem::Operator &op=nf->GetGradient(sv);
timer->Stop();
std::cout<<"[pp="<<i<<"] The assembly time is: "<<timer->RealTime()<<std::endl;
mfem::Solver *prec;
#ifdef MFEM_USE_SUITESPARSE
prec=new mfem::UMFPackSolver();
#else
prec=new mfem::GSSmoother();
#endif
mfem::CGSolver *j_pcg = new mfem::CGSolver();
j_pcg->SetRelTol(1e-7);
j_pcg->SetAbsTol(1e-15);
j_pcg->SetMaxIter(500);
j_pcg->SetPrintLevel(print_level);
j_pcg->SetPreconditioner(*prec);
mfem::NewtonSolver* ns;
ns=new mfem::NewtonSolver();
ns->iterative_mode = true;
ns->SetSolver(*j_pcg);
ns->SetOperator(*nf);
ns->SetPrintLevel(print_level);
ns->SetRelTol(1e-6);
ns->SetAbsTol(1e-12);
ns->SetMaxIter(10);
//solve the problem
timer->Clear();
timer->Start();
ns->Mult(tv, sv);
timer->Stop();
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;
energy=nf->GetEnergy(sv);
std::cout<<"[pp="<<i<<"] The total energy of the system is E="<<energy<<std::endl;
delete ns;
delete j_pcg;
delete prec;
x.SetFromTrueDofs(sv);
dacol->SetTime(i);
dacol->SetCycle(i);
dacol->Save();
}
// 13. Continue with the final power
if( std::abs(pp-2.0) > std::numeric_limits<double>::epsilon())
{
delete nf;
nf=new mfem::NonlinearForm(&fespace);
if(integrator==0)
{
nf->AddDomainIntegrator(new mfem::pLaplace(c_pp,c_ee,load));
}else
if(integrator==1)
{
nf->AddDomainIntegrator(new mfem::pLaplaceAD(c_pp,c_ee,load));
}
nf->SetEssentialBC(ess_bdr);
// compute the energy
double energy=nf->GetEnergy(sv);
std::cout<<"[pp="<<pp<<"] The total energy of the system is E="<<energy<<std::endl;
// time the assembly
timer->Clear();
timer->Start();
mfem::Operator &op=nf->GetGradient(sv);
timer->Stop();
std::cout<<"[pp="<<pp<<"] The assembly time is: "<<timer->RealTime()<<std::endl;
mfem::Solver *prec;
#ifdef MFEM_USE_SUITESPARSE
prec=new mfem::UMFPackSolver();
#else
prec=new mfem::GSSmoother();
#endif
mfem::CGSolver *j_pcg = new mfem::CGSolver();
j_pcg->SetRelTol(1e-7);
j_pcg->SetAbsTol(1e-15);
j_pcg->SetMaxIter(500);
j_pcg->SetPrintLevel(print_level);
j_pcg->SetPreconditioner(*prec);
mfem::NewtonSolver* ns;
ns=new mfem::NewtonSolver();
ns->iterative_mode = true;
ns->SetSolver(*j_pcg);
ns->SetOperator(*nf);
ns->SetPrintLevel(print_level);
ns->SetRelTol(1e-6);
ns->SetAbsTol(1e-12);
ns->SetMaxIter(10);
//solve the problem
timer->Clear();
timer->Start();
ns->Mult(tv, sv);
timer->Stop();
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;
energy=nf->GetEnergy(sv);
std::cout<<"[pp="<<pp<<"] The total energy of the system is E="<<energy<<std::endl;
delete ns;
delete j_pcg;
delete prec;
x.SetFromTrueDofs(sv);
dacol->SetTime(pp);
if(pp<2.0)
{
dacol->SetCycle(std::floor(pp));
}
else
{
dacol->SetCycle(std::ceil(pp));
}
dacol->Save();
}
// 19. Free the used memory
delete dacol;
delete nf;
delete mesh;
delete timer;
return 0;
}
+619
View File
@@ -0,0 +1,619 @@
// shared implementation ex71p/ex71 for the AD integrands and
// the handconded integrators
#ifndef EXAMPLE71_H
#define EXAMPLE71_H
#include "mfem.hpp"
#include <memory>
#include <iostream>
#include <fstream>
namespace mfem {
class pLapIntegrandJ: public ADQFunctionJ
{
private:
template<typename DType, typename MVType>
void MyQFunctionDU(const mfem::Vector& vparam, MVType& uu, MVType& rr)
{
double pp=vparam[0];
double ee=vparam[1];
double ff=vparam[2];
DType norm2=uu[0]*uu[0]+uu[1]*uu[1]+uu[2]*uu[2];
DType tvar=pow(ee*ee+norm2,(pp-2.0)/2.0);
rr[0]=tvar*uu[0];
rr[1]=tvar*uu[1];
rr[2]=tvar*uu[2];
rr[3]=-ff;
}
public:
pLapIntegrandJ():ADQFunctionJ(4){} //the residual vector rr has size of 4 elements
~pLapIntegrandJ(){}
virtual double QFunction(const mfem::Vector &vparam,const mfem::Vector &uu) override
{
double pp=vparam[0];
double ee=vparam[1];
double ff=vparam[2];
double u=uu[3];
double norm2=uu[0]*uu[0]+uu[1]*uu[1]+uu[2]*uu[2];
double rez= pow(ee*ee+norm2,pp/2.0)/pp-ff*u;
return rez;
}
virtual void QFunctionDU(const mfem::Vector& vparam, mfem::Vector& uu, mfem::Vector& rr) override
{
MyQFunctionDU<double,mfem::Vector>(vparam,uu,rr);
}
virtual void QFunctionDU(const mfem::Vector &vparam, ADFVector &uu, ADFVector &rr) override
{
MyQFunctionDU<ADFType,ADFVector>(vparam,uu,rr);
}
};
class pLapIntegrandH: public ADQFunctionH
{
private:
//MVType - vector type taking one of the following
// mfem::Vector - scalar double
// ADFVector - scalar ADFType
// ADSVector - scalar ADSType
template<typename DType, typename MVType>
DType MyQFunction(const mfem::Vector& vparam, MVType& uu)
{
double pp=vparam[0];
double ee=vparam[1];
double ff=vparam[2];
DType u=uu[3];
DType norm2=uu[0]*uu[0]+uu[1]*uu[1]+uu[2]*uu[2];
DType rez= pow(ee*ee+norm2,pp/2.0)/pp-ff*u;
return rez;
}
public:
pLapIntegrandH(){}
virtual ~pLapIntegrandH(){}
virtual double QFunction(const mfem::Vector &vparam,const mfem::Vector &uu) override
{
double rez=MyQFunction<double,const mfem::Vector>(vparam,uu);
return rez;
}
virtual ADFType QFunction(const mfem::Vector &vparam, ADFVector& uu) override
{
ADFType rez=MyQFunction<ADFType,ADFVector>(vparam,uu);
return rez;
}
virtual ADSType QFunction(const mfem::Vector &vparam, ADSVector& uu) override
{
ADSType rez=MyQFunction<ADSType,ADSVector>(vparam,uu);
return rez;
}
};
class pLaplaceAD: public mfem::NonlinearFormIntegrator
{
protected:
mfem::Coefficient* pp;
mfem::Coefficient* coeff;
mfem::Coefficient* load;
pLapIntegrandJ qint;
public:
pLaplaceAD()
{
coeff=nullptr;
pp=nullptr;
}
pLaplaceAD(mfem::Coefficient& pp_):pp(&pp_), coeff(nullptr), load(nullptr)
{
}
pLaplaceAD(mfem::Coefficient &pp_,mfem::Coefficient& q, mfem::Coefficient& ld_): pp(&pp_), coeff(&q), load(&ld_)
{
}
virtual ~pLaplaceAD()
{
}
virtual double GetElementEnergy(const mfem::FiniteElement &el, mfem::ElementTransformation &trans, const mfem::Vector &elfun) override
{
double energy=0.0;
int ndof = el.GetDof();
int ndim = el.GetDim();
int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
mfem::Vector shapef(ndof);
mfem::DenseMatrix dshape_iso(ndof,ndim);
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
mfem::Vector grad(spaceDim);
mfem::Vector vparam(3);//[power, epsilon, load]
mfem::Vector uu(4);//[diff_x,diff_y,diff_z,u]
uu=0.0;
vparam[0]=2.0; //default power
vparam[1]=1e-8; //default epsilon
vparam[2]=1.0; //default load
double w;
double detJ;
for(int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w*w);
w = ip.weight *w;
el.CalcDShape(ip,dshape_iso);
el.CalcShape(ip,shapef);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
mfem::Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
// dshape_xyz should be devided by detJ for obtaining the real value
// calculate the gradient
dshape_xyz.MultTranspose(elfun,grad);
//set the power
if(pp!=nullptr)
{
vparam[0]=pp->Eval(trans,ip);
}
//set the coefficient ensuring possitiveness of the tangent matrix
if(coeff!=nullptr)
{
vparam[1]=coeff->Eval(trans,ip);
}
//add the contribution from the load
if(load!=nullptr)
{
vparam[2]=load->Eval(trans,ip);
}
//fill the values of vector uu
for(int jj=0;jj<spaceDim;jj++)
{
uu[jj]=grad[jj]/detJ;
}
uu[3]=shapef*elfun;
energy = energy + w * (qint.QFunction(vparam,uu));
}
return energy;
}
virtual void AssembleElementVector(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const mfem::Vector & elfun,
mfem::Vector & elvect) override
{
int ndof = el.GetDof();
int ndim = el.GetDim();
int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
mfem::Vector shapef(ndof);
mfem::DenseMatrix dshape_iso(ndof,ndim);
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
mfem::Vector lvec(ndof);
elvect.SetSize(ndof);
elvect=0.0;
mfem::DenseMatrix B(ndof,4); //[diff_x,diff_y,diff_z, shape]
mfem::Vector vparam(3);//[power, epsilon, load]
mfem::Vector uu(4);//[diff_x,diff_y,diff_z,u]
mfem::Vector du(4);
B=0.0;
uu=0.0;
//initialize the parameters - keep the same order
//utilized in the pLapIntegrator definition
vparam[0]=2.0; //default power
vparam[1]=1e-8; //default epsilon
vparam[2]=1.0; //default load
double w;
double detJ;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w*w);
w = ip.weight * w;
el.CalcDShape(ip,dshape_iso);
el.CalcShape(ip,shapef);
mfem::Mult(dshape_iso, trans.InverseJacobian(), dshape_xyz);
//set the matrix B
for(int jj=0;jj<spaceDim;jj++)
{
B.SetCol(jj,dshape_xyz.GetColumn(jj));
}
B.SetCol(3,shapef);
//set the power
if(pp!=nullptr)
{
vparam[0]=pp->Eval(trans,ip);
}
//set the coefficient ensuring possitiveness of the tangent matrix
if(coeff!=nullptr)
{
vparam[1]=coeff->Eval(trans,ip);
}
//add the contribution from the load
if(load!=nullptr)
{
vparam[2]=load->Eval(trans,ip);
}
//calculate uu
B.MultTranspose(elfun,uu);
//calculate derivative of the energy with respect to uu
qint.QFunctionDU(vparam,uu,du);
B.Mult(du,lvec);
elvect.Add( w, lvec);
}// end integration loop
}
virtual void AssembleElementGrad(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const mfem::Vector & elfun, mfem::DenseMatrix & elmat) override
{
int ndof = el.GetDof();
int ndim = el.GetDim();
int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
mfem::Vector shapef(ndof);
mfem::DenseMatrix dshape_iso(ndof,ndim);
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
elmat.SetSize(ndof,ndof);
elmat=0.0;
mfem::DenseMatrix B(ndof,4); //[diff_x,diff_y,diff_z, shape]
mfem::DenseMatrix A(ndof,4);
mfem::Vector vparam(3);//[power, epsilon, load]
mfem::Vector uu(4);//[diff_x,diff_y,diff_z,u]
mfem::DenseMatrix duu(4,4);
B=0.0;
uu=0.0;
//initialize the parameters - keep the same order
//utilized in the pLapIntegrator definition
vparam[0]=2.0; //default power
vparam[1]=1e-8; //default epsilon
vparam[2]=1.0; //default load
double w;
double detJ;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w*w);
w = ip.weight * w;
el.CalcDShape(ip,dshape_iso);
el.CalcShape(ip,shapef);
mfem::Mult(dshape_iso, trans.InverseJacobian(), dshape_xyz);
//set the matrix B
for(int jj=0;jj<spaceDim;jj++)
{
B.SetCol(jj,dshape_xyz.GetColumn(jj));
}
B.SetCol(3,shapef);
//set the power
if(pp!=nullptr)
{
vparam[0]=pp->Eval(trans,ip);
}
//set the coefficient ensuring possitiveness of the tangent matrix
if(coeff!=nullptr)
{
vparam[1]=coeff->Eval(trans,ip);
}
//add the contribution from the load
if(load!=nullptr)
{
vparam[2]=load->Eval(trans,ip);
}
//calculate uu
B.MultTranspose(elfun,uu);
//calculate derivative of the energy with respect to uu
qint.QFunctionDD(vparam,uu,duu);
mfem::Mult(B,duu,A);
mfem::AddMult_a_ABt(w,A,B,elmat);
}//end integration loop
}
};
class pLaplace: public mfem::NonlinearFormIntegrator
{
protected:
mfem::Coefficient* pp;
mfem::Coefficient* coeff;
mfem::Coefficient* load;
public:
pLaplace()
{
coeff=nullptr;
pp=nullptr;
}
pLaplace(mfem::Coefficient& pp_):pp(&pp_), coeff(nullptr), load(nullptr)
{
}
pLaplace(mfem::Coefficient &pp_,mfem::Coefficient& q, mfem::Coefficient& ld_): pp(&pp_), coeff(&q), load(&ld_)
{
}
virtual ~pLaplace()
{
}
virtual double GetElementEnergy(const mfem::FiniteElement &el, mfem::ElementTransformation &trans, const mfem::Vector &elfun) override
{
double energy=0.0;
int ndof = el.GetDof();
int ndim = el.GetDim();
int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
mfem::Vector shapef(ndof);
mfem::DenseMatrix dshape_iso(ndof,ndim);
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
mfem::Vector grad(spaceDim);
double w;
double detJ;
double nrgrad2;
double ppp=2.0;
double eee=0.0;
for(int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w*w);
w = ip.weight *w;
el.CalcDShape(ip,dshape_iso);
el.CalcShape(ip,shapef);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
mfem::Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
// dshape_xyz should be devided by detJ for obtaining the real value
// calculate the gradient
dshape_xyz.MultTranspose(elfun,grad);
nrgrad2=grad*grad/(detJ*detJ);
//set the power
if(pp!=nullptr)
{
ppp=pp->Eval(trans,ip);
}
//set the coefficient ensuring possitiveness of the tangent matrix
if(coeff!=nullptr)
{
eee=coeff->Eval(trans,ip);
}
energy = energy + w * std::pow( nrgrad2 + eee * eee , ppp / 2.0 ) / ppp;
//add the contribution from the load
if(load!=nullptr)
{
energy = energy - w * (shapef*elfun) * load->Eval(trans,ip);
}
}
return energy;
}
virtual void AssembleElementVector(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const mfem::Vector & elfun,
mfem::Vector & elvect) override
{
int ndof = el.GetDof();
int ndim = el.GetDim();
int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
mfem::Vector shapef(ndof);
mfem::DenseMatrix dshape_iso(ndof,ndim);
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
mfem::Vector grad(spaceDim);
mfem::Vector lvec(ndof);
elvect.SetSize(ndof);
elvect=0.0;
double w;
double detJ;
double nrgrad;
double aa;
double ppp=2.0;
double eee=0.0;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w*w);
w = ip.weight * w;//w;
el.CalcDShape(ip,dshape_iso);
el.CalcShape(ip,shapef);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
mfem::Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
// dshape_xyz should be devided by detJ for obtaining the real value
//calculate the gradient
dshape_xyz.MultTranspose(elfun,grad);
nrgrad=grad.Norml2()/detJ;
//grad is not scaled so far, i.e., grad=grad/detJ
//set the power
if(pp!=nullptr)
{
ppp=pp->Eval(trans,ip);
}
//set the coefficient ensuring possitiveness of the tangent matrix
if(coeff!=nullptr)
{
eee=coeff->Eval(trans,ip);
}
aa = nrgrad * nrgrad + eee * eee;
aa=std::pow( aa , ( ppp - 2.0 ) / 2.0 );
dshape_xyz.Mult(grad,lvec);
elvect.Add( w * aa / ( detJ * detJ ), lvec);
//add loading
if(load!=nullptr)
{
elvect.Add(-w*load->Eval(trans,ip),shapef);
}
}// end integration loop
}
virtual void AssembleElementGrad(const mfem::FiniteElement & el,
mfem::ElementTransformation & trans,
const mfem::Vector & elfun, mfem::DenseMatrix & elmat) override
{
int ndof = el.GetDof();
int ndim = el.GetDim();
int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
const mfem::IntegrationRule *ir = NULL;
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
mfem::DenseMatrix dshape_iso(ndof,ndim);
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
mfem::Vector grad(spaceDim);
mfem::Vector lvec(ndof);
elmat.SetSize(ndof,ndof);
elmat=0.0;
double w;
double detJ;
double nrgrad;
double aa0;
double aa1;
double ppp=2.0;
double eee=0.0;
for (int i = 0; i < ir -> GetNPoints(); i++)
{
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w*w);
w = ip.weight * w;
el.CalcDShape(ip,dshape_iso);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
mfem::Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
// dshape_xyz should be devided by detJ for obtaining the real value
// grad is not scaled so far,i.e., grad=grad/detJ
//set the power
if(pp!=nullptr)
{
ppp=pp->Eval(trans,ip);
}
//set the coefficient ensuring possitiveness of the tangent matrix
if(coeff!=nullptr)
{
eee=coeff->Eval(trans,ip);
}
//calculate the gradient
dshape_xyz.MultTranspose(elfun,grad);
nrgrad = grad.Norml2() / detJ;
aa0 = nrgrad * nrgrad + eee * eee;
aa1 = std::pow( aa0 , ( ppp - 2.0 ) / 2.0 );
aa0 = ( ppp - 2.0 ) * std::pow(aa0, ( ppp - 4.0 ) / 2.0 );
dshape_xyz.Mult(grad,lvec);
w = w / ( detJ * detJ );
mfem::AddMult_a_VVt( w * aa0 / ( detJ * detJ ), lvec, elmat);
mfem::AddMult_a_AAt( w * aa1 , dshape_xyz, elmat);
}//end integration loop
}
};
}
#endif
+378
View File
@@ -0,0 +1,378 @@
// MFEM Example 71 - Parallel Version
//
// Compile with: make ex71p
//
// Sample runs:
// mpirun -np 2 ex71p -m ../data/beam-quad.mesh
// mpirun -np 2 ex71p -m ../data/beam-tri.mesh
// mpirun -np 2 ex71p -m ../data/beam-hex.mesh
// mpirun -np 2 ex71p -m ../data/beam-tet.mesh
// mpirun -np 2 ex71p -m ../data/beam-wedge.mesh
//
// Description: This examples solves a quasi-static nonlinear
// pLaplacian problem with zero Dirichlet boundary
// conditions applied on all defined boundaries
//
// The example demonstrates the use of nonlinear operators
// combined with automatic differentiation (AD). The definitions
// of the integrators are written in the ex71.hpp.
// Selecting integrator=0 will use handcoded integrator.
// Selecting integrator=1 will utilize AD integrator.
// The AD integrator can be modifief to use ADQFunctionJ
// or ADQFunctionH by overwritting the class type of qint,
// i.e., pLapIntegrandJ or pLapIntegrandH.
//
// qint (the integrand) is a function which is evaluated
// at every integration point. For implementations utilizing
// ADQFunctionJ, the user has to implement the function and the
// residual evaluation - all virtual methods. The Jacobian of
// the residual is evaluated using AD
//
// For implementations utilizing ADQFunctionH, the user has
// to implement only the function evaluation (preferebaly as
// a template) and the first derivative (the residual) and the
// second derivatives (the Hessian) are evaluated using AD.
//
// We recommend viewing examples 1 and 19, before viewing this
// example.
#include "ex71.hpp"
int main(int argc, char *argv[])
{
// 1. Initialize MPI
int num_procs, myrank;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
// 2. Parse command-line options
const char *mesh_file = "../data/beam-tet.mesh";
int ser_ref_levels = 0;
int par_ref_levels = 0;
int order = 2;
bool visualization = true;
double newton_rel_tol = 1e-4;
double newton_abs_tol = 1e-6;
int newton_iter = 500;
int print_level = 0;
double pp = 2.0;
int integrator=0;
mfem::StopWatch* timer=new mfem::StopWatch();
mfem::OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
"Number of times to refine the mesh uniformly in parallel.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&newton_rel_tol, "-rel", "--relative-tolerance",
"Relative tolerance for the Newton solve.");
args.AddOption(&newton_abs_tol, "-abs", "--absolute-tolerance",
"Absolute tolerance for the Newton solve.");
args.AddOption(&newton_iter, "-it", "--newton-iterations",
"Maximum iterations for the Newton solve.");
args.AddOption(&pp, "-pp", "--power-parameter",
"Power parameter (>=2.0) for the p-Laplacian.");
args.AddOption((&print_level),"-prt","--print-level",
"Print level.");
args.AddOption(&integrator, "-int","--integrator",
"Integrator 0: standard; 1: AD uaing energy; 2: AD using gradients");
args.Parse();
if (!args.Good())
{
if (myrank == 0)
{
args.PrintUsage(std::cout);
}
MPI_Finalize();
return 1;
}
if (myrank == 0)
{
args.PrintOptions(std::cout);
}
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral and hexahedral meshes
// with the same code.
mfem::Mesh *mesh = new mfem::Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. Refine the mesh in serial to increase the resolution. In this example
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
// a command-line parameter.
for (int lev = 0; lev < ser_ref_levels; lev++)
{
mesh->UniformRefinement();
}
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
mfem::ParMesh *pmesh = new mfem::ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
for (int lev = 0; lev < par_ref_levels; lev++)
{
pmesh->UniformRefinement();
}
// 6. Define the power parameter for the p-Laplacian and all other
// coefficients
mfem::ConstantCoefficient c_pp(pp);
mfem::ConstantCoefficient load(1.000000000);
mfem::ConstantCoefficient c_ee(0.000000001);
// 7. Define the finite element spaces for the solution
mfem::H1_FECollection fec(order,dim);
mfem::ParFiniteElementSpace fespace(pmesh,&fec,1,mfem::Ordering::byVDIM);
HYPRE_Int glob_size=fespace.GlobalTrueVSize();
if (myrank == 0)
{
std::cout << "Number of finite element unknowns: " << glob_size << std::endl;
}
// 8. Define the Dirichlet conditions
mfem::Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
// 9. Define the nonlinear form
mfem::ParNonlinearForm* nf=new mfem::ParNonlinearForm(&fespace);
// 10. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
mfem::ParGridFunction x(&fespace);
x = 0.0;
mfem::HypreParVector* tv=x.GetTrueDofs();
mfem::HypreParVector* sv=x.GetTrueDofs();
// 11. Define ParaView DataCollection
mfem::ParaViewDataCollection *dacol=new mfem::ParaViewDataCollection("pLap",pmesh);
dacol->SetLevelsOfDetail(order);
dacol->RegisterField("sol",&x);
// 11. Set domain integrators - start with linear diffusion
{
// the default power coefficient is 2.0
mfem::ConstantCoefficient lpp(2.0);
if(integrator==0)
{
nf->AddDomainIntegrator(new mfem::pLaplace(lpp,c_ee,load));
}else
if(integrator==1)
{
nf->AddDomainIntegrator(new mfem::pLaplaceAD(lpp,c_ee,load));
}
nf->SetEssentialBC(ess_bdr);
// compute the energy
double energy=nf->GetEnergy(*tv);
if(myrank==0){
std::cout<<"[2] The total energy of the system is E="<<energy<<std::endl;}
// time the assembly
timer->Clear();
timer->Start();
mfem::Operator &op=nf->GetGradient(*sv);
timer->Stop();
if(myrank==0){
std::cout<<"[2] The assembly time is: "<<timer->RealTime()<<std::endl;}
mfem::Solver *prec=new mfem::HypreBoomerAMG();
mfem::GMRESSolver *j_gmres = new mfem::GMRESSolver(MPI_COMM_WORLD);
j_gmres->SetRelTol(1e-7);
j_gmres->SetAbsTol(1e-15);
j_gmres->SetMaxIter(300);
j_gmres->SetPrintLevel(print_level);
j_gmres->SetPreconditioner(*prec);
mfem::NewtonSolver* ns;
ns=new mfem::NewtonSolver(MPI_COMM_WORLD);
ns->iterative_mode = true;
ns->SetSolver(*j_gmres);
ns->SetOperator(*nf);
ns->SetPrintLevel(print_level);
ns->SetRelTol(1e-6);
ns->SetAbsTol(1e-12);
ns->SetMaxIter(3);
//solve the problem
timer->Clear();
timer->Start();
ns->Mult(*tv, *sv);
timer->Stop();
if(myrank==0){
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;}
energy=nf->GetEnergy(*sv);
if(myrank==0){
std::cout<<"[pp=2] The total energy of the system is E="<<energy<<std::endl;}
delete ns;
delete j_gmres;
delete prec;
x.SetFromTrueDofs(*sv);
dacol->SetTime(2.0);
dacol->SetCycle(2);
dacol->Save();
}
// 12. Continue with powers higher than 2
for(int i=3;i<pp;i++)
{
delete nf;
nf=new mfem::ParNonlinearForm(&fespace);
mfem::ConstantCoefficient lpp((double)i);
if(integrator==0)
{
nf->AddDomainIntegrator(new mfem::pLaplace(lpp,c_ee,load));
}else
if(integrator==1)
{
nf->AddDomainIntegrator(new mfem::pLaplaceAD(lpp,c_ee,load));
}
nf->SetEssentialBC(ess_bdr);
// compute the energy
double energy=nf->GetEnergy(*sv);
if(myrank==0){
std::cout<<"[pp="<<i<<"] The total energy of the system is E="<<energy<<std::endl;}
// time the assembly
timer->Clear();
timer->Start();
mfem::Operator &op=nf->GetGradient(*sv);
timer->Stop();
if(myrank==0){
std::cout<<"[pp="<<i<<"] The assembly time is: "<<timer->RealTime()<<std::endl;}
mfem::Solver *prec=new mfem::HypreBoomerAMG();
mfem::GMRESSolver *j_gmres = new mfem::GMRESSolver(MPI_COMM_WORLD);
j_gmres->SetRelTol(1e-7);
j_gmres->SetAbsTol(1e-15);
j_gmres->SetMaxIter(300);
j_gmres->SetPrintLevel(print_level);
j_gmres->SetPreconditioner(*prec);
mfem::NewtonSolver* ns;
ns=new mfem::NewtonSolver(MPI_COMM_WORLD);
ns->iterative_mode = true;
ns->SetSolver(*j_gmres);
ns->SetOperator(*nf);
ns->SetPrintLevel(print_level);
ns->SetRelTol(1e-6);
ns->SetAbsTol(1e-12);
ns->SetMaxIter(3);
//solve the problem
timer->Clear();
timer->Start();
ns->Mult(*tv, *sv);
timer->Stop();
if(myrank==0){
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;}
energy=nf->GetEnergy(*sv);
if(myrank==0){
std::cout<<"[pp="<<i<<"] The total energy of the system is E="<<energy<<std::endl;}
delete ns;
delete j_gmres;
delete prec;
x.SetFromTrueDofs(*sv);
dacol->SetTime(i);
dacol->SetCycle(i);
dacol->Save();
}
// 13. Continue with the final power
if( std::abs(pp-2.0) > std::numeric_limits<double>::epsilon())
{
delete nf;
nf=new mfem::ParNonlinearForm(&fespace);
if(integrator==0)
{
nf->AddDomainIntegrator(new mfem::pLaplace(c_pp,c_ee,load));
}else
if(integrator==1)
{
nf->AddDomainIntegrator(new mfem::pLaplaceAD(c_pp,c_ee,load));
}
nf->SetEssentialBC(ess_bdr);
// compute the energy
double energy=nf->GetEnergy(*sv);
if(myrank==0){
std::cout<<"[pp="<<pp<<"] The total energy of the system is E="<<energy<<std::endl;}
// time the assembly
timer->Clear();
timer->Start();
mfem::Operator &op=nf->GetGradient(*sv);
timer->Stop();
if(myrank==0){
std::cout<<"[pp="<<pp<<"] The assembly time is: "<<timer->RealTime()<<std::endl;}
mfem::Solver *prec=new mfem::HypreBoomerAMG();
mfem::GMRESSolver *j_gmres = new mfem::GMRESSolver(MPI_COMM_WORLD);
j_gmres->SetRelTol(1e-8);
j_gmres->SetAbsTol(1e-15);
j_gmres->SetMaxIter(300);
j_gmres->SetPrintLevel(print_level);
j_gmres->SetPreconditioner(*prec);
mfem::NewtonSolver* ns;
ns=new mfem::NewtonSolver(MPI_COMM_WORLD);
ns->iterative_mode = true;
ns->SetSolver(*j_gmres);
ns->SetOperator(*nf);
ns->SetPrintLevel(print_level);
ns->SetRelTol(1e-6);
ns->SetAbsTol(1e-12);
ns->SetMaxIter(3);
//solve the problem
timer->Clear();
timer->Start();
ns->Mult(*tv, *sv);
timer->Stop();
if(myrank==0){
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;}
energy=nf->GetEnergy(*sv);
if(myrank==0){
std::cout<<"[pp="<<pp<<"] The total energy of the system is E="<<energy<<std::endl;}
delete ns;
delete j_gmres;
delete prec;
x.SetFromTrueDofs(*sv);
dacol->SetTime(pp);
if(pp<2.0)
{
dacol->SetCycle(std::floor(pp));
}
else
{
dacol->SetCycle(std::ceil(pp));
}
dacol->Save();
}
// 19. Free the used memory
delete dacol;
delete sv;
delete tv;
delete nf;
delete pmesh;
delete timer;
MPI_Finalize();
return 0;
}
+9 -18
View File
@@ -20,11 +20,8 @@
// Device sample runs:
// ex9 -pa
// ex9 -ea
// ex9 -fa
// ex9 -pa -m ../data/periodic-cube.mesh
// ex9 -pa -m ../data/periodic-cube.mesh -d cuda
// ex9 -ea -m ../data/periodic-cube.mesh -d cuda
// ex9 -fa -m ../data/periodic-cube.mesh -d cuda
//
// Description: This example code solves the time-dependent advection equation
// du/dt + v.grad(u) = 0, where v is a given fluid velocity, and
@@ -147,7 +144,6 @@ int main(int argc, char *argv[])
int order = 3;
bool pa = false;
bool ea = false;
bool fa = false;
const char *device_config = "cpu";
int ode_solver_type = 4;
double t_final = 10.0;
@@ -174,8 +170,6 @@ int main(int argc, char *argv[])
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&fa, "-fa", "--full-assembly", "-no-fa",
"--no-full-assembly", "Enable Full Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
@@ -284,11 +278,6 @@ int main(int argc, char *argv[])
m.SetAssemblyLevel(AssemblyLevel::ELEMENT);
k.SetAssemblyLevel(AssemblyLevel::ELEMENT);
}
else if (fa)
{
m.SetAssemblyLevel(AssemblyLevel::FULL);
k.SetAssemblyLevel(AssemblyLevel::FULL);
}
m.AddDomainIntegrator(new MassIntegrator);
k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
k.AddInteriorFaceIntegrator(
@@ -448,19 +437,21 @@ int main(int argc, char *argv[])
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 (M.GetAssemblyLevel() == AssemblyLevel::LEGACYFULL)
{
M_prec = new DSmoother(M.SpMat());
M_solver.SetOperator(M.SpMat());
dg_solver = new DG_Solver(M.SpMat(), K.SpMat(), *M.FESpace());
}
else
if (pa || ea)
{
M_prec = new OperatorJacobiSmoother(M, ess_tdof_list);
M_solver.SetOperator(M);
dg_solver = NULL;
}
else
{
M_prec = new DSmoother(M.SpMat());
dg_solver = new DG_Solver(M.SpMat(), K.SpMat(), *M.FESpace());
M_solver.SetOperator(M.SpMat());
}
M_solver.SetPreconditioner(*M_prec);
M_solver.iterative_mode = false;
M_solver.SetRelTol(1e-9);
+15 -24
View File
@@ -21,11 +21,8 @@
// Device sample runs:
// mpirun -np 4 ex9p -pa
// mpirun -np 4 ex9p -ea
// mpirun -np 4 ex9p -fa
// mpirun -np 4 ex9p -pa -m ../data/periodic-cube.mesh
// mpirun -np 4 ex9p -pa -m ../data/periodic-cube.mesh -d cuda
// mpirun -np 4 ex9p -ea -m ../data/periodic-cube.mesh -d cuda
// mpirun -np 4 ex9p -fa -m ../data/periodic-cube.mesh -d cuda
//
// Description: This example code solves the time-dependent advection equation
// du/dt + v.grad(u) = 0, where v is a given fluid velocity, and
@@ -167,7 +164,6 @@ int main(int argc, char *argv[])
int order = 3;
bool pa = false;
bool ea = false;
bool fa = false;
const char *device_config = "cpu";
int ode_solver_type = 4;
double t_final = 10.0;
@@ -197,8 +193,6 @@ int main(int argc, char *argv[])
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&fa, "-fa", "--full-assembly", "-no-fa",
"--no-full-assembly", "Enable Full Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
@@ -335,12 +329,6 @@ int main(int argc, char *argv[])
m->SetAssemblyLevel(AssemblyLevel::ELEMENT);
k->SetAssemblyLevel(AssemblyLevel::ELEMENT);
}
else if (fa)
{
m->SetAssemblyLevel(AssemblyLevel::FULL);
k->SetAssemblyLevel(AssemblyLevel::FULL);
}
m->AddDomainIntegrator(new MassIntegrator);
k->AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
k->AddInteriorFaceIntegrator(
@@ -577,21 +565,29 @@ FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K,
M_solver(_M.ParFESpace()->GetComm()),
z(_M.Height())
{
if (_M.GetAssemblyLevel()==AssemblyLevel::LEGACYFULL)
{
M.Reset(_M.ParallelAssemble(), true);
K.Reset(_K.ParallelAssemble(), true);
}
else
bool pa = _M.GetAssemblyLevel()==AssemblyLevel::PARTIAL;
bool ea = _M.GetAssemblyLevel()==AssemblyLevel::ELEMENT;
if (pa || ea)
{
M.Reset(&_M, false);
K.Reset(&_K, false);
}
else
{
M.Reset(_M.ParallelAssemble(), true);
K.Reset(_K.ParallelAssemble(), true);
}
M_solver.SetOperator(*M);
Array<int> ess_tdof_list;
if (_M.GetAssemblyLevel()==AssemblyLevel::LEGACYFULL)
if (pa || ea)
{
M_prec = new OperatorJacobiSmoother(_M, ess_tdof_list);
dg_solver = NULL;
}
else
{
HypreParMatrix &M_mat = *M.As<HypreParMatrix>();
HypreParMatrix &K_mat = *K.As<HypreParMatrix>();
@@ -600,11 +596,6 @@ FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K,
dg_solver = new DG_Solver(M_mat, K_mat, *_M.FESpace());
}
else
{
M_prec = new OperatorJacobiSmoother(_M, ess_tdof_list);
dg_solver = NULL;
}
M_solver.SetPreconditioner(*M_prec);
M_solver.iterative_mode = false;
-5
View File
@@ -114,11 +114,6 @@ ex11p-test-strumpack: ex11p
@$(call mfem-test,$<, $(RUN_MPI), STRUMPACK example,--strumpack)
test-par-YES: ex11p-test-strumpack
endif
ifeq ($(MFEM_USE_SUPERLU),YES)
ex11p-test-superlu: ex11p
@$(call mfem-test,$<, $(RUN_MPI), SuperLU_DIST example,--superlu)
test-par-YES: ex11p-test-superlu
endif
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
+4 -23
View File
@@ -34,15 +34,6 @@ if (MFEM_USE_MPI)
)
endif()
if (MFEM_USE_SLEPC)
list(APPEND PETSC_EXAMPLES_SRCS
ex11p.cpp
)
list(APPEND PETSC_RC_FILES
rc_ex11p_lobpcg rc_ex11p_gd
)
endif()
# Include the source directory where mfem.hpp and mfem-performance.hpp are.
include_directories(BEFORE ${PROJECT_BINARY_DIR})
@@ -87,22 +78,12 @@ set(EX9_E_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts
set(EX9_ES_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step)
set(EX9_IS_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5)
set(EX10_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3)
if (MFEM_USE_SLEPC)
set(EX11_ARGS_SINV -m ../../data/star.mesh --useslepc)
set(EX11_ARGS_LOBPCG -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg)
set(EX11_ARGS_GD -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_gd)
endif()
# Add the tests: one test per command-line-variable.
set(TEST_OPTIONS_VARS
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
if (MFEM_USE_SLEPC)
list(APPEND TEST_OPTIONS_VARS EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
endif()
foreach(TEST_OPTIONS_VAR ${TEST_OPTIONS_VARS})
foreach(TEST_OPTIONS_VAR
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
string(REGEX REPLACE "^(.+)_ARGS" "\\1" TEST_NAME_UC ${TEST_OPTIONS_VAR})
string(REGEX REPLACE "^([^_]+)" "\\1P" TEST_NAME_UC ${TEST_NAME_UC})
string(TOLOWER ${TEST_NAME_UC} TEST_NAME_FULL)
-440
View File
@@ -1,440 +0,0 @@
// MFEM Example 11 - Parallel Version
// PETSc Modification
//
// Compile with: make ex11p
//
// Sample runs: mpirun -np 4 ex11p -m ../../data/star.mesh
// mpirun -np 4 ex11p -m ../../data/star.mesh --slepcopts rc_ex11p_lobpcg
// mpirun -np 4 ex11p -m ../../data/star.mesh --slepcopts rc_ex11p_gd
//
// Description: This example code demonstrates the use of MFEM to solve the
// eigenvalue problem -Delta u = lambda u with homogeneous
// Dirichlet boundary conditions.
//
// We compute a number of the lowest eigenmodes by discretizing
// the Laplacian and Mass operators using a FE space of the
// specified order, or an isoparametric/isogeometric space if
// order < 1 (quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example demonstrates the use of the SLEPc eigensolver as an
// alternative to the LOBPCG eigenvalue solver. The shift and
// invert spectral transformation is used to help the convergence
// to the smaller eigenvalues. Alternative solver parameters can
// be passed in a file with "-slepcopts".
//
// Reusing a single GLVis visualization window for multiple
// eigenfunctions is also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#ifndef MFEM_USE_SLEPC
#error This examples requires that MFEM is build with MFEM_USE_SLEPC=YES
#endif
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../../data/star.mesh";
int ser_ref_levels = 2;
int par_ref_levels = 1;
int order = 1;
int nev = 5;
int seed = 75;
bool slu_solver = false;
bool sp_solver = false;
bool visualization = 1;
bool use_slepc = true;
const char *slepcrc_file = "";
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
"Number of times to refine the mesh uniformly in parallel.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&nev, "-n", "--num-eigs",
"Number of desired eigenmodes.");
args.AddOption(&seed, "-s", "--seed",
"Random seed used to initialize LOBPCG.");
#ifdef MFEM_USE_SUPERLU
args.AddOption(&slu_solver, "-slu", "--superlu", "-no-slu",
"--no-superlu", "Use the SuperLU Solver.");
#endif
#ifdef MFEM_USE_STRUMPACK
args.AddOption(&sp_solver, "-sp", "--strumpack", "-no-sp",
"--no-strumpack", "Use the STRUMPACK Solver.");
#endif
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&use_slepc, "-useslepc","--useslepc","-no-slepc",
"--no-slepc","Use or not SLEPc to solve the eigenvalue problem");
args.AddOption(&slepcrc_file, "-slepcopts", "--slepcopts",
"SlepcOptions file to use.");
args.Parse();
if (slu_solver && sp_solver)
{
if (myid == 0)
cout << "WARNING: Both SuperLU and STRUMPACK have been selected,"
<< " please choose either one." << endl
<< " Defaulting to SuperLU." << endl;
sp_solver = false;
}
// The command line options are also passed to the STRUMPACK
// solver. So do not exit if some options are not recognized.
if (!sp_solver)
{
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 2b. We initialize SLEPc. This internally initializes PETSc as well.
MFEMInitializeSlepc(NULL,NULL,slepcrc_file,NULL);
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement (2 by default, or
// specified on the command line with -rs).
for (int lev = 0; lev < ser_ref_levels; lev++)
{
mesh->UniformRefinement();
}
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution (1 time by
// default, or specified on the command line with -rp). Once the parallel
// mesh is defined, the serial mesh can be deleted.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
for (int lev = 0; lev < par_ref_levels; lev++)
{
pmesh->UniformRefinement();
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (pmesh->GetNodes())
{
fec = pmesh->GetNodes()->OwnFEC();
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of unknowns: " << size << endl;
}
// 7. Set up the parallel bilinear forms a(.,.) and m(.,.) on the finite
// element space. The first corresponds to the Laplacian operator -Delta,
// while the second is a simple mass matrix needed on the right hand side
// of the generalized eigenvalue problem below. The boundary conditions
// are implemented by elimination with special values on the diagonal to
// shift the Dirichlet eigenvalues out of the computational range. After
// serial and parallel assembly we extract the corresponding parallel
// matrices A and M.
ConstantCoefficient one(1.0);
Array<int> ess_bdr;
if (pmesh->bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh->bdr_attributes.Max());
ess_bdr = 1;
}
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
if (pmesh->bdr_attributes.Size() == 0)
{
// Add a mass term if the mesh has no boundary, e.g. periodic mesh or
// closed surface.
a->AddDomainIntegrator(new MassIntegrator(one));
}
a->Assemble();
a->EliminateEssentialBCDiag(ess_bdr, 1.0);
a->Finalize();
ParBilinearForm *m = new ParBilinearForm(fespace);
m->AddDomainIntegrator(new MassIntegrator(one));
m->Assemble();
// shift the eigenvalue corresponding to eliminated dofs to a large value
m->EliminateEssentialBCDiag(ess_bdr, numeric_limits<double>::min());
m->Finalize();
PetscParMatrix *pA = NULL, *pM = NULL;
HypreParMatrix *A = NULL, *M = NULL;
Operator::Type tid =
!use_slepc ? Operator::Hypre_ParCSR : Operator::PETSC_MATAIJ;
OperatorHandle Ah(tid), Mh(tid);
a->ParallelAssemble(Ah);
if (!use_slepc) { Ah.Get(A); }
else { Ah.Get(pA); }
Ah.SetOperatorOwner(false);
m->ParallelAssemble(Mh);
if (!use_slepc) {Mh.Get(M); }
else {Mh.Get(pM); }
Mh.SetOperatorOwner(false);
#if defined(MFEM_USE_SUPERLU) || defined(MFEM_USE_STRUMPACK)
Operator * Arow = NULL;
#ifdef MFEM_USE_SUPERLU
if (slu_solver)
{
Arow = new SuperLURowLocMatrix(*A);
}
#endif
#ifdef MFEM_USE_STRUMPACK
if (sp_solver)
{
Arow = new STRUMPACKRowLocMatrix(*A);
}
#endif
#endif
delete a;
delete m;
// 8. Define and configure the LOBPCG eigensolver and the BoomerAMG
// preconditioner for A to be used within the solver. Set the matrices
// which define the generalized eigenproblem A x = lambda M x.
Solver * precond = NULL;
if (!use_slepc)
{
if (!slu_solver && !sp_solver)
{
HypreBoomerAMG * amg = new HypreBoomerAMG(*A);
amg->SetPrintLevel(0);
precond = amg;
}
else
{
#ifdef MFEM_USE_SUPERLU
if (slu_solver)
{
SuperLUSolver * superlu = new SuperLUSolver(MPI_COMM_WORLD);
superlu->SetPrintStatistics(false);
superlu->SetSymmetricPattern(true);
superlu->SetColumnPermutation(superlu::PARMETIS);
superlu->SetOperator(*Arow);
precond = superlu;
}
#endif
#ifdef MFEM_USE_STRUMPACK
if (sp_solver)
{
STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv, MPI_COMM_WORLD);
strumpack->SetPrintFactorStatistics(true);
strumpack->SetPrintSolveStatistics(false);
strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
strumpack->DisableMatching();
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
precond = strumpack;
}
#endif
}
}
HypreLOBPCG * lobpcg = NULL;
SlepcEigenSolver * slepc = NULL;
if (!use_slepc)
{
lobpcg = new HypreLOBPCG(MPI_COMM_WORLD);
lobpcg->SetNumModes(nev);
lobpcg->SetRandomSeed(seed);
lobpcg->SetPreconditioner(*precond);
lobpcg->SetMaxIter(200);
lobpcg->SetTol(1e-8);
lobpcg->SetPrecondUsageMode(1);
lobpcg->SetPrintLevel(1);
lobpcg->SetMassMatrix(*M);
lobpcg->SetOperator(*A);
}
else
{
slepc = new SlepcEigenSolver(MPI_COMM_WORLD);
slepc->SetNumModes(nev);
slepc->SetWhichEigenpairs(SlepcEigenSolver::TARGET_REAL);
slepc->SetTarget(0.0);
slepc->SetSpectralTransformation(SlepcEigenSolver::SHIFT_INVERT);
slepc->SetOperators(*pA,*pM);
}
// 9. Compute the eigenmodes and extract the array of eigenvalues. Define a
// parallel grid function to represent each of the eigenmodes returned by
// the solver.
Array<double> eigenvalues;
if (!use_slepc)
{
lobpcg->Solve();
lobpcg->GetEigenvalues(eigenvalues);
}
else
{
slepc->Solve();
eigenvalues.SetSize(nev);
for (int i=0; i<nev; i++)
{
slepc->GetEigenvalue(i,eigenvalues[i]);
}
}
Vector temp(fespace->GetTrueVSize());
ParGridFunction x(fespace);
// 10. Save the refined mesh and the modes in parallel. This output can be
// viewed later using GLVis: "glvis -np <np> -m mesh -g mode".
{
ostringstream mesh_name, mode_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
for (int i=0; i<nev; i++)
{
// convert eigenvector from HypreParVector to ParGridFunction
if (!use_slepc)
{
x = lobpcg->GetEigenvector(i);
}
else
{
slepc->GetEigenvector(i,temp);
x.Distribute(temp);
}
mode_name << "mode_" << setfill('0') << setw(2) << i << "."
<< setfill('0') << setw(6) << myid;
ofstream mode_ofs(mode_name.str().c_str());
mode_ofs.precision(8);
x.Save(mode_ofs);
mode_name.str("");
}
}
// 11. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream mode_sock(vishost, visport);
mode_sock.precision(8);
for (int i=0; i<nev; i++)
{
if ( myid == 0 )
{
cout << "Eigenmode " << i+1 << '/' << nev
<< ", Lambda = " << eigenvalues[i] << endl;
}
// convert eigenvector from HypreParVector to ParGridFunction
if (!use_slepc)
{
x = lobpcg->GetEigenvector(i);
}
else
{
slepc->GetEigenvector(i,temp);
x.Distribute(temp);
}
mode_sock << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << *pmesh << x << flush
<< "window_title 'Eigenmode " << i+1 << '/' << nev
<< ", Lambda = " << eigenvalues[i] << "'" << endl;
char c;
if (myid == 0)
{
cout << "press (q)uit or (c)ontinue --> " << flush;
cin >> c;
}
MPI_Bcast(&c, 1, MPI_CHAR, 0, MPI_COMM_WORLD);
if (c != 'c')
{
break;
}
}
mode_sock.close();
}
// 12. Free the used memory.
if (!use_slepc)
{
delete lobpcg;
}
else
{
delete slepc;
}
delete precond;
delete M;
delete A;
#if defined(MFEM_USE_SUPERLU) || defined(MFEM_USE_STRUMPACK)
delete Arow;
#endif
delete fespace;
if (order > 0)
{
delete fec;
}
delete pmesh;
// We finalize SLEPc
MFEMFinalizeSlepc();
MPI_Finalize();
return 0;
}
-12
View File
@@ -23,9 +23,6 @@ MFEM_LIB_FILE = mfem_is_not_built
SEQ_EXAMPLES =
PAR_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex9p ex10p
ifeq ($(MFEM_USE_SLEPC),YES)
PAR_EXAMPLES += ex11p
endif
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
else
@@ -90,9 +87,6 @@ EX10_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p
EX10_MF_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mf -tf 6 -s 3 -rs 0 -dt 3
EX10_MFOP_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mfop -tf 6 -s 3 -rs 0 -dt 3
EX10_JFNK_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_jfnk --jfnk -tf 6 -s 3 -rs 0 -dt 3
EX11_ARGS_SINV := -m ../../data/star.mesh --useslepc
EX11_ARGS_LOBPCG := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg
EX11_ARGS_GD := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_gd
ex1p-test-par: ex1p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_W))
@@ -120,12 +114,6 @@ ex10p-test-par: ex10p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_MF_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_MFOP_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_JFNK_ARGS))
ifeq ($(MFEM_USE_SLEPC),YES)
ex11p-test-par: ex11p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_SINV))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_LOBPCG))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_GD))
endif
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
-6
View File
@@ -1,6 +0,0 @@
# Options for the eigenvalue solver
-eps_view
-eps_converged_reason
-eps_type gd
# Options for the spectral transform
-st_type precond
-11
View File
@@ -1,11 +0,0 @@
# Options for the eigenvalue solver
-eps_monitor
-eps_converged_reason
-eps_view_values
-eps_type lobpcg
-eps_gen_hermitian
-eps_smallest_real
-eps_lobpcg_blocksize 5
# Options for the spectral transform
-st_type precond
-st_pc_type gamg
+2 -37
View File
@@ -50,45 +50,13 @@ set(SRCS
fespacehierarchy.cpp
nonlininteg_vectorconvection.cpp
quadinterpolator.cpp
quadinterpolator_det.cpp
quadinterpolator_eval_by_nodes.cpp
quadinterpolator_eval_by_vdim.cpp
quadinterpolator_grad_by_nodes.cpp
quadinterpolator_grad_by_vdim.cpp
quadinterpolator_grad_phys_by_nodes.cpp
quadinterpolator_grad_phys_by_vdim.cpp
quadinterpolator_face.cpp
restriction.cpp
staticcond.cpp
tmop.cpp
tmop_pa.cpp
tmop_pa_h2d.cpp
tmop_pa_h2d_c0.cpp
tmop_pa_h2m.cpp
tmop_pa_h2m_c0.cpp
tmop_pa_h2s.cpp
tmop_pa_h2s_c0.cpp
tmop_pa_h3d.cpp
tmop_pa_h3d_c0.cpp
tmop_pa_h3m.cpp
tmop_pa_h3m_c0.cpp
tmop_pa_h3s.cpp
tmop_pa_h3s_c0.cpp
tmop_pa_jp2.cpp
tmop_pa_jp3.cpp
tmop_pa_jt2_tc.cpp
tmop_pa_jt3_datc.cpp
tmop_pa_jt3_tc.cpp
tmop_pa_p2.cpp
tmop_pa_p2_c0.cpp
tmop_pa_p3.cpp
tmop_pa_p3_c0.cpp
tmop_pa_w2.cpp
tmop_pa_w2_c0.cpp
tmop_pa_w3.cpp
tmop_pa_w3_c0.cpp
tmop_tools.cpp
gslib.cpp
adnonlininteg.cpp
transfer.cpp
)
@@ -116,10 +84,7 @@ set(HDRS
nonlinearform_ext.hpp
nonlininteg.hpp
quadinterpolator.hpp
quadinterpolator_eval.hpp
quadinterpolator_face.hpp
quadinterpolator_grad.hpp
quadinterpolator_grad_phys.hpp
restriction.hpp
fespacehierarchy.hpp
staticcond.hpp
@@ -132,9 +97,9 @@ set(HDRS
tfespace.hpp
tintrules.hpp
tmop.hpp
tmop_pa.hpp
tmop_tools.hpp
gslib.hpp
adnonlininteg.hpp
transfer.hpp
)
+408
View File
@@ -0,0 +1,408 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "fem.hpp"
#include "../general/forall.hpp"
#include "adnonlininteg.hpp"
namespace mfem
{
void ADQFunctionJ::QFunctionDD(const Vector &vparam, const Vector &uu, DenseMatrix &jac)
{
#if defined MFEM_USE_ADEPT
//use ADEPT package
adept::Stack* p_stack=adept::active_stack();
p_stack->deactivate();
int n=uu.Size();
jac.SetSize(m,n);
jac=0.0;
m_stack.activate();
{
ADFVector aduu(uu);
ADFVector rr(m); //residual vector
m_stack.new_recording();
this->QFunctionDU(vparam,aduu,rr);
m_stack.independent(aduu.GetData(), n);//independent variables
m_stack.dependent(rr.GetData(), m);//dependent variables
m_stack.jacobian(jac.Data());
}
m_stack.deactivate();
#elif defined MFEM_USE_CODIPACK
#if defined MFEM_USE_ADFORWARD
//use CoDipack
int n=uu.Size();
jac.SetSize(m,n);
jac=0.0;
{
ADFVector aduu(n);
ADFVector rr(m);
for(int i=0;i<n;i++)
{
aduu[i]=uu[i];
aduu[i].setGradient(0.0);
}
for(int ii=0;ii<n;ii++){
aduu[ii].setGradient(1.0);
this->QFunctionDU(vparam,aduu,rr);
for(int jj=0;jj<m;jj++)
{
jac(jj,ii)=rr[jj].getGradient();
}
aduu[ii].setGradient(0.0);
}
}
#else
//use CoDiPack in reverse mode
int n=uu.Size();
jac.SetSize(m,n);
jac=0.0;
{
ADFVector aduu(n);
ADFVector rr(m);
for(int i=0;i<n;i++)
{
aduu[i]=uu[i];
}
ADFType::TapeType& tape= ADFType::getGlobalTape();
typename ADFType::TapeType::Position pos=tape.getPosition();
tape.setActive();
for(int ii=0;ii<n;ii++){ tape.registerInput(aduu[ii]); }
this->QFunctionDU(vparam,aduu,rr);
for(int ii=0;ii<m;ii++){ tape.registerOutput(rr[ii]); }
tape.setPassive();
for(int jj=0;jj<m;jj++){
rr[jj].setGradient(1.0);
tape.evaluate();
for(int ii=0;ii<n;ii++){
jac(jj,ii)=aduu[ii].getGradient();
}
rr[jj].setGradient(0.0);
}
tape.reset(pos);
}
#endif
#elif defined MFEM_USE_FADBADPP
//use FADBAD++
#ifdef MFEM_USE_ADFORWARD
int n=uu.Size();
jac.SetSize(m,n);
jac=0.0;
{
ADFVector aduu(uu);
ADFVector rr(m);
for(int ii=0;ii<n;ii++){
aduu[ii].diff(ii,n);
}
this->QFunctionDU(vparam,aduu,rr);
for(int ii=0;ii<n;ii++){
for(int jj=0;jj<m;jj++)
{
jac(jj,ii)=rr[jj].d(ii);
}
}
}
#else
int n=uu.Size();
jac.SetSize(m,n);
jac=0.0;
{
ADFVector aduu(uu);
ADFVector rr(m);
this->QFunctionDU(vparam,aduu,rr);
for(int ii=0;ii<m;ii++)
{
rr[ii].diff(ii,m);
}
for(int ii=0;ii<n;ii++){
for(int jj=0;jj<m;jj++)
{
jac(jj,ii)=aduu[ii].d(jj);
}
}
}
#endif
#else
//use native AD package
int n=uu.Size();
jac.SetSize(m,n);
jac=0.0;
{
ADFVector aduu(uu); //all dual numbers are initialized to zero
ADFVector rr(m);
for(int ii=0;ii<n;ii++){
aduu[ii].dual(1.0);
this->QFunctionDU(vparam,aduu,rr);
for(int jj=0;jj<m;jj++)
{
jac(jj,ii)=rr[jj].dual();
}
aduu[ii].dual(0.0);
}
}
#endif
}
void ADQFunctionH::QFunctionDU(const Vector &vparam, Vector &uu, Vector &rr)
{
#if defined MFEM_USE_CODIPACK
int n=uu.Size();
rr.SetSize(n);
ADFVector aduu(n);
ADFType rez;
for(int ii=0;ii<n;ii++)
{
aduu[ii].setValue(uu[ii]);
aduu[ii].setGradient(0.0);
}
for(int ii=0;ii<n;ii++)
{
aduu[ii].setGradient(1.0);
rez=this->QFunction(vparam,aduu);
rr[ii]=rez.getGradient();
aduu[ii].setGradient(0.0);
}
#elif defined MFEM_USE_FADBADPP
int n=uu.Size();
rr.SetSize(n);
ADFVector aduu(uu);
ADFType rez;
rez=this->QFunction(vparam,aduu);
rez.diff(0,1);
for(int ii=0;ii<n;ii++)
{
rr[ii]=aduu[ii].d(0);
}
#else
int n=uu.Size();
rr.SetSize(n);
ADFVector aduu(uu);
ADFType rez;
for(int ii=0;ii<n;ii++)
{
aduu[ii].dual(1.0);
rez=this->QFunction(vparam,aduu);
rr[ii]=rez.dual();
aduu[ii].dual(0.0);
}
#endif
}
void ADQFunctionH::QFunctionDD(const Vector &vparam, const Vector &uu, DenseMatrix &jac)
{
#if defined MFEM_USE_CODIPACK
#if defined MFEM_USE_ADFORWARD
int n=uu.Size();
jac.SetSize(n);
jac=0.0;
{
ADSVector aduu(n);
for(int ii = 0; ii < n ; ii++)
{
aduu[ii].value().value()=uu[ii];
aduu[ii].value().gradient()=0.0;
aduu[ii].gradient().value()=0.0;
aduu[ii].gradient().gradient()=0.0;
}
for(int ii = 0; ii < n ; ii++)
{
aduu[ii].value().gradient()=1.0;
for(int jj=0; jj<(ii+1); jj++)
{
aduu[ii].gradient().value()=1.0;
ADSType rez= this->QFunction(vparam,aduu);
jac(ii,jj)=rez.gradient().gradient();
jac(jj,ii)=jac(ii,jj);
aduu[jj].gradient().value()=0.0;
}
aduu[ii].value().gradient()=0.0;
}
}
#else
int n=uu.Size();
jac.SetSize(n);
jac=0.0;
{
ADSVector aduu(n);
for(int ii=0;ii < n ; ii++)
{
aduu[ii].value().value()=uu[ii];
}
ADSType rez;
ADSType::TapeType& tape = ADSType::getGlobalTape();
typename ADSType::TapeType::Position pos;
for(int ii = 0; ii < n ; ii++)
{
pos=tape.getPosition();
tape.setActive();
for(int jj=0;jj < n; jj++) {
if(jj==ii) {aduu[jj].value().gradient()=1.0;}
else {aduu[jj].value().gradient()=0.0;}
tape.registerInput(aduu[jj]);
}
rez=this->QFunction(vparam,aduu);
tape.registerOutput(rez);
tape.setPassive();
rez.gradient().value()=1.0;
tape.evaluate();
for(int jj=0; jj<(ii+1); jj++)
{
jac(ii,jj)=aduu[jj].gradient().gradient();
jac(jj,ii)=jac(ii,jj);
}
tape.reset(pos);
}
}
#endif
#elif defined MFEM_USE_FADBADPP
int n=uu.Size();
jac.SetSize(n);
jac=0.0;
{
ADSVector aduu(n);
for(int ii = 0; ii < n ; ii++)
{
aduu[ii]=uu[ii];
aduu[ii].x().diff(ii,n);
}
ADSType rez= this->QFunction(vparam,aduu);
rez.diff(0,1);
for(int ii = 0; ii < n ; ii++)
{
for(int jj=0; jj<ii; jj++)
{
jac(ii,jj)=aduu[ii].d(0).d(jj);
jac(jj,ii)=aduu[jj].d(0).d(ii);
}
jac(ii,ii)=aduu[ii].d(0).d(ii);
}
}
#else
int n=uu.Size();
jac.SetSize(n);
jac=0.0;
{
ADSVector aduu(n);
for(int ii = 0; ii < n ; ii++)
{
aduu[ii].real(ADFType(uu[ii],0.0));
aduu[ii].dual(ADFType(0.0,0.0));
}
for(int ii = 0; ii < n ; ii++)
{
aduu[ii].real(ADFType(uu[ii],1.0));
for(int jj=0; jj<(ii+1); jj++)
{
aduu[jj].dual(ADFType(1.0,0.0));
ADSType rez= this->QFunction(vparam,aduu);
jac(ii,jj)=rez.dual().dual();
jac(jj,ii)=rez.dual().dual();
aduu[jj].dual(ADFType(0.0,0.0));
}
aduu[ii].real(ADFType(uu[ii],0.0));
}
}
#endif
}
double ADNonlinearFormIntegratorH::GetElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & Tr,
const mfem::Vector & elfun)
{
return this->ElementEnergy(el,Tr,elfun);
}
void ADNonlinearFormIntegratorH::AssembleElementVector(const mfem::FiniteElement & el,
mfem::ElementTransformation & Tr,
const mfem::Vector & elfun, mfem::Vector & elvect)
{
int ndof = el.GetDof();
elvect.SetSize(ndof);
{
ADFVector adelfun(elfun);
//all dual numbers in adelfun are initialized to 0.0
for(int ii = 0; ii < adelfun.Size(); ii++)
{
//set the dual for the ii^th element to 1.0
adelfun[ii].dual(1.0);
ADFType rez= this->ElementEnergy(el,Tr, adelfun);
elvect[ii]=rez.dual();
//return it back to zero
adelfun[ii].dual(0.0);
}
}
}
void ADNonlinearFormIntegratorH::AssembleElementGrad(const mfem::FiniteElement & el,
mfem::ElementTransformation & Tr,
const mfem::Vector & elfun,
mfem::DenseMatrix & elmat)
{
int ndof = el.GetDof();
elmat.SetSize(ndof);
elmat=0.0;
{
ADSVector adelfun(ndof);
for(int ii = 0; ii < ndof; ii++)
{
adelfun[ii].real(ADFType(elfun[ii],0.0));
adelfun[ii].dual(ADFType(0.0,0.0));
}
for(int ii = 0; ii < adelfun.Size(); ii++)
{
adelfun[ii].real(ADFType(elfun[ii],1.0));
for(int jj = 0; jj < (ii+1); jj++)
{
adelfun[jj].dual(ADFType(1.0,0.0));
ADSType rez= this->ElementEnergy(el,Tr, adelfun);
elmat(ii,jj)=rez.dual().dual();
elmat(jj,ii)=rez.dual().dual();
adelfun[jj].dual(ADFType(0.0,0.0));
}
adelfun[ii].real(ADFType(elfun[ii],0.0));
}
}
}
} //end namespace mfem
+204
View File
@@ -0,0 +1,204 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_ADNONLININTEG
#define MFEM_ADNONLININTEG
#include "../config/config.hpp"
#include "fe.hpp"
#include "coefficient.hpp"
#include "fespace.hpp"
#include "nonlininteg.hpp"
#include "../linalg/tadvector.hpp"
#include "../linalg/taddensemat.hpp"
#include "../linalg/fdual.hpp"
#if defined MFEM_USE_ADEPT
#include <adept.h>
#elif defined MFEM_USE_CODIPACK
#include <codi.hpp>
#elif defined MFEM_USE_FADBADPP
#include <fadiff.h>
#include <badiff.h>
#endif
//define Forward AD mode
//#define MFEM_USE_ADFORWARD
namespace mfem
{
class ADQFunctionJ
{
private:
int m; //dimension of the residual vector
//the Jacobian will have dimensions [m,length(uu)]
protected:protected:
#ifdef MFEM_USE_ADEPT
adept::Stack m_stack;
#endif
public:
#if defined MFEM_USE_ADEPT
typedef adept::adouble ADFType;
typedef TADVector<ADFType> ADFVector;
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
#elif defined MFEM_USE_CODIPACK
#if defined MFEM_USE_ADFORWARD
typedef codi::RealForward ADFType;
typedef TADVector<ADFType> ADFVector;
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
#else
typedef codi::RealRevers ADFType;
typedef TADVector<ADFType> ADFVector;
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
#endif
#elif defined MFEM_USE_FADBADPP
#ifdef MFEM_USE_ADFORWARD
typedef fadbad::F<double> ADFType;
typedef TADVector<ADFType> ADFVector;
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
#else
typedef fadbad::B<double> ADFType;
typedef TADVector<ADFType> ADFVector;
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
#endif
#else
typedef mfem::ad::FDual<double> ADFType;
typedef TADVector<ADFType> ADFVector;
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
#endif
#ifdef MFEM_USE_ADEPT
ADQFunctionJ(int m_=1):m_stack(false)
{
m=m_;
}
#else
ADQFunctionJ(int m_=1){ m=m_;}
#endif
virtual ~ADQFunctionJ(){}
virtual double QFunction(const mfem::Vector& vparam, const mfem::Vector& uu)=0;
virtual void QFunctionDU(const mfem::Vector& vparam, ADFVector& uu, ADFVector& rr)=0;
virtual void QFunctionDU(const mfem::Vector& vparam, mfem::Vector& uu, mfem::Vector& rr)=0;
void QFunctionDD(const mfem::Vector& vparam, const mfem::Vector& uu, mfem::DenseMatrix& jj);
};
class ADQFunctionH
{
public:
#if defined MFEM_USE_CODIPACK
#if defined MFEM_USE_ADFORWARD
//use forward mode for both the first and the second derivatives
typedef codi::RealForwardGen<double> ADFType;
typedef TADVector<ADFType> ADFVector;
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
typedef codi::RealForwardGen<ADFType> ADSType;
typedef TADVector<ADSType> ADSVector;
typedef TADDenseMatrix<ADSType> ADSDenseMatrix;
#else
//use mixed forward and reverse mode
typedef codi::RealForwardGen<double> ADFType;
typedef TADVector<ADFType> ADFVector;
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
typedef codi::RealReverseGen<ADFType> ADSType;
typedef TADVector<ADSType> ADSVector;
typedef TADDenseMatrix<ADSType> ADSDenseMatrix;
#endif
#elif defined MFEM_USE_FADBADPP
typedef fadbad::B<double> ADFType;
typedef TADVector<ADFType> ADFVector;
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
typedef fadbad::B<fadbad::F<double>> ADSType;
typedef TADVector<ADSType> ADSVector;
typedef TADDenseMatrix<ADSType> ADSDenseMatrix;
#else
typedef mfem::ad::FDual<double> ADFType;
typedef TADVector<ADFType> ADFVector;
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
typedef mfem::ad::FDual<ADFType> ADSType;
typedef TADVector<ADSType> ADSVector;
typedef TADDenseMatrix<ADSType> ADSDenseMatrix;
#endif
ADQFunctionH(){}
virtual ~ADQFunctionH(){}
virtual double QFunction(const mfem::Vector& vparam, const mfem::Vector& uu)=0;
virtual ADFType QFunction(const mfem::Vector& vparam, ADFVector& uu)=0;
virtual ADSType QFunction(const mfem::Vector &vparam, ADSVector& uu)=0;
virtual void QFunctionDU(const mfem::Vector& vparam, mfem::Vector& uu, mfem::Vector& rr);
void QFunctionDD(const mfem::Vector& vparam, const mfem::Vector& uu, mfem::DenseMatrix& jj);
};
class ADNonlinearFormIntegratorH: public NonlinearFormIntegrator
{
public:
typedef mfem::ad::FDual<double> ADFType;
typedef TADVector<ADFType> ADFVector;
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
typedef mfem::ad::FDual<ADFType> ADSType;
typedef TADVector<ADSType> ADSVector;
typedef TADDenseMatrix<ADSType> ADSDenseMatrix;
ADNonlinearFormIntegratorH(){}
virtual ~ADNonlinearFormIntegratorH(){}
virtual ADSType ElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & Tr,
const ADSVector & elfun)=0;
virtual ADFType ElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & Tr,
const ADFVector & elfun)=0;
virtual double ElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & Tr,
const mfem::Vector & elfun)=0;
virtual double GetElementEnergy(const mfem::FiniteElement & el,
mfem::ElementTransformation & Tr,
const mfem::Vector & elfun) override;
virtual void AssembleElementVector(const mfem::FiniteElement & el,
mfem::ElementTransformation & Tr,
const mfem::Vector & elfun, mfem::Vector & elvect) override;
virtual void AssembleElementGrad(const mfem::FiniteElement & el,
mfem::ElementTransformation & Tr,
const mfem::Vector & elfun,
mfem::DenseMatrix & elmat) override;
};
}
#endif
+14 -16
View File
@@ -76,7 +76,7 @@ BilinearForm::BilinearForm(FiniteElementSpace * f)
precompute_sparsity = 0;
diag_policy = DIAG_KEEP;
assembly = AssemblyLevel::LEGACYFULL;
assembly = AssemblyLevel::FULL;
batch = 1;
ext = NULL;
}
@@ -94,7 +94,7 @@ BilinearForm::BilinearForm (FiniteElementSpace * f, BilinearForm * bf, int ps)
precompute_sparsity = ps;
diag_policy = DIAG_KEEP;
assembly = AssemblyLevel::LEGACYFULL;
assembly = AssemblyLevel::FULL;
batch = 1;
ext = NULL;
@@ -121,10 +121,9 @@ void BilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
assembly = assembly_level;
switch (assembly)
{
case AssemblyLevel::LEGACYFULL:
break;
case AssemblyLevel::FULL:
ext = new FABilinearFormExtension(this);
// ext = new FABilinearFormExtension(this);
// Use the original BilinearForm implementation for now
break;
case AssemblyLevel::ELEMENT:
ext = new EABilinearFormExtension(this);
@@ -144,7 +143,7 @@ void BilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
void BilinearForm::EnableStaticCondensation()
{
delete static_cond;
if (assembly != AssemblyLevel::LEGACYFULL)
if (assembly != AssemblyLevel::FULL)
{
static_cond = NULL;
MFEM_WARNING("Static condensation not supported for this assembly level");
@@ -169,7 +168,7 @@ void BilinearForm::EnableHybridization(FiniteElementSpace *constr_space,
const Array<int> &ess_tdof_list)
{
delete hybridization;
if (assembly != AssemblyLevel::LEGACYFULL)
if (assembly != AssemblyLevel::FULL)
{
delete constr_integ;
hybridization = NULL;
@@ -224,7 +223,7 @@ MatrixInverse * BilinearForm::Inverse() const
void BilinearForm::Finalize (int skip_zeros)
{
if (assembly == AssemblyLevel::LEGACYFULL)
if (assembly == AssemblyLevel::FULL)
{
if (!static_cond) { mat->Finalize(skip_zeros); }
if (mat_e) { mat_e->Finalize(skip_zeros); }
@@ -640,7 +639,8 @@ void BilinearForm::AssembleDiagonal(Vector &diag) const
}
else
{
mat->GetDiag(diag);
MFEM_ABORT("Not implemented. Maybe assemble your bilinear form into a "
"matrix and use SparseMatrix::GetDiag?");
}
}
@@ -1083,7 +1083,7 @@ MixedBilinearForm::MixedBilinearForm (FiniteElementSpace *tr_fes,
mat = NULL;
mat_e = NULL;
extern_bfs = 0;
assembly = AssemblyLevel::LEGACYFULL;
assembly = AssemblyLevel::FULL;
ext = NULL;
}
@@ -1108,7 +1108,7 @@ MixedBilinearForm::MixedBilinearForm (FiniteElementSpace *tr_fes,
bbfi_marker = mbf->bbfi_marker;
btfbfi_marker = mbf->btfbfi_marker;
assembly = AssemblyLevel::LEGACYFULL;
assembly = AssemblyLevel::FULL;
ext = NULL;
}
@@ -1121,8 +1121,6 @@ void MixedBilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
assembly = assembly_level;
switch (assembly)
{
case AssemblyLevel::LEGACYFULL:
break;
case AssemblyLevel::FULL:
// ext = new FAMixedBilinearFormExtension(this);
// Use the original BilinearForm implementation for now
@@ -1193,7 +1191,7 @@ void MixedBilinearForm::AddMultTranspose(const Vector & x, Vector & y,
MatrixInverse * MixedBilinearForm::Inverse() const
{
if (assembly != AssemblyLevel::LEGACYFULL)
if (assembly != AssemblyLevel::FULL)
{
MFEM_WARNING("MixedBilinearForm::Inverse not possible with this assembly level!");
return NULL;
@@ -1206,7 +1204,7 @@ MatrixInverse * MixedBilinearForm::Inverse() const
void MixedBilinearForm::Finalize (int skip_zeros)
{
if (assembly == AssemblyLevel::LEGACYFULL)
if (assembly == AssemblyLevel::FULL)
{
mat -> Finalize (skip_zeros);
}
@@ -1483,7 +1481,7 @@ void MixedBilinearForm::AssembleDiagonal_ADAt(const Vector &D,
void MixedBilinearForm::ConformingAssemble()
{
if (assembly != AssemblyLevel::LEGACYFULL)
if (assembly != AssemblyLevel::FULL)
{
MFEM_WARNING("Conforming assemble not supported for this assembly level!");
return;
+3 -6
View File
@@ -29,11 +29,8 @@ namespace mfem
form classes derived from Operator. */
enum class AssemblyLevel
{
/// Legacy fully assembled form, i.e. a global sparse matrix in MFEM, Hypre
/// or PETSC format. This assembly is ALWAYS performed on the host.
LEGACYFULL = 0,
/// Fully assembled form, i.e. a global sparse matrix in MFEM format. This
/// assembly is compatible with device execution.
/// Fully assembled form, i.e. a global sparse matrix in MFEM, Hypre or PETSC
/// format.
FULL,
/// Form assembled at element level, which computes and stores dense element
/// matrices.
@@ -122,7 +119,7 @@ protected:
static_cond = NULL; hybridization = NULL;
precompute_sparsity = 0;
diag_policy = DIAG_KEEP;
assembly = AssemblyLevel::LEGACYFULL;
assembly = AssemblyLevel::FULL;
batch = 1;
ext = NULL;
}
+36 -188
View File
@@ -15,7 +15,6 @@
#include "../general/forall.hpp"
#include "bilinearform.hpp"
#include "libceed/ceed.hpp"
#include "pgridfunc.hpp"
namespace mfem
{
@@ -116,7 +115,7 @@ void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int iSz = integrators.Size();
if (elem_restrict && !DeviceCanUseCeed())
if (elem_restrict)
{
localY = 0.0;
for (int i = 0; i < iSz; ++i)
@@ -293,8 +292,7 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
// Data and methods for element-assembled bilinear forms
EABilinearFormExtension::EABilinearFormExtension(BilinearForm *form)
: PABilinearFormExtension(form),
factorize_face_terms(form->FESpace()->IsDGSpace())
: PABilinearFormExtension(form)
{
}
@@ -349,17 +347,6 @@ void EABilinearFormExtension::Assemble()
{
bdrFaceIntegrators[i]->AssembleEABoundaryFaces(*a->FESpace(),ea_data_bdr);
}
if (factorize_face_terms && int_face_restrict_lex)
{
auto restFint = dynamic_cast<const L2FaceRestriction&>(*int_face_restrict_lex);
restFint.AddFaceMatricesToElementMatrices(ea_data_int, ea_data);
}
if (factorize_face_terms && bdr_face_restrict_lex)
{
auto restFbdr = dynamic_cast<const L2FaceRestriction&>(*bdr_face_restrict_lex);
restFbdr.AddFaceMatricesToElementMatrices(ea_data_bdr, ea_data);
}
}
void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
@@ -412,27 +399,24 @@ void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
const int NDOFS = faceDofs;
auto X = Reshape(faceIntX.Read(), NDOFS, 2, nf_int);
auto Y = Reshape(faceIntY.ReadWrite(), NDOFS, 2, nf_int);
if (!factorize_face_terms)
auto A_int = Reshape(ea_data_int.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
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++)
{
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;
});
}
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,
{
@@ -459,7 +443,7 @@ void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
// Treatment of boundary faces
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (!factorize_face_terms && bdr_face_restrict_lex && bFISz>0)
if (bdr_face_restrict_lex && bFISz>0)
{
// Apply the Boundary Face Restriction
bdr_face_restrict_lex->Mult(x, faceBdrX);
@@ -538,27 +522,24 @@ void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
const int NDOFS = faceDofs;
auto X = Reshape(faceIntX.Read(), NDOFS, 2, nf_int);
auto Y = Reshape(faceIntY.ReadWrite(), NDOFS, 2, nf_int);
if (!factorize_face_terms)
auto A_int = Reshape(ea_data_int.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
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++)
{
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;
});
}
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,
{
@@ -585,7 +566,7 @@ void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
// Treatment of boundary faces
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (!factorize_face_terms && bdr_face_restrict_lex && bFISz>0)
if (bdr_face_restrict_lex && bFISz>0)
{
// Apply the Boundary Face Restriction
bdr_face_restrict_lex->Mult(x, faceBdrX);
@@ -614,139 +595,6 @@ void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
}
}
// Data and methods for fully-assembled bilinear forms
FABilinearFormExtension::FABilinearFormExtension(BilinearForm *form)
: EABilinearFormExtension(form),
mat(form->FESpace()->GetVSize(),form->FESpace()->GetVSize(),0),
face_mat(form->FESpace()->GetVSize(),0,0),
use_face_mat(false)
{
#ifdef MFEM_USE_MPI
if ( ParFiniteElementSpace* pfes =
dynamic_cast<ParFiniteElementSpace*>(form->FESpace()) )
{
if (pfes->IsDGSpace())
{
use_face_mat = true;
pfes->ExchangeFaceNbrData();
face_mat.SetWidth(pfes->GetFaceNbrVSize());
}
}
#endif
}
void FABilinearFormExtension::Assemble()
{
EABilinearFormExtension::Assemble();
FiniteElementSpace &fes = *a->FESpace();
if (fes.IsDGSpace())
{
const L2ElementRestriction *restE =
static_cast<const L2ElementRestriction*>(elem_restrict);
const L2FaceRestriction *restF =
static_cast<const L2FaceRestriction*>(int_face_restrict_lex);
// 1. Fill I
// 1.1 Increment with restE
restE->FillI(mat);
// 1.2 Increment with restF
if (restF) { restF->FillI(mat, face_mat); }
// 1.3 Sum the non-zeros in I
auto h_I = mat.HostReadWriteI();
int cpt = 0;
const int vd = fes.GetVDim();
const int ndofs = ne*elemDofs*vd;
for (int i = 0; i < ndofs; i++)
{
const int nnz = h_I[i];
h_I[i] = cpt;
cpt += nnz;
}
const int nnz = cpt;
h_I[ndofs] = nnz;
mat.GetMemoryJ().New(nnz, mat.GetMemoryJ().GetMemoryType());
mat.GetMemoryData().New(nnz, mat.GetMemoryData().GetMemoryType());
if (use_face_mat && restF)
{
auto h_I_face = face_mat.HostReadWriteI();
int cpt = 0;
for (int i = 0; i < ndofs; i++)
{
const int nnz = h_I_face[i];
h_I_face[i] = cpt;
cpt += nnz;
}
const int nnz_face = cpt;
h_I_face[ndofs] = nnz_face;
face_mat.GetMemoryJ().New(nnz_face,
face_mat.GetMemoryJ().GetMemoryType());
face_mat.GetMemoryData().New(nnz_face,
face_mat.GetMemoryData().GetMemoryType());
}
// 2. Fill J and Data
// 2.1 Fill J and Data with Elem ea_data
restE->FillJAndData(ea_data, mat);
// 2.2 Fill J and Data with Face ea_data_ext
if (restF) { restF->FillJAndData(ea_data_ext, mat, face_mat); }
// 2.3 Shift indirections in I back to original
auto I = mat.HostReadWriteI();
for (int i = ndofs; i > 0; i--)
{
I[i] = I[i-1];
}
I[0] = 0;
if (use_face_mat && restF)
{
auto I_face = face_mat.HostReadWriteI();
for (int i = ndofs; i > 0; i--)
{
I_face[i] = I_face[i-1];
}
I_face[0] = 0;
}
}
else // continuous Galerkin case
{
const ElementRestriction &rest =
static_cast<const ElementRestriction&>(*elem_restrict);
rest.FillSparseMatrix(ea_data, mat);
}
}
void FABilinearFormExtension::Mult(const Vector &x, Vector &y) const
{
mat.Mult(x, y);
#ifdef MFEM_USE_MPI
if (const ParFiniteElementSpace *pfes =
dynamic_cast<const ParFiniteElementSpace*>(testFes))
{
ParGridFunction x_gf;
x_gf.MakeRef(const_cast<ParFiniteElementSpace*>(pfes),
const_cast<Vector&>(x),0);
x_gf.ExchangeFaceNbrData();
Vector &shared_x = x_gf.FaceNbrData();
if (shared_x.Size()) { face_mat.AddMult(shared_x, y); }
}
#endif
}
void FABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
{
mat.MultTranspose(x, y);
#ifdef MFEM_USE_MPI
if (const ParFiniteElementSpace *pfes =
dynamic_cast<const ParFiniteElementSpace*>(testFes))
{
ParGridFunction x_gf;
x_gf.MakeRef(const_cast<ParFiniteElementSpace*>(pfes),
const_cast<Vector&>(x),0);
x_gf.ExchangeFaceNbrData();
Vector &shared_x = x_gf.FaceNbrData();
if (shared_x.Size()) { face_mat.AddMultTranspose(shared_x, y); }
}
#endif
}
MixedBilinearFormExtension::MixedBilinearFormExtension(MixedBilinearForm *form)
: Operator(form->Height(), form->Width()), a(form)
{
+21 -19
View File
@@ -62,6 +62,27 @@ public:
virtual void Update() = 0;
};
/** @brief Data and methods for fully-assembled bilinear forms.
Not yet implemented! Use the BilinearForm Class instead. */
class FABilinearFormExtension : public BilinearFormExtension
{
public:
FABilinearFormExtension(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() {}
~FABilinearFormExtension() {}
};
/// Data and methods for partially-assembled bilinear forms
class PABilinearFormExtension : public BilinearFormExtension
{
@@ -98,12 +119,10 @@ class EABilinearFormExtension : public PABilinearFormExtension
protected:
int ne;
int elemDofs;
// The element matrices are stored row major
Vector ea_data;
int nf_int, nf_bdr;
int faceDofs;
Vector ea_data_int, ea_data_ext, ea_data_bdr;
bool factorize_face_terms;
public:
EABilinearFormExtension(BilinearForm *form);
@@ -113,23 +132,6 @@ public:
void MultTranspose(const Vector &x, Vector &y) const;
};
/// Data and methods for fully-assembled bilinear forms
class FABilinearFormExtension : public EABilinearFormExtension
{
private:
SparseMatrix mat;
/// face_mat handles parallelism for DG face terms.
SparseMatrix face_mat;
bool use_face_mat;
public:
FABilinearFormExtension(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.
class MFBilinearFormExtension : public BilinearFormExtension
{
+2 -32
View File
@@ -1685,22 +1685,6 @@ protected:
{
trial_fe.CalcPhysCurlShape(Trans, shape);
}
using BilinearFormIntegrator::AssemblePA;
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 DofToQuad *mapsOtest; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsCtest; ///< Not owned. DOF-to-quad map, closed.
const GeometricFactors *geom; ///< Not owned
int dim, ne, dofs1D, dofs1Dtest,quad1D, testType, trialType, coeffDim;
};
/** Class for integrating the bilinear form a(u,v) := (Q u, curl v) in 3D and
@@ -1740,20 +1724,6 @@ protected:
{
test_fe.CalcPhysCurlShape(Trans, shape);
}
using BilinearFormIntegrator::AssemblePA;
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
@@ -1954,7 +1924,7 @@ public:
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe);
void SetupPA(const FiniteElementSpace &fes);
void SetupPA(const FiniteElementSpace &fes, const bool force = false);
};
/** Class for local mass matrix assembling a(u,v) := (Q u, v) */
@@ -2030,7 +2000,7 @@ public:
const FiniteElement &test_fe,
ElementTransformation &Trans);
void SetupPA(const FiniteElementSpace &fes);
void SetupPA(const FiniteElementSpace &fes, const bool force = false);
};
/** Mass integrator (u, v) restricted to the boundary of a domain */
+6 -6
View File
@@ -32,7 +32,7 @@ static void EAConvectionAssemble1D(const int NE,
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.ReadWrite(), D1D, D1D, 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;
@@ -54,7 +54,7 @@ static void EAConvectionAssemble1D(const int NE,
{
val += r_Bj[k1] * D(k1, e) * r_Gi[k1];
}
A(i1, j1, e) += val;
A(i1, j1, e) = val;
}
}
});
@@ -76,7 +76,7 @@ static void EAConvectionAssemble2D(const int NE,
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.ReadWrite(), D1D, D1D, D1D, D1D, 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;
@@ -121,7 +121,7 @@ static void EAConvectionAssemble2D(const int NE,
* r_B[k1][j1]* r_B[k2][j2];
}
}
A(i1, i2, j1, j2, e) += val;
A(i1, i2, j1, j2, e) = val;
}
}
}
@@ -145,7 +145,7 @@ static void EAConvectionAssemble3D(const int NE,
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.ReadWrite(), D1D, D1D, D1D, D1D, D1D, D1D, 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;
@@ -191,7 +191,7 @@ static void EAConvectionAssemble3D(const int NE,
}
}
}
A(i1, i2, i3, j1, j2, j3, e) += val;
A(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
+73 -289
View File
@@ -13,10 +13,6 @@
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "restriction.hpp"
#include "tmop_pa.hpp"
#include "../linalg/kernels.hpp"
using namespace std;
namespace mfem
@@ -72,53 +68,47 @@ static void PAConvectionSetup3D(const int Q1D,
const double alpha,
Vector &op)
{
const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
const int NQ = Q1D*Q1D*Q1D;
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
const bool const_v = vel.Size() == 3;
const auto V = const_v ?
Reshape(vel.Read(), 3,1,1,1,1) :
Reshape(vel.Read(), 3,Q1D,Q1D,Q1D,NE);
auto y = Reshape(op.Write(), Q1D,Q1D,Q1D,3,NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
auto V =
const_v ? Reshape(vel.Read(), 3,1,1) : Reshape(vel.Read(), 3,NQ,NE);
auto y = Reshape(op.Write(), NQ, 3, NE);
MFEM_FORALL(e, NE,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
for (int q = 0; q < NQ; ++q)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double J11 = J(qx,qy,qz,0,0,e);
const double J12 = J(qx,qy,qz,0,1,e);
const double J13 = J(qx,qy,qz,0,2,e);
const double J21 = J(qx,qy,qz,1,0,e);
const double J22 = J(qx,qy,qz,1,1,e);
const double J23 = J(qx,qy,qz,1,2,e);
const double J31 = J(qx,qy,qz,2,0,e);
const double J32 = J(qx,qy,qz,2,1,e);
const double J33 = J(qx,qy,qz,2,2,e);
const double w = alpha * W(qx,qy,qz);
const double v0 = const_v ? V(0,0,0,0,0) : V(0,qx,qy,qz,e);
const double v1 = const_v ? V(1,0,0,0,0) : V(1,qx,qy,qz,e);
const double v2 = const_v ? V(2,0,0,0,0) : V(2,qx,qy,qz,e);
const double wx = w * v0;
const double wy = w * v1;
const double wz = w * v2;
// 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);
// q . J^{-1} = q . adj(J)
y(qx,qy,qz,0,e) = wx * A11 + wy * A12 + wz * A13;
y(qx,qy,qz,1,e) = wx * A21 + wy * A22 + wz * A23;
y(qx,qy,qz,2,e) = wx * A31 + wy * A32 + wz * A33;
}
}
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 w = alpha * W[q];
const double v0 = const_v ? V(0,0,0) : V(0,q,e);
const double v1 = const_v ? V(1,0,0) : V(1,q,e);
const double v2 = const_v ? V(2,0,0) : V(2,q,e);
const double wx = w * v0;
const double wy = w * v1;
const double wz = w * v2;
// 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);
// q . J^{-1} = q . adj(J)
y(q,0,e) = wx * A11 + wy * A12 + wz * A13;
y(q,1,e) = wx * A21 + wy * A22 + wz * A23;
y(q,2,e) = wx * A31 + wy * A32 + wz * A33;
}
});
}
@@ -194,8 +184,8 @@ void PAConvectionApply2D(const int ne,
Gu[dy][qx] = 0.0;
for (int dx = 0; dx < D1D; ++dx)
{
const double bx = B(qx,dx);
const double gx = G(qx,dx);
const double bx = B(qx,dx);
const double gx = G(qx,dx);
const double x = u[dy][dx];
Bu[dy][qx] += bx * x;
Gu[dy][qx] += gx * x;
@@ -212,8 +202,8 @@ void PAConvectionApply2D(const int ne,
BGu[qy][qx] = 0.0;
for (int dy = 0; dy < D1D; ++dy)
{
const double bx = B(qy,dy);
const double gx = G(qy,dy);
const double bx = B(qy,dy);
const double gx = G(qy,dy);
GBu[qy][qx] += gx * Bu[dy][qx];
BGu[qy][qx] += bx * Gu[dy][qx];
}
@@ -242,7 +232,7 @@ void PAConvectionApply2D(const int ne,
BDGu[dy][qx] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
const double w = Bt(dy,qy);
const double w = Bt(dy,qy);
BDGu[dy][qx] += w * DGu[qy][qx];
}
}
@@ -254,7 +244,7 @@ void PAConvectionApply2D(const int ne,
double BBDGu = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
const double w = Bt(dx,qx);
const double w = Bt(dx,qx);
BBDGu += w * BDGu[dy][qx];
}
y(dx,dy,e) += BBDGu;
@@ -320,7 +310,7 @@ void SmemPAConvectionApply2D(const int ne,
{
const double bx = B(qx,dx);
const double gx = G(qx,dx);
const double x = u[tidz][dy][dx];
const double x = u[tidz][dy][dx];
Bu[tidz][dy][qx] += bx * x;
Gu[tidz][dy][qx] += gx * x;
}
@@ -337,8 +327,8 @@ void SmemPAConvectionApply2D(const int ne,
BGu[tidz][qy][qx] = 0.0;
for (int dy = 0; dy < D1D; ++dy)
{
const double bx = B(qy,dy);
const double gx = G(qy,dy);
const double bx = B(qy,dy);
const double gx = G(qy,dy);
GBu[tidz][qy][qx] += gx * Bu[tidz][dy][qx];
BGu[tidz][qy][qx] += bx * Gu[tidz][dy][qx];
}
@@ -369,7 +359,7 @@ void SmemPAConvectionApply2D(const int ne,
BDGu[tidz][dy][qx] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
const double w = Bt(dy,qy);
const double w = Bt(dy,qy);
BDGu[tidz][dy][qx] += w * DGu[tidz][qy][qx];
}
}
@@ -382,7 +372,7 @@ void SmemPAConvectionApply2D(const int ne,
double BBDGu = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
const double w = Bt(dx,qx);
const double w = Bt(dx,qx);
BBDGu += w * BDGu[tidz][dy][qx];
}
y(dx,dy,e) += BBDGu;
@@ -446,8 +436,8 @@ void PAConvectionApply3D(const int ne,
Gu[dz][dy][qx] = 0.0;
for (int dx = 0; dx < D1D; ++dx)
{
const double bx = B(qx,dx);
const double gx = G(qx,dx);
const double bx = B(qx,dx);
const double gx = G(qx,dx);
const double x = u[dz][dy][dx];
Bu[dz][dy][qx] += bx * x;
Gu[dz][dy][qx] += gx * x;
@@ -469,8 +459,8 @@ void PAConvectionApply3D(const int ne,
BGu[dz][qy][qx] = 0.0;
for (int dy = 0; dy < D1D; ++dy)
{
const double bx = B(qy,dy);
const double gx = G(qy,dy);
const double bx = B(qy,dy);
const double gx = G(qy,dy);
BBu[dz][qy][qx] += bx * Bu[dz][dy][qx];
GBu[dz][qy][qx] += gx * Bu[dz][dy][qx];
BGu[dz][qy][qx] += bx * Gu[dz][dy][qx];
@@ -492,8 +482,8 @@ void PAConvectionApply3D(const int ne,
BBGu[qz][qy][qx] = 0.0;
for (int dz = 0; dz < D1D; ++dz)
{
const double bx = B(qz,dz);
const double gx = G(qz,dz);
const double bx = B(qz,dz);
const double gx = G(qz,dz);
GBBu[qz][qy][qx] += gx * BBu[dz][qy][qx];
BGBu[qz][qy][qx] += bx * GBu[dz][qy][qx];
BBGu[qz][qy][qx] += bx * BGu[dz][qy][qx];
@@ -531,7 +521,7 @@ void PAConvectionApply3D(const int ne,
BDGu[dz][qy][qx] = 0.0;
for (int qz = 0; qz < Q1D; ++qz)
{
const double w = Bt(dz,qz);
const double w = Bt(dz,qz);
BDGu[dz][qy][qx] += w * DGu[qz][qy][qx];
}
}
@@ -547,7 +537,7 @@ void PAConvectionApply3D(const int ne,
BBDGu[dz][dy][qx] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
const double w = Bt(dy,qy);
const double w = Bt(dy,qy);
BBDGu[dz][dy][qx] += w * BDGu[dz][qy][qx];
}
}
@@ -562,7 +552,7 @@ void PAConvectionApply3D(const int ne,
double BBBDGu = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
const double w = Bt(dx,qx);
const double w = Bt(dx,qx);
BBBDGu += w * BBDGu[dz][dy][qx];
}
y(dx,dy,dz,e) += BBBDGu;
@@ -635,8 +625,8 @@ void SmemPAConvectionApply3D(const int ne,
double Gu_ = 0.0;
for (int dx = 0; dx < D1D; ++dx)
{
const double bx = B(qx,dx);
const double gx = G(qx,dx);
const double bx = B(qx,dx);
const double gx = G(qx,dx);
const double x = u[dz][dy][dx];
Bu_ += bx * x;
Gu_ += gx * x;
@@ -661,8 +651,8 @@ void SmemPAConvectionApply3D(const int ne,
double BGu_ = 0.0;
for (int dy = 0; dy < D1D; ++dy)
{
const double bx = B(qy,dy);
const double gx = G(qy,dy);
const double bx = B(qy,dy);
const double gx = G(qy,dy);
BBu_ += bx * Bu[dz][dy][qx];
GBu_ += gx * Bu[dz][dy][qx];
BGu_ += bx * Gu[dz][dy][qx];
@@ -688,8 +678,8 @@ void SmemPAConvectionApply3D(const int ne,
double BBGu_ = 0.0;
for (int dz = 0; dz < D1D; ++dz)
{
const double bx = B(qz,dz);
const double gx = G(qz,dz);
const double bx = B(qz,dz);
const double gx = G(qz,dz);
GBBu_ += gx * BBu[dz][qy][qx];
BGBu_ += bx * GBu[dz][qy][qx];
BBGu_ += bx * BGu[dz][qy][qx];
@@ -731,7 +721,7 @@ void SmemPAConvectionApply3D(const int ne,
double BDGu_ = 0.0;
for (int qz = 0; qz < Q1D; ++qz)
{
const double w = Bt(dz,qz);
const double w = Bt(dz,qz);
BDGu_ += w * DGu[qz][qy][qx];
}
BDGu[dz][qy][qx] = BDGu_;
@@ -749,7 +739,7 @@ void SmemPAConvectionApply3D(const int ne,
double BBDGu_ = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
const double w = Bt(dy,qy);
const double w = Bt(dy,qy);
BBDGu_ += w * BDGu[dz][qy][qx];
}
BBDGu[dz][dy][qx] = BBDGu_;
@@ -766,7 +756,7 @@ void SmemPAConvectionApply3D(const int ne,
double BBBDGu = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
const double w = Bt(dx,qx);
const double w = Bt(dx,qx);
BBBDGu += w * BBDGu[dz][dy][qx];
}
y(dx,dy,dz,e) = BBBDGu;
@@ -776,117 +766,6 @@ void SmemPAConvectionApply3D(const int ne,
});
}
template<int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0, int T_MAX = 0>
static void QEvalVGF2D(const int NE,
const double *b_,
const double *x_,
double *y_,
const int vdim = 1,
const int d1d = 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;
const auto b = Reshape(b_, Q1D, D1D);
const auto X = Reshape(x_, D1D, D1D, VDIM, NE);
auto C = Reshape(y_, VDIM, Q1D, Q1D, NE);
MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
{
constexpr int NBZ = 1;
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
MFEM_SHARED double B[MQ1*MD1];
mfem::kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
MFEM_SHARED double DD[NBZ][MD1*MD1];
MFEM_SHARED double DQ[NBZ][MD1*MQ1];
MFEM_SHARED double QQ[NBZ][MQ1*MQ1];
for (int c = 0; c < VDIM; c++)
{
mfem::kernels::LoadX<MD1,NBZ>(e,D1D,c,X,DD);
mfem::kernels::EvalX<MD1,MQ1,NBZ>(D1D,Q1D,B,DD,DQ);
mfem::kernels::EvalY<MD1,MQ1,NBZ>(D1D,Q1D,B,DQ,QQ);
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
double G;
mfem::kernels::PullEval<MQ1,NBZ>(qx,qy,QQ,G);
C(c,qx,qy,e) = G;
}
}
MFEM_SYNC_THREAD;
}
});
}
template<int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0, int T_MAX = 0>
static void QEvalVGF3D(const int NE,
const double *b_,
const double *x_,
double *y_,
const int vdim = 1,
const int d1d = 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;
const auto b = Reshape(b_, Q1D, D1D);
const auto X = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
auto C = Reshape(y_, VDIM, Q1D, Q1D, Q1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
{
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 MQ1 = T_Q1D ? T_Q1D : T_MAX;
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
MFEM_SHARED double B[MQ1*MD1];
mfem::kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
MFEM_SHARED double DDD[MD1*MD1*MD1];
MFEM_SHARED double DDQ[MD1*MD1*MQ1];
MFEM_SHARED double DQQ[MD1*MQ1*MQ1];
MFEM_SHARED double QQQ[MQ1*MQ1*MQ1];
for (int c = 0; c < VDIM; c++)
{
mfem::kernels::LoadX<MD1>(e,D1D,c,X,DDD);
mfem::kernels::EvalX<MD1,MQ1>(D1D,Q1D,B,DDD,DDQ);
mfem::kernels::EvalY<MD1,MQ1>(D1D,Q1D,B,DDQ,DQQ);
mfem::kernels::EvalZ<MD1,MQ1>(D1D,Q1D,B,DQQ,QQQ);
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
double G;
mfem::kernels::PullEval<MQ1>(qx,qy,qz,QQQ,G);
C(c,qx,qy,qz,e) = G;
}
}
}
MFEM_SYNC_THREAD;
}
});
}
void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assumes tensor-product elements
@@ -899,104 +778,16 @@ void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
ne = fes.GetNE();
const DofToQuad::Mode mode = DofToQuad::TENSOR;
#ifdef MFEM_USE_UMPIRE
const MemoryType temp_type = Device::GetDeviceMemoryType() == MemoryType::DEVICE_UMPIRE
? MemoryType::DEVICE_UMPIRE_2 : Device::GetDeviceMemoryType();
#else
const MemoryType temp_type = Device::GetDeviceMemoryType();
#endif
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mode, temp_type);
maps = &el.GetDofToQuad(*ir, mode);
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(symmDims * nq * ne, temp_type);
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
Vector vel;
if (VectorConstantCoefficient *cQ =
dynamic_cast<VectorConstantCoefficient*>(Q))
if (VectorConstantCoefficient *cQ = dynamic_cast<VectorConstantCoefficient*>(Q))
{
vel = cQ->GetVec();
}
else if (VectorGridFunctionCoefficient *vgfQ =
dynamic_cast<VectorGridFunctionCoefficient*>(Q))
{
Vector xe;
vel.SetSize(dim * nq * ne, temp_type);
const GridFunction *gf = vgfQ->GetGridFunction();
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
const FiniteElementSpace &gf_fes = *gf->FESpace();
const int vdim = gf_fes.GetVDim();
const Operator *R = gf_fes.GetElementRestriction(ordering);
const FiniteElement &el_gf = *gf_fes.GetFE(0);
const DofToQuad *maps_gf = &el_gf.GetDofToQuad(*ir, mode);
const int D1D = maps_gf->ndof;
const int Q1D = maps_gf->nqpt;
MFEM_VERIFY(R,"");
MFEM_VERIFY(vdim == dim, "");
MFEM_VERIFY(dim==2 || dim==3,"");
xe.SetSize(R->Height(), Device::GetMemoryType());
xe.UseDevice(true);
R->Mult(*gf, xe);
const auto B = maps_gf->B.Read();
const auto x = xe.Read();
auto y = vel.Write();
const int id = (D1D << 4 ) | Q1D;
if (dim == 2)
{
switch (id)
{
case 0x22: QEvalVGF2D<2,2,2>(ne,B,x,y); break;
case 0x33: QEvalVGF2D<2,3,3>(ne,B,x,y); break;
case 0x34: QEvalVGF2D<2,3,4>(ne,B,x,y); break;
default:
{
constexpr int MAX_DQ = 8;
MFEM_VERIFY(D1D <= MAX_DQ, "");
MFEM_VERIFY(Q1D <= MAX_DQ, "");
QEvalVGF2D<0,0,0,MAX_DQ>(ne,B,x,y,vdim,D1D,Q1D);
}
}
}
if (dim == 3)
{
switch (id)
{
case 0x23: QEvalVGF3D<3,2,3>(ne,B,x,y); break;
case 0x34: QEvalVGF3D<3,3,4>(ne,B,x,y); break;
case 0x35: QEvalVGF3D<3,3,5>(ne,B,x,y); break;
case 0x46: QEvalVGF3D<3,4,6>(ne,B,x,y); break;
case 0x48: QEvalVGF3D<3,4,8>(ne,B,x,y); break;
default:
{
constexpr int MAX_DQ = 6;
MFEM_VERIFY(D1D <= MAX_DQ, "");
MFEM_VERIFY(Q1D <= MAX_DQ, "");
QEvalVGF3D<0,0,0,MAX_DQ>(ne,B,x,y,vdim,D1D,Q1D);
}
}
}
}
else if (VectorQuadratureFunctionCoefficient* cQ =
dynamic_cast<VectorQuadratureFunctionCoefficient*>(Q))
{
const QuadratureFunction &qFun = cQ->GetQuadFunction();
MFEM_VERIFY(qFun.Size() == dim * nq * ne,
"Incompatible QuadratureFunction dimension \n");
MFEM_VERIFY(ir == &qFun.GetSpace()->GetElementIntRule(0),
"IntegrationRule used within integrator and in"
" QuadratureFunction appear to be different");
qFun.Read();
vel.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
}
else
{
vel.SetSize(dim * nq * ne);
@@ -1036,12 +827,9 @@ static void PAConvectionApply(const int dim,
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPAConvectionApply2D<2,2,8>(NE,B,G,Bt,Gt,op,x,y);
case 0x33: return SmemPAConvectionApply2D<3,3,4>(NE,B,G,Bt,Gt,op,x,y);
case 0x34: return SmemPAConvectionApply2D<3,4,4>(NE,B,G,Bt,Gt,op,x,y);
case 0x44: return SmemPAConvectionApply2D<4,4,4>(NE,B,G,Bt,Gt,op,x,y);
case 0x46: return SmemPAConvectionApply2D<4,6,4>(NE,B,G,Bt,Gt,op,x,y);
case 0x33: return SmemPAConvectionApply2D<3,3,3>(NE,B,G,Bt,Gt,op,x,y);
case 0x44: return SmemPAConvectionApply2D<4,4,2>(NE,B,G,Bt,Gt,op,x,y);
case 0x55: return SmemPAConvectionApply2D<5,5,2>(NE,B,G,Bt,Gt,op,x,y);
case 0x58: return SmemPAConvectionApply2D<5,8,2>(NE,B,G,Bt,Gt,op,x,y);
case 0x66: return SmemPAConvectionApply2D<6,6,1>(NE,B,G,Bt,Gt,op,x,y);
case 0x77: return SmemPAConvectionApply2D<7,7,1>(NE,B,G,Bt,Gt,op,x,y);
case 0x88: return SmemPAConvectionApply2D<8,8,1>(NE,B,G,Bt,Gt,op,x,y);
@@ -1054,12 +842,8 @@ static void PAConvectionApply(const int dim,
switch ((D1D << 4 ) | Q1D)
{
case 0x23: return SmemPAConvectionApply3D<2,3>(NE,B,G,Bt,Gt,op,x,y);
case 0x24: return SmemPAConvectionApply3D<2,4>(NE,B,G,Bt,Gt,op,x,y);
case 0x26: return SmemPAConvectionApply3D<2,6>(NE,B,G,Bt,Gt,op,x,y);
case 0x34: return SmemPAConvectionApply3D<3,4>(NE,B,G,Bt,Gt,op,x,y);
case 0x35: return SmemPAConvectionApply3D<3,5>(NE,B,G,Bt,Gt,op,x,y);
case 0x45: return SmemPAConvectionApply3D<4,5>(NE,B,G,Bt,Gt,op,x,y);
case 0x48: return SmemPAConvectionApply3D<4,8>(NE,B,G,Bt,Gt,op,x,y);
case 0x56: return SmemPAConvectionApply3D<5,6>(NE,B,G,Bt,Gt,op,x,y);
case 0x67: return SmemPAConvectionApply3D<6,7>(NE,B,G,Bt,Gt,op,x,y);
case 0x78: return SmemPAConvectionApply3D<7,8>(NE,B,G,Bt,Gt,op,x,y);
-27
View File
@@ -167,19 +167,6 @@ void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
r.SetSize(1);
r(0) = c_rho->constant;
}
else if (QuadratureFunctionCoefficient* c_rho =
dynamic_cast<QuadratureFunctionCoefficient*>(rho))
{
const QuadratureFunction &qFun = c_rho->GetQuadFunction();
MFEM_VERIFY(qFun.Size() == nq * nf,
"Incompatible QuadratureFunction dimension \n");
MFEM_VERIFY(ir == &qFun.GetSpace()->GetElementIntRule(0),
"IntegrationRule used within integrator and in"
" QuadratureFunction appear to be different");
qFun.Read();
r.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
}
else
{
r.SetSize(nq * nf);
@@ -213,20 +200,6 @@ void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
{
vel = c_u->GetVec();
}
else if (VectorQuadratureFunctionCoefficient* c_u =
dynamic_cast<VectorQuadratureFunctionCoefficient*>(u))
{
// Assumed to be in lexicographical ordering
const QuadratureFunction &qFun = c_u->GetQuadFunction();
MFEM_VERIFY(qFun.Size() == dim * nq * nf,
"Incompatible QuadratureFunction dimension \n");
MFEM_VERIFY(ir == &qFun.GetSpace()->GetElementIntRule(0),
"IntegrationRule used within integrator and in"
" QuadratureFunction appear to be different");
qFun.Read();
vel.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
}
else
{
vel.SetSize(dim * nq * nf);
+6 -6
View File
@@ -31,7 +31,7 @@ static void EADiffusionAssemble1D(const int NE,
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto A = Reshape(eadata.ReadWrite(), D1D, D1D, 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;
@@ -53,7 +53,7 @@ static void EADiffusionAssemble1D(const int NE,
{
val += r_Gj[k1] * D(k1, e) * r_Gi[k1];
}
A(i1, j1, e) += val;
A(i1, j1, e) = val;
}
}
});
@@ -75,7 +75,7 @@ static void EADiffusionAssemble2D(const int NE,
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.ReadWrite(), D1D, D1D, D1D, D1D, 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;
@@ -120,7 +120,7 @@ static void EADiffusionAssemble2D(const int NE,
+ gbi * D11 * gbj;
}
}
A(i1, i2, j1, j2, e) += val;
A(i1, i2, j1, j2, e) = val;
}
}
}
@@ -144,7 +144,7 @@ static void EADiffusionAssemble3D(const int NE,
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.ReadWrite(), D1D, D1D, D1D, D1D, D1D, D1D, 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;
@@ -208,7 +208,7 @@ static void EADiffusionAssemble3D(const int NE,
}
}
}
A(i1, i2, i3, j1, j2, j3, e) += val;
A(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
+215 -301
View File
@@ -170,53 +170,47 @@ static void PADiffusionSetup3D(const int Q1D,
const Vector &c,
Vector &d)
{
const int NQ = Q1D*Q1D*Q1D;
const bool const_c = c.Size() == 1;
const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1) :
Reshape(c.Read(), Q1D,Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D,Q1D, 6, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
auto D = Reshape(d.Write(), NQ, 6, NE);
MFEM_FORALL(e, NE,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
for (int q = 0; q < NQ; ++q)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double J11 = J(qx,qy,qz,0,0,e);
const double J21 = J(qx,qy,qz,1,0,e);
const double J31 = J(qx,qy,qz,2,0,e);
const double J12 = J(qx,qy,qz,0,1,e);
const double J22 = J(qx,qy,qz,1,1,e);
const double J32 = J(qx,qy,qz,2,1,e);
const double J13 = J(qx,qy,qz,0,2,e);
const double J23 = J(qx,qy,qz,1,2,e);
const double J33 = J(qx,qy,qz,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,0,0) : C(qx,qy,qz,e);
const double c_detJ = W(qx,qy,qz) * 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(qx,qy,qz,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
D(qx,qy,qz,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
D(qx,qy,qz,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
D(qx,qy,qz,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
D(qx,qy,qz,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
D(qx,qy,qz,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
}
}
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
}
});
}
@@ -259,7 +253,8 @@ static void PADiffusionSetup(const int dim,
}
}
void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes)
void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
const bool force)
{
// Assuming the same element type
fespace = &fes;
@@ -268,7 +263,7 @@ void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes)
const FiniteElement &el = *fes.GetFE(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
if (DeviceCanUseCeed() && !force)
{
if (ceedDataPtr) { delete ceedDataPtr; }
CeedData* ptr = new CeedData();
@@ -276,16 +271,17 @@ 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
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
ne = fes.GetNE();
const DofToQuad::Mode mode = DofToQuad::TENSOR;
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mode);
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
const int sdim = mesh->SpaceDimension();
maps = &el.GetDofToQuad(*ir, mode);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(symmDims * nq * ne, Device::GetDeviceMemoryType());
@@ -300,19 +296,6 @@ void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes)
coeff.SetSize(1);
coeff(0) = cQ->constant;
}
else if (QuadratureFunctionCoefficient* cQ =
dynamic_cast<QuadratureFunctionCoefficient*>(Q))
{
const QuadratureFunction &qFun = cQ->GetQuadFunction();
MFEM_VERIFY(qFun.Size() == ne*nq,
"Incompatible QuadratureFunction dimension \n");
MFEM_VERIFY(ir == &qFun.GetSpace()->GetElementIntRule(0),
"IntegrationRule used within integrator and in"
" QuadratureFunction appear to be different");
qFun.Read();
coeff.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
}
else
{
coeff.SetSize(nq * ne);
@@ -740,7 +723,6 @@ static void PADiffusionAssembleDiagonal(const int dim,
case 0x23: return SmemPADiffusionDiagonal3D<2,3>(NE,B,G,D,Y);
case 0x34: return SmemPADiffusionDiagonal3D<3,4>(NE,B,G,D,Y);
case 0x45: return SmemPADiffusionDiagonal3D<4,5>(NE,B,G,D,Y);
case 0x46: return SmemPADiffusionDiagonal3D<4,6>(NE,B,G,D,Y);
case 0x56: return SmemPADiffusionDiagonal3D<5,6>(NE,B,G,D,Y);
case 0x67: return SmemPADiffusionDiagonal3D<6,7>(NE,B,G,D,Y);
case 0x78: return SmemPADiffusionDiagonal3D<7,8>(NE,B,G,D,Y);
@@ -754,17 +736,9 @@ static void PADiffusionAssembleDiagonal(const int dim,
void DiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAssembleDiagonalPA(ceedDataPtr, diag);
}
else
#endif
{
PADiffusionAssembleDiagonal(dim, dofs1D, quad1D, ne,
maps->B, maps->G, pa_data, diag);
}
if (pa_data.Size()==0) { SetupPA(*fespace, true); }
PADiffusionAssembleDiagonal(dim, dofs1D, quad1D, ne,
maps->B, maps->G, pa_data, diag);
}
@@ -1333,33 +1307,7 @@ static void PADiffusionApply3D(const int NE,
});
}
// Half of B and G are stored in shared to get B, Bt, G and Gt.
// Indices computation for SmemPADiffusionApply3D.
static MFEM_HOST_DEVICE inline int qi(const int q, const int d, const int Q)
{
return (q<=d) ? q : Q-1-q;
}
static MFEM_HOST_DEVICE inline int dj(const int q, const int d, const int D)
{
return (q<=d) ? d : D-1-d;
}
static MFEM_HOST_DEVICE inline int qk(const int q, const int d, const int Q)
{
return (q<=d) ? Q-1-q : q;
}
static MFEM_HOST_DEVICE inline int dl(const int q, const int d, const int D)
{
return (q<=d) ? D-1-d : d;
}
static MFEM_HOST_DEVICE inline double sign(const int q, const int d)
{
return (q<=d) ? -1.0 : 1.0;
}
// Shared memory PA Diffusion Apply 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void SmemPADiffusionApply3D(const int NE,
const Array<double> &b_,
@@ -1372,27 +1320,28 @@ static void SmemPADiffusionApply3D(const int NE,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int M1Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int M1D = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= M1D, "");
MFEM_VERIFY(Q1D <= M1Q, "");
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= MD1, "");
MFEM_VERIFY(Q1D <= MQ1, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto g = Reshape(g_.Read(), Q1D, D1D);
auto d = Reshape(d_.Read(), Q1D, Q1D, Q1D, 6, NE);
auto d = Reshape(d_.Read(), Q1D*Q1D*Q1D, 6, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, 1,
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
{
const int tidz = MFEM_THREAD_ID(z);
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;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
MFEM_SHARED double sBG[MQ1*MD1];
double (*B)[MD1] = (double (*)[MD1]) sBG;
double (*G)[MD1] = (double (*)[MD1]) sBG;
double (*Bt)[MQ1] = (double (*)[MQ1]) sBG;
double (*Gt)[MQ1] = (double (*)[MQ1]) sBG;
constexpr int MDQ = MQ1 > MD1 ? MQ1 : MD1;
MFEM_SHARED double sBG[2][MQ1*MD1];
double (*B)[MD1] = (double (*)[MD1]) (sBG+0);
double (*G)[MD1] = (double (*)[MD1]) (sBG+1);
double (*Bt)[MQ1] = (double (*)[MQ1]) (sBG+0);
double (*Gt)[MQ1] = (double (*)[MQ1]) (sBG+1);
MFEM_SHARED double sm0[3][MDQ*MDQ*MDQ];
MFEM_SHARED double sm1[3][MDQ*MDQ*MDQ];
double (*X)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+2);
@@ -1410,127 +1359,108 @@ static void SmemPADiffusionApply3D(const int NE,
double (*QDD0)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+0);
double (*QDD1)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+1);
double (*QDD2)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+2);
MFEM_FOREACH_THREAD(dy,y,D1D)
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
MFEM_FOREACH_THREAD(dx,x,D1D)
{
X[dz][dy][dx] = x(dx,dy,dz,e);
}
}
MFEM_FOREACH_THREAD(qx,x,Q1D)
}
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
{
const int i = qi(qx,dy,Q1D);
const int j = dj(qx,dy,D1D);
const int k = qk(qx,dy,Q1D);
const int l = dl(qx,dy,D1D);
B[i][j] = b(qx,dy);
G[k][l] = g(qx,dy) * sign(qx,dy);
MFEM_FOREACH_THREAD(q,x,Q1D)
{
B[q][d] = b(q,d);
G[q][d] = g(q,d);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
MFEM_FOREACH_THREAD(dy,y,D1D)
{
double u[D1D], v[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++) { u[dz] = v[dz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dx = 0; dx < D1D; ++dx)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const int i = qi(qx,dx,Q1D);
const int j = dj(qx,dx,D1D);
const int k = qk(qx,dx,Q1D);
const int l = dl(qx,dx,D1D);
const double s = sign(qx,dx);
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
double u = 0.0;
double v = 0.0;
for (int dx = 0; dx < D1D; ++dx)
{
const double coords = X[dz][dy][dx];
u[dz] += coords * B[i][j];
v[dz] += coords * G[k][l] * s;
u += coords * B[qx][dx];
v += coords * G[qx][dx];
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
DDQ0[dz][dy][qx] = u[dz];
DDQ1[dz][dy][qx] = v[dz];
DDQ0[dz][dy][qx] = u;
DDQ1[dz][dy][qx] = v;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy,y,Q1D)
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
double u[D1D], v[D1D], w[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++) { u[dz] = v[dz] = w[dz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dy = 0; dy < D1D; ++dy)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const int i = qi(qy,dy,Q1D);
const int j = dj(qy,dy,D1D);
const int k = qk(qy,dy,Q1D);
const int l = dl(qy,dy,D1D);
const double s = sign(qy,dy);
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++)
double u = 0.0;
double v = 0.0;
double w = 0.0;
for (int dy = 0; dy < D1D; ++dy)
{
u[dz] += DDQ1[dz][dy][qx] * B[i][j];
v[dz] += DDQ0[dz][dy][qx] * G[k][l] * s;
w[dz] += DDQ0[dz][dy][qx] * B[i][j];
u += DDQ1[dz][dy][qx] * B[qy][dy];
v += DDQ0[dz][dy][qx] * G[qy][dy];
w += DDQ0[dz][dy][qx] * B[qy][dy];
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++)
{
DQQ0[dz][qy][qx] = u[dz];
DQQ1[dz][qy][qx] = v[dz];
DQQ2[dz][qy][qx] = w[dz];
DQQ0[dz][qy][qx] = u;
DQQ1[dz][qy][qx] = v;
DQQ2[dz][qy][qx] = w;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy,y,Q1D)
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
double u[Q1D], v[Q1D], w[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++) { u[qz] = v[qz] = w[qz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++)
double u = 0.0;
double v = 0.0;
double w = 0.0;
for (int dz = 0; dz < D1D; ++dz)
{
const int i = qi(qz,dz,Q1D);
const int j = dj(qz,dz,D1D);
const int k = qk(qz,dz,Q1D);
const int l = dl(qz,dz,D1D);
const double s = sign(qz,dz);
u[qz] += DQQ0[dz][qy][qx] * B[i][j];
v[qz] += DQQ1[dz][qy][qx] * B[i][j];
w[qz] += DQQ2[dz][qy][qx] * G[k][l] * s;
u += DQQ0[dz][qy][qx] * B[qz][dz];
v += DQQ1[dz][qy][qx] * B[qz][dz];
w += DQQ2[dz][qy][qx] * G[qz][dz];
}
QQQ0[qz][qy][qx] = u;
QQQ1[qz][qy][qx] = v;
QQQ2[qz][qy][qx] = w;
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++)
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const double O11 = d(qx,qy,qz,0,e);
const double O12 = d(qx,qy,qz,1,e);
const double O13 = d(qx,qy,qz,2,e);
const double O22 = d(qx,qy,qz,3,e);
const double O23 = d(qx,qy,qz,4,e);
const double O33 = d(qx,qy,qz,5,e);
const double gX = u[qz];
const double gY = v[qz];
const double gZ = w[qz];
const int q = qx + ((qy*Q1D) + (qz*Q1D*Q1D));
const double O11 = d(q,0,e);
const double O12 = d(q,1,e);
const double O13 = d(q,2,e);
const double O22 = d(q,3,e);
const double O23 = d(q,4,e);
const double O33 = d(q,5,e);
const double gX = QQQ0[qz][qy][qx];
const double gY = QQQ1[qz][qy][qx];
const double gZ = QQQ2[qz][qy][qx];
QQQ0[qz][qy][qx] = (O11*gX) + (O12*gY) + (O13*gZ);
QQQ1[qz][qy][qx] = (O12*gX) + (O22*gY) + (O23*gZ);
QQQ2[qz][qy][qx] = (O13*gX) + (O23*gY) + (O33*gZ);
@@ -1538,112 +1468,78 @@ static void SmemPADiffusionApply3D(const int NE,
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(d,y,D1D)
if (tidz == 0)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
MFEM_FOREACH_THREAD(d,y,D1D)
{
const int i = qi(q,d,Q1D);
const int j = dj(q,d,D1D);
const int k = qk(q,d,Q1D);
const int l = dl(q,d,D1D);
Bt[j][i] = b(q,d);
Gt[l][k] = g(q,d) * sign(q,d);
MFEM_FOREACH_THREAD(q,x,Q1D)
{
Bt[d][q] = b(q,d);
Gt[d][q] = g(q,d);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy,y,Q1D)
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
double u[Q1D], v[Q1D], w[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = v[qz] = w[qz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qx = 0; qx < Q1D; ++qx)
MFEM_FOREACH_THREAD(dx,x,D1D)
{
const int i = qi(qx,dx,Q1D);
const int j = dj(qx,dx,D1D);
const int k = qk(qx,dx,Q1D);
const int l = dl(qx,dx,D1D);
const double s = sign(qx,dx);
MFEM_UNROLL(MQ1)
double u = 0.0;
double v = 0.0;
double w = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
u += QQQ0[qz][qy][qx] * Gt[dx][qx];
v += QQQ1[qz][qy][qx] * Bt[dx][qx];
w += QQQ2[qz][qy][qx] * Bt[dx][qx];
}
QQD0[qz][qy][dx] = u;
QQD1[qz][qy][dx] = v;
QQD2[qz][qy][dx] = w;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u = 0.0;
double v = 0.0;
double w = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
u += QQD0[qz][qy][dx] * Bt[dy][qy];
v += QQD1[qz][qy][dx] * Gt[dy][qy];
w += QQD2[qz][qy][dx] * Bt[dy][qy];
}
QDD0[qz][dy][dx] = u;
QDD1[qz][dy][dx] = v;
QDD2[qz][dy][dx] = w;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u = 0.0;
double v = 0.0;
double w = 0.0;
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += QQQ0[qz][qy][qx] * Gt[l][k] * s;
v[qz] += QQQ1[qz][qy][qx] * Bt[j][i];
w[qz] += QQQ2[qz][qy][qx] * Bt[j][i];
u += QDD0[qz][dy][dx] * Bt[dz][qz];
v += QDD1[qz][dy][dx] * Bt[dz][qz];
w += QDD2[qz][dy][dx] * Gt[dz][qz];
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
QQD0[qz][qy][dx] = u[qz];
QQD1[qz][qy][dx] = v[qz];
QQD2[qz][qy][dx] = w[qz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[Q1D], v[Q1D], w[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = v[qz] = w[qz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qy = 0; qy < Q1D; ++qy)
{
const int i = qi(qy,dy,Q1D);
const int j = dj(qy,dy,D1D);
const int k = qk(qy,dy,Q1D);
const int l = dl(qy,dy,D1D);
const double s = sign(qy,dy);
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += QQD0[qz][qy][dx] * Bt[j][i];
v[qz] += QQD1[qz][qy][dx] * Gt[l][k] * s;
w[qz] += QQD2[qz][qy][dx] * Bt[j][i];
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
QDD0[qz][dy][dx] = u[qz];
QDD1[qz][dy][dx] = v[qz];
QDD2[qz][dy][dx] = w[qz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[D1D], v[D1D], w[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz) { u[dz] = v[dz] = w[dz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
const int i = qi(qz,dz,Q1D);
const int j = dj(qz,dz,D1D);
const int k = qk(qz,dz,Q1D);
const int l = dl(qz,dz,D1D);
const double s = sign(qz,dz);
u[dz] += QDD0[qz][dy][dx] * Bt[j][i];
v[dz] += QDD1[qz][dy][dx] * Bt[j][i];
w[dz] += QDD2[qz][dy][dx] * Gt[l][k] * s;
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
y(dx,dy,dz,e) += (u[dz] + v[dz] + w[dz]);
y(dx,dy,dz,e) += (u + v + w);
}
}
}
@@ -1678,11 +1574,9 @@ static void PADiffusionApply(const int dim,
MFEM_ABORT("OCCA PADiffusionApply unknown kernel!");
}
#endif // MFEM_USE_OCCA
const int ID = (D1D << 4 ) | Q1D;
if (dim == 2)
{
switch (ID)
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);
@@ -1695,13 +1589,11 @@ static void PADiffusionApply(const int dim,
default: return PADiffusionApply2D(NE,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
}
}
if (dim == 3)
else if (dim == 3)
{
switch (ID)
switch ((D1D << 4 ) | Q1D)
{
case 0x23: return SmemPADiffusionApply3D<2,3>(NE,B,G,D,X,Y);
case 0x24: return SmemPADiffusionApply3D<2,4>(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);
@@ -1722,7 +1614,29 @@ void DiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAddMultPA(ceedDataPtr, x, y);
const CeedScalar *x_ptr;
CeedScalar *y_ptr;
CeedMemType mem;
CeedGetPreferredMemType(internal::ceed, &mem);
if ( Device::Allows(Backend::CUDA) && mem==CEED_MEM_DEVICE )
{
x_ptr = x.Read();
y_ptr = y.ReadWrite();
}
else
{
x_ptr = x.HostRead();
y_ptr = y.HostReadWrite();
mem = CEED_MEM_HOST;
}
CeedVectorSetArray(ceedDataPtr->u, mem, CEED_USE_POINTER,
const_cast<CeedScalar*>(x_ptr));
CeedVectorSetArray(ceedDataPtr->v, mem, CEED_USE_POINTER, y_ptr);
CeedOperatorApplyAdd(ceedDataPtr->oper, ceedDataPtr->u, ceedDataPtr->v,
CEED_REQUEST_IMMEDIATE);
CeedVectorSyncArray(ceedDataPtr->v, mem);
}
else
#endif
+30 -1330
View File
File diff suppressed because it is too large Load Diff
+1 -11
View File
@@ -114,8 +114,6 @@ void PAHdivMassApply2D(const int D1D,
Vector &_y)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HDIV_MAX_D1D;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
@@ -240,7 +238,6 @@ void PAHdivMassAssembleDiagonal2D(const int D1D,
Vector &_diag)
{
constexpr static int VDIM = 2;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
@@ -617,8 +614,6 @@ static void PADivDivApply2D(const int D1D,
Vector &_y)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HDIV_MAX_D1D;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
auto Bot = Reshape(_Bot.Read(), D1D-1, Q1D);
@@ -982,7 +977,6 @@ static void PADivDivAssembleDiagonal2D(const int D1D,
Vector &_diag)
{
constexpr static int VDIM = 2;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
auto Gc = Reshape(_Gc.Read(), Q1D, D1D);
@@ -1406,8 +1400,6 @@ static void PAHdivL2Apply2D(const int D1D,
Vector &_y)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HDIV_MAX_D1D;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
auto Gc = Reshape(_Gc.Read(), Q1D, D1D);
@@ -1674,8 +1666,6 @@ static void PAHdivL2ApplyTranspose2D(const int D1D,
Vector &_y)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HDIV_MAX_D1D;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto L2Bo = Reshape(_L2Bo.Read(), Q1D, L2D1D);
auto Gct = Reshape(_Gct.Read(), D1D, Q1D);
@@ -1734,7 +1724,7 @@ static void PAHdivL2ApplyTranspose2D(const int D1D,
for (int qy = 0; qy < Q1D; ++qy)
{
double aX[MAX_D1D];
double aX[HDIV_MAX_D1D];
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y components
+6 -6
View File
@@ -30,7 +30,7 @@ static void EAMassAssemble1D(const int NE,
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto M = Reshape(eadata.ReadWrite(), D1D, D1D, 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;
@@ -52,7 +52,7 @@ static void EAMassAssemble1D(const int NE,
{
val += r_Bi[k1] * r_Bj[k1] * D(k1, e);
}
M(i1, j1, e) += val;
M(i1, j1, e) = val;
}
}
});
@@ -72,7 +72,7 @@ static void EAMassAssemble2D(const int NE,
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, NE);
auto M = Reshape(eadata.ReadWrite(), D1D, D1D, D1D, D1D, 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;
@@ -114,7 +114,7 @@ static void EAMassAssemble2D(const int NE,
* s_D[k1][k2];
}
}
M(i1, i2, j1, j2, e) += val;
M(i1, i2, j1, j2, e) = val;
}
}
}
@@ -136,7 +136,7 @@ static void EAMassAssemble3D(const int NE,
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.ReadWrite(), D1D, D1D, D1D, D1D, D1D, D1D, 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;
@@ -189,7 +189,7 @@ static void EAMassAssemble3D(const int NE,
}
}
}
M(i1, i2, i3, j1, j2, j3, e) += val;
M(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
+57 -101
View File
@@ -23,9 +23,8 @@ namespace mfem
// PA Mass Assemble kernel
void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
{
// Assuming the same element type
fespace = &fes;
Mesh *mesh = fes.GetMesh();
@@ -34,7 +33,7 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
ElementTransformation *T = mesh->GetElementTransformation(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, *T);
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
if (DeviceCanUseCeed() && !force)
{
if (ceedDataPtr) { delete ceedDataPtr; }
CeedData* ptr = new CeedData();
@@ -46,57 +45,27 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
dim = mesh->Dimension();
ne = fes.GetMesh()->GetNE();
nq = ir->GetNPoints();
const DofToQuad::Mode mode = DofToQuad::TENSOR;
const int flags = GeometricFactors::JACOBIANS |
GeometricFactors::COORDINATES;
#ifdef MFEM_USE_UMPIRE
const MemoryType temp_type = Device::GetDeviceMemoryType() == MemoryType::DEVICE_UMPIRE
? MemoryType::DEVICE_UMPIRE_2 : Device::GetDeviceMemoryType();
#else
const MemoryType temp_type = Device::GetDeviceMemoryType();
#endif
geom = mesh->GetGeometricFactors(*ir, flags, mode, temp_type);
maps = &el.GetDofToQuad(*ir, mode);
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::COORDINATES |
GeometricFactors::JACOBIANS);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
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) = cQ->constant;
}
else if (QuadratureCoefficient* cQ = dynamic_cast<QuadratureCoefficient*>(Q))
{
coeff = cQ->Data();
own_coeff = false;
}
else if (QuadratureFunctionCoefficient* cQ =
dynamic_cast<QuadratureFunctionCoefficient*>(Q))
{
const QuadratureFunction &qFun = cQ->GetQuadFunction();
MFEM_VERIFY(qFun.Size() == nq * ne,
"Incompatible QuadratureFunction dimension \n");
MFEM_VERIFY(ir == &qFun.GetSpace()->GetElementIntRule(0),
"IntegrationRule used within integrator and in"
" QuadratureFunction appear to be different");
qFun.Read();
coeff->MakeRef(const_cast<QuadratureFunction &>(qFun),0);
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);
@@ -111,11 +80,11 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
{
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,
{
@@ -134,43 +103,28 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
if (dim==3)
{
const int NE = ne;
const int Q1D = quad1D;
const bool const_c = coeff->Size() == 1;
const auto W = Reshape(ir->GetWeights().Read(),Q1D,Q1D,Q1D);
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,Q1D,3,3,NE);
const auto C = const_c ?
Reshape(coeff->Read(), 1,1,1,1) :
Reshape(coeff->Read(), Q1D,Q1D,Q1D,NE);
auto V = Reshape(pa_data.Write(), Q1D,Q1D,Q1D,NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
const int NQ = nq;
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);
auto v = Reshape(pa_data.Write(), NQ,NE);
MFEM_FORALL(e, NE,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
for (int q = 0; q < NQ; ++q)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double J11 = J(qx,qy,qz,0,0,e);
const double J12 = J(qx,qy,qz,0,1,e);
const double J13 = J(qx,qy,qz,0,2,e);
const double J21 = J(qx,qy,qz,1,0,e);
const double J22 = J(qx,qy,qz,1,1,e);
const double J23 = J(qx,qy,qz,1,2,e);
const double J31 = J(qx,qy,qz,2,0,e);
const double J32 = J(qx,qy,qz,2,1,e);
const double J33 = J(qx,qy,qz,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,0,0) : C(qx,qy,qz,e);
V(qx,qy,qz,e) = W(qx,qy,qz) * coeff * detJ;
}
}
const double J11 = J(q,0,0,e), J12 = J(q,0,1,e), J13 = J(q,0,2,e);
const double J21 = J(q,1,0,e), J22 = J(q,1,1,e), J23 = J(q,1,2,e);
const double J31 = J(q,2,0,e), J32 = J(q,2,1,e), 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);
v(q,e) = W[q] * coeff * detJ;
}
});
}
if (own_coeff) { delete coeff; }
}
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
@@ -472,12 +426,8 @@ static void PAMassAssembleDiagonal(const int dim, const int D1D,
switch ((D1D << 4 ) | Q1D)
{
case 0x23: return SmemPAMassAssembleDiagonal3D<2,3>(NE,B,D,Y);
case 0x24: return SmemPAMassAssembleDiagonal3D<2,4>(NE,B,D,Y);
case 0x26: return SmemPAMassAssembleDiagonal3D<2,6>(NE,B,D,Y);
case 0x34: return SmemPAMassAssembleDiagonal3D<3,4>(NE,B,D,Y);
case 0x35: return SmemPAMassAssembleDiagonal3D<3,5>(NE,B,D,Y);
case 0x45: return SmemPAMassAssembleDiagonal3D<4,5>(NE,B,D,Y);
case 0x48: return SmemPAMassAssembleDiagonal3D<4,8>(NE,B,D,Y);
case 0x56: return SmemPAMassAssembleDiagonal3D<5,6>(NE,B,D,Y);
case 0x67: return SmemPAMassAssembleDiagonal3D<6,7>(NE,B,D,Y);
case 0x78: return SmemPAMassAssembleDiagonal3D<7,8>(NE,B,D,Y);
@@ -490,16 +440,8 @@ static void PAMassAssembleDiagonal(const int dim, const int D1D,
void MassIntegrator::AssembleDiagonalPA(Vector &diag)
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAssembleDiagonalPA(ceedDataPtr, diag);
}
else
#endif
{
PAMassAssembleDiagonal(dim, dofs1D, quad1D, ne, maps->B, pa_data, diag);
}
if (pa_data.Size()==0) { SetupPA(*fespace, true); }
PAMassAssembleDiagonal(dim, dofs1D, quad1D, ne, maps->B, pa_data, diag);
}
@@ -697,7 +639,6 @@ static void SmemPAMassApply2D(const int NE,
const int d1d = 0,
const int q1d = 0)
{
MFEM_CONTRACT_VAR(bt_);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
@@ -961,7 +902,6 @@ static void SmemPAMassApply3D(const int NE,
const int d1d = 0,
const int q1d = 0)
{
MFEM_CONTRACT_VAR(bt_);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int M1Q = T_Q1D ? T_Q1D : MAX_Q1D;
@@ -1211,13 +1151,10 @@ static void PAMassApply(const int dim,
case 0x24: return SmemPAMassApply2D<2,4,16>(NE,B,Bt,D,X,Y);
case 0x33: return SmemPAMassApply2D<3,3,16>(NE,B,Bt,D,X,Y);
case 0x34: return SmemPAMassApply2D<3,4,16>(NE,B,Bt,D,X,Y);
case 0x35: return SmemPAMassApply2D<3,5,16>(NE,B,Bt,D,X,Y);
case 0x36: return SmemPAMassApply2D<3,6,16>(NE,B,Bt,D,X,Y);
case 0x44: return SmemPAMassApply2D<4,4,8>(NE,B,Bt,D,X,Y);
case 0x46: return SmemPAMassApply2D<4,6,8>(NE,B,Bt,D,X,Y);
case 0x48: return SmemPAMassApply2D<4,8,4>(NE,B,Bt,D,X,Y);
case 0x55: return SmemPAMassApply2D<5,5,8>(NE,B,Bt,D,X,Y);
case 0x57: return SmemPAMassApply2D<5,7,8>(NE,B,Bt,D,X,Y);
case 0x58: return SmemPAMassApply2D<5,8,2>(NE,B,Bt,D,X,Y);
case 0x66: return SmemPAMassApply2D<6,6,4>(NE,B,Bt,D,X,Y);
case 0x77: return SmemPAMassApply2D<7,7,4>(NE,B,Bt,D,X,Y);
@@ -1225,7 +1162,6 @@ static void PAMassApply(const int dim,
case 0x99: return SmemPAMassApply2D<9,9,2>(NE,B,Bt,D,X,Y);
default: return PAMassApply2D(NE,B,Bt,D,X,Y,D1D,Q1D);
}
mfem::out << "Unknown 2D kernel 0x" << std::hex << id << std::endl;
}
else if (dim == 3)
{
@@ -1234,9 +1170,7 @@ static void PAMassApply(const int dim,
case 0x23: return SmemPAMassApply3D<2,3>(NE,B,Bt,D,X,Y);
case 0x24: return SmemPAMassApply3D<2,4>(NE,B,Bt,D,X,Y);
case 0x34: return SmemPAMassApply3D<3,4>(NE,B,Bt,D,X,Y);
case 0x35: return SmemPAMassApply3D<3,5>(NE,B,Bt,D,X,Y);
case 0x36: return SmemPAMassApply3D<3,6>(NE,B,Bt,D,X,Y);
case 0x37: return SmemPAMassApply3D<3,7>(NE,B,Bt,D,X,Y);
case 0x45: return SmemPAMassApply3D<4,5>(NE,B,Bt,D,X,Y);
case 0x46: return SmemPAMassApply3D<4,6>(NE,B,Bt,D,X,Y);
case 0x48: return SmemPAMassApply3D<4,8>(NE,B,Bt,D,X,Y);
@@ -1248,8 +1182,8 @@ static void PAMassApply(const int dim,
case 0x9A: return SmemPAMassApply3D<9,10>(NE,B,Bt,D,X,Y);
default: return PAMassApply3D(NE,B,Bt,D,X,Y,D1D,Q1D);
}
mfem::out << "Unknown 3D kernel 0x" << std::hex << id << std::endl;
}
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
MFEM_ABORT("Unknown kernel.");
}
@@ -1258,7 +1192,29 @@ void MassIntegrator::AddMultPA(const Vector &x, Vector &y) const
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAddMultPA(ceedDataPtr, x, y);
const CeedScalar *x_ptr;
CeedScalar *y_ptr;
CeedMemType mem;
CeedGetPreferredMemType(internal::ceed, &mem);
if ( Device::Allows(Backend::CUDA) && mem==CEED_MEM_DEVICE )
{
x_ptr = x.Read();
y_ptr = y.ReadWrite();
}
else
{
x_ptr = x.HostRead();
y_ptr = y.HostReadWrite();
mem = CEED_MEM_HOST;
}
CeedVectorSetArray(ceedDataPtr->u, mem, CEED_USE_POINTER,
const_cast<CeedScalar*>(x_ptr));
CeedVectorSetArray(ceedDataPtr->v, mem, CEED_USE_POINTER, y_ptr);
CeedOperatorApplyAdd(ceedDataPtr->oper, ceedDataPtr->u, ceedDataPtr->v,
CEED_REQUEST_IMMEDIATE);
CeedVectorSyncArray(ceedDataPtr->v, mem);
}
else
#endif
+1 -1
View File
@@ -25,7 +25,7 @@ void TransposeIntegrator::AssembleEA(const FiniteElementSpace &fes,
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.ReadWrite(), dofs, dofs, ne);
auto AT = Reshape(ea_data.Write(), dofs, dofs, ne);
MFEM_FORALL(e, ne,
{
for (int i = 0; i < dofs; i++)
+7 -30
View File
@@ -9,14 +9,12 @@
// 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 PAHcurlSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
@@ -24,7 +22,6 @@ void PAHcurlSetup2D(const int Q1D,
Vector &op);
void PAHcurlSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
@@ -175,36 +172,16 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
const int coeffDim = VQ ? VQ->GetVDim() : 1;
Vector coeff(coeffDim * ne * nq);
Vector coeff(ne * nq);
coeff = 1.0;
auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
if (Q || VQ)
if (Q)
{
Vector D(VQ ? coeffDim : 0);
if (VQ)
{
MFEM_VERIFY(coeffDim == dim, "");
}
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
if (VQ)
{
VQ->Eval(D, *tr, ir->IntPoint(p));
for (int i=0; i<coeffDim; ++i)
{
coeffh(i, p, e) = D[i];
}
}
else
{
coeffh(0, p, e) = Q->Eval(*tr, ir->IntPoint(p));
}
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
@@ -213,12 +190,12 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 3)
@@ -371,12 +348,12 @@ void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
// Use the same setup functions as VectorFEMassIntegrator.
if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, 1, ne, ir->GetWeights(), geom->J,
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, 1, ne, ir->GetWeights(), geom->J,
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
-8
View File
@@ -12,7 +12,6 @@
// Implementation of Coefficient class
#include "fem.hpp"
#include "../linalg/dtensor.hpp"
#include <cmath>
#include <limits>
@@ -22,13 +21,6 @@ namespace mfem
using namespace std;
double QuadratureCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
auto coeff = mfem::Reshape(qData->HostRead(), nip, NE);
return coeff(ip.index, T.ElementNo);
}
double PWConstCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
+1 -31
View File
@@ -30,10 +30,7 @@ class ParMesh;
/** @brief Base class Coefficients that optionally depend on space and time.
These are used by the BilinearFormIntegrator, LinearFormIntegrator, and
NonlinearFormIntegrator classes to represent the physical coefficients in
the PDEs that are being discretized. This class can also be used in a more
general way to represent functions that don't necessarily belong to a FE
space, e.g., to project onto GridFunctions to use as initial conditions,
exact solutions, etc. See, e.g., ex4 or ex22 for these uses. */
the PDEs that are being discretized. */
class Coefficient
{
protected:
@@ -87,33 +84,6 @@ public:
{ return (constant); }
};
/// class for quadrature coefficient
class QuadratureCoefficient : public Coefficient
{
private:
const int nip;
const int NE;
public:
Vector *qData{nullptr};
//Set external data
QuadratureCoefficient(Vector *Data, int in_nip, int in_NE)
: qData(Data), nip(in_nip), NE(in_NE)
{ }
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
Vector *Data()
{
return qData;
}
};
/// class for piecewise constant coefficient
/** @brief A piecewise constant coefficient with the constants keyed
off the element attribute numbers. */
class PWConstCoefficient : public Coefficient
+53 -135
View File
@@ -342,10 +342,11 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
int ci)
{
FiniteElementSpace * fes = blfr->FESpace();
int vsize = fes->GetVSize();
// Allocate temporary vectors
Vector b_0(vsize); b_0 = 0.0;
Vector b_0(vsize); b_0 = 0.0;
// Extract the real and imaginary parts of the input vectors
MFEM_ASSERT(x.Size() == 2 * vsize, "Input GridFunction of incorrect size!");
@@ -359,7 +360,8 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
if (conv == ComplexOperator::BLOCK_SYMMETRIC) { b_i *= -1.0; }
int tvsize = fes->GetTrueVSize();
OperatorHandle A_r, A_i;
SparseMatrix * A_r = nullptr;
SparseMatrix * A_i = nullptr;
X.SetSize(2 * tvsize);
B.SetSize(2 * tvsize);
@@ -372,39 +374,42 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
if (RealInteg())
{
A_r = new SparseMatrix;
blfr->SetDiagonalPolicy(diag_policy);
b_0 = b_r;
blfr->FormLinearSystem(ess_tdof_list, x_r, b_0, A_r, X_0, B_0, ci);
blfr->FormLinearSystem(ess_tdof_list, x_r, b_0, *A_r, X_0, B_0, ci);
X_r = X_0; B_r = B_0;
b_0 = b_i;
blfr->FormLinearSystem(ess_tdof_list, x_i, b_0, A_r, X_0, B_0, ci);
blfr->FormLinearSystem(ess_tdof_list, x_i, b_0, *A_r, X_0, B_0, ci);
X_i = X_0; B_i = B_0;
if (ImagInteg())
{
A_i = new SparseMatrix;
blfi->SetDiagonalPolicy(mfem::Matrix::DiagonalPolicy::DIAG_ZERO);
b_0 = 0.0;
blfi->FormLinearSystem(ess_tdof_list, x_i, b_0, A_i, X_0, B_0, false);
blfi->FormLinearSystem(ess_tdof_list, x_i, b_0, *A_i, X_0, B_0, false);
B_r -= B_0;
b_0 = 0.0;
blfi->FormLinearSystem(ess_tdof_list, x_r, b_0, A_i, X_0, B_0, false);
blfi->FormLinearSystem(ess_tdof_list, x_r, b_0, *A_i, X_0, B_0, false);
B_i += B_0;
}
}
else if (ImagInteg())
{
A_i = new SparseMatrix;
blfi->SetDiagonalPolicy(diag_policy);
b_0 = b_i;
blfi->FormLinearSystem(ess_tdof_list, x_r, b_0, A_i, X_0, B_0, ci);
blfi->FormLinearSystem(ess_tdof_list, x_r, b_0, *A_i, X_0, B_0, ci);
X_r = X_0; B_i = B_0;
b_0 = b_r; b_0 *= -1.0;
blfi->FormLinearSystem(ess_tdof_list, x_i, b_0, A_i, X_0, B_0, ci);
blfi->FormLinearSystem(ess_tdof_list, x_i, b_0, *A_i, X_0, B_0, ci);
X_i = X_0; B_r = B_0; B_r *= -1.0;
}
else
@@ -412,55 +417,16 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
MFEM_ABORT("Real and Imaginary part of the Sesquilinear form are empty");
}
if (RealInteg() && ImagInteg())
{
// Modify RHS and offdiagonal blocks (imaginary parts of the matrix) to
// conform with standard essential BC treatment
if (A_i.Is<ConstrainedOperator>())
{
int n = ess_tdof_list.Size();
for (int k = 0; k < n; k++)
{
int j = ess_tdof_list[k];
B_r(j) = X_r(j);
B_i(j) = X_i(j);
}
A_i.As<ConstrainedOperator>()->SetDiagonalPolicy
(mfem::Operator::DiagonalPolicy::DIAG_ZERO);
}
}
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
{
B_i *= -1.0;
b_i *= -1.0;
}
// A = A_r + i A_i
A.Clear();
if ( A_r.Type() == Operator::MFEM_SPARSEMAT ||
A_i.Type() == Operator::MFEM_SPARSEMAT )
{
ComplexSparseMatrix * A_sp =
new ComplexSparseMatrix(A_r.As<SparseMatrix>(),
A_i.As<SparseMatrix>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexSparseMatrix>(A_sp, true);
}
else
{
ComplexOperator * A_op =
new ComplexOperator(A_r.Ptr(),
A_i.Ptr(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexOperator>(A_op, true);
}
A_r.SetOperatorOwner(false);
A_i.SetOperatorOwner(false);
ComplexSparseMatrix * A_sp;
A_sp = new ComplexSparseMatrix(A_r, A_i, true, true, conv);
A.Reset<ComplexSparseMatrix>(A_sp, true);
}
void
@@ -468,60 +434,31 @@ SesquilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
OperatorHandle &A)
{
OperatorHandle A_r, A_i;
SparseMatrix * A_r = nullptr;
SparseMatrix * A_i = nullptr;
if (RealInteg())
{
A_r = new SparseMatrix;
blfr->SetDiagonalPolicy(diag_policy);
blfr->FormSystemMatrix(ess_tdof_list, A_r);
blfr->FormSystemMatrix(ess_tdof_list, *A_r);
}
if (ImagInteg())
{
blfi->SetDiagonalPolicy(RealInteg() ?
mfem::Matrix::DiagonalPolicy::DIAG_ZERO :
diag_policy);
blfi->FormSystemMatrix(ess_tdof_list, A_i);
A_i = new SparseMatrix;
blfr->SetDiagonalPolicy(diag_policy);
blfi->FormSystemMatrix(ess_tdof_list, *A_i);
}
if (!RealInteg() && !ImagInteg())
{
MFEM_ABORT("Both Real and Imaginary part of the Sesquilinear form are empty");
}
if (RealInteg() && ImagInteg())
{
// Modify offdiagonal blocks (imaginary parts of the matrix) to conform
// with standard essential BC treatment
if (A_i.Is<ConstrainedOperator>())
{
A_i.As<ConstrainedOperator>()->SetDiagonalPolicy
(mfem::Operator::DiagonalPolicy::DIAG_ZERO);
}
}
// A = A_r + i A_i
A.Clear();
if ( A_r.Type() == Operator::MFEM_SPARSEMAT ||
A_i.Type() == Operator::MFEM_SPARSEMAT )
{
ComplexSparseMatrix * A_sp =
new ComplexSparseMatrix(A_r.As<SparseMatrix>(),
A_i.As<SparseMatrix>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexSparseMatrix>(A_sp, true);
}
else
{
ComplexOperator * A_op =
new ComplexOperator(A_r.Ptr(),
A_i.Ptr(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexOperator>(A_op, true);
}
A_r.SetOperatorOwner(false);
A_i.SetOperatorOwner(false);
ComplexSparseMatrix * A_sp =
new ComplexSparseMatrix(A_r, A_i, true, true, conv);
A.Reset<ComplexSparseMatrix>(A_sp, true);
}
void
@@ -709,7 +646,7 @@ ParComplexLinearForm::ParComplexLinearForm(ParFiniteElementSpace *pfes,
int n = (HYPRE_AssumedPartitionCheck()) ? 2 : pfes->GetNRanks();
tdof_offsets = new HYPRE_Int[n+1];
for (int i = 0; i <= n; i++)
for (int i=0; i<=n; i++)
{
tdof_offsets[i] = 2 * tdof_offsets_fes[i];
}
@@ -717,8 +654,7 @@ ParComplexLinearForm::ParComplexLinearForm(ParFiniteElementSpace *pfes,
ParComplexLinearForm::ParComplexLinearForm(ParFiniteElementSpace *pfes,
ParLinearForm *plf_r,
ParLinearForm *plf_i,
ParLinearForm *plf_r, ParLinearForm *plf_i,
ComplexOperator::Convention
convention)
: Vector(2*(pfes->GetVSize())),
@@ -734,7 +670,7 @@ ParComplexLinearForm::ParComplexLinearForm(ParFiniteElementSpace *pfes,
int n = (HYPRE_AssumedPartitionCheck()) ? 2 : pfes->GetNRanks();
tdof_offsets = new HYPRE_Int[n+1];
for (int i = 0; i <= n; i++)
for (int i=0; i<=n; i++)
{
tdof_offsets[i] = 2 * tdof_offsets_fes[i];
}
@@ -881,8 +817,7 @@ ParSesquilinearForm::ParSesquilinearForm(ParFiniteElementSpace *pf,
{}
ParSesquilinearForm::ParSesquilinearForm(ParFiniteElementSpace *pf,
ParBilinearForm *pbfr,
ParBilinearForm *pbfi,
ParBilinearForm *pbfr, ParBilinearForm *pbfi,
ComplexOperator::Convention convention)
: conv(convention),
pblfr(new ParBilinearForm(pf,pbfr)),
@@ -978,10 +913,9 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
int vsize = pfes->GetVSize();
// Allocate temporary vectors
Vector b_0(vsize); b_0 = 0.0;
Vector b_0(vsize); b_0 = 0.0;
// Extract the real and imaginary parts of the input vectors
MFEM_ASSERT(x.Size() == 2 * vsize, "Input GridFunction of incorrect size!");
Vector x_r(x.GetData(), vsize);
Vector x_i(&(x.GetData())[vsize], vsize);
@@ -1040,34 +974,25 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
MFEM_ABORT("Real and Imaginary part of the Sesquilinear form are empty");
}
// Modify RHS and offdiagonal blocks (Imaginary parts of the matrix) to
// conform with standard essential BC treatment i.e. zero out rows and
// columns and place ones on the diagonal.
if (RealInteg() && ImagInteg())
{
int n = ess_tdof_list.Size();
// Modify RHS to conform with standard essential BC treatment
for (int k = 0; k < n; k++)
{
int j=ess_tdof_list[k];
B_r(j) = X_r(j);
B_i(j) = X_i(j);
}
// Modify offdiagonal blocks (imaginary parts of the matrix) to conform
// with standard essential BC treatment
if ( A_i.Type() == Operator::Hypre_ParCSR )
{
HypreParMatrix * Ah;
A_i.Get(Ah);
hypre_ParCSRMatrix *Aih = *Ah;
for (int k = 0; k < n; k++)
HypreParMatrix * Ah; A_i.Get(Ah);
int n = ess_tdof_list.Size();
hypre_ParCSRMatrix * Aih =
(hypre_ParCSRMatrix *)const_cast<HypreParMatrix&>(*Ah);
for (int k=0; k<n; k++)
{
int j = ess_tdof_list[k];
int j=ess_tdof_list[k];
Aih->diag->data[Aih->diag->i[j]] = 0.0;
B_r(j) = X_r(j);
B_i(j) = X_i(j);
}
}
else
{
A_i.As<ConstrainedOperator>()->SetDiagonalPolicy
(mfem::Operator::DiagonalPolicy::DIAG_ZERO);
}
}
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
@@ -1075,7 +1000,6 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
B_i *= -1.0;
b_i *= -1.0;
}
// A = A_r + i A_i
A.Clear();
if ( A_r.Type() == Operator::Hypre_ParCSR ||
@@ -1099,8 +1023,6 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
conv);
A.Reset<ComplexOperator>(A_op, true);
}
A_r.SetOperatorOwner(false);
A_i.SetOperatorOwner(false);
}
void
@@ -1121,27 +1043,25 @@ ParSesquilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
MFEM_ABORT("Both Real and Imaginary part of the Sesquilinear form are empty");
}
// Modify offdiagonal blocks (Imaginary parts of the matrix) to conform with
// standard essential BC treatment i.e. zero out rows and columns and place
// ones on the diagonal.
if (RealInteg() && ImagInteg())
{
// Modify offdiagonal blocks (imaginary parts of the matrix) to conform
// with standard essential BC treatment
if ( A_i.Type() == Operator::Hypre_ParCSR )
{
int n = ess_tdof_list.Size();
HypreParMatrix * Ah;
A_i.Get(Ah);
hypre_ParCSRMatrix * Aih = *Ah;
for (int k = 0; k < n; k++)
int j;
HypreParMatrix * Ah; A_i.Get(Ah);
hypre_ParCSRMatrix * Aih =
(hypre_ParCSRMatrix *)const_cast<HypreParMatrix&>(*Ah);
for (int k=0; k<n; k++)
{
int j = ess_tdof_list[k];
j=ess_tdof_list[k];
Aih->diag->data[Aih->diag->i[j]] = 0.0;
}
}
else
{
A_i.As<ConstrainedOperator>()->SetDiagonalPolicy
(mfem::Operator::DiagonalPolicy::DIAG_ZERO);
}
}
// A = A_r + i A_i
@@ -1167,8 +1087,6 @@ ParSesquilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
conv);
A.Reset<ComplexOperator>(A_op, true);
}
A_r.SetOperatorOwner(false);
A_i.SetOperatorOwner(false);
}
void
+1 -31
View File
@@ -219,21 +219,6 @@ public:
void SetConvention(const ComplexOperator::Convention &
convention) { conv = convention; }
/// Set the desired assembly level.
/** Valid choices are:
- AssemblyLevel::FULL (default)
- AssemblyLevel::PARTIAL
- AssemblyLevel::ELEMENT
- AssemblyLevel::NONE
This method must be called before assembly. */
void SetAssemblyLevel(AssemblyLevel assembly_level)
{
blfr->SetAssemblyLevel(assembly_level);
blfi->SetAssemblyLevel(assembly_level);
}
BilinearForm & real() { return *blfr; }
BilinearForm & imag() { return *blfi; }
const BilinearForm & real() const { return *blfr; }
@@ -493,7 +478,7 @@ public:
/** Class for a parallel sesquilinear form
A sesquilinear form is a generalization of a bilinear form to complex-valued
fields. Sesquilinear forms are linear in the second argument but the
fields. Sesquilinear forms are linear in the second argument but but the
first argument involves a complex conjugate in the sense that:
a(alpha u, beta v) = conj(alpha) beta a(u, v)
@@ -539,21 +524,6 @@ public:
void SetConvention(const ComplexOperator::Convention &
convention) { conv = convention; }
/// Set the desired assembly level.
/** Valid choices are:
- AssemblyLevel::FULL (default)
- AssemblyLevel::PARTIAL
- AssemblyLevel::ELEMENT
- AssemblyLevel::NONE
This method must be called before assembly. */
void SetAssemblyLevel(AssemblyLevel assembly_level)
{
pblfr->SetAssemblyLevel(assembly_level);
pblfi->SetAssemblyLevel(assembly_level);
}
ParBilinearForm & real() { return *pblfr; }
ParBilinearForm & imag() { return *pblfi; }
const ParBilinearForm & real() const { return *pblfr; }
+8 -40
View File
@@ -415,6 +415,9 @@ void VisItDataCollection::SetMesh(MPI_Comm comm, Mesh *new_mesh)
void VisItDataCollection::RegisterField(const std::string& name,
GridFunction *gf)
{
DataCollection::RegisterField(name, gf);
field_info_map[name] = VisItFieldInfo("nodes", gf->VectorDim());
int LOD = 1;
if (gf->FESpace()->GetNURBSext())
{
@@ -428,27 +431,6 @@ void VisItDataCollection::RegisterField(const std::string& name,
}
}
DataCollection::RegisterField(name, gf);
field_info_map[name] = VisItFieldInfo("nodes", gf->VectorDim(), LOD);
visit_levels_of_detail = std::max(visit_levels_of_detail, LOD);
}
void VisItDataCollection::RegisterQField(const std::string& name,
QuadratureFunction *qf)
{
int LOD = -1;
Mesh *mesh = qf->GetSpace()->GetMesh();
for (int e=0; e<qf->GetSpace()->GetNE(); e++)
{
int locLOD = GlobGeometryRefiner.GetRefinementLevelFromElems(
mesh->GetElementBaseGeometry(e),
qf->GetElementIntRule(e).GetNPoints());
LOD = std::max(LOD,locLOD);
}
DataCollection::RegisterQField(name, qf);
field_info_map[name] = VisItFieldInfo("elements", 1, LOD);
visit_levels_of_detail = std::max(visit_levels_of_detail, LOD);
}
@@ -616,28 +598,14 @@ void VisItDataCollection::LoadFields()
// TODO: 1) load parallel GridFunction on one processor
if (serial)
{
if ((it->second).association == "nodes")
{
field_map.Register(it->first, new GridFunction(mesh, file), own_data);
}
else if ((it->second).association == "elements")
{
q_field_map.Register(it->first, new QuadratureFunction(mesh, file), own_data);
}
field_map.Register(it->first, new GridFunction(mesh, file), own_data);
}
else
{
#ifdef MFEM_USE_MPI
if ((it->second).association == "nodes")
{
field_map.Register(
it->first,
new ParGridFunction(dynamic_cast<ParMesh*>(mesh), file), own_data);
}
else if ((it->second).association == "elements")
{
q_field_map.Register(it->first, new QuadratureFunction(mesh, file), own_data);
}
field_map.Register(
it->first,
new ParGridFunction(dynamic_cast<ParMesh*>(mesh), file), own_data);
#else
error = READ_ERROR;
MFEM_WARNING("Reading parallel format in serial is not supported");
@@ -672,7 +640,7 @@ std::string VisItDataCollection::GetVisItRootString()
{
ftags["assoc"] = picojson::value((it->second).association);
ftags["comps"] = picojson::value(to_string((it->second).num_components));
ftags["lod"] = picojson::value(to_string((it->second).lod));
ftags["lod"] = picojson::value(to_string(visit_levels_of_detail));
field["path"] = picojson::value(path_str + it->first + file_ext_format);
field["tags"] = picojson::value(ftags);
fields[it->first] = picojson::value(field);
+3 -10
View File
@@ -391,10 +391,9 @@ class VisItFieldInfo
public:
std::string association;
int num_components;
int lod;
VisItFieldInfo() { association = ""; num_components = 0; lod = 1;}
VisItFieldInfo(std::string _association, int _num_components, int _lod = 1)
{ association = _association; num_components = _num_components; lod =_lod;}
VisItFieldInfo() { association = ""; num_components = 0; }
VisItFieldInfo(std::string _association, int _num_components)
{ association = _association; num_components = _num_components; }
};
/// Data collection with VisIt I/O routines
@@ -446,12 +445,6 @@ public:
/// Add a grid function to the collection and update the root file
virtual void RegisterField(const std::string& field_name, GridFunction *gf);
/// Add a quadrature function to the collection and update the root file.
/** Visualization of quadrature function is not supported in VisIt(3.12).
A patch has been sent to VisIt developers in June 2020. */
virtual void RegisterQField(const std::string& q_field_name,
QuadratureFunction *qf);
/// Set VisIt parameter: default levels of detail for the MultiresControl
void SetLevelsOfDetail(int levels_of_detail);
+1 -4
View File
@@ -37,8 +37,7 @@ public:
ClosedUniform = 4, ///< Nodes: x_i = i/(n-1), i=0,...,n-1
OpenHalfUniform = 5, ///< Nodes: x_i = (i+1/2)/n, i=0,...,n-1
Serendipity = 6, ///< Serendipity basis (squares / cubes)
ClosedGL = 7, ///< Closed GaussLegendre
NumBasisTypes = 8 /**< Keep track of maximum types to prevent
NumBasisTypes = 7 /**< Keep track of maximum types to prevent
hard-coding */
};
/** @brief If the input does not represents a valid BasisType, abort with an
@@ -70,7 +69,6 @@ public:
case ClosedUniform: return Quadrature1D::ClosedUniform;
case OpenHalfUniform: return Quadrature1D::OpenHalfUniform;
case Serendipity: return Quadrature1D::GaussLobatto;
case ClosedGL: return Quadrature1D::ClosedGL;
}
return Quadrature1D::Invalid;
}
@@ -84,7 +82,6 @@ public:
case Quadrature1D::OpenUniform: return OpenUniform;
case Quadrature1D::ClosedUniform: return ClosedUniform;
case Quadrature1D::OpenHalfUniform: return OpenHalfUniform;
case Quadrature1D::ClosedGL: return ClosedGL;
}
return Invalid;
}
+1
View File
@@ -34,6 +34,7 @@
#include "tmop.hpp"
#include "tmop_tools.hpp"
#include "gslib.hpp"
#include "adnonlininteg.hpp"
#include "restriction.hpp"
#include "quadinterpolator.hpp"
#include "quadinterpolator_face.hpp"
+6 -6
View File
@@ -944,7 +944,7 @@ const Operator *FiniteElementSpace::GetFaceRestriction(
}
const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
const IntegrationRule &ir, const DofToQuad::Mode mode) const
const IntegrationRule &ir) const
{
for (int i = 0; i < E2Q_array.Size(); i++)
{
@@ -952,13 +952,13 @@ const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
if (qi->IntRule == &ir) { return qi; }
}
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, ir, mode);
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, ir);
E2Q_array.Append(qi);
return qi;
}
const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
const QuadratureSpace &qs, const DofToQuad::Mode mode) const
const QuadratureSpace &qs) const
{
for (int i = 0; i < E2Q_array.Size(); i++)
{
@@ -966,7 +966,7 @@ const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
if (qi->qspace == &qs) { return qi; }
}
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, qs, mode);
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, qs);
E2Q_array.Append(qi);
return qi;
}
@@ -983,8 +983,8 @@ const FaceQuadratureInterpolator
if (qi->IntRule == &ir) { return qi; }
}
FaceQuadratureInterpolator *qi =
new FaceQuadratureInterpolator(*this, ir, type);
FaceQuadratureInterpolator *qi = new FaceQuadratureInterpolator(*this, ir,
type);
E2IFQ_array.Append(qi);
return qi;
}
+2 -8
View File
@@ -367,7 +367,7 @@ public:
All elements will use the same IntegrationRule, @a ir as the target
quadrature points. */
const QuadratureInterpolator *GetQuadratureInterpolator(
const IntegrationRule &ir, const DofToQuad::Mode = DofToQuad::FULL) const;
const IntegrationRule &ir) const;
/** @brief Return a QuadratureInterpolator that interpolates E-vectors to
quadrature point values and/or derivatives (Q-vectors). */
@@ -378,7 +378,7 @@ public:
The target quadrature points in the elements are described by the given
QuadratureSpace, @a qs. */
const QuadratureInterpolator *GetQuadratureInterpolator(
const QuadratureSpace &qs, const DofToQuad::Mode = DofToQuad::FULL) const;
const QuadratureSpace &qs) const;
/** @brief Return a FaceQuadratureInterpolator that interpolates E-vectors to
quadrature point values and/or derivatives (Q-vectors). */
@@ -756,12 +756,6 @@ public:
/// Return the total number of quadrature points.
int GetSize() const { return size; }
/// Returns the mesh
inline Mesh *GetMesh() const { return mesh; }
/// Returns number of elements in the mesh.
inline int GetNE() const { return mesh->GetNE(); }
/// Get the IntegrationRule associated with mesh element @a idx.
const IntegrationRule &GetElementIntRule(int idx) const
{ return *int_rule[mesh->GetElementBaseGeometry(idx)]; }
+33 -141
View File
@@ -1344,14 +1344,15 @@ const IntegrationRule *GeometryRefiner::RefineInterior(Geometry::Type Geom,
return NULL;
}
ir = FindInIntPts(Geom, Times-1);
if (ir) { return ir; }
ir = new IntegrationRule(Times-1);
for (int i = 1; i < Times; i++)
if (ir == NULL)
{
IntegrationPoint &ip = ir->IntPoint(i-1);
ip.x = double(i) / Times;
ip.y = ip.z = 0.0;
ir = new IntegrationRule(Times-1);
for (int i = 1; i < Times; i++)
{
IntegrationPoint &ip = ir->IntPoint(i-1);
ip.x = double(i) / Times;
ip.y = ip.z = 0.0;
}
}
}
break;
@@ -1363,17 +1364,18 @@ const IntegrationRule *GeometryRefiner::RefineInterior(Geometry::Type Geom,
return NULL;
}
ir = FindInIntPts(Geom, ((Times-1)*(Times-2))/2);
if (ir) { return ir; }
ir = new IntegrationRule(((Times-1)*(Times-2))/2);
for (int k = 0, j = 1; j < Times-1; j++)
for (int i = 1; i < Times-j; i++, k++)
{
IntegrationPoint &ip = ir->IntPoint(k);
ip.x = double(i) / Times;
ip.y = double(j) / Times;
ip.z = 0.0;
}
if (ir == NULL)
{
ir = new IntegrationRule(((Times-1)*(Times-2))/2);
for (int k = 0, j = 1; j < Times-1; j++)
for (int i = 1; i < Times-j; i++, k++)
{
IntegrationPoint &ip = ir->IntPoint(k);
ip.x = double(i) / Times;
ip.y = double(j) / Times;
ip.z = 0.0;
}
}
}
break;
@@ -1384,17 +1386,18 @@ const IntegrationRule *GeometryRefiner::RefineInterior(Geometry::Type Geom,
return NULL;
}
ir = FindInIntPts(Geom, (Times-1)*(Times-1));
if (ir) { return ir; }
ir = new IntegrationRule((Times-1)*(Times-1));
for (int k = 0, j = 1; j < Times; j++)
for (int i = 1; i < Times; i++, k++)
{
IntegrationPoint &ip = ir->IntPoint(k);
ip.x = double(i) / Times;
ip.y = double(j) / Times;
ip.z = 0.0;
}
if (ir == NULL)
{
ir = new IntegrationRule((Times-1)*(Times-1));
for (int k = 0, j = 1; j < Times; j++)
for (int i = 1; i < Times; i++, k++)
{
IntegrationPoint &ip = ir->IntPoint(k);
ip.x = double(i) / Times;
ip.y = double(j) / Times;
ip.z = 0.0;
}
}
}
break;
@@ -1402,121 +1405,10 @@ const IntegrationRule *GeometryRefiner::RefineInterior(Geometry::Type Geom,
mfem_error("GeometryRefiner::RefineInterior(...)");
}
MFEM_ASSERT(ir != NULL, "Failed to construct the refined IntegrationRule.");
IntPts[Geom].Append(ir);
if (ir) { IntPts[Geom].Append(ir); }
return ir;
}
int GeometryRefiner::GetRefinementLevelFromPoints(Geometry::Type geom, int Npts)
{
switch (geom)
{
case Geometry::POINT:
{
return -1;
}
case Geometry::SEGMENT:
{
return Npts -1;
}
case Geometry::TRIANGLE:
{
for (int n = 0, np = 0; (n < 15) && (np < Npts) ; n++)
{
np = (n+1)*(n+2)/2;
if (np == Npts) { return n; }
}
return -1;
}
case Geometry::SQUARE:
{
for (int n = 0, np = 0; (n < 15) && (np < Npts) ; n++)
{
np = (n+1)*(n+1);
if (np == Npts) { return n; }
}
return -1;
}
case Geometry::CUBE:
{
for (int n = 0, np = 0; (n < 15) && (np < Npts) ; n++)
{
np = (n+1)*(n+1)*(n+1);
if (np == Npts) { return n; }
}
return -1;
}
case Geometry::TETRAHEDRON:
{
for (int n = 0, np = 0; (n < 15) && (np < Npts) ; n++)
{
np = (n+3)*(n+2)*(n+1)/6;
if (np == Npts) { return n; }
}
return -1;
}
case Geometry::PRISM:
{
for (int n = 0, np = 0; (n < 15) && (np < Npts) ; n++)
{
np = (n+1)*(n+1)*(n+2)/2;
if (np == Npts) { return n; }
}
return -1;
}
default:
{
mfem_error("Non existing Geometry.");
}
}
return -1;
}
int GeometryRefiner::GetRefinementLevelFromElems(Geometry::Type geom, int Nels)
{
switch (geom)
{
case Geometry::POINT:
{
return -1;
}
case Geometry::SEGMENT:
{
return Nels;
}
case Geometry::TRIANGLE:
case Geometry::SQUARE:
{
for (int n = 0; (n < 15) && (n*n < Nels+1) ; n++)
{
if (n*n == Nels) { return n-1; }
}
return -1;
}
case Geometry::CUBE:
case Geometry::TETRAHEDRON:
case Geometry::PRISM:
{
for (int n = 0; (n < 15) && (n*n*n < Nels+1) ; n++)
{
if (n*n*n == Nels) { return n-1; }
}
return -1;
}
default:
{
mfem_error("Non existing Geometry.");
}
}
return -1;
}
GeometryRefiner GlobGeometryRefiner;
}
-6
View File
@@ -273,12 +273,6 @@ public:
/// @note This method always uses Quadrature1D::OpenUniform points.
const IntegrationRule *RefineInterior(Geometry::Type Geom, int Times);
/// Get the Refinement level based on number of points
virtual int GetRefinementLevelFromPoints(Geometry::Type Geom, int Npts);
/// Get the Refinement level based on number of elements
virtual int GetRefinementLevelFromElems(Geometry::Type geom, int Npts);
~GeometryRefiner();
};
+5 -20
View File
@@ -397,16 +397,8 @@ const
fes->DofsToVDofs(vdim-1, dofs);
Vector DofVal(dofs.Size()), LocVec;
const FiniteElement *fe = fes->GetFE(i);
if (fe->GetMapType() == FiniteElement::VALUE)
{
fe->CalcShape(ip, DofVal);
}
else
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
Tr->SetIntPoint(&ip);
fe->CalcPhysShape(*Tr, DofVal);
}
MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type");
fe->CalcShape(ip, DofVal);
GetSubVector(dofs, LocVec);
return (DofVal * LocVec);
@@ -423,17 +415,10 @@ void GridFunction::GetVectorValue(int i, const IntegrationPoint &ip,
GetSubVector(vdofs, loc_data);
if (FElem->GetRangeType() == FiniteElement::SCALAR)
{
MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
"invalid FE map type");
Vector shape(dof);
if (FElem->GetMapType() == FiniteElement::VALUE)
{
FElem->CalcShape(ip, shape);
}
else
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
Tr->SetIntPoint(&ip);
FElem->CalcPhysShape(*Tr, shape);
}
FElem->CalcShape(ip, shape);
int vdim = fes->GetVDim();
val.SetSize(vdim);
for (int k = 0; k < vdim; k++)
+3 -4
View File
@@ -105,7 +105,7 @@ public:
have the same size.
@note Defining this method overwrites the implicitly defined copy
assignment operator. */
assignemnt operator. */
GridFunction &operator=(const GridFunction &rhs)
{ return operator=((const Vector &)rhs); }
@@ -162,8 +162,7 @@ public:
int vdim = 1) const;
/** Return a vector value from within the given element. */
virtual void GetVectorValue(int i, const IntegrationPoint &ip,
Vector &val) const;
void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const;
///@}
/** @name Element Index Get Values Methods
@@ -714,7 +713,7 @@ public:
the same size.
@note Defining this method overwrites the implicitly defined copy
assignment operator. */
assignemnt operator. */
QuadratureFunction &operator=(const QuadratureFunction &v);
/// Get the IntegrationRule associated with mesh element @a idx.
-25
View File
@@ -618,26 +618,6 @@ void QuadratureFunctions1D::OpenHalfUniform(const int np, IntegrationRule* ir)
CalculateUniformWeights(ir, Quadrature1D::OpenHalfUniform);
}
void QuadratureFunctions1D::ClosedGL(const int np, IntegrationRule* ir)
{
ir->SetSize(np);
ir->IntPoint(0).x = 0.0;
ir->IntPoint(np-1).x = 1.0;
if ( np > 2 )
{
IntegrationRule gl_ir;
GaussLegendre(np-1, &gl_ir);
for (int i = 1; i < np-1; ++i)
{
ir->IntPoint(i).x = (gl_ir.IntPoint(i-1).x + gl_ir.IntPoint(i).x)/2;
}
}
CalculateUniformWeights(ir, Quadrature1D::ClosedGL);
}
void QuadratureFunctions1D::GivePolyPoints(const int np, double *pts,
const int type)
{
@@ -670,11 +650,6 @@ void QuadratureFunctions1D::GivePolyPoints(const int np, double *pts,
OpenHalfUniform(np, &ir);
break;
}
case Quadrature1D::ClosedGL:
{
ClosedGL(np, &ir);
break;
}
default:
{
MFEM_ABORT("Asking for an unknown type of 1D Quadrature points, "
+1 -3
View File
@@ -272,7 +272,6 @@ public:
void OpenUniform(const int np, IntegrationRule *ir);
void ClosedUniform(const int np, IntegrationRule *ir);
void OpenHalfUniform(const int np, IntegrationRule *ir);
void ClosedGL(const int np, IntegrationRule *ir);
///@}
/// A helper function that will play nice with Poly_1D::OpenPoints and
@@ -294,8 +293,7 @@ public:
GaussLobatto = 1,
OpenUniform = 2, ///< aka open Newton-Cotes
ClosedUniform = 3, ///< aka closed Newton-Cotes
OpenHalfUniform = 4, ///< aka "open half" Newton-Cotes
ClosedGL = 5 ///< aka closed Gauss Legendre
OpenHalfUniform = 4 ///< aka "open half" Newton-Cotes
};
/** @brief If the Quadrature1D type is not closed return Invalid; otherwise
return type. */
-1465
View File
File diff suppressed because it is too large Load Diff
+19 -91
View File
@@ -97,8 +97,6 @@ static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes,
Vector qweight(Q);
Vector shape_i(P);
DenseMatrix grad_i(P, dim);
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
const Table &el_dof = fes.GetElementToDofTable();
Array<int> tp_el_dof(el_dof.Size_of_connections());
const TensorBasisElement * tfe =
@@ -130,15 +128,7 @@ static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes,
const int el_offset = fe->GetDof() * i;
for (int j = 0; j < fe->GetDof(); j++)
{
if (compstride == 1)
{
tp_el_dof[j + el_offset] = fes.GetVDim()*
el_dof.GetJ()[dof_map[j] + el_offset];
}
else
{
tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset];
}
tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset];
}
}
}
@@ -167,23 +157,20 @@ static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes,
{
for (int i = 0; i < P; i++)
{
if (compstride == 1)
{
tp_el_dof[i + e*P] = fes.GetVDim()*el_dof.GetJ()[i + e*P];
}
else
{
tp_el_dof[i + e*P] = el_dof.GetJ()[i + e*P];
}
tp_el_dof[i + e*P] = el_dof.GetJ()[i + e*P];
}
}
}
CeedBasisCreateH1(ceed, GetCeedTopology(fe->GetGeomType()), fes.GetVDim(),
fe->GetDof(), ir.GetNPoints(), shape.GetData(),
grad.GetData(), qref.GetData(), qweight.GetData(), basis);
CeedElemRestrictionCreate(ceed, mesh->GetNE(), fe->GetDof(), fes.GetVDim(),
compstride, (fes.GetVDim())*(fes.GetNDofs()),
CEED_MEM_HOST, CEED_COPY_VALUES,
CeedInterlaceMode imode = CEED_NONINTERLACED;
if (fes.GetOrdering()==Ordering::byVDIM)
{
imode = CEED_INTERLACED;
}
CeedElemRestrictionCreate(ceed, imode, mesh->GetNE(), fe->GetDof(),
fes.GetNDofs(), fes.GetVDim(), CEED_MEM_HOST, CEED_COPY_VALUES,
tp_el_dof.GetData(), restr);
}
@@ -228,7 +215,6 @@ static void InitCeedTensorBasisAndRestriction(const FiniteElementSpace &fes,
grad1d.GetData(), qref1d.GetData(),
qweight1d.GetData(), basis);
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
const Table &el_dof = fes.GetElementToDofTable();
Array<int> tp_el_dof(el_dof.Size_of_connections());
for (int i = 0; i < mesh->GetNE(); i++)
@@ -236,20 +222,16 @@ static void InitCeedTensorBasisAndRestriction(const FiniteElementSpace &fes,
const int el_offset = fe->GetDof() * i;
for (int j = 0; j < fe->GetDof(); j++)
{
if (compstride == 1)
{
tp_el_dof[j + el_offset] = fes.GetVDim()*
el_dof.GetJ()[dof_map[j] + el_offset];
}
else
{
tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset];
}
tp_el_dof[j + el_offset] = el_dof.GetJ()[dof_map[j] + el_offset];
}
}
CeedElemRestrictionCreate(ceed, mesh->GetNE(), fe->GetDof(), fes.GetVDim(),
compstride, (fes.GetVDim())*(fes.GetNDofs()),
CEED_MEM_HOST, CEED_COPY_VALUES,
CeedInterlaceMode imode = CEED_NONINTERLACED;
if (fes.GetOrdering()==Ordering::byVDIM)
{
imode = CEED_INTERLACED;
}
CeedElemRestrictionCreate(ceed, imode, mesh->GetNE(), fe->GetDof(),
fes.GetNDofs(), fes.GetVDim(), CEED_MEM_HOST, CEED_COPY_VALUES,
tp_el_dof.GetData(), restr);
}
@@ -316,9 +298,8 @@ void CeedPAAssemble(const CeedPAOperator& op,
CeedBasisGetNumQuadraturePoints(ceedData.basis, &nqpts);
const int qdatasize = op.qdatasize;
CeedElemRestrictionCreateStrided(ceed, nelem, nqpts, qdatasize,
nelem*nqpts*qdatasize, CEED_STRIDES_BACKEND,
&ceedData.restr_i);
CeedElemRestrictionCreateStrided(ceed, nelem, nqpts, nelem*nqpts, qdatasize,
CEED_STRIDES_BACKEND, &ceedData.restr_i);
CeedVectorCreate(ceed, mesh->GetNodes()->Size(), &ceedData.node_coords);
CeedVectorSetArray(ceedData.node_coords, CEED_MEM_HOST, CEED_USE_POINTER,
@@ -415,59 +396,6 @@ void CeedPAAssemble(const CeedPAOperator& op,
CeedVectorCreate(ceed, fes.GetNDofs(), &ceedData.v);
}
void CeedAddMultPA(const CeedData *ceedDataPtr,
const Vector &x,
Vector &y)
{
const CeedScalar *x_ptr;
CeedScalar *y_ptr;
CeedMemType mem;
CeedGetPreferredMemType(internal::ceed, &mem);
if ( Device::Allows(Backend::CUDA) && mem==CEED_MEM_DEVICE )
{
x_ptr = x.Read();
y_ptr = y.ReadWrite();
}
else
{
x_ptr = x.HostRead();
y_ptr = y.HostReadWrite();
mem = CEED_MEM_HOST;
}
CeedVectorSetArray(ceedDataPtr->u, mem, CEED_USE_POINTER,
const_cast<CeedScalar*>(x_ptr));
CeedVectorSetArray(ceedDataPtr->v, mem, CEED_USE_POINTER, y_ptr);
CeedOperatorApplyAdd(ceedDataPtr->oper, ceedDataPtr->u, ceedDataPtr->v,
CEED_REQUEST_IMMEDIATE);
CeedVectorTakeArray(ceedDataPtr->u, mem, const_cast<CeedScalar**>(&x_ptr));
CeedVectorTakeArray(ceedDataPtr->v, mem, &y_ptr);
}
void CeedAssembleDiagonalPA(const CeedData *ceedDataPtr,
Vector &diag)
{
CeedScalar *d_ptr;
CeedMemType mem;
CeedGetPreferredMemType(internal::ceed, &mem);
if ( Device::Allows(Backend::CUDA) && mem==CEED_MEM_DEVICE )
{
d_ptr = diag.ReadWrite();
}
else
{
d_ptr = diag.HostReadWrite();
mem = CEED_MEM_HOST;
}
CeedVectorSetArray(ceedDataPtr->v, mem, CEED_USE_POINTER, d_ptr);
CeedOperatorLinearAssembleAddDiagonal(ceedDataPtr->oper, ceedDataPtr->v,
CEED_REQUEST_IMMEDIATE);
CeedVectorTakeArray(ceedDataPtr->v, mem, &d_ptr);
}
} // namespace mfem
#endif // MFEM_USE_CEED
-10
View File
@@ -16,7 +16,6 @@
#ifdef MFEM_USE_CEED
#include "../../general/device.hpp"
#include "../../linalg/vector.hpp"
#include <ceed.h>
namespace mfem
@@ -145,15 +144,6 @@ const std::string &GetCeedPath();
void CeedPAAssemble(const CeedPAOperator& op,
CeedData& ceedData);
/** @brief Function that applies a libCEED PA operator. */
void CeedAddMultPA(const CeedData *ceedDataPtr,
const Vector &x,
Vector &y);
/** @brief Function that assembles a libCEED PA operator diagonal. */
void CeedAssembleDiagonalPA(const CeedData *ceedDataPtr,
Vector &diag);
/** @brief Function that determines if a CEED kernel should be used, based on
the current mfem::Device configuration. */
inline bool DeviceCanUseCeed()
+1 -2
View File
@@ -199,8 +199,7 @@ void LinearForm::Assemble()
void LinearForm::Update(FiniteElementSpace *f, Vector &v, int v_offset)
{
fes = f;
NewMemoryAndSize(Memory<double>(v.GetMemory(), v_offset, f->GetVSize()),
f->GetVSize(), false);
NewDataAndSize((double *)v + v_offset, fes->GetVSize());
ResetDeltaLocations();
}
+4 -11
View File
@@ -135,18 +135,11 @@ void Multigrid::SetOperator(const Operator& op)
MFEM_ABORT("SetOperator not supported in Multigrid");
}
void Multigrid::SmoothingStep(int level, bool transpose) const
void Multigrid::SmoothingStep(int level) const
{
GetOperatorAtLevel(level)->Mult(*Y[level], *R[level]); // r = A x
subtract(*X[level], *R[level], *R[level]); // r = b - A x
if (transpose)
{
GetSmootherAtLevel(level)->MultTranspose(*R[level], *Z[level]); // z = S r
}
else
{
GetSmootherAtLevel(level)->Mult(*R[level], *Z[level]); // z = S r
}
GetSmootherAtLevel(level)->Mult(*R[level], *Z[level]); // z = S r
add(*Y[level], 1.0, *Z[level], *Y[level]); // x = x + S (b - A x)
}
@@ -160,7 +153,7 @@ void Multigrid::Cycle(int level) const
for (int i = 0; i < preSmoothingSteps; i++)
{
SmoothingStep(level, false);
SmoothingStep(level);
}
// Compute residual
@@ -194,7 +187,7 @@ void Multigrid::Cycle(int level) const
// Post-smooth
for (int i = 0; i < postSmoothingSteps; i++)
{
SmoothingStep(level, true);
SmoothingStep(level);
}
}
+1 -1
View File
@@ -108,7 +108,7 @@ public:
private:
/// Application of a smoothing step at particular level
void SmoothingStep(int level, bool transpose) const;
void SmoothingStep(int level) const;
/// Application of a cycle at particular level
void Cycle(int level) const;
+14 -63
View File
@@ -10,7 +10,6 @@
// CONTRIBUTING.md for details.
#include "fem.hpp"
#include "../general/forall.hpp"
namespace mfem
{
@@ -28,7 +27,7 @@ void NonlinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
// This is the default behavior.
break;
case AssemblyLevel::PARTIAL:
ext = new PANonlinearForm(this);
ext = new PANonlinearFormExtension(this);
break;
default:
mfem_error("Unknown assembly level for this form.");
@@ -81,13 +80,6 @@ void NonlinearForm::SetEssentialVDofs(const Array<int> &ess_vdofs_list)
double NonlinearForm::GetGridFunctionEnergy(const Vector &x) const
{
if (ext)
{
MFEM_VERIFY(!fnfi.Size(), "Interior faces terms not yet implemented!");
MFEM_VERIFY(!bfnfi.Size(), "Boundary face terms not yet implemented!");
return ext->GetGridFunctionEnergy(x);
}
Array<int> vdofs;
Vector el_x;
const FiniteElement *fe;
@@ -146,14 +138,6 @@ void NonlinearForm::Mult(const Vector &x, Vector &y) const
if (ext)
{
ext->Mult(px, py);
if (Serial())
{
if (cP) { cP->MultTranspose(py, y); }
const int N = ess_tdof_list.Size();
const auto tdof = ess_tdof_list.Read();
auto Y = y.ReadWrite();
MFEM_FORALL(i, N, Y[tdof[i]] = 0.0; );
}
return;
}
@@ -280,16 +264,7 @@ Operator &NonlinearForm::GetGradient(const Vector &x) const
{
if (ext)
{
Operator &grad = ext->GetGradient(Prolongate(x));
hGrad.Reset(&grad, false);
if (Serial())
{
Operator *Gop;
if (cP) { hGrad.Reset(new RAPOperator(*cP, grad, *cP)); }
hGrad.Ptr()->Operator::FormSystemOperator(ess_tdof_list, Gop);
hGrad.Reset(Gop);
}
return *hGrad.Ptr();
MFEM_ABORT("Not yet implemented!");
}
const int skip_zeros = 0;
@@ -451,31 +426,7 @@ void NonlinearForm::Update()
void NonlinearForm::Setup()
{
if (ext) { return ext->Setup(); }
}
void NonlinearForm::AssembleGradientDiagonal(Vector &diag) const
{
if (ext)
{
MFEM_ASSERT(diag.Size() == fes->GetTrueVSize(),
"Vector for holding diagonal has wrong size!");
const Operator *P = fes->GetProlongationMatrix();
if (!IsIdentityProlongation(P))
{
Vector local_diag(P->Height());
ext->AssembleGradientDiagonal(local_diag);
P->MultTranspose(local_diag, diag);
}
else
{
ext->AssembleGradientDiagonal(diag);
}
}
else
{
MFEM_ABORT("Not implemented. Can be obtained through GetGradient().");
}
if (ext) { return ext->AssemblePA(); }
}
NonlinearForm::~NonlinearForm()
@@ -982,17 +933,6 @@ Operator &BlockNonlinearForm::GetGradientBlocked(const BlockVector &bx) const
}
}
if (!Grads(0,0)->Finalized())
{
for (int i=0; i<fes.Size(); ++i)
{
for (int j=0; j<fes.Size(); ++j)
{
Grads(i,j)->Finalize(skip_zeros);
}
}
}
for (int s=0; s<fes.Size(); ++s)
{
for (int i = 0; i < ess_vdofs[s]->Size(); ++i)
@@ -1012,6 +952,17 @@ Operator &BlockNonlinearForm::GetGradientBlocked(const BlockVector &bx) const
}
}
if (!Grads(0,0)->Finalized())
{
for (int i=0; i<fes.Size(); ++i)
{
for (int j=0; j<fes.Size(); ++j)
{
Grads(i,j)->Finalize(skip_zeros);
}
}
}
for (int i=0; i<fes.Size(); ++i)
{
for (int j=0; j<fes.Size(); ++j)
-10
View File
@@ -45,7 +45,6 @@ protected:
Array<Array<int>*> bfnfi_marker; // not owned
mutable SparseMatrix *Grad, *cGrad; // owned
mutable OperatorHandle hGrad;
/// A list of all essential true dofs
Array<int> ess_tdof_list;
@@ -166,15 +165,6 @@ public:
/// Setup the NonlinearForm
virtual void Setup();
/** @brief Assemble the diagonal of the gradient into diag
For adaptively refined meshes, this returns P^T d_e, where d_e is the
locally assembled diagonal on each element and P^T is the transpose of
the conforming prolongation. In general this is not the correct diagonal
for an AMR mesh. */
void AssembleGradientDiagonal(Vector &diag) const;
/// Get the finite element space prolongation matrix
virtual const Operator *GetProlongation() const { return P; }
/// Get the finite element space restriction matrix
+38 -77
View File
@@ -13,101 +13,62 @@
// PABilinearFormExtension and MFBilinearFormExtension.
#include "nonlinearform.hpp"
#include "../general/forall.hpp"
namespace mfem
{
NonlinearFormExtension::NonlinearFormExtension(const NonlinearForm *nlf)
: Operator(nlf->FESpace()->GetTrueVSize()), nlf(nlf) { }
PANonlinearForm::PANonlinearForm(NonlinearForm *nlf):
NonlinearFormExtension(nlf),
x_grad(NULL),
fes(*nlf->FESpace()),
dnfi(*nlf->GetDNFI()),
R(fes.GetElementRestriction(ElementDofOrdering::LEXICOGRAPHIC))
NonlinearFormExtension::NonlinearFormExtension(NonlinearForm *form)
: Operator(form->FESpace()->GetTrueVSize()), n(form)
{
MFEM_VERIFY(R, "Not yet implemented!");
xe.SetSize(R->Height(), Device::GetMemoryType());
ye.SetSize(R->Height(), Device::GetMemoryType());
ye.UseDevice(true);
// empty
}
double PANonlinearForm::GetGridFunctionEnergy(const Vector &x) const
PANonlinearFormExtension::PANonlinearFormExtension(NonlinearForm *form):
NonlinearFormExtension(form), fes(*form->FESpace())
{
double energy = 0.0;
R->Mult(x, xe);
for (int i = 0; i < dnfi.Size(); i++)
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
elem_restrict_lex = fes.GetElementRestriction(ordering);
if (elem_restrict_lex)
{
energy += dnfi[i]->GetGridFunctionEnergyPA(xe);
localX.SetSize(elem_restrict_lex->Height(), Device::GetMemoryType());
localY.SetSize(elem_restrict_lex->Height(), Device::GetMemoryType());
localY.UseDevice(true); // ensure 'localY = 0.0' is done on device
}
return energy;
}
void PANonlinearForm::Setup()
void PANonlinearFormExtension::AssemblePA()
{
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AssemblePA(fes); }
}
void PANonlinearForm::Mult(const Vector &x, Vector &y) const
{
ye = 0.0;
R->Mult(x, xe);
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AddMultPA(xe, ye); }
R->MultTranspose(ye, y);
}
void PANonlinearForm::AssembleGradientDiagonal(Vector &diag) const
{
MFEM_VERIFY(x_grad, "GetGradient() has not been called");
R->Mult(*x_grad, xe);
ye = 0.0;
for (int i = 0; i < dnfi.Size(); ++i)
Array<NonlinearFormIntegrator*> &integrators = *n->GetDNFI();
const int Ni = integrators.Size();
for (int i = 0; i < Ni; ++i)
{
dnfi[i]->AssembleGradientDiagonalPA(xe, ye);
integrators[i]->AssemblePA(*n->FESpace());
}
R->MultTranspose(ye, diag);
}
Operator &PANonlinearForm::GetGradient(const Vector &x) const
void PANonlinearFormExtension::Mult(const Vector &x, Vector &y) const
{
// Store the last x that was used to compute the gradient.
x_grad = &x;
Grad.Reset(new PANonlinearForm::Gradient(x, *this));
return *Grad.Ptr();
Array<NonlinearFormIntegrator*> &integrators = *n->GetDNFI();
const int iSz = integrators.Size();
if (elem_restrict_lex)
{
elem_restrict_lex->Mult(x, localX);
localY = 0.0;
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AddMultPA(localX, localY);
}
elem_restrict_lex->MultTranspose(localY, y);
}
else
{
y.UseDevice(true); // typically this is a large vector, so store on device
y = 0.0;
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AddMultPA(x, y);
}
}
}
PANonlinearForm::Gradient::Gradient(const Vector &x, const PANonlinearForm &e):
Operator(e.fes.GetVSize()), R(e.R), dnfi(e.dnfi)
{
ge.UseDevice(true);
ge.SetSize(R->Height(), Device::GetMemoryType());
R->Mult(x, ge);
xe.UseDevice(true);
xe.SetSize(R->Height(), Device::GetMemoryType());
ye.UseDevice(true);
ye.SetSize(R->Height(), Device::GetMemoryType());
ze.UseDevice(true);
ze.SetSize(R->Height(), Device::GetMemoryType());
// Do we still need to do this?
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AssemblePA(e.fes); }
}
void PANonlinearForm::Gradient::Mult(const Vector &x, Vector &y) const
{
ze = x;
ye = 0.0;
R->Mult(ze, xe);
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AddMultGradPA(ge, xe, ye); }
R->MultTranspose(ye, y);
}
} // namespace mfem
+9 -41
View File
@@ -17,60 +17,28 @@
namespace mfem
{
class NonlinearForm;
class NonlinearFormIntegrator;
/** @brief Class extending the NonlinearForm class to support the different
AssemblyLevel%s. */
class NonlinearFormExtension : public Operator
{
protected:
const NonlinearForm *nlf;
NonlinearForm *n; ///< Not owned
public:
NonlinearFormExtension(const NonlinearForm*);
virtual void Setup() = 0;
virtual Operator &GetGradient(const Vector&) const = 0;
virtual double GetGridFunctionEnergy(const Vector &x) const = 0;
virtual void AssembleGradientDiagonal(Vector &diag) const
{
MFEM_ABORT("Not implemented for this assembly level!");
}
NonlinearFormExtension(NonlinearForm *form);
virtual void AssemblePA() = 0;
};
class PANonlinearForm;
/// Data and methods for partially-assembled nonlinear forms
class PANonlinearForm : public NonlinearFormExtension
class PANonlinearFormExtension : public NonlinearFormExtension
{
private:
class Gradient : public Operator
{
protected:
const Operator *R;
mutable Vector ge, xe, ye, ze;
const Array<NonlinearFormIntegrator*> &dnfi;
public:
Gradient(const Vector &x, const PANonlinearForm &ext);
virtual void Mult(const Vector &x, Vector &y) const;
};
protected:
mutable Vector xe, ye;
mutable const Vector *x_grad;
mutable OperatorHandle Grad;
const FiniteElementSpace &fes;
const Array<NonlinearFormIntegrator*> &dnfi;
const Operator *R;
const FiniteElementSpace &fes; // Not owned
mutable Vector localX, localY;
const Operator *elem_restrict_lex; // Not owned
public:
PANonlinearForm(NonlinearForm *nlf);
void Setup();
PANonlinearFormExtension(NonlinearForm*);
void AssemblePA();
void Mult(const Vector &x, Vector &y) const;
Operator &GetGradient(const Vector &x) const;
double GetGridFunctionEnergy(const Vector &x) const;
void AssembleGradientDiagonal(Vector &diag) const;
};
}
#endif // NONLINEARFORM_EXT_HPP
-21
View File
@@ -15,13 +15,6 @@
namespace mfem
{
double NonlinearFormIntegrator::GetGridFunctionEnergyPA(const Vector &x) const
{
mfem_error ("NonlinearFormIntegrator::GetGridFunctionEnergyPA(...)\n"
" is not implemented for this class.");
return 0.0;
}
void NonlinearFormIntegrator::AssemblePA(const FiniteElementSpace&)
{
mfem_error ("NonlinearFormIntegrator::AssemblePA(...)\n"
@@ -41,20 +34,6 @@ void NonlinearFormIntegrator::AddMultPA(const Vector &, Vector &) const
" is not implemented for this class.");
}
void NonlinearFormIntegrator::AddMultGradPA(const Vector&,
const Vector&, Vector&) const
{
mfem_error ("NonlinearFormIntegrator::AddMultGradPA(...)\n"
" is not implemented for this class.");
}
void NonlinearFormIntegrator::AssembleGradientDiagonalPA(const mfem::Vector &x,
mfem::Vector &diag) const
{
mfem_error ("NonlinearFormIntegrator::AssembleDiagonalPA(...)\n"
" is not implemented for this class.");
}
void NonlinearFormIntegrator::AssembleElementVector(
const FiniteElement &el, ElementTransformation &Tr,
const Vector &elfun, Vector &elvect)
-9
View File
@@ -68,9 +68,6 @@ public:
ElementTransformation &Tr,
const Vector &elfun);
/// Compute the local energy with partial assembly.
virtual double GetGridFunctionEnergyPA(const Vector &x) const;
/// Method defining partial assembly.
/** The result of the partial assembly is stored internally so that it can be
used later in the methods AddMultPA(). */
@@ -91,12 +88,6 @@ public:
called. */
virtual void AddMultPA(const Vector &x, Vector &y) const;
/// Method for partially assembled gradient action.
virtual void AddMultGradPA(const Vector &g,
const Vector &x, Vector &y) const;
virtual void AssembleGradientDiagonalPA(const Vector &x, Vector &diag) const;
virtual ~NonlinearFormIntegrator() { }
};
+1 -1
View File
@@ -241,7 +241,7 @@ void ParBilinearForm::Assemble(int skip_zeros)
BilinearForm::Assemble(skip_zeros);
if (!ext && fbfi.Size() > 0)
if (fbfi.Size() > 0)
{
AssembleSharedFaces(skip_zeros);
}
+2 -2
View File
@@ -3147,7 +3147,7 @@ static void SetSubVector(const int N,
const Array<int> &indices,
const Vector &in, Vector &out)
{
auto y = out.ReadWrite();
auto y = out.Write();
const auto x = in.Read();
const auto I = indices.Read();
MFEM_FORALL(i, N, y[I[i]] = x[i];);
@@ -3234,7 +3234,7 @@ static void AddSubVector(const int num_unique_dst_indices,
const Vector &src,
Vector &dst)
{
auto y = dst.ReadWrite();
auto y = dst.Write();
const auto x = src.Read();
const auto DST_I = unique_dst_indices.Read();
const auto SRC_O = unique_to_src_offsets.Read();
-2
View File
@@ -347,8 +347,6 @@ public:
const FiniteElement *GetFaceNbrFE(int i) const;
const FiniteElement *GetFaceNbrFaceFE(int i) const;
const HYPRE_Int *GetFaceNbrGlobalDofMap() { return face_nbr_glob_dof_map; }
ElementTransformation *GetFaceNbrElementTransformation(int i) const
{ return pmesh->GetFaceNbrElementTransformation(i); }
void Lose_Dof_TrueDof_Matrix();
void LoseDofOffsets() { dof_offsets.LoseData(); }
+3 -75
View File
@@ -271,7 +271,6 @@ const
{
int fes_vdim = pfes->GetVDim();
pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs);
const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no);
if (fes_vdim > 1)
{
int s = dofs.Size()/fes_vdim;
@@ -284,17 +283,7 @@ const
face_nbr_data.GetSubVector(dofs, LocVec);
DofVal.SetSize(dofs.Size());
}
if (fe->GetMapType() == FiniteElement::VALUE)
{
fe->CalcShape(ip, DofVal);
}
else
{
ElementTransformation *Tr =
pfes->GetFaceNbrElementTransformation(nbr_el_no);
Tr->SetIntPoint(&ip);
fe->CalcPhysShape(*Tr, DofVal);
}
pfes->GetFaceNbrFE(nbr_el_no)->CalcShape(ip, DofVal);
}
else
{
@@ -302,73 +291,14 @@ const
fes->DofsToVDofs(vdim-1, dofs);
DofVal.SetSize(dofs.Size());
const FiniteElement *fe = fes->GetFE(i);
if (fe->GetMapType() == FiniteElement::VALUE)
{
fe->CalcShape(ip, DofVal);
}
else
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
Tr->SetIntPoint(&ip);
fe->CalcPhysShape(*Tr, DofVal);
}
MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type");
fe->CalcShape(ip, DofVal);
GetSubVector(dofs, LocVec);
}
return (DofVal * LocVec);
}
void ParGridFunction::GetVectorValue(int i, const IntegrationPoint &ip,
Vector &val) const
{
int nbr_el_no = i - pfes->GetParMesh()->GetNE();
if (nbr_el_no >= 0)
{
Array<int> dofs;
pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs);
Vector loc_data;
face_nbr_data.GetSubVector(dofs, loc_data);
const FiniteElement *FElem = pfes->GetFaceNbrFE(nbr_el_no);
int dof = FElem->GetDof();
if (FElem->GetRangeType() == FiniteElement::SCALAR)
{
Vector shape(dof);
if (FElem->GetMapType() == FiniteElement::VALUE)
{
FElem->CalcShape(ip, shape);
}
else
{
ElementTransformation *Tr =
pfes->GetParMesh()->GetFaceNbrElementTransformation(nbr_el_no);
Tr->SetIntPoint(&ip);
FElem->CalcPhysShape(*Tr, shape);
}
int vdim = fes->GetVDim();
val.SetSize(vdim);
for (int k = 0; k < vdim; k++)
{
val(k) = shape * ((const double *)loc_data + dof * k);
}
}
else
{
int spaceDim = fes->GetMesh()->SpaceDimension();
DenseMatrix vshape(dof, spaceDim);
ElementTransformation *Tr =
pfes->GetParMesh()->GetFaceNbrElementTransformation(nbr_el_no);
Tr->SetIntPoint(&ip);
FElem->CalcVShape(*Tr, vshape);
val.SetSize(spaceDim);
vshape.MultTranspose(loc_data, val);
}
}
else
{
GridFunction::GetVectorValue(i, ip, val);
}
}
double ParGridFunction::GetValue(ElementTransformation &T,
const IntegrationPoint &ip,
int comp, Vector *tr) const
@@ -711,9 +641,7 @@ void ParGridFunction::SaveAsOne(std::ostream &out)
int *nfdofs = new int[NRanks];
int *nrdofs = new int[NRanks];
HostReadWrite();
values[0] = data;
nv[0] = pfes -> GetVSize();
nvdofs[0] = pfes -> GetNVDofs();
nedofs[0] = pfes -> GetNEDofs();

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