Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e8625cf89 | ||
|
|
3f7a432e74 |
+8
-10
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -132,21 +109,6 @@ New and updated examples and miniapps
|
||||
for applying Dirichlet, Neumann (both homogeneous and inhomogeneous), Robin,
|
||||
and periodic boundary conditions with either H1 or DG discretizations.
|
||||
|
||||
- Added a new miniapp, Navier, that solves the time-dependent Navier-Stokes
|
||||
equations of incompressible fluid dynamics. See the miniapps/navier directory
|
||||
for more details.
|
||||
|
||||
- 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 +116,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 +128,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
|
||||
|
||||
+4
-8
@@ -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()
|
||||
|
||||
@@ -356,7 +352,7 @@ endif()
|
||||
# integers, the METIS header (with 32-bit indices, as used by mfem) needs to
|
||||
# be before SuiteSparse.
|
||||
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
|
||||
SLEPC MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
|
||||
MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
|
||||
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2)
|
||||
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
|
||||
set(TPL_LIBRARIES "")
|
||||
|
||||
@@ -109,7 +109,6 @@ The MFEM source code has the following structure:
|
||||
├── linalg
|
||||
├── mesh
|
||||
├── miniapps
|
||||
│ ├── adjoint
|
||||
│ ├── common
|
||||
│ ├── electromagnetics
|
||||
│ ├── gslib
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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@)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
"
|
||||
)
|
||||
@@ -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})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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@
|
||||
|
||||
@@ -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,7 +49,7 @@ option(MFEM_USE_OCCA "Enable OCCA" OFF)
|
||||
option(MFEM_USE_RAJA "Enable RAJA" OFF)
|
||||
option(MFEM_USE_CEED "Enable CEED" OFF)
|
||||
option(MFEM_USE_UMPIRE "Enable Umpire" OFF)
|
||||
option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" OFF)
|
||||
option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" ON)
|
||||
option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
|
||||
|
||||
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
|
||||
@@ -88,8 +87,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 +155,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
|
||||
|
||||
+2
-10
@@ -138,8 +138,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 +189,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
|
||||
@@ -373,11 +370,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
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
+2
-11
@@ -91,7 +91,7 @@ foreach(SRC_FILE ${ALL_EXE_SRCS})
|
||||
add_test(NAME ${TEST_NAME}_ser
|
||||
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
|
||||
else()
|
||||
add_test(NAME ${TEST_NAME}_np=${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 +101,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
@@ -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;
|
||||
}
|
||||
|
||||
+8
-3
@@ -88,6 +88,8 @@ private:
|
||||
Vector funval2;
|
||||
Vector nor;
|
||||
Vector fluxN;
|
||||
IntegrationPoint eip1;
|
||||
IntegrationPoint eip2;
|
||||
|
||||
public:
|
||||
FaceIntegrator(RiemannSolver &rsolver_, const int dim);
|
||||
@@ -422,16 +424,19 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
Tr.SetAllIntPoints(&ip); // set face and element int. points
|
||||
Tr.Loc1.Transform(ip, eip1);
|
||||
Tr.Loc2.Transform(ip, eip2);
|
||||
|
||||
// Calculate basis functions on both elements at the face
|
||||
el1.CalcShape(Tr.GetElement1IntPoint(), shape1);
|
||||
el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
|
||||
el1.CalcShape(eip1, shape1);
|
||||
el2.CalcShape(eip2, shape2);
|
||||
|
||||
// Interpolate elfun at the point
|
||||
elfun1_mat.MultTranspose(shape1, funval1);
|
||||
elfun2_mat.MultTranspose(shape2, funval2);
|
||||
|
||||
Tr.SetIntPoint(&ip);
|
||||
|
||||
// Get the normal vector and the flux on the face
|
||||
CalcOrtho(Tr.Jacobian(), nor);
|
||||
const double mcs = rsolver.Eval(funval1, funval2, nor, fluxN);
|
||||
|
||||
+36
-39
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
+21
-42
@@ -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
@@ -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
@@ -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
|
||||
|
||||
+9
-18
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -50,43 +50,10 @@ 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
|
||||
transfer.cpp
|
||||
@@ -116,10 +83,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,7 +96,6 @@ set(HDRS
|
||||
tfespace.hpp
|
||||
tintrules.hpp
|
||||
tmop.hpp
|
||||
tmop_pa.hpp
|
||||
tmop_tools.hpp
|
||||
gslib.hpp
|
||||
transfer.hpp
|
||||
|
||||
+14
-16
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
{
|
||||
|
||||
+23
-40
@@ -926,14 +926,11 @@ void BoundaryMassIntegrator::AssembleFaceMatrix(
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
// Set the integration point in the face and the neighboring element
|
||||
Trans.SetAllIntPoints(&ip);
|
||||
|
||||
// Access the neighboring element's integration point
|
||||
const IntegrationPoint &eip = Trans.GetElement1IntPoint();
|
||||
IntegrationPoint eip;
|
||||
Trans.Loc1.Transform(ip, eip);
|
||||
el1.CalcShape(eip, shape);
|
||||
|
||||
Trans.SetIntPoint(&ip);
|
||||
w = Trans.Weight() * ip.weight;
|
||||
if (Q)
|
||||
{
|
||||
@@ -2574,17 +2571,16 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
|
||||
for (int p = 0; p < ir->GetNPoints(); p++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(p);
|
||||
|
||||
// Set the integration point in the face and the neighboring elements
|
||||
Trans.SetAllIntPoints(&ip);
|
||||
|
||||
// Access the neighboring elements' integration points
|
||||
// Note: eip2 will only contain valid data if Elem2 exists
|
||||
const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
|
||||
const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
|
||||
|
||||
IntegrationPoint eip1, eip2;
|
||||
Trans.Loc1.Transform(ip, eip1);
|
||||
if (ndof2)
|
||||
{
|
||||
Trans.Loc2.Transform(ip, eip2);
|
||||
}
|
||||
el1.CalcShape(eip1, shape1);
|
||||
|
||||
Trans.SetIntPoint(&ip);
|
||||
|
||||
u->Eval(vu, *Trans.Elem1, eip1);
|
||||
|
||||
if (dim == 1)
|
||||
@@ -2731,15 +2727,10 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
|
||||
for (int p = 0; p < ir->GetNPoints(); p++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(p);
|
||||
IntegrationPoint eip1, eip2;
|
||||
|
||||
// Set the integration point in the face and the neighboring elements
|
||||
Trans.SetAllIntPoints(&ip);
|
||||
|
||||
// Access the neighboring elements' integration points
|
||||
// Note: eip2 will only contain valid data if Elem2 exists
|
||||
const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
|
||||
const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
|
||||
|
||||
Trans.Loc1.Transform(ip, eip1);
|
||||
Trans.SetIntPoint(&ip);
|
||||
if (dim == 1)
|
||||
{
|
||||
nor(0) = 2*eip1.x - 1.0;
|
||||
@@ -2796,6 +2787,7 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
|
||||
|
||||
if (ndof2)
|
||||
{
|
||||
Trans.Loc2.Transform(ip, eip2);
|
||||
el2.CalcShape(eip2, shape2);
|
||||
el2.CalcDShape(eip2, dshape2);
|
||||
w = ip.weight/2/Trans.Elem2->Weight();
|
||||
@@ -3013,14 +3005,9 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
|
||||
for (int pind = 0; pind < ir->GetNPoints(); ++pind)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(pind);
|
||||
|
||||
// Set the integration point in the face and the neighboring elements
|
||||
Trans.SetAllIntPoints(&ip);
|
||||
|
||||
// Access the neighboring elements' integration points
|
||||
// Note: eip2 will only contain valid data if Elem2 exists
|
||||
const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
|
||||
const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
|
||||
IntegrationPoint eip1, eip2; // integration point in the reference space
|
||||
Trans.Loc1.Transform(ip, eip1);
|
||||
Trans.SetIntPoint(&ip);
|
||||
|
||||
el1.CalcShape(eip1, shape1);
|
||||
el1.CalcDShape(eip1, dshape1);
|
||||
@@ -3040,6 +3027,7 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
|
||||
double w, wLM;
|
||||
if (ndofs2)
|
||||
{
|
||||
Trans.Loc2.Transform(ip, eip2);
|
||||
el2.CalcShape(eip2, shape2);
|
||||
el2.CalcDShape(eip2, dshape2);
|
||||
CalcAdjugate(Trans.Elem2->Jacobian(), adjJ);
|
||||
@@ -3177,22 +3165,17 @@ void TraceJumpIntegrator::AssembleFaceMatrix(
|
||||
for (int p = 0; p < ir->GetNPoints(); p++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(p);
|
||||
|
||||
// Set the integration point in the face and the neighboring elements
|
||||
Trans.SetAllIntPoints(&ip);
|
||||
|
||||
// Access the neighboring elements' integration points
|
||||
// Note: eip2 will only contain valid data if Elem2 exists
|
||||
const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
|
||||
const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
|
||||
|
||||
IntegrationPoint eip1, eip2;
|
||||
// Trace finite element shape function
|
||||
Trans.SetIntPoint(&ip);
|
||||
trial_face_fe.CalcShape(ip, face_shape);
|
||||
// Side 1 finite element shape function
|
||||
Trans.Loc1.Transform(ip, eip1);
|
||||
test_fe1.CalcShape(eip1, shape1);
|
||||
if (ndof2)
|
||||
{
|
||||
// Side 2 finite element shape function
|
||||
Trans.Loc2.Transform(ip, eip2);
|
||||
test_fe2.CalcShape(eip2, shape2);
|
||||
}
|
||||
w = ip.weight;
|
||||
|
||||
+2
-32
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+216
-303
@@ -170,54 +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(eq, NE*NQ,
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
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 int e = eq / NQ;
|
||||
const int q = eq % NQ;
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J31 = J(q,2,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double J32 = J(q,2,1,e);
|
||||
const double J13 = J(q,0,2,e);
|
||||
const double J23 = J(q,1,2,e);
|
||||
const double J33 = J(q,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
const double c_detJ = W[q] * coeff / detJ;
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
const double A12 = (J32 * J13) - (J12 * J33);
|
||||
const double A13 = (J12 * J23) - (J22 * J13);
|
||||
const double A21 = (J31 * J23) - (J21 * J33);
|
||||
const double A22 = (J11 * J33) - (J13 * J31);
|
||||
const double A23 = (J21 * J13) - (J11 * J23);
|
||||
const double A31 = (J21 * J32) - (J31 * J22);
|
||||
const double A32 = (J31 * J12) - (J11 * J32);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
|
||||
D(q,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
|
||||
D(q,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
|
||||
D(q,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
|
||||
D(q,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
|
||||
D(q,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
|
||||
D(q,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
|
||||
});
|
||||
}
|
||||
|
||||
@@ -259,7 +252,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 +262,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 +270,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 +295,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 +722,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 +735,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 +1306,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 +1319,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 +1358,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 +1467,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 +1573,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 +1588,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 +1613,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
File diff suppressed because it is too large
Load Diff
+1
-11
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+48
-80
@@ -23,7 +23,7 @@ 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
|
||||
@@ -34,7 +34,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,17 +46,9 @@ 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());
|
||||
@@ -72,26 +64,13 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
{
|
||||
coeff = new Vector;
|
||||
coeff->SetSize(1);
|
||||
(*coeff)(0) = cQ->constant;
|
||||
(*coeff)(0) = 1.0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
coeff = new Vector;
|
||||
@@ -134,38 +113,25 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
if (dim==3)
|
||||
{
|
||||
const int NE = ne;
|
||||
const int Q1D = quad1D;
|
||||
const int NQ = nq;
|
||||
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,
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -472,12 +438,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 +452,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 +651,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 +914,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 +1163,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 +1174,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 +1182,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 +1194,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 +1204,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
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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
|
||||
|
||||
+6
-12
@@ -217,24 +217,18 @@ void GradientGridFunctionCoefficient::Eval(
|
||||
GridFunc->GetGradients(T, ir, M);
|
||||
}
|
||||
|
||||
CurlGridFunctionCoefficient::CurlGridFunctionCoefficient(
|
||||
CurlGridFunctionCoefficient::CurlGridFunctionCoefficient (
|
||||
const GridFunction *gf)
|
||||
: VectorCoefficient(0)
|
||||
: VectorCoefficient ((gf) ?
|
||||
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0)
|
||||
{
|
||||
SetGridFunction(gf);
|
||||
GridFunc = gf;
|
||||
}
|
||||
|
||||
void CurlGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
|
||||
{
|
||||
if (gf)
|
||||
{
|
||||
int sdim = gf -> FESpace() -> GetMesh() -> SpaceDimension();
|
||||
MFEM_VERIFY(sdim == 2 || sdim == 3,
|
||||
"CurlGridFunctionCoefficient "
|
||||
"only defind for spaces of dimension 2 or 3.");
|
||||
}
|
||||
GridFunc = gf;
|
||||
vdim = (gf) ? (2 * gf -> FESpace() -> GetMesh() -> SpaceDimension() - 3) : 0;
|
||||
GridFunc = gf; vdim = (gf) ?
|
||||
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0;
|
||||
}
|
||||
|
||||
void CurlGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
|
||||
+1
-4
@@ -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:
|
||||
|
||||
+53
-135
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
+15
-21
@@ -552,32 +552,26 @@ void IntegrationPointTransformation::Transform (const IntegrationRule &ir1,
|
||||
}
|
||||
}
|
||||
|
||||
void FaceElementTransformations::SetIntPoint(const IntegrationPoint *face_ip)
|
||||
void FaceElementTransformations::SetIntPoint(const IntegrationPoint *ip)
|
||||
{
|
||||
IsoparametricTransformation::SetIntPoint(face_ip);
|
||||
IsoparametricTransformation::SetIntPoint(ip);
|
||||
|
||||
if (mask & 4)
|
||||
if (Elem1)
|
||||
{
|
||||
Loc1.Transform(*face_ip, eip1);
|
||||
if (Elem1)
|
||||
{
|
||||
Elem1->SetIntPoint(&eip1);
|
||||
}
|
||||
Loc1.Transform(*ip, eip1);
|
||||
Elem1->SetIntPoint(&eip1);
|
||||
}
|
||||
if (mask & 8)
|
||||
if (Elem2)
|
||||
{
|
||||
Loc2.Transform(*face_ip, eip2);
|
||||
if (Elem2)
|
||||
{
|
||||
Elem2->SetIntPoint(&eip2);
|
||||
}
|
||||
Loc2.Transform(*ip, eip2);
|
||||
Elem2->SetIntPoint(&eip2);
|
||||
}
|
||||
}
|
||||
|
||||
ElementTransformation &
|
||||
FaceElementTransformations::GetElement1Transformation()
|
||||
{
|
||||
MFEM_VERIFY(mask & HAVE_ELEM1 && Elem1 != NULL, "The ElementTransformation "
|
||||
MFEM_VERIFY(mask & 1 && Elem1 != NULL, "The ElementTransformation "
|
||||
"for the element has not been configured for side 1.");
|
||||
return *Elem1;
|
||||
}
|
||||
@@ -585,7 +579,7 @@ FaceElementTransformations::GetElement1Transformation()
|
||||
ElementTransformation &
|
||||
FaceElementTransformations::GetElement2Transformation()
|
||||
{
|
||||
MFEM_VERIFY(mask & HAVE_ELEM2 && Elem2 != NULL, "The ElementTransformation "
|
||||
MFEM_VERIFY(mask & 2 && Elem2 != NULL, "The ElementTransformation "
|
||||
"for the element has not been configured for side 2.");
|
||||
return *Elem2;
|
||||
}
|
||||
@@ -593,7 +587,7 @@ FaceElementTransformations::GetElement2Transformation()
|
||||
IntegrationPointTransformation &
|
||||
FaceElementTransformations::GetIntPoint1Transformation()
|
||||
{
|
||||
MFEM_VERIFY(mask & HAVE_LOC1, "The IntegrationPointTransformation "
|
||||
MFEM_VERIFY(mask & 4, "The IntegrationPointTransformation "
|
||||
"for the element has not been configured for side 1.");
|
||||
return Loc1;
|
||||
}
|
||||
@@ -601,7 +595,7 @@ FaceElementTransformations::GetIntPoint1Transformation()
|
||||
IntegrationPointTransformation &
|
||||
FaceElementTransformations::GetIntPoint2Transformation()
|
||||
{
|
||||
MFEM_VERIFY(mask & HAVE_LOC2, "The IntegrationPointTransformation "
|
||||
MFEM_VERIFY(mask & 8, "The IntegrationPointTransformation "
|
||||
"for the element has not been configured for side 2.");
|
||||
return Loc2;
|
||||
}
|
||||
@@ -609,7 +603,7 @@ FaceElementTransformations::GetIntPoint2Transformation()
|
||||
void FaceElementTransformations::Transform(const IntegrationPoint &ip,
|
||||
Vector &trans)
|
||||
{
|
||||
MFEM_VERIFY(mask & HAVE_FACE, "The ElementTransformation "
|
||||
MFEM_VERIFY(mask & 16, "The ElementTransformation "
|
||||
"for the face has not been configured.");
|
||||
IsoparametricTransformation::Transform(ip, trans);
|
||||
}
|
||||
@@ -617,7 +611,7 @@ void FaceElementTransformations::Transform(const IntegrationPoint &ip,
|
||||
void FaceElementTransformations::Transform(const IntegrationRule &ir,
|
||||
DenseMatrix &tr)
|
||||
{
|
||||
MFEM_VERIFY(mask & HAVE_FACE, "The ElementTransformation "
|
||||
MFEM_VERIFY(mask & 16, "The ElementTransformation "
|
||||
"for the face has not been configured.");
|
||||
IsoparametricTransformation::Transform(ir, tr);
|
||||
}
|
||||
@@ -625,7 +619,7 @@ void FaceElementTransformations::Transform(const IntegrationRule &ir,
|
||||
void FaceElementTransformations::Transform(const DenseMatrix &matrix,
|
||||
DenseMatrix &result)
|
||||
{
|
||||
MFEM_VERIFY(mask & HAVE_FACE, "The ElementTransformation "
|
||||
MFEM_VERIFY(mask & 16, "The ElementTransformation "
|
||||
"for the face has not been configured.");
|
||||
IsoparametricTransformation::Transform(matrix, result);
|
||||
}
|
||||
|
||||
+8
-83
@@ -439,57 +439,15 @@ public:
|
||||
void Transform (const IntegrationRule &, IntegrationRule &);
|
||||
};
|
||||
|
||||
/** @brief A specialized ElementTransformation class representing a face and
|
||||
its two neighboring elements.
|
||||
|
||||
This class can be used as a container for the element transformation data
|
||||
needed for integrating discontinuous fields on element interfaces in a
|
||||
Discontinuous Galerkin (DG) context.
|
||||
|
||||
The secondary purpose of this class is to enable the
|
||||
GridFunction::GetValue function, and various related functions, to properly
|
||||
evaluate fields with limited continuity on boundary elements.
|
||||
*/
|
||||
class FaceElementTransformations : public IsoparametricTransformation
|
||||
{
|
||||
private:
|
||||
|
||||
// Bitwise OR of ConfigMasks
|
||||
int mask;
|
||||
|
||||
IntegrationPoint eip1, eip2;
|
||||
|
||||
protected: // interface for Mesh to be able to configure this object.
|
||||
|
||||
friend class Mesh;
|
||||
#ifdef MFEM_USE_MPI
|
||||
friend class ParMesh;
|
||||
#endif
|
||||
|
||||
/// Set the mask indicating which portions of the object have been setup
|
||||
/** The argument @a m is a bitmask used in
|
||||
Mesh::GetFaceElementTransformations to indicate which portions of the
|
||||
FaceElementTransformations object have been configured.
|
||||
|
||||
mask & 1: Elem1 is configured
|
||||
mask & 2: Elem2 is configured
|
||||
mask & 4: Loc1 is configured
|
||||
mask & 8: Loc2 is configured
|
||||
mask & 16: The Face transformation itself is configured
|
||||
*/
|
||||
void SetConfigurationMask(int m) { mask = m; }
|
||||
|
||||
public:
|
||||
|
||||
enum ConfigMasks
|
||||
{
|
||||
HAVE_ELEM1 = 1, ///< Element on side 1 is configured
|
||||
HAVE_ELEM2 = 2, ///< Element on side 2 is configured
|
||||
HAVE_LOC1 = 4, ///< Point transformation for side 1 is configured
|
||||
HAVE_LOC2 = 8, ///< Point transformation for side 2 is configured
|
||||
HAVE_FACE = 16 ///< Face transformation is configured
|
||||
};
|
||||
|
||||
int Elem1No, Elem2No;
|
||||
Geometry::Type &FaceGeom; ///< @deprecated Use GetGeometryType instead
|
||||
ElementTransformation *Elem1, *Elem2;
|
||||
@@ -508,10 +466,10 @@ public:
|
||||
*/
|
||||
void SetGeometryType(Geometry::Type g) { geom = g; }
|
||||
|
||||
/** @brief Return the mask defining the configuration state.
|
||||
|
||||
The mask value indicates which portions of FaceElementTransformations
|
||||
object have been configured.
|
||||
/// Set the mask indicating which portions of the object have been setup
|
||||
/** The argument @a m is a bitmask used in
|
||||
Mesh::GetFaceElementTransformations to indicate which portions of the
|
||||
FaceElement Transformations object have been configured.
|
||||
|
||||
mask & 1: Elem1 is configured
|
||||
mask & 2: Elem2 is configured
|
||||
@@ -519,45 +477,12 @@ public:
|
||||
mask & 8: Loc2 is configured
|
||||
mask & 16: The Face transformation itself is configured
|
||||
*/
|
||||
int GetConfigurationMask() const { return mask; }
|
||||
void SetConfigurationMask(int m) { mask = m; }
|
||||
int GetConfigurationMask() const { return mask; }
|
||||
|
||||
/** @brief Set the integration point in the Face and the two neighboring
|
||||
elements, if present.
|
||||
|
||||
The point @a face_ip must be in the reference coordinate system of the
|
||||
face.
|
||||
*/
|
||||
void SetIntPoint(const IntegrationPoint *face_ip);
|
||||
|
||||
/** @brief Set the integration point in the Face and the two neighboring
|
||||
elements, if present.
|
||||
|
||||
This is a more expressive member function name than SetIntPoint, which
|
||||
in this special case, does the same thing. This function can be used for
|
||||
greater code clarity.
|
||||
*/
|
||||
inline void SetAllIntPoints(const IntegrationPoint *face_ip)
|
||||
{ FaceElementTransformations::SetIntPoint(face_ip); }
|
||||
|
||||
/** @brief Get a const reference to the integration point in neighboring
|
||||
element 1 corresponding to the currently set integration point on the
|
||||
face.
|
||||
|
||||
This IntegrationPoint object will only contain up-to-date data if
|
||||
SetIntPoint or SetAllIntPoints has been called with the latest
|
||||
integration point for the face and the appropriate point transformation
|
||||
has been configured. */
|
||||
const IntegrationPoint &GetElement1IntPoint() { return eip1; }
|
||||
|
||||
/** @brief Get a const reference to the integration point in neighboring
|
||||
element 2 corresponding to the currently set integration point on the
|
||||
face.
|
||||
|
||||
This IntegrationPoint object will only contain up-to-date data if
|
||||
SetIntPoint or SetAllIntPoints has been called with the latest
|
||||
integration point for the face and the appropriate point transformation
|
||||
has been configured. */
|
||||
const IntegrationPoint &GetElement2IntPoint() { return eip2; }
|
||||
elements, if present. */
|
||||
void SetIntPoint(const IntegrationPoint *ip);
|
||||
|
||||
virtual void Transform(const IntegrationPoint &, Vector &);
|
||||
virtual void Transform(const IntegrationRule &, DenseMatrix &);
|
||||
|
||||
+1
-4
@@ -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;
|
||||
}
|
||||
|
||||
+6
-6
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
+96
-320
@@ -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++)
|
||||
@@ -767,21 +752,19 @@ double GridFunction::GetValue(ElementTransformation &T,
|
||||
IntegrationPoint fip;
|
||||
be_to_bfe(FET->GetGeometryType(), o, ip, fip);
|
||||
|
||||
// Compute and set the point in element 1 from fip
|
||||
FET->SetAllIntPoints(&fip);
|
||||
FET->SetIntPoint(&fip);
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
return GetValue(T1, T1.GetIntPoint(), comp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ElementTransformation::BDR_FACE:
|
||||
{
|
||||
FaceElementTransformations * FET =
|
||||
dynamic_cast<FaceElementTransformations *>(&T);
|
||||
|
||||
// Evaluate in neighboring element for both continuous and
|
||||
// discontinuous fields (the integration point in T1 should have
|
||||
// already been set).
|
||||
// discontinuous fields.
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
return GetValue(T1, T1.GetIntPoint(), comp);
|
||||
}
|
||||
@@ -905,21 +888,19 @@ void GridFunction::GetVectorValue(ElementTransformation &T,
|
||||
IntegrationPoint fip;
|
||||
be_to_bfe(FET->GetGeometryType(), o, ip, fip);
|
||||
|
||||
// Compute and set the point in element 1 from fip
|
||||
FET->SetAllIntPoints(&fip);
|
||||
FET->SetIntPoint(&fip);
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
return GetVectorValue(T1, T1.GetIntPoint(), val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ElementTransformation::BDR_FACE:
|
||||
{
|
||||
FaceElementTransformations * FET =
|
||||
dynamic_cast<FaceElementTransformations *>(&T);
|
||||
|
||||
// Evaluate in neighboring element for both continuous and
|
||||
// discontinuous fields (the integration point in T1 should have
|
||||
// already been set).
|
||||
// discontinuous fields.
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
return GetVectorValue(T1, T1.GetIntPoint(), val);
|
||||
}
|
||||
@@ -1357,262 +1338,107 @@ void GridFunction::GetVectorGradientHat(
|
||||
MultAtB(loc_data_mat, dshape, gh);
|
||||
}
|
||||
|
||||
double GridFunction::GetDivergence(ElementTransformation &T) const
|
||||
double GridFunction::GetDivergence(ElementTransformation &tr) const
|
||||
{
|
||||
switch (T.ElementType)
|
||||
double div_v;
|
||||
int elNo = tr.ElementNo;
|
||||
const FiniteElement *FElem = fes->GetFE(elNo);
|
||||
if (FElem->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
case ElementTransformation::ELEMENT:
|
||||
MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
|
||||
"invalid FE map type");
|
||||
DenseMatrix grad_hat;
|
||||
GetVectorGradientHat(tr, grad_hat);
|
||||
const DenseMatrix &Jinv = tr.InverseJacobian();
|
||||
div_v = 0.0;
|
||||
for (int i = 0; i < Jinv.Width(); i++)
|
||||
{
|
||||
int elNo = T.ElementNo;
|
||||
const FiniteElement *fe = fes->GetFE(elNo);
|
||||
if (fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
for (int j = 0; j < Jinv.Height(); j++)
|
||||
{
|
||||
MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
|
||||
"invalid FE map type");
|
||||
DenseMatrix grad_hat;
|
||||
GetVectorGradientHat(T, grad_hat);
|
||||
const DenseMatrix &Jinv = T.InverseJacobian();
|
||||
double div_v = 0.0;
|
||||
for (int i = 0; i < Jinv.Width(); i++)
|
||||
{
|
||||
for (int j = 0; j < Jinv.Height(); j++)
|
||||
{
|
||||
div_v += grad_hat(i, j) * Jinv(j, i);
|
||||
}
|
||||
}
|
||||
return div_v;
|
||||
div_v += grad_hat(i, j) * Jinv(j, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assuming RT-type space
|
||||
Array<int> dofs;
|
||||
fes->GetElementDofs(elNo, dofs);
|
||||
Vector loc_data, divshape(fe->GetDof());
|
||||
GetSubVector(dofs, loc_data);
|
||||
fe->CalcDivShape(T.GetIntPoint(), divshape);
|
||||
return (loc_data * divshape) / T.Weight();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ElementTransformation::BDR_ELEMENT:
|
||||
{
|
||||
// In order to properly capture the derivative of the normal component
|
||||
// of the field (as well as the transverse divergence of the
|
||||
// tangential compoents) we must evaluate it in the neighboring
|
||||
// element.
|
||||
FaceElementTransformations * FET =
|
||||
fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo);
|
||||
|
||||
// Boundary elements and Boundary Faces may have different
|
||||
// orientations so adjust the integration point if necessary.
|
||||
int o = 0;
|
||||
if (fes->GetMesh()->Dimension() == 3)
|
||||
{
|
||||
int f;
|
||||
fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
|
||||
}
|
||||
|
||||
IntegrationPoint fip;
|
||||
be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip);
|
||||
|
||||
// Compute and set the point in element 1 from fip
|
||||
FET->SetAllIntPoints(&fip);
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
|
||||
return GetDivergence(T1);
|
||||
}
|
||||
break;
|
||||
case ElementTransformation::BDR_FACE:
|
||||
{
|
||||
// This must be a DG context so this dynamic cast must succeed.
|
||||
FaceElementTransformations * FET =
|
||||
dynamic_cast<FaceElementTransformations *>(&T);
|
||||
|
||||
// Evaluate in neighboring element (the integration point in T1 should
|
||||
// have already been set).
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
return GetDivergence(T1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
MFEM_ABORT("GridFunction::GetDivergence: Unsupported element type \""
|
||||
<< T.ElementType << "\"");
|
||||
}
|
||||
}
|
||||
return 0.0; // never reached
|
||||
else
|
||||
{
|
||||
// Assuming RT-type space
|
||||
Array<int> dofs;
|
||||
fes->GetElementDofs(elNo, dofs);
|
||||
Vector loc_data, divshape(FElem->GetDof());
|
||||
GetSubVector(dofs, loc_data);
|
||||
FElem->CalcDivShape(tr.GetIntPoint(), divshape);
|
||||
div_v = (loc_data * divshape) / tr.Weight();
|
||||
}
|
||||
return div_v;
|
||||
}
|
||||
|
||||
void GridFunction::GetCurl(ElementTransformation &T, Vector &curl) const
|
||||
void GridFunction::GetCurl(ElementTransformation &tr, Vector &curl) const
|
||||
{
|
||||
switch (T.ElementType)
|
||||
int elNo = tr.ElementNo;
|
||||
const FiniteElement *FElem = fes->GetFE(elNo);
|
||||
if (FElem->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
case ElementTransformation::ELEMENT:
|
||||
MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
|
||||
"invalid FE map type");
|
||||
DenseMatrix grad_hat;
|
||||
GetVectorGradientHat(tr, grad_hat);
|
||||
const DenseMatrix &Jinv = tr.InverseJacobian();
|
||||
DenseMatrix grad(grad_hat.Height(), Jinv.Width()); // vdim x FElem->Dim
|
||||
Mult(grad_hat, Jinv, grad);
|
||||
MFEM_ASSERT(grad.Height() == grad.Width(), "");
|
||||
if (grad.Height() == 3)
|
||||
{
|
||||
int elNo = T.ElementNo;
|
||||
const FiniteElement *fe = fes->GetFE(elNo);
|
||||
if (fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
|
||||
"invalid FE map type");
|
||||
DenseMatrix grad_hat;
|
||||
GetVectorGradientHat(T, grad_hat);
|
||||
const DenseMatrix &Jinv = T.InverseJacobian();
|
||||
// Dimensions of grad are vdim x FElem->Dim
|
||||
DenseMatrix grad(grad_hat.Height(), Jinv.Width());
|
||||
Mult(grad_hat, Jinv, grad);
|
||||
MFEM_ASSERT(grad.Height() == grad.Width(), "");
|
||||
if (grad.Height() == 3)
|
||||
{
|
||||
curl.SetSize(3);
|
||||
curl(0) = grad(2,1) - grad(1,2);
|
||||
curl(1) = grad(0,2) - grad(2,0);
|
||||
curl(2) = grad(1,0) - grad(0,1);
|
||||
}
|
||||
else if (grad.Height() == 2)
|
||||
{
|
||||
curl.SetSize(1);
|
||||
curl(0) = grad(1,0) - grad(0,1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assuming ND-type space
|
||||
Array<int> dofs;
|
||||
fes->GetElementDofs(elNo, dofs);
|
||||
Vector loc_data;
|
||||
GetSubVector(dofs, loc_data);
|
||||
DenseMatrix curl_shape(fe->GetDof(), fe->GetDim() == 3 ? 3 : 1);
|
||||
fe->CalcCurlShape(T.GetIntPoint(), curl_shape);
|
||||
curl.SetSize(curl_shape.Width());
|
||||
if (curl_shape.Width() == 3)
|
||||
{
|
||||
double curl_hat[3];
|
||||
curl_shape.MultTranspose(loc_data, curl_hat);
|
||||
T.Jacobian().Mult(curl_hat, curl);
|
||||
}
|
||||
else
|
||||
{
|
||||
curl_shape.MultTranspose(loc_data, curl);
|
||||
}
|
||||
curl /= T.Weight();
|
||||
}
|
||||
curl.SetSize(3);
|
||||
curl(0) = grad(2,1) - grad(1,2);
|
||||
curl(1) = grad(0,2) - grad(2,0);
|
||||
curl(2) = grad(1,0) - grad(0,1);
|
||||
}
|
||||
break;
|
||||
case ElementTransformation::BDR_ELEMENT:
|
||||
else if (grad.Height() == 2)
|
||||
{
|
||||
// In order to capture the tangential components of the curl we
|
||||
// must evaluate it in the neighboring element.
|
||||
FaceElementTransformations * FET =
|
||||
fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo);
|
||||
|
||||
// Boundary elements and Boundary Faces may have different
|
||||
// orientations so adjust the integration point if necessary.
|
||||
int o = 0;
|
||||
if (fes->GetMesh()->Dimension() == 3)
|
||||
{
|
||||
int f;
|
||||
fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
|
||||
}
|
||||
|
||||
IntegrationPoint fip;
|
||||
be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip);
|
||||
|
||||
// Compute and set the point in element 1 from fip
|
||||
FET->SetAllIntPoints(&fip);
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
|
||||
GetCurl(T1, curl);
|
||||
curl.SetSize(1);
|
||||
curl(0) = grad(1,0) - grad(0,1);
|
||||
}
|
||||
break;
|
||||
case ElementTransformation::BDR_FACE:
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assuming ND-type space
|
||||
Array<int> dofs;
|
||||
fes->GetElementDofs(elNo, dofs);
|
||||
Vector loc_data;
|
||||
GetSubVector(dofs, loc_data);
|
||||
DenseMatrix curl_shape(FElem->GetDof(), FElem->GetDim() == 3 ? 3 : 1);
|
||||
FElem->CalcCurlShape(tr.GetIntPoint(), curl_shape);
|
||||
curl.SetSize(curl_shape.Width());
|
||||
if (curl_shape.Width() == 3)
|
||||
{
|
||||
// This must be a DG context so this dynamic cast must succeed.
|
||||
FaceElementTransformations * FET =
|
||||
dynamic_cast<FaceElementTransformations *>(&T);
|
||||
|
||||
// Evaluate in neighboring element (the integration point in T1 should
|
||||
// have already been set).
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
GetCurl(T1, curl);
|
||||
double curl_hat[3];
|
||||
curl_shape.MultTranspose(loc_data, curl_hat);
|
||||
tr.Jacobian().Mult(curl_hat, curl);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("GridFunction::GetCurl: Unsupported element type \""
|
||||
<< T.ElementType << "\"");
|
||||
curl_shape.MultTranspose(loc_data, curl);
|
||||
}
|
||||
curl /= tr.Weight();
|
||||
}
|
||||
}
|
||||
|
||||
void GridFunction::GetGradient(ElementTransformation &T, Vector &grad) const
|
||||
void GridFunction::GetGradient(ElementTransformation &tr, Vector &grad) const
|
||||
{
|
||||
switch (T.ElementType)
|
||||
{
|
||||
case ElementTransformation::ELEMENT:
|
||||
{
|
||||
const FiniteElement * fe = fes->GetFE(T.ElementNo);
|
||||
MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
|
||||
"invalid FE map type");
|
||||
int spaceDim = fes->GetMesh()->SpaceDimension();
|
||||
int dim = fe->GetDim(), dof = fe->GetDof();
|
||||
DenseMatrix dshape(dof, dim);
|
||||
Vector lval, gh(dim);
|
||||
Array<int> dofs;
|
||||
int elNo = tr.ElementNo;
|
||||
const FiniteElement *fe = fes->GetFE(elNo);
|
||||
MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type");
|
||||
int dim = fe->GetDim(), dof = fe->GetDof();
|
||||
DenseMatrix dshape(dof, dim);
|
||||
Vector lval, gh(dim);
|
||||
Array<int> dofs;
|
||||
|
||||
grad.SetSize(spaceDim);
|
||||
fes->GetElementDofs(T.ElementNo, dofs);
|
||||
GetSubVector(dofs, lval);
|
||||
fe->CalcDShape(T.GetIntPoint(), dshape);
|
||||
dshape.MultTranspose(lval, gh);
|
||||
T.InverseJacobian().MultTranspose(gh, grad);
|
||||
}
|
||||
break;
|
||||
case ElementTransformation::BDR_ELEMENT:
|
||||
{
|
||||
// In order to properly capture the normal component of the gradient
|
||||
// as well as its tangential components we must evaluate it in the
|
||||
// neighboring element.
|
||||
FaceElementTransformations * FET =
|
||||
fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo);
|
||||
|
||||
// Boundary elements and Boundary Faces may have different
|
||||
// orientations so adjust the integration point if necessary.
|
||||
int o = 0;
|
||||
if (fes->GetMesh()->Dimension() == 3)
|
||||
{
|
||||
int f;
|
||||
fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
|
||||
}
|
||||
|
||||
IntegrationPoint fip;
|
||||
be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip);
|
||||
|
||||
// Compute and set the point in element 1 from fip
|
||||
FET->SetAllIntPoints(&fip);
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
|
||||
GetGradient(T1, grad);
|
||||
}
|
||||
break;
|
||||
case ElementTransformation::BDR_FACE:
|
||||
{
|
||||
// This must be a DG context so this dynamic cast must succeed.
|
||||
FaceElementTransformations * FET =
|
||||
dynamic_cast<FaceElementTransformations *>(&T);
|
||||
|
||||
// Evaluate in neighboring element (the integration point in T1 should
|
||||
// have already been set).
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
GetGradient(T1, grad);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
MFEM_ABORT("GridFunction::GetGradient: Unsupported element type \""
|
||||
<< T.ElementType << "\"");
|
||||
}
|
||||
}
|
||||
grad.SetSize(dim);
|
||||
fes->GetElementDofs(elNo, dofs);
|
||||
GetSubVector(dofs, lval);
|
||||
fe->CalcDShape(tr.GetIntPoint(), dshape);
|
||||
dshape.MultTranspose(lval, gh);
|
||||
tr.InverseJacobian().MultTranspose(gh, grad);
|
||||
}
|
||||
|
||||
void GridFunction::GetGradients(ElementTransformation &tr,
|
||||
@@ -1641,65 +1467,15 @@ void GridFunction::GetGradients(ElementTransformation &tr,
|
||||
}
|
||||
|
||||
void GridFunction::GetVectorGradient(
|
||||
ElementTransformation &T, DenseMatrix &grad) const
|
||||
ElementTransformation &tr, DenseMatrix &grad) const
|
||||
{
|
||||
switch (T.ElementType)
|
||||
{
|
||||
case ElementTransformation::ELEMENT:
|
||||
{
|
||||
MFEM_ASSERT(fes->GetFE(T.ElementNo)->GetMapType() ==
|
||||
FiniteElement::VALUE, "invalid FE map type");
|
||||
DenseMatrix grad_hat;
|
||||
GetVectorGradientHat(T, grad_hat);
|
||||
const DenseMatrix &Jinv = T.InverseJacobian();
|
||||
grad.SetSize(grad_hat.Height(), Jinv.Width());
|
||||
Mult(grad_hat, Jinv, grad);
|
||||
}
|
||||
break;
|
||||
case ElementTransformation::BDR_ELEMENT:
|
||||
{
|
||||
// In order to capture the normal component of the gradient we
|
||||
// must evaluate it in the neighboring element.
|
||||
FaceElementTransformations * FET =
|
||||
fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo);
|
||||
|
||||
// Boundary elements and Boundary Faces may have different
|
||||
// orientations so adjust the integration point if necessary.
|
||||
int o = 0;
|
||||
if (fes->GetMesh()->Dimension() == 3)
|
||||
{
|
||||
int f;
|
||||
fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
|
||||
}
|
||||
|
||||
IntegrationPoint fip;
|
||||
be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip);
|
||||
|
||||
// Compute and set the point in element 1 from fip
|
||||
FET->SetAllIntPoints(&fip);
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
|
||||
GetVectorGradient(T1, grad);
|
||||
}
|
||||
break;
|
||||
case ElementTransformation::BDR_FACE:
|
||||
{
|
||||
// This must be a DG context so this dynamic cast must succeed.
|
||||
FaceElementTransformations * FET =
|
||||
dynamic_cast<FaceElementTransformations *>(&T);
|
||||
|
||||
// Evaluate in neighboring element (the integration point in T1 should
|
||||
// have already been set).
|
||||
ElementTransformation & T1 = FET->GetElement1Transformation();
|
||||
GetVectorGradient(T1, grad);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
MFEM_ABORT("GridFunction::GetVectorGradient: "
|
||||
"Unsupported element type \"" << T.ElementType << "\"");
|
||||
}
|
||||
}
|
||||
MFEM_ASSERT(fes->GetFE(tr.ElementNo)->GetMapType() == FiniteElement::VALUE,
|
||||
"invalid FE map type");
|
||||
DenseMatrix grad_hat;
|
||||
GetVectorGradientHat(tr, grad_hat);
|
||||
const DenseMatrix &Jinv = tr.InverseJacobian();
|
||||
grad.SetSize(grad_hat.Height(), Jinv.Width());
|
||||
Mult(grad_hat, Jinv, grad);
|
||||
}
|
||||
|
||||
void GridFunction::GetElementAverages(GridFunction &avgs) const
|
||||
|
||||
+7
-9
@@ -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
|
||||
@@ -209,14 +208,13 @@ public:
|
||||
///@{
|
||||
/** Return a scalar value from within the element indicated by the
|
||||
ElementTransformation Object. */
|
||||
virtual double GetValue(ElementTransformation &T, const IntegrationPoint &ip,
|
||||
int comp = 0, Vector *tr = NULL) const;
|
||||
double GetValue(ElementTransformation &T, const IntegrationPoint &ip,
|
||||
int comp = 0, Vector *tr = NULL) const;
|
||||
|
||||
/** Return a vector value from within the element indicated by the
|
||||
ElementTransformation Object. */
|
||||
virtual void GetVectorValue(ElementTransformation &T,
|
||||
const IntegrationPoint &ip,
|
||||
Vector &val, Vector *tr = NULL) const;
|
||||
void GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip,
|
||||
Vector &val, Vector *tr = NULL) const;
|
||||
///@}
|
||||
|
||||
/** @name ElementTransformation Get Values Methods
|
||||
@@ -714,7 +712,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.
|
||||
|
||||
@@ -192,7 +192,6 @@ void FindPointsGSLIB::Interpolate(Array<unsigned int> &codes,
|
||||
const int ncomp = field_in.FESpace()->GetVDim(),
|
||||
points_fld = field_in.Size() / ncomp,
|
||||
points_cnt = codes.Size();
|
||||
field_out.SetSize(points_cnt*ncomp);
|
||||
|
||||
for (int i = 0; i < ncomp; i++)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+19
-91
@@ -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
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+18
-31
@@ -159,13 +159,10 @@ void BoundaryLFIntegrator::AssembleRHSElementVect(
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
IntegrationPoint eip;
|
||||
Tr.Loc1.Transform(ip, eip);
|
||||
|
||||
// Set the integration point in the face and the neighboring element
|
||||
Tr.SetAllIntPoints(&ip);
|
||||
|
||||
// Access the neighboring element's integration point
|
||||
const IntegrationPoint &eip = Tr.GetElement1IntPoint();
|
||||
|
||||
Tr.Face->SetIntPoint (&ip);
|
||||
double val = Tr.Face->Weight() * ip.weight * Q.Eval(*Tr.Face, ip);
|
||||
|
||||
el.CalcShape(eip, shape);
|
||||
@@ -362,12 +359,10 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
IntegrationPoint eip;
|
||||
Tr.Loc1.Transform(ip, eip);
|
||||
|
||||
// Set the integration point in the face and the neighboring element
|
||||
Tr.SetAllIntPoints(&ip);
|
||||
|
||||
// Access the neighboring element's integration point
|
||||
const IntegrationPoint &eip = Tr.GetElement1IntPoint();
|
||||
Tr.SetIntPoint(&ip);
|
||||
|
||||
// Use Tr transformation in case Q depends on boundary attribute
|
||||
Q.Eval(vec, Tr, ip);
|
||||
@@ -688,14 +683,12 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
|
||||
for (int p = 0; p < ir->GetNPoints(); p++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(p);
|
||||
|
||||
// Set the integration point in the face and the neighboring element
|
||||
Tr.SetAllIntPoints(&ip);
|
||||
|
||||
// Access the neighboring element's integration point
|
||||
const IntegrationPoint &eip = Tr.GetElement1IntPoint();
|
||||
IntegrationPoint eip;
|
||||
Tr.Loc1.Transform(ip, eip);
|
||||
el.CalcShape(eip, shape);
|
||||
|
||||
Tr.SetIntPoint(&ip);
|
||||
|
||||
// Use Tr.Elem1 transformation for u so that it matches the coefficient
|
||||
// used with the ConvectionIntegrator and/or the DGTraceIntegrator.
|
||||
u->Eval(vu, *Tr.Elem1, eip);
|
||||
@@ -759,13 +752,10 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect(
|
||||
for (int p = 0; p < ir->GetNPoints(); p++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(p);
|
||||
IntegrationPoint eip;
|
||||
|
||||
// Set the integration point in the face and the neighboring element
|
||||
Tr.SetAllIntPoints(&ip);
|
||||
|
||||
// Access the neighboring element's integration point
|
||||
const IntegrationPoint &eip = Tr.GetElement1IntPoint();
|
||||
|
||||
Tr.Loc1.Transform(ip, eip);
|
||||
Tr.SetIntPoint(&ip);
|
||||
if (dim == 1)
|
||||
{
|
||||
nor(0) = 2*eip.x - 1.0;
|
||||
@@ -784,14 +774,14 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect(
|
||||
{
|
||||
if (Q)
|
||||
{
|
||||
w *= Q->Eval(*Tr.Elem1, eip);
|
||||
w *= Q->Eval(Tr, ip);
|
||||
}
|
||||
ni.Set(w, nor);
|
||||
}
|
||||
else
|
||||
{
|
||||
nh.Set(w, nor);
|
||||
MQ->Eval(mq, *Tr.Elem1, eip);
|
||||
MQ->Eval(mq, Tr, ip);
|
||||
mq.MultTranspose(nh, ni);
|
||||
}
|
||||
CalcAdjugate(Tr.Elem1->Jacobian(), adjJ);
|
||||
@@ -855,12 +845,9 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
|
||||
for (int pi = 0; pi < ir->GetNPoints(); ++pi)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(pi);
|
||||
|
||||
// Set the integration point in the face and the neighboring element
|
||||
Tr.SetAllIntPoints(&ip);
|
||||
|
||||
// Access the neighboring element's integration point
|
||||
const IntegrationPoint &eip = Tr.GetElement1IntPoint();
|
||||
IntegrationPoint eip;
|
||||
Tr.Loc1.Transform(ip, eip);
|
||||
Tr.SetIntPoint(&ip);
|
||||
|
||||
// Evaluate the Dirichlet b.c. using the face transformation.
|
||||
uD.Eval(u_dir, Tr, ip);
|
||||
|
||||
+4
-11
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() { }
|
||||
};
|
||||
|
||||
|
||||
@@ -198,9 +198,8 @@ void ParBilinearForm::AssembleSharedFaces(int skip_zeros)
|
||||
for (int i = 0; i < nfaces; i++)
|
||||
{
|
||||
T = pmesh->GetSharedFaceTransformations(i);
|
||||
int Elem2NbrNo = T->Elem2No - pmesh->GetNE();
|
||||
pfes->GetElementVDofs(T->Elem1No, vdofs1);
|
||||
pfes->GetFaceNbrElementVDofs(Elem2NbrNo, vdofs2);
|
||||
pfes->GetFaceNbrElementVDofs(T->Elem2No, vdofs2);
|
||||
vdofs1.Copy(vdofs_all);
|
||||
for (int j = 0; j < vdofs2.Size(); j++)
|
||||
{
|
||||
@@ -217,7 +216,7 @@ void ParBilinearForm::AssembleSharedFaces(int skip_zeros)
|
||||
for (int k = 0; k < fbfi.Size(); k++)
|
||||
{
|
||||
fbfi[k]->AssembleFaceMatrix(*pfes->GetFE(T->Elem1No),
|
||||
*pfes->GetFaceNbrFE(Elem2NbrNo),
|
||||
*pfes->GetFaceNbrFE(T->Elem2No),
|
||||
*T, elemmat);
|
||||
if (keep_nbr_block)
|
||||
{
|
||||
@@ -241,7 +240,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
@@ -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();
|
||||
|
||||
@@ -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
-177
@@ -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,175 +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
|
||||
{
|
||||
// We can assume faces and edges are local
|
||||
if (T.ElementType != ElementTransformation::ELEMENT)
|
||||
{
|
||||
return GridFunction::GetValue(T, ip, comp, tr);
|
||||
}
|
||||
|
||||
// Check for evaluation in a local element
|
||||
int nbr_el_no = T.ElementNo - pfes->GetParMesh()->GetNE();
|
||||
if (nbr_el_no < 0)
|
||||
{
|
||||
return GridFunction::GetValue(T, ip, comp, tr);
|
||||
}
|
||||
|
||||
// Evaluate using DoFs from a neighboring element
|
||||
if (tr)
|
||||
{
|
||||
T.SetIntPoint(&ip);
|
||||
T.Transform(ip, *tr);
|
||||
}
|
||||
|
||||
Array<int> dofs;
|
||||
const FiniteElement * fe = pfes->GetFaceNbrFE(nbr_el_no);
|
||||
pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs);
|
||||
|
||||
pfes->DofsToVDofs(comp-1, dofs);
|
||||
Vector DofVal(dofs.Size()), LocVec;
|
||||
if (fe->GetMapType() == FiniteElement::VALUE)
|
||||
{
|
||||
fe->CalcShape(ip, DofVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
fe->CalcPhysShape(T, DofVal);
|
||||
}
|
||||
face_nbr_data.GetSubVector(dofs, LocVec);
|
||||
|
||||
return (DofVal * LocVec);
|
||||
}
|
||||
|
||||
void ParGridFunction::GetVectorValue(ElementTransformation &T,
|
||||
const IntegrationPoint &ip,
|
||||
Vector &val, Vector *tr) const
|
||||
{
|
||||
// We can assume faces and edges are local
|
||||
if (T.ElementType != ElementTransformation::ELEMENT)
|
||||
{
|
||||
return GridFunction::GetVectorValue(T, ip, val, tr);
|
||||
}
|
||||
|
||||
// Check for evaluation in a local element
|
||||
int nbr_el_no = T.ElementNo - pfes->GetParMesh()->GetNE();
|
||||
if (nbr_el_no < 0)
|
||||
{
|
||||
return GridFunction::GetVectorValue(T, ip, val, tr);
|
||||
}
|
||||
|
||||
// Evaluate using DoFs from a neighboring element
|
||||
if (tr)
|
||||
{
|
||||
T.SetIntPoint(&ip);
|
||||
T.Transform(ip, *tr);
|
||||
}
|
||||
|
||||
Array<int> vdofs;
|
||||
pfes->GetFaceNbrElementVDofs(nbr_el_no, vdofs);
|
||||
const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no);
|
||||
|
||||
int dof = fe->GetDof();
|
||||
Vector loc_data;
|
||||
face_nbr_data.GetSubVector(vdofs, loc_data);
|
||||
if (fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
Vector shape(dof);
|
||||
if (fe->GetMapType() == FiniteElement::VALUE)
|
||||
{
|
||||
fe->CalcShape(ip, shape);
|
||||
}
|
||||
else
|
||||
{
|
||||
fe->CalcPhysShape(T, shape);
|
||||
}
|
||||
int vdim = pfes->GetVDim();
|
||||
val.SetSize(vdim);
|
||||
for (int k = 0; k < vdim; k++)
|
||||
{
|
||||
val(k) = shape * ((const double *)loc_data + dof * k);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int spaceDim = pfes->GetMesh()->SpaceDimension();
|
||||
DenseMatrix vshape(dof, spaceDim);
|
||||
fe->CalcVShape(T, vshape);
|
||||
val.SetSize(spaceDim);
|
||||
vshape.MultTranspose(loc_data, val);
|
||||
}
|
||||
}
|
||||
|
||||
void ParGridFunction::ProjectCoefficient(Coefficient &coeff)
|
||||
{
|
||||
DeltaCoefficient *delta_c = dynamic_cast<DeltaCoefficient *>(&coeff);
|
||||
@@ -711,9 +539,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();
|
||||
|
||||
+1
-13
@@ -39,7 +39,7 @@ protected:
|
||||
Vector face_nbr_data;
|
||||
|
||||
/** @brief Vector used as an MPI buffer to send face-neighbor data
|
||||
in ExchangeFaceNbrData() to neighboring processors. */
|
||||
in ExchangeFaceNbrData() to neighboring processors. */
|
||||
//TODO: Use temporary memory to avoid CUDA malloc allocation cost.
|
||||
Vector send_data;
|
||||
|
||||
@@ -209,18 +209,6 @@ public:
|
||||
double GetValue(ElementTransformation &T)
|
||||
{ return GetValue(T.ElementNo, T.GetIntPoint()); }
|
||||
|
||||
// Redefine to handle the case when T describes a face-neighbor element
|
||||
virtual double GetValue(ElementTransformation &T, const IntegrationPoint &ip,
|
||||
int comp = 0, Vector *tr = NULL) const;
|
||||
|
||||
virtual void GetVectorValue(int i, const IntegrationPoint &ip,
|
||||
Vector &val) const;
|
||||
|
||||
// Redefine to handle the case when T describes a face-neighbor element
|
||||
virtual void GetVectorValue(ElementTransformation &T,
|
||||
const IntegrationPoint &ip,
|
||||
Vector &val, Vector *tr = NULL) const;
|
||||
|
||||
using GridFunction::ProjectCoefficient;
|
||||
virtual void ProjectCoefficient(Coefficient &coeff);
|
||||
|
||||
|
||||
+11
-19
@@ -14,7 +14,6 @@
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -50,7 +49,6 @@ void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
|
||||
if (fnfi.Size())
|
||||
{
|
||||
MFEM_VERIFY(!NonlinearForm::ext,"");
|
||||
// Terms over shared interior faces in parallel.
|
||||
ParFiniteElementSpace *pfes = ParFESpace();
|
||||
ParMesh *pmesh = pfes->GetParMesh();
|
||||
@@ -66,13 +64,12 @@ void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
for (int i = 0; i < n_shared_faces; i++)
|
||||
{
|
||||
tr = pmesh->GetSharedFaceTransformations(i, true);
|
||||
int Elem2NbrNo = tr->Elem2No - pmesh->GetNE();
|
||||
|
||||
fe1 = pfes->GetFE(tr->Elem1No);
|
||||
fe2 = pfes->GetFaceNbrFE(Elem2NbrNo);
|
||||
fe2 = pfes->GetFaceNbrFE(tr->Elem2No);
|
||||
|
||||
pfes->GetElementVDofs(tr->Elem1No, vdofs1);
|
||||
pfes->GetFaceNbrElementVDofs(Elem2NbrNo, vdofs2);
|
||||
pfes->GetFaceNbrElementVDofs(tr->Elem2No, vdofs2);
|
||||
|
||||
el_x.SetSize(vdofs1.Size() + vdofs2.Size());
|
||||
X.GetSubVector(vdofs1, el_x.GetData());
|
||||
@@ -88,16 +85,15 @@ void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
|
||||
P->MultTranspose(aux2, y);
|
||||
|
||||
const int N = ess_tdof_list.Size();
|
||||
const auto idx = ess_tdof_list.Read();
|
||||
auto Y = y.ReadWrite();
|
||||
MFEM_FORALL(i, N, Y[idx[i]] = 0.0; );
|
||||
y.HostReadWrite();
|
||||
for (int i = 0; i < ess_tdof_list.Size(); i++)
|
||||
{
|
||||
y(ess_tdof_list[i]) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
const SparseMatrix &ParNonlinearForm::GetLocalGradient(const Vector &x) const
|
||||
{
|
||||
if (NonlinearForm::ext) { MFEM_ABORT("Not yet implemented!"); }
|
||||
|
||||
NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.
|
||||
|
||||
return *Grad;
|
||||
@@ -107,20 +103,16 @@ Operator &ParNonlinearForm::GetGradient(const Vector &x) const
|
||||
{
|
||||
ParFiniteElementSpace *pfes = ParFESpace();
|
||||
|
||||
Operator &grad = NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.
|
||||
|
||||
pGrad.Clear();
|
||||
|
||||
NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.
|
||||
|
||||
OperatorHandle dA(pGrad.Type()), Ph(pGrad.Type());
|
||||
|
||||
if (fnfi.Size() == 0)
|
||||
{
|
||||
if (NonlinearForm::ext) { dA.Reset(&grad, false); }
|
||||
else
|
||||
{
|
||||
dA.MakeSquareBlockDiag(pfes->GetComm(), pfes->GlobalVSize(),
|
||||
pfes->GetDofOffsets(), Grad);
|
||||
}
|
||||
dA.MakeSquareBlockDiag(pfes->GetComm(), pfes->GlobalVSize(),
|
||||
pfes->GetDofOffsets(), Grad);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+57
-136
@@ -27,24 +27,35 @@ ParL2FaceRestriction::ParL2FaceRestriction(const ParFiniteElementSpace &fes,
|
||||
ElementDofOrdering e_ordering,
|
||||
FaceType type,
|
||||
L2FaceValues m)
|
||||
: L2FaceRestriction(fes, type, m)
|
||||
: fes(fes),
|
||||
nf(fes.GetNFbyType(type)),
|
||||
vdim(fes.GetVDim()),
|
||||
byvdim(fes.GetOrdering() == Ordering::byVDIM),
|
||||
ndofs(fes.GetNDofs()),
|
||||
dof(nf>0 ?
|
||||
fes.GetTraceElement(0, fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof()
|
||||
: 0),
|
||||
m(m),
|
||||
nfdofs(nf*dof),
|
||||
scatter_indices1(nf*dof),
|
||||
scatter_indices2(m==L2FaceValues::DoubleValued?nf*dof:0),
|
||||
offsets(ndofs+1),
|
||||
gather_indices((m==L2FaceValues::DoubleValued? 2 : 1)*nf*dof)
|
||||
{
|
||||
if (nf==0) { return; }
|
||||
// If fespace == L2
|
||||
const ParFiniteElementSpace &pfes =
|
||||
static_cast<const ParFiniteElementSpace&>(this->fes);
|
||||
const FiniteElement *fe = pfes.GetFE(0);
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
const TensorBasisElement *tfe = dynamic_cast<const TensorBasisElement*>(fe);
|
||||
MFEM_VERIFY(tfe != NULL &&
|
||||
(tfe->GetBasisType()==BasisType::GaussLobatto ||
|
||||
tfe->GetBasisType()==BasisType::Positive),
|
||||
"Only Gauss-Lobatto and Bernstein basis are supported in "
|
||||
"ParL2FaceRestriction.");
|
||||
MFEM_VERIFY(pfes.GetMesh()->Conforming(),
|
||||
MFEM_VERIFY(fes.GetMesh()->Conforming(),
|
||||
"Non-conforming meshes not yet supported with partial assembly.");
|
||||
// Assuming all finite elements are using Gauss-Lobatto dofs
|
||||
height = (m==L2FaceValues::DoubleValued? 2 : 1)*vdim*nf*dof;
|
||||
width = pfes.GetVSize();
|
||||
width = fes.GetVSize();
|
||||
const bool dof_reorder = (e_ordering == ElementDofOrdering::LEXICOGRAPHIC);
|
||||
if (!dof_reorder)
|
||||
{
|
||||
@@ -52,32 +63,32 @@ ParL2FaceRestriction::ParL2FaceRestriction(const ParFiniteElementSpace &fes,
|
||||
}
|
||||
if (dof_reorder && nf > 0)
|
||||
{
|
||||
for (int f = 0; f < pfes.GetNF(); ++f)
|
||||
for (int f = 0; f < fes.GetNF(); ++f)
|
||||
{
|
||||
const FiniteElement *fe =
|
||||
pfes.GetTraceElement(f, pfes.GetMesh()->GetFaceBaseGeometry(f));
|
||||
fes.GetTraceElement(f, fes.GetMesh()->GetFaceBaseGeometry(f));
|
||||
const TensorBasisElement* el =
|
||||
dynamic_cast<const TensorBasisElement*>(fe);
|
||||
if (el) { continue; }
|
||||
mfem_error("Finite element not suitable for lexicographic ordering");
|
||||
}
|
||||
}
|
||||
const Table& e2dTable = pfes.GetElementToDofTable();
|
||||
const Table& e2dTable = fes.GetElementToDofTable();
|
||||
const int* elementMap = e2dTable.GetJ();
|
||||
Array<int> faceMap1(dof), faceMap2(dof);
|
||||
int e1, e2;
|
||||
int inf1, inf2;
|
||||
int face_id1, face_id2;
|
||||
int orientation;
|
||||
const int dof1d = pfes.GetFE(0)->GetOrder()+1;
|
||||
const int elem_dofs = pfes.GetFE(0)->GetDof();
|
||||
const int dim = pfes.GetMesh()->SpaceDimension();
|
||||
const int dof1d = fes.GetFE(0)->GetOrder()+1;
|
||||
const int elem_dofs = fes.GetFE(0)->GetDof();
|
||||
const int dim = fes.GetMesh()->SpaceDimension();
|
||||
// Computation of scatter indices
|
||||
int f_ind=0;
|
||||
for (int f = 0; f < pfes.GetNF(); ++f)
|
||||
for (int f = 0; f < fes.GetNF(); ++f)
|
||||
{
|
||||
pfes.GetMesh()->GetFaceElements(f, &e1, &e2);
|
||||
pfes.GetMesh()->GetFaceInfos(f, &inf1, &inf2);
|
||||
fes.GetMesh()->GetFaceElements(f, &e1, &e2);
|
||||
fes.GetMesh()->GetFaceInfos(f, &inf1, &inf2);
|
||||
if (dof_reorder)
|
||||
{
|
||||
orientation = inf1 % 64;
|
||||
@@ -125,7 +136,7 @@ ParL2FaceRestriction::ParL2FaceRestriction(const ParFiniteElementSpace &fes,
|
||||
{
|
||||
const int se2 = -1 - e2;
|
||||
Array<int> sharedDofs;
|
||||
pfes.GetFaceNbrElementVDofs(se2, sharedDofs);
|
||||
fes.GetFaceNbrElementVDofs(se2, sharedDofs);
|
||||
for (int d = 0; d < dof; ++d)
|
||||
{
|
||||
const int pd = PermuteFaceL2(dim, face_id1, face_id2,
|
||||
@@ -169,10 +180,10 @@ ParL2FaceRestriction::ParL2FaceRestriction(const ParFiniteElementSpace &fes,
|
||||
offsets[i] = 0;
|
||||
}
|
||||
f_ind = 0;
|
||||
for (int f = 0; f < pfes.GetNF(); ++f)
|
||||
for (int f = 0; f < fes.GetNF(); ++f)
|
||||
{
|
||||
pfes.GetMesh()->GetFaceElements(f, &e1, &e2);
|
||||
pfes.GetMesh()->GetFaceInfos(f, &inf1, &inf2);
|
||||
fes.GetMesh()->GetFaceElements(f, &e1, &e2);
|
||||
fes.GetMesh()->GetFaceInfos(f, &inf1, &inf2);
|
||||
if ((type==FaceType::Interior && (e2>=0 || (e2<0 && inf2>=0))) ||
|
||||
(type==FaceType::Boundary && e2<0 && inf2<0) )
|
||||
{
|
||||
@@ -211,10 +222,10 @@ ParL2FaceRestriction::ParL2FaceRestriction(const ParFiniteElementSpace &fes,
|
||||
offsets[i] += offsets[i - 1];
|
||||
}
|
||||
f_ind = 0;
|
||||
for (int f = 0; f < pfes.GetNF(); ++f)
|
||||
for (int f = 0; f < fes.GetNF(); ++f)
|
||||
{
|
||||
pfes.GetMesh()->GetFaceElements(f, &e1, &e2);
|
||||
pfes.GetMesh()->GetFaceInfos(f, &inf1, &inf2);
|
||||
fes.GetMesh()->GetFaceElements(f, &e1, &e2);
|
||||
fes.GetMesh()->GetFaceInfos(f, &inf1, &inf2);
|
||||
if ((type==FaceType::Interior && (e2>=0 || (e2<0 && inf2>=0))) ||
|
||||
(type==FaceType::Boundary && e2<0 && inf2<0) )
|
||||
{
|
||||
@@ -261,10 +272,8 @@ ParL2FaceRestriction::ParL2FaceRestriction(const ParFiniteElementSpace &fes,
|
||||
|
||||
void ParL2FaceRestriction::Mult(const Vector& x, Vector& y) const
|
||||
{
|
||||
const ParFiniteElementSpace &pfes =
|
||||
static_cast<const ParFiniteElementSpace&>(this->fes);
|
||||
ParGridFunction x_gf;
|
||||
x_gf.MakeRef(const_cast<ParFiniteElementSpace*>(&pfes),
|
||||
x_gf.MakeRef(const_cast<ParFiniteElementSpace*>(&fes),
|
||||
const_cast<Vector&>(x), 0);
|
||||
x_gf.ExchangeFaceNbrData();
|
||||
|
||||
@@ -328,122 +337,34 @@ void ParL2FaceRestriction::Mult(const Vector& x, Vector& y) const
|
||||
}
|
||||
}
|
||||
|
||||
static MFEM_HOST_DEVICE int AddNnz(const int iE, int *I, const int dofs)
|
||||
void ParL2FaceRestriction::MultTranspose(const Vector& x, Vector& y) const
|
||||
{
|
||||
int val = AtomicAdd(I[iE],dofs);
|
||||
return val;
|
||||
}
|
||||
|
||||
void ParL2FaceRestriction::FillI(SparseMatrix &mat,
|
||||
SparseMatrix &face_mat) const
|
||||
{
|
||||
const int face_dofs = dof;
|
||||
const int Ndofs = ndofs;
|
||||
auto d_indices1 = scatter_indices1.Read();
|
||||
auto d_indices2 = scatter_indices2.Read();
|
||||
auto I = mat.ReadWriteI();
|
||||
auto I_face = face_mat.ReadWriteI();
|
||||
MFEM_FORALL(i, ne*elemDofs*vdim+1,
|
||||
// Assumes all elements have the same number of dofs
|
||||
const int nd = dof;
|
||||
const int vd = vdim;
|
||||
const bool t = byvdim;
|
||||
const int dofs = nfdofs;
|
||||
auto d_offsets = offsets.Read();
|
||||
auto d_indices = gather_indices.Read();
|
||||
auto d_x = Reshape(x.Read(), nd, vd, 2, nf);
|
||||
auto d_y = Reshape(y.Write(), t?vd:ndofs, t?ndofs:vd);
|
||||
MFEM_FORALL(i, ndofs,
|
||||
{
|
||||
I_face[i] = 0;
|
||||
});
|
||||
MFEM_FORALL(fdof, nf*face_dofs,
|
||||
{
|
||||
const int f = fdof/face_dofs;
|
||||
const int iF = fdof%face_dofs;
|
||||
const int iE1 = d_indices1[f*face_dofs+iF];
|
||||
if (iE1 < Ndofs)
|
||||
const int offset = d_offsets[i];
|
||||
const int nextOffset = d_offsets[i + 1];
|
||||
for (int c = 0; c < vd; ++c)
|
||||
{
|
||||
for (int jF = 0; jF < face_dofs; jF++)
|
||||
double dofValue = 0;
|
||||
for (int j = offset; j < nextOffset; ++j)
|
||||
{
|
||||
const int jE2 = d_indices2[f*face_dofs+jF];
|
||||
if (jE2 < Ndofs)
|
||||
{
|
||||
AddNnz(iE1,I,1);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddNnz(iE1,I_face,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
const int iE2 = d_indices2[f*face_dofs+iF];
|
||||
if (iE2 < Ndofs)
|
||||
{
|
||||
for (int jF = 0; jF < face_dofs; jF++)
|
||||
{
|
||||
const int jE1 = d_indices1[f*face_dofs+jF];
|
||||
if (jE1 < Ndofs)
|
||||
{
|
||||
AddNnz(iE2,I,1);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddNnz(iE2,I_face,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ParL2FaceRestriction::FillJAndData(const Vector &ea_data,
|
||||
SparseMatrix &mat,
|
||||
SparseMatrix &face_mat) const
|
||||
{
|
||||
const int face_dofs = dof;
|
||||
const int Ndofs = ndofs;
|
||||
auto d_indices1 = scatter_indices1.Read();
|
||||
auto d_indices2 = scatter_indices2.Read();
|
||||
auto mat_fea = Reshape(ea_data.Read(), face_dofs, face_dofs, 2, nf);
|
||||
auto I = mat.ReadWriteI();
|
||||
auto I_face = face_mat.ReadWriteI();
|
||||
auto J = mat.WriteJ();
|
||||
auto J_face = face_mat.WriteJ();
|
||||
auto Data = mat.WriteData();
|
||||
auto Data_face = face_mat.WriteData();
|
||||
MFEM_FORALL(fdof, nf*face_dofs,
|
||||
{
|
||||
const int f = fdof/face_dofs;
|
||||
const int iF = fdof%face_dofs;
|
||||
const int iE1 = d_indices1[f*face_dofs+iF];
|
||||
if (iE1 < Ndofs)
|
||||
{
|
||||
for (int jF = 0; jF < face_dofs; jF++)
|
||||
{
|
||||
const int jE2 = d_indices2[f*face_dofs+jF];
|
||||
if (jE2 < Ndofs)
|
||||
{
|
||||
const int offset = AddNnz(iE1,I,1);
|
||||
J[offset] = jE2;
|
||||
Data[offset] = mat_fea(jF,iF,1,f);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int offset = AddNnz(iE1,I_face,1);
|
||||
J_face[offset] = jE2-Ndofs;
|
||||
Data_face[offset] = mat_fea(jF,iF,1,f);
|
||||
}
|
||||
}
|
||||
}
|
||||
const int iE2 = d_indices2[f*face_dofs+iF];
|
||||
if (iE2 < Ndofs)
|
||||
{
|
||||
for (int jF = 0; jF < face_dofs; jF++)
|
||||
{
|
||||
const int jE1 = d_indices1[f*face_dofs+jF];
|
||||
if (jE1 < Ndofs)
|
||||
{
|
||||
const int offset = AddNnz(iE2,I,1);
|
||||
J[offset] = jE1;
|
||||
Data[offset] = mat_fea(jF,iF,0,f);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int offset = AddNnz(iE2,I_face,1);
|
||||
J_face[offset] = jE1-Ndofs;
|
||||
Data_face[offset] = mat_fea(jF,iF,0,f);
|
||||
}
|
||||
int idx_j = d_indices[j];
|
||||
bool isE1 = idx_j < dofs;
|
||||
idx_j = isE1 ? idx_j : idx_j - dofs;
|
||||
dofValue += isE1 ?
|
||||
d_x(idx_j % nd, c, 0, idx_j / nd)
|
||||
:d_x(idx_j % nd, c, 1, idx_j / nd);
|
||||
}
|
||||
d_y(t?c:i,t?i:c) += dofValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+16
-9
@@ -26,21 +26,28 @@ class ParFiniteElementSpace;
|
||||
/// Operator that extracts Face degrees of freedom in parallel.
|
||||
/** Objects of this type are typically created and owned by FiniteElementSpace
|
||||
objects, see FiniteElementSpace::GetFaceRestriction(). */
|
||||
class ParL2FaceRestriction : public L2FaceRestriction
|
||||
class ParL2FaceRestriction : public Operator
|
||||
{
|
||||
protected:
|
||||
const ParFiniteElementSpace &fes;
|
||||
const int nf;
|
||||
const int vdim;
|
||||
const bool byvdim;
|
||||
const int ndofs;
|
||||
const int dof;
|
||||
const L2FaceValues m;
|
||||
const int nfdofs;
|
||||
Array<int> scatter_indices1;
|
||||
Array<int> scatter_indices2;
|
||||
Array<int> offsets;
|
||||
Array<int> gather_indices;
|
||||
|
||||
public:
|
||||
ParL2FaceRestriction(const ParFiniteElementSpace&, ElementDofOrdering,
|
||||
FaceType type,
|
||||
L2FaceValues m = L2FaceValues::DoubleValued);
|
||||
void Mult(const Vector &x, Vector &y) const;
|
||||
/** Fill the I array of SparseMatrix corresponding to the sparsity pattern
|
||||
given by this ParL2FaceRestriction. */
|
||||
void FillI(SparseMatrix &mat, SparseMatrix &face_mat) const;
|
||||
/** Fill the J and Data arrays of SparseMatrix corresponding to the sparsity
|
||||
pattern given by this ParL2FaceRestriction, and the values of ea_data. */
|
||||
void FillJAndData(const Vector &ea_data,
|
||||
SparseMatrix &mat,
|
||||
SparseMatrix &face_mat) const;
|
||||
void MultTranspose(const Vector &x, Vector &y) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+1128
-400
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user