Compare commits

..
222 changed files with 13859 additions and 66111 deletions
+1 -3
View File
@@ -15,9 +15,7 @@ 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
# Install METIS
- ps: Start-FileDownload 'https://mfem.github.io/tpls/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
+1 -8
View File
@@ -50,6 +50,7 @@ examples/ex1[04-9]
examples/ex1[0-9]p
examples/ex2[0-9]
examples/ex2[0-9]p
examples/ex25-gpu
examples/refined.mesh
examples/displaced.mesh
@@ -175,7 +176,6 @@ miniapps/meshing/mesh-optimizer
miniapps/meshing/pmesh-optimizer
miniapps/meshing/minimal-surface
miniapps/meshing/pminimal-surface
miniapps/meshing/polar-nc
miniapps/meshing/mobius-strip.mesh
miniapps/meshing/klein-bottle.mesh
@@ -188,7 +188,6 @@ miniapps/meshing/extruder.mesh
miniapps/meshing/trimmer.mesh
miniapps/meshing/optimized*
miniapps/meshing/perturbed*
miniapps/meshing/polar-nc.mesh
miniapps/performance/ex1
miniapps/performance/ex1p
@@ -235,7 +234,6 @@ miniapps/nurbs/mode_*
miniapps/nurbs/Example1*
miniapps/gslib/field-diff
miniapps/gslib/field-interp
miniapps/gslib/findpts
miniapps/gslib/pfindpts
@@ -262,10 +260,5 @@ tests/scripts/*.err
tests/scripts/*.out
tests/scripts/*.msg
# Other tests
tests/convergence/rates
tests/convergence/prates
tests/par-mesh-format/ex1p
# VPATH builds
build-*/*
+1 -17
View File
@@ -71,8 +71,6 @@ stages:
- build
- test
- deallocate
- lassen_build
- lassen_test
- baseline_check
- baseline_publish
@@ -81,11 +79,7 @@ stages:
# TODO: updating tests and tpls is not necessary anymore since pipelines are
# now using unique directories so repo are never shared with another pipeline.
# This is not memory efficient (we keep a lot of data), hence this reminder.
# Setup
setup:
tags:
- shell
- quartz
.setup:
stage: setup
variables:
GIT_STRATEGY: none
@@ -106,15 +100,6 @@ setup:
before_script:
- module load gcc/6.1.0
# On lassen
.with_gcc_8_3_1:
variables:
TOOLCHAIN: gcc_8_3_1
CXX: g++
CC: gcc
before_script:
- module load gcc/8.3.1
.with_gcc_4_9_3:
variables:
TOOLCHAIN: gcc_4_9_3
@@ -305,4 +290,3 @@ setup:
# The list on jobs is defined in machine-specific files.
include:
- local: .gitlab/quartz.yml
- local: .gitlab/lassen.yml
-57
View File
@@ -1,57 +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.
# GitLab pipelines configurations for the Lassen machine at LLNL
.on_lassen:
tags:
- shell
- lassen
variables:
PLAT: lassen
# Build MFEM
build_mfem_ser_lassen:
extends: [.with_gcc_8_3_1, .on_lassen]
needs: [setup]
stage: lassen_build
script:
- mkdir -p ${BUILD_PATH}
- cp -r ${CI_PROJECT_DIR} ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser
- lalloc 1 -W 5 -q pdebug make -j cuda CUDA_ARCH=sm_70
build_mfem_debug_ser_lassen:
extends: [.with_gcc_8_3_1, .on_lassen]
needs: [setup]
stage: lassen_build
script:
- mkdir -p ${BUILD_PATH}
- cp -r ${CI_PROJECT_DIR} ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser_debug
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser_debug
- lalloc 1 -W 5 -q pdebug make -j cuda MFEM_DEBUG="YES" CUDA_ARCH=sm_70
# Sanity check
sanitycheck_mfem_ser_lassen:
extends: [.with_gcc_8_3_1, .on_lassen]
stage: lassen_test
needs: [build_mfem_ser_lassen]
script:
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser
- lalloc 1 -W 15 -q pdebug make -j test
sanitycheck_mfem_debug_ser_lassen:
extends: [.with_gcc_8_3_1, .on_lassen]
stage: lassen_test
needs: [build_mfem_debug_ser_lassen]
script:
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser_debug
- lalloc 1 -W 30 -q pdebug make -j test
+4
View File
@@ -22,6 +22,10 @@
MAKE_PAR: 6
BASELINE_PAR: 18
# Setup
setup_quartz:
extends: [.setup, .on_quartz]
# Allocate
allocate_quartz:
variables:
+13 -77
View File
@@ -11,9 +11,6 @@
language: cpp
os: linux
dist: bionic
stages:
- checks
- tests
@@ -37,7 +34,6 @@ jobs:
- stage: checks
os: linux
dist: xenial
name: "code-style"
addons:
apt:
@@ -56,6 +52,9 @@ jobs:
packages:
- doxygen
- graphviz
- mpich
- libmpich-dev
env: MPI=YES
script:
- cd ${TRAVIS_BUILD_DIR}
- cd tests/scripts
@@ -70,24 +69,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 +84,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 +112,6 @@ jobs:
MPI=NO
CODECOV=NO
MFEM_TEST_TARGET=check
cache:
ccache: true
- os: linux
compiler: gcc
@@ -135,8 +120,6 @@ jobs:
MPI=NO
CODECOV=NO
MFEM_TEST_TARGET=test
cache:
ccache: true
- os: linux
compiler: gcc
@@ -160,7 +143,6 @@ jobs:
MFEM_TEST_TARGET=check
NPROCS=2
cache:
ccache: true
directories:
- $TRAVIS_BUILD_DIR/../$HYPRE_TOP_DIR/src/hypre
- $TRAVIS_BUILD_DIR/../metis-4.0
@@ -191,7 +173,6 @@ jobs:
MFEM_TEST_TARGET=test
NPROCS=2
cache:
ccache: true
directories:
- $TRAVIS_BUILD_DIR/../$HYPRE_TOP_DIR/src/hypre
- $TRAVIS_BUILD_DIR/../metis-4.0
@@ -223,7 +204,6 @@ jobs:
- make -j3
- ctest --output-on-failure
cache:
ccache: true
directories:
- $TRAVIS_BUILD_DIR/../$HYPRE_TOP_DIR/src/hypre
- $TRAVIS_BUILD_DIR/../metis-4.0
@@ -241,43 +221,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,7 +249,6 @@ jobs:
NPROCS=4
TMPDIR=/tmp
cache:
ccache: true
directories:
- $TRAVIS_BUILD_DIR/../$HYPRE_TOP_DIR/src/hypre
- $TRAVIS_BUILD_DIR/../metis-4.0
@@ -296,13 +259,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,7 +269,6 @@ jobs:
NPROCS=4
TMPDIR=/tmp
cache:
ccache: true
directories:
- $TRAVIS_BUILD_DIR/../$HYPRE_TOP_DIR/src/hypre
- $TRAVIS_BUILD_DIR/../metis-4.0
@@ -326,19 +284,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;
@@ -399,9 +352,7 @@ install:
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;
@@ -414,18 +365,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 +385,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
+14 -60
View File
@@ -16,12 +16,7 @@ Meshing improvements
- The graph linear ordering library Gecko, previously an external dependency, is
now included directly in MFEM. As a result, Mesh::GetGeckoElementOrdering is
always available. The interface has also been improved, see for example the
Mesh Explorer miniapp.
- Improved Gmsh reader (version 2.2), which now supports both high-order and
periodic meshes. Segments, triangles, quadrilaterals, and tetrahedra are
supported up to order 10. Wedges and hexahedra are supported up to order 9.
For sample periodic meshes, see the periodic*.msh files in the data directory.
mesh-explorer miniapp.
- Added support for finite difference-based gradient and Hessian approximation
in the TMOP mesh optimization algorithms. This improves the accuracy of the
@@ -32,17 +27,15 @@ Meshing improvements
the user to specify different discrete functions for controlling the
size, aspect-ratio, orientation, and skew of elements in the mesh.
- Added TMOP capability for approximate tangential mesh relaxation. Added
support and examples for using TMOP on mixed meshes.
- Added TMOP capability for approximate tangential mesh relaxation.
- Added support for reading periodic meshes in Gmsh format (version 2.2). See
for example the periodic-annulus-sector and periodic-torus-sector files in
the data directory.
- Added complete action of the TMOP Integrator to account for the spatial
derivatives of discrete and analytic targets.
- Added support for initialization of (serial) non-conforming meshes. Hanging
nodes can be marked with Mesh::AddVertexParents when building the mesh with
the "init" constructor. The usage is demonstrated in a new meshing miniapp
(polar-nc) which generates meshes that are non-conforming from the start.
Performance improvements
------------------------
- Added support for explicit vectorization in the high-performance templated
@@ -51,7 +44,7 @@ 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
@@ -65,15 +58,11 @@ Improved GPU capabilities
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 CUDA support for sparse matrix-vector multiplication with cuSPARSE.
- Added AmgX solver class for simple integration with NVIDIA's multigrid library.
- Added support for BlockOperator on GPU. See the updated Example 5.
- Added partial assembly and GPU support for complex operators, including the
classes ComplexOperator, [Par]ComplexGridFunction, [Par]ComplexLinearForm, and
[Par]SesquilinearForm. See the updated Example 22.
- Added partial assembly and GPU support for ComplexOperator,
[Par]ComplexGridFunction, [Par]ComplexLinearForm, and [Par]SesquilinearForm.
See the updated Example 22.
Discretization improvements
---------------------------
@@ -103,14 +92,6 @@ Discretization improvements
- Added support face integrals on the boundaries of NURBS meshes.
- Added support for interpolation of functions in L2, H(div) and H(curl)
spaces using GSLIB-FindPoints.
- Added support for computing asymptotic error estimates and convergence rates
for the whole de Rham sequence based on the new class ConvergenceStudy and new
member methods in GridFunction and ParGridFunction. See the rates.cpp file in
the tests/convergence directory for sample usage.
Linear and nonlinear solvers
----------------------------
- Added power method to iteratively estimate the largest eigenvalue and the
@@ -136,9 +117,6 @@ Linear and nonlinear solvers
- Added support for the SLEPc eigensolver package.
- Added partially assembled convergent diagonal preconditioner for adaptively
refined meshes (i.e. non-conforming finite element spaces), see Example 6/6p.
New and updated examples and miniapps
-------------------------------------
- Added a new example, Example 25/25p, to demonstrate the use of a Perfectly
@@ -175,12 +153,6 @@ 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 a new meshing miniapp, Polar NC, which demonstrates the construction of
polar non-conforming meshes.
- Added partial assembly support to Example 4/4p and Example 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
@@ -192,47 +164,29 @@ 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 a new miniapp (field-interp) that demonstrates transfer of grid function
between different meshes using GSLIB-FindPoints.
- Added diagonal preconditioner in Example 6/6p for partial assembly with AMR.
- Added device support in Example 5/5p.
- Added partial assembly and device support to Example 22/22p, with diagonal
preconditioning.
- Added the option to plot a function in Mesh Explorer.
- Added partial assembly and device support to Example 4/4p, Example 5/5p,
Example 22/22p, and Example 25/25p, with diagonal preconditioning.
Improved testing
----------------
- Upgraded the Catch unit test framework from version 1.6.1 to version 2.13.0.
- Added a GitLab pipeline that automates PR testing on supercomputing systems
and Linux clusters at Lawrence Livermore National Lab (LLNL). This can be
triggered only by LLNL developers, see .gitlab-ci.yml, the .gitlab directory
and the updated CONTRIBUTING.md file.
- Added testing of the parallel mesh format in tests/par-mesh-format.
Miscellaneous
-------------
- Added support for ADIOS2 for parallel I/O with ParaView visualization. The
classes adios2stream and ADIOS2DataCollection are introduced in mfem as the
interfaces to generate ADIOS2 Binary Pack (BP4) directory datasets for the
entire spatial and temporal node data. Cell centered data is accessible by
ADIOS2 data readers (e.g. Python), but currently not yet implement as of
ParaView v5.8.1. In addition, ADIOS2 allows for setting a user-defined number
of data substreams/subfiles at scale. See examples 5, 9, 12, 16.
entire spatial and temporal data. In addition, ADIOS2 allows for setting a
user-defined number of data substreams/subfiles. See examples 5, 9, 12, 16.
- The integration order used in the ComputeLpError and ComputeElementLpError
methods of class GridFunction has been increased.
- Various other simplifications, extensions, and bugfixes in the code.
- Renamed "Backend::DEBUG" to "Backend::DEBUG_DEVICE" to avoid conflicts,
as DEBUG is sometimes used as a macro.
Version 4.1, released on March 10, 2020
=======================================
+17 -37
View File
@@ -89,38 +89,8 @@ enable_language(CXX)
if (MFEM_USE_CUDA)
# MFEM_USE_CUDA requires CMake 3.8 or newer (for direct CUDA support)
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
# Use ${CMAKE_CXX_COMPILER} as the cuda host compiler.
if (NOT CMAKE_CUDA_HOST_COMPILER)
set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER})
endif()
enable_language(CUDA)
set(CMAKE_CUDA_STANDARD 11)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_EXTENSIONS OFF)
set(CUDA_FLAGS "--expt-extended-lambda")
if (CMAKE_VERSION VERSION_LESS 3.18.0)
set(CUDA_FLAGS "-arch=${CUDA_ARCH} ${CUDA_FLAGS}")
elseif (NOT CMAKE_CUDA_ARCHITECTURES)
string(REGEX REPLACE "^sm_" "" ARCH_NUMBER "${CUDA_ARCH}")
if ("${CUDA_ARCH}" STREQUAL "sm_${ARCH_NUMBER}")
set(CMAKE_CUDA_ARCHITECTURES "${ARCH_NUMBER}")
else()
message(FATAL_ERROR "Unknown CUDA_ARCH: ${CUDA_ARCH}")
endif()
else()
set(CUDA_ARCH "CMAKE_CUDA_ARCHITECTURES: ${CMAKE_CUDA_ARCHITECTURES}")
endif()
message(STATUS "Using CUDA architecture: ${CUDA_ARCH}")
if (CMAKE_VERSION VERSION_LESS 3.12.0)
# CMake versions 3.8 and 3.9 require this to work; 3.10 and 3.11 are not
# tested and may not actually need this (but should be ok to keep).
set(CUDA_FLAGS "-ccbin=${CMAKE_CXX_COMPILER} ${CUDA_FLAGS}")
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CMAKE_CXX_COMPILER})
endif()
set(CMAKE_CUDA_FLAGS "${CUDA_FLAGS}" CACHE STRING
"CUDA flags set for MFEM" FORCE)
set(CUSPARSE_FOUND TRUE)
set(CUSPARSE_LIBRARIES "cusparse")
endif()
if (XSDK_ENABLE_C)
@@ -295,11 +265,6 @@ if (MFEM_USE_CEED)
find_package(libCEED REQUIRED)
endif()
if (MFEM_USE_AMGX)
include_directories(${AMGX_DIR}/include)
link_directories(${AMGX_DIR}/lib64 -L${AMGX_DIR}/lib -Xlinker=-rpath=${CUDA_HOME}/lib64)
endif()
if (MFEM_USE_CONDUIT)
find_package(Conduit REQUIRED conduit relay blueprint )
endif()
@@ -331,6 +296,22 @@ if (MFEM_USE_HIOP)
# find_package updates HIOP_FOUND, HIOP_INCLUDE_DIRS, HIOP_LIBRARIES
endif()
# CUDA
if (MFEM_USE_CUDA)
set(CMAKE_CUDA_STANDARD 11)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_EXTENSIONS OFF)
set(CMAKE_CUDA_FLAGS "-arch=${CUDA_ARCH} --expt-extended-lambda"
CACHE STRING "CUDA flags set for MFEM" FORCE)
if (MFEM_USE_MPI)
set(CUDA_CCBIN_COMPILER ${MPI_CXX_COMPILER})
else()
set(CUDA_CCBIN_COMPILER ${CMAKE_CXX_COMPILER})
endif()
string(APPEND CMAKE_CUDA_FLAGS " -ccbin ${CUDA_CCBIN_COMPILER}")
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CUDA_CCBIN_COMPILER})
endif()
# OCCA
if (MFEM_USE_OCCA)
find_package(OCCA REQUIRED)
@@ -376,8 +357,7 @@ endif()
# be before SuiteSparse.
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
SLEPC MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2
CUSPARSE AMGX)
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
set(TPL_INCLUDE_DIRS "")
+1 -13
View File
@@ -350,12 +350,6 @@ MFEM_USE_STRUMPACK = YES/NO
classes. When enabled, this option uses the STRUMPACK_* library options, see
below.
MFEM_USE_AMGX = YES/NO
Enable MFEM functionality based on the AMGX multigrid library from
NVIDIA. When enabled, this options enables the user to use SparseMatrices
and HypreParMatrices to solve linear systems using routines from the AMGX
library.
MFEM_USE_GINKGO = YES/NO
Enable MFEM functionality based on the Ginkgo library, which provides
iterative linear solvers and preconditioners with OpenMP, CUDA backends, see
@@ -656,11 +650,6 @@ The specific libraries and their options are:
Options: CUDA_CXX, CUDA_ARCH, CUDA_OPT, CUDA_LIB.
Versions: CUDA >= 9.1, older versions may work too.
- AMGX (optional), used when MFEM_USE_AMGX = YES.
URL: https://github.com/NVIDIA/AMGX
Options: AMGX_OPT, AMGX_LIB.
Versions: AMGX >= 2.1, older versions may work too.
- HIP (optional), used when MFEM_USE_HIP = YES.
URL: https://rocm.github.io/ROCmInstall.html
Options: HIP_CXX, HIP_ARCH, HIP_OPT, HIP_LIB.
@@ -674,7 +663,7 @@ The specific libraries and their options are:
URL: https://github.com/CEED/libCEED
https://ceed.exascaleproject.org/libceed
Options: CEED_DIR, CEED_OPT, CEED_LIB.
Versions: libCEED > 0.6, git-hash bdfed75.
Versions: libCEED >= 0.6, git-hash a970f63.
- RAJA (optional), used when MFEM_USE_RAJA = YES.
Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported.
@@ -817,7 +806,6 @@ MFEM_USE_MESQUITE
MFEM_USE_SUITESPARSE
MFEM_USE_SUPERLU
MFEM_USE_STRUMPACK
MFEM_USE_AMGX
MFEM_USE_GINKGO
MFEM_USE_GNUTLS
MFEM_USE_NETCDF
-3
View File
@@ -126,9 +126,6 @@
// Requires a CUDA compiler (nvcc).
#cmakedefine MFEM_USE_CUDA
// Enable MFEM functionality based on the AMGX library
#cmakedefine MFEM_USE_AMGX
// Enable MFEM functionality based on the RAJA library
#cmakedefine MFEM_USE_RAJA
+1 -13
View File
@@ -38,19 +38,7 @@ if(NOT ADIOS2_FOUND)
endif()
find_path(ADIOS2_INCLUDE_DIR adios2.h ${ADIOS2_INCLUDE_OPTS})
# adios2 version 2.5.0
find_library(ADIOS2_LIBRARY NAMES adios2 ${ADIOS2_LIBRARY_OPTS})
# adios2 version 2.6.0 and onwards
if(NOT ADIOS2_LIBRARY)
find_library(ADIOS2_CXX11_MPI_LIBRARY NAMES adios2_cxx11_mpi ${ADIOS2_LIBRARY_OPTS})
find_library(ADIOS2_CXX11_LIBRARY NAMES adios2_cxx11 ${ADIOS2_LIBRARY_OPTS})
set(ADIOS2_LIBRARY ${ADIOS2_CXX11_MPI_LIBRARY} ${ADIOS2_CXX11_LIBRARY})
if(MFEM_USE_MPI)
add_definitions(-DADIOS2_USE_MPI)
endif()
endif()
find_library(ADIOS2_LIBRARY NAMES adios2 ${ADIOS2_LIBRARY_OPTS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ADIOS2
@@ -128,15 +128,7 @@ function(add_mfem_miniapp MFEM_EXE_NAME)
if (MFEM_USE_CUDA)
set_property(SOURCE ${MAIN_LIST} ${EXTRA_SOURCES_LIST}
PROPERTY LANGUAGE CUDA)
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
list(TRANSFORM EXTRA_OPTIONS_LIST PREPEND "-Xcompiler=")
else()
set(LIST_)
foreach(item IN LISTS EXTRA_OPTIONS_LIST)
list(APPEND LIST_ "-Xcompiler=${item}")
endforeach()
set(EXTRA_OPTIONS_LIST ${LIST_})
endif()
list(TRANSFORM EXTRA_OPTIONS_LIST PREPEND "-Xcompiler=")
endif()
# Actually add the executable
-3
View File
@@ -137,9 +137,6 @@
// Requires a CUDA compiler (nvcc).
// #define MFEM_USE_CUDA
// Enable MFEM functionality based on the AMGX library.
// #define MFEM_USE_AMGX
// Build the AMD GPU/HIP-enabled version of the MFEM library.
// Requires a HIP compiler (hipcc).
// #define MFEM_USE_HIP
-1
View File
@@ -45,7 +45,6 @@ MFEM_USE_PUMI = @MFEM_USE_PUMI@
MFEM_USE_HIOP = @MFEM_USE_HIOP@
MFEM_USE_GSLIB = @MFEM_USE_GSLIB@
MFEM_USE_CUDA = @MFEM_USE_CUDA@
MFEM_USE_AMGX = @MFEM_USE_AMGX@
MFEM_USE_HIP = @MFEM_USE_HIP@
MFEM_USE_RAJA = @MFEM_USE_RAJA@
MFEM_USE_OCCA = @MFEM_USE_OCCA@
+1 -7
View File
@@ -50,7 +50,7 @@ option(MFEM_USE_OCCA "Enable OCCA" OFF)
option(MFEM_USE_RAJA "Enable RAJA" OFF)
option(MFEM_USE_CEED "Enable CEED" OFF)
option(MFEM_USE_UMPIRE "Enable Umpire" OFF)
option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" 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")
@@ -83,11 +83,6 @@ set(HYPRE_DIR "${MFEM_DIR}/../hypre/src/hypre" CACHE PATH
# If hypre was compiled to depend on BLAS and LAPACK:
# set(HYPRE_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
# "Packages that HYPRE depends on.")
if (MFEM_USE_CUDA)
# This is only necessary when hypre is built with cuda:
set(HYPRE_REQUIRED_LIBRARIES "-lcusparse" "-lcurand" CACHE STRING
"Libraries that HYPRE depends on.")
endif()
set(METIS_DIR "${MFEM_DIR}/../metis-4.0" CACHE PATH "Path to the METIS library.")
@@ -187,7 +182,6 @@ set(HIOP_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
set(OCCA_DIR "${MFEM_DIR}/../occa" CACHE PATH "Path to OCCA")
set(RAJA_DIR "${MFEM_DIR}/../raja" CACHE PATH "Path to RAJA")
set(AMGX_DIR "${MFEM_DIR}/../amgx" CACHE PATH "Path to AMGX")
set(CEED_DIR "${MFEM_DIR}/../libCEED" CACHE PATH "Path to libCEED")
set(UMPIRE_DIR "${MFEM_DIR}/../umpire" CACHE PATH "Path to Umpire")
+3 -13
View File
@@ -133,13 +133,12 @@ MFEM_USE_PUMI = NO
MFEM_USE_HIOP = NO
MFEM_USE_GSLIB = NO
MFEM_USE_CUDA = NO
MFEM_USE_AMGX = NO
MFEM_USE_HIP = NO
MFEM_USE_RAJA = NO
MFEM_USE_OCCA = NO
MFEM_USE_CEED = NO
MFEM_USE_UMPIRE = NO
MFEM_USE_SIMD = NO
MFEM_USE_SIMD = YES
MFEM_USE_ADIOS2 = NO
# Compile and link options for zlib.
@@ -155,10 +154,6 @@ LIBUNWIND_LIB = $(if $(NOTMAC),-lunwind -ldl,)
HYPRE_DIR = @MFEM_DIR@/../hypre/src/hypre
HYPRE_OPT = -I$(HYPRE_DIR)/include
HYPRE_LIB = -L$(HYPRE_DIR)/lib -lHYPRE
ifeq (YES,$(MFEM_USE_CUDA))
# This is only necessary when hypre is built with cuda:
HYPRE_LIB += -lcusparse -lcurand
endif
# METIS library configuration
ifeq ($(MFEM_USE_SUPERLU)$(MFEM_USE_STRUMPACK),NONO)
@@ -346,9 +341,9 @@ GSLIB_DIR = @MFEM_DIR@/../gslib/build
GSLIB_OPT = -I$(GSLIB_DIR)/include
GSLIB_LIB = -L$(GSLIB_DIR)/lib -lgs
# CUDA library configuration
# CUDA library configuration (currently not needed)
CUDA_OPT =
CUDA_LIB = -lcusparse
CUDA_LIB =
# HIP library configuration (currently not needed)
HIP_OPT =
@@ -377,11 +372,6 @@ UMPIRE_DIR = @MFEM_DIR@/../umpire
UMPIRE_OPT = -I$(UMPIRE_DIR)/include
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -lumpire
# AMGX library configuration
AMGX_DIR = @MFEM_DIR@/../amgx
AMGX_OPT = -I$(AMGX_DIR)/include
AMGX_LIB = -L$(CUDA_HOME)/lib64 -lcusparse -lcusolver -lcublas -lnvToolsExt -L$(AMGX_DIR)/lib -lamgx -Xlinker=-rpath=$(CUDA_HOME)/lib64
# If YES, enable some informational messages
VERBOSE = NO
+7 -50
View File
@@ -78,14 +78,6 @@ groups_parallel=(
"miniapps/electromagnetics"
"joule.cpp"'
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
'"convergence"
"Convergence tests:"
"tests/convergence"
"diffusion.cpp"'
'"par-mesh-format"
"Parallel mesh tests:"
"tests/par-mesh-format"
"ex1p.cpp"'
)
# All groups serial + parallel runs mixed in the same group:
groups_all=(
@@ -115,14 +107,6 @@ groups_all=(
"miniapps/electromagnetics"
"joule.cpp"'
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
'"convergence"
"Convergence tests:"
"tests/convergence"
"diffusion.cpp"'
'"par-mesh-format"
"Parallel mesh tests:"
"tests/par-mesh-format"
"ex1p.cpp"'
)
make_all="all"
base_timeformat=$'real: %3Rs user: %3Us sys: %3Ss %%cpu: %P'
@@ -396,15 +380,10 @@ function timed_run()
# This function is used to execute the sample runs
function go()
{
# Strip leading and trailing spaces from $1 and store the result in cmd_line
shopt -s extglob
local cmd_line="${1##+( )}"
cmd_line="${cmd_line%%+( )}"
shopt -u extglob
eval local cmd=(${cmd_line})
local cmd=("$@")
local res=""
echo $sep
echo "<${group}>" "${cmd_line}"
echo "<${group}>" "${cmd[@]}"
echo $sep
if [ "${timing}" == "yes" ]; then
timed_run "${cmd[@]}"
@@ -416,15 +395,15 @@ function go()
else
res="${red}FAILED${none}"
fi
printf "[${res}] <${group}> ${cmd_line}\n"
printf "[${res}] <${group}> ${cmd[*]}\n"
if [ "${timing}" == "yes" ]; then
printf "Run time: %s\n" "${timer}"
timer=(${timer})
timer="${timer[1]}"
printf -v line "[$res](%8s) ${cmd_line}" "$timer"
printf -v line "[$res](%8s) ${cmd[*]}" "$timer"
summary=("${summary[@]}" "$line")
else
summary=("${summary[@]}" "[${res}] ${cmd_line}")
summary=("${summary[@]}" "[${res}] ${cmd[*]}")
fi
echo $sep
}
@@ -459,7 +438,7 @@ function go_group()
fi
for run in "${runs[@]}"; do
if [ "${run}" == "" ]; then continue; fi
eval go \"\${run_prefix} \${run} \${run_suffix}\" $output
eval go \${run_prefix} \${run} \${run_suffix} $output
done
done
${make} clean-exec
@@ -525,7 +504,7 @@ function echo_run()
{
echo " $@"
{ echo " $@"; echo "$sep";
eval "$@"
"$@"
echo "$sep"; } >> "$echo_log" 2>&1
}
@@ -545,28 +524,6 @@ function build_all()
echo_run ${make} config ${mfem_config} || exit 1
echo_run ${make} ${make_j} || exit 1
echo_run ${make} ${make_all} ${make_j} || exit 1
# Build groups in directories other than the directories built by 'make all':
for group_params in "${groups[@]}"; do
eval params=(${group_params})
group_dir="${params[2]}"
case "$group_dir" in
(examples*|miniapps*)
# Built by 'make all'
;;
(*)
if [ "${mfem_dir}" != "${mfem_build_dir}" ]; then
echo_run mkdir -p "${group_dir}" || exit 1
echo_run cd "${group_dir}" || exit 1
echo_run cp -af "${mfem_dir}/${group_dir}/makefile" . || exit 1
else
echo_run cd "${group_dir}" || exit 1
fi
echo_run ${make} clean || exit 1
echo_run ${make} MFEM_DIR="${mfem_dir}" ${make_j} || exit 1
echo_run cd "${mfem_build_dir}" || exit 1
;;
esac
done
}
# Function that runs all sample runs, given by the array variable "groups".
+8 -57
View File
@@ -1,38 +1,13 @@
SetFactory("OpenCASCADE");
// Select periodic mesh by setting this to either 0 - standard, 1 - periodic
periodic = 1;
// Set the geometry order (1, 2, ..., 9)
order = 3;
// Set the element type (3 - triangles, 4 - quadrilaterals)
type = 3;
// Number of radial elements
nrad = 2;
// Number of azimuthal elements on inner arc
nazm1 = 3;
// Number of azimuthal elements on outer arc
nazm2 = 5;
// Note: Using type = 4 with nazm1 != nazm2 can lead to mixed meshes
// containing both triangles and quadrilaterals.
// Inner and outer radii
R1 = 1.0;
R2 = 2.0;
// Angular size of the sector
Phi = Pi/3.0;
Point(1) = {0.0, 0, 0, 1.0};
Point(2) = {R1, 0, 0, 1.0};
Point(3) = {R2, 0, 0, 1.0};
Point(4) = {R1*Cos(Phi), R1*Sin(Phi), 0, 1.0};
Point(5) = {R2*Cos(Phi), R2*Sin(Phi), 0, 1.0};
Point(4) = {R1*Cos(Pi/3), R1*Sin(Pi/3), 0, 1.0};
Point(5) = {R2*Cos(Pi/3), R2*Sin(Pi/3), 0, 1.0};
Line(1) = {2, 3};
Line(2) = {4, 5};
Circle(3) = {2, 1, 4};
@@ -40,23 +15,13 @@ Circle(4) = {3, 1, 5};
Curve Loop(5) = {1, 4, -2, -3};
Plane Surface(1) = {5};
Transfinite Curve{1} = nrad+1;
Transfinite Curve{2} = nrad+1;
Transfinite Curve{3} = nazm1+1;
Transfinite Curve{4} = nazm2+1;
If (nazm1 == nazm2)
Transfinite Surface{1};
EndIf
If (type == 4)
Recombine Surface {1};
EndIf
Transfinite Curve{1} = 7;
Transfinite Curve{2} = 7;
Transfinite Curve{3} = 4;
Transfinite Curve{4} = 10;
// Set a rotation periodicity constraint:
If (periodic)
Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Phi};
EndIf
Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Pi/3};
// Tag surfaces and volumes with positive integers
Physical Curve(1) = {3};
@@ -65,22 +30,8 @@ Physical Curve(3) = {1};
Physical Curve(4) = {2};
Physical Surface(1) = {1};
// Optimize the high-order mesh
// See https://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eHighOrderOptimize
// Mesh.ElementOrder = order;
// Mesh.HighOrderOptimize = 1;
// Generate 2D mesh
Mesh 2;
SetOrder order;
Mesh.MshFileVersion = 2.2;
// Check the element quality (the Plugin may be called AnalyseCurvedMesh)
// Plugin(AnalyseMeshQuality).JacobianDeterminant = 1;
// Plugin(AnalyseMeshQuality).Run;
If (periodic)
Save Sprintf("periodic-annulus-sector-t%01g-o%01g.msh", type, order);
Else
Save Sprintf("annulus-sector-t%01g-o%01g.msh", type, order);
EndIf
Save "periodic-annulus-sector.msh";
+161 -168
View File
@@ -2,191 +2,184 @@ $MeshFormat
2.2 0 8
$EndMeshFormat
$Nodes
136
55
1 1 0 0
2 2 0 0
3 0.5000000000000001 0.8660254037844386 0
4 1 1.732050807568877 0
5 1.5 0 0
6 1.166666666666667 0 0
7 1.333333333333333 0 0
5 1.166666666666667 0 0
6 1.333333333333333 0 0
7 1.5 0 0
8 1.666666666666667 0 0
9 1.833333333333333 0 0
10 0.7500000000000002 1.299038105676658 0
11 0.5833333333333335 1.010362971081845 0
12 0.6666666666666667 1.154700538379251 0
10 0.5833333333333335 1.010362971081845 0
11 0.6666666666666667 1.154700538379251 0
12 0.7500000000000002 1.299038105676658 0
13 0.8333333333333335 1.443375672974064 0
14 0.9166666666666669 1.587713240271471 0
15 0.9396926207859085 0.3420201433256683 0
16 0.7660444431189786 0.6427876096865386 0
17 0.993238357741943 0.1160929141252301 0
18 0.9730448705798238 0.2306158707424401 0
19 0.8936326403234125 0.4487991802004617 0
20 0.8354878114129367 0.5495089780708056 0
21 0.6862416378687343 0.7273736415730481 0
22 0.597158591702787 0.8021231927550432 0
23 1.956295201467611 0.4158233816355181 0
24 1.827090915285202 0.8134732861515996 0
25 1.618033988749896 1.175570504584944 0
26 1.338261212717719 1.486289650954786 0
27 1.995128100519648 0.1395129474882505 0
28 1.980536137483141 0.278346201920131 0
29 1.922523391876638 0.551274711633998 0
30 1.879385241571817 0.6840402866513373 0
31 1.765895185717855 0.9389431255717802 0
32 1.696096192312853 1.059838528466408 0
33 1.532088886237958 1.285575219373077 0
34 1.438679600677305 1.389316740917992 0
35 1.231322950651319 1.576021507213442 0
36 1.118385806941496 1.658075145110082 0
37 1.162276263405681 0.6710405135499813 0
38 1.248615852873337 1.079531485311822 0
39 1.559209616901855 0.5415673055003691 0
40 1.478306597054007 0.8535007117539289 0
41 0.9210953433941653 0.9653302893212266 0
42 1.296548225291847 0.3150268220262836 0
43 1.055002035226811 1.358510675893086 0
44 1.704005774249187 0.2344032256041583 0
45 0.6403651144647218 0.8991270322967013 0
46 0.7807302289294435 0.9322286608089638 0
47 0.864063562262777 1.07656622810637 0
48 0.8070317811313885 1.187802166891514 0
49 0.7236984477980553 1.043464599594108 0
50 1.432182741763949 0.1050089406754279 0
51 1.364365483527898 0.2100178813508558 0
52 1.197698816861231 0.2100178813508558 0
53 1.098849408430616 0.1050089406754279 0
54 1.265516075097282 0.1050089406754278 0
55 0.8177280765440409 0.7503018362314346 0
56 0.869411709969103 0.8578160627763305 0
57 0.7348318576552288 0.8316090412164392 0
58 1.177596357123201 0.3240245957927452 0
59 1.058644488954555 0.3330223695592067 0
60 1.087610484537871 0.2205785356313179 0
61 1.267619707955123 0.7318605796179638 0
62 1.372963152504565 0.7926806456859463 0
63 1.40174301566045 0.9288443029398934 0
64 1.325179434266893 1.004187894125858 0
65 1.219835989717452 0.9433678280578752 0
66 1.191056126561566 0.8072041708039283 0
67 1.296399571111008 0.8680242368719107 0
68 1.532241943619239 0.645545107584889 0
69 1.505274270336623 0.7495229096694089 0
70 1.294587381237739 0.6278827775334439 0
71 1.426898499069797 0.5847250415169065 0
72 1.399930825787181 0.6887028436014264 0
73 1.139442349713613 1.041464419981624 0
74 1.030268846553889 1.003397354651425 0
75 1.001488983398004 0.8672336973974781 0
76 1.081882623401843 0.7691371054737297 0
77 1.110662486557728 0.9053007627276766 0
78 1.207033584034403 0.5523692830420821 0
79 1.251790904663125 0.4336980525341829 0
80 1.384102022495183 0.3905403165176455 0
81 1.471655819698519 0.4660538110090073 0
82 1.339344701866461 0.5092115470255447 0
83 1.73779714915742 0.7228379592678562 0
84 1.648503383029637 0.6322026323841127 0
85 1.691571478423774 0.4996526642120855 0
86 1.823933339945692 0.4577380229238018 0
87 1.787039416783436 0.5922941012619014 0
88 1.308379426102925 1.350703595740465 0
89 1.278497639488131 1.215117540526144 0
90 1.371755231498856 1.111544491736196 0
91 1.494894610124376 1.14355749816057 0
92 1.4064614465962 1.25147448186763 0
93 1.013887168325833 0.451693600067106 0
94 1.088081715865757 0.5613670568085436 0
95 1.03019898997678 0.6616228789288338 0
96 0.8981217165478794 0.6522052443076862 0
97 0.9637989050473432 0.5564495572737495 0
98 1.432367408277627 0.2881522898855752 0
99 1.568186591263407 0.2612777577448668 0
100 1.655740388466743 0.3367912522362286 0
101 1.607475002684299 0.4391792788682989 0
102 1.519921205480963 0.3636657843769371 0
103 1.184077913657828 1.17252454883891 0
104 1.119539974442319 1.265517612365998 0
105 1.010366471282595 1.2274505470358 0
106 0.9657309073383804 1.096390418178513 0
107 1.074904410498104 1.134457483508712 0
108 1.901335258083062 0.07813440853471942 0
109 1.802670516166124 0.1562688170694388 0
110 1.636003849499458 0.156268817069439 0
111 1.568001924749729 0.07813440853471942 0
112 1.734668591416396 0.07813440853471944 0
113 0.8516673450756037 1.318862295748801 0
114 0.9533346901512071 1.338686485820944 0
115 1.03666802348454 1.48302405311835 0
116 1.01833401174227 1.607537430343614 0
117 0.9350006784089369 1.463199863046207 0
118 1.710829475874804 0.8268157613523761 0
119 1.594568036464405 0.8401582365531526 0
120 1.621535709747021 0.7361804344686326 0
121 1.52488239428597 0.9608573093642675 0
122 1.571458191517933 1.068213906974606 0
123 1.448318812892413 1.036200900550232 0
124 0.908699126206992 1.207626356963657 0
125 1.500184666513678 0.1831433492101474 0
126 1.646765991694905 0.9507607885973723 0
127 0.9498053499729417 0.7597194708525821 0
128 1.132839036494479 0.4426958263006443 0
129 1.149421761057113 1.40110366758032 0
130 1.243841486887416 1.443696659267553 0
131 1.134903597606542 1.530869109405537 0
132 1.872198725728137 0.3553499962917315 0
133 1.788102249988661 0.2948766109479449 0
134 1.893223337417325 0.2174207916708467 0
135 1.213959700272622 1.308110604053232 0
136 1.739836864206217 0.3972646375800152 0
17 1.986476715483886 0.2321858282504602 0
18 1.946089741159648 0.4612317414848793 0
19 1.879385241571817 0.6840402866513365 0
20 1.787265280646825 0.8975983604009234 0
21 1.670975622825874 1.09901795614161 0
22 1.532088886237958 1.285575219373077 0
23 1.372483275737469 1.454747283146095 0
24 1.194317183405575 1.604246385510085 0
25 1.425989114816062 0.1915326920916892 0
26 0.8788667344146573 1.13917645290495 0
27 1.630372059110754 0.7154531062316609 0
28 1.436395769298814 1.053728612482506 0
29 1.081023776188756 0.6241293681829633 0
30 1.168737372335971 1.428012728596308 0
31 1.821063986059922 0.298149890497067 0
32 1.234707097211386 0.3469796339295647 0
33 1.377747393186519 0.6200150626754309 0
34 1.457047681210906 0.3890895843559762 0
35 0.917846726184522 0.8957978954532204 0
36 1.218335619030348 0.9017812086952638 0
37 1.066623110765233 1.061857005744772 0
38 1.587029716281926 0.1355955181472859 0
39 1.744445799211916 0.1441515753740107 0
40 1.25 0.1443375672974065 0
41 1.453660070628011 0.8435769396609902 0
42 1.741367044061892 0.499612708014486 0
43 1.30550638526547 1.257610469847477 0
44 1.118213276932792 0.1666674689105279 0
45 0.9109440214958271 1.306610291787315 0
46 0.9970618258753989 1.438658589955562 0
47 0.7499999999999998 1.010362971081845 0
48 0.7034449005273667 0.8850673702175776 0
49 1.605449512513618 0.9269067082200894 0
50 1.561654019115059 0.5298592532912715 0
51 1.229782222487711 1.096820457143683 0
52 1.617066998712459 0.3090202662210922 0
53 1.079645953234324 1.246963713711438 0
54 1.877063966817811 0.1348974588243076 0
55 1.055356609656722 1.558136350380461 0
$EndNodes
$Elements
38
1 26 2 3 1 1 5 6 7
2 26 2 3 1 5 2 8 9
3 26 2 4 2 3 10 11 12
4 26 2 4 2 10 4 13 14
5 26 2 1 3 1 15 17 18
6 26 2 1 3 15 16 19 20
7 26 2 1 3 16 3 21 22
8 26 2 2 4 2 23 27 28
9 26 2 2 4 23 24 29 30
10 26 2 2 4 24 25 31 32
11 26 2 2 4 25 26 33 34
12 26 2 2 4 26 4 35 36
13 21 2 1 1 3 41 10 45 46 47 48 12 11 49
14 21 2 1 1 5 42 1 50 51 52 53 6 7 54
15 21 2 1 1 16 41 3 55 56 46 45 22 21 57
16 21 2 1 1 1 42 15 53 52 58 59 18 17 60
17 21 2 1 1 37 40 38 61 62 63 64 65 66 67
18 21 2 1 1 39 40 37 68 69 62 61 70 71 72
19 21 2 1 1 38 41 37 73 74 75 76 66 65 77
20 21 2 1 1 37 42 39 78 79 80 81 71 70 82
21 21 2 1 1 24 39 23 83 84 85 86 29 30 87
22 21 2 1 1 26 38 25 88 89 90 91 33 34 92
23 21 2 1 1 15 37 16 93 94 95 96 20 19 97
24 21 2 1 1 42 44 39 98 99 100 101 81 80 102
25 21 2 1 1 38 43 41 103 104 105 106 74 73 107
26 21 2 1 1 2 44 5 108 109 110 111 8 9 112
27 21 2 1 1 10 43 4 113 114 115 116 14 13 117
28 21 2 1 1 24 40 39 118 119 69 68 84 83 120
29 21 2 1 1 38 40 25 64 63 121 122 91 90 123
30 21 2 1 1 41 43 10 106 105 114 113 48 47 124
31 21 2 1 1 5 44 42 111 110 99 98 51 50 125
32 21 2 1 1 25 40 24 122 121 119 118 31 32 126
33 21 2 1 1 37 41 16 76 75 56 55 96 95 127
34 21 2 1 1 15 42 37 59 58 79 78 94 93 128
35 21 2 1 1 4 43 26 116 115 129 130 35 36 131
36 21 2 1 1 23 44 2 132 133 109 108 27 28 134
37 21 2 1 1 26 43 38 130 129 104 103 89 88 135
38 21 2 1 1 39 44 23 101 100 133 132 86 85 136
108
1 1 2 3 1 1 5
2 1 2 3 1 5 6
3 1 2 3 1 6 7
4 1 2 3 1 7 8
5 1 2 3 1 8 9
6 1 2 3 1 9 2
7 1 2 4 2 3 10
8 1 2 4 2 10 11
9 1 2 4 2 11 12
10 1 2 4 2 12 13
11 1 2 4 2 13 14
12 1 2 4 2 14 4
13 1 2 1 3 1 15
14 1 2 1 3 15 16
15 1 2 1 3 16 3
16 1 2 2 4 2 17
17 1 2 2 4 17 18
18 1 2 2 4 18 19
19 1 2 2 4 19 20
20 1 2 2 4 20 21
21 1 2 2 4 21 22
22 1 2 2 4 22 23
23 1 2 2 4 23 24
24 1 2 2 4 24 4
25 2 2 1 1 32 40 25
26 2 2 1 1 25 34 32
27 2 2 1 1 33 41 36
28 2 2 1 1 38 52 25
29 2 2 1 1 33 36 29
30 2 2 1 1 26 47 35
31 2 2 1 1 35 37 26
32 2 2 1 1 25 52 34
33 2 2 1 1 32 44 40
34 2 2 1 1 15 32 29
35 2 2 1 1 15 29 16
36 2 2 1 1 36 41 28
37 2 2 1 1 32 33 29
38 2 2 1 1 50 52 42
39 2 2 1 1 32 34 33
40 2 2 1 1 42 52 31
41 2 2 1 1 43 53 51
42 2 2 1 1 27 41 33
43 2 2 1 1 26 53 45
44 2 2 1 1 18 31 17
45 2 2 1 1 29 35 16
46 2 2 1 1 29 36 35
47 2 2 1 1 24 30 23
48 2 2 1 1 30 53 43
49 2 2 1 1 17 54 2
50 2 2 1 1 4 55 24
51 2 2 1 1 28 51 36
52 2 2 1 1 47 48 35
53 2 2 1 1 36 37 35
54 2 2 1 1 37 53 26
55 2 2 1 1 22 28 21
56 2 2 1 1 20 27 19
57 2 2 1 1 33 50 27
58 2 2 1 1 15 44 32
59 2 2 1 1 18 42 31
60 2 2 1 1 30 43 23
61 2 2 1 1 35 48 16
62 2 2 1 1 31 54 17
63 2 2 1 1 9 39 8
64 2 2 1 1 8 38 7
65 2 2 1 1 7 25 6
66 2 2 1 1 22 43 28
67 2 2 1 1 23 43 22
68 2 2 1 1 39 54 31
69 2 2 1 1 19 42 18
70 2 2 1 1 24 55 30
71 2 2 1 1 27 42 19
72 2 2 1 1 13 46 14
73 2 2 1 1 51 53 37
74 2 2 1 1 39 52 38
75 2 2 1 1 6 40 5
76 2 2 1 1 34 52 50
77 2 2 1 1 12 45 13
78 2 2 1 1 30 55 46
79 2 2 1 1 10 47 11
80 2 2 1 1 8 39 38
81 2 2 1 1 28 49 21
82 2 2 1 1 7 38 25
83 2 2 1 1 41 49 28
84 2 2 1 1 20 49 27
85 2 2 1 1 11 26 12
86 2 2 1 1 27 49 41
87 2 2 1 1 31 52 39
88 2 2 1 1 25 40 6
89 2 2 1 1 2 54 9
90 2 2 1 1 14 55 4
91 2 2 1 1 45 53 46
92 2 2 1 1 45 46 13
93 2 2 1 1 5 44 1
94 2 2 1 1 21 49 20
95 2 2 1 1 46 53 30
96 2 2 1 1 3 48 10
97 2 2 1 1 34 50 33
98 2 2 1 1 36 51 37
99 2 2 1 1 26 45 12
100 2 2 1 1 11 47 26
101 2 2 1 1 27 50 42
102 2 2 1 1 40 44 5
103 2 2 1 1 43 51 28
104 2 2 1 1 10 48 47
105 2 2 1 1 9 54 39
106 2 2 1 1 46 55 14
107 2 2 1 1 1 44 15
108 2 2 1 1 16 48 3
$EndElements
$Periodic
1
1 1 2
Affine 0.5000000000000001 0.8660254037844386 0 0 -0.8660254037844386 0.5000000000000001 0 0 0 0 1 0 0 0 0 1
3
7
9 14
6 11
8 13
5 10
1 3
7 12
2 4
1 3
$EndPeriodic
+13 -129
View File
@@ -1,141 +1,25 @@
// Select periodic mesh by setting this to either 0 - standard, 1 - periodic
periodic = 1;
SetFactory("OpenCASCADE");
// Set the geometry order (1, 2, ..., 10 for tetrahedra or 9 for other types)
order = 3;
R = 1.5;
r = 0.5;
// Set the element type (4 - tetrahedra, 6 - wedges, 8 - hexahedra)
type = 8;
Torus(1) = {0,0,0, R, r, Pi/3};
// Minor and major radii
R1 = 1.0;
R2 = 2.0;
pts() = PointsOf{ Volume{1}; };
// Side length of interior square
A1 = 0.8;
// Angular size of the sector
Phi = Pi/3.0;
// Number of azimuthal elements
nazm = 3;
// Number of elements around a quarter of the circle
narc = 2;
// Number of elements between surface and interior square
nshl = 1;
lc = 0.5;
a1 = A1 / Sqrt(2.0);
Point(1) = {R2+R1, 0, 0, lc};
Point(2) = {R2, 0, R1, lc};
Point(3) = {R2-R1, 0, 0, lc};
Point(4) = {R2, 0, -R1, lc};
Point(5) = {R2, 0, 0, lc};
Point(6) = {R2+a1, 0, 0, lc};
Point(7) = {R2, 0, a1, lc};
Point(8) = {R2-a1, 0, 0, lc};
Point(9) = {R2, 0, -a1, lc};
Circle(1) = {1,5,2};
Circle(2) = {2,5,3};
Circle(3) = {3,5,4};
Circle(4) = {4,5,1};
Line(5) = {6,1};
Line(6) = {7,2};
Line(7) = {8,3};
Line(8) = {9,4};
Line(9) = {6, 7};
Line(10) = {7, 8};
Line(11) = {8, 9};
Line(12) = {9, 6};
Line Loop(101) = {1, -6, -9, 5};
Line Loop(102) = {2, -7, -10, 6};
Line Loop(103) = {3, -8, -11, 7};
Line Loop(104) = {4, -5, -12, 8};
Line Loop(105) = {9, 10, 11, 12};
Plane Surface(201) = {101};
Plane Surface(202) = {102};
Plane Surface(203) = {103};
Plane Surface(204) = {104};
Plane Surface(205) = {105};
Transfinite Curve{1} = narc+1;
Transfinite Curve{2} = narc+1;
Transfinite Curve{3} = narc+1;
Transfinite Curve{4} = narc+1;
Transfinite Curve{5} = nshl+1;
Transfinite Curve{6} = nshl+1;
Transfinite Curve{7} = nshl+1;
Transfinite Curve{8} = nshl+1;
Transfinite Curve{9} = narc+1;
Transfinite Curve{10} = narc+1;
Transfinite Curve{11} = narc+1;
Transfinite Curve{12} = narc+1;
If (type == 8)
Recombine Surface {201};
Recombine Surface {202};
Recombine Surface {203};
Recombine Surface {204};
Recombine Surface {205};
Transfinite Surface {201} = {1,2,7,6};
Transfinite Surface {202} = {2,3,8,7};
Transfinite Surface {203} = {3,4,9,8};
Transfinite Surface {204} = {4,1,6,9};
Transfinite Surface {205} = {6,7,8,9};
EndIf
If (type == 4)
Extrude { {0,0,1} , {0,0,0} , Phi} {
Surface{201,202,203,204,205}; Layers{nazm};
}
Else
Extrude { {0,0,1} , {0,0,0} , Phi} {
Surface{201,202,203,204,205}; Layers{nazm}; Recombine;
}
EndIf
Characteristic Length{ pts() } = 0.25;
// Set a rotation periodicity constraint:
If (periodic)
Periodic Surface{227} = {201} Rotate{{0,0,1}, {0,0,0}, Phi};
Periodic Surface{249} = {202} Rotate{{0,0,1}, {0,0,0}, Phi};
Periodic Surface{271} = {203} Rotate{{0,0,1}, {0,0,0}, Phi};
Periodic Surface{293} = {204} Rotate{{0,0,1}, {0,0,0}, Phi};
Periodic Surface{315} = {205} Rotate{{0,0,1}, {0,0,0}, Phi};
EndIf
Periodic Surface{3} = {2} Rotate{{0,0,1}, {0,0,0}, Pi/3};
// Tag surfaces and volumes with positive integers
Physical Surface(1) = {201,202,203,204,205};
Physical Surface(2) = {227,249,271,293,315};
Physical Surface(3) = {214,236,258,280};
Physical Volume(1) = {1,2,3,4,5};
// Optimize the high-order mesh
// See https://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eHighOrderOptimize
// Mesh.ElementOrder = order;
// Mesh.HighOrderOptimize = 1;
Physical Surface(1) = {1};
Physical Surface(2) = {2};
Physical Surface(3) = {3};
Physical Volume(1) = {1};
// Generate 3D mesh
Mesh 3;
SetOrder order;
Mesh.MshFileVersion = 2.2;
// Check the element quality (the Plugin may be called AnalyseCurvedMesh)
// Plugin(AnalyseMeshQuality).JacobianDeterminant = 1;
// Plugin(AnalyseMeshQuality).Run;
If (periodic)
Save Sprintf("periodic-torus-sector-t%01g-o%01g.msh", type, order);
Else
Save Sprintf("torus-sector-t%01g-o%01g.msh", type, order);
EndIf
Save "periodic-torus-sector.msh";
File diff suppressed because it is too large Load Diff
-118
View File
@@ -1,118 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
2
elements
20
1 3 0 1 6 5
1 3 1 2 7 6
1 3 2 3 8 7
1 3 3 4 9 8
1 3 5 6 11 10
1 2 6 7 11
1 2 7 12 11
1 2 7 8 13
1 2 7 13 12
1 3 8 9 14 13
1 3 10 11 16 15
1 2 11 12 17
1 2 11 17 16
1 2 12 13 17
1 2 13 18 17
1 3 13 14 19 18
1 3 15 16 21 20
1 3 16 17 22 21
1 3 17 18 23 22
1 3 18 19 24 23
boundary
16
2 1 0 1
2 1 1 2
2 1 2 3
2 1 3 4
2 1 21 20
2 1 22 21
2 1 23 22
2 1 24 23
1 1 5 0
1 1 10 5
1 1 15 10
1 1 20 15
1 1 4 9
1 1 9 14
1 1 14 19
1 1 19 24
vertices
25
nodes
FiniteElementSpace
FiniteElementCollection: H1_2D_P1
VDim: 2
Ordering: 0
0
0.25
0.5
0.75
1
0
0.25
0.5
0.75
1
0
0.25
0.5
0.75
1
0
0.25
0.5
0.75
1
0
0.25
0.5
0.75
1
0
0
0
0
0
0.25
0.25
0.25
0.25
0.25
0.5
0.5
0.5
0.5
0.5
0.75
0.75
0.75
0.75
0.75
1
1
1
1
1
+2 -3
View File
@@ -144,12 +144,12 @@ namespace mfem {
* - <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
* - <a class="el" href="minimal-surface_8cpp_source.html">Minimal Surface</a>: compute minimal surfaces, <a class="el" href="minimal-surface_8cpp_source.html">serial</a> and <a class="el" href="pminimal-surface_8cpp_source.html">parallel</a> versions
* - <a class="el" href="polar-nc_8cpp_source.html">Polar NC</a>: generate polar non-conforming meshes
* - <a class="el" href="shaper_8cpp_source.html">Shaper</a>: resolve material interfaces by mesh refinement
* - <a class="el" href="extruder_8cpp_source.html">Extruder</a>: extrude a low-dimensional mesh into a higher dimension
* - <a class="el" href="mesh-explorer_8cpp_source.html">Mesh Explorer</a>: visualize and manipulate meshes
@@ -162,7 +162,6 @@ namespace mfem {
* - <a class="el" href="lor-transfer_8cpp_source.html">LOR Transfer</a>: map functions between high-order and low-order refined spaces
* - <a class="el" href="findpts_8cpp_source.html">Find Points</a>: evaluate grid function in physical space, <a class="el" href="findpts_8cpp_source.html">serial</a> and <a class="el" href="pfindpts_8cpp_source.html">parallel</a> versions
* - <a class="el" href="field-diff_8cpp_source.html">Field Diff</a>: compare grid functions on different meshes
* - <a class="el" href="field-interp_8cpp_source.html">Field Interp</a>: transfer a grid functions betwen meshes
* - <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
*
+1 -1
View File
@@ -19,7 +19,7 @@ html: $(DOXYGEN_CONF)
@# Generate the html documentation
@doxygen $(DOXYGEN_CONF)
@echo "<meta http-equiv=\"REFRESH\" content=\"0;URL=CodeDocumentation/html/index.html\">" > CodeDocumentation.html
@cat warnings.log 1>&2
@cat warnings.log
@# Generate the log of undocumented methods
@( cat $(DOXYGEN_CONF) ; echo "GENERATE_HTML=NO" ; echo "EXTRACT_ALL=NO" ; echo "WARN_LOGFILE=undoc.log" ; echo "QUIET=YES" ) | doxygen - &> /dev/null
-38
View File
@@ -1,38 +0,0 @@
{
"config_version": 2,
"solver": {
"preconditioner": {
"print_grid_stats": 1,
"print_vis_data": 0,
"solver": "AMG",
"smoother": {
"scope": "jacobi",
"solver": "BLOCK_JACOBI",
"relaxation_factor": 0.7,
"monitor_residual": 0,
"print_solve_stats": 0
},
"print_solve_stats": 0,
"presweeps": 1,
"interpolator": "D2",
"max_row_sum" : 0.9,
"strength_threshold" : 0.25,
"max_iters": 1,
"monitor_residual": 0,
"store_res_history": 0,
"scope": "amg",
"max_levels": 100,
"cycle": "V",
"postsweeps": 1
},
"solver": "PCG",
"print_solve_stats": 1,
"obtain_timings": 1,
"max_iters": 100,
"monitor_residual": 1,
"convergence": "RELATIVE_MAX",
"scope": "main",
"tolerance": 1e-12,
"norm": "L2"
}
}
-271
View File
@@ -1,271 +0,0 @@
// MFEM Example 1
//
// Compile with: make ex1
//
// Sample runs: ex1 -m ../../data/square-disc.mesh
// ex1 -m ../../data/star.mesh
// ex1 -m ../../data/star-mixed.mesh
// ex1 -m ../../data/escher.mesh
// ex1 -m ../../data/fichera.mesh
// ex1 -m ../../data/fichera-mixed.mesh
// ex1 -m ../../data/toroid-wedge.mesh
// ex1 -m ../../data/periodic-annulus-sector.msh
// ex1 -m ../../data/periodic-torus-sector.msh
// ex1 -m ../../data/square-disc-p2.vtk -o 2
// ex1 -m ../../data/square-disc-p3.mesh -o 3
// ex1 -m ../../data/square-disc-nurbs.mesh -o -1
// ex1 -m ../../data/star-mixed-p2.mesh -o 2
// ex1 -m ../../data/disc-nurbs.mesh -o -1
// ex1 -m ../../data/pipe-nurbs.mesh -o -1
// ex1 -m ../../data/fichera-mixed-p2.mesh -o 2
// ex1 -m ../../data/star-surf.mesh
// ex1 -m ../../data/square-disc-surf.mesh
// ex1 -m ../../data/inline-segment.mesh
// ex1 -m ../../data/amr-quad.mesh
// ex1 -m ../../data/amr-hex.mesh
// ex1 -m ../../data/fichera-amr.mesh
// ex1 -m ../../data/mobius-strip.mesh
// ex1 -m ../../data/mobius-strip.mesh -o -1 -sc
//
// Device sample runs:
// ex1 -pa -d cuda
// ex1 -pa -d raja-cuda
// ex1 -pa -d occa-cuda
// ex1 -pa -d raja-omp
// ex1 -pa -d occa-omp
// ex1 -pa -d ceed-cpu
// * ex1 -pa -d ceed-cuda
// ex1 -pa -d ceed-cuda:/gpu/cuda/shared
// ex1 -m ../../data/beam-hex.mesh -pa -d cuda
// ex1 -m ../../data/beam-tet.mesh -pa -d ceed-cpu
// ex1 -m ../../data/beam-tet.mesh -pa -d ceed-cuda:/gpu/cuda/ref
//
// AmgX sample runs:
// ./ex1 --amgx-file multi_gs.json --amgx-solver
// ./ex1 --amgx-file precon.json --amgx-preconditioner
// ./ex1 --amgx-file multi_gs.json --amgx-solver -d cuda
// ./ex1 --amgx-file precon.json --amgx-preconditioner -d cuda
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/star.mesh";
int order = 1;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
bool amgx_solver = true;
const char* amgx_json_file = ""; // jason file for amgx
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&amgx_json_file, "--amgx-file", "--amgx-file",
"AMGX solver config file (overrides --amgx-solver, --amgx-verbose)");
args.AddOption(&amgx_solver, "--amgx-solver", "--amgx-solver",
"--amgx-preconditioner",
"--amgx-preconditioner",
"Configure AMGX as solver or preconditioner.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
MFEM_VERIFY(!pa && strcmp(amgx_json_file,"") != 0,
"An AmgX json file is needed for this example \n");
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 50,000
// elements.
{
int ref_levels =
(int)floor(log(50000./mesh.GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
}
// 5. Define a finite element space on the mesh. Here we use continuous
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
bool delete_fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
delete_fec = true;
}
else if (mesh.GetNodes())
{
fec = mesh.GetNodes()->OwnFEC();
delete_fec = false;
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
fec = new H1_FECollection(order = 1, dim);
delete_fec = true;
}
FiniteElementSpace fespace(&mesh, fec);
cout << "Number of finite element unknowns: "
<< 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())
{
Array<int> ess_bdr(mesh.bdr_attributes.Max());
ess_bdr = 1;
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);
ConstantCoefficient one(1.0);
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);
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));
// 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();
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
cout << "Size of linear system: " << A->Height() << endl;
// 11. Solve the linear system A X = B.
if (!pa)
{
AmgXSolver amgx;
amgx.ReadParameters(amgx_json_file, AmgXSolver::EXTERNAL);
amgx.InitSerial();
amgx.SetOperator(*A.As<SparseMatrix>());
if (amgx_solver)
{
amgx.Mult(B,X);
}
else
{
PCG(*A.As<SparseMatrix>(), amgx, B, X, 3, 40, 1e-12, 0.0);
}
}
else // Jacobi preconditioning in partial assembly mode
{
if (UsesTensorBasis(fespace))
{
OperatorJacobiSmoother M(a, ess_tdof_list);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
else
{
CG(*A, B, X, 1, 400, 1e-12, 0.0);
}
}
// 12. Recover the solution as a finite element grid function.
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);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
// 14. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << mesh << x << flush;
}
// 15. Free the used memory.
if (delete_fec)
{
delete fec;
}
return 0;
}
-322
View File
@@ -1,322 +0,0 @@
// MFEM Example 1 - Parallel Version
//
// Compile with: make ex1p
//
// Sample runs: mpirun -np 4 ex1p -m ../../data/square-disc.mesh
// mpirun -np 4 ex1p -m ../../data/star.mesh
// mpirun -np 4 ex1p -m ../../data/star-mixed.mesh
// mpirun -np 4 ex1p -m ../../data/escher.mesh
// mpirun -np 4 ex1p -m ../../data/fichera.mesh
// mpirun -np 4 ex1p -m ../../data/fichera-mixed.mesh
// mpirun -np 4 ex1p -m ../../data/toroid-wedge.mesh
// mpirun -np 4 ex1p -m ../../data/periodic-annulus-sector.msh
// mpirun -np 4 ex1p -m ../../data/periodic-torus-sector.msh
// mpirun -np 4 ex1p -m ../../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex1p -m ../../data/square-disc-p3.mesh -o 3
// mpirun -np 4 ex1p -m ../../data/square-disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../../data/star-mixed-p2.mesh -o 2
// mpirun -np 4 ex1p -m ../../data/disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../../data/pipe-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../../data/ball-nurbs.mesh -o 2
// mpirun -np 4 ex1p -m ../../data/fichera-mixed-p2.mesh -o 2
// mpirun -np 4 ex1p -m ../../data/star-surf.mesh
// mpirun -np 4 ex1p -m ../../data/square-disc-surf.mesh
// mpirun -np 4 ex1p -m ../../data/inline-segment.mesh
// mpirun -np 4 ex1p -m ../../data/amr-quad.mesh
// mpirun -np 4 ex1p -m ../../data/amr-hex.mesh
// mpirun -np 4 ex1p -m ../../data/mobius-strip.mesh
// mpirun -np 4 ex1p -m ../../data/mobius-strip.mesh -o -1 -sc
//
// Device sample runs:
// mpirun -np 4 ex1p -pa -d cuda
// 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 -m ../../data/beam-tet.mesh -pa -d ceed-cpu
//
// AmgX sample runs:
//
// mpirun -n 40 ./ex1p --amgx-file amg_pcg.json
// lrun -n 4 ./ex1p --amgx-file amg_pcg.json --amgx-mpi-gpu-exclusive
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
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 order = 1;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
bool amgx_mpi_teams = true;
const char* amgx_json_file = ""; // jason file for amgx
int ndevices = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&amgx_json_file, "--amgx-file", "--amgx-file",
"AMGX solver config file (overrides --amgx-solver, --amgx-verbose)");
args.AddOption(&amgx_mpi_teams, "--amgx-mpi-teams", "--amgx-mpi-teams",
"--amgx-mpi-gpu-exclusive", "--amgx-mpi-gpu-exclusive",
"Create MPI teams when using AMGX.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&ndevices, "-nd","--nd","Number of GPU devices.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
MFEM_VERIFY(!pa == true && strcmp(amgx_json_file,"") != 0,
"An AmgX json file is needed for this example \n");
}
// 3. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
// 5. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 10,000 elements.
{
int ref_levels =
(int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
}
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
{
int par_ref_levels = 2;
for (int l = 0; l < par_ref_levels; l++)
{
pmesh.UniformRefinement();
}
}
// 7. 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;
bool delete_fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
delete_fec = true;
}
else if (pmesh.GetNodes())
{
fec = pmesh.GetNodes()->OwnFEC();
delete_fec = false;
if (myid == 0)
{
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
}
else
{
fec = new H1_FECollection(order = 1, dim);
delete_fec = true;
}
ParFiniteElementSpace fespace(&pmesh, fec);
HYPRE_Int size = fespace.GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 8. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
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);
ConstantCoefficient one(1.0);
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);
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));
// 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();
OperatorPtr A;
Vector B, X;
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.
// * With partial assembly, use Jacobi smoothing, for now.
Solver *prec = NULL;
if (!pa)
{
AmgXSolver amgx;
amgx.ReadParameters(amgx_json_file, AmgXSolver::EXTERNAL);
if (amgx_mpi_teams)
{
//Forms MPI teams to load balance between mpi ranks and gpus
amgx.InitMPITeams(MPI_COMM_WORLD, ndevices);
}
else
{
//Assumes MPI == number of devices
amgx.InitExclusiveGPU(MPI_COMM_WORLD);
}
amgx.SetOperator(*A.As<HypreParMatrix>());
amgx.Mult(B, X);
}
else
{
if (UsesTensorBasis(fespace))
{
prec = new OperatorJacobiSmoother(a, ess_tdof_list);
}
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
if (prec) { cg.SetPreconditioner(*prec); }
cg.SetOperator(*A);
cg.Mult(B, X);
delete prec;
}
// 14. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
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".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh.Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << x << flush;
}
// 17. Free the used memory.
if (delete_fec)
{
delete fec;
}
MPI_Finalize();
return 0;
}
-72
View File
@@ -1,72 +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.
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/amgx/,)
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_EXAMPLES = ex1
PAR_EXAMPLES = ex1p
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
else
EXAMPLES = $(PAR_EXAMPLES) $(SEQ_EXAMPLES)
endif
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all clean clean-build clean-exec
# Remove built-in rule
%: %.cpp
# Replace the default implicit rule for *.cpp files
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
all: $(EXAMPLES)
ifeq ($(MFEM_USE_AMGX),NO)
$(EXAMPLES):
$(error MFEM is not configured with AMGX)
endif
MFEM_TESTS = EXAMPLES
include $(MFEM_TEST_MK)
# Testing: Parallel vs. serial runs
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
SERIAL_NAME := Serial AMGX example
PARALLEL_NAME := Parallel AMGX example
%-test-par: %
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME))
%-test-seq: %
@$(call mfem-test,$<,, $(SERIAL_NAME))
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
# Generate an error message if the MFEM library is not built and exit
$(MFEM_LIB_FILE):
$(error The MFEM library is not build)
clean: clean-build
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
rm -rf *.dSYM *.TVD.*breakpoints
-24
View File
@@ -1,24 +0,0 @@
{
"config_version": 2,
"solver": {
"max_uncolored_percentage": 0.15,
"algorithm": "AGGREGATION",
"solver": "AMG",
"smoother": "MULTICOLOR_GS",
"presweeps": 1,
"symmetric_GS" : 1,
"selector": "SIZE_2",
"coarsest_sweeps": 10,
"max_iters": 10000,
"postsweeps": 1,
"scope": "main",
"max_levels": 1000,
"matrix_coloring_scheme" : "MIN_MAX",
"tolerance": 0.0000001,
"print_solve_stats": 1,
"obtain_timings": 1,
"monitor_residual": 1,
"norm": "L2",
"cycle": "V"
}
}
-21
View File
@@ -1,21 +0,0 @@
{
"config_version": 2,
"solver": {
"max_uncolored_percentage": 0.15,
"algorithm": "AGGREGATION",
"solver": "AMG",
"smoother": "MULTICOLOR_GS",
"presweeps": 1,
"symmetric_GS" : 1,
"selector": "SIZE_2",
"coarsest_sweeps": 10,
"max_iters": 2,
"postsweeps": 1,
"scope": "main",
"max_levels": 1000,
"matrix_coloring_scheme" : "MIN_MAX",
"tolerance": 0.0,
"norm": "L2",
"cycle": "V"
}
}
-1211
View File
File diff suppressed because it is too large Load Diff
-14321
View File
File diff suppressed because it is too large Load Diff
-3286
View File
File diff suppressed because it is too large Load Diff
+13 -28
View File
@@ -71,7 +71,6 @@ int main(int argc, char *argv[])
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
bool amgx = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -83,8 +82,6 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&amgx, "-amgx", "--amgx-precon", "-no-amgx",
"--no-amgx-precon", "Use AmgX V-cycle as preconditioner for CG.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
@@ -194,31 +191,7 @@ int main(int argc, char *argv[])
cout << "Size of linear system: " << A->Height() << endl;
// 11. Solve the linear system A X = B.
if (pa)
{
// Jacobi preconditioning in partial assembly mode
if (UsesTensorBasis(fespace))
{
OperatorJacobiSmoother M(a, ess_tdof_list);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
else
{
CG(*A, B, X, 1, 400, 1e-12, 0.0);
}
}
else if (amgx)
{
#if defined(MFEM_USE_AMGX)
bool amgx_verbose = false;
AmgXSolver amgx(AmgXSolver::PRECONDITIONER, amgx_verbose);
amgx.SetOperator(*A.As<SparseMatrix>());
PCG(*A, amgx, B, X, 1, 200, 1e-12, 0.0);
#else
mfem_error("MFEM not configured with AMGX \n");
#endif
}
else
if (!pa)
{
#ifndef MFEM_USE_SUITESPARSE
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
@@ -232,6 +205,18 @@ int main(int argc, char *argv[])
umf_solver.Mult(B, X);
#endif
}
else // Jacobi preconditioning in partial assembly mode
{
if (UsesTensorBasis(fespace))
{
OperatorJacobiSmoother M(a, ess_tdof_list);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
else
{
CG(*A, B, X, 1, 400, 1e-12, 0.0);
}
}
// 12. Recover the solution as a finite element grid function.
a.RecoverFEMSolution(X, b, x);
-14
View File
@@ -73,7 +73,6 @@ int main(int argc, char *argv[])
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
bool amgx = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -85,8 +84,6 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&amgx, "-amgx", "--amgx-precon", "-no-amgx",
"--no-amgx-precon", "Use AmgX V-cycle as preconditioner for CG.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
@@ -221,7 +218,6 @@ int main(int argc, char *argv[])
// 13. Solve the linear system A X = B.
// * With full assembly, use the BoomerAMG preconditioner from hypre.
// * If AmgX is available solve using amg preconditioner.
// * With partial assembly, use Jacobi smoothing, for now.
Solver *prec = NULL;
if (pa)
@@ -231,16 +227,6 @@ int main(int argc, char *argv[])
prec = new OperatorJacobiSmoother(a, ess_tdof_list);
}
}
else if (amgx)
{
#if defined(MFEM_USE_AMGX)
bool amgx_verbose = false;
prec = new AmgXSolver(MPI_COMM_WORLD, AmgXSolver::PRECONDITIONER,
amgx_verbose);
#else
mfem_error("MFEM not configured with AMGX \n");
#endif
}
else
{
prec = new HypreBoomerAMG;
-503
View File
@@ -1,503 +0,0 @@
// MFEM Example 1 - Parallel Version
//
// Compile with: make ex1p
//
// Sample runs: mpirun -np 4 ex1p -m ../data/square-disc.mesh
// mpirun -np 4 ex1p -m ../data/star.mesh
// mpirun -np 4 ex1p -m ../data/star-mixed.mesh
// mpirun -np 4 ex1p -m ../data/escher.mesh
// mpirun -np 4 ex1p -m ../data/fichera.mesh
// mpirun -np 4 ex1p -m ../data/fichera-mixed.mesh
// mpirun -np 4 ex1p -m ../data/toroid-wedge.mesh
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3
// mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/star-mixed-p2.mesh -o 2
// mpirun -np 4 ex1p -m ../data/disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/pipe-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/ball-nurbs.mesh -o 2
// mpirun -np 4 ex1p -m ../data/fichera-mixed-p2.mesh -o 2
// mpirun -np 4 ex1p -m ../data/star-surf.mesh
// mpirun -np 4 ex1p -m ../data/square-disc-surf.mesh
// mpirun -np 4 ex1p -m ../data/inline-segment.mesh
// mpirun -np 4 ex1p -m ../data/amr-quad.mesh
// mpirun -np 4 ex1p -m ../data/amr-hex.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh -o -1 -sc
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
double u_exact(const Vector &x);
double f_exact(const Vector &x);
// #define FORM_DEFINITE
#define USE_GMRES
#define USE_CSL
#define K2 250.0
int dim;
double kappa;
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/beam-tet.mesh";
int order = 1;
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. 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);
dim = mesh->Dimension();
kappa = 2.0 * M_PI;
// 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.
{
int ref_levels =
(int)floor(log(100000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
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();
}
}
{
double minsize = pmesh->GetElementSize(0);
double maxsize = minsize;
for (int i=1; i<pmesh->GetNE(); ++i)
{
const double size_i = pmesh->GetElementSize(i);
minsize = std::min(minsize, size_i);
maxsize = std::max(maxsize, size_i);
}
cout << myid << ": Element size range: (" << minsize << ", " << maxsize << ")"
<< endl;
}
// 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();
if (myid == 0)
{
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
}
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 finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (1,phi_i) where phi_i are the basis functions in fespace.
ParLinearForm *b = new ParLinearForm(fespace);
//ConstantCoefficient bcoef(1.0);
FunctionCoefficient bcoef(f_exact);
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
ConstantCoefficient neg(-K2);
ConstantCoefficient pos(K2);
b->AddDomainIntegrator(new DomainLFIntegrator(bcoef));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(fespace);
x = 0.0;
// 10. 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 = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
a->AddDomainIntegrator(new MassIntegrator(neg));
#ifdef FORM_DEFINITE
ParBilinearForm *adef = new ParBilinearForm(fespace);
adef->AddDomainIntegrator(new DiffusionIntegrator(one));
adef->AddDomainIntegrator(new MassIntegrator(pos));
if (static_cond) { adef->EnableStaticCondensation(); }
adef->Assemble();
ParGridFunction xdef(fespace);
xdef = 0.0;
ParLinearForm *bdef = new ParLinearForm(fespace);
bdef->AddDomainIntegrator(new DomainLFIntegrator(bcoef));
bdef->Assemble();
HypreParMatrix Adef;
Vector Bdef, Xdef;
adef->FormLinearSystem(ess_tdof_list, xdef, *bdef, Adef, Xdef, Bdef);
#endif
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
//A.Print("helmholtz");
// 12. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
#ifdef FORM_DEFINITE
HypreSolver *amg = new HypreBoomerAMG(Adef);
#else
HypreSolver *amg = new HypreBoomerAMG(A);
#endif
const bool fullDirect = true;
if (fullDirect)
{
#ifdef USE_CSL
Vector Bdef, Xdef;
ParBilinearForm *Mform = new ParBilinearForm(fespace);
Mform->AddDomainIntegrator(new MassIntegrator(pos));
Mform->Assemble();
HypreParMatrix Mmat, Smat, Mcopy;
Mform->FormLinearSystem(ess_tdof_list, x, *b, Mmat, Xdef, Bdef);
Mform->FormLinearSystem(ess_tdof_list, x, *b, Mcopy, Xdef,
Bdef); // There must be a better way than creating two identical matrices.
ParBilinearForm *Sform = new ParBilinearForm(fespace);
Sform->AddDomainIntegrator(new DiffusionIntegrator(one));
Sform->Assemble();
Sform->FormLinearSystem(ess_tdof_list, x, *b, Smat, Xdef, Bdef);
const double beta1 = 1.0;
const double beta2 = 1.0;
Mmat *= -beta1;
HypreParMatrix * cslRe = ParAdd(&Smat, &Mmat);
Mcopy *= beta2;
ComplexHypreParMatrix chpm(cslRe, &Mcopy, false, false);
HypreParMatrix *cSysMat = chpm.GetSystemMatrix();
Array<int> block_trueOffsets(3); // number of variables + 1
block_trueOffsets[0] = 0;
block_trueOffsets[1] = fespace->TrueVSize();
block_trueOffsets[2] = fespace->TrueVSize();
block_trueOffsets.PartialSum();
// Note that B is of true size.
BlockVector trueY(block_trueOffsets), trueX(block_trueOffsets),
trueRhs(block_trueOffsets);
trueRhs.GetBlock(0) = B;
trueRhs.GetBlock(1) = 0.0;
Operator * Arow = new STRUMPACKRowLocMatrix(*cSysMat);
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->SetMC64Job(strumpack::MC64Job::NONE);
// strumpack->SetSymmetricPattern(true);
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
//Solver * precond = strumpack;
// strumpack->Mult(B, X);
BlockOperator blockDiagA(block_trueOffsets);
for (int i=0; i<2; ++i)
{
blockDiagA.SetDiagonalBlock(i, &A);
}
ProductOperator prod(&blockDiagA, strumpack, false, false);
//GMRESSolver *gmres = new GMRESSolver(fespace->GetComm());
BiCGSTABSolver *gmres = new BiCGSTABSolver(fespace->GetComm());
gmres->SetOperator(prod);
gmres->SetRelTol(1e-8);
gmres->SetMaxIter(10000);
gmres->SetPrintLevel(1);
gmres->Mult(trueRhs, trueY);
strumpack->Mult(trueY, trueX);
X = trueX.GetBlock(0);
double xim2 = trueX.GetBlock(1).Norml2();
xim2 *= xim2;
double sumxim2 = 0.0;
MPI_Allreduce(&xim2, &sumxim2, 1, MPI_DOUBLE, MPI_SUM, fespace->GetComm());
if (myid == 0)
{
cout << myid << ": norm of Xim " << trueX.GetBlock(1).Norml2() << ", global " <<
sqrt(sumxim2) << endl;
}
delete gmres;
delete strumpack;
delete Arow;
#else
Operator * Arow = new STRUMPACKRowLocMatrix(A);
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->SetMC64Job(strumpack::MC64Job::NONE);
// strumpack->SetSymmetricPattern(true);
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
//Solver * precond = strumpack;
strumpack->Mult(B, X);
delete strumpack;
delete Arow;
#endif
}
else
{
#ifdef USE_GMRES
HypreGMRES *gmres = new HypreGMRES(A);
gmres->SetTol(1e-12);
gmres->SetMaxIter(1000);
gmres->SetPrintLevel(10);
gmres->SetPreconditioner(*amg);
gmres->Mult(B, X);
delete gmres;
#else
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(100);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*amg);
pcg->Mult(B, X);
#endif
}
/*
HYPRE_ParCSRMatrix* amgP = amg->Get_Restriction();
HypreParMatrix P0(amgP[0], false);
HypreParMatrix P1(amgP[1], false);
HypreParMatrix P2(amgP[2], false);
//HypreParMatrix P3(amgP[3], false);
P0.Print("P0");
*/
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// Compute and print the L^2 norm of the error.
{
FunctionCoefficient uex(u_exact);
double err = x.ComputeL2Error(uex);
double xnrm = x.ComputeL2Error(zero);
ParGridFunction zerogf(fespace);
zerogf = 0.0;
double normE = zerogf.ComputeL2Error(uex);
if (myid == 0)
{
cout << "|| E_h - E ||_{L^2} = " << err << endl;
cout << "|| E_h ||_{L^2} = " << xnrm << endl;
cout << "|| E ||_{L^2} = " << normE << endl;
}
}
// 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, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 15. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 16. Free the used memory.
//delete pcg;
delete amg;
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete pmesh;
MPI_Finalize();
return 0;
}
double u_exact(const Vector & x)
{
double xi(x(0));
double yi(x(1));
double zi(1.0);
if (x.Size() == 3)
{
zi = x(2);
}
return sin(kappa*xi)*sin(kappa*yi)*sin(kappa*zi);
}
double f_exact(const Vector &x)
{
double xi(x(0));
double yi(x(1));
double zi(1.0);
if (x.Size() == 3)
{
zi = x(2);
}
const double s = 1.0;
return ((3.0*kappa*kappa) - (s*K2)) * sin(kappa*xi)*sin(kappa*yi)*sin(
kappa*zi) / s;
}
+2 -2
View File
@@ -6,13 +6,11 @@
// ex22 -m ../data/inline-tri.mesh -o 3
// ex22 -m ../data/inline-quad.mesh -o 3
// ex22 -m ../data/inline-quad.mesh -o 3 -p 1
// ex22 -m ../data/inline-quad.mesh -o 3 -p 1 -pa
// ex22 -m ../data/inline-quad.mesh -o 3 -p 2
// ex22 -m ../data/inline-tet.mesh -o 2
// ex22 -m ../data/inline-hex.mesh -o 2
// ex22 -m ../data/inline-hex.mesh -o 2 -p 1
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2 -pa
// ex22 -m ../data/star.mesh -r 1 -o 2 -sigma 10.0
//
// Device sample runs:
@@ -431,6 +429,8 @@ int main(int argc, char *argv[])
// 12. Recover the solution as a finite element grid function and compute the
// errors if the exact solution is known.
a->RecoverFEMSolution(U, b, u);
u.real().SyncMemory(u);
u.imag().SyncMemory(u);
if (exact_sol)
{
+3 -3
View File
@@ -7,12 +7,10 @@
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 3
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 3 -p 1
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 3 -p 2
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 1 -p 1 -pa
// mpirun -np 4 ex22p -m ../data/inline-tet.mesh -o 2
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2 -p 1
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2 -p 2
// 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
//
// Device sample runs:
@@ -167,7 +165,7 @@ int main(int argc, char *argv[])
// 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(); }
device.Print();
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
@@ -471,6 +469,8 @@ int main(int argc, char *argv[])
// 14. Recover the parallel grid function corresponding to U. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(U, b, u);
u.real().SyncMemory(u);
u.imag().SyncMemory(u);
if (exact_sol)
{
File diff suppressed because it is too large Load Diff
+69 -34
View File
@@ -10,6 +10,10 @@
// ex25 -o 2 -f 8.0 -ref 3 -prob 4 -m ../data/inline-quad.mesh
// ex25 -o 2 -f 2.0 -ref 1 -prob 4 -m ../data/inline-hex.mesh
//
// Device sample runs:
// ex25 -o 2 -f 8.0 -ref 3 -prob 4 -m ../data/inline-quad.mesh -pa -d cuda
// ex25 -o 2 -f 2.0 -ref 1 -prob 4 -m ../data/inline-hex.mesh -pa -d cuda
//
// Description: This example code solves a simple electromagnetic wave
// propagation problem corresponding to the second order
// indefinite Maxwell equation
@@ -93,9 +97,6 @@ public:
CartesianPML * pml_)
: VectorCoefficient(dim), pml(pml_), Function(F)
{}
using VectorCoefficient::Eval;
virtual void Eval(Vector &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
@@ -156,6 +157,8 @@ int main(int argc, char *argv[])
double freq = 5.0;
bool herm_conv = true;
bool visualization = 1;
bool pa = false;
const char *device_config = "cpu";
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -177,12 +180,21 @@ 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.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.Parse();
if (iprob > 4) { iprob = 4; }
prob = (prob_type)iprob;
// 2. Setup the mesh
// 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. Setup the mesh
if (!mesh_file)
{
exact_known = true;
@@ -223,7 +235,7 @@ int main(int argc, char *argv[])
// Setup PML length
Array2D<double> length(dim, 2); length = 0.0;
// 3. Setup the Cartesian PML region.
// 4. Setup the Cartesian PML region.
switch (prob)
{
case disc:
@@ -249,19 +261,19 @@ int main(int argc, char *argv[])
comp_domain_bdr = pml->GetCompDomainBdr();
domain_bdr = pml->GetDomainBdr();
// 4. Refine the mesh to increase the resolution.
// 5. Refine the mesh to increase the resolution.
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
// 5. Reorient mesh in case of a tet mesh
// 6. Reorient mesh in case of a tet mesh
mesh->ReorientTetMesh();
// Set element attributes in order to distinguish elements in the PML region
pml->SetAttributes(mesh);
// 6. Define a finite element space on the mesh. Here we use the Nedelec
// 7. Define a finite element space on the mesh. Here we use the Nedelec
// finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
@@ -269,7 +281,7 @@ int main(int argc, char *argv[])
cout << "Number of finite element unknowns: " << size << endl;
// 7. Determine the list of true essential boundary dofs. In this example,
// 8. Determine the list of true essential boundary dofs. In this example,
// the boundary conditions are defined based on the specific mesh and the
// problem type.
Array<int> ess_tdof_list;
@@ -311,12 +323,12 @@ int main(int argc, char *argv[])
}
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
// 8. Setup Complex Operator convention
// 9. Setup Complex Operator convention
ComplexOperator::Convention conv =
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
// 9. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system.
// 10. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system.
VectorFunctionCoefficient f(dim, source);
ComplexLinearForm b(fespace, conv);
if (prob == load_src)
@@ -326,7 +338,7 @@ int main(int argc, char *argv[])
b.Vector::operator=(0.0);
b.Assemble();
// 10. Define the solution vector x as a complex finite element grid function
// 11. Define the solution vector x as a complex finite element grid function
// corresponding to fespace.
ComplexGridFunction x(fespace);
x = 0.0;
@@ -334,7 +346,7 @@ int main(int argc, char *argv[])
VectorFunctionCoefficient E_Im(dim, E_bdr_data_Im);
x.ProjectBdrCoefficientTangent(E_Re, E_Im, ess_bdr);
// 11. Set up the sesquilinear form a(.,.)
// 12. Set up the sesquilinear form a(.,.)
//
// In Comp
// Domain: 1/mu (Curl E, Curl F) - omega^2 * epsilon (E,F)
@@ -388,26 +400,30 @@ int main(int argc, char *argv[])
a.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_Re),
new VectorFEMassIntegrator(restr_c2_Im));
// 12. Assemble the bilinear form and the corresponding linear system,
// 13. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: assembly, eliminating
// boundary conditions, applying conforming constraints for
// non-conforming AMR, etc.
#ifndef MFEM_USE_SUITESPARSE
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
#endif
a.Assemble(0);
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
// 13. Solve using a direct or an iterative solver
// 14. Solve using a direct or an iterative solver
#ifdef MFEM_USE_SUITESPARSE
{
if (pa) { cout << "PA not available with MFEM_USE_SUITESPARSE" << endl; }
ComplexUMFPackSolver csolver(*A.As<ComplexSparseMatrix>());
csolver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
csolver.SetPrintLevel(1);
csolver.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)
@@ -433,39 +449,58 @@ int main(int argc, char *argv[])
prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_abs));
prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_abs));
if (pa) { prec.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
prec.Assemble();
OperatorPtr PCOpAh;
prec.FormSystemMatrix(ess_tdof_list, PCOpAh);
// 13b. Define and apply a GMRES solver for AU=B with a block diagonal
// preconditioner based on the Gauss-Seidel sparse smoother.
// 14b. Define and apply a GMRES solver for AU=B with a block diagonal
// preconditioner based on the Gauss-Seidel or Jacobi sparse smoother.
Array<int> offsets(3);
offsets[0] = 0;
offsets[1] = fespace->GetTrueVSize();
offsets[2] = fespace->GetTrueVSize();
offsets.PartialSum();
GSSmoother gs00(*PCOpAh.As<SparseMatrix>());
BlockDiagonalPreconditioner BlockGS(offsets);
ScaledOperator gs11(&gs00,
(conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0);
BlockGS.SetDiagonalBlock(0,&gs00);
BlockGS.SetDiagonalBlock(1,&gs11);
Operator *pc_r = nullptr;
Operator *pc_i = nullptr;
int s = (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0;
if (pa)
{
// Jacobi Smoother
OperatorJacobiSmoother *d00 = new OperatorJacobiSmoother(prec, ess_tdof_list);
ScaledOperator *d11 = new ScaledOperator(d00, s);
pc_r = d00;
pc_i = d11;
}
else
{
OperatorPtr PCOpAh;
prec.SetDiagonalPolicy(mfem::Operator::DIAG_ONE);
prec.FormSystemMatrix(ess_tdof_list, PCOpAh);
// Gauss-Seidel Smoother
GSSmoother *gs00 = new GSSmoother(*PCOpAh.As<SparseMatrix>());
ScaledOperator *gs11 = new ScaledOperator(gs00, s);
pc_r = gs00;
pc_i = gs11;
}
BlockDiagonalPreconditioner BlockDP(offsets);
BlockDP.SetDiagonalBlock(0, pc_r);
BlockDP.SetDiagonalBlock(1, pc_i);
GMRESSolver gmres;
gmres.SetPrintLevel(1);
gmres.SetKDim(200);
gmres.SetMaxIter(2000);
gmres.SetMaxIter(pa ? 5000 : 2000);
gmres.SetRelTol(1e-5);
gmres.SetAbsTol(0.0);
gmres.SetOperator(*A);
gmres.SetPreconditioner(BlockGS);
gmres.SetPreconditioner(BlockDP);
gmres.Mult(B, X);
}
#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);
@@ -502,7 +537,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");
@@ -517,7 +552,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)
@@ -568,7 +603,7 @@ int main(int argc, char *argv[])
}
}
// 17. Free the used memory.
// 18. Free the used memory.
delete pml;
delete fespace;
delete fec;
+64 -30
View File
@@ -10,6 +10,10 @@
// mpirun -np 4 ex25p -o 2 -f 8.0 -rs 2 -rp 2 -prob 4 -m ../data/inline-quad.mesh
// mpirun -np 4 ex25p -o 2 -f 2.0 -rs 1 -rp 1 -prob 4 -m ../data/inline-hex.mesh
//
// Device sample runs:
// mpirun -np 4 ex25p -o 1 -f 3.0 -rs 3 -rp 1 -prob 2 -pa -d cuda
// mpirun -np 4 ex25p -o 2 -f 1.0 -rs 1 -rp 1 -prob 3 -pa -d cuda
//
// Description: This example code solves a simple electromagnetic wave
// propagation problem corresponding to the second order
// indefinite Maxwell equation
@@ -93,9 +97,6 @@ public:
CartesianPML * pml_)
: VectorCoefficient(dim), pml(pml_), Function(F)
{}
using VectorCoefficient::Eval;
virtual void Eval(Vector &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
@@ -163,6 +164,8 @@ int main(int argc, char *argv[])
double freq = 5.0;
bool herm_conv = true;
bool visualization = 1;
bool pa = false;
const char *device_config = "cpu";
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -186,12 +189,21 @@ 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.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.Parse();
if (iprob > 4) { iprob = 4; }
prob = (prob_type)iprob;
// 3. Setup the (serial) mesh on all processors.
// 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);
device.Print();
// 4. Setup the (serial) mesh on all processors.
if (!mesh_file)
{
exact_known = true;
@@ -239,7 +251,7 @@ int main(int argc, char *argv[])
// Setup PML length
Array2D<double> length(dim, 2); length = 0.0;
// 4. Setup the Cartesian PML region.
// 5. Setup the Cartesian PML region.
switch (prob)
{
case disc:
@@ -265,13 +277,13 @@ int main(int argc, char *argv[])
comp_domain_bdr = pml->GetCompDomainBdr();
domain_bdr = pml->GetDomainBdr();
// 5. Refine the serial mesh on all processors to increase the resolution.
// 6. Refine the serial mesh on all processors to increase the resolution.
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
// 6. Define a parallel mesh by a partitioning of the serial mesh.
// 7. Define a parallel mesh by a partitioning of the serial mesh.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
{
@@ -281,13 +293,13 @@ int main(int argc, char *argv[])
}
}
// 6a. Reorient mesh in case of a tet mesh
// 7a. Reorient mesh in case of a tet mesh
pmesh->ReorientTetMesh();
// 7. Set element attributes in order to distinguish elements in the PML
// 8. Set element attributes in order to distinguish elements in the PML
pml->SetAttributes(pmesh);
// 8. Define a parallel finite element space on the parallel mesh. Here we
// 9. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
@@ -297,9 +309,9 @@ int main(int argc, char *argv[])
cout << "Number of finite element unknowns: " << size << endl;
}
// 9. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// based on the specific mesh and the problem type.
// 10. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// based on the specific mesh and the problem type.
Array<int> ess_tdof_list;
Array<int> ess_bdr;
if (pmesh->bdr_attributes.Size())
@@ -339,11 +351,11 @@ int main(int argc, char *argv[])
}
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
// 10. Setup Complex Operator convention
// 11. Setup Complex Operator convention
ComplexOperator::Convention conv =
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
// 11. Set up the parallel linear form b(.) which corresponds to the
// 12. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system.
VectorFunctionCoefficient f(dim, source);
ParComplexLinearForm b(fespace, conv);
@@ -354,7 +366,7 @@ int main(int argc, char *argv[])
b.Vector::operator=(0.0);
b.Assemble();
// 12. Define the solution vector x as a parallel complex finite element grid
// 13. Define the solution vector x as a parallel complex finite element grid
// function corresponding to fespace.
ParComplexGridFunction x(fespace);
x = 0.0;
@@ -362,7 +374,7 @@ int main(int argc, char *argv[])
VectorFunctionCoefficient E_Im(dim, E_bdr_data_Im);
x.ProjectBdrCoefficientTangent(E_Re, E_Im, ess_bdr);
// 13. Set up the parallel sesquilinear form a(.,.)
// 14. Set up the parallel sesquilinear form a(.,.)
//
// In Comp
// Domain: 1/mu (Curl E, Curl F) - omega^2 * epsilon (E,F)
@@ -416,19 +428,23 @@ int main(int argc, char *argv[])
a.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_Re),
new VectorFEMassIntegrator(restr_c2_Im));
// 14. Assemble the parallel bilinear form and the corresponding linear
// 15. 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, etc.
#ifndef MFEM_USE_SUPERLU
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
#endif
a.Assemble();
OperatorPtr Ah;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, Ah, X, B);
// 15. Solve using a direct or an iterative solver
// 16. Solve using a direct or an iterative solver
#ifdef MFEM_USE_SUPERLU
{
if (pa) { cout << "PA not available with MFEM_USE_SUPERLU" << endl; }
// Transform to monolithic HypreParMatrix
HypreParMatrix *A = Ah.As<ComplexHypreParMatrix>()->GetSystemMatrix();
SuperLURowLocMatrix SA(*A);
@@ -467,11 +483,9 @@ int main(int argc, char *argv[])
prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_abs));
prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_abs));
if (pa) { prec.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
prec.Assemble();
OperatorPtr PCOpAh;
prec.FormSystemMatrix(ess_tdof_list, PCOpAh);
// 16b. Define and apply a parallel GMRES solver for AU=B with a block
// diagonal preconditioner based on hypre's AMS preconditioner.
Array<int> offsets(3);
@@ -480,21 +494,41 @@ int main(int argc, char *argv[])
offsets[2] = fespace->GetTrueVSize();
offsets.PartialSum();
HypreAMS ams00(*PCOpAh.As<HypreParMatrix>(),fespace);
BlockDiagonalPreconditioner BlockAMS(offsets);
ScaledOperator ams11(&ams00,
(conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0);
BlockAMS.SetDiagonalBlock(0,&ams00);
BlockAMS.SetDiagonalBlock(1,&ams11);
Operator *pc_r = nullptr;
Operator *pc_i = nullptr;
int s = (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0;
if (pa)
{
// Jacobi Smoother
OperatorJacobiSmoother *d00 = new OperatorJacobiSmoother(prec, ess_tdof_list);
ScaledOperator *d11 = new ScaledOperator(d00, s);
pc_r = d00;
pc_i = d11;
}
else
{
OperatorPtr PCOpAh;
prec.FormSystemMatrix(ess_tdof_list, PCOpAh);
// Hypre AMS
HypreAMS *ams00 = new HypreAMS(*PCOpAh.As<HypreParMatrix>(), fespace);
ScaledOperator *ams11 = new ScaledOperator(ams00, s);
pc_r = ams00;
pc_i = ams11;
}
BlockDiagonalPreconditioner BlockDP(offsets);
BlockDP.SetDiagonalBlock(0, pc_r);
BlockDP.SetDiagonalBlock(1, pc_i);
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetPrintLevel(1);
gmres.SetKDim(200);
gmres.SetMaxIter(2000);
gmres.SetMaxIter(pa ? 5000 : 2000);
gmres.SetRelTol(1e-5);
gmres.SetAbsTol(0.0);
gmres.SetOperator(*Ah);
gmres.SetPreconditioner(BlockAMS);
gmres.SetPreconditioner(BlockDP);
gmres.Mult(B, X);
}
#endif
+2 -12
View File
@@ -60,7 +60,6 @@ int main(int argc, char *argv[])
bool static_cond = false;
bool visualization = 1;
bool amg_elast = 0;
bool reorder_space = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -76,8 +75,6 @@ int main(int argc, char *argv[])
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&reorder_space, "-nodes", "--by-nodes", "-vdim", "--by-vdim",
"Use byNODES ordering of vector space instead of byVDIM");
args.Parse();
if (!args.Good())
{
@@ -159,14 +156,7 @@ int main(int argc, char *argv[])
else
{
fec = new H1_FECollection(order, dim);
if (reorder_space)
{
fespace = new ParFiniteElementSpace(pmesh, fec, dim, Ordering::byNODES);
}
else
{
fespace = new ParFiniteElementSpace(pmesh, fec, dim, Ordering::byVDIM);
}
fespace = new ParFiniteElementSpace(pmesh, fec, dim, Ordering::byVDIM);
}
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
@@ -259,7 +249,7 @@ int main(int argc, char *argv[])
}
else
{
amg->SetSystemsOptions(dim, reorder_space);
amg->SetSystemsOptions(dim);
}
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-8);
+5 -23
View File
@@ -158,9 +158,9 @@ 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;
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
@@ -207,36 +207,18 @@ int main(int argc, char *argv[])
// 13. Solve the system AX=B using PCG with the AMS preconditioner from hypre
// (in the full assembly case) or CG with Jacobi preconditioner (in the
// partial assembly case).
if (pa) // matrix-free auxiliary space solver with PA
if (pa) // Jacobi preconditioning in partial assembly mode
{
StopWatch sw;
sw.Clear();
sw.Start();
MatrixFreeAMS *ams = new MatrixFreeAMS(*a, *A, *fespace, muinv, sigma, NULL,
ess_bdr); //, 2, 2);
//OperatorJacobiSmoother jacobi(*a, ess_tdof_list);
OperatorJacobiSmoother Jacobi(*a, ess_tdof_list);
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(1000);
cg.SetPrintLevel(1);
cg.SetOperator(*A);
cg.SetPreconditioner(*ams);
//cg.SetPreconditioner(jacobi);
//cg.iterative_mode = false;
sw.Stop();
cout << myid << ": MatrixFreeAMS-CG setup time " << sw.RealTime() << endl;
sw.Clear();
sw.Start();
cg.SetPreconditioner(Jacobi);
cg.Mult(B, X);
sw.Stop();
cout << myid << ": MatrixFreeAMS-CG solve time " << sw.RealTime() << endl;
ams->PrintTimings(myid);
}
else
{
-425
View File
@@ -1,425 +0,0 @@
// MFEM Example 3 - Parallel Version
//
// Compile with: make ex3p
//
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
// mpirun -np 4 ex3p -m ../data/escher.mesh
// mpirun -np 4 ex3p -m ../data/escher.mesh -o 2
// mpirun -np 4 ex3p -m ../data/fichera.mesh
// mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
// mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
// mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
//
// Description: This example code solves a simple electromagnetic diffusion
// problem corresponding to the second order definite Maxwell
// equation curl curl E + E = f with boundary condition
// E x n = <given tangential field>. Here, we use a given exact
// solution E and compute the corresponding r.h.s. f.
// We discretize with Nedelec finite elements in 2D or 3D.
//
// The example demonstrates the use of H(curl) finite element
// spaces with the curl-curl and the (vector finite element) mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Static condensation is
// also illustrated.
//
// We recommend viewing examples 1-2 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
#define TEST_AIRY
#ifdef TEST_AIRY
#include "gsl_sf_airy.h"
#define XSHIFT 0.0 // 0.25
#endif
// Exact solution, E, and r.h.s., f. See below for implementation.
void E_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
double freq = 1.0, kappa;
int dim;
//#define K2_VALUE 11.9
//#define K2_VALUE 2.1
//#define K2_VALUE 1500.9
#define K2_VALUE 10981.41589009910 // 104.792251097584^2 or 5 GHz
void test_Airy_epsilon(const Vector &x, Vector &e)
{
e(0) = 1.0;
e(1) = 1.0;
e(2) = (4.0 * (x(0) + XSHIFT)) - 1.0;
e *= -K2_VALUE;
}
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/beam-tet.mesh";
const char *mesh_file = "../data/inline-tetHalf.mesh";
//const char *mesh_file = "inline-tetSlab.mesh";
//const char *mesh_file = "../data/inline-hexHalf.mesh";
//const char *mesh_file = "../data/inline-tet.mesh";
int order = 2;
bool static_cond = false;
bool visualization = 1;
#ifdef MFEM_USE_STRUMPACK
bool use_strumpack = false;
#endif
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
" solution.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
#ifdef MFEM_USE_STRUMPACK
args.AddOption(&use_strumpack, "-strumpack", "--strumpack-solver",
"-no-strumpack", "--no-strumpack-solver",
"Use STRUMPACK's double complex linear solver.");
#endif
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
cout << "Using k2 " << K2_VALUE << endl;
}
kappa = freq * M_PI;
// 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);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
{
int ref_levels =
(int)floor(log(100000./mesh->GetNE())/log(2.)/dim);
ref_levels = 0;
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them.
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->ReorientTetMesh();
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
long globalNE = pmesh->GetGlobalNE();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
cout << "Number of mesh elements: " << globalNE << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
VectorFunctionCoefficient f(sdim, f_exact);
ParLinearForm *b = new ParLinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
ParGridFunction solproj(fespace);
VectorFunctionCoefficient E(sdim, E_exact);
x.ProjectCoefficient(E);
solproj = x;
// 10. Set up the parallel bilinear form corresponding to the EM diffusion
// operator curl muinv curl + sigma I, by adding the curl-curl and the
// mass domain integrators.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(-K2_VALUE);
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
#ifdef TEST_AIRY
VectorFunctionCoefficient epsilon(3, test_Airy_epsilon);
a->AddDomainIntegrator(new VectorFEMassIntegrator(epsilon));
#else
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
#endif
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
StopWatch chrono;
chrono.Clear();
chrono.Start();
#ifdef MFEM_USE_STRUMPACK
if (use_strumpack)
{
Operator * Arow = new STRUMPACKRowLocMatrix(A);
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->SetMC64Job(strumpack::MC64Job::NONE);
// strumpack->SetSymmetricPattern(true);
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
//Solver * precond = strumpack;
strumpack->Mult(B, X);
//X = 0.0;
{
// Check residual
Vector res(X.Size());
Vector ssol(X.Size());
ssol = X;
const double Bnrm = B.Norml2();
const double Bnrm2 = Bnrm*Bnrm;
A.Mult(ssol, res);
res -= B;
const double Rnrm = res.Norml2();
const double Rnrm2 = Rnrm*Rnrm;
double sumBnrm2 = 0.0;
double sumRnrm2 = 0.0;
MPI_Allreduce(&Bnrm2, &sumBnrm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce(&Rnrm2, &sumRnrm2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
if (myid == 0)
{
cout << myid << ": STRUMPACK residual norm " << sqrt(sumRnrm2) << ", B norm " <<
sqrt(sumBnrm2) << endl;
}
}
delete strumpack;
delete Arow;
}
else
#endif
{
// 12. Define and apply a parallel PCG solver for AX=B with the AMS
// preconditioner from hypre.
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
HypreSolver *ams = new HypreAMS(A, prec_fespace);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*ams);
pcg->Mult(B, X);
delete pcg;
delete ams;
}
chrono.Stop();
if (myid == 0)
{
cout << "Solver time " << chrono.RealTime() << endl;
}
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(E);
ParGridFunction x0(fespace);
x0 = 0.0;
double solnrm = x0.ComputeL2Error(E);
if (myid == 0)
{
cout << "\n|| E_h - E ||_{L^2} = " << err << ", relative error " << err / solnrm
<< endl;
}
}
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
//solproj.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
delete a;
delete sigma;
delete muinv;
delete b;
delete fespace;
delete fec;
delete pmesh;
MPI_Finalize();
return 0;
}
void E_exact(const Vector &x, Vector &E)
{
if (dim == 3)
{
#ifdef TEST_AIRY
const double y = (4.0 * (x(0) + XSHIFT)) - 1.0;
const double k = sqrt(K2_VALUE);
const double beta = pow(0.25 * k, 2.0/3.0);
E(0) = 0.0;
E(1) = 0.0;
E(2) = gsl_sf_airy_Ai(-beta * y, GSL_PREC_DOUBLE);
#else
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(2));
E(2) = sin(kappa * x(0));
#endif
}
else
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(0));
if (x.Size() == 3) { E(2) = 0.0; }
}
}
void f_exact(const Vector &x, Vector &f)
{
if (dim == 3)
{
#ifdef TEST_AIRY
f = 0.0;
#else
f(0) = (-K2_VALUE + kappa * kappa) * sin(kappa * x(1));
f(1) = (-K2_VALUE + kappa * kappa) * sin(kappa * x(2));
f(2) = (-K2_VALUE + kappa * kappa) * sin(kappa * x(0));
#endif
}
else
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
if (x.Size() == 3) { f(2) = 0.0; }
}
}
-848
View File
@@ -1,848 +0,0 @@
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include "gsl_sf_airy.h"
#include "multigrid.hpp"
using namespace std;
using namespace mfem;
//#define DIRECT_SOLVER
// Define exact solution
void E_exact(const Vector & x, Vector & E);
void H_exact(const Vector & x, Vector & H);
void f_exact_H(const Vector & x, Vector & f_H);
void get_maxwell_solution(const Vector & x, double E[], double curlE[],
double curl2E[]);
void epsilon_func(const Vector &x, Vector &M);
void epsilon2_func(const Vector &x, Vector &M);
void epsilon_func_mat(const Vector &x, DenseMatrix &M);
int dim;
double omega;
int sol = 3;
class FOSLSSolver : public Solver
{
public:
FOSLSSolver(ParFiniteElementSpace *fespace_, std::vector<HypreParMatrix*>& P,
const int myid_)
: Solver(2 * fespace_->GetTrueVSize()), M_inv(MPI_COMM_WORLD),
fespace(fespace_),
n(fespace_->GetTrueVSize()), nfull(fespace_->GetVSize()), LSpcg(MPI_COMM_WORLD),
myid(myid_)
{
z.SetSize(n);
Minv_x.SetSize(n);
ParMesh *pmesh = fespace->GetParMesh();
int dim = pmesh->Dimension();
int sdim = pmesh->SpaceDimension();
VectorFunctionCoefficient epsilon(dim, epsilon_func);
VectorFunctionCoefficient epsilonT(epsilon); // transpose of epsilon
VectorFunctionCoefficient epsilon2(dim,epsilon2_func);
ConstantCoefficient pos(omega);
ConstantCoefficient sigma(omega*omega);
ScalarVectorProductCoefficient coeff(pos,epsilon);
ScalarVectorProductCoefficient coeffT(pos,epsilonT);
ScalarVectorProductCoefficient coeff2(sigma,epsilon2);
bM = new ParBilinearForm(fespace);
bM->AddDomainIntegrator(new VectorFEMassIntegrator());
bM->Assemble();
bM->Finalize();
bM_eps = new ParBilinearForm(fespace);
bM_eps->AddDomainIntegrator(new VectorFEMassIntegrator(epsilonT));
bM_eps->Assemble();
bM_eps->Finalize();
bM_curl = new ParMixedBilinearForm(fespace,fespace);
bM_curl->AddDomainIntegrator(new MixedVectorWeakCurlIntegrator());
bM_curl->Assemble();
bM_curl->Finalize();
Array<int> ess_tdof_list; // empty
bM->FormSystemMatrix(ess_tdof_list, M);
bM_eps->FormSystemMatrix(ess_tdof_list, M_eps);
//bM_curl->FormColSystemMatrix(ess_tdof_list, M_curl);
{
OperatorPtr M_curl_ptr;
bM_curl->FormRectangularSystemMatrix(ess_tdof_list, ess_tdof_list, M_curl_ptr);
M_curl = M_curl_ptr.As<HypreParMatrix>();
}
M_inv.SetAbsTol(1.0e-12);
M_inv.SetRelTol(1.0e-12);
M_inv.SetMaxIter(100);
M_inv.SetOperator(M);
M_inv.SetPrintLevel(0);
block_trueOffsets.SetSize(5);
block_trueOffsets[0] = 0;
block_trueOffsets[1] = n;
block_trueOffsets[2] = n;
block_trueOffsets[3] = n;
block_trueOffsets[4] = n;
block_trueOffsets.PartialSum();
trueRhs = new BlockVector(block_trueOffsets);
trueSol = new BlockVector(block_trueOffsets);
// _ _ _ _ _ _
// | | | | | |
// | A00 A01 | | E | |F_E |
// | | | | = | |
// | A10 A11 | | H | |F_G |
// |_ _| |_ _| |_ _|
//
// A00 = (curl E, curl F) + \omega^2 (E,F)
// A01 = - \omega *( (curl E, F) + (E,curl F)
// A10 = - \omega *( (curl H, G) + (H,curl G)
// A11 = (curl H, curl G) + \omega^2 (H,G)
ParBilinearForm *a_EE = new ParBilinearForm(fespace);
a_EE->AddDomainIntegrator(new CurlCurlIntegrator());
a_EE->AddDomainIntegrator(new VectorFEMassIntegrator(coeff2));
a_EE->AddBoundaryIntegrator(new VectorFEMassIntegrator());
a_EE->Assemble();
a_EE->Finalize();
HypreParMatrix *A_EE = new HypreParMatrix;
a_EE->FormSystemMatrix(ess_tdof_list, *A_EE);
ParBilinearForm *a_HH = new ParBilinearForm(fespace);
a_HH->AddDomainIntegrator(new CurlCurlIntegrator());
a_HH->AddDomainIntegrator(new VectorFEMassIntegrator(sigma));
a_HH->AddBoundaryIntegrator(new VectorFEMassIntegrator());
a_HH->Assemble();
a_HH->Finalize();
HypreParMatrix *A_HH = new HypreParMatrix;
a_HH->FormSystemMatrix(ess_tdof_list, *A_HH);
ParBilinearForm *a_tang = new ParBilinearForm(fespace);
a_tang->AddBoundaryIntegrator(new VectorFEBoundaryTangentIntegrator(1.0));
a_tang->Assemble();
a_tang->Finalize();
OperatorHandle A_tang_ptr;
a_tang->FormSystemMatrix(ess_tdof_list, A_tang_ptr);
HypreParMatrix *A_tang = A_tang_ptr.As<HypreParMatrix>();
// (k curl u, eps v) + (k u, curl v)
ParMixedBilinearForm *a_mix1 = new ParMixedBilinearForm(fespace,fespace);
a_mix1->AddDomainIntegrator(new MixedVectorCurlIntegrator(coeffT));
a_mix1->AddDomainIntegrator(new MixedVectorWeakCurlIntegrator(pos));
a_mix1->Assemble();
a_mix1->Finalize();
HypreParMatrix *A_mix1 = NULL; // new HypreParMatrix;
//a_mix1->FormColSystemMatrix(ess_tdof_list, *A_mix1);
{
OperatorPtr A_mix1_ptr;
a_mix1->FormRectangularSystemMatrix(ess_tdof_list, ess_tdof_list, A_mix1_ptr);
A_mix1 = A_mix1_ptr.As<HypreParMatrix>();
}
// (k curl u, v) + (k eps u, curl v)
ParMixedBilinearForm *a_mix2 = new ParMixedBilinearForm(fespace,fespace);
a_mix2->AddDomainIntegrator(new MixedVectorCurlIntegrator(pos));
a_mix2->AddDomainIntegrator(new MixedVectorWeakCurlIntegrator(coeff));
a_mix2->Assemble();
a_mix2->Finalize();
HypreParMatrix *A_mix2 = NULL; // new HypreParMatrix;
//a_mix2->FormColSystemMatrix(ess_tdof_list, *A_mix2);
{
OperatorPtr A_mix2_ptr;
a_mix2->FormRectangularSystemMatrix(ess_tdof_list, ess_tdof_list, A_mix2_ptr);
A_mix2 = A_mix2_ptr.As<HypreParMatrix>();
}
BlockOperator *LS_Maxwellop = new BlockOperator(block_trueOffsets);
const int numBlocks = 4;
LS_Maxwellop->SetBlock(0, 0, A_EE);
LS_Maxwellop->SetBlock(1, 0, A_mix2, -1.0); // no bc
LS_Maxwellop->SetBlock(3, 0, A_tang, -1.0);
LS_Maxwellop->SetBlock(0, 1, A_mix1, -1.0); // no bc
LS_Maxwellop->SetBlock(1, 1, A_HH);
LS_Maxwellop->SetBlock(2, 1, A_tang, -1.0); // other rotation
LS_Maxwellop->SetBlock(1, 2, A_tang);
LS_Maxwellop->SetBlock(2, 2, A_EE);
LS_Maxwellop->SetBlock(3, 2, A_mix2, -1.0); // no bc
LS_Maxwellop->SetBlock(0, 3, A_tang); // other rotation
LS_Maxwellop->SetBlock(2, 3, A_mix1, -1.0); // no bc
LS_Maxwellop->SetBlock(3, 3, A_HH);
// Set up the preconditioner
Array2D<HypreParMatrix*> blockA(numBlocks, numBlocks);
Array2D<double> blockAcoef(numBlocks, numBlocks);
for (int i=0; i<numBlocks; ++i)
{
for (int j=0; j<numBlocks; ++j)
{
if (LS_Maxwellop->IsZeroBlock(i,j) == 0)
{
blockA(i,j) = static_cast<HypreParMatrix *>(&LS_Maxwellop->GetBlock(i,j));
blockAcoef(i,j) = LS_Maxwellop->GetBlockCoef(i,j);
}
else
{
blockA(i,j) = NULL;
blockAcoef(i,j) = 1.0;
}
}
}
LSpcg.SetAbsTol(1.0e-12);
LSpcg.SetRelTol(1.0e-8);
LSpcg.SetMaxIter(2000);
LSpcg.SetOperator(*LS_Maxwellop);
LSpcg.SetPrintLevel(1);
BlockMGSolver * precMG = NULL;
#ifdef DIRECT_SOLVER
std::vector<std::vector<int> > blockProcOffsets(numBlocks);
std::vector<std::vector<int> > all_block_num_loc_rows(numBlocks);
Array2D<SparseMatrix*> Asp;
Asp.SetSize(numBlocks,numBlocks);
{
int nprocs, rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
std::vector<int> allnumrows(nprocs);
const int blockNumRows = n;
MPI_Allgather(&blockNumRows, 1, MPI_INT, allnumrows.data(), 1, MPI_INT,
MPI_COMM_WORLD);
for (int b=0; b<numBlocks; ++b)
{
blockProcOffsets[b].resize(nprocs);
all_block_num_loc_rows[b].resize(nprocs);
for (int j=0; j<numBlocks; ++j)
{
Asp(b,j) = NULL;
}
}
blockProcOffsets[0][0] = 0;
for (int i=0; i<nprocs-1; ++i)
{
blockProcOffsets[0][i+1] = blockProcOffsets[0][i] + allnumrows[i];
}
for (int i=0; i<nprocs; ++i)
{
for (int b=0; b<numBlocks; ++b)
{
all_block_num_loc_rows[b][i] = allnumrows[i];
}
for (int b=1; b<numBlocks; ++b)
{
blockProcOffsets[b][i] = blockProcOffsets[0][i];
}
}
}
LSH = CreateHypreParMatrixFromBlocks(MPI_COMM_WORLD, block_trueOffsets, blockA,
Asp,
blockAcoef, blockProcOffsets, all_block_num_loc_rows);
invLSH = CreateStrumpackSolver(new STRUMPACKRowLocMatrix(*LSH), MPI_COMM_WORLD);
#else
precMG = new BlockMGSolver(LS_Maxwellop->Height(), LS_Maxwellop->Width(),
blockA, blockAcoef, P);
precMG->SetTheta(0.5);
LSpcg.SetPreconditioner(*precMG);
#endif
}
void SetOperator(const Operator &op) { }
void Mult(const Vector &x, Vector &y) const
{
// Solve (curl E, curl v) - k^2 (eps E, v) + ik <pi(u), pi(v)> = (x, v), with no BC,
// where x is complex, using FOSLS. This is the Galerkin discretization of
// curl curl u - k^2 eps u = x, with ik n x u x n - n x curl u = 0 on the boundary.
MFEM_VERIFY(x.Size() == 2*n, "");
(*trueRhs) = 0.0;
for (int i=0; i<n; ++i)
{
z[i] = x[i]; // Set z = x_Re
}
M_inv.Mult(z, Minv_x);
M_eps.Mult(Minv_x, z);
trueRhs->GetBlock(0) -= z;
M_curl->Mult(Minv_x, z);
z *= 1.0 / omega;
trueRhs->GetBlock(1) = z;
for (int i=0; i<n; ++i)
{
z[i] = x[n + i]; // Set z = x_Im
}
M_inv.Mult(z, Minv_x);
M_eps.Mult(Minv_x, z);
trueRhs->GetBlock(2) -= z;
M_curl->Mult(Minv_x, z);
z *= 1.0 / omega;
trueRhs->GetBlock(3) += z;
#ifdef DIRECT_SOLVER
invLSH->Mult(*trueRhs, *trueSol);
#else
LSpcg.Mult(*trueRhs, *trueSol);
#endif
for (int i=0; i<n; ++i)
{
y[i] = trueSol->GetBlock(0)[i]; // Set y_Re = E_Re
}
for (int i=0; i<n; ++i)
{
y[n + i] = trueSol->GetBlock(2)[i]; // Set y_Im = E_Im
}
}
void ComplexFOSLSTest()
{
Array<int> block_offsets;
block_offsets.SetSize(5);
block_offsets[0] = 0;
block_offsets[1] = nfull;
block_offsets[2] = nfull;
block_offsets[3] = nfull;
block_offsets[4] = nfull;
block_offsets.PartialSum();
BlockVector rhs(block_offsets);
BlockVector rhsIm(block_offsets);
rhs = 0.0;
rhsIm = 0.0;
const double ci = 0.0; // 3.3;
// Exact complex solution: E = Er + i Ei = Epw + ci i Epw, where Epw is E_exact.
// Set up the linear form with the real part Fr only.
const int sdim = 3;
VectorFunctionCoefficient Eex(sdim, E_exact);
VectorFunctionCoefficient Hex(sdim, H_exact);
ConstantCoefficient negOne(-1.0);
VectorFunctionCoefficient mEex(sdim, E_exact, &negOne);
VectorFunctionCoefficient mHex(sdim, H_exact, &negOne);
ConstantCoefficient neg(-omega);
ConstantCoefficient pos(omega);
VectorFunctionCoefficient f_H(3,f_exact_H); // f / omega
ScalarVectorProductCoefficient sf_H(neg,f_H);
ScalarVectorProductCoefficient spf_H(pos,f_H);
ScalarVectorProductCoefficient mf_H(negOne,f_H);
VectorFunctionCoefficient epsilon(3, epsilon_func);
VectorFunctionCoefficient epsilonT(3, epsilon_func); // transpose of epsilon
MatrixFunctionCoefficient epsilonTmat(3,
epsilon_func_mat); // transpose of epsilon
MatVecCoefficient epsT_spf_H(epsilonTmat, spf_H);
MatVecCoefficient epsT_sf_H(epsilonTmat, sf_H);
ParLinearForm *b_E = new ParLinearForm;
b_E->Update(fespace, rhs.GetBlock(0), 0);
b_E->AddDomainIntegrator(new VectorFEDomainLFIntegrator(
epsT_sf_H)); // (k^{-1} Fr, -k eps Qr)
b_E->AddBoundaryIntegrator(new VectorFEDomainLFIntegrator(
Eex)); // <n x E_Re x n, n x Q_Re x n>
b_E->Assemble();
ParLinearForm *b_H = new ParLinearForm;
b_H->Update(fespace, rhs.GetBlock(1), 0);
b_H->AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(
f_H)); // (k^{-1} Fr, curl Rr)
b_H->AddBoundaryIntegrator(new VectorFEDomainLFIntegrator(
Hex)); // <n x H_Re, n x R_Re>
b_H->Assemble();
ParLinearForm *b_E_Im = new ParLinearForm;
b_E_Im->Update(fespace, rhs.GetBlock(2), 0);
b_E_Im->AddBoundaryIntegrator(new VectorFEBoundaryTangentLFIntegrator(
mHex)); // <n x H_Re, n x Q_Im x n>
b_E_Im->Assemble();
ParLinearForm *b_H_Im = new ParLinearForm;
b_H_Im->Update(fespace, rhs.GetBlock(3), 0);
b_H_Im->AddBoundaryIntegrator(new VectorFEBoundaryTangentLFIntegrator(
mEex)); // -<n x E_Re x n, n x R_Im>
b_H_Im->Assemble();
// Add the imaginary part Fi.
ParLinearForm *b_Ei = new ParLinearForm;
b_Ei->Update(fespace, rhsIm.GetBlock(0), 0);
b_Ei->AddBoundaryIntegrator(new VectorFEBoundaryTangentLFIntegrator(
Hex)); // -<n x H_Im, n x Q_Re x n>
b_Ei->Assemble();
ParLinearForm *b_Hi = new ParLinearForm;
b_Hi->Update(fespace, rhsIm.GetBlock(1), 0);
b_Hi->AddBoundaryIntegrator(new VectorFEBoundaryTangentLFIntegrator(
Eex)); // <n x E_Im x n, n x R_Re>
b_Hi->Assemble();
ParLinearForm *b_Ei_Im = new ParLinearForm;
b_Ei_Im->Update(fespace, rhsIm.GetBlock(2), 0);
b_Ei_Im->AddDomainIntegrator(new VectorFEDomainLFIntegrator(
epsT_sf_H)); // -(k^{-1} Fi, k eps Qi)
b_Ei_Im->AddBoundaryIntegrator(new VectorFEDomainLFIntegrator(
Eex)); // <n x E_Im x n, n x Q_Im x n>
b_Ei_Im->Assemble();
ParLinearForm *b_Hi_Im = new ParLinearForm;
b_Hi_Im->Update(fespace, rhsIm.GetBlock(3), 0);
b_Hi_Im->AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(
f_H)); // (k^{-1} Fi, curl Ri)
b_Hi_Im->AddBoundaryIntegrator(new VectorFEDomainLFIntegrator(
Hex)); // <n x H_Im, n x R_Im>
b_Hi_Im->Assemble();
rhsIm *= ci;
rhs += rhsIm;
for (int i=0; i<4; ++i)
{
fespace->GetProlongationMatrix()->MultTranspose(rhs.GetBlock(i),
trueRhs->GetBlock(i));
}
#ifdef DIRECT_SOLVER
invLSH->Mult(*trueRhs, *trueSol);
#else
LSpcg.Mult(*trueRhs, *trueSol);
#endif
// Check error
ParGridFunction E_gf(fespace);
int order = 2;
int order_quad = std::max(2, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
ParMesh *pmesh = fespace->GetParMesh();
// Check error of real part
E_gf.SetFromTrueDofs(trueSol->GetBlock(0));
double Error_E = E_gf.ComputeL2Error(Eex, irs);
double norm_E = ComputeGlobalLpNorm(2, Eex, *pmesh, irs);
cout << myid << ": real error " << Error_E << " relative to " << norm_E << endl;
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
E_gf.Save(sol_ofs);
}
// Check error of imaginary part
E_gf.SetFromTrueDofs(trueSol->GetBlock(2));
const double iml2 = E_gf.Norml2();
E_gf *= ci == 0.0 ? 0.0 : (1.0 / ci);
Error_E = E_gf.ComputeL2Error(Eex, irs);
cout << myid << ": imag error " << Error_E << " relative to " << norm_E <<
", l2 norm " << iml2 << endl;
}
private:
BlockVector *trueRhs, *trueSol;
Array<int> block_trueOffsets;
ParBilinearForm *bM, *bM_eps;
ParMixedBilinearForm *bM_curl;
HypreParMatrix M, M_eps;
HypreParMatrix *M_curl;
CGSolver M_inv;
const int n;
const int nfull;
const int myid;
mutable Vector z, Minv_x;
CGSolver LSpcg;
STRUMPACKSolver *invLSH;
HypreParMatrix *LSH;
ParFiniteElementSpace *fespace;
};
int main(int argc, char *argv[])
{
StopWatch chrono;
// 1. Initialize MPI
int num_procs, myid;
MPI_Init(&argc, &argv); // Initialize MPI
MPI_Comm_size(MPI_COMM_WORLD,
&num_procs); //total number of processors available
MPI_Comm_rank(MPI_COMM_WORLD, &myid); // Determine process identifier
// 1. Parse command-line options.
// geometry file
const char *mesh_file = "../data/inline-hex.mesh";
// finite element order of approximation
int order = 1;
// static condensation flag
bool static_cond = false;
// visualization flag
bool visualization = 1;
// number of wavelengths
double k = 1.0;
// number of mg levels
int ref_levels = 1;
// number of initial ref
int initref = 1;
// optional command line inputs
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&k, "-k", "--wavelengths",
"Number of wavelengths.");
args.AddOption(&ref_levels, "-ref", "--ref_levels",
"Number of Refinements.");
args.AddOption(&initref, "-initref", "--initref",
"Number of initial refinements.");
args.AddOption(&sol, "-sol", "--exact",
"Exact solution flag - "
" 1:sinusoidal, 2: point source, 3: plane wave");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
// check if the inputs are correct
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// Angular frequency
//omega = 2.0*k*M_PI;
omega = k;
// 2. Read the mesh from the given mesh file.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
if (sol == 4)
{
mesh->EnsureNodes();
GridFunction *nodes = mesh->GetNodes();
(*nodes) *= 0.5;
}
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 3. Executing uniform h-refinement
for (int i = 0; i < initref; i++ )
{
mesh->UniformRefinement();
}
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
// 4. Define a finite element space on the mesh.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
std::vector<ParFiniteElementSpace * > fespaces(ref_levels+1);
std::vector<ParMesh * > ParMeshes(ref_levels+1);
std::vector<HypreParMatrix*> P(ref_levels);
for (int i = 0; i < ref_levels; i++)
{
ParMeshes[i] =new ParMesh(*pmesh);
fespaces[i] = new ParFiniteElementSpace(*fespace, *ParMeshes[i]);
pmesh->UniformRefinement();
// Update fespace
fespace->Update();
OperatorHandle Tr(Operator::Hypre_ParCSR);
fespace->GetTrueTransferOperator(*fespaces[i], Tr);
Tr.SetOperatorOwner(false);
Tr.Get(P[i]);
}
fespaces[ref_levels] = new ParFiniteElementSpace(*fespace);
FOSLSSolver fosls(fespace, P, myid);
fosls.ComplexFOSLSTest();
for (auto p: ParMeshes) { delete p; }
for (auto p: fespaces) { delete p; }
for (auto p: P) { delete p; }
ParMeshes.clear();
fespaces.clear();
P.clear();
delete fec;
delete fespace;
delete pmesh;
MPI_Finalize();
return 0;
}
//define exact solution
void E_exact(const Vector &x, Vector &E)
{
double curlE[3], curl2E[3];
get_maxwell_solution(x, E, curlE, curl2E);
}
void H_exact(const Vector &x, Vector &H)
{
double E[3], curlE[3], curl2E[3];
get_maxwell_solution(x, E, curlE, curl2E);
for (int i = 0; i<3; i++) { H(i) = curlE[i]/omega; }
}
void f_exact_H(const Vector &x, Vector &f)
{
// curl H - omega E = f
// = curl (curl E / omega) - omega E
f = 0.0;
if (sol !=4)
{
double E[3], curlE[3], curl2E[3];
get_maxwell_solution(x, E, curlE, curl2E);
f(0) = curl2E[0] / omega - omega * E[0];
f(1) = curl2E[1] / omega - omega * E[1];
f(2) = curl2E[2] / omega - omega * E[2];
}
}
void get_maxwell_solution(const Vector &X, double E[], double curlE[],
double curl2E[])
{
double x = X[0];
double y = X[1];
double z = X[2];
if (sol ==-1)
{
E[0] = y * z * (1.0 - y) * (1.0 - z);
E[1] = x * y * z * (1.0 - x) * (1.0 - z);
E[2] = x * y * (1.0 - x) * (1.0 - y);
curlE[0] = -(x-1.0) * x * (y*(2.0*z-3.0)+1.0);
curlE[1] = -2.0*(y-1.0)*y*(x-z);
curlE[2] = (z-1)*z*(1.0+y*(2.0*x-3.0));
curl2E[0] = 2.0 * y * (1.0 - y) - (2.0 * x - 3.0) * z * (1 - z);
curl2E[1] = 2.0 * y * (x * (1.0 - x) + (1.0 - z) * z);
curl2E[2] = 2.0 * y * (1.0 - y) + x * (3.0 - 2.0 * z) * (1.0 - x);
}
else if (sol == 0) // polynomial
{
// Polynomial vanishing on the boundary
E[0] = y * z * (1.0 - y) * (1.0 - z);
E[1] = (1.0 - x) * x * y * (1.0 - z) * z;
E[2] = (1.0 - x) * x * (1.0 - y) * y;
//
curlE[0] = -(-1.0 + x) * x * (1.0 + y * (-3.0 + 2.0 * z));
curlE[1] = -2.0 * (-1.0 + y) * y * (x - z);
curlE[2] = (1.0 + (-3.0 + 2.0 * x) * y) * (-1.0 + z) * z;
curl2E[0] = -2.0 * (-1.0 + y) * y + (-3.0 + 2.0 * x) * (-1.0 + z) * z;
curl2E[1] = -2.0 * y * (-x + x * x + (-1.0 + z) * z);
curl2E[2] = -2.0 * (-1.0 + y) * y + (-1.0 + x) * x * (-3.0 + 2.0 * z);
}
else if (sol == 1) // sinusoidal
{
E[0] = sin(omega * y);
E[1] = sin(omega * z);
E[2] = sin(omega * x);
curlE[0] = -omega * cos(omega * z);
curlE[1] = -omega * cos(omega * x);
curlE[2] = -omega * cos(omega * y);
curl2E[0] = omega * omega * E[0];
curl2E[1] = omega * omega * E[1];
curl2E[2] = omega * omega * E[2];
}
else if (sol == 2) // point source
{
// shift to avoid singularity
double x0 = x + 0.1;
double x1 = y + 0.1;
double x2 = z + 0.1;
double r = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
E[0] = cos(omega * r);
E[1] = 0.0;
E[2] = 0.0;
double r_x = x0 / r;
double r_y = x1 / r;
double r_z = x2 / r;
double r_xy = -(r_x / r) * r_y;
double r_xz = -(r_x / r) * r_z;
double r_yx = r_xy;
double r_yy = (1.0 / r) * (1.0 - r_y * r_y);
double r_zx = r_xz;
double r_zz = (1.0 / r) * (1.0 - r_z * r_z);
curlE[0] = 0.0;
curlE[1] = -omega * r_z * sin(omega * r);
curlE[2] = omega * r_y * sin(omega * r);
curl2E[0] = omega * ((r_yy + r_zz) * sin(omega * r) +
(omega * r_y * r_y + omega * r_z * r_z) * cos(omega * r));
curl2E[1] = -omega * (r_yx * sin(omega * r) + omega * r_y * r_x * cos(
omega * r));
curl2E[2] = -omega * (r_zx * sin(omega * r) + omega * r_z * r_x * cos(
omega * r));
}
else if (sol == 3) // plane wave
{
double coeff = omega / sqrt(3.0);
E[0] = cos(coeff * (x + y + z));
E[1] = 0.0;
E[2] = 0.0;
curlE[0] = 0.0;
curlE[1] = -coeff * sin(coeff * (x + y + z));
curlE[2] = coeff * sin(coeff * (x + y + z));
curl2E[0] = 2.0 * coeff * coeff * E[0];
curl2E[1] = -coeff * coeff * E[0];
curl2E[2] = -coeff * coeff * E[0];
}
else if (sol == -1)
{
E[0] = cos(omega * y);
E[1] = 0.0;
curlE[0] = 0.0;
curlE[1] = 0.0;
curlE[2] = -omega * sin(omega * y);
curl2E[0] = omega*omega * cos(omega*y);
curl2E[1] = 0.0;
curl2E[2] = 0.0;
}
else if (sol == 4) // Airy function
{
E[0] = 0;
E[1] = 0;
// double b = -pow(omega/4.0,2.0/3.0)*(4.0*x(0)-1.0);
double b = -pow(omega/4.0,2.0/3.0)*(4.0*x-1.0);
//E[2] = boost::math::airy_ai(b);
E[2] = gsl_sf_airy_Ai(b, GSL_PREC_DOUBLE);
curlE[0] = 0.0;
curlE[1] = 4.0 * pow(omega/4.0,2.0/3.0) * gsl_sf_airy_Ai_deriv(b,
GSL_PREC_DOUBLE);
curlE[2] = 0.0;
// not used
curl2E[0] = 0.0;
curl2E[1] = 0.0;
curl2E[2] = 0.0;
}
}
void epsilon_func(const Vector &x, Vector &M)
{
M.SetSize(3);
M = 1.0;
if (sol == 4)
{
M[2] = 4.0*x(0)-1.0;
}
}
void epsilon2_func(const Vector &x, Vector &M)
{
M.SetSize(3);
M = 1.0;
if (sol == 4)
{
M[2] = (4.0*x(0)-1.0) * (4.0*x(0)-1.0);
}
}
void epsilon_func_mat(const Vector &x, DenseMatrix &M)
{
M.SetSize(3);
M = 0.0;
M(0,0) = 1.0;
M(1,1) = 1.0;
if (sol != 4)
{
M(2,2) = 1.0;
}
else
{
M(2,2) = 4.0*x(0)-1.0;
}
}
-3293
View File
File diff suppressed because it is too large Load Diff
-764
View File
@@ -1,764 +0,0 @@
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include "gsl_sf_airy.h"
#include "multigrid.hpp"
using namespace std;
using namespace mfem;
#define COMPLEX_IMPEDANCE // Whether to use impedance BC and solve a complex system
// Define exact solution
void E_exact(const Vector & x, Vector & E);
void H_exact(const Vector & x, Vector & H);
void f_exact_H(const Vector & x, Vector & f_H);
void get_maxwell_solution(const Vector & x, double E[], double curlE[],
double curl2E[]);
void epsilon_func(const Vector &x, DenseMatrix &M);
void epsilon2_func(const Vector &x, DenseMatrix &M);
int dim;
double omega;
int sol = 4;
int main(int argc, char *argv[])
{
StopWatch chrono;
// 1. Initialize MPI
int num_procs, myid;
MPI_Init(&argc, &argv); // Initialize MPI
MPI_Comm_size(MPI_COMM_WORLD,
&num_procs); //total number of processors available
MPI_Comm_rank(MPI_COMM_WORLD, &myid); // Determine process identifier
// 1. Parse command-line options.
// geometry file
const char *mesh_file = "../data/inline-hex.mesh";
// finite element order of approximation
int order = 1;
// static condensation flag
bool static_cond = false;
// visualization flag
bool visualization = 1;
// number of wavelengths
double k = 1.0;
// number of mg levels
int ref_levels = 1;
// number of initial ref
int initref = 1;
// optional command line inputs
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&k, "-k", "--wavelengths",
"Number of wavelengths.");
args.AddOption(&ref_levels, "-ref", "--ref_levels",
"Number of Refinements.");
args.AddOption(&initref, "-initref", "--initref",
"Number of initial refinements.");
args.AddOption(&sol, "-sol", "--exact",
"Exact solution flag - "
" 1:sinusoidal, 2: point source, 3: plane wave");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
// check if the inputs are correct
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// Angular frequency
//omega = 2.0*k*M_PI;
omega = k;
// 2. Read the mesh from the given mesh file.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
if (sol == 4)
{
mesh->EnsureNodes();
GridFunction *nodes = mesh->GetNodes();
(*nodes) *= 0.5;
}
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 3. Executing uniform h-refinement
for (int i = 0; i < initref; i++ )
{
mesh->UniformRefinement();
}
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
// 4. Define a finite element space on the mesh.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
std::vector<ParFiniteElementSpace * > fespaces(ref_levels+1);
std::vector<ParMesh * > ParMeshes(ref_levels+1);
std::vector<HypreParMatrix*> P(ref_levels);
for (int i = 0; i < ref_levels; i++)
{
ParMeshes[i] =new ParMesh(*pmesh);
fespaces[i] = new ParFiniteElementSpace(*fespace, *ParMeshes[i]);
pmesh->UniformRefinement();
// Update fespace
fespace->Update();
OperatorHandle Tr(Operator::Hypre_ParCSR);
fespace->GetTrueTransferOperator(*fespaces[i], Tr);
Tr.SetOperatorOwner(false);
Tr.Get(P[i]);
}
fespaces[ref_levels] = new ParFiniteElementSpace(*fespace);
Array<int> ess_tdof_listE;
Array<int> ess_tdof_listH;
Array<int> ess_bdrE(pmesh->bdr_attributes.Max());
Array<int> ess_bdrH(pmesh->bdr_attributes.Max());
#ifdef COMPLEX_IMPEDANCE
ess_bdrE = 0;
ess_bdrH = 0; // Neumann
#else
ess_bdrE = 1;
ess_bdrH = 0; // Neumann
#endif
fespace->GetEssentialTrueDofs(ess_bdrE, ess_tdof_listE);
fespace->GetEssentialTrueDofs(ess_bdrH, ess_tdof_listH);
#ifdef COMPLEX_IMPEDANCE
Array<int> bdr_attr(pmesh->bdr_attributes.Max());
bdr_attr = 1;
ConstantCoefficient impedance(omega);
RestrictedCoefficient imp_rest(impedance, bdr_attr);
Array<int> block_offsets(5);
Array<int> block_trueOffsets(5);
#else
Array<int> block_offsets(3);
Array<int> block_trueOffsets(3);
#endif
block_offsets[0] = 0;
block_offsets[1] = fespace->GetVSize();
block_offsets[2] = fespace->GetVSize();
#ifdef COMPLEX_IMPEDANCE
block_offsets[3] = fespace->GetVSize();
block_offsets[4] = fespace->GetVSize();
#endif
block_offsets.PartialSum();
block_trueOffsets[0] = 0;
block_trueOffsets[1] = fespace->TrueVSize();
block_trueOffsets[2] = fespace->TrueVSize();
#ifdef COMPLEX_IMPEDANCE
block_trueOffsets[3] = fespace->TrueVSize();
block_trueOffsets[4] = fespace->TrueVSize();
#endif
block_trueOffsets.PartialSum();
// _ _ _ _ _ _
// | | | | | |
// | A00 A01 | | E | |F_E |
// | | | | = | |
// | A10 A11 | | H | |F_G |
// |_ _| |_ _| |_ _|
//
// A00 = (curl E, curl F) + \omega^2 (E,F)
// A01 = - \omega *( (curl E, F) + (E,curl F)
// A10 = - \omega *( (curl H, G) + (H,curl G)
// A11 = (curl H, curl G) + \omega^2 (H,G)
BlockVector x(block_offsets), rhs(block_offsets);
BlockVector trueX(block_trueOffsets), trueRhs(block_trueOffsets);
x = 0.0;
rhs = 0.0;
trueX = 0.0;
trueRhs = 0.0;
VectorFunctionCoefficient Eex(sdim, E_exact);
ConstantCoefficient negOne(-1.0);
VectorFunctionCoefficient mEex(sdim, E_exact, &negOne);
ParGridFunction * E_gf = new ParGridFunction;
ParGridFunction * Exact_gf = new ParGridFunction(fespace);
E_gf->MakeRef(fespace, x.GetBlock(0));
E_gf->ProjectCoefficient(Eex);
Exact_gf->ProjectCoefficient(Eex);
VectorFunctionCoefficient Hex(sdim, H_exact);
ParGridFunction * H_gf = new ParGridFunction;
H_gf->MakeRef(fespace, x.GetBlock(1));
H_gf->ProjectCoefficient(Hex);
ConstantCoefficient one(1.0);
ConstantCoefficient sigma(pow(omega, 2));
ConstantCoefficient neg(-abs(omega));
ConstantCoefficient pos(abs(omega));
MatrixFunctionCoefficient epsilon(dim,epsilon_func);
TransposeMatrixCoefficient epsilonT(epsilon); // transpose of epsilon
MatrixFunctionCoefficient epsilon2(dim,epsilon2_func);
ScalarMatrixProductCoefficient coeff(neg,epsilon);
ScalarMatrixProductCoefficient coeff2(sigma,epsilon2);
// 6. Set up the linear form
VectorFunctionCoefficient f_H(sdim,f_exact_H);
ScalarVectorProductCoefficient sf_H(neg,f_H);
MatVecCoefficient epsT_sf_H(epsilonT, sf_H);
ParLinearForm *b_E = new ParLinearForm;
b_E->Update(fespace, rhs.GetBlock(0), 0);
b_E->AddDomainIntegrator(new VectorFEDomainLFIntegrator(epsT_sf_H));
#ifdef COMPLEX_IMPEDANCE
b_E->AddBoundaryIntegrator(new VectorFEDomainLFIntegrator(
Eex)); // <g_Im, n x Q x n> = <n x E_Re x n, n x Q x n>
ParLinearForm *b_E_Im = new ParLinearForm;
b_E_Im->Update(fespace, rhs.GetBlock(2), 0);
b_E_Im->AddBoundaryIntegrator(new VectorFEBoundaryTangentLFIntegrator(
Hex)); // -<g_Re, n x Q x n> = <n x H_Re, n x Q x n>
b_E_Im->Assemble();
#endif
b_E->Assemble();
ParLinearForm *b_H = new ParLinearForm;
b_H->Update(fespace, rhs.GetBlock(1), 0);
b_H->AddDomainIntegrator(new VectorFEDomainLFCurlIntegrator(f_H));
#ifdef COMPLEX_IMPEDANCE
b_H->AddBoundaryIntegrator(new VectorFEDomainLFIntegrator(
Hex)); // -<g_Re, n x R> = <n x H_Re, n x R>
ParLinearForm *b_H_Im = new ParLinearForm;
b_H_Im->Update(fespace, rhs.GetBlock(3), 0);
b_H_Im->AddBoundaryIntegrator(new VectorFEBoundaryTangentLFIntegrator(
mEex)); // -<g_Im, n x R> = -<n x E_Re x n, n x R>
b_H_Im->Assemble();
#endif
b_H->Assemble();
#ifdef COMPLEX_IMPEDANCE
fespace->GetProlongationMatrix()->MultTranspose(rhs.GetBlock(2),
trueRhs.GetBlock(2));
fespace->GetProlongationMatrix()->MultTranspose(rhs.GetBlock(3),
trueRhs.GetBlock(3));
#endif
// 7. Bilinear form a(.,.) on the finite element space
ParBilinearForm *a_EE = new ParBilinearForm(fespace);
a_EE->AddDomainIntegrator(new CurlCurlIntegrator(one));
a_EE->AddDomainIntegrator(new VectorFEMassIntegrator(coeff2));
#ifdef COMPLEX_IMPEDANCE
a_EE->AddBoundaryIntegrator(new VectorFEMassIntegrator());
//a_EE->AddBoundaryIntegrator(new VectorFEMassIntegrator(imp_rest));
//a_EE->AddBoundaryIntegrator(new BoundaryMassIntegrator(imp_rest));
//a_EE->AddBdrFaceIntegrator(new BoundaryMassIntegrator(imp_rest));
#endif
a_EE->Assemble();
a_EE->Finalize();
HypreParMatrix *A_EE = new HypreParMatrix;
a_EE->FormLinearSystem(ess_tdof_listE, x.GetBlock(0), rhs.GetBlock(0), *A_EE,
trueX.GetBlock(0), trueRhs.GetBlock(0));
ParBilinearForm *a_HH = new ParBilinearForm(fespace);
a_HH->AddDomainIntegrator(new CurlCurlIntegrator(one)); // one is the coeff
a_HH->AddDomainIntegrator(new VectorFEMassIntegrator(sigma));
#ifdef COMPLEX_IMPEDANCE
a_HH->AddBoundaryIntegrator(new VectorFEMassIntegrator());
//a_HH->AddBoundaryIntegrator(new VectorFEMassIntegrator(imp_rest));
//a_HH->AddBoundaryIntegrator(new BoundaryMassIntegrator(imp_rest));
#endif
a_HH->Assemble();
a_HH->Finalize();
HypreParMatrix *A_HH = new HypreParMatrix;
a_HH->FormLinearSystem(ess_tdof_listH, x.GetBlock(1), rhs.GetBlock(1), *A_HH,
trueX.GetBlock(1), trueRhs.GetBlock(1));
ParMixedBilinearForm *a_HE = new ParMixedBilinearForm(fespace,fespace);
a_HE->AddDomainIntegrator(new MixedVectorCurlIntegrator(neg));
a_HE->AddDomainIntegrator(new MixedVectorWeakCurlIntegrator(coeff));
a_HE->Assemble();
a_HE->Finalize();
HypreParMatrix *A_HE = new HypreParMatrix;
a_HE->FormColLinearSystem(ess_tdof_listE,x.GetBlock(0),rhs.GetBlock(1),*A_HE,
trueX.GetBlock(0),trueRhs.GetBlock(1));
HypreParMatrix *A_EH = A_HE->Transpose();
#ifdef COMPLEX_IMPEDANCE
ParBilinearForm *a_EH_Im = new ParBilinearForm(fespace);
//a_EH_Im->AddBoundaryIntegrator(new VectorFEBoundaryTangentIntegrator(imp_rest));
//a_EH_Im->AddBoundaryIntegrator(new VectorFEBoundaryTangentIntegrator(impedance));
//a_EH_Im->AddBoundaryIntegrator(new VectorFEBoundaryTangentIntegrator(omega));
a_EH_Im->AddBoundaryIntegrator(new VectorFEBoundaryTangentIntegrator());
a_EH_Im->Assemble();
a_EH_Im->Finalize();
OperatorHandle A_EH_Im_ptr;
a_EH_Im->FormSystemMatrix(ess_tdof_listE,
A_EH_Im_ptr); // empty ess_tdof_list for impedance
HypreParMatrix *A_EH_Im = A_EH_Im_ptr.As<HypreParMatrix>();
HypreParMatrix *A_HE_Im = A_EH_Im->Transpose();
#endif
BlockOperator *LS_Maxwellop = new BlockOperator(block_trueOffsets);
#ifdef COMPLEX_IMPEDANCE
const int numBlocks = 4;
#else
const int numBlocks = 2;
#endif
LS_Maxwellop->SetBlock(0, 0, A_EE);
LS_Maxwellop->SetBlock(0, 1, A_EH);
LS_Maxwellop->SetBlock(1, 0, A_HE);
LS_Maxwellop->SetBlock(1, 1, A_HH);
#ifdef COMPLEX_IMPEDANCE
LS_Maxwellop->SetBlock(0, 3, A_EH_Im);
LS_Maxwellop->SetBlock(1, 2, A_HE_Im, -1.0);
LS_Maxwellop->SetBlock(2, 1, A_EH_Im, -1.0);
LS_Maxwellop->SetBlock(3, 0, A_HE_Im);
LS_Maxwellop->SetBlock(2, 2, A_EE);
LS_Maxwellop->SetBlock(2, 3, A_EH);
LS_Maxwellop->SetBlock(3, 2, A_HE);
LS_Maxwellop->SetBlock(3, 3, A_HH);
#endif
if (myid == 0)
{
cout << "Size of fine grid system: "
<< 2.0 * A_EE->GetGlobalNumRows() << " x " << 2.0* A_EE->GetGlobalNumCols() <<
endl;
}
// Set up the preconditioner
Array2D<HypreParMatrix*> blockA(numBlocks, numBlocks);
Array2D<double> blockAcoef(numBlocks, numBlocks);
for (int i=0; i<numBlocks; ++i)
{
for (int j=0; j<numBlocks; ++j)
{
if (LS_Maxwellop->IsZeroBlock(i,j) == 0)
{
blockA(i,j) = static_cast<HypreParMatrix *>(&LS_Maxwellop->GetBlock(i,j));
blockAcoef(i,j) = LS_Maxwellop->GetBlockCoef(i,j);
}
else
{
blockA(i,j) = NULL;
blockAcoef(i,j) = 1.0;
}
}
}
// // double nnz = A_HH->NNZ();
// // double ndof = A_HH->GetGlobalNumRows();
// // double est_mem_b = nnz*12.0 + (ndof+1.0)*4;
// // double gb = est_mem_b*4.0/pow(1024.0,3);
// // mfem::out << "Estimated memory taken by the global matrix: " << gb << endl;
int maxit(2000);
double rtol(1.e-8);
double atol(1.e-12);
// trueX = 0.0;
CGSolver pcg(MPI_COMM_WORLD);
pcg.SetAbsTol(atol);
pcg.SetRelTol(rtol);
pcg.SetMaxIter(maxit);
pcg.SetOperator(*LS_Maxwellop);
pcg.SetPrintLevel(1);
chrono.Clear();
chrono.Start();
BlockMGSolver * precMG = new BlockMGSolver(LS_Maxwellop->Height(),
LS_Maxwellop->Width(), blockA, blockAcoef, P);
//precMG->SetTheta(0.5);
// // int lv_coarse = min(ref_levels,ref_levels-1);
// // int levels = ref_levels - lv_coarse;
// // BlkParSchwarzSmoother * precAS = new BlkParSchwarzSmoother(fespaces[lv_coarse]->GetParMesh(),levels,fespaces[ref_levels],LS_Maxwellop);
chrono.Stop();
if (myid == 0)
{
cout << "MG Setup time: " << chrono.RealTime() << endl;
}
// Randomize H RHS
//trueRhs = 1.0;
/*
for (int i=block_trueOffsets[1]; i<block_trueOffsets[2]; ++i)
trueRhs[i] = i % 53;
*/
chrono.Clear();
chrono.Start();
pcg.SetPreconditioner(*precMG);
// // pcg.SetPreconditioner(*precAS);
pcg.Mult(trueRhs, trueX);
chrono.Stop();
delete precMG;
// // delete precAS;
// // trueX = 0.0;
// // invA->Mult(trueRhs,trueX);
if (myid == 0)
{
cout << "MG Solution time time: " << chrono.RealTime() << endl;
}
// // cin.get();
// // if(myid == 0)
// // cout << "MG prec Solution time: " << chrono.RealTime() << endl;
// // chrono.Clear();
// // chrono.Start();
// // Block_AMSSolver * precAMS = new Block_AMSSolver(block_trueOffsets,fespaces);
// // precAMS->SetSmootherType(Block_AMS::BlkSmootherType::SCHWARZ);
// // precAMS->SetSmootherType(Block_AMS::BlkSmootherType::HYPRE);
// // precAMS->SetOperator(LS_Maxwellop);
// // precAMS->SetTheta(1.0/5.0);
// // // 0-Smoother, 1-Grad, 2,3,4-Pix,Piy,Piz
// // precAMS->SetCycleType("023414320");
// // precAMS->SetNumberofCycles(1);
// // chrono.Stop();
// // if(myid == 0)
// // cout << "BlkAMS Setup time: " << chrono.RealTime() << endl;
// // // resolve with block AMS
// // trueX = 0;
// // chrono.Clear();
// // chrono.Start();
// // pcg.SetPreconditioner(*precAMS);
// // pcg.Mult(trueRhs, trueX);
// // chrono.Stop();
// // delete precAMS;
// // if(myid == 0)
// // cout << "BlockAMS Solution time: " << chrono.RealTime() << endl;
a_EE->RecoverFEMSolution(trueX.GetBlock(0), *b_E, *E_gf);
a_HH->RecoverFEMSolution(trueX.GetBlock(1), *b_H, *H_gf);
int order_quad = max(2, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
double Error_E = E_gf->ComputeL2Error(Eex, irs);
double norm_E = ComputeGlobalLpNorm(2, Eex, *pmesh, irs);
double Error_H = H_gf->ComputeL2Error(Hex, irs);
double norm_H = ComputeGlobalLpNorm(2, Hex , *pmesh, irs);
if (myid == 0)
{
cout << "|| E_h - E || = " << Error_E << "\n";
cout << "|| E_h - E ||/||E|| = " << Error_E/norm_E << "\n";
cout << "|| H_h - H || = " << Error_H << "\n";
cout << "|| H_h - H ||/||H|| = " << Error_H/norm_H << "\n";
cout << "Total error = " << setprecision(15) << sqrt(Error_H*Error_H
+Error_E*Error_E) << "\n";
}
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
E_gf->Save(sol_ofs);
}
//ParGridFunction ExactE(fespace);
/*
if (visualization)
{
// 8. Connect to GLVis.
char vishost[] = "localhost";
int visport = 19916;
// socketstream E_sock(vishost, visport);
// E_sock << "parallel " << num_procs << " " << myid << "\n";
// E_sock.precision(8);
// E_sock << "solution\n" << *pmesh << *E_gf << "window_title 'Electric field'" << endl;
socketstream Exact_sock(vishost, visport);
Exact_sock << "parallel " << num_procs << " " << myid << "\n";
Exact_sock.precision(8);
Exact_sock << "solution\n" << *pmesh << *Exact_gf << "window_title 'Electric field'" << endl;
// MPI_Barrier(pmesh->GetComm());
// socketstream Eex_sock(vishost, visport);
// Eex_sock << "parallel " << num_procs << " " << myid << "\n";
// Eex_sock.precision(8);
// Eex_sock << "solution\n" << *pmesh << *Exact_gf << "window_title 'Exact Electric field'" << endl;
}
*/
// delete A_EE;
// delete A_HE;
// delete A_EH;
// delete A_HH;
// delete LS_Maxwellop;
// delete a_EE;
// delete a_HE;
// delete a_HH;
// delete b_E;
// delete b_H;
delete E_gf;
delete Exact_gf;
for (auto p: ParMeshes) { delete p; }
for (auto p: fespaces) { delete p; }
for (auto p: P) { delete p; }
ParMeshes.clear();
fespaces.clear();
P.clear();
delete fec;
delete fespace;
delete pmesh;
// cout << "Freed memory: " << endl;
// cin.get();
MPI_Finalize();
return 0;
}
//define exact solution
void E_exact(const Vector &x, Vector &E)
{
double curlE[3], curl2E[3];
get_maxwell_solution(x, E, curlE, curl2E);
}
void H_exact(const Vector &x, Vector &H)
{
double E[3], curlE[3], curl2E[3];
get_maxwell_solution(x, E, curlE, curl2E);
for (int i = 0; i<3; i++) { H(i) = curlE[i]/omega; }
}
void f_exact_H(const Vector &x, Vector &f)
{
// curl H - omega E = f
// = curl (curl E / omega) - omega E
f = 0.0;
if (sol !=4)
{
double E[3], curlE[3], curl2E[3];
get_maxwell_solution(x, E, curlE, curl2E);
f(0) = curl2E[0] / omega - omega * E[0];
f(1) = curl2E[1] / omega - omega * E[1];
f(2) = curl2E[2] / omega - omega * E[2];
}
}
void get_maxwell_solution(const Vector &X, double E[], double curlE[],
double curl2E[])
{
double x = X[0];
double y = X[1];
double z = X[2];
if (sol ==-1)
{
E[0] = y * z * (1.0 - y) * (1.0 - z);
E[1] = x * y * z * (1.0 - x) * (1.0 - z);
E[2] = x * y * (1.0 - x) * (1.0 - y);
curlE[0] = -(x-1.0) * x * (y*(2.0*z-3.0)+1.0);
curlE[1] = -2.0*(y-1.0)*y*(x-z);
curlE[2] = (z-1)*z*(1.0+y*(2.0*x-3.0));
curl2E[0] = 2.0 * y * (1.0 - y) - (2.0 * x - 3.0) * z * (1 - z);
curl2E[1] = 2.0 * y * (x * (1.0 - x) + (1.0 - z) * z);
curl2E[2] = 2.0 * y * (1.0 - y) + x * (3.0 - 2.0 * z) * (1.0 - x);
}
else if (sol == 0) // polynomial
{
// Polynomial vanishing on the boundary
E[0] = y * z * (1.0 - y) * (1.0 - z);
E[1] = (1.0 - x) * x * y * (1.0 - z) * z;
E[2] = (1.0 - x) * x * (1.0 - y) * y;
//
curlE[0] = -(-1.0 + x) * x * (1.0 + y * (-3.0 + 2.0 * z));
curlE[1] = -2.0 * (-1.0 + y) * y * (x - z);
curlE[2] = (1.0 + (-3.0 + 2.0 * x) * y) * (-1.0 + z) * z;
curl2E[0] = -2.0 * (-1.0 + y) * y + (-3.0 + 2.0 * x) * (-1.0 + z) * z;
curl2E[1] = -2.0 * y * (-x + x * x + (-1.0 + z) * z);
curl2E[2] = -2.0 * (-1.0 + y) * y + (-1.0 + x) * x * (-3.0 + 2.0 * z);
}
else if (sol == 1) // sinusoidal
{
E[0] = sin(omega * y);
E[1] = sin(omega * z);
E[2] = sin(omega * x);
curlE[0] = -omega * cos(omega * z);
curlE[1] = -omega * cos(omega * x);
curlE[2] = -omega * cos(omega * y);
curl2E[0] = omega * omega * E[0];
curl2E[1] = omega * omega * E[1];
curl2E[2] = omega * omega * E[2];
}
else if (sol == 2) // point source
{
// shift to avoid singularity
double x0 = x + 0.1;
double x1 = y + 0.1;
double x2 = z + 0.1;
//
double r = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
E[0] = cos(omega * r);
E[1] = 0.0;
E[2] = 0.0;
double r_x = x0 / r;
double r_y = x1 / r;
double r_z = x2 / r;
double r_xy = -(r_x / r) * r_y;
double r_xz = -(r_x / r) * r_z;
double r_yx = r_xy;
double r_yy = (1.0 / r) * (1.0 - r_y * r_y);
double r_zx = r_xz;
double r_zz = (1.0 / r) * (1.0 - r_z * r_z);
curlE[0] = 0.0;
curlE[1] = -omega * r_z * sin(omega * r);
curlE[2] = omega * r_y * sin(omega * r);
curl2E[0] = omega * ((r_yy + r_zz) * sin(omega * r) +
(omega * r_y * r_y + omega * r_z * r_z) * cos(omega * r));
curl2E[1] = -omega * (r_yx * sin(omega * r) + omega * r_y * r_x * cos(
omega * r));
curl2E[2] = -omega * (r_zx * sin(omega * r) + omega * r_z * r_x * cos(
omega * r));
}
else if (sol == 3) // plane wave
{
double coeff = omega / sqrt(3.0);
E[0] = cos(coeff * (x + y + z));
E[1] = 0.0;
E[2] = 0.0;
curlE[0] = 0.0;
curlE[1] = -coeff * sin(coeff * (x + y + z));
curlE[2] = coeff * sin(coeff * (x + y + z));
curl2E[0] = 2.0 * coeff * coeff * E[0];
curl2E[1] = -coeff * coeff * E[0];
curl2E[2] = -coeff * coeff * E[0];
}
else if (sol == -1)
{
E[0] = cos(omega * y);
E[1] = 0.0;
curlE[0] = 0.0;
curlE[1] = 0.0;
curlE[2] = -omega * sin(omega * y);
curl2E[0] = omega*omega * cos(omega*y);
curl2E[1] = 0.0;
curl2E[2] = 0.0;
}
else if (sol == 4) // Airy function
{
E[0] = 0;
E[1] = 0;
// double b = -pow(omega/4.0,2.0/3.0)*(4.0*x(0)-1.0);
double b = -pow(omega/4.0,2.0/3.0)*(4.0*x-1.0);
//E[2] = boost::math::airy_ai(b);
E[2] = gsl_sf_airy_Ai(b, GSL_PREC_DOUBLE);
curlE[0] = 0.0;
curlE[1] = 4.0 * pow(omega/4.0,2.0/3.0) * gsl_sf_airy_Ai_deriv(b,
GSL_PREC_DOUBLE);
curlE[2] = 0.0;
// not used
curl2E[0] = 0.0;
curl2E[1] = 0.0;
curl2E[2] = 0.0;
}
}
void epsilon_func(const Vector &x, DenseMatrix &M)
{
M.SetSize(3);
M = 0.0;
M(0,0) = 1.0;
M(1,1) = 1.0;
if (sol != 4)
{
M(2,2) = 1.0;
}
else
{
M(2,2) = 4.0*x(0)-1.0;
// M(2,2) = 2.0;
}
}
void epsilon2_func(const Vector &x, DenseMatrix &M)
{
M.SetSize(3);
M = 0.0;
M(0,0) = 1.0;
M(1,1) = 1.0;
if (sol != 4)
{
M(2,2) = 1.0;
}
else
{
M(2,2) = (4.0*x(0)-1.0) * (4.0*x(0)-1.0);
// M(2,2) = 4.0;
}
}
-915
View File
@@ -1,915 +0,0 @@
// MFEM Example 3 - Parallel Version
//
// Compile with: make ex3p
//
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
// mpirun -np 4 ex3p -m ../data/escher.mesh
// mpirun -np 4 ex3p -m ../data/escher.mesh -o 2
// mpirun -np 4 ex3p -m ../data/fichera.mesh
// mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
// mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
// mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
//
// Description: This example code solves a simple electromagnetic diffusion
// problem corresponding to the second order definite Maxwell
// equation curl curl E + E = f with boundary condition
// E x n = <given tangential field>. Here, we use a given exact
// solution E and compute the corresponding r.h.s. f.
// We discretize with Nedelec finite elements in 2D or 3D.
//
// The example demonstrates the use of H(curl) finite element
// spaces with the curl-curl and the (vector finite element) mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Static condensation is
// also illustrated.
//
// We recommend viewing examples 1-2 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Exact solution, E, and r.h.s., f. See below for implementation.
void E_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
double freq = 1.0, kappa;
int dim;
#define SIGMAVAL -250.0
//#define FORM_DEFINITE
//#define SOLVE_A2
//#define ITER_A2
//#define USE_CSL
//#define USE_HELMHOLTZ
//#define TEST_MULTIPLE_SP
#ifdef USE_HELMHOLTZ
void GetHelmholtzMatrix(ParMesh *pmesh, const int dir, HypreParMatrix *A)
{
const int order = 1;
FiniteElementCollection *fec;
fec = new H1_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
Array<int> ess_tdof_list;
const bool homogeneousBCeverywhere = false;
if (homogeneousBCeverywhere)
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
// Set boundary conditions, depending on dir.
MFEM_VERIFY(dim == 3, "");
for (int i=0; i<pmesh->GetNBE(); ++i)
{
Element *elem = pmesh->GetBdrElement(i);
MFEM_VERIFY(elem->GetNVertices() >= 3, "");
const int *vertices = elem->GetVertices();
double *v[3];
for (int j=0; j<3; ++j)
{
v[j] = pmesh->GetVertex(vertices[j]);
}
double u[3];
double w[3];
for (int j=0; j<3; ++j)
{
u[j] = v[1][j] - v[0][j]; // An edge tangent
w[j] = v[2][j] - v[1][j]; // Another edge tangent, not parallel to u.
}
double n[3]; // normal vector, taken as the cross product u x v
n[0] = (u[1]*w[2]) - (u[2]*w[1]);
n[1] = (u[2]*w[0]) - (u[0]*w[2]);
n[2] = (u[0]*w[1]) - (u[1]*w[0]);
double t = sqrt((n[0]*n[0]) + (n[1]*n[1]) + (n[2]*n[2]));
int d = -1;
for (int j=0; j<3; ++j)
{
n[j] /= t; // normalize
if (fabs(fabs(n[j]) - 1.0) < 1.0e-8)
{
d = j;
}
}
MFEM_VERIFY(d >= 0, "");
if (d != dir) // face has essential BC at all DOF's.
{
elem->SetAttribute(1);
}
else
{
elem->SetAttribute(0);
}
}
Array<int> ess_bdr(2);
ess_bdr = 0;
ess_bdr[1] = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
ParBilinearForm *a = new ParBilinearForm(fespace);
ConstantCoefficient one(1.0);
ConstantCoefficient neg(SIGMAVAL);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
a->AddDomainIntegrator(new MassIntegrator(neg));
ParLinearForm *b = new ParLinearForm(fespace);
ConstantCoefficient zero(0.0);
b->AddDomainIntegrator(new DomainLFIntegrator(zero));
b->Assemble();
bool static_cond = false;
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
ParGridFunction x(fespace);
x = 0.0;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, *A, X, B);
}
#endif
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/beam-tet.mesh";
int order = 2;
bool static_cond = false;
bool visualization = 1;
#ifdef MFEM_USE_STRUMPACK
bool use_strumpack = false;
#endif
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
" solution.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
#ifdef MFEM_USE_STRUMPACK
args.AddOption(&use_strumpack, "-strumpack", "--strumpack-solver",
"-no-strumpack", "--no-strumpack-solver",
"Use STRUMPACK's double complex linear solver.");
#endif
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
kappa = freq * M_PI;
// 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);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
{
int ref_levels =
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
//(int)floor(log(100000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them.
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->ReorientTetMesh();
{
double minsize = pmesh->GetElementSize(0);
double maxsize = minsize;
for (int i=1; i<pmesh->GetNE(); ++i)
{
const double size_i = pmesh->GetElementSize(i);
minsize = std::min(minsize, size_i);
maxsize = std::max(maxsize, size_i);
}
cout << myid << ": Element size range: (" << minsize << ", " << maxsize << ")"
<< endl;
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
long globalNE = pmesh->GetGlobalNE();
if (myid == 0)
{
cout << "Number of mesh elements: " << globalNE << endl;
cout << "Number of finite element unknowns: " << size << endl;
cout << "Root local number of finite element unknowns: " << fespace->TrueVSize()
<< endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
VectorFunctionCoefficient f(sdim, f_exact);
ParLinearForm *b = new ParLinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
VectorFunctionCoefficient E(sdim, E_exact);
x.ProjectCoefficient(E);
// 10. Set up the parallel bilinear form corresponding to the EM diffusion
// operator curl muinv curl + sigma I, by adding the curl-curl and the
// mass domain integrators.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(SIGMAVAL);
Coefficient *sigmaAbs = new ConstantCoefficient(fabs(SIGMAVAL));
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
//cout << myid << ": NBE " << pmesh->GetNBE() << endl;
#ifdef FORM_DEFINITE
ParBilinearForm *adef = new ParBilinearForm(fespace);
adef->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
adef->AddDomainIntegrator(new VectorFEMassIntegrator(*sigmaAbs));
if (static_cond) { adef->EnableStaticCondensation(); }
adef->Assemble();
HypreParMatrix Adef;
Vector Bdef, Xdef;
adef->FormLinearSystem(ess_tdof_list, x, *b, Adef, Xdef, Bdef);
#endif
#ifdef USE_CSL
Vector Bdef, Xdef;
ParBilinearForm *Mform = new ParBilinearForm(fespace);
Mform->AddDomainIntegrator(new VectorFEMassIntegrator(*sigmaAbs));
Mform->Assemble();
// Mform->Finalize();
HypreParMatrix Mmat, Smat, Mcopy;
Mform->FormLinearSystem(ess_tdof_list, x, *b, Mmat, Xdef, Bdef);
Mform->FormLinearSystem(ess_tdof_list, x, *b, Mcopy, Xdef,
Bdef); // There must be a better way than creating two identical matrices.
ParBilinearForm *Sform = new ParBilinearForm(fespace);
Sform->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
Sform->Assemble();
Sform->FormLinearSystem(ess_tdof_list, x, *b, Smat, Xdef, Bdef);
ParBilinearForm *agrad = new ParBilinearForm(fespace);
//agrad->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
agrad->AddDomainIntegrator(new VectorFEMassIntegrator(*muinv));
if (static_cond) { agrad->EnableStaticCondensation(); }
agrad->Assemble();
HypreParMatrix Agrad;
agrad->FormLinearSystem(ess_tdof_list, x, *b, Agrad, Xdef, Bdef);
#endif
#ifdef ITER_A2
Vector Bdef, Xdef;
ParBilinearForm *Mform = new ParBilinearForm(fespace);
Mform->AddDomainIntegrator(new VectorFEMassIntegrator(*sigmaAbs));
Mform->Assemble();
Mform->Finalize();
HypreParMatrix Mmat, Mcopy;
Mform->FormLinearSystem(ess_tdof_list, x, *b, Mmat, Xdef, Bdef);
Mform->FormLinearSystem(ess_tdof_list, x, *b, Mcopy, Xdef,
Bdef); // There must be a better way to implement M^2.
/*
HypreParMatrix *Mmat = Mform->ParallelAssemble();
HypreParMatrix *Mcopy = Mform->ParallelAssemble(); // There must be a better way to implement M^2.
*/
ParBilinearForm *Sform = new ParBilinearForm(fespace);
Sform->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
Sform->Assemble();
HypreParMatrix Smat, Scopy;
Sform->FormLinearSystem(ess_tdof_list, x, *b, Smat, Xdef, Bdef);
Sform->FormLinearSystem(ess_tdof_list, x, *b, Scopy, Xdef, Bdef);
#endif
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
#ifdef SOLVE_A2
HypreParMatrix Acopy;
{
Vector Bdum, Xdum;
a->FormLinearSystem(ess_tdof_list, x, *b, Acopy, Xdum, Bdum);
}
#endif
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
StopWatch chrono;
chrono.Clear();
chrono.Start();
//A.Print("maxwell1000_2");
#ifdef MFEM_USE_STRUMPACK
if (use_strumpack)
{
const bool fullDirect = true;
#ifdef USE_CSL
const double beta1 = 1.0;
const double beta2 = 0.5;
Mmat *= -beta1;
// HypreParMatrix *cslRe = Add(1.0, Smat, -beta1, Mmat);
HypreParMatrix * cslRe = ParAdd(&Smat, &Mmat);
Mcopy *= beta2;
//ComplexHypreParMatrix chpm(cslRe, &Mcopy, false, false);
ComplexHypreParMatrix chpm(&A, &Mcopy, false,
false); // For the case beta1 = 1.
HypreParMatrix *cSysMat = chpm.GetSystemMatrix();
Array<int> block_offsets(3); // number of variables + 1
block_offsets[0] = 0;
block_offsets[1] = fespace->GetVSize();
block_offsets[2] = fespace->GetVSize();
block_offsets.PartialSum();
Array<int> block_trueOffsets(3); // number of variables + 1
block_trueOffsets[0] = 0;
block_trueOffsets[1] = fespace->TrueVSize();
block_trueOffsets[2] = fespace->TrueVSize();
block_trueOffsets.PartialSum();
//cout << myid << ": V size " << fespace->GetVSize() << ", true " << fespace->TrueVSize() << ", global true " << size << ", B size "
//<< B.Size() << ", X size " << X.Size() << endl;
// Note that B is of true size.
BlockVector trueY(block_trueOffsets), trueX(block_trueOffsets),
trueRhs(block_trueOffsets);
trueRhs.GetBlock(0) = B;
trueRhs.GetBlock(1) = 0.0;
Operator * Arow = new STRUMPACKRowLocMatrix(*cSysMat);
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->SetMC64Job(strumpack::MC64Job::NONE);
// strumpack->SetSymmetricPattern(true);
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
#endif
if (fullDirect)
{
#ifdef USE_CSL
//Solver * precond = strumpack;
// strumpack->Mult(B, X);
BlockOperator blockDiagA(block_trueOffsets);
for (int i=0; i<2; ++i)
{
blockDiagA.SetDiagonalBlock(i, &A);
}
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
HypreSolver *amsgrad = new HypreAMS(Agrad, prec_fespace);
#ifdef HYPRE_DYLAN
{
Vector Xtmp(X);
amsgrad->Mult(B,
Xtmp); // Just a hack to get ams to run its setup function. There should be a better way.
}
HypreAMSG *amsg = new HypreAMSG((HypreAMS*) amsgrad, argc, argv);
BlockOperator blockDiagP(block_trueOffsets);
for (int i=0; i<2; ++i)
{
blockDiagP.SetDiagonalBlock(i, amsg);
}
TripleProductOperator strumpackProj(&blockDiagP, strumpack, &blockDiagP, false,
false, false);
ProductOperator prod(&blockDiagA, &strumpackProj, false, false);
#else
ProductOperator prod(&blockDiagA, strumpack, false, false);
#endif
GMRESSolver *gmres = new GMRESSolver(fespace->GetComm());
//BiCGSTABSolver *gmres = new BiCGSTABSolver(fespace->GetComm());
gmres->SetOperator(prod);
gmres->SetRelTol(1e-12);
gmres->SetMaxIter(1000);
gmres->SetPrintLevel(1);
gmres->Mult(trueRhs, trueY);
strumpack->Mult(trueY, trueX);
X = trueX.GetBlock(0);
double xim2 = trueX.GetBlock(1).Norml2();
xim2 *= xim2;
double sumxim2 = 0.0;
MPI_Allreduce(&xim2, &sumxim2, 1, MPI_DOUBLE, MPI_SUM, fespace->GetComm());
if (myid == 0)
{
cout << myid << ": norm of Xim " << trueX.GetBlock(1).Norml2() << ", global " <<
sqrt(sumxim2) << endl;
}
delete gmres;
delete strumpack;
delete Arow;
#else
cout << "Solving with STRUMPACK" << endl;
#ifdef TEST_MULTIPLE_SP
const int Ns = 2;
std::vector<Operator*> Arows(Ns);
std::vector<STRUMPACKSolver*> strumpacks(Ns);
//Operator * Arow = new STRUMPACKRowLocMatrix(A);
for (int m=0; m<Ns; ++m)
{
Arows[m] = new STRUMPACKRowLocMatrix(A);
//STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv, MPI_COMM_WORLD);
strumpacks[m] = new STRUMPACKSolver(argc, argv, MPI_COMM_WORLD);
strumpacks[m]->SetPrintFactorStatistics(true);
strumpacks[m]->SetPrintSolveStatistics(false);
strumpacks[m]->SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
strumpacks[m]->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
// strumpack->SetMC64Job(strumpack::MC64Job::NONE);
// strumpack->SetSymmetricPattern(true);
strumpacks[m]->SetOperator(*Arows[m]);
strumpacks[m]->SetFromCommandLine();
//Solver * precond = strumpack;
strumpacks[m]->Mult(B, X);
//delete strumpack;
//delete Arow;
}
#else
Operator * Arow = new STRUMPACKRowLocMatrix(A);
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->SetMC64Job(strumpack::MC64Job::NONE);
// strumpack->SetSymmetricPattern(true);
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
//Solver * precond = strumpack;
cout << "Solving with strumpack one time" << endl;
strumpack->Mult(B, X);
delete strumpack;
delete Arow;
#endif
#endif
}
else
{
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
HypreSolver *ams = new HypreAMS(A, prec_fespace);
#ifdef HYPRE_DYLAN
{
Vector Xtmp(X);
ams->Mult(B,
Xtmp); // Just a hack to get ams to run its setup function. There should be a better way.
}
HypreParMatrix H[3];
#ifdef USE_HELMHOLTZ
for (int i=0; i<3; ++i)
{
GetHelmholtzMatrix(pmesh, i, &(H[i]));
}
#endif
#ifdef USE_CSL
HypreIAMS *iams = new HypreIAMS(A, H, strumpack, &trueX, &trueY,
(HypreAMS*) ams, argc, argv);
#else
HypreIAMS *iams = new HypreIAMS(A, H, strumpack, NULL, NULL, (HypreAMS*) ams,
argc, argv);
#endif
GMRESSolver *gmres = new GMRESSolver(fespace->GetComm());
//FGMRESSolver *gmres = new FGMRESSolver(fespace->GetComm());
//BiCGSTABSolver *gmres = new BiCGSTABSolver(fespace->GetComm());
//MINRESSolver *gmres = new MINRESSolver(fespace->GetComm());
gmres->SetOperator(A);
gmres->SetRelTol(1e-16);
gmres->SetMaxIter(1000);
gmres->SetPrintLevel(1);
#ifdef SOLVE_A2
{
StopWatch chronoA2;
chronoA2.Clear();
chronoA2.Start();
HypreParMatrix * A2 = ParMult(&A, &Acopy);
chronoA2.Stop();
cout << "A2 setup time " << chronoA2.RealTime() << endl;
Vector AB(B);
A.Mult(B, AB);
gmres->SetOperator(*A2);
HypreSolver *ams2 = new HypreAMS(A, prec_fespace);
{
Vector Xtmp(X);
ams2->Mult(B,
Xtmp); // Just a hack to get ams to run its setup function. There should be a better way.
}
#ifdef ITER_A2
// Iteratively solve 0.5 (A^2 + S^2 + M^2) u^{k+1} = 0.5 (SM + MS) u^k + Ab
StopWatch chronoIterA2;
chronoIterA2.Clear();
chronoIterA2.Start();
HypreParMatrix * M2 = ParMult(&Mmat, &Mcopy);
HypreParMatrix * S2 = ParMult(&Smat, &Scopy);
HypreParMatrix * MS = ParMult(&Mmat, &Scopy);
HypreParMatrix * SM = ParMult(&Smat, &Mcopy);
HypreParMatrix * Bmat = ParAdd(SM, MS);
(*Bmat) *= 0.5;
// TODO: there must be a better way to form a sum of three matrices. Of course, we could define an operator that does 3 mat-vecs.
//HypreParMatrix * S2M2 = ParAdd(S2, M2);
//HypreParMatrix * iterMat = ParAdd(A2, S2M2);
HypreParMatrix * iterMat = ParAdd(A2, Bmat);
chronoIterA2.Stop();
cout << "Iter A2 setup time " << chronoIterA2.RealTime() << endl;
/*
HypreSolver *ams3 = new HypreAMS(*iterMat, prec_fespace);
{
Vector Xtmp(X);
ams3->Mult(B, Xtmp); // Just a hack to get ams to run its setup function. There should be a better way.
}
*/
/*
// GMRES
gmres->SetOperator(*iterMat);
gmres->SetPreconditioner(*ams2);
*/
//HypreBoomerAMG *amg = new HypreBoomerAMG(*iterMat);
HypreBoomerAMG *amg = new HypreBoomerAMG(*A2);
// PCG
HyprePCG *pcg = new HyprePCG(*iterMat);
//HyprePCG *pcg = new HyprePCG(*A2);
pcg->SetTol(1e-12);
pcg->SetMaxIter(10);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*amg);
/*
// Strumpack linear solver
Operator * Arow = new STRUMPACKRowLocMatrix(*iterMat);
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->SetOperator(*Arow);
strumpack->SetFromCommandLine();
*/
Vector iterRHS(AB);
Vector iterU(AB);
Vector iterU0(AB);
iterU = 0.0;
iterU0 = 0.0;
bool iterate = true;
int numIter = 0;
while (iterate)
{
iterRHS = iterU;
iterRHS.Add(-1.0, iterU0);
cout << "Iteration " << numIter + 1 << ": diff norm " << iterRHS.Norml2() <<
endl;
iterU0 = iterU;
Bmat->Mult(iterU0, iterRHS);
//iterRHS.Add(2.0, AB);
iterRHS.Add(1.0, AB);
//gmres->Mult(iterRHS, iterU);
pcg->Mult(iterRHS, iterU);
//strumpack->Mult(iterRHS, iterU);
numIter++;
if (numIter > 100)
{
iterate = false;
}
}
//delete strumpack;
//delete Arow;
delete pcg;
X = iterU;
#else
//HypreIAMS *iams2 = new HypreIAMS(*A2, (HypreAMS*) ams2, argc, argv);
//gmres->SetPreconditioner(*iams2);
cout << myid << ": Solving" << endl;
gmres->SetPreconditioner(*ams2);
gmres->Mult(AB, X);
cout << myid << ": Solved" << endl;
return 3;
#endif
}
#else
gmres->SetPreconditioner(*iams);
gmres->Mult(B, X);
#endif
#else
HypreGMRES *gmres = new HypreGMRES(A);
gmres->SetTol(1e-12);
gmres->SetMaxIter(100);
gmres->SetPrintLevel(10);
#ifdef FORM_DEFINITE
HypreSolver *amsdef = new HypreAMS(Adef, prec_fespace);
gmres->SetPreconditioner(*amsdef);
#else
gmres->SetPreconditioner(*ams);
#endif
gmres->Mult(B, X);
#endif
delete gmres;
//delete iams;
//delete ams;
}
}
else
#endif
{
// 12. Define and apply a parallel PCG solver for AX=B with the AMS
// preconditioner from hypre.
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
HypreSolver *ams = new HypreAMS(A, prec_fespace);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*ams);
pcg->Mult(B, X);
delete pcg;
delete ams;
}
chrono.Stop();
cout << myid << ": Solver time " << chrono.RealTime() << endl;
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(E);
Vector zeroVec(3);
zeroVec = 0.0;
VectorConstantCoefficient vzero(zeroVec);
ParGridFunction zerogf(fespace);
zerogf = 0.0;
double normE = zerogf.ComputeL2Error(E);
double normX = x.ComputeL2Error(vzero);
if (myid == 0)
{
cout << "|| E_h - E ||_{L^2} = " << err << endl;
cout << "|| E_h ||_{L^2} = " << normX << endl;
cout << "|| E ||_{L^2} = " << normE << endl;
}
}
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
delete a;
delete sigma;
delete muinv;
delete b;
delete fespace;
delete fec;
delete pmesh;
MPI_Finalize();
return 0;
}
void E_exact(const Vector &x, Vector &E)
{
if (dim == 3)
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(2));
E(2) = sin(kappa * x(0));
}
else
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(0));
if (x.Size() == 3) { E(2) = 0.0; }
}
}
void f_exact(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = (SIGMAVAL + kappa * kappa) * sin(kappa * x(1));
f(1) = (SIGMAVAL + kappa * kappa) * sin(kappa * x(2));
f(2) = (SIGMAVAL + kappa * kappa) * sin(kappa * x(0));
}
else
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
if (x.Size() == 3) { f(2) = 0.0; }
}
}
+3 -8
View File
@@ -108,11 +108,7 @@ int main(int argc, char *argv[])
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
// problem yet, this will be done in the main loop.
BilinearForm a(&fespace);
if (pa)
{
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a.SetDiagonalPolicy(Operator::DIAG_ONE);
}
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
LinearForm b(&fespace);
ConstantCoefficient one(1.0);
@@ -203,10 +199,9 @@ int main(int argc, char *argv[])
umf_solver.Mult(B, X);
#endif
}
else // Diagonal preconditioning in partial assembly mode.
else // No preconditioning for now in partial assembly mode.
{
OperatorJacobiSmoother M(a, ess_tdof_list);
PCG(*A, M, B, X, 3, 2000, 1e-12, 0.0);
CG(*A, B, X, 3, 2000, 1e-12, 0.0);
}
// 18. After solving the linear system, reconstruct the solution as a
+6 -19
View File
@@ -129,11 +129,7 @@ int main(int argc, char *argv[])
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
// problem yet, this will be done in the main loop.
ParBilinearForm a(&fespace);
if (pa)
{
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a.SetDiagonalPolicy(Operator::DIAG_ONE);
}
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
ParLinearForm b(&fespace);
ConstantCoefficient one(1.0);
@@ -224,26 +220,17 @@ int main(int argc, char *argv[])
// 17. Solve the linear system A X = B.
// * With full assembly, use the BoomerAMG preconditioner from hypre.
// * With partial assembly, use a diagonal preconditioner.
Solver *M = NULL;
if (pa)
{
M = new OperatorJacobiSmoother(a, ess_tdof_list);
}
else
{
HypreBoomerAMG *amg = new HypreBoomerAMG;
amg->SetPrintLevel(0);
M = amg;
}
// * With partial assembly, use no preconditioner, for now.
HypreBoomerAMG *amg = NULL;
if (!pa) { amg = new HypreBoomerAMG; amg->SetPrintLevel(0); }
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-6);
cg.SetMaxIter(2000);
cg.SetPrintLevel(3); // print the first and the last iterations only
cg.SetPreconditioner(*M);
if (amg) { cg.SetPreconditioner(*amg); }
cg.SetOperator(*A);
cg.Mult(B, X);
delete M;
delete amg;
// 18. Switch back to the host and extract the parallel grid function
// corresponding to the finite element approximation X. This is the
-517
View File
@@ -1,517 +0,0 @@
#pragma once
#include "mfem.hpp"
using namespace std;
namespace mfem
{
STRUMPACKSolver* CreateStrumpackSolver(Operator *Arow, MPI_Comm comm)
{
//STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv, comm);
STRUMPACKSolver * strumpack = new STRUMPACKSolver(0, NULL, comm);
strumpack->SetPrintFactorStatistics(true);
strumpack->SetPrintSolveStatistics(false);
strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
return strumpack;
}
hypre_CSRMatrix* GetHypreParMatrixData(const HypreParMatrix & hypParMat)
{
// First cast the parameter to a hypre_ParCSRMatrix
hypre_ParCSRMatrix * parcsr_op =
(hypre_ParCSRMatrix *)const_cast<HypreParMatrix&>(hypParMat);
MFEM_ASSERT(parcsr_op != NULL,"STRUMPACK: const_cast failed in SetOperator");
// Create the CSRMatrixMPI A_ by borrowing the internal data from a hypre_CSRMatrix.
return hypre_MergeDiagAndOffd(parcsr_op);
}
// Row and column offsets are assumed to be the same, for each process.
// Array offsets stores process-local offsets with respect to the blocks. Process offsets are not included.
HypreParMatrix* CreateHypreParMatrixFromBlocks(MPI_Comm comm,
Array<int> const& offsets, Array2D<HypreParMatrix*> const& blocks,
Array2D<SparseMatrix*> const& blocksSp,
Array2D<double> const& coefficient,
std::vector<std::vector<int> > const& blockProcOffsets,
std::vector<std::vector<int> > const& all_block_num_loc_rows)
{
const int numBlocks = offsets.Size() - 1;
const int num_loc_rows = offsets[numBlocks];
int nprocs, rank;
MPI_Comm_rank(comm, &rank);
MPI_Comm_size(comm, &nprocs);
std::vector<int> all_num_loc_rows(nprocs);
std::vector<int> procOffsets(nprocs);
std::vector<std::vector<int> > procBlockOffsets(nprocs);
MPI_Allgather(&num_loc_rows, 1, MPI_INT, all_num_loc_rows.data(), 1, MPI_INT,
comm);
int first_loc_row = 0;
int glob_nrows = 0;
procOffsets[0] = 0;
for (int i=0; i<nprocs; ++i)
{
glob_nrows += all_num_loc_rows[i];
if (i < rank)
{
first_loc_row += all_num_loc_rows[i];
}
if (i < nprocs-1)
{
procOffsets[i+1] = procOffsets[i] + all_num_loc_rows[i];
}
if (numBlocks > 0)
{
procBlockOffsets[i].resize(numBlocks);
procBlockOffsets[i][0] = 0;
}
for (int j=1; j<numBlocks; ++j)
{
procBlockOffsets[i][j] = procBlockOffsets[i][j-1] + all_block_num_loc_rows[j
-1][i];
}
}
const int glob_ncols = glob_nrows;
std::vector<int> opI(num_loc_rows+1);
std::vector<int> cnt(num_loc_rows);
for (int i=0; i<num_loc_rows; ++i)
{
opI[i] = 0;
cnt[i] = 0;
}
opI[num_loc_rows] = 0;
Array2D<hypre_CSRMatrix*> csr_blocks(numBlocks, numBlocks);
// Loop over all blocks, to determine nnz for each row.
for (int i=0; i<numBlocks; ++i)
{
for (int j=0; j<numBlocks; ++j)
{
if (blocks(i, j) == NULL)
{
csr_blocks(i, j) = NULL;
if (blocksSp(i, j) != NULL)
{
const int nrows = blocksSp(i, j)->Height();
for (int k=0; k<nrows; ++k)
{
const int rowg = offsets[i] + k;
opI[rowg + 1] += blocksSp(i, j)->GetI()[k+1] - blocksSp(i, j)->GetI()[k];
}
}
}
else
{
MFEM_VERIFY(blocksSp(i, j) == NULL, "");
csr_blocks(i, j) = GetHypreParMatrixData(*(blocks(i, j)));
const int nrows = csr_blocks(i, j)->num_rows;
for (int k=0; k<nrows; ++k)
{
const int rowg = offsets[i] + k;
//(*(leftInjection(i, j)))[k]
opI[rowg + 1] += csr_blocks(i, j)->i[k+1] - csr_blocks(i, j)->i[k];
}
}
}
}
// Now opI[i] is nnz for row i-1. Do a partial sum to get offsets.
for (int i=0; i<num_loc_rows; ++i)
{
opI[i+1] += opI[i];
}
const int nnz = opI[num_loc_rows];
std::vector<HYPRE_Int> opJ(nnz);
std::vector<double> data(nnz);
// Loop over all blocks, to set matrix data.
for (int i=0; i<numBlocks; ++i)
{
for (int j=0; j<numBlocks; ++j)
{
if (csr_blocks(i, j) != NULL || blocksSp(i, j) != NULL)
{
const bool useCSR = (csr_blocks(i, j) != NULL);
const int nrows = useCSR ? csr_blocks(i, j)->num_rows : blocksSp(i,
j)->Height();
const double coef = coefficient(i, j);
int *Iarray = useCSR ? csr_blocks(i, j)->i : blocksSp(i, j)->GetI();
//const bool failure = (nrows != offsets[i+1] - offsets[i]);
MFEM_VERIFY(nrows == offsets[i+1] - offsets[i], "");
for (int k=0; k<nrows; ++k)
{
const int rowg = offsets[i] + k; // process-local row
const int nnz_k = Iarray[k+1] - Iarray[k];
const int osk = Iarray[k];
for (int l=0; l<nnz_k; ++l)
{
// Find the column process offset for the block.
const int bcol = useCSR ? csr_blocks(i, j)->j[osk + l] : blocksSp(i,
j)->GetJ()[osk + l];
int bcolproc = 0;
for (int p=1; p<nprocs; ++p)
{
if (blockProcOffsets[j][p] > bcol)
{
bcolproc = p-1;
break;
}
}
if (blockProcOffsets[j][nprocs - 1] <= bcol)
{
bcolproc = nprocs - 1;
}
const int colg = procOffsets[bcolproc] + procBlockOffsets[bcolproc][j] +
(bcol - blockProcOffsets[j][bcolproc]);
if (colg < 0)
{
cout << "BUG, negative global column index" << endl;
}
opJ[opI[rowg] + cnt[rowg]] = colg;
data[opI[rowg] + cnt[rowg]] = useCSR ? coef * csr_blocks(i,
j)->data[osk + l] : coef * blocksSp(i, j)->GetData()[osk + l];
cnt[rowg]++;
}
}
}
}
}
bool cntCheck = true;
for (int i=0; i<num_loc_rows; ++i)
{
if (cnt[i] != opI[i+1] - opI[i])
{
cntCheck = false;
}
}
MFEM_VERIFY(cntCheck, "");
for (int i=0; i<numBlocks; ++i)
{
for (int j=0; j<numBlocks; ++j)
{
if (csr_blocks(i, j) != NULL)
{
hypre_CSRMatrixDestroy(csr_blocks(i, j));
}
}
}
std::vector<HYPRE_Int> rowStarts2(2);
rowStarts2[0] = first_loc_row;
rowStarts2[1] = first_loc_row + all_num_loc_rows[rank];
if (nnz > 0)
{
HYPRE_Int minJ = opJ[0];
HYPRE_Int maxJ = opJ[0];
for (int i=0; i<nnz; ++i)
{
minJ = std::min(minJ, opJ[i]);
maxJ = std::max(maxJ, opJ[i]);
if (opJ[i] >= glob_ncols)
{
cout << "Column indices out of range" << endl;
}
}
}
HypreParMatrix *hmat = new HypreParMatrix(comm, num_loc_rows, glob_nrows,
glob_ncols, (int*) opI.data(), (HYPRE_Int*) opJ.data(), (double*) data.data(),
(HYPRE_Int*) rowStarts2.data(), (HYPRE_Int*) rowStarts2.data());
return hmat;
}
class BlockMGSolver : public Solver
{
private:
/// The linear system matrix
Array2D<HypreParMatrix *>&
Af; // TODO: remove this, as it is used only in the constructor
Array2D<double>&
Acoef; // TODO: remove this, as it is used only in the constructor
vector<Array<int>> Aoffsets;
vector<Array<int>> Poffsets_i;
vector<Array<int>> Poffsets_j;
std::vector<Array2D<HypreParMatrix *>> A;
std::vector<HypreParMatrix *>& P;
std::vector<BlockOperator *> BlkP;
std::vector<BlockOperator *> BlkA;
std::vector<BlockOperator *> S;
HypreParMatrix * Ac;
int numGrids, numBlocks;
STRUMPACKSolver *invAc = nullptr;
double theta = 0.5;
public:
BlockMGSolver(const int height, const int width, Array2D<HypreParMatrix *>& Af_,
Array2D<double>& Acoef_, std::vector<HypreParMatrix *>& P_);
virtual void SetOperator(const Operator &op) {}
virtual void SetTheta(const double a) { theta = a; }
virtual void Mult(const Vector &r, Vector &z) const;
virtual ~BlockMGSolver();
};
BlockMGSolver::BlockMGSolver(const int height, const int width,
Array2D<HypreParMatrix *>& Af_, Array2D<double>& Acoef_,
std::vector<HypreParMatrix *>& P_)
: Solver(height, width), Af(Af_), Acoef(Acoef_), P(P_)
{
numBlocks = Af.NumRows();
MFEM_VERIFY(Af.NumCols() == numBlocks, "");
numGrids = P.size();
BlkP.resize(numGrids);
BlkA.resize(numGrids+1);
S.resize(numGrids);
A.resize(numGrids + 1);
A[numGrids] = Af;
Aoffsets.resize(numGrids+1);
Poffsets_i.resize(numGrids);
Poffsets_j.resize(numGrids);
// Construct Bilinear form Matrices on each level
for (int k = numGrids ; k > 0; k--)
{
A[k - 1].SetSize(numBlocks,numBlocks);
Aoffsets[k].SetSize(numBlocks+1); Aoffsets[k][0] = 0;
for (int i=0; i<numBlocks; i++)
{
Aoffsets[k][i+1] = A[k](i,i)->Height();
}
Aoffsets[k].PartialSum();
BlkA[k] = new BlockOperator(Aoffsets[k]);
S[k-1] = new BlockOperator(Aoffsets[k]); // Smoother
for (int i=0; i<numBlocks; i++)
{
for (int j=0; j<numBlocks; j++)
{
if (A[k](i,j) == NULL)
{
A[k - 1](i,j) = NULL;
}
else
{
A[k - 1](i,j) = RAP(A[k](i,j), P[k - 1]);
BlkA[k]->SetBlock(i, j, A[k](i,j), Acoef(i,j));
}
}
HypreSmoother *S_i = new HypreSmoother;
S_i->SetType(HypreSmoother::Jacobi);
S_i->SetOperator(*(A[k](i,i)));
S[k - 1]->SetBlock(i,i,S_i);
}
Poffsets_i[k-1].SetSize(numBlocks+1); Poffsets_i[k-1][0] = 0;
Poffsets_j[k-1].SetSize(numBlocks+1); Poffsets_j[k-1][0] = 0;
for (int i=0; i<numBlocks; i++)
{
Poffsets_i[k-1][i+1] = P[k-1]->Height();
Poffsets_j[k-1][i+1] = P[k-1]->Width();
}
Poffsets_i[k-1].PartialSum();
Poffsets_j[k-1].PartialSum();
BlkP[k-1] = new BlockOperator(Poffsets_i[k-1],Poffsets_j[k-1]);
for (int i=0; i<numBlocks; i++)
{
BlkP[k-1]->SetBlock(i,i,P[k-1]);
}
}
// Set up coarse solve operator
// Convert the coarse grid blockmatrix to a HypreParMatrix
Array<int> offsets(numBlocks+1);
offsets[0]=0;
for (int i=0; i<numBlocks; i++)
{
offsets[i+1]=A[0](i,i)->Height();
}
offsets.PartialSum();
BlkA[0] = new BlockOperator(offsets);
Array2D<SparseMatrix*> Asp;
//Array2D<double> Acoef;
Asp.SetSize(numBlocks,numBlocks);
//Acoef.SetSize(numBlocks,numBlocks);
for (int i=0; i<numBlocks; i++)
{
for (int j=0; j<numBlocks; j++)
{
if (A[0](i,j) != NULL)
{
BlkA[0]->SetBlock(i, j, A[0](i,j), Acoef(i,j));
}
Asp(i,j) = NULL;
//Acoef(i,j) = 1.0;
}
}
// Convert to HypreParMatrix
HypreParMatrix * Ac;
std::vector<std::vector<int> > blockProcOffsets(numBlocks);
std::vector<std::vector<int> > all_block_num_loc_rows(numBlocks);
{
int nprocs, rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
std::vector<int> allnumrows(nprocs);
const int blockNumRows = A[0](0,0)->Height();
MPI_Allgather(&blockNumRows, 1, MPI_INT, allnumrows.data(), 1, MPI_INT,
MPI_COMM_WORLD);
for (int b=0; b<numBlocks; ++b)
{
blockProcOffsets[b].resize(nprocs);
all_block_num_loc_rows[b].resize(nprocs);
}
blockProcOffsets[0][0] = 0;
for (int i=0; i<nprocs-1; ++i)
{
blockProcOffsets[0][i+1] = blockProcOffsets[0][i] + allnumrows[i];
}
for (int i=0; i<nprocs; ++i)
{
for (int b=0; b<numBlocks; ++b)
{
all_block_num_loc_rows[b][i] = allnumrows[i];
}
for (int b=1; b<numBlocks; ++b)
{
blockProcOffsets[b][i] = blockProcOffsets[0][i];
}
}
}
Ac = CreateHypreParMatrixFromBlocks(MPI_COMM_WORLD, offsets, A[0], Asp,
Acoef, blockProcOffsets, all_block_num_loc_rows);
invAc = CreateStrumpackSolver(new STRUMPACKRowLocMatrix(*Ac), MPI_COMM_WORLD);
delete Ac;
}
void BlockMGSolver::Mult(const Vector &r, Vector &z) const
{
// Residual vectors
std::vector<Vector> rv(numGrids + 1);
// correction vectors
std::vector<Vector> zv(numGrids + 1);
// allocation
for (int i = 0; i <= numGrids ; i++)
{
int n = (i==0) ? invAc->Height(): BlkA[i]->Width();
rv[i].SetSize(n);
zv[i].SetSize(n);
}
// Initial residual
rv[numGrids] = r;
// smooth and update residuals down to the coarsest level
for (int i = numGrids; i > 0 ; i--)
{
// Pre smooth
S[i - 1]->Mult(rv[i], zv[i]); zv[i] *= theta;
// compute residual
int n = BlkA[i]->Width();
Vector w(n);
BlkA[i]->Mult(zv[i], w);
rv[i] -= w;
// Restrict
BlkP[i - 1]->MultTranspose(rv[i], rv[i - 1]);
}
// Coarse grid Solve
invAc->Mult(rv[0], zv[0]);
//
for (int i = 1; i <= numGrids ; i++)
{
// Prolong correction
Vector u(BlkP[i - 1]->Height());
BlkP[i - 1]->Mult(zv[i - 1], u);
// Update correction
zv[i] += u;
// Update residual
Vector v(BlkA[i]->Height());
BlkA[i]->Mult(u, v); rv[i] -= v;
// Post smooth
S[i - 1]->Mult(rv[i], v); v *= theta;
// Update correction
zv[i] += v;
}
z = zv[numGrids];
}
BlockMGSolver::~BlockMGSolver()
{
for (int i = numGrids - 1; i >= 0 ; i--)
{
delete S[i];
delete BlkP[i];
delete BlkA[i];
for (int j=0; j<numBlocks; j++)
{
for (int k=0; k<numBlocks; k++)
{
delete A[i](j,k);
}
}
A[i].DeleteAll();
}
delete BlkA[numGrids];
delete invAc;
A.clear();
}
} // namespace mfem
-869
View File
@@ -1,869 +0,0 @@
#ifndef BGMULTIGRID
#define BGMULTIGRID
#include "mfem.hpp"
using namespace std;
//namespace mfem {
namespace blockgmg
{
// Row and column offsets are assumed to be the same, for each process.
// Array offsets stores process-local offsets with respect to the blocks. Process offsets are not included.
HypreParMatrix* CreateHypreParMatrixFromBlocks2(MPI_Comm comm,
Array<int> const& offsets, Array2D<HypreParMatrix*> const& blocks,
Array2D<SparseMatrix*> const& blocksSp,
Array2D<double> const& coefficient,
std::vector<std::vector<int> > const& blockProcOffsets,
std::vector<std::vector<int> > const& all_block_num_loc_rows);
class BlockMGSolver : public Solver
{
private:
/// The linear system matrix
Array2D<HypreParMatrix *>&
Af; // TODO: remove this, as it is used only in the constructor
Array2D<double>&
Acoef; // TODO: remove this, as it is used only in the constructor
vector<Array<int>> Aoffsets;
vector<Array<int>> Poffsets_i;
vector<Array<int>> Poffsets_j;
std::vector<Array2D<HypreParMatrix *>> A;
std::vector<HypreParMatrix *> const& P;
std::vector<BlockOperator *> BlkP;
std::vector<BlockOperator *> BlkA;
std::vector<BlockOperator *> S;
HypreParMatrix * Ac;
SparseMatrix AcSp;
int numGrids, numBlocks;
//STRUMPACKSolver *invAc = nullptr;
Operator *invAc = nullptr;
double theta = 0.5;
public:
BlockMGSolver(MPI_Comm comm, const int height, const int width,
Array2D<HypreParMatrix *>& Af_,
Array2D<double>& Acoef_, std::vector<HypreParMatrix *> const& P_)
: Solver(height, width), Af(Af_), Acoef(Acoef_), P(P_)
{
numBlocks = Af.NumRows();
MFEM_VERIFY(Af.NumCols() == numBlocks, "");
numGrids = P.size();
BlkP.resize(numGrids);
BlkA.resize(numGrids+1);
S.resize(numGrids);
A.resize(numGrids + 1);
A[numGrids] = Af;
Aoffsets.resize(numGrids+1);
Poffsets_i.resize(numGrids);
Poffsets_j.resize(numGrids);
// Construct Bilinear form Matrices on each level
for (int k = numGrids ; k > 0; k--)
{
A[k - 1].SetSize(numBlocks,numBlocks);
Aoffsets[k].SetSize(numBlocks+1); Aoffsets[k][0] = 0;
for (int i=0; i<numBlocks; i++)
{
Aoffsets[k][i+1] = A[k](i,i)->Height();
}
Aoffsets[k].PartialSum();
BlkA[k] = new BlockOperator(Aoffsets[k]);
S[k-1] = new BlockOperator(Aoffsets[k]); // Smoother
for (int i=0; i<numBlocks; i++)
{
for (int j=0; j<numBlocks; j++)
{
if (A[k](i,j) == NULL)
{
A[k - 1](i,j) = NULL;
}
else
{
A[k - 1](i,j) = RAP(A[k](i,j), P[k - 1]);
BlkA[k]->SetBlock(i, j, A[k](i,j), Acoef(i,j));
}
}
HypreSmoother *S_i = new HypreSmoother;
S_i->SetType(HypreSmoother::Jacobi);
S_i->SetOperator(*(A[k](i,i)));
S[k - 1]->SetBlock(i,i,S_i);
}
Poffsets_i[k-1].SetSize(numBlocks+1); Poffsets_i[k-1][0] = 0;
Poffsets_j[k-1].SetSize(numBlocks+1); Poffsets_j[k-1][0] = 0;
for (int i=0; i<numBlocks; i++)
{
Poffsets_i[k-1][i+1] = P[k-1]->Height();
Poffsets_j[k-1][i+1] = P[k-1]->Width();
}
Poffsets_i[k-1].PartialSum();
Poffsets_j[k-1].PartialSum();
BlkP[k-1] = new BlockOperator(Poffsets_i[k-1],Poffsets_j[k-1]);
for (int i=0; i<numBlocks; i++)
{
BlkP[k-1]->SetBlock(i,i,P[k-1]);
}
}
// Set up coarse solve operator
// Convert the coarse grid blockmatrix to a HypreParMatrix
Array<int> offsets(numBlocks+1);
offsets[0]=0;
for (int i=0; i<numBlocks; i++)
{
offsets[i+1]=A[0](i,i)->Height();
}
offsets.PartialSum();
BlkA[0] = new BlockOperator(offsets);
Array2D<SparseMatrix*> Asp;
//Array2D<double> Acoef;
Asp.SetSize(numBlocks,numBlocks);
//Acoef.SetSize(numBlocks,numBlocks);
for (int i=0; i<numBlocks; i++)
{
for (int j=0; j<numBlocks; j++)
{
if (A[0](i,j) != NULL)
{
BlkA[0]->SetBlock(i, j, A[0](i,j), Acoef(i,j));
}
Asp(i,j) = NULL;
//Acoef(i,j) = 1.0;
}
}
// Convert to HypreParMatrix
//HypreParMatrix * Ac;
std::vector<std::vector<int> > blockProcOffsets(numBlocks);
std::vector<std::vector<int> > all_block_num_loc_rows(numBlocks);
{
int nprocs, rank;
MPI_Comm_rank(comm, &rank);
MPI_Comm_size(comm, &nprocs);
std::vector<int> allnumrows(nprocs);
const int blockNumRows = A[0](0,
0)->Height(); // TODO: Not valid if blocks are of different size
MPI_Allgather(&blockNumRows, 1, MPI_INT, allnumrows.data(), 1, MPI_INT, comm);
for (int b=0; b<numBlocks; ++b)
{
blockProcOffsets[b].resize(nprocs);
all_block_num_loc_rows[b].resize(nprocs);
}
blockProcOffsets[0][0] = 0;
for (int i=0; i<nprocs-1; ++i)
{
blockProcOffsets[0][i+1] = blockProcOffsets[0][i] + allnumrows[i];
}
for (int i=0; i<nprocs; ++i)
{
for (int b=0; b<numBlocks; ++b)
{
all_block_num_loc_rows[b][i] = allnumrows[i];
}
for (int b=1; b<numBlocks; ++b)
{
blockProcOffsets[b][i] = blockProcOffsets[0][i];
}
}
}
Ac = CreateHypreParMatrixFromBlocks2(comm, offsets, A[0], Asp,
Acoef, blockProcOffsets, all_block_num_loc_rows);
#ifdef MFEM_USE_STRUMPACK
invAc = CreateStrumpackSolver(new STRUMPACKRowLocMatrix(*Ac), comm);
delete Ac;
#else
Ac->GetDiag(AcSp); // AcSp does not own the data
UMFPackSolver *umf_solver = new UMFPackSolver();
umf_solver->Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver->SetOperator(AcSp);
invAc = umf_solver;
#endif
}
virtual void SetOperator(const Operator &op) {}
virtual void SetTheta(const double a) { theta = a; }
virtual void Mult(const Vector &r, Vector &z) const
{
// Residual vectors
std::vector<Vector> rv(numGrids + 1);
// correction vectors
std::vector<Vector> zv(numGrids + 1);
// allocation
for (int i = 0; i <= numGrids ; i++)
{
int n = (i==0) ? invAc->Height(): BlkA[i]->Width();
rv[i].SetSize(n);
zv[i].SetSize(n);
}
// Initial residual
rv[numGrids] = r;
// smooth and update residuals down to the coarsest level
for (int i = numGrids; i > 0 ; i--)
{
// Pre smooth
S[i - 1]->Mult(rv[i], zv[i]); zv[i] *= theta;
// compute residual
int n = BlkA[i]->Width();
Vector w(n);
BlkA[i]->Mult(zv[i], w);
rv[i] -= w;
// Restrict
BlkP[i - 1]->MultTranspose(rv[i], rv[i - 1]);
}
// Coarse grid Solve
invAc->Mult(rv[0], zv[0]);
//
for (int i = 1; i <= numGrids ; i++)
{
// Prolong correction
Vector u(BlkP[i - 1]->Height());
BlkP[i - 1]->Mult(zv[i - 1], u);
// Update correction
zv[i] += u;
// Update residual
Vector v(BlkA[i]->Height());
BlkA[i]->Mult(u, v); rv[i] -= v;
// Post smooth
S[i - 1]->Mult(rv[i], v); v *= theta;
// Update correction
zv[i] += v;
}
z = zv[numGrids];
}
virtual ~BlockMGSolver()
{
for (int i = numGrids - 1; i >= 0 ; i--)
{
delete S[i];
delete BlkP[i];
delete BlkA[i];
for (int j=0; j<numBlocks; j++)
{
for (int k=0; k<numBlocks; k++)
{
delete A[i](j,k);
}
}
A[i].DeleteAll();
}
delete BlkA[numGrids];
delete invAc;
A.clear();
}
#ifdef MFEM_USE_STRUMPACK
STRUMPACKSolver* CreateStrumpackSolver(Operator *Arow, MPI_Comm comm)
{
//STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv, comm);
STRUMPACKSolver * strumpack = new STRUMPACKSolver(0, NULL, comm);
strumpack->SetPrintFactorStatistics(true);
strumpack->SetPrintSolveStatistics(false);
strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
return strumpack;
}
#endif
};
#define SWTIMING
#define SERIAL_PROLONGATION
#define ITERATIVE_COARSE_SOLVE
#define SPARSE_JACOBI
//#define SPARSE_ICHOLESKY
//#define SPARSE_ILU
//#define COARSE_PA
//#define BLOCK_DIAG
//#define COARSE_AMS
class BlockMGPASolver : public Solver
{
private:
/// The linear system matrix
Array2D<Operator*>&
Af; // TODO: remove this, as it is used only in the constructor
Array2D<double>&
Acoef; // TODO: remove this, as it is used only in the constructor
vector<Array<int>> Aoffsets;
vector<Array<int>> Poffsets_i;
vector<Array<int>> Poffsets_j;
Array<int> Coffsets;
std::vector<Array2D<Operator*>> A;
#ifdef SERIAL_PROLONGATION
std::vector<SparseMatrix *> P;
#else
std::vector<HypreParMatrix *> const& P;
#endif
std::vector<Vector*> const& diag;
std::vector<Operator*> Pt;
std::vector<BlockOperator *> BlkP;
std::vector<BlockOperator *> BlkA;
std::vector<BlockOperator *> S;
std::vector<OperatorJacobiSmoother*> Jacobi;
HypreParMatrix * Ac;
SparseMatrix AcSp;
int numGrids, numBlocks;
//STRUMPACKSolver *invAc = nullptr;
Operator *invAc = nullptr;
double theta = 0.5;
mutable std::vector<Vector> rv, zv;
mutable Vector u, v, w;
Vector diagAc;
Array<int> emptyEssDof;
OperatorJacobiSmoother *JacobiAc;
#ifdef SPARSE_ICHOLESKY
Solver *iCholAc;
#endif
#ifdef SPARSE_ILU
Solver *iluAc;
#endif
#ifdef BLOCK_DIAG
HypreParMatrix *AcDiag;
SparseMatrix AcDiagSp;
#endif
public:
BlockMGPASolver(MPI_Comm comm, const int height, const int width,
Array2D<Operator*>& Af_, Array2D<double>& Acoef_,
#ifdef COARSE_PA
BlockOperator *BlkAc,
#else
Array2D<HypreParMatrix*> const& BlkAc,
#endif
#ifdef COARSE_AMS
ParFiniteElementSpace* coarseFespace,
#endif
std::vector<HypreParMatrix *> const& P_, std::vector<Vector*> const& diag_,
Array<int>& ess_tdof_list)
#ifdef SERIAL_PROLONGATION
: Solver(height, width), Af(Af_), Acoef(Acoef_), diag(diag_)
#else
: Solver(height, width), Af(Af_), Acoef(Acoef_), P(P_), diag(diag_)
#endif
{
timeMult = 0.0;
timeMultAc = 0.0;
timeMultPresmooth = 0.0;
timeMultResidual = 0.0;
timeMultRestrict = 0.0;
#ifdef SERIAL_PROLONGATION
P.resize(P_.size());
for (int i=0; i<P_.size(); ++i)
{
P[i] = new SparseMatrix();
P_[i]->GetDiag(*P[i]);
P[i]->BuildTranspose();
}
#endif
numBlocks = Af.NumRows();
MFEM_VERIFY(Af.NumCols() == numBlocks, "");
#ifndef COARSE_PA
MFEM_VERIFY(BlkAc.NumCols() == numBlocks && BlkAc.NumRows() == numBlocks, "");
#endif
numGrids = P.size();
MFEM_VERIFY(diag.size() == numBlocks, "");
BlkP.resize(numGrids);
BlkA.resize(numGrids+1);
Pt.resize(numGrids);
S.resize(numGrids);
A.resize(numGrids + 1);
A[numGrids] = Af;
Aoffsets.resize(numGrids+1);
Poffsets_i.resize(numGrids);
Poffsets_j.resize(numGrids);
Jacobi.resize(numBlocks);
for (int i=0; i<numBlocks; ++i)
{
Jacobi[i] = new OperatorJacobiSmoother(*(diag[i]), ess_tdof_list, 1.0);
}
// Construct Bilinear form Matrices on each level
for (int k = numGrids ; k > 0; k--)
{
A[k - 1].SetSize(numBlocks,numBlocks);
Aoffsets[k].SetSize(numBlocks+1); Aoffsets[k][0] = 0;
for (int i=0; i<numBlocks; i++)
{
Aoffsets[k][i+1] = A[k](i,i)->Height();
}
Aoffsets[k].PartialSum();
BlkA[k] = new BlockOperator(Aoffsets[k]);
S[k-1] = new BlockOperator(Aoffsets[k]); // Smoother
Pt[k - 1] = new TransposeOperator(P[k - 1]);
for (int i=0; i<numBlocks; i++)
{
for (int j=0; j<numBlocks; j++)
{
if (A[k](i,j) == NULL)
{
A[k - 1](i,j) = NULL;
}
else
{
//A[k - 1](i,j) = RAP(A[k](i,j), P[k - 1]);
A[k - 1](i,j) = new TripleProductOperator(Pt[k - 1], A[k](i,j), P[k - 1], false,
false, false);
BlkA[k]->SetBlock(i, j, A[k](i,j), Acoef(i,j));
}
}
if (k == numGrids) // finest level
{
S[k - 1]->SetBlock(i,i,Jacobi[i]);
}
else
{
S[k - 1]->SetBlock(i,i, new TripleProductOperator(Pt[k], &(S[k]->GetBlock(i,i)),
P[k], false,
false, false)); // TODO: get a diagonal on each level
}
}
Poffsets_i[k-1].SetSize(numBlocks+1); Poffsets_i[k-1][0] = 0;
Poffsets_j[k-1].SetSize(numBlocks+1); Poffsets_j[k-1][0] = 0;
for (int i=0; i<numBlocks; i++)
{
Poffsets_i[k-1][i+1] = P[k-1]->Height();
Poffsets_j[k-1][i+1] = P[k-1]->Width();
}
Poffsets_i[k-1].PartialSum();
Poffsets_j[k-1].PartialSum();
BlkP[k-1] = new BlockOperator(Poffsets_i[k-1],Poffsets_j[k-1]);
for (int i=0; i<numBlocks; i++)
{
BlkP[k-1]->SetBlock(i,i,P[k-1]);
}
}
// Set up coarse solve operator
// Convert the coarse grid blockmatrix to a HypreParMatrix
Coffsets.SetSize(numBlocks+1);
Coffsets[0]=0;
for (int i=0; i<numBlocks; i++)
{
Coffsets[i+1]=A[0](i,i)->Height();
#ifndef COARSE_PA
MFEM_VERIFY(BlkAc(i,i)->Height() == A[0](i,i)->Height(), "");
MFEM_VERIFY(BlkAc(i,i)->Width() == A[0](i,i)->Width(), "");
#endif
}
Coffsets.PartialSum();
#ifdef COARSE_PA
BlkA[0] = BlkAc;
#else
BlkA[0] = new BlockOperator(Coffsets);
#endif
Array2D<SparseMatrix*> Asp;
//Array2D<double> Acoef;
Asp.SetSize(numBlocks,numBlocks);
//Acoef.SetSize(numBlocks,numBlocks);
for (int i=0; i<numBlocks; i++)
{
for (int j=0; j<numBlocks; j++)
{
#ifndef COARSE_PA
MFEM_VERIFY((A[0](i,j) == NULL) == (BlkAc(i,j) == NULL), "");
if (BlkAc(i,j) != NULL)
{
BlkA[0]->SetBlock(i, j, BlkAc(i,j), Acoef(i,j));
}
#endif
Asp(i,j) = NULL;
//Acoef(i,j) = 1.0;
}
}
#ifdef COARSE_PA
CGSolver *cg_solver = new CGSolver();
cg_solver->SetAbsTol(1.0e-6);
cg_solver->SetRelTol(1.0e-6);
cg_solver->SetMaxIter(1000);
cg_solver->SetOperator(*BlkAc);
cg_solver->SetPrintLevel(0);
cg_solver->iterative_mode = false;
invAc = cg_solver;
#else
// Convert to HypreParMatrix
HypreParMatrix * Ac;
std::vector<std::vector<int> > blockProcOffsets(numBlocks);
std::vector<std::vector<int> > all_block_num_loc_rows(numBlocks);
{
int nprocs, rank;
MPI_Comm_rank(comm, &rank);
MPI_Comm_size(comm, &nprocs);
std::vector<int> allnumrows(nprocs);
// TODO: Not valid if blocks are of different size
const int blockNumRows = BlkAc(0,0)->Height();
MPI_Allgather(&blockNumRows, 1, MPI_INT, allnumrows.data(), 1, MPI_INT, comm);
for (int b=0; b<numBlocks; ++b)
{
blockProcOffsets[b].resize(nprocs);
all_block_num_loc_rows[b].resize(nprocs);
}
blockProcOffsets[0][0] = 0;
for (int i=0; i<nprocs-1; ++i)
{
blockProcOffsets[0][i+1] = blockProcOffsets[0][i] + allnumrows[i];
}
for (int i=0; i<nprocs; ++i)
{
for (int b=0; b<numBlocks; ++b)
{
all_block_num_loc_rows[b][i] = allnumrows[i];
}
for (int b=1; b<numBlocks; ++b)
{
blockProcOffsets[b][i] = blockProcOffsets[0][i];
}
}
}
Ac = CreateHypreParMatrixFromBlocks2(comm, Coffsets, BlkAc, Asp,
Acoef, blockProcOffsets, all_block_num_loc_rows);
#ifdef BLOCK_DIAG
{
Array2D<HypreParMatrix*> BlkAcDiag(numBlocks, numBlocks);
Array2D<double> DiagCoef(numBlocks, numBlocks);
DiagCoef = 0.0;
for (int i=0; i<numBlocks; ++i)
{
DiagCoef(i,i) = Acoef(i,i);
for (int j=0; j<numBlocks; ++j)
{
BlkAcDiag(i,j) = NULL;
}
BlkAcDiag(i,i) = BlkAc(i,i);
}
AcDiag = CreateHypreParMatrixFromBlocks2(comm, Coffsets, BlkAcDiag, Asp,
DiagCoef, blockProcOffsets, all_block_num_loc_rows);
AcDiag->GetDiag(AcDiagSp);
//delete AcDiag;
}
#endif
#ifdef MFEM_USE_STRUMPACK
invAc = CreateStrumpackSolver(new STRUMPACKRowLocMatrix(*Ac), comm);
delete Ac;
#else
Ac->GetDiag(AcSp); // AcSp does not own the data
delete Ac;
#ifdef ITERATIVE_COARSE_SOLVE
//CGSolver *cg_solver = new CGSolver(comm);
CGSolver *cg_solver = new CGSolver();
cg_solver->SetAbsTol(1.0e-6);
cg_solver->SetRelTol(1.0e-6);
cg_solver->SetMaxIter(1000);
cg_solver->SetOperator(AcSp);
cg_solver->SetPrintLevel(0);
cg_solver->iterative_mode = false;
#ifdef SPARSE_JACOBI
AcSp.GetDiag(diagAc);
JacobiAc = new OperatorJacobiSmoother(diagAc, emptyEssDof);
cg_solver->SetPreconditioner(*JacobiAc);
#endif
#ifdef SPARSE_ICHOLESKY
{
Vector tmpX(AcSp.Height());
Vector tmpY(AcSp.Height());
tmpX = 1.0;
tmpY = 0.0;
#ifdef BLOCK_DIAG
AcDiagSp.Finalize();
AcDiagSp.SortColumnIndices();
AcDiagSp.Mult(tmpX, tmpY);
#else
AcSp.Finalize();
AcSp.SortColumnIndices();
AcSp.Mult(tmpX, tmpY);
#endif
}
#ifdef BLOCK_DIAG
iCholAc = new IncompleteCholesky(AcDiagSp);
#else
iCholAc = new IncompleteCholesky(AcSp);
#endif
cg_solver->SetPreconditioner(*iCholAc);
cg_solver->SetPrintLevel(-1);
#endif // SPARSE_ICHOLESKY
#ifdef SPARSE_ILU
{
Vector tmpX(AcSp.Height());
Vector tmpY(AcSp.Height());
tmpX = 1.0;
tmpY = 0.0;
#ifdef BLOCK_DIAG
AcDiagSp.Finalize();
AcDiagSp.SortColumnIndices();
AcDiagSp.Mult(tmpX, tmpY);
#else
AcSp.Finalize();
AcSp.SortColumnIndices();
AcSp.Mult(tmpX, tmpY);
#endif
}
#ifdef BLOCK_DIAG
iluAc = new ILUcusparse(AcDiagSp);
#else
iluAc = new ILUcusparse(AcSp);
#endif
cg_solver->SetPreconditioner(*iluAc);
cg_solver->SetPrintLevel(0);
#endif // SPARSE_ILU
#ifdef COARSE_AMS
#ifndef COARSE_PA
MFEM_VERIFY(numBlocks == 4, "");
// TODO: just set 2 AMS solvers for E and H.
if (coarseFespace != NULL)
{
BlockDiagonalPreconditioner *blkAMS = new BlockDiagonalPreconditioner(Coffsets);
for (int i=0; i<numBlocks; ++i)
{
HypreAMS *ams = new HypreAMS(*BlkAc(i,i), coarseFespace);
blkAMS->SetDiagonalBlock(i, ams);
}
cg_solver->SetPreconditioner(*blkAMS);
}
#endif
#endif
invAc = cg_solver;
#else
UMFPackSolver *umf_solver = new UMFPackSolver();
umf_solver->Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver->SetOperator(AcSp);
invAc = umf_solver;
#endif
#endif
#endif // COARSE_PA
// Residual vectors
rv.resize(numGrids + 1);
// correction vectors
zv.resize(numGrids + 1);
// allocation
for (int i = 0; i <= numGrids ; i++)
{
int n = (i==0) ? invAc->Height(): BlkA[i]->Width();
rv[i].SetSize(n);
zv[i].SetSize(n);
rv[i].UseDevice(true);
zv[i].UseDevice(true);
}
}
virtual void SetOperator(const Operator &op) {}
virtual void SetTheta(const double a) { theta = a; }
virtual void Mult(const Vector &r, Vector &z) const
{
#ifdef SWTIMING
StopWatch sw;
sw.Clear();
sw.Start();
#endif
// Initial residual
rv[numGrids] = r;
// smooth and update residuals down to the coarsest level
for (int i = numGrids; i > 0 ; i--)
{
// Pre smooth
#ifdef SWTIMING
StopWatch sws;
sws.Clear();
sws.Start();
#endif
S[i - 1]->Mult(rv[i], zv[i]); zv[i] *= theta;
#ifdef SWTIMING
sws.Stop();
timeMultPresmooth += sws.RealTime();
#endif
// compute residual
int n = BlkA[i]->Width();
w.SetSize(n);
w.UseDevice(true);
#ifdef SWTIMING
StopWatch swop;
swop.Clear();
swop.Start();
#endif
BlkA[i]->Mult(zv[i], w);
rv[i] -= w;
#ifdef SWTIMING
swop.Stop();
timeMultResidual += swop.RealTime();
#endif
// Restrict
#ifdef SWTIMING
StopWatch swr;
swr.Clear();
swr.Start();
#endif
BlkP[i - 1]->MultTranspose(rv[i], rv[i - 1]);
#ifdef SWTIMING
swr.Stop();
timeMultRestrict += swr.RealTime();
#endif
}
#ifdef SWTIMING
StopWatch swAc;
swAc.Clear();
swAc.Start();
#endif
// Coarse grid Solve
invAc->Mult(rv[0], zv[0]);
//
#ifdef SWTIMING
swAc.Stop();
timeMultAc += swAc.RealTime();
#endif
for (int i = 1; i <= numGrids ; i++)
{
// Prolong correction
u.SetSize(BlkP[i - 1]->Height());
u.UseDevice(true);
BlkP[i - 1]->Mult(zv[i - 1], u);
// Update correction
zv[i] += u;
// Update residual
v.SetSize(BlkA[i]->Height());
v.UseDevice(true);
BlkA[i]->Mult(u, v); rv[i] -= v;
// Post smooth
S[i - 1]->Mult(rv[i], v); v *= theta;
// Update correction
zv[i] += v;
}
z = zv[numGrids];
#ifdef SWTIMING
sw.Stop();
timeMult += sw.RealTime();
#endif
}
virtual ~BlockMGPASolver()
{
for (int i = numGrids - 1; i >= 0 ; i--)
{
delete S[i];
delete BlkP[i];
delete BlkA[i];
for (int j=0; j<numBlocks; j++)
{
for (int k=0; k<numBlocks; k++)
{
delete A[i](j,k);
}
}
A[i].DeleteAll();
}
delete BlkA[numGrids];
delete invAc;
A.clear();
#ifdef SPARSE_ICHOLESKY
delete iCholAc;
#endif
#ifdef SPARSE_ILU
delete iluAc;
#endif
}
#ifdef MFEM_USE_STRUMPACK
STRUMPACKSolver* CreateStrumpackSolver(Operator *Arow, MPI_Comm comm)
{
//STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv, comm);
STRUMPACKSolver * strumpack = new STRUMPACKSolver(0, NULL, comm);
strumpack->SetPrintFactorStatistics(true);
strumpack->SetPrintSolveStatistics(false);
strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
return strumpack;
}
#endif
mutable double timeMult, timeMultAc, timeMultPresmooth, timeMultResidual,
timeMultRestrict;
};
}
//} // namespace mfem
#endif // BGMULTIGRID
-363
View File
@@ -1,363 +0,0 @@
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <cmath>
using namespace std;
class HypreMat
{
private:
std::vector<int> I, J;
std::vector<double> d;
int size;
public:
HypreMat() : size(0)
{
}
int Size() const { return size; }
void ReadMatrixParallel(std::string filename, const int np)
{
int lastRow = 0;
int count = 0;
std::vector<int> R;
for (int p=0; p<np; ++p)
{
std::ifstream f(filename.c_str() + std::to_string(p), std::ifstream::in);
int rowFirst, rowLast, colFirst, colLast, row, col;
double v;
f >> rowFirst >> rowLast >> colFirst >> colLast;
I.resize(rowLast+2);
for (row=rowFirst+1; row<=rowLast+1; ++row)
{
I[row] = 0;
}
while (f.good())
{
f >> row >> col >> v;
if (row >= 2485)
{
abort();
}
//if (row < lastRow) // verify ascending order of rows
// abort();
lastRow = row;
I[row+1]++;
R.push_back(row);
J.push_back(col);
d.push_back(v);
count++;
}
f.close();
}
// Partial sum of I
size = I.size() - 1;
I[0] = 0;
for (int j=1; j<size; ++j)
{
I[j+1] += I[j];
}
//int *Idata = I.data();
if (I[size] != J.size() || I[size] != d.size())
{
abort();
}
{
// Reorder J and d
const int nnz = J.size();
if (nnz != d.size() || nnz != R.size())
{
abort();
}
std::vector<int> JJ(nnz);
std::vector<double> dd(nnz);
std::vector<int> cnt;
JJ = J;
dd = d;
cnt.assign(I.size(), 0); // slightly larger than necessary
for (int j=0; j<nnz; ++j)
{
J[I[R[j]] + cnt[R[j]]] = JJ[j];
d[I[R[j]] + cnt[R[j]]] = dd[j];
cnt[R[j]]++;
}
}
}
void CopyReorder(HypreMat const& A, std::vector<int> const& permRow,
std::vector<int> const& permCol)
{
if (permRow.size() != A.Size() || permCol.size() != A.Size())
{
abort();
}
size = A.Size();
I.resize(size+1);
I[0] = 0;
for (int j=0; j<size; ++j)
{
const std::size_t nnz_j = A.I[j+1] - A.I[j];
I[permRow[j]+1] = nnz_j;
}
for (int j=1; j<size; ++j)
{
I[j+1] += I[j];
}
const std::size_t nnz = I[size];
J.resize(nnz);
d.resize(nnz);
std::vector<std::size_t> cnt;
cnt.assign(size, 0);
for (int j=0; j<size; ++j)
{
const int pj = permRow[j];
const std::size_t nnz_j = A.I[j+1] - A.I[j];
for (int k=0; k<nnz_j; ++k, cnt[pj]++)
{
J[I[pj] + cnt[pj]] = permCol[A.J[A.I[j] + k]];
d[I[pj] + cnt[pj]] = A.d[A.I[j] + k];
}
}
}
void Print(std::string filename)
{
std::ofstream f(filename.c_str());
for (int j=0; j<size; ++j)
{
for (int k=I[j]; k<I[j+1]; ++k)
{
f << j << " " << J[k] << " " << d[k] << endl;
}
}
f.close();
}
void Compare(HypreMat const& A)
{
if (size != A.Size())
{
abort();
}
for (int j=0; j<size; ++j)
{
for (int k=I[j]; k<I[j+1]; ++k)
{
int m = -1;
for (int l=A.I[j]; l<A.I[j+1]; ++l)
{
if (A.J[l] == J[k])
{
m = l;
}
}
if (m < 0)
{
cout << "row " << j << " column " << J[k] << " not found" << endl;
}
//else if (fabs(A.d[m] - d[k]) > 1.0e-8)
else if (fabs(fabs(A.d[m]) - fabs(d[k])) > 0.0)
{
cout << "entry (" << j << ", " << J[k] << ") " << d[k] << " != " << A.d[m] <<
endl;
}
}
}
}
};
void ReadCrd(std::string filename, std::vector<double>& crd)
{
std::ifstream f(filename.c_str(), std::ifstream::in);
double c;
while (f.good())
{
f >> c;
crd.push_back(c);
}
// for some reason, the last value gets pushed twice
crd.pop_back();
f.close();
}
void ReadCrdParallel(std::string filenamebase, const int np,
std::vector<double>& crd)
{
for (int p=0; p<np; ++p)
{
ReadCrd(filenamebase + std::to_string(p),
crd); // results get concatenated in crd
}
}
// crd is the DOF coordinates in serial, crdp in parallel.
void SerialToParallelDOFMap(std::vector<double> const& crd,
std::vector<double> const& crdp,
std::vector<int>& sp)
{
if (crdp.size() != crd.size())
{
abort();
}
const int dim = 3;
const int n = crd.size() / dim; // number of DOF's
sp.resize(n);
const double tol = 1.0e-8;
// Simple O(n^2) search
for (int i=0; i<n; ++i)
{
sp[i] = -1;
for (int j=0; j<n; ++j)
{
bool eq = true;
for (int l=0; l<dim; ++l)
{
if (fabs(crd[(dim*i)+l] - crdp[(dim*j)+l]) > tol)
{
eq = false;
}
}
if (eq)
{
if (sp[i] != -1)
{
abort();
}
sp[i] = j;
}
}
if (sp[i] < 0)
{
abort();
}
}
}
int main()
{
const int np = 2;
std::vector<double> crd0, crdp0, crd1, crdp1;
ReadCrd("dofcrd0Ser", crd0);
ReadCrd("dofcrd1Ser", crd1);
const int numCrd = crd0.size() / 3;
if (3*numCrd != crd0.size())
{
abort();
}
//for (int i=7440; i<crd.size(); ++i)
//cout << "crd[" << i << "] " << crd[i] << endl;
ReadCrdParallel("dofcrd0Par", np, crdp0);
ReadCrdParallel("dofcrd1Par", np, crdp1);
if (3*numCrd != crdp0.size())
{
abort();
}
std::vector<int> sp0, sp1; // serial to parallel DOF map for a subdomain
SerialToParallelDOFMap(crd0, crdp0, sp0);
SerialToParallelDOFMap(crd1, crdp1, sp1);
/*
for (int i=0; i<sp.size(); ++i)
cout << i << " " << sp[i] << endl;
*/
cout << "sp0" << endl;
for (int i=0; i<sp0.size(); ++i)
{
cout << i << " " << sp0[i] << endl;
}
cout << "sp1" << endl;
for (int i=0; i<sp1.size(); ++i)
{
cout << i << " " << sp1[i] << endl;
}
HypreMat Aser, Apar, AserToPar;
/*
Aser.ReadMatrixParallel("HypreAsdComplexIm1_Serial.0000", 1);
Apar.ReadMatrixParallel("HypreAsdComplexIm1_Par5.0000", np);
*/
Aser.ReadMatrixParallel("ifopSer.0000", 1);
Apar.ReadMatrixParallel("ifopPar.0000", np);
//AserToPar.CopyReorder(Aser, sp, sp);
AserToPar.CopyReorder(Aser, sp0, sp1);
/*
Aser.Print("rbSer");
AserToPar.Print("rbSerToPar");
Apar.Print("rbPar");
*/
cout << "Comparing " << endl;
AserToPar.Compare(Apar);
return 0;
}
-105
View File
@@ -1,105 +0,0 @@
#ifndef TESTSTRUMPACK_HPP
#define TESTSTRUMPACK_HPP
#include "mfem.hpp"
using namespace mfem;
using namespace std;
void TestStrumpackConstructor()
{
int num_procs, rank;
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
const int num_loc_rows = 100;
const int first_loc_row = num_loc_rows * rank;
const int glob_nrows = num_loc_rows * num_procs;
const int glob_ncols = glob_nrows;
int *opI = new int[num_loc_rows+1];
for (int i=0; i<num_loc_rows+1; ++i)
{
opI[i] = 0;
}
for (int i=0; i<num_loc_rows; ++i)
{
int nnz_i = 3;
if ((first_loc_row + i) == 0 ||
(first_loc_row + i) == glob_nrows-1) // if first or last row
{
nnz_i = 2;
}
opI[i+1] = opI[i] + nnz_i;
}
const int nnz = opI[num_loc_rows];
int *opJ = new int[nnz];
double *data = new double[nnz];
int cnt = 0;
for (int i=0; i<num_loc_rows; ++i)
{
const int globalRow = first_loc_row + i;
// Diagonal entry
opJ[cnt] = first_loc_row + i;
if (globalRow == 0 || globalRow == glob_nrows-1)
{
data[cnt] = 2.0;
}
else
{
data[cnt] = 3.0;
}
cnt++;
// Upper diagonal
if (globalRow < glob_nrows-1)
{
opJ[cnt] = first_loc_row + i + 1;
data[cnt] = -1.0;
cnt++;
}
// Lower diagonal
if (globalRow > 0)
{
opJ[cnt] = first_loc_row + i - 1;
data[cnt] = -1.0;
cnt++;
}
}
Operator *op = new STRUMPACKRowLocMatrix(MPI_COMM_WORLD, num_loc_rows,
first_loc_row, glob_nrows, glob_ncols, opI, opJ, data);
STRUMPACKSolver * strumpack = new STRUMPACKSolver(0, NULL, MPI_COMM_WORLD);
strumpack->SetPrintFactorStatistics(true);
strumpack->SetPrintSolveStatistics(false);
strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
strumpack->SetOperator(*op);
strumpack->SetFromCommandLine();
Vector x(num_loc_rows);
Vector y(num_loc_rows);
x = 1.0;
strumpack->Mult(x, y);
delete opI;
delete opJ;
delete data;
}
#endif // TESTSTRUMPACK_HPP
-2
View File
@@ -31,7 +31,6 @@ set(SRCS
bilininteg_vecmass.cpp
coefficient.cpp
complex_fem.cpp
convergence.cpp
datacollection.cpp
eltrans.cpp
estimators.cpp
@@ -66,7 +65,6 @@ set(HDRS
bilininteg.hpp
coefficient.hpp
complex_fem.hpp
convergence.hpp
datacollection.hpp
eltrans.hpp
estimators.hpp
-58
View File
@@ -627,33 +627,6 @@ void BilinearForm::AssembleDiagonal(Vector &diag) const
MFEM_ASSERT(diag.Size() == fes->GetTrueVSize(),
"Vector for holding diagonal has wrong size!");
const Operator *P = fes->GetProlongationMatrix();
// For an AMR mesh, a convergent diagonal is assembled with |P^T| d_e,
// where |P^T| has the entry-wise absolute values of the conforming
// prolongation transpose operator.
if (P && !fes->Conforming())
{
Vector local_diag(P->Height());
ext->AssembleDiagonal(local_diag);
const SparseMatrix *SP = dynamic_cast<const SparseMatrix*>(P);
#ifdef MFEM_USE_MPI
const HypreParMatrix *HP = dynamic_cast<const HypreParMatrix*>(P);
#endif
if (SP)
{
SP->AbsMultTranspose(local_diag, diag);
}
#ifdef MFEM_USE_MPI
else if (HP)
{
HP->AbsMultTranspose(1.0, local_diag, 0.0, diag);
}
#endif
else
{
MFEM_ABORT("Prolongation matrix has unexpected type.");
}
return;
}
if (!IsIdentityProlongation(P))
{
Vector local_diag(P->Height());
@@ -1771,40 +1744,9 @@ MixedBilinearForm::~MixedBilinearForm()
delete ext;
}
void DiscreteLinearOperator::SetAssemblyLevel(AssemblyLevel assembly_level)
{
if (ext)
{
MFEM_ABORT("the assembly level has already been set!");
}
assembly = assembly_level;
switch (assembly)
{
case AssemblyLevel::FULL:
// Use the original BilinearForm implementation for now
break;
case AssemblyLevel::ELEMENT:
mfem_error("Element assembly not supported yet... stay tuned!");
break;
case AssemblyLevel::PARTIAL:
ext = new PADiscreteLinearOperatorExtension(this);
break;
case AssemblyLevel::NONE:
mfem_error("Matrix-free action not supported yet... stay tuned!");
break;
default:
mfem_error("Unknown assembly level");
}
}
void DiscreteLinearOperator::Assemble(int skip_zeros)
{
if (ext)
{
ext->Assemble();
return;
}
Array<int> dom_vdofs, ran_vdofs;
ElementTransformation *T;
const FiniteElement *dom_fe, *ran_fe;
-23
View File
@@ -375,9 +375,6 @@ public:
/// Get the output finite element space prolongation matrix
virtual const Operator *GetOutputProlongation() const
{ return GetProlongation(); }
/// Get the output finite element space prolongation matrix (local diagonal)
virtual const Operator *GetLocalOutputProlongation() const
{ return GetOutputProlongation(); }
/// Get the output finite element space restriction matrix
virtual const Operator *GetOutputRestriction() const
{ return GetRestriction(); }
@@ -594,18 +591,6 @@ public:
/// Indicate that integrators are not owned by the BilinearForm
void UseExternalIntegrators() { extern_bfs = 1; };
void GetTimings(double& t1, double& t2)
{
t1 = 0.0;
t2 = 0.0;
PABilinearFormExtension *paext = dynamic_cast<PABilinearFormExtension*>(ext);
if (paext != NULL)
{
t1 = paext->timingDomain;
t2 = paext->timingBoundary;
}
}
/// Destroys bilinear form.
virtual ~BilinearForm();
};
@@ -999,17 +984,9 @@ public:
/// Access all interpolators added with AddDomainInterpolator().
Array<BilinearFormIntegrator*> *GetDI() { return &dbfi; }
/// Set the desired assembly level. The default is AssemblyLevel::FULL.
/** This method must be called before assembly. */
void SetAssemblyLevel(AssemblyLevel assembly_level);
/** @brief Construct the internal matrix representation of the discrete
linear operator. */
virtual void Assemble(int skip_zeros = 1);
/// Get the output finite element space prolongation matrix (local diagonal)
virtual const Operator *GetLocalOutputProlongation() const
{ return test_fes->GetLocalProlongationMatrix(); }
};
}
+8 -344
View File
@@ -17,8 +17,6 @@
#include "libceed/ceed.hpp"
#include "pgridfunc.hpp"
#include "../general/tic_toc.hpp"
namespace mfem
{
@@ -48,9 +46,6 @@ PABilinearFormExtension::PABilinearFormExtension(BilinearForm *form)
elem_restrict = NULL;
int_face_restrict_lex = NULL;
bdr_face_restrict_lex = NULL;
timingDomain = 0.0;
timingBoundary = 0.0;
}
void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
@@ -101,13 +96,6 @@ void PABilinearFormExtension::Assemble()
integrators[i]->AssemblePA(*a->FESpace());
}
Array<BilinearFormIntegrator*> &bdryIntegrators = *a->GetBBFI();
const int bdryIntegratorCount = bdryIntegrators.Size();
for (int i = 0; i < bdryIntegratorCount; ++i)
{
bdryIntegrators[i]->AssemblePA(*a->FESpace());
}
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int intFaceIntegratorCount = intFaceIntegrators.Size();
for (int i = 0; i < intFaceIntegratorCount; ++i)
@@ -121,96 +109,6 @@ void PABilinearFormExtension::Assemble()
{
bdrFaceIntegrators[i]->AssemblePABoundaryFaces(*a->FESpace());
}
timingDomain = 0.0;
timingBoundary = 0.0;
if (bdryIntegratorCount > 0)
{
FiniteElementSpace *fes = a->GetFES();
const int nbe = fes->GetNBE();
const int bedofs = nbe > 0 ? nbe * fes->GetVDim() * fes->GetBE(0)->GetDof() : 0;
gatherMap.SetSize(bedofs);
indices.SetSize(bedofs);
ndofs = fes->GetNDofs();
offsets.SetSize(ndofs+1);
for (int i = 0; i <= ndofs; ++i)
{
offsets[i] = 0;
}
for (int i = 0; i < nbe; i++)
{
const FiniteElement &be = *fes->GetBE(i);
Array<int> vdofs;
fes -> GetBdrElementVDofs (i, vdofs);
const TensorBasisElement* el =
dynamic_cast<const TensorBasisElement*>(&be);
MFEM_VERIFY(el != NULL, "");
const Array<int> &fe_dof_map = el->GetDofMap();
MFEM_VERIFY(fe_dof_map.Size() == fes->GetBE(i)->GetDof(), "");
MFEM_VERIFY(vdofs.Size() == fes->GetBE(i)->GetDof(), "");
for (int j=0; j<vdofs.Size(); ++j)
{
const int sidj = fe_dof_map[j];
const int idj = sidj >= 0 ? sidj : -1 - sidj;
const int dof_j = vdofs[idj];
const int d = dof_j >= 0 ? dof_j : -1-dof_j;
offsets[d+1]++;
}
}
for (int i = 1; i <= ndofs; ++i)
{
// Partial sum
offsets[i] += offsets[i - 1];
}
int os = 0;
Array<int> cnt(ndofs);
cnt = 0;
indices = 0;
for (int i = 0; i < nbe; i++)
{
const FiniteElement &be = *fes->GetBE(i);
Array<int> vdofs;
fes -> GetBdrElementVDofs (i, vdofs);
const TensorBasisElement* el =
dynamic_cast<const TensorBasisElement*>(&be);
MFEM_VERIFY(el != NULL, "");
const Array<int> &fe_dof_map = el->GetDofMap();
MFEM_VERIFY(fe_dof_map.Size() == fes->GetBE(i)->GetDof(), "");
MFEM_VERIFY(vdofs.Size() == fes->GetBE(i)->GetDof(), "");
for (int j=0; j<vdofs.Size(); ++j)
{
const int sidj = fe_dof_map[j];
const int idj = sidj >= 0 ? sidj : -1 - sidj;
const int dof_j = vdofs[idj];
const bool plus = (sidj >= 0 && dof_j >= 0) || (sidj < 0 && dof_j < 0);
const int d = dof_j >= 0 ? dof_j : -1-dof_j;
const int lid = os + j;
gatherMap[lid] = plus ? d : -1-d;
indices[offsets[d] + cnt[d]] = plus ? lid : -1-lid;
cnt[d]++;
}
os += vdofs.Size();
}
MFEM_VERIFY(os == bedofs, "");
}
}
void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
@@ -218,7 +116,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)
@@ -278,18 +176,10 @@ void PABilinearFormExtension::FormLinearSystem(const Array<int> &ess_tdof_list,
A.Reset(oper); // A will own oper
}
//#define SWTIMING
void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
{
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
#ifdef SWTIMING
StopWatch swd;
swd.Clear();
swd.Start();
#endif
const int iSz = integrators.Size();
if (DeviceCanUseCeed() || !elem_restrict)
{
@@ -311,93 +201,6 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
elem_restrict->MultTranspose(localY, y);
}
#ifdef SWTIMING
swd.Stop();
timingDomain += swd.RealTime();
StopWatch swb;
swb.Clear();
swb.Start();
#endif
Array<BilinearFormIntegrator*> &bdryIntegrators = *a->GetBBFI();
const int biSz = bdryIntegrators.Size();
if (DeviceCanUseCeed() || !elem_restrict)
{
MFEM_ABORT("Not implemented");
}
else if (biSz > 0)
{
FiniteElementSpace *fes = a->GetFES();
const int nbe = fes->GetNBE();
const int bedofs = nbe > 0 ? nbe * fes->GetVDim() * fes->GetBE(0)->GetDof() : 0;
bdryX.SetSize(bedofs);
bdryY.SetSize(bedofs);
bdryX.UseDevice(true);
bdryY.UseDevice(true);
bdryX = 0.0;
bdryY = 0.0;
{
MFEM_VERIFY(gatherMap.Size() == bedofs, "");
auto d_gatherMap = gatherMap.Read();
auto d_x = x.Read();
auto d_bdryX = bdryX.Write();
MFEM_FORALL(i, bedofs,
{
const int gid = d_gatherMap[i];
const bool plus = gid >= 0;
const int j = plus ? gid : -1-gid;
d_bdryX[i] = plus ? d_x[j] : -d_x[j];
});
}
for (int i = 0; i < biSz; ++i)
{
bdryIntegrators[i]->AddMultPA(bdryX, bdryY);
}
//elem_restrict->MultTranspose(bdryY, y);
// bdryY contains quantities on all boundary elements. Now add them to y.
{
const int xsize = x.Size();
MFEM_VERIFY(y.Size() == xsize, "");
MFEM_VERIFY(gatherMap.Size() == bedofs, "");
auto d_offsets = offsets.Read();
auto d_indices = indices.Read();
auto d_y = y.ReadWrite();
auto d_bdryY = bdryY.Read();
MFEM_FORALL(i, ndofs,
{
const int offset = d_offsets[i];
const int nextOffset = d_offsets[i + 1];
double val = 0.0;
for (int j = offset; j < nextOffset; ++j)
{
const int id = d_indices[j];
const bool plus = id >= 0;
const int idj = plus ? id : -1-id;
const double yval = d_bdryY[idj];
val += plus ? yval : -yval;
}
d_y[i] += val;
});
}
}
#ifdef SWTIMING
swb.Stop();
timingBoundary += swb.RealTime();
#endif
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int iFISz = intFaceIntegrators.Size();
if (int_face_restrict_lex && iFISz>0)
@@ -455,10 +258,6 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
}
}
Array<BilinearFormIntegrator*> &bdryIntegrators = *a->GetBBFI();
const int biSz = bdryIntegrators.Size();
MFEM_VERIFY(biSz == 0, "TODO");
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int iFISz = intFaceIntegrators.Size();
if (int_face_restrict_lex && iFISz>0)
@@ -508,21 +307,19 @@ void EABilinearFormExtension::Assemble()
ea_data.SetSize(ne*elemDofs*elemDofs, Device::GetMemoryType());
ea_data.UseDevice(true);
ea_data = 0.0;
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int integratorCount = integrators.Size();
for (int i = 0; i < integratorCount; ++i)
{
integrators[i]->AssembleEA(*a->FESpace(), ea_data, i);
integrators[i]->AssembleEA(*a->FESpace(), ea_data);
}
faceDofs = trialFes ->
GetTraceElement(0, trialFes->GetMesh()->GetFaceBaseGeometry(0)) ->
GetDof();
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
"Element assembly does not support AddBoundaryIntegrator yet.");
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int intFaceIntegratorCount = intFaceIntegrators.Size();
if (intFaceIntegratorCount>0)
@@ -530,13 +327,14 @@ void EABilinearFormExtension::Assemble()
nf_int = trialFes->GetNFbyType(FaceType::Interior);
ea_data_int.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_ext.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_int = 0.0;
ea_data_ext = 0.0;
}
for (int i = 0; i < intFaceIntegratorCount; ++i)
{
intFaceIntegrators[i]->AssembleEAInteriorFaces(*a->FESpace(),
ea_data_int,
ea_data_ext,
i);
ea_data_ext);
}
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
@@ -549,7 +347,7 @@ void EABilinearFormExtension::Assemble()
}
for (int i = 0; i < boundFaceIntegratorCount; ++i)
{
bdrFaceIntegrators[i]->AssembleEABoundaryFaces(*a->FESpace(),ea_data_bdr,i);
bdrFaceIntegrators[i]->AssembleEABoundaryFaces(*a->FESpace(),ea_data_bdr);
}
if (factorize_face_terms && int_face_restrict_lex)
@@ -996,12 +794,6 @@ void PAMixedBilinearFormExtension::Assemble()
{
integrators[i]->AssemblePA(*trialFes, *testFes);
}
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
"Partial assembly does not support AddBoundaryIntegrator yet.");
MFEM_VERIFY(a->GetTFBFI()->Size() == 0,
"Partial assembly does not support AddTraceFaceIntegrator yet.");
MFEM_VERIFY(a->GetBTFBFI()->Size() == 0,
"Partial assembly does not support AddBdrTraceFaceIntegrator yet.");
}
void PAMixedBilinearFormExtension::Update()
@@ -1019,6 +811,7 @@ void PAMixedBilinearFormExtension::Update()
localTrial.UseDevice(true);
localTrial.SetSize(elem_restrict_trial->Height(),
Device::GetMemoryType());
}
if (elem_restrict_test)
{
@@ -1218,133 +1011,4 @@ void PAMixedBilinearFormExtension::AssembleDiagonal_ADAt(const Vector &D,
}
}
PADiscreteLinearOperatorExtension::PADiscreteLinearOperatorExtension(
DiscreteLinearOperator *linop) :
PAMixedBilinearFormExtension(linop)
{
}
const Operator *PADiscreteLinearOperatorExtension::GetLocalOutputProlongation()
const
{
return a->GetLocalOutputProlongation();
}
void PADiscreteLinearOperatorExtension::Assemble()
{
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int integratorCount = integrators.Size();
for (int i = 0; i < integratorCount; ++i)
{
integrators[i]->AssemblePA(*trialFes, *testFes);
}
test_multiplicity.UseDevice(true);
test_multiplicity.SetSize(elem_restrict_test->Width()); // l-vector
Vector ones(elem_restrict_test->Height()); // e-vector
ones = 1.0;
const ElementRestriction* elem_restrict =
dynamic_cast<const ElementRestriction*>(elem_restrict_test);
if (elem_restrict)
{
elem_restrict->MultTransposeUnsigned(ones, test_multiplicity);
}
else
{
mfem_error("A real ElementRestriction is required in this setting!");
}
auto tm = test_multiplicity.ReadWrite();
MFEM_FORALL(i, test_multiplicity.Size(),
{
tm[i] = 1.0 / tm[i];
});
}
void PADiscreteLinearOperatorExtension::AddMult(
const Vector &x, Vector &y, const double c) const
{
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int iSz = integrators.Size();
// * G operation
SetupMultInputs(elem_restrict_trial, x, localTrial,
elem_restrict_test, y, localTest, c);
// * B^TDB operation
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AddMultPA(localTrial, localTest);
}
// do a kind of "set" rather than "add" in the below
// operation as compared to the BilinearForm case
// * G^T operation (kind of...)
const ElementRestriction* elem_restrict =
dynamic_cast<const ElementRestriction*>(elem_restrict_test);
if (elem_restrict)
{
tempY.SetSize(y.Size());
elem_restrict->MultLeftInverse(localTest, tempY);
y += tempY;
}
else
{
mfem_error("In this setting you need a real ElementRestriction!");
}
}
void PADiscreteLinearOperatorExtension::AddMultTranspose(
const Vector &x, Vector &y, const double c) const
{
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int iSz = integrators.Size();
// do a kind of "set" rather than "add" in the below
// operation as compared to the BilinearForm case
// * G operation (kinda)
Vector xscaled(x);
MFEM_VERIFY(x.Size() == test_multiplicity.Size(), "Input vector of wrong size");
auto xs = xscaled.ReadWrite();
auto tm = test_multiplicity.Read();
MFEM_FORALL(i, x.Size(),
{
xs[i] *= tm[i];
});
SetupMultInputs(elem_restrict_test, xscaled, localTest,
elem_restrict_trial, y, localTrial, c);
// * B^TD^TB operation
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AddMultTransposePA(localTest, localTrial);
}
// * G^T operation
if (elem_restrict_trial)
{
tempY.SetSize(y.Size());
elem_restrict_trial->MultTranspose(localTrial, tempY);
y += tempY;
}
else
{
mfem_error("Trial ElementRestriction not defined");
}
}
void PADiscreteLinearOperatorExtension::FormRectangularSystemOperator(
const Array<int>& ess1, const Array<int>& ess2, OperatorHandle &A)
{
const Operator *Pi = this->GetProlongation();
const Operator *Po = this->GetLocalOutputProlongation();
Operator *rap = SetupRAP(Pi, Po);
RectangularConstrainedOperator *Arco
= new RectangularConstrainedOperator(rap, ess1, ess2, rap != this);
A.Reset(Arco);
}
} // namespace mfem
+1 -36
View File
@@ -21,7 +21,6 @@ namespace mfem
class BilinearForm;
class MixedBilinearForm;
class DiscreteLinearOperator;
/// Class extending the BilinearForm class to support different AssemblyLevels.
/** FA - Full Assembly
@@ -69,16 +68,11 @@ class PABilinearFormExtension : public BilinearFormExtension
protected:
const FiniteElementSpace *trialFes, *testFes; // Not owned
mutable Vector localX, localY;
mutable Vector bdryX, bdryY;
mutable Vector faceIntX, faceIntY;
mutable Vector faceBdrX, faceBdrY;
const Operator *elem_restrict; // Not owned
const Operator *int_face_restrict_lex; // Not owned
const Operator *bdr_face_restrict_lex; // Not owned
Array<int> gatherMap;
Array<int> indices;
Array<int> offsets;
int ndofs;
public:
PABilinearFormExtension(BilinearForm*);
@@ -94,8 +88,6 @@ public:
void MultTranspose(const Vector &x, Vector &y) const;
void Update();
mutable double timingDomain, timingBoundary;
protected:
void SetupRestrictionOperators(const L2FaceValues m);
};
@@ -213,7 +205,7 @@ protected:
mutable Vector localTrial, localTest, tempY;
const Operator *elem_restrict_trial; // Not owned
const Operator *elem_restrict_test; // Not owned
private:
/// Helper function to set up inputs/outputs for Mult or MultTranspose
void SetupMultInputs(const Operator *elem_restrict_x,
const Vector &x, Vector &localX,
@@ -259,33 +251,6 @@ public:
void Update();
};
/**
This acts very much like PAMixedBilinearFormExtension, but its
FormRectangularSystemOperator implementation emulates 'Set' rather than
'Add' in the assembly case.
*/
class PADiscreteLinearOperatorExtension : public PAMixedBilinearFormExtension
{
public:
PADiscreteLinearOperatorExtension(DiscreteLinearOperator *linop);
/// Partial assembly of all internal integrators
void Assemble();
void AddMult(const Vector &x, Vector &y, const double c) const;
void AddMultTranspose(const Vector &x, Vector &y, const double c=1.0) const;
void FormRectangularSystemOperator(const Array<int>&, const Array<int>&,
OperatorHandle& A);
const Operator * GetLocalOutputProlongation() const;
private:
Vector test_multiplicity;
};
}
#endif
+6 -47
View File
@@ -22,14 +22,14 @@ namespace mfem
void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&)
{
mfem_error ("BilinearFormIntegrator::AssemblePA(fes)\n"
mfem_error ("BilinearFormIntegrator::AssemblePA(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&,
const FiniteElementSpace&)
{
mfem_error ("BilinearFormIntegrator::AssemblePA(fes, fes)\n"
mfem_error ("BilinearFormIntegrator::AssemblePA(...)\n"
" is not implemented for this class.");
}
@@ -52,8 +52,7 @@ void BilinearFormIntegrator::AssembleDiagonalPA(Vector &)
}
void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &emat,
const bool add)
Vector &emat)
{
mfem_error ("BilinearFormIntegrator::AssembleEA(...)\n"
" is not implemented for this class.");
@@ -62,8 +61,7 @@ void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
&fes,
Vector &ea_data_int,
Vector &ea_data_ext,
const bool add)
Vector &ea_data_ext)
{
mfem_error ("BilinearFormIntegrator::AssembleEAInteriorFaces(...)\n"
" is not implemented for this class.");
@@ -71,8 +69,7 @@ void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
void BilinearFormIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace
&fes,
Vector &ea_data_bdr,
const bool add)
Vector &ea_data_bdr)
{
mfem_error ("BilinearFormIntegrator::AssembleEABoundaryFaces(...)\n"
" is not implemented for this class.");
@@ -92,7 +89,7 @@ void BilinearFormIntegrator::AddMultPA(const Vector &, Vector &) const
void BilinearFormIntegrator::AddMultTransposePA(const Vector &, Vector &) const
{
mfem_error ("BilinearFormIntegrator::AddMultTransposePA(...)\n"
mfem_error ("BilinearFormIntegrator::MultAssembledTranspose(...)\n"
" is not implemented for this class.");
}
@@ -900,44 +897,6 @@ const IntegrationRule &MassIntegrator::GetRule(const FiniteElement &trial_fe,
return IntRules.Get(trial_fe.GetGeomType(), order);
}
/// alpha (n x u, v)
void VectorFEBoundaryTangentIntegrator::AssembleElementMatrix
(const FiniteElement &el, ElementTransformation &Trans,
DenseMatrix &elmat)
{
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
const int nd1 = el.GetDof();
DenseMatrix vshape(nd1, 3);
DenseMatrix vshapeRotated(nd1, 3);
elmat.SetSize(nd1);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
Vector n(3);
CalcOrtho(Trans.Jacobian(), n);
el.CalcVShape(Trans, vshape);
for (int j=0; j<nd1; ++j)
{
// Set vshapeRotated(j) = n x vshape
vshapeRotated(j, 0) = (n[1] * vshape(j, 2)) - (n[2] * vshape(j, 1));
vshapeRotated(j, 1) = (n[2] * vshape(j, 0)) - (n[0] * vshape(j, 2));
vshapeRotated(j, 2) = (n[0] * vshape(j, 1)) - (n[1] * vshape(j, 0));
}
const double w = alpha * ip.weight; // Trans.Weight() is included in n
AddMult_a_ABt(w, vshape, vshapeRotated, elmat);
}
}
void BoundaryMassIntegrator::AssembleFaceMatrix(
const FiniteElement &el1, const FiniteElement &el2,
+17 -89
View File
@@ -17,8 +17,6 @@
#include "fespace.hpp"
#include "libceed/ceed.hpp"
//#define SETUPONHOST
namespace mfem
{
@@ -88,10 +86,9 @@ public:
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
/// Method defining element assembly.
/** The result of the element assembly is added to the @a emat Vector if
@a add is true. Otherwise, if @a add is false, we set @a emat. */
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
const bool add = true);
/** The result of the element assembly is added and stored in the @a emat
Vector. */
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
/** Used with BilinearFormIntegrators that have different spaces. */
// virtual void AssembleEA(const FiniteElementSpace &trial_fes,
// const FiniteElementSpace &test_fes,
@@ -99,12 +96,10 @@ public:
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext,
const bool add = true);
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
Vector &ea_data_bdr,
const bool add = true);
Vector &ea_data_bdr);
/// Given a particular Finite Element computes the element matrix elmat.
virtual void AssembleElementMatrix(const FiniteElement &el,
@@ -209,9 +204,6 @@ public:
{ return 0.0; }
virtual ~BilinearFormIntegrator() { }
bool isBdryInteg = false;
Array<int> *el_marker = NULL;
};
/** Wraps a given @a BilinearFormIntegrator and transposes the resulting element
@@ -270,17 +262,14 @@ public:
bfi->AddMultTransposePA(x, y);
}
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
const bool add);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext,
const bool add);
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
Vector &ea_data_bdr,
const bool add);
Vector &ea_data_bdr);
virtual ~TransposeIntegrator() { if (own_bfi) { delete bfi; } }
};
@@ -1814,10 +1803,8 @@ protected:
};
/** Class for integrating the bilinear form a(u,v) := (Q grad u, v) where Q is a
scalar coefficient, and v is a vector with components v_i in the same (H1) space
as u.
See also MixedVectorGradientIntegrator when v is in H(curl). */
scalar coefficient, and v is a vector with components v_i in the same space
as u. */
class GradientIntegrator : public BilinearFormIntegrator
{
protected:
@@ -1965,8 +1952,7 @@ public:
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
const bool add);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleDiagonalPA(Vector &diag);
@@ -1975,7 +1961,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) */
@@ -2041,8 +2027,7 @@ public:
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
const bool add);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleDiagonalPA(Vector &diag);
@@ -2052,7 +2037,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 */
@@ -2069,20 +2054,6 @@ public:
DenseMatrix &elmat);
};
/// alpha (n x u, v)
class VectorFEBoundaryTangentIntegrator : public MassIntegrator
{
private:
double alpha;
public:
VectorFEBoundaryTangentIntegrator(double a = 1.0) : alpha(a)
{ }
void AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans, DenseMatrix &elmat);
};
/// alpha (q . grad u, v)
class ConvectionIntegrator : public BilinearFormIntegrator
{
@@ -2112,8 +2083,7 @@ public:
virtual void AssemblePA(const FiniteElementSpace&);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
const bool add);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AddMultPA(const Vector&, Vector&) const;
@@ -2690,12 +2660,10 @@ public:
virtual void AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext,
const bool add);
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr,
const bool add);
Vector &ea_data_bdr);
static const IntegrationRule &GetRule(Geometry::Type geom, int order,
FaceElementTransformations &T);
@@ -2899,33 +2867,11 @@ class DiscreteInterpolator : public BilinearFormIntegrator { };
class GradientInterpolator : public DiscreteInterpolator
{
public:
GradientInterpolator() : fake_fe(NULL) { }
virtual ~GradientInterpolator() { delete fake_fe; }
virtual void AssembleElementMatrix2(const FiniteElement &h1_fe,
const FiniteElement &nd_fe,
ElementTransformation &Trans,
DenseMatrix &elmat)
{ nd_fe.ProjectGrad(h1_fe, Trans, elmat); }
using BilinearFormIntegrator::AssemblePA;
/**
trial_fes should be H1 Lagrange
test_fes should be Nedelec
*/
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes);
virtual void AddMultPA(const Vector &x, Vector &y) const;
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
private:
/// 1D finit element that generates and owns the 1D DofToQuad maps below
FiniteElement * fake_fe;
const DofToQuad *maps_C_C; // one-d map with Lobatto rows, Lobatto columns
const DofToQuad *maps_O_C; // one-d map with Legendre rows, Lobatto columns
int dim, ne, o_dofs1D, c_dofs1D;
};
@@ -2940,24 +2886,6 @@ public:
ElementTransformation &Trans,
DenseMatrix &elmat)
{ ran_fe.Project(dom_fe, Trans, elmat); }
using BilinearFormIntegrator::AssemblePA;
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes);
virtual void AddMultPA(const Vector &x, Vector &y) const;
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
private:
/// 1D finit element that generates and owns the 1D DofToQuad maps below
FiniteElement * fake_fe;
const DofToQuad *maps_C_C; // one-d map with Lobatto rows, Lobatto columns
const DofToQuad *maps_O_C; // one-d map with Legendre rows, Lobatto columns
int dim, ne, o_dofs1D, c_dofs1D;
Vector pa_data;
};
+30 -58
View File
@@ -22,7 +22,6 @@ static void EAConvectionAssemble1D(const int NE,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -55,14 +54,7 @@ static void EAConvectionAssemble1D(const int NE,
{
val += r_Bj[k1] * D(k1, e) * r_Gi[k1];
}
if (add)
{
A(i1, j1, e) += val;
}
else
{
A(i1, j1, e) = val;
}
A(i1, j1, e) += val;
}
}
});
@@ -74,7 +66,6 @@ static void EAConvectionAssemble2D(const int NE,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -130,14 +121,7 @@ static void EAConvectionAssemble2D(const int NE,
* r_B[k1][j1]* r_B[k2][j2];
}
}
if (add)
{
A(i1, i2, j1, j2, e) += val;
}
else
{
A(i1, i2, j1, j2, e) = val;
}
A(i1, i2, j1, j2, e) += val;
}
}
}
@@ -151,7 +135,6 @@ static void EAConvectionAssemble3D(const int NE,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -208,14 +191,7 @@ static void EAConvectionAssemble3D(const int NE,
}
}
}
if (add)
{
A(i1, i2, i3, j1, j2, j3, e) += val;
}
else
{
A(i1, i2, i3, j1, j2, j3, e) = val;
}
A(i1, i2, i3, j1, j2, j3, e) += val;
}
}
}
@@ -226,8 +202,7 @@ static void EAConvectionAssemble3D(const int NE,
}
void ConvectionIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data,
const bool add)
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
@@ -237,47 +212,44 @@ void ConvectionIntegrator::AssembleEA(const FiniteElementSpace &fes,
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAConvectionAssemble1D<2,2>(ne,B,G,pa_data,ea_data,add);
case 0x33: return EAConvectionAssemble1D<3,3>(ne,B,G,pa_data,ea_data,add);
case 0x44: return EAConvectionAssemble1D<4,4>(ne,B,G,pa_data,ea_data,add);
case 0x55: return EAConvectionAssemble1D<5,5>(ne,B,G,pa_data,ea_data,add);
case 0x66: return EAConvectionAssemble1D<6,6>(ne,B,G,pa_data,ea_data,add);
case 0x77: return EAConvectionAssemble1D<7,7>(ne,B,G,pa_data,ea_data,add);
case 0x88: return EAConvectionAssemble1D<8,8>(ne,B,G,pa_data,ea_data,add);
case 0x99: return EAConvectionAssemble1D<9,9>(ne,B,G,pa_data,ea_data,add);
default: return EAConvectionAssemble1D(ne,B,G,pa_data,ea_data,add,
dofs1D,quad1D);
case 0x22: return EAConvectionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EAConvectionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EAConvectionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EAConvectionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EAConvectionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EAConvectionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EAConvectionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EAConvectionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAConvectionAssemble2D<2,2>(ne,B,G,pa_data,ea_data,add);
case 0x33: return EAConvectionAssemble2D<3,3>(ne,B,G,pa_data,ea_data,add);
case 0x44: return EAConvectionAssemble2D<4,4>(ne,B,G,pa_data,ea_data,add);
case 0x55: return EAConvectionAssemble2D<5,5>(ne,B,G,pa_data,ea_data,add);
case 0x66: return EAConvectionAssemble2D<6,6>(ne,B,G,pa_data,ea_data,add);
case 0x77: return EAConvectionAssemble2D<7,7>(ne,B,G,pa_data,ea_data,add);
case 0x88: return EAConvectionAssemble2D<8,8>(ne,B,G,pa_data,ea_data,add);
case 0x99: return EAConvectionAssemble2D<9,9>(ne,B,G,pa_data,ea_data,add);
default: return EAConvectionAssemble2D(ne,B,G,pa_data,ea_data,add,
dofs1D,quad1D);
case 0x22: return EAConvectionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EAConvectionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EAConvectionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EAConvectionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EAConvectionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EAConvectionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EAConvectionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EAConvectionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EAConvectionAssemble3D<2,3>(ne,B,G,pa_data,ea_data,add);
case 0x34: return EAConvectionAssemble3D<3,4>(ne,B,G,pa_data,ea_data,add);
case 0x45: return EAConvectionAssemble3D<4,5>(ne,B,G,pa_data,ea_data,add);
case 0x56: return EAConvectionAssemble3D<5,6>(ne,B,G,pa_data,ea_data,add);
case 0x67: return EAConvectionAssemble3D<6,7>(ne,B,G,pa_data,ea_data,add);
case 0x78: return EAConvectionAssemble3D<7,8>(ne,B,G,pa_data,ea_data,add);
case 0x89: return EAConvectionAssemble3D<8,9>(ne,B,G,pa_data,ea_data,add);
default: return EAConvectionAssemble3D(ne,B,G,pa_data,ea_data,add,
dofs1D,quad1D);
case 0x23: return EAConvectionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
case 0x34: return EAConvectionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
case 0x45: return EAConvectionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
case 0x56: return EAConvectionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
case 0x67: return EAConvectionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
case 0x78: return EAConvectionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
case 0x89: return EAConvectionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
+3 -3
View File
@@ -806,16 +806,16 @@ void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
vel.SetSize(dim * nq * ne);
auto C = Reshape(vel.HostWrite(), dim, nq, ne);
DenseMatrix Q_ir;
Vector Vq(dim);
for (int e = 0; e < ne; ++e)
{
ElementTransformation& T = *fes.GetElementTransformation(e);
Q->Eval(Q_ir, T, *ir);
for (int q = 0; q < nq; ++q)
{
Q->Eval(Vq, T, ir->IntPoint(q));
for (int i = 0; i < dim; ++i)
{
C(i,q,e) = Q_ir(i,q);
C(i,q,e) = Vq(i);
}
}
}
+55 -114
View File
@@ -20,8 +20,7 @@ static void EADGTraceAssemble1DInt(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext,
const bool add)
Vector &eadata_ext)
{
auto D = Reshape(padata.Read(), 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), 2, NF);
@@ -33,41 +32,23 @@ static void EADGTraceAssemble1DInt(const int NF,
val_ext10 = D(1, 0, f);
val_ext01 = D(0, 1, f);
val_int1 = D(1, 1, f);
if (add)
{
A_int(0, f) += val_int0;
A_int(1, f) += val_int1;
A_ext(0, f) += val_ext01;
A_ext(1, f) += val_ext10;
}
else
{
A_int(0, f) = val_int0;
A_int(1, f) = val_int1;
A_ext(0, f) = val_ext01;
A_ext(1, f) = val_ext10;
}
A_int(0, f) += val_int0;
A_int(1, f) += val_int1;
A_ext(0, f) += val_ext01;
A_ext(1, f) += val_ext10;
});
}
static void EADGTraceAssemble1DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr,
const bool add)
Vector &eadata_bdr)
{
auto D = Reshape(padata.Read(), 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), NF);
MFEM_FORALL(f, NF,
{
if (add)
{
A_bdr(f) += D(0, 0, f);
}
else
{
A_bdr(f) = D(0, 0, f);
}
A_bdr(f) += D(0, 0, f);
});
}
@@ -77,7 +58,6 @@ static void EADGTraceAssemble2DInt(const int NF,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -108,20 +88,10 @@ static void EADGTraceAssemble2DInt(const int NF,
val_ext10 += B(k1,i1) * B(k1,j1) * D(k1, 1, 0, f);
val_int1 += B(k1,i1) * B(k1,j1) * D(k1, 1, 1, f);
}
if (add)
{
A_int(i1, j1, 0, f) += val_int0;
A_int(i1, j1, 1, f) += val_int1;
A_ext(i1, j1, 0, f) += val_ext01;
A_ext(i1, j1, 1, f) += val_ext10;
}
else
{
A_int(i1, j1, 0, f) = val_int0;
A_int(i1, j1, 1, f) = val_int1;
A_ext(i1, j1, 0, f) = val_ext01;
A_ext(i1, j1, 1, f) = val_ext10;
}
A_int(i1, j1, 0, f) += val_int0;
A_int(i1, j1, 1, f) += val_int1;
A_ext(i1, j1, 0, f) += val_ext01;
A_ext(i1, j1, 1, f) += val_ext10;
}
}
});
@@ -132,7 +102,6 @@ static void EADGTraceAssemble2DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -156,14 +125,7 @@ static void EADGTraceAssemble2DBdr(const int NF,
{
val_bdr += B(k1,i1) * B(k1,j1) * D(k1, 0, 0, f);
}
if (add)
{
A_bdr(i1, j1, f) += val_bdr;
}
else
{
A_bdr(i1, j1, f) = val_bdr;
}
A_bdr(i1, j1, f) += val_bdr;
}
}
});
@@ -175,7 +137,6 @@ static void EADGTraceAssemble3DInt(const int NF,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -246,20 +207,10 @@ static void EADGTraceAssemble3DInt(const int NF,
* s_D[k1][k2][1][0];
}
}
if (add)
{
A_int(i1, i2, j1, j2, 0, f) += val_int0;
A_int(i1, i2, j1, j2, 1, f) += val_int1;
A_ext(i1, i2, j1, j2, 0, f) += val_ext01;
A_ext(i1, i2, j1, j2, 1, f) += val_ext10;
}
else
{
A_int(i1, i2, j1, j2, 0, f) = val_int0;
A_int(i1, i2, j1, j2, 1, f) = val_int1;
A_ext(i1, i2, j1, j2, 0, f) = val_ext01;
A_ext(i1, i2, j1, j2, 1, f) = val_ext10;
}
A_int(i1, i2, j1, j2, 0, f) += val_int0;
A_int(i1, i2, j1, j2, 1, f) += val_int1;
A_ext(i1, i2, j1, j2, 0, f) += val_ext01;
A_ext(i1, i2, j1, j2, 1, f) += val_ext10;
}
}
}
@@ -272,7 +223,6 @@ static void EADGTraceAssemble3DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -330,14 +280,7 @@ static void EADGTraceAssemble3DBdr(const int NF,
* s_D[k1][k2][0][0];
}
}
if (add)
{
A_bdr(i1, i2, j1, j2, f) += val_bdr;
}
else
{
A_bdr(i1, i2, j1, j2, f) = val_bdr;
}
A_bdr(i1, i2, j1, j2, f) += val_bdr;
}
}
}
@@ -347,8 +290,7 @@ static void EADGTraceAssemble3DBdr(const int NF,
void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext,
const bool add)
Vector &ea_data_ext)
{
SetupPA(fes, FaceType::Interior);
nf = fes.GetNFbyType(FaceType::Interior);
@@ -356,7 +298,7 @@ void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
const Array<double> &B = maps->B;
if (dim == 1)
{
return EADGTraceAssemble1DInt(nf,B,pa_data,ea_data_int,ea_data_ext,add);
return EADGTraceAssemble1DInt(nf,B,pa_data,ea_data_int,ea_data_ext);
}
else if (dim == 2)
{
@@ -364,31 +306,31 @@ void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
{
case 0x22:
return EADGTraceAssemble2DInt<2,2>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x33:
return EADGTraceAssemble2DInt<3,3>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x44:
return EADGTraceAssemble2DInt<4,4>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x55:
return EADGTraceAssemble2DInt<5,5>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x66:
return EADGTraceAssemble2DInt<6,6>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x77:
return EADGTraceAssemble2DInt<7,7>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x88:
return EADGTraceAssemble2DInt<8,8>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x99:
return EADGTraceAssemble2DInt<9,9>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
default:
return EADGTraceAssemble2DInt(nf,B,pa_data,ea_data_int,
ea_data_ext,add,dofs1D,quad1D);
ea_data_ext,dofs1D,quad1D);
}
}
else if (dim == 3)
@@ -397,36 +339,35 @@ void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
{
case 0x23:
return EADGTraceAssemble3DInt<2,3>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x34:
return EADGTraceAssemble3DInt<3,4>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x45:
return EADGTraceAssemble3DInt<4,5>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x56:
return EADGTraceAssemble3DInt<5,6>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x67:
return EADGTraceAssemble3DInt<6,7>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x78:
return EADGTraceAssemble3DInt<7,8>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
case 0x89:
return EADGTraceAssemble3DInt<8,9>(nf,B,pa_data,ea_data_int,
ea_data_ext,add);
ea_data_ext);
default:
return EADGTraceAssemble3DInt(nf,B,pa_data,ea_data_int,
ea_data_ext,add,dofs1D,quad1D);
ea_data_ext,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
void DGTraceIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr,
const bool add)
Vector &ea_data_bdr)
{
SetupPA(fes, FaceType::Boundary);
nf = fes.GetNFbyType(FaceType::Boundary);
@@ -434,37 +375,37 @@ void DGTraceIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
const Array<double> &B = maps->B;
if (dim == 1)
{
return EADGTraceAssemble1DBdr(nf,B,pa_data,ea_data_bdr,add);
return EADGTraceAssemble1DBdr(nf,B,pa_data,ea_data_bdr);
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADGTraceAssemble2DBdr<2,2>(nf,B,pa_data,ea_data_bdr,add);
case 0x33: return EADGTraceAssemble2DBdr<3,3>(nf,B,pa_data,ea_data_bdr,add);
case 0x44: return EADGTraceAssemble2DBdr<4,4>(nf,B,pa_data,ea_data_bdr,add);
case 0x55: return EADGTraceAssemble2DBdr<5,5>(nf,B,pa_data,ea_data_bdr,add);
case 0x66: return EADGTraceAssemble2DBdr<6,6>(nf,B,pa_data,ea_data_bdr,add);
case 0x77: return EADGTraceAssemble2DBdr<7,7>(nf,B,pa_data,ea_data_bdr,add);
case 0x88: return EADGTraceAssemble2DBdr<8,8>(nf,B,pa_data,ea_data_bdr,add);
case 0x99: return EADGTraceAssemble2DBdr<9,9>(nf,B,pa_data,ea_data_bdr,add);
case 0x22: return EADGTraceAssemble2DBdr<2,2>(nf,B,pa_data,ea_data_bdr);
case 0x33: return EADGTraceAssemble2DBdr<3,3>(nf,B,pa_data,ea_data_bdr);
case 0x44: return EADGTraceAssemble2DBdr<4,4>(nf,B,pa_data,ea_data_bdr);
case 0x55: return EADGTraceAssemble2DBdr<5,5>(nf,B,pa_data,ea_data_bdr);
case 0x66: return EADGTraceAssemble2DBdr<6,6>(nf,B,pa_data,ea_data_bdr);
case 0x77: return EADGTraceAssemble2DBdr<7,7>(nf,B,pa_data,ea_data_bdr);
case 0x88: return EADGTraceAssemble2DBdr<8,8>(nf,B,pa_data,ea_data_bdr);
case 0x99: return EADGTraceAssemble2DBdr<9,9>(nf,B,pa_data,ea_data_bdr);
default:
return EADGTraceAssemble2DBdr(nf,B,pa_data,ea_data_bdr,add,dofs1D,quad1D);
return EADGTraceAssemble2DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EADGTraceAssemble3DBdr<2,3>(nf,B,pa_data,ea_data_bdr,add);
case 0x34: return EADGTraceAssemble3DBdr<3,4>(nf,B,pa_data,ea_data_bdr,add);
case 0x45: return EADGTraceAssemble3DBdr<4,5>(nf,B,pa_data,ea_data_bdr,add);
case 0x56: return EADGTraceAssemble3DBdr<5,6>(nf,B,pa_data,ea_data_bdr,add);
case 0x67: return EADGTraceAssemble3DBdr<6,7>(nf,B,pa_data,ea_data_bdr,add);
case 0x78: return EADGTraceAssemble3DBdr<7,8>(nf,B,pa_data,ea_data_bdr,add);
case 0x89: return EADGTraceAssemble3DBdr<8,9>(nf,B,pa_data,ea_data_bdr,add);
case 0x23: return EADGTraceAssemble3DBdr<2,3>(nf,B,pa_data,ea_data_bdr);
case 0x34: return EADGTraceAssemble3DBdr<3,4>(nf,B,pa_data,ea_data_bdr);
case 0x45: return EADGTraceAssemble3DBdr<4,5>(nf,B,pa_data,ea_data_bdr);
case 0x56: return EADGTraceAssemble3DBdr<5,6>(nf,B,pa_data,ea_data_bdr);
case 0x67: return EADGTraceAssemble3DBdr<6,7>(nf,B,pa_data,ea_data_bdr);
case 0x78: return EADGTraceAssemble3DBdr<7,8>(nf,B,pa_data,ea_data_bdr);
case 0x89: return EADGTraceAssemble3DBdr<8,9>(nf,B,pa_data,ea_data_bdr);
default:
return EADGTraceAssemble3DBdr(nf,B,pa_data,ea_data_bdr,add,dofs1D,quad1D);
return EADGTraceAssemble3DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
+55 -81
View File
@@ -43,7 +43,7 @@ static void PADGTraceSetup2D(const int Q1D,
auto W = w.Read();
auto qd = Reshape(op.Write(), Q1D, 2, 2, NF);
MFEM_FORALL(f, NF, // can be optimized with Q1D thread for NF blocks
MFEM_FORALL(f, NF,//can be optimized with Q1D thread for NF blocks
{
for (int q = 0; q < Q1D; ++q)
{
@@ -85,7 +85,7 @@ static void PADGTraceSetup3D(const int Q1D,
auto W = w.Read();
auto qd = Reshape(op.Write(), Q1D, Q1D, 2, 2, NF);
MFEM_FORALL(f, NF, // can be optimized with Q1D*Q1D threads for NF blocks
MFEM_FORALL(f, NF,//can be optimized with Q1D*Q1D threads for NF blocks
{
for (int q1 = 0; q1 < Q1D; ++q1)
{
@@ -156,6 +156,57 @@ void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(symmDims * nq * nf, Device::GetMemoryType());
Vector r;
if (rho==nullptr)
{
r.SetSize(1);
r(0) = 1.0;
}
else if (ConstantCoefficient *c_rho = dynamic_cast<ConstantCoefficient*>(rho))
{
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);
auto C = Reshape(r.HostWrite(), nq, nf);
int f_ind = 0;
for (int f = 0; f < fes.GetNF(); ++f)
{
int e1, e2;
int inf1, inf2;
fes.GetMesh()->GetFaceElements(f, &e1, &e2);
fes.GetMesh()->GetFaceInfos(f, &inf1, &inf2);
int face_id = inf1 / 64;
if ((type==FaceType::Interior && (e2>=0 || (e2<0 && inf2>=0))) ||
(type==FaceType::Boundary && e2<0 && inf2<0) )
{
ElementTransformation& T = *fes.GetMesh()->GetFaceTransformation(f);
for (int q = 0; q < nq; ++q)
{
// Convert to lexicographic ordering
int iq = ToLexOrdering(dim, face_id, quad1D, q);
C(iq,f_ind) = rho->Eval(T, ir->IntPoint(q));
}
f_ind++;
}
}
MFEM_VERIFY(f_ind==nf, "Incorrect number of faces.");
}
Vector vel;
if (VectorConstantCoefficient *c_u = dynamic_cast<VectorConstantCoefficient*>
(u))
@@ -192,15 +243,12 @@ void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
if ((type==FaceType::Interior && (e2>=0 || (e2<0 && inf2>=0))) ||
(type==FaceType::Boundary && e2<0 && inf2<0) )
{
FaceElementTransformations &T =
*fes.GetMesh()->GetFaceElementTransformations(f);
ElementTransformation& T = *fes.GetMesh()->GetFaceTransformation(f);
for (int q = 0; q < nq; ++q)
{
// Convert to lexicographic ordering
int iq = ToLexOrdering(dim, face_id, quad1D, q);
T.SetAllIntPoints(&ir->IntPoint(q));
const IntegrationPoint &eip1 = T.GetElement1IntPoint();
u->Eval(Vq, *T.Elem1, eip1);
u->Eval(Vq, T, ir->IntPoint(q));
for (int i = 0; i < dim; ++i)
{
C(i,iq,f_ind) = Vq(i);
@@ -211,80 +259,6 @@ void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
}
MFEM_VERIFY(f_ind==nf, "Incorrect number of faces.");
}
Vector r;
if (rho==nullptr)
{
r.SetSize(1);
r(0) = 1.0;
}
else if (ConstantCoefficient *c_rho = dynamic_cast<ConstantCoefficient*>(rho))
{
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);
auto C_vel = Reshape(vel.HostRead(), dim, nq, nf);
auto n = Reshape(geom->normal.HostRead(), nq, dim, nf);
auto C = Reshape(r.HostWrite(), nq, nf);
int f_ind = 0;
for (int f = 0; f < fes.GetNF(); ++f)
{
int e1, e2;
int inf1, inf2;
fes.GetMesh()->GetFaceElements(f, &e1, &e2);
fes.GetMesh()->GetFaceInfos(f, &inf1, &inf2);
int face_id = inf1 / 64;
if ((type==FaceType::Interior && (e2>=0 || (e2<0 && inf2>=0))) ||
(type==FaceType::Boundary && e2<0 && inf2<0) )
{
FaceElementTransformations &T =
*fes.GetMesh()->GetFaceElementTransformations(f);
for (int q = 0; q < nq; ++q)
{
// Convert to lexicographic ordering
int iq = ToLexOrdering(dim, face_id, quad1D, q);
T.SetAllIntPoints(&ir->IntPoint(q));
const IntegrationPoint &eip1 = T.GetElement1IntPoint();
const IntegrationPoint &eip2 = T.GetElement2IntPoint();
double r;
if (inf2 < 0)
{
r = rho->Eval(*T.Elem1, eip1);
}
else
{
double udotn = 0.0;
for (int d=0; d<dim; ++d)
{
udotn += C_vel(d,iq,f_ind)*n(iq,d,f_ind);
}
if (udotn >= 0.0) { r = rho->Eval(*T.Elem2, eip2); }
else { r = rho->Eval(*T.Elem1, eip1); }
}
C(iq,f_ind) = r;
}
f_ind++;
}
}
MFEM_VERIFY(f_ind==nf, "Incorrect number of faces.");
}
PADGTraceSetup(dim, dofs1D, quad1D, nf, ir->GetWeights(),
geom->detJ, geom->normal, r, vel,
alpha, beta, pa_data);
+31 -59
View File
@@ -22,7 +22,6 @@ static void EADiffusionAssemble1D(const int NE,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -54,14 +53,7 @@ static void EADiffusionAssemble1D(const int NE,
{
val += r_Gj[k1] * D(k1, e) * r_Gi[k1];
}
if (add)
{
A(i1, j1, e) += val;
}
else
{
A(i1, j1, e) = val;
}
A(i1, j1, e) += val;
}
}
});
@@ -73,7 +65,6 @@ static void EADiffusionAssemble2D(const int NE,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -129,14 +120,7 @@ static void EADiffusionAssemble2D(const int NE,
+ gbi * D11 * gbj;
}
}
if (add)
{
A(i1, i2, j1, j2, e) += val;
}
else
{
A(i1, i2, j1, j2, e) = val;
}
A(i1, i2, j1, j2, e) += val;
}
}
}
@@ -146,11 +130,10 @@ static void EADiffusionAssemble2D(const int NE,
template<int T_D1D = 0, int T_Q1D = 0>
static void EADiffusionAssemble3D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Array<double> &b,
const Vector &padata,
Vector &eadata,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -225,14 +208,7 @@ static void EADiffusionAssemble3D(const int NE,
}
}
}
if (add)
{
A(i1, i2, i3, j1, j2, j3, e) += val;
}
else
{
A(i1, i2, i3, j1, j2, j3, e) = val;
}
A(i1, i2, i3, j1, j2, j3, e) += val;
}
}
}
@@ -243,8 +219,7 @@ static void EADiffusionAssemble3D(const int NE,
}
void DiffusionIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data,
const bool add)
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
@@ -254,47 +229,44 @@ void DiffusionIntegrator::AssembleEA(const FiniteElementSpace &fes,
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADiffusionAssemble1D<2,2>(ne,B,G,pa_data,ea_data,add);
case 0x33: return EADiffusionAssemble1D<3,3>(ne,B,G,pa_data,ea_data,add);
case 0x44: return EADiffusionAssemble1D<4,4>(ne,B,G,pa_data,ea_data,add);
case 0x55: return EADiffusionAssemble1D<5,5>(ne,B,G,pa_data,ea_data,add);
case 0x66: return EADiffusionAssemble1D<6,6>(ne,B,G,pa_data,ea_data,add);
case 0x77: return EADiffusionAssemble1D<7,7>(ne,B,G,pa_data,ea_data,add);
case 0x88: return EADiffusionAssemble1D<8,8>(ne,B,G,pa_data,ea_data,add);
case 0x99: return EADiffusionAssemble1D<9,9>(ne,B,G,pa_data,ea_data,add);
default: return EADiffusionAssemble1D(ne,B,G,pa_data,ea_data,add,
dofs1D,quad1D);
case 0x22: return EADiffusionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EADiffusionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EADiffusionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EADiffusionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EADiffusionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EADiffusionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EADiffusionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EADiffusionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADiffusionAssemble2D<2,2>(ne,B,G,pa_data,ea_data,add);
case 0x33: return EADiffusionAssemble2D<3,3>(ne,B,G,pa_data,ea_data,add);
case 0x44: return EADiffusionAssemble2D<4,4>(ne,B,G,pa_data,ea_data,add);
case 0x55: return EADiffusionAssemble2D<5,5>(ne,B,G,pa_data,ea_data,add);
case 0x66: return EADiffusionAssemble2D<6,6>(ne,B,G,pa_data,ea_data,add);
case 0x77: return EADiffusionAssemble2D<7,7>(ne,B,G,pa_data,ea_data,add);
case 0x88: return EADiffusionAssemble2D<8,8>(ne,B,G,pa_data,ea_data,add);
case 0x99: return EADiffusionAssemble2D<9,9>(ne,B,G,pa_data,ea_data,add);
default: return EADiffusionAssemble2D(ne,B,G,pa_data,ea_data,add,
dofs1D,quad1D);
case 0x22: return EADiffusionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EADiffusionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EADiffusionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EADiffusionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EADiffusionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EADiffusionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EADiffusionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EADiffusionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EADiffusionAssemble3D<2,3>(ne,B,G,pa_data,ea_data,add);
case 0x34: return EADiffusionAssemble3D<3,4>(ne,B,G,pa_data,ea_data,add);
case 0x45: return EADiffusionAssemble3D<4,5>(ne,B,G,pa_data,ea_data,add);
case 0x56: return EADiffusionAssemble3D<5,6>(ne,B,G,pa_data,ea_data,add);
case 0x67: return EADiffusionAssemble3D<6,7>(ne,B,G,pa_data,ea_data,add);
case 0x78: return EADiffusionAssemble3D<7,8>(ne,B,G,pa_data,ea_data,add);
case 0x89: return EADiffusionAssemble3D<8,9>(ne,B,G,pa_data,ea_data,add);
default: return EADiffusionAssemble3D(ne,B,G,pa_data,ea_data,add,
dofs1D,quad1D);
case 0x23: return EADiffusionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
case 0x34: return EADiffusionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
case 0x45: return EADiffusionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
case 0x56: return EADiffusionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
case 0x67: return EADiffusionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
case 0x78: return EADiffusionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
case 0x89: return EADiffusionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
+111 -104
View File
@@ -96,28 +96,26 @@ void PADiffusionSetup2D<2>(const int Q1D,
const Vector &c,
Vector &d)
{
const int NQ = Q1D*Q1D;
const bool const_c = c.Size() == 1;
const auto W = Reshape(w.Read(), Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,2,2,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
Reshape(c.Read(), Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
auto D = Reshape(d.Write(), NQ, 3, NE);
MFEM_FORALL(e, NE,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
for (int q = 0; q < NQ; ++q)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double J11 = J(qx,qy,0,0,e);
const double J21 = J(qx,qy,1,0,e);
const double J12 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
const double c_detJ = W(qx,qy) * coeff / ((J11*J22)-(J21*J12));
D(qx,qy,0,e) = c_detJ * (J12*J12 + J22*J22); // 1,1
D(qx,qy,1,e) = -c_detJ * (J12*J11 + J22*J21); // 1,2
D(qx,qy,2,e) = c_detJ * (J11*J11 + J21*J21); // 2,2
}
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double coeff = const_c ? C(0,0) : C(q,e);
const double c_detJ = W[q] * coeff / ((J11*J22)-(J21*J12));
D(q,0,e) = c_detJ * (J12*J12 + J22*J22); // 1,1
D(q,1,e) = -c_detJ * (J12*J11 + J22*J21); // 1,2
D(q,2,e) = c_detJ * (J11*J11 + J21*J21); // 2,2
}
});
}
@@ -133,35 +131,33 @@ void PADiffusionSetup2D<3>(const int Q1D,
{
constexpr int DIM = 2;
constexpr int SDIM = 3;
const int NQ = Q1D*Q1D;
const bool const_c = c.Size() == 1;
const auto W = Reshape(w.Read(), Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,SDIM,DIM,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
Reshape(c.Read(), Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, SDIM, DIM, NE);
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
auto D = Reshape(d.Write(), NQ, 3, NE);
MFEM_FORALL(e, NE,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
for (int q = 0; q < NQ; ++q)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double wq = W(qx,qy);
const double J11 = J(qx,qy,0,0,e);
const double J21 = J(qx,qy,1,0,e);
const double J31 = J(qx,qy,2,0,e);
const double J12 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double J32 = J(qx,qy,2,1,e);
const double E = J11*J11 + J21*J21 + J31*J31;
const double G = J12*J12 + J22*J22 + J32*J32;
const double F = J11*J12 + J21*J22 + J31*J32;
const double iw = 1.0 / sqrt(E*G - F*F);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
const double alpha = wq * coeff * iw;
D(qx,qy,0,e) = alpha * G; // 1,1
D(qx,qy,1,e) = -alpha * F; // 1,2
D(qx,qy,2,e) = alpha * E; // 2,2
}
const double wq = W[q];
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J31 = J(q,2,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double J32 = J(q,2,1,e);
const double E = J11*J11 + J21*J21 + J31*J31;
const double G = J12*J12 + J22*J22 + J32*J32;
const double F = J11*J12 + J21*J22 + J31*J32;
const double iw = 1.0 / sqrt(E*G - F*F);
const double coeff = const_c ? C(0,0) : C(q,e);
const double alpha = wq * coeff * iw;
D(q,0,e) = alpha * G; // 1,1
D(q,1,e) = -alpha * F; // 1,2
D(q,2,e) = alpha * E; // 2,2
}
});
}
@@ -174,53 +170,47 @@ static void PADiffusionSetup3D(const int Q1D,
const Vector &c,
Vector &d)
{
const int NQ = Q1D*Q1D*Q1D;
const bool const_c = c.Size() == 1;
const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1) :
Reshape(c.Read(), Q1D,Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D,Q1D, 6, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
auto D = Reshape(d.Write(), NQ, 6, NE);
MFEM_FORALL(e, NE,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
for (int q = 0; q < NQ; ++q)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double J11 = J(qx,qy,qz,0,0,e);
const double J21 = J(qx,qy,qz,1,0,e);
const double J31 = J(qx,qy,qz,2,0,e);
const double J12 = J(qx,qy,qz,0,1,e);
const double J22 = J(qx,qy,qz,1,1,e);
const double J32 = J(qx,qy,qz,2,1,e);
const double J13 = J(qx,qy,qz,0,2,e);
const double J23 = J(qx,qy,qz,1,2,e);
const double J33 = J(qx,qy,qz,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double coeff = const_c ? C(0,0,0,0) : C(qx,qy,qz,e);
const double c_detJ = W(qx,qy,qz) * coeff / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
D(qx,qy,qz,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
D(qx,qy,qz,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
D(qx,qy,qz,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
D(qx,qy,qz,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
D(qx,qy,qz,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
D(qx,qy,qz,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
}
}
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J31 = J(q,2,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double J32 = J(q,2,1,e);
const double J13 = J(q,0,2,e);
const double J23 = J(q,1,2,e);
const double J33 = J(q,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double coeff = const_c ? C(0,0) : C(q,e);
const double c_detJ = W[q] * coeff / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
D(q,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
D(q,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
D(q,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
D(q,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
D(q,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
D(q,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
}
});
}
@@ -263,7 +253,8 @@ static void PADiffusionSetup(const int dim,
}
}
void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes)
void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
const bool force)
{
// Assuming the same element type
fespace = &fes;
@@ -272,7 +263,7 @@ void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes)
const FiniteElement &el = *fes.GetFE(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
if (DeviceCanUseCeed() && !force)
{
if (ceedDataPtr) { delete ceedDataPtr; }
CeedData* ptr = new CeedData();
@@ -280,6 +271,8 @@ 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
@@ -756,17 +749,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);
}
@@ -1680,7 +1665,7 @@ static void PADiffusionApply(const int dim,
MFEM_ABORT("OCCA PADiffusionApply unknown kernel!");
}
#endif // MFEM_USE_OCCA
const int ID = (D1D << 4) | Q1D;
const int ID = (D1D << 4 ) | Q1D;
if (dim == 2)
{
@@ -1723,7 +1708,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
+1 -1
View File
@@ -334,7 +334,7 @@ static void PAGradientApplyTranspose2D(const int NE,
const int q1d = 0)
{
// TODO
MFEM_ASSERT(false, "PAGradientApplyTranspose2D not implemented.");
MFEM_ASSERT(false, "GradientPAApplyTranspose 3D not implemented.");
}
// PA Gradient Apply 3D kernel
+292 -4256
View File
File diff suppressed because it is too large Load Diff
+30 -58
View File
@@ -21,7 +21,6 @@ static void EAMassAssemble1D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -53,14 +52,7 @@ static void EAMassAssemble1D(const int NE,
{
val += r_Bi[k1] * r_Bj[k1] * D(k1, e);
}
if (add)
{
M(i1, j1, e) += val;
}
else
{
M(i1, j1, e) = val;
}
M(i1, j1, e) += val;
}
}
});
@@ -71,7 +63,6 @@ static void EAMassAssemble2D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -123,14 +114,7 @@ static void EAMassAssemble2D(const int NE,
* s_D[k1][k2];
}
}
if (add)
{
M(i1, i2, j1, j2, e) += val;
}
else
{
M(i1, i2, j1, j2, e) = val;
}
M(i1, i2, j1, j2, e) += val;
}
}
}
@@ -143,7 +127,6 @@ static void EAMassAssemble3D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const bool add,
const int d1d = 0,
const int q1d = 0)
{
@@ -206,14 +189,7 @@ static void EAMassAssemble3D(const int NE,
}
}
}
if (add)
{
M(i1, i2, i3, j1, j2, j3, e) += val;
}
else
{
M(i1, i2, i3, j1, j2, j3, e) = val;
}
M(i1, i2, i3, j1, j2, j3, e) += val;
}
}
}
@@ -224,8 +200,7 @@ static void EAMassAssemble3D(const int NE,
}
void MassIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data,
const bool add)
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
@@ -234,47 +209,44 @@ void MassIntegrator::AssembleEA(const FiniteElementSpace &fes,
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAMassAssemble1D<2,2>(ne,B,pa_data,ea_data,add);
case 0x33: return EAMassAssemble1D<3,3>(ne,B,pa_data,ea_data,add);
case 0x44: return EAMassAssemble1D<4,4>(ne,B,pa_data,ea_data,add);
case 0x55: return EAMassAssemble1D<5,5>(ne,B,pa_data,ea_data,add);
case 0x66: return EAMassAssemble1D<6,6>(ne,B,pa_data,ea_data,add);
case 0x77: return EAMassAssemble1D<7,7>(ne,B,pa_data,ea_data,add);
case 0x88: return EAMassAssemble1D<8,8>(ne,B,pa_data,ea_data,add);
case 0x99: return EAMassAssemble1D<9,9>(ne,B,pa_data,ea_data,add);
default: return EAMassAssemble1D(ne,B,pa_data,ea_data,add,
dofs1D,quad1D);
case 0x22: return EAMassAssemble1D<2,2>(ne,B,pa_data,ea_data);
case 0x33: return EAMassAssemble1D<3,3>(ne,B,pa_data,ea_data);
case 0x44: return EAMassAssemble1D<4,4>(ne,B,pa_data,ea_data);
case 0x55: return EAMassAssemble1D<5,5>(ne,B,pa_data,ea_data);
case 0x66: return EAMassAssemble1D<6,6>(ne,B,pa_data,ea_data);
case 0x77: return EAMassAssemble1D<7,7>(ne,B,pa_data,ea_data);
case 0x88: return EAMassAssemble1D<8,8>(ne,B,pa_data,ea_data);
case 0x99: return EAMassAssemble1D<9,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble1D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAMassAssemble2D<2,2>(ne,B,pa_data,ea_data,add);
case 0x33: return EAMassAssemble2D<3,3>(ne,B,pa_data,ea_data,add);
case 0x44: return EAMassAssemble2D<4,4>(ne,B,pa_data,ea_data,add);
case 0x55: return EAMassAssemble2D<5,5>(ne,B,pa_data,ea_data,add);
case 0x66: return EAMassAssemble2D<6,6>(ne,B,pa_data,ea_data,add);
case 0x77: return EAMassAssemble2D<7,7>(ne,B,pa_data,ea_data,add);
case 0x88: return EAMassAssemble2D<8,8>(ne,B,pa_data,ea_data,add);
case 0x99: return EAMassAssemble2D<9,9>(ne,B,pa_data,ea_data,add);
default: return EAMassAssemble2D(ne,B,pa_data,ea_data,add,
dofs1D,quad1D);
case 0x22: return EAMassAssemble2D<2,2>(ne,B,pa_data,ea_data);
case 0x33: return EAMassAssemble2D<3,3>(ne,B,pa_data,ea_data);
case 0x44: return EAMassAssemble2D<4,4>(ne,B,pa_data,ea_data);
case 0x55: return EAMassAssemble2D<5,5>(ne,B,pa_data,ea_data);
case 0x66: return EAMassAssemble2D<6,6>(ne,B,pa_data,ea_data);
case 0x77: return EAMassAssemble2D<7,7>(ne,B,pa_data,ea_data);
case 0x88: return EAMassAssemble2D<8,8>(ne,B,pa_data,ea_data);
case 0x99: return EAMassAssemble2D<9,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble2D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EAMassAssemble3D<2,3>(ne,B,pa_data,ea_data,add);
case 0x34: return EAMassAssemble3D<3,4>(ne,B,pa_data,ea_data,add);
case 0x45: return EAMassAssemble3D<4,5>(ne,B,pa_data,ea_data,add);
case 0x56: return EAMassAssemble3D<5,6>(ne,B,pa_data,ea_data,add);
case 0x67: return EAMassAssemble3D<6,7>(ne,B,pa_data,ea_data,add);
case 0x78: return EAMassAssemble3D<7,8>(ne,B,pa_data,ea_data,add);
case 0x89: return EAMassAssemble3D<8,9>(ne,B,pa_data,ea_data,add);
default: return EAMassAssemble3D(ne,B,pa_data,ea_data,add,
dofs1D,quad1D);
case 0x23: return EAMassAssemble3D<2,3>(ne,B,pa_data,ea_data);
case 0x34: return EAMassAssemble3D<3,4>(ne,B,pa_data,ea_data);
case 0x45: return EAMassAssemble3D<4,5>(ne,B,pa_data,ea_data);
case 0x56: return EAMassAssemble3D<5,6>(ne,B,pa_data,ea_data);
case 0x67: return EAMassAssemble3D<6,7>(ne,B,pa_data,ea_data);
case 0x78: return EAMassAssemble3D<7,8>(ne,B,pa_data,ea_data);
case 0x89: return EAMassAssemble3D<8,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble3D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
+217 -146
View File
@@ -1,13 +1,13 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
// 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 see http://mfem.org.
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
@@ -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
fespace = &fes;
@@ -33,7 +33,7 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
ElementTransformation *T = mesh->GetElementTransformation(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, *T);
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
if (DeviceCanUseCeed() && !force)
{
if (ceedDataPtr) { delete ceedDataPtr; }
CeedData* ptr = new CeedData();
@@ -41,6 +41,8 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
InitCeedCoeff(Q, ptr);
return CeedPAMassAssemble(fes, *ir, *ptr);
}
#else
MFEM_CONTRACT_VAR(force);
#endif
dim = mesh->Dimension();
ne = fes.GetMesh()->GetNE();
@@ -50,7 +52,7 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(ne*nq, Device::GetMemoryType());
pa_data.SetSize(ne*nq, Device::GetDeviceMemoryType());
Vector coeff;
if (Q == nullptr)
{
@@ -92,64 +94,49 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
if (dim==2)
{
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);
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,2,2,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D, NE);
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
auto w = ir->GetWeights().Read();
auto J = Reshape(geom->J.Read(), NQ,2,2,NE);
auto C =
const_c ? Reshape(coeff.Read(), 1,1) : Reshape(coeff.Read(), NQ,NE);
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)
{
const double J11 = J(qx,qy,0,0,e);
const double J12 = J(qx,qy,1,0,e);
const double J21 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double detJ = (J11*J22)-(J21*J12);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
v(qx,qy,e) = W(qx,qy) * coeff * detJ;
}
const double J11 = J(q,0,0,e);
const double J12 = J(q,1,0,e);
const double J21 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double detJ = (J11*J22)-(J21*J12);
const double coeff = const_c ? C(0,0) : C(q,e);
v(q,e) = w[q] * coeff * detJ;
}
});
}
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 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);
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;
}
});
}
@@ -468,16 +455,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);
}
@@ -950,9 +929,8 @@ static void SmemPAMassApply3D(const int NE,
auto d = Reshape(d_.Read(), Q1D, Q1D, Q1D, 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, Q1D,
MFEM_FORALL_3D(e, NE, Q1D, Q1D, 1,
{
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;
@@ -969,130 +947,188 @@ static void SmemPAMassApply3D(const int NE,
double (*QQQ)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) sm1;
double (*QQD)[MQ1][MD1] = (double (*)[MQ1][MD1]) sm0;
double (*QDD)[MD1][MD1] = (double (*)[MD1][MD1]) sm1;
MFEM_FOREACH_THREAD(dz,z,D1D)
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
MFEM_FOREACH_THREAD(dx,x,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
X[dz][dy][dx] = x(dx,dy,dz,e);
}
}
}
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
MFEM_FOREACH_THREAD(dx,x,Q1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
B[q][d] = b(q,d);
}
B[dx][dy] = b(dx,dy);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1D)
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
double u[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++)
{
double u = 0.0;
for (int dx = 0; dx < D1D; ++dx)
{
u += X[dz][dy][dx] * B[qx][dx];
}
DDQ[dz][dy][qx] = u;
u[dz] = 0;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
MFEM_UNROLL(MD1)
for (int dx = 0; dx < D1D; ++dx)
{
double u = 0.0;
for (int dy = 0; dy < D1D; ++dy)
{
u += DDQ[dz][dy][qx] * B[qy][dy];
}
DQQ[dz][qy][qx] = u;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u = 0.0;
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
u += DQQ[dz][qy][qx] * B[qz][dz];
u[dz] += X[dz][dy][dx] * B[qx][dx];
}
QQQ[qz][qy][qx] = u * d(qx,qy,qz,e);
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
DDQ[dz][dy][qx] = u[dz];
}
}
}
MFEM_SYNC_THREAD;
if (tidz == 0)
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(d,y,D1D)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
double u[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++)
{
Bt[d][q] = b(q,d);
u[dz] = 0;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
MFEM_UNROLL(MD1)
for (int dy = 0; dy < D1D; ++dy)
{
double u = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++)
{
u += QQQ[qz][qy][qx] * Bt[dx][qx];
u[dz] += DDQ[dz][dy][qx] * B[qy][dy];
}
QQD[qz][qy][dx] = u;
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++)
{
DQQ[dz][qy][qx] = u[dz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz,z,Q1D)
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
double u[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++)
{
double u = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
u[qz] = 0;
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++)
{
u += QQD[qz][qy][dx] * Bt[dy][qy];
u[qz] += DQQ[dz][qy][qx] * B[qz][dz];
}
QDD[qz][dy][dx] = u;
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++)
{
QQQ[qz][qy][qx] = u[qz] * d(qx,qy,qz,e);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1D)
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
MFEM_FOREACH_THREAD(q,x,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
Bt[d][q] = b(q,d);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
double u = 0.0;
u[qz] = 0;
}
MFEM_UNROLL(MQ1)
for (int qx = 0; qx < Q1D; ++qx)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u += QDD[qz][dy][dx] * Bt[dz][qz];
u[qz] += QQQ[qz][qy][qx] * Bt[dx][qx];
}
y(dx,dy,dz,e) += u;
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
QQD[qz][qy][dx] = u[qz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] = 0;
}
MFEM_UNROLL(MQ1)
for (int qy = 0; qy < Q1D; ++qy)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += QQD[qz][qy][dx] * Bt[dy][qy];
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
QDD[qz][dy][dx] = u[qz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
u[dz] = 0;
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
u[dz] += QDD[qz][dy][dx] * Bt[dz][qz];
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
y(dx,dy,dz,e) += u[dz];
}
}
}
@@ -1123,14 +1159,20 @@ static void PAMassApply(const int dim,
MFEM_ABORT("OCCA PA Mass Apply unknown kernel!");
}
#endif // MFEM_USE_OCCA
const int id = (D1D << 4) | Q1D;
if (dim == 2)
{
switch ((D1D << 4) | Q1D)
switch (id)
{
case 0x22: return SmemPAMassApply2D<2,2,16>(NE,B,Bt,D,X,Y);
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 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 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 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);
case 0x88: return SmemPAMassApply2D<8,8,2>(NE,B,Bt,D,X,Y);
@@ -1140,18 +1182,25 @@ static void PAMassApply(const int dim,
}
else if (dim == 3)
{
switch ((D1D << 4) | Q1D)
switch (id)
{
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 0x36: return SmemPAMassApply3D<3,6>(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);
case 0x56: return SmemPAMassApply3D<5,6>(NE,B,Bt,D,X,Y);
case 0x58: return SmemPAMassApply3D<5,8>(NE,B,Bt,D,X,Y);
case 0x67: return SmemPAMassApply3D<6,7>(NE,B,Bt,D,X,Y);
case 0x78: return SmemPAMassApply3D<7,8>(NE,B,Bt,D,X,Y);
case 0x89: return SmemPAMassApply3D<8,9>(NE,B,Bt,D,X,Y);
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 kernel 0x" << std::hex << id << std::endl;
MFEM_ABORT("Unknown kernel.");
}
@@ -1160,7 +1209,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
+56 -139
View File
@@ -16,171 +16,88 @@ namespace mfem
{
void TransposeIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data, const bool add)
Vector &ea_data)
{
if (add)
Vector ea_data_tmp(ea_data.Size());
ea_data_tmp = 0.0;
bfi->AssembleEA(fes, ea_data_tmp);
const int ne = fes.GetNE();
if (ne == 0) { return; }
const int dofs = fes.GetFE(0)->GetDof();
auto A = Reshape(ea_data_tmp.Write(), dofs, dofs, ne);
auto AT = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
MFEM_FORALL(e, ne,
{
Vector ea_data_tmp(ea_data.Size());
bfi->AssembleEA(fes, ea_data_tmp, false);
const int ne = fes.GetNE();
if (ne == 0) { return; }
const int dofs = fes.GetFE(0)->GetDof();
auto A = Reshape(ea_data_tmp.Read(), dofs, dofs, ne);
auto AT = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
MFEM_FORALL(e, ne,
for (int i = 0; i < dofs; i++)
{
for (int i = 0; i < dofs; i++)
for (int j = 0; j < dofs; j++)
{
for (int j = 0; j < dofs; j++)
{
const double a = A(i, j, e);
AT(j, i, e) += a;
}
const double a = A(i, j, e);
AT(j, i, e) += a;
}
});
}
else
{
bfi->AssembleEA(fes, ea_data, false);
const int ne = fes.GetNE();
if (ne == 0) { return; }
const int dofs = fes.GetFE(0)->GetDof();
auto A = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
MFEM_FORALL(e, ne,
{
for (int i = 0; i < dofs; i++)
{
for (int j = i+1; j < dofs; j++)
{
const double aij = A(i, j, e);
const double aji = A(j, i, e);
A(j, i, e) = aij;
A(i, j, e) = aji;
}
}
});
}
}
});
}
void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext,
const bool add)
Vector &ea_data_ext)
{
const int nf = fes.GetNFbyType(FaceType::Interior);
if (nf == 0) { return; }
if (add)
Vector ea_data_int_tmp(ea_data_int.Size());
Vector ea_data_ext_tmp(ea_data_ext.Size());
ea_data_int_tmp = 0.0;
ea_data_ext_tmp = 0.0;
bfi->AssembleEAInteriorFaces(fes, ea_data_int_tmp, ea_data_ext_tmp);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_int = Reshape(ea_data_int_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
auto AT_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
MFEM_FORALL(f, nf,
{
Vector ea_data_int_tmp(ea_data_int.Size());
Vector ea_data_ext_tmp(ea_data_ext.Size());
bfi->AssembleEAInteriorFaces(fes, ea_data_int_tmp, ea_data_ext_tmp, false);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_int = Reshape(ea_data_int_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
auto AT_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
MFEM_FORALL(f, nf,
for (int i = 0; i < faceDofs; i++)
{
for (int i = 0; i < faceDofs; i++)
for (int j = 0; j < faceDofs; j++)
{
for (int j = 0; j < faceDofs; j++)
{
const double a_int0 = A_int(i, j, 0, f);
const double a_int1 = A_int(i, j, 1, f);
const double a_ext0 = A_ext(i, j, 0, f);
const double a_ext1 = A_ext(i, j, 1, f);
AT_int(j, i, 0, f) += a_int0;
AT_int(j, i, 1, f) += a_int1;
AT_ext(j, i, 0, f) += a_ext1;
AT_ext(j, i, 1, f) += a_ext0;
}
const double a_int0 = A_int(i, j, 0, f);
const double a_int1 = A_int(i, j, 1, f);
const double a_ext0 = A_ext(i, j, 0, f);
const double a_ext1 = A_ext(i, j, 1, f);
AT_int(j, i, 0, f) += a_int0;
AT_int(j, i, 1, f) += a_int1;
AT_ext(j, i, 0, f) += a_ext1;
AT_ext(j, i, 1, f) += a_ext0;
}
});
}
else
{
bfi->AssembleEAInteriorFaces(fes, ea_data_int, ea_data_ext, false);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
auto A_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
MFEM_FORALL(f, nf,
{
for (int i = 0; i < faceDofs; i++)
{
for (int j = i+1; j < faceDofs; j++)
{
const double aij_int0 = A_int(i, j, 0, f);
const double aij_int1 = A_int(i, j, 1, f);
const double aji_int0 = A_int(j, i, 0, f);
const double aji_int1 = A_int(j, i, 1, f);
A_int(j, i, 0, f) = aij_int0;
A_int(j, i, 1, f) = aij_int1;
A_int(i, j, 0, f) = aji_int0;
A_int(i, j, 1, f) = aji_int1;
}
}
for (int i = 0; i < faceDofs; i++)
{
for (int j = 0; j < faceDofs; j++)
{
const double aij_ext0 = A_ext(i, j, 0, f);
const double aji_ext1 = A_ext(j, i, 1, f);
A_ext(j, i, 1, f) = aij_ext0;
A_ext(i, j, 0, f) = aji_ext1;
}
}
});
}
}
});
}
void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr,
const bool add)
Vector &ea_data_bdr)
{
const int nf = fes.GetNFbyType(FaceType::Boundary);
if (nf == 0) { return; }
if (add)
Vector ea_data_bdr_tmp(ea_data_bdr.Size());
ea_data_bdr_tmp = 0.0;
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr_tmp);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
MFEM_FORALL(f, nf,
{
Vector ea_data_bdr_tmp(ea_data_bdr.Size());
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr_tmp, false);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
MFEM_FORALL(f, nf,
for (int i = 0; i < faceDofs; i++)
{
for (int i = 0; i < faceDofs; i++)
for (int j = 0; j < faceDofs; j++)
{
for (int j = 0; j < faceDofs; j++)
{
const double a_bdr = A_bdr(i, j, f);
AT_bdr(j, i, f) += a_bdr;
}
const double a_bdr = A_bdr(i, j, f);
AT_bdr(j, i, f) += a_bdr;
}
});
}
else
{
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr, false);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
MFEM_FORALL(f, nf,
{
for (int i = 0; i < faceDofs; i++)
{
for (int j = i+1; j < faceDofs; j++)
{
const double aij_bdr = A_bdr(i, j, f);
const double aji_bdr = A_bdr(j, i, f);
A_bdr(j, i, f) = aij_bdr;
A_bdr(i, j, f) = aji_bdr;
}
}
});
}
}
});
}
}
+84 -253
View File
@@ -20,96 +20,58 @@ void PAHcurlSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff,
Vector &_coeff,
Vector &op);
void PAHcurlSetup2Din3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHcurlSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff,
Vector &_coeff,
Vector &op);
void PAHcurlMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &bo,
const Array<double> &bc,
const Vector &pa_data,
Vector &diag);
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHcurlMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &bo,
const Array<double> &bc,
const Vector &pa_data,
Vector &diag);
void PAHcurlMassAssembleDiagonal3DHost(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
template<int T_D1D = 0, int T_Q1D = 0>
void SmemPAHcurlMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &bo,
const Array<double> &bc,
const Vector &pa_data,
Vector &diag);
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &bo,
const Array<double> &bc,
const Array<double> &bot,
const Array<double> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y);
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &bo,
const Array<double> &bc,
const Array<double> &bot,
const Array<double> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y);
template<int T_D1D = 0, int T_Q1D = 0>
void SmemPAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &bo,
const Array<double> &bc,
const Array<double> &bot,
const Array<double> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y);
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHdivSetup2D(const int Q1D,
const int NE,
@@ -128,24 +90,24 @@ void PAHdivSetup3D(const int Q1D,
void PAHcurlH1Apply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &bc,
const Array<double> &gc,
const Array<double> &bot,
const Array<double> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y);
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHcurlH1Apply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &bc,
const Array<double> &gc,
const Array<double> &bot,
const Array<double> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y);
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHdivMassAssembleDiagonal2D(const int D1D,
const int Q1D,
@@ -737,14 +699,8 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
{
// Assumes tensor-product elements
Mesh *mesh = trial_fes.GetMesh();
dim = mesh->Dimension();
const bool bdryInteg = isBdryInteg;
// TODO: this implementation applies boundary markers just by setting coeff to zero on boundary elements. It would be better to skip those elements in AddMultPA.
const FiniteElement *trial_fel = bdryInteg ? trial_fes.GetBE(
0) : trial_fes.GetFE(0);
const FiniteElement *trial_fel = trial_fes.GetFE(0);
const VectorTensorFiniteElement *trial_el =
dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
@@ -754,38 +710,21 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
if (bdryInteg)
{
MFEM_VERIFY(trial_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3 &&
mesh->SpaceDimension() == 3 && trial_el->GetDim() == 2, "");
}
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
bdryInteg ? *mesh->GetBdrElementTransformation(0) :
*mesh->GetElementTransformation(0));
const int dims = trial_el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
ne = bdryInteg ? trial_fes.GetNBE() : trial_fes.GetNE();
Vector bdryJac;
if (bdryInteg)
{
bdryJac.SetSize(ne*nq*6);
}
else
{
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
}
MFEM_VERIFY(ne == (bdryInteg ? test_fes.GetNBE() : test_fes.GetNE()),
ne = trial_fes.GetNE();
MFEM_VERIFY(ne == test_fes.GetNE(),
"Different meshes for test and trial spaces");
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &trial_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &trial_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
@@ -807,24 +746,17 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
symmetric = MQ ? MQ->IsSymmetric() : true;
const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
if ((trial_curl && test_div) || (trial_div && test_curl))
if ((trial_fetype == mfem::FiniteElement::CURL &&
test_fetype == mfem::FiniteElement::DIV) ||
(trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == mfem::FiniteElement::CURL))
pa_data.SetSize((coeffDim == 1 ? 1 : dim*dim) * nq * ne,
Device::GetMemoryType());
else
pa_data.SetSize((symmetric ? symmDims : MQfullDim) * nq * ne,
Device::GetMemoryType());
if (bdryInteg)
{
MFEM_VERIFY(coeffDim == 1 && dims == 2, "");
}
Vector coeff(coeffDim * nq * ne);
Vector coeff(coeffDim * ne * nq);
coeff = 1.0;
auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
if (Q || VQ || MQ)
@@ -856,8 +788,7 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = bdryInteg ? mesh->GetBdrElementTransformation(
e) : mesh->GetElementTransformation(e);
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
if (MQ)
@@ -898,89 +829,34 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
}
}
if (el_marker)
if (trial_fetype == mfem::FiniteElement::CURL && test_fetype == trial_fetype
&& dim == 3)
{
MFEM_VERIFY(bdryInteg, "");
MFEM_VERIFY(el_marker->Size() == mesh->bdr_attributes.Max(), "");
for (int e=0; e<ne; ++e)
{
const int el_attr = (bdryInteg) ? mesh->GetBdrAttribute(e) : -1;
MFEM_VERIFY(el_attr > 0, "");
if ((*el_marker)[el_attr-1] == 0)
{
for (int p=0; p<nq; ++p)
{
for (int i=0; i<coeffDim; ++i)
{
coeffh(i, p, e) = 0.0;
}
}
}
}
}
if (isBdryInteg || (trial_el->GetDerivType() == mfem::FiniteElement::CURL &&
dim == 2 && mesh->SpaceDimension() == 3))
{
MFEM_VERIFY(coeffDim == 1,
""); // Vector coefficient not implemented in this case
if (isBdryInteg)
{
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetBdrElementTransformation(e);
for (int q = 0; q < nq; ++q)
{
tr->SetIntPoint(&(ir->IntPoint(q)));
const DenseMatrix& jac = tr->Jacobian();
for (int i=0; i<3; ++i)
for (int j=0; j<2; ++j)
{
bdryJac[(6*nq*e) + (3*nq*j) + (i*nq) + q] = jac(i,j);
}
}
}
}
else
{
// J is allocated as 3x3, but entries (i,j) are set only for 0 <= i < 3, 0 <= j < 2.
// That is, on each element J is 3x2 with 6 entries, not 9, so the last third of geom->J is unused.
MFEM_VERIFY(geom->J.Size() == 6 * ne * nq, "");
}
PAHcurlSetup2Din3D(quad1D, ne, ir->GetWeights(),
isBdryInteg ? bdryJac : geom->J,
coeff, pa_data);
}
else if (trial_curl && test_curl && dim == 3)
{
#ifdef SETUPONHOST
PAHcurlSetup3DHost(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
#else
PAHcurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
#endif
}
else if (trial_curl && test_curl && dim == 2)
else if (trial_fetype == mfem::FiniteElement::CURL
&& test_fetype == trial_fetype && dim == 2)
{
PAHcurlSetup2D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (trial_div && test_div && dim == 3)
else if (trial_fetype == mfem::FiniteElement::DIV
&& test_fetype == trial_fetype && dim == 3)
{
PAHdivSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (trial_div && test_div && dim == 2)
else if (trial_fetype == mfem::FiniteElement::DIV
&& test_fetype == trial_fetype && dim == 2)
{
PAHdivSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (((trial_curl && test_div) || (trial_div && test_curl)) &&
else if (((trial_fetype == mfem::FiniteElement::CURL &&
test_fetype == mfem::FiniteElement::DIV) ||
(trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == mfem::FiniteElement::CURL)) &&
test_fel->GetOrder() == trial_fel->GetOrder())
{
if (coeffDim == 1)
@@ -989,7 +865,8 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
}
else
{
const bool tr = (trial_div && test_curl);
const bool tr = (trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == mfem::FiniteElement::CURL);
if (dim == 3)
PAHcurlHdivSetup3D(quad1D, coeffDim, ne, tr, ir->GetWeights(),
geom->J, coeff, pa_data);
@@ -1010,30 +887,8 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
{
if (trial_fetype == mfem::FiniteElement::CURL && test_fetype == trial_fetype)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
const int ID = (dofs1D << 4) | quad1D;
switch (ID)
{
case 0x23: return SmemPAHcurlMassAssembleDiagonal3D<2,3>(dofs1D, quad1D, ne,
symmetric,
mapsO->B, mapsC->B, pa_data, diag);
case 0x34: return SmemPAHcurlMassAssembleDiagonal3D<3,4>(dofs1D, quad1D, ne,
symmetric,
mapsO->B, mapsC->B, pa_data, diag);
case 0x45: return SmemPAHcurlMassAssembleDiagonal3D<4,5>(dofs1D, quad1D, ne,
symmetric,
mapsO->B, mapsC->B, pa_data, diag);
case 0x56: return SmemPAHcurlMassAssembleDiagonal3D<5,6>(dofs1D, quad1D, ne,
symmetric,
mapsO->B, mapsC->B, pa_data, diag);
default: return SmemPAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, pa_data, diag);
}
}
else
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, pa_data, diag);
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, pa_data, diag);
}
else if (trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == trial_fetype)
@@ -1068,58 +923,29 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
if (dim == 3 && !isBdryInteg)
if (dim == 3)
{
if (trial_curl && test_curl)
if (trial_fetype == mfem::FiniteElement::CURL && test_fetype == trial_fetype)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
const int ID = (dofs1D << 4) | quad1D;
switch (ID)
{
case 0x23: return SmemPAHcurlMassApply3D<2,3>(dofs1D, quad1D, ne, symmetric,
mapsO->B,
mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
case 0x34: return SmemPAHcurlMassApply3D<3,4>(dofs1D, quad1D, ne, symmetric,
mapsO->B,
mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
case 0x45: return SmemPAHcurlMassApply3D<4,5>(dofs1D, quad1D, ne, symmetric,
mapsO->B,
mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
case 0x56: return SmemPAHcurlMassApply3D<5,6>(dofs1D, quad1D, ne, symmetric,
mapsO->B,
mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
default: return SmemPAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric, mapsO->B,
mapsC->B,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
}
}
else
PAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
PAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
}
else if (trial_div && test_div)
else if (trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == trial_fetype)
{
PAHdivMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if (trial_curl && test_div)
else if (trial_fetype == mfem::FiniteElement::CURL &&
test_fetype == mfem::FiniteElement::DIV)
{
const bool scalarCoeff = !(VQ || MQ);
PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
true, mapsO->B, mapsC->B, mapsOtest->Bt,
mapsCtest->Bt, pa_data, x, y);
}
else if (trial_div && test_curl)
else if (trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == mfem::FiniteElement::CURL)
{
const bool scalarCoeff = !(VQ || MQ);
PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
@@ -1133,21 +959,26 @@ void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
}
else
{
if (trial_curl && test_curl)
if (trial_fetype == mfem::FiniteElement::CURL && test_fetype == trial_fetype)
{
PAHcurlMassApply2D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
}
else if (trial_div && test_div)
else if (trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == trial_fetype)
{
PAHdivMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if ((trial_curl && test_div) || (trial_div && test_curl))
else if ((trial_fetype == mfem::FiniteElement::CURL &&
test_fetype == mfem::FiniteElement::DIV) ||
(trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == mfem::FiniteElement::CURL))
{
const bool scalarCoeff = !(VQ || MQ);
const bool trialHcurl = (trial_fetype == mfem::FiniteElement::CURL);
PAHcurlHdivMassApply2D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
trial_curl, mapsO->B, mapsC->B, mapsOtest->Bt,
trialHcurl, mapsO->B, mapsC->B, mapsOtest->Bt,
mapsCtest->Bt, pa_data, x, y);
}
else
+1 -1
View File
@@ -968,7 +968,7 @@ ParComplexLinearForm::ParallelAssemble()
2*(pfes->GlobalTrueVSize()),
tdof_offsets);
((Vector*) tv)->Write(true);
tv->Write();
Vector tvr; tvr.MakeRef(*tv, 0, tvsize);
Vector tvi; tvi.MakeRef(*tv, tvsize, tvsize);
+4 -37
View File
@@ -38,8 +38,8 @@ protected:
void Destroy() { delete gfr; delete gfi; }
public:
/** @brief Construct a ComplexGridFunction associated with the
FiniteElementSpace @a *f. */
/* @brief Construct a ComplexGridFunction associated with the
FiniteElementSpace @a *f. */
ComplexGridFunction(FiniteElementSpace *f);
void Update();
@@ -71,14 +71,6 @@ public:
const GridFunction & real() const { return *gfr; }
const GridFunction & imag() const { return *gfi; }
/// Update the memory location of the real and imaginary GridFunction @a gfr
/// and @a gfi to match the ComplexGridFunction.
void Sync() { gfr->SyncMemory(*this); gfi->SyncMemory(*this); }
/// Update the alias memory location of the real and imaginary GridFunction
/// @a gfr and @a gfi to match the ComplexGridFunction.
void SyncAlias() { gfr->SyncAliasMemory(*this); gfi->SyncAliasMemory(*this); }
/// Destroys the grid function.
virtual ~ComplexGridFunction() { Destroy(); }
@@ -165,14 +157,6 @@ public:
const LinearForm & real() const { return *lfr; }
const LinearForm & imag() const { return *lfi; }
/// Update the memory location of the real and imaginary LinearForm @a lfr
/// and @a lfi to match the ComplexLinearForm.
void Sync() { lfr->SyncMemory(*this); lfi->SyncMemory(*this); }
/// Update the alias memory location of the real and imaginary LinearForm @a
/// lfr and @a lfi to match the ComplexLinearForm.
void SyncAlias() { lfr->SyncAliasMemory(*this); lfi->SyncAliasMemory(*this); }
void Update();
void Update(FiniteElementSpace *f);
@@ -339,8 +323,8 @@ protected:
public:
/** @brief Construct a ParComplexGridFunction associated with the
ParFiniteElementSpace @a *pf. */
/* @brief Construct a ParComplexGridFunction associated with the
ParFiniteElementSpace @a *pf. */
ParComplexGridFunction(ParFiniteElementSpace *pf);
void Update();
@@ -381,15 +365,6 @@ public:
const ParGridFunction & real() const { return *pgfr; }
const ParGridFunction & imag() const { return *pgfi; }
/// Update the memory location of the real and imaginary ParGridFunction @a
/// pgfr and @a pgfi to match the ParComplexGridFunction.
void Sync() { pgfr->SyncMemory(*this); pgfi->SyncMemory(*this); }
/// Update the alias memory location of the real and imaginary
/// ParGridFunction @a pgfr and @a pgfi to match the ParComplexGridFunction.
void SyncAlias() { pgfr->SyncAliasMemory(*this); pgfi->SyncAliasMemory(*this); }
virtual double ComputeL2Error(Coefficient &exsolr, Coefficient &exsoli,
const IntegrationRule *irs[] = NULL) const
{
@@ -500,14 +475,6 @@ public:
const ParLinearForm & real() const { return *plfr; }
const ParLinearForm & imag() const { return *plfi; }
/// Update the memory location of the real and imaginary ParLinearForm @a lfr
/// and @a lfi to match the ParComplexLinearForm.
void Sync() { plfr->SyncMemory(*this); plfi->SyncMemory(*this); }
/// Update the alias memory location of the real and imaginary ParLinearForm
/// @a plfr and @a plfi to match the ParComplexLinearForm.
void SyncAlias() { plfr->SyncAliasMemory(*this); plfi->SyncAliasMemory(*this); }
void Update(ParFiniteElementSpace *pf = NULL);
/// Assembles the linear form i.e. sums over all domain/bdr integrators.
-297
View File
@@ -1,297 +0,0 @@
#include "convergence.hpp"
using namespace std;
namespace mfem
{
void ConvergenceStudy::Reset()
{
counter=0;
dcounter=0;
fcounter=0;
cont_type=-1;
print_flag=1;
L2Errors.SetSize(0);
L2Rates.SetSize(0);
DErrors.SetSize(0);
DRates.SetSize(0);
EnErrors.SetSize(0);
EnRates.SetSize(0);
DGFaceErrors.SetSize(0);
DGFaceRates.SetSize(0);
ndofs.SetSize(0);
}
double ConvergenceStudy::GetNorm(GridFunction *gf, Coefficient *scalar_u,
VectorCoefficient *vector_u)
{
bool norm_set = false;
double norm=0.0;
int order = gf->FESpace()->GetOrder(0);
int order_quad = std::max(2, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
#ifdef MFEM_USE_MPI
ParGridFunction *pgf = dynamic_cast<ParGridFunction *>(gf);
if (pgf)
{
ParMesh *pmesh = pgf->ParFESpace()->GetParMesh();
if (scalar_u)
{
norm = ComputeGlobalLpNorm(2.0,*scalar_u,*pmesh,irs);
}
else if (vector_u)
{
norm = ComputeGlobalLpNorm(2.0,*vector_u,*pmesh,irs);
}
norm_set = true;
}
#endif
if (!norm_set)
{
Mesh *mesh = gf->FESpace()->GetMesh();
if (scalar_u)
{
norm = ComputeLpNorm(2.0,*scalar_u,*mesh,irs);
}
else if (vector_u)
{
norm = ComputeLpNorm(2.0,*vector_u,*mesh,irs);
}
}
return norm;
}
void ConvergenceStudy::AddL2Error(GridFunction *gf,
Coefficient *scalar_u, VectorCoefficient *vector_u)
{
int tdofs=0;
#ifdef MFEM_USE_MPI
ParGridFunction *pgf = dynamic_cast<ParGridFunction *>(gf);
if (pgf)
{
MPI_Comm comm = pgf->ParFESpace()->GetComm();
int rank;
MPI_Comm_rank(comm, &rank);
print_flag = 0;
if (rank==0) { print_flag = 1; }
tdofs = pgf->ParFESpace()->GlobalTrueVSize();
}
#endif
if (!tdofs) { tdofs = gf->FESpace()->GetTrueVSize(); }
ndofs.Append(tdofs);
double L2Err;
if (scalar_u)
{
L2Err = gf->ComputeL2Error(*scalar_u);
CoeffNorm = GetNorm(gf,scalar_u,nullptr);
}
else if (vector_u)
{
L2Err = gf->ComputeL2Error(*vector_u);
CoeffNorm = GetNorm(gf,nullptr,vector_u);
}
else
{
MFEM_ABORT("Exact Solution Coefficient pointer is NULL");
}
L2Errors.Append(L2Err);
// Compute the rate of convergence by:
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
double val = (counter) ? log(L2Errors[counter-1]/L2Err)/log(2.0) : 0.0;
L2Rates.Append(val);
counter++;
}
void ConvergenceStudy::AddGf(GridFunction *gf, Coefficient *scalar_u,
VectorCoefficient *grad,
Coefficient *ell_coeff, double Nu)
{
cont_type = gf->FESpace()->FEColl()->GetContType();
MFEM_VERIFY((cont_type == mfem::FiniteElementCollection::CONTINUOUS) ||
(cont_type == mfem::FiniteElementCollection::DISCONTINUOUS),
"This constructor is intended for H1 or L2 Elements")
AddL2Error(gf,scalar_u, nullptr);
if (grad)
{
double GradErr = gf->ComputeGradError(grad);
DErrors.Append(GradErr);
double err = sqrt(L2Errors[counter-1]*L2Errors[counter-1]+GradErr*GradErr);
EnErrors.Append(err);
// Compute the rate of convergence by:
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
double val = (dcounter) ? log(DErrors[dcounter-1]/GradErr)/log(2.0) : 0.0;
double eval = (dcounter) ? log(EnErrors[dcounter-1]/err)/log(2.0) : 0.0;
DRates.Append(val);
EnRates.Append(eval);
CoeffDNorm = GetNorm(gf,nullptr,grad);
dcounter++;
MFEM_VERIFY(counter == dcounter,
"Number of added solutions and derivatives do not match")
}
if (cont_type == mfem::FiniteElementCollection::DISCONTINUOUS && ell_coeff)
{
double DGErr = gf->ComputeDGFaceJumpError(scalar_u,ell_coeff,Nu);
DGFaceErrors.Append(DGErr);
// Compute the rate of convergence by:
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
double val=(fcounter) ? log(DGFaceErrors[fcounter-1]/DGErr)/log(2.0):0.;
DGFaceRates.Append(val);
fcounter++;
MFEM_VERIFY(fcounter == counter, "Number of added solutions mismatch");
}
}
void ConvergenceStudy::AddGf(GridFunction *gf, VectorCoefficient *vector_u,
VectorCoefficient *curl, Coefficient *div)
{
cont_type = gf->FESpace()->FEColl()->GetContType();
AddL2Error(gf,nullptr,vector_u);
double DErr = 0.0;
bool derivative = false;
if (curl)
{
DErr = gf->ComputeCurlError(curl);
CoeffDNorm = GetNorm(gf,nullptr,curl);
derivative = true;
}
else if (div)
{
DErr = gf->ComputeDivError(div);
// update coefficient norm
CoeffDNorm = GetNorm(gf,div,nullptr);
derivative = true;
}
if (derivative)
{
double err = sqrt(L2Errors[counter-1]*L2Errors[counter-1] + DErr*DErr);
DErrors.Append(DErr);
EnErrors.Append(err);
// Compute the rate of convergence by:
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
double val = (dcounter) ? log(DErrors[dcounter-1]/DErr)/log(2.0) : 0.0;
double eval = (dcounter) ? log(EnErrors[dcounter-1]/err)/log(2.0) : 0.0;
DRates.Append(val);
EnRates.Append(eval);
dcounter++;
MFEM_VERIFY(counter == dcounter,
"Number of added solutions and derivatives do not match")
}
}
void ConvergenceStudy::Print(bool relative, std::ostream &out)
{
if (print_flag)
{
std::string title = (relative) ? "Relative " : "Absolute ";
out << "\n";
out << " -------------------------------------------" << "\n";
out << std::setw(21) << title << "L2 Error " << "\n";
out << " -------------------------------------------"
<< "\n";
out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13) << "Error ";
out << std::setw(15) << "Rate " << "\n";
out << " -------------------------------------------"
<< "\n";
out << std::setprecision(4);
double d = (relative) ? CoeffNorm : 1.0;
for (int i =0; i<counter; i++)
{
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
<< std::scientific << L2Errors[i]/d << std::setw(13)
<< std::fixed << L2Rates[i] << "\n";
}
out << "\n";
if (dcounter == counter)
{
std::string dname;
switch (cont_type)
{
case 0: dname = "Grad"; break;
case 1: dname = "Curl"; break;
case 2: dname = "Div"; break;
case 3: dname = "DG Grad"; break;
default: break;
}
out << " -------------------------------------------" << "\n";
out << std::setw(21) << title << dname << " Error " << "\n";
out << " -------------------------------------------" << "\n";
out << std::right<<std::setw(11)<< "DOFs "<< std::setw(13) << "Error";
out << std::setw(15) << "Rate " << "\n";
out << " -------------------------------------------"
<< "\n";
out << std::setprecision(4);
d = (relative) ? CoeffDNorm : 1.0;
for (int i =0; i<dcounter; i++)
{
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
<< std::scientific << DErrors[i]/d << std::setw(13)
<< std::fixed << DRates[i] << "\n";
}
out << "\n";
switch (cont_type)
{
case 0: dname = "H1"; break;
case 1: dname = "H(Curl)"; break;
case 2: dname = "H(Div)"; break;
case 3: dname = "DG H1"; break;
default: break;
}
if (dcounter)
{
d = (relative) ?
sqrt(CoeffNorm*CoeffNorm + CoeffDNorm*CoeffDNorm):1.0;
out << " -------------------------------------------" << "\n";
out << std::setw(21) << title << dname << " Error " << "\n";
out << " -------------------------------------------" << "\n";
out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13);
out << "Error ";
out << std::setw(15) << "Rate " << "\n";
out << " -------------------------------------------"
<< "\n";
out << std::setprecision(4);
for (int i =0; i<dcounter; i++)
{
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
<< std::scientific << EnErrors[i]/d << std::setw(13)
<< std::fixed << EnRates[i] << "\n";
}
out << "\n";
}
if (cont_type == 3 && fcounter)
{
out << " -------------------------------------------" << "\n";
out << " DG Face Jump Error " << "\n";
out << " -------------------------------------------"
<< "\n";
out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13);
out << "Error ";
out << std::setw(15) << "Rate " << "\n";
out << " -------------------------------------------"
<< "\n";
out << std::setprecision(4);
for (int i =0; i<fcounter; i++)
{
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
<< std::scientific << DGFaceErrors[i] << std::setw(13)
<< std::fixed << DGFaceRates[i] << "\n";
}
out << "\n";
}
}
}
}
} // namespace mfem
-149
View File
@@ -1,149 +0,0 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_CONVERGENCE
#define MFEM_CONVERGENCE
#include "../linalg/linalg.hpp"
#include "gridfunc.hpp"
#ifdef MFEM_USE_MPI
#include "pgridfunc.hpp"
#endif
namespace mfem
{
/** @brief Class to compute error and convergence rates.
It supports H1, H(curl) (ND elements), H(div) (RT elements) and L2 (DG).
For "smooth enough" solutions the Galerkin error measured in the appropriate
norm satisfies || u - u_h || ~ h^k
Here, k is called the asymptotic rate of convergence
For successive uniform h-refinements the rate can be estimated by
k = log(||u - u_h|| / ||u - u_{h/2}||)/log(2)
*/
class ConvergenceStudy
{
private:
// counters for solutions/derivatives
int counter=0;
int dcounter=0;
int fcounter=0;
// space continuity type
int cont_type=-1;
// printing flag for helpful for MPI calls
int print_flag=1;
// exact solution and derivatives
double CoeffNorm;
double CoeffDNorm;
// Arrays to store error/rates
Array<double> L2Errors, DGFaceErrors, DErrors, EnErrors;
Array<double> L2Rates, DGFaceRates, DRates, EnRates;
Array<int> ndofs;
void AddL2Error(GridFunction *gf, Coefficient *scalar_u,
VectorCoefficient *vector_u);
void AddGf(GridFunction *gf, Coefficient *scalar_u,
VectorCoefficient *grad=nullptr,
Coefficient *ell_coeff=nullptr, double Nu=1.0);
void AddGf(GridFunction *gf, VectorCoefficient *vector_u,
VectorCoefficient *curl, Coefficient *div);
// returns the L2-norm of scalar_u or vector_u
double GetNorm(GridFunction *gf, Coefficient *scalar_u,
VectorCoefficient *vector_u);
public:
/// Clear any internal data
void Reset();
/// Add L2 GridFunction, the exact solution and possibly its gradient and/or
/// DG face jumps parameters
void AddL2GridFunction(GridFunction *gf, Coefficient *scalar_u,
VectorCoefficient *grad=nullptr,
Coefficient *ell_coeff=nullptr, double Nu=1.0)
{
AddGf(gf, scalar_u, grad, ell_coeff, Nu);
}
/// Add H1 GridFunction, the exact solution and possibly its gradient
void AddH1GridFunction(GridFunction *gf, Coefficient *scalar_u,
VectorCoefficient *grad=nullptr)
{
AddGf(gf, scalar_u, grad);
}
/// Add H(curl) GridFunction, the exact solution and possibly its curl
void AddHcurlGridFunction(GridFunction *gf, VectorCoefficient *vector_u,
VectorCoefficient *curl=nullptr)
{
AddGf(gf, vector_u, curl, nullptr);
}
/// Add H(div) GridFunction, the exact solution and possibly its div
void AddHdivGridFunction(GridFunction *gf, VectorCoefficient *vector_u,
Coefficient *div=nullptr)
{
AddGf(gf,vector_u, nullptr, div);
}
/// Get the L2 error at step n
double GetL2Error(int n)
{
MFEM_VERIFY( n <= counter,"Step out of bounds")
return L2Errors[n];
}
/// Get all L2 errors
void GetL2Errors(Array<double> & L2Errors_)
{
L2Errors_ = L2Errors;
}
/// Get the Grad/Curl/Div error at step n
double GetDError(int n)
{
MFEM_VERIFY(n <= dcounter,"Step out of bounds")
return DErrors[n];
}
/// Get all Grad/Curl/Div errors
void GetDErrors(Array<double> & DErrors_)
{
DErrors_ = DErrors;
}
/// Get the DGFaceJumps error at step n
double GetDGFaceJumpsError(int n)
{
MFEM_VERIFY(n<= fcounter,"Step out of bounds")
return DGFaceErrors[n];
}
/// Get all DGFaceJumps errors
void GetDGFaceJumpsErrors(Array<double> & DGFaceErrors_)
{
DGFaceErrors_ = DGFaceErrors;
}
/// Print rates and errors
void Print(bool relative = false, std::ostream &out = mfem::out);
};
} // namespace mfem
#endif // MFEM_CONVERGENCE
-2
View File
@@ -563,8 +563,6 @@ void VisItDataCollection::LoadVisItRootFile(const std::string& root_name)
void VisItDataCollection::LoadMesh()
{
// GetMeshFileName() uses 'serial', so we need to set it in advance.
serial = (format == SERIAL_FORMAT);
std::string mesh_fname = GetMeshFileName();
named_ifgzstream file(mesh_fname);
// TODO: in parallel, check for errors on all processors
+3 -17
View File
@@ -77,9 +77,6 @@ public:
ElementTransformation();
/** @brief Force the reevaluation of the Jacobian in the next call. */
void Reset() { EvalState = 0; }
/** @brief Set the integration point @a ip that weights and Jacobians will
be evaluated at. */
void SetIntPoint(const IntegrationPoint *ip)
@@ -360,17 +357,9 @@ private:
// Evaluate the Hessian of the transformation at the IntPoint and store it
// in d2Fdx2.
virtual const DenseMatrix &EvalHessian();
public:
IsoparametricTransformation() : FElem(NULL) {}
/// Set the element that will be used to compute the transformations
void SetFE(const FiniteElement *FE)
{
MFEM_ASSERT(FE != NULL, "Must provide a valid FiniteElement object!");
EvalState = (FE != FElem) ? 0 : EvalState;
FElem = FE; geom = FE->GetGeomType();
}
void SetFE(const FiniteElement *FE) { FElem = FE; geom = FE->GetGeomType(); }
/// Get the current element used to compute the transformations
const FiniteElement* GetFE() const { return FElem; }
@@ -385,15 +374,12 @@ public:
the column-vector of all basis functions evaluated at \f$ \hat x \f$ .
The columns of @a P represent the control points in physical space
defining the transformation. */
void SetPointMat(const DenseMatrix &pm) { PointMat = pm; EvalState = 0; }
void SetPointMat(const DenseMatrix &pm) { PointMat = pm; }
/// Return the stored point matrix.
const DenseMatrix &GetPointMat() const { return PointMat; }
/// @brief Write access to the stored point matrix. Use with caution.
/** If the point matrix is altered using this member function the Reset
function should also be called to force the reevaluation of the
Jacobian, etc.. */
/// Write access to the stored point matrix. Use with caution.
DenseMatrix &GetPointMat() { return PointMat; }
/// Set the FiniteElement Geometry for the reference elements being used.
-203
View File
@@ -139,12 +139,6 @@ void FiniteElement::Project (
mfem_error ("FiniteElement::Project (...) (vector) is not overloaded !");
}
void FiniteElement::ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
Vector &dofs) const
{
mfem_error ("FiniteElement::ProjectFromNodes() (vector) is not overloaded!");
}
void FiniteElement::ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
{
@@ -931,23 +925,6 @@ void VectorFiniteElement::Project_RT(
}
}
void VectorFiniteElement::Project_RT(
const double *nk, const Array<int> &d2n,
Vector &vc, ElementTransformation &Trans, Vector &dofs) const
{
const int sdim = Trans.GetSpaceDim();
const bool square_J = (dim == sdim);
for (int k = 0; k < dof; k++)
{
Trans.SetIntPoint(&Nodes.IntPoint(k));
// dof_k = nk^t adj(J) xk
Vector vk(vc.GetData()+k*sdim, sdim);
dofs(k) = Trans.AdjugateJacobian().InnerProduct(vk, nk + d2n[k]*dim);
if (!square_J) { dofs(k) /= Trans.Weight(); }
}
}
void VectorFiniteElement::ProjectMatrixCoefficient_RT(
const double *nk, const Array<int> &d2n,
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
@@ -1124,19 +1101,6 @@ void VectorFiniteElement::Project_ND(
}
}
void VectorFiniteElement::Project_ND(
const double *tk, const Array<int> &d2t,
Vector &vc, ElementTransformation &Trans, Vector &dofs) const
{
for (int k = 0; k < dof; k++)
{
Trans.SetIntPoint(&Nodes.IntPoint(k));
Vector vk(vc.GetData()+k*dim, dim);
// dof_k = xk^t J tk
dofs(k) = Trans.Jacobian().InnerProduct(tk + d2t[k]*dim, vk);
}
}
void VectorFiniteElement::ProjectMatrixCoefficient_ND(
const double *tk, const Array<int> &d2t,
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
@@ -7070,95 +7034,6 @@ void Poly_1D::Basis::Eval(const double y, Vector &u, Vector &d) const
}
}
void Poly_1D::Basis::Eval(const double y, Vector &u, Vector &d,
Vector &d2) const
{
MFEM_VERIFY(etype == Barycentric,
"Basis::Eval with second order derivatives not implemented for"
" etype = " << etype);
switch (etype)
{
case ChangeOfBasis:
{
CalcBasis(Ai.Width() - 1, y, x, w);
Ai.Mult(x, u);
Ai.Mult(w, d);
// set d2 (not implemented yet)
break;
}
case Barycentric:
{
int i, k, p = x.Size() - 1;
double l, lp, lp2, lk, sk, si, sk2;
if (p == 0)
{
u(0) = 1.0;
d(0) = 0.0;
d2(0) = 0.0;
return;
}
lk = 1.0;
for (k = 0; k < p; k++)
{
if (y >= (x(k) + x(k+1))/2)
{
lk *= y - x(k);
}
else
{
for (i = k+1; i <= p; i++)
{
lk *= y - x(i);
}
break;
}
}
l = lk * (y - x(k));
sk = 0.0;
sk2 = 0.0;
for (i = 0; i < k; i++)
{
si = 1.0/(y - x(i));
sk += si;
sk2 -= si * si;
u(i) = l * si * w(i);
}
u(k) = lk * w(k);
for (i++; i <= p; i++)
{
si = 1.0/(y - x(i));
sk += si;
sk2 -= si * si;
u(i) = l * si * w(i);
}
lp = l * sk + lk;
lp2 = lp * sk + l * sk2 + sk * lk;
for (i = 0; i < k; i++)
{
d(i) = (lp * w(i) - u(i))/(y - x(i));
d2(i) = (lp2 * w(i) - 2 * d(i))/(y - x(i));
}
d(k) = sk * u(k);
d2(k) = sk2 * u(k) + sk * d(k);
for (i++; i <= p; i++)
{
d(i) = (lp * w(i) - u(i))/(y - x(i));
d2(i) = (lp2 * w(i) - 2 * d(i))/(y - x(i));
}
break;
}
case Positive:
CalcBernstein(x.Size() - 1, y, u, d);
break;
default: break;
}
}
const int *Poly_1D::Binom(const int p)
{
if (binom.NumCols() <= p)
@@ -7714,7 +7589,6 @@ H1_SegmentElement::H1_SegmentElement(const int p, const int btype)
#ifndef MFEM_THREAD_SAFE
shape_x.SetSize(p+1);
dshape_x.SetSize(p+1);
d2shape_x.SetSize(p+1);
#endif
Nodes.IntPoint(0).x = cp[0];
@@ -7763,25 +7637,6 @@ void H1_SegmentElement::CalcDShape(const IntegrationPoint &ip,
}
}
void H1_SegmentElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), dshape_x(p+1), d2shape_x(p+1);
#endif
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
Hessian(0,0) = d2shape_x(0);
Hessian(1,0) = d2shape_x(p);
for (int i = 1; i < p; i++)
{
Hessian(i+1,0) = d2shape_x(i);
}
}
void H1_SegmentElement::ProjectDelta(int vertex, Vector &dofs) const
{
const int p = order;
@@ -7822,8 +7677,6 @@ H1_QuadrilateralElement::H1_QuadrilateralElement(const int p, const int btype)
shape_y.SetSize(p1);
dshape_x.SetSize(p1);
dshape_y.SetSize(p1);
d2shape_x.SetSize(p1);
d2shape_y.SetSize(p1);
#endif
int o = 0;
@@ -7877,30 +7730,6 @@ void H1_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
}
}
void H1_QuadrilateralElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1),
d2shape_x(p+1), d2shape_y(p+1);
#endif
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
basis1d.Eval(ip.y, shape_y, dshape_y, d2shape_y);
for (int o = 0, j = 0; j <= p; j++)
{
for (int i = 0; i <= p; i++)
{
Hessian(dof_map[o],0) = d2shape_x(i)* shape_y(j);
Hessian(dof_map[o],1) = dshape_x(i)* dshape_y(j);
Hessian(dof_map[o],2) = shape_x(i)*d2shape_y(j); o++;
}
}
}
void H1_QuadrilateralElement::ProjectDelta(int vertex, Vector &dofs) const
{
const int p = order;
@@ -7964,9 +7793,6 @@ H1_HexahedronElement::H1_HexahedronElement(const int p, const int btype)
dshape_x.SetSize(p1);
dshape_y.SetSize(p1);
dshape_z.SetSize(p1);
d2shape_x.SetSize(p1);
d2shape_y.SetSize(p1);
d2shape_z.SetSize(p1);
#endif
int o = 0;
@@ -8023,35 +7849,6 @@ void H1_HexahedronElement::CalcDShape(const IntegrationPoint &ip,
}
}
void H1_HexahedronElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1), shape_z(p+1);
Vector dshape_x(p+1), dshape_y(p+1), dshape_z(p+1);
Vector d2shape_x(p+1), d2shape_y(p+1), d2shape_z(p+1);
#endif
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
basis1d.Eval(ip.y, shape_y, dshape_y, d2shape_y);
basis1d.Eval(ip.z, shape_z, dshape_z, d2shape_z);
for (int o = 0, k = 0; k <= p; k++)
for (int j = 0; j <= p; j++)
for (int i = 0; i <= p; i++)
{
Hessian(dof_map[o],0) = d2shape_x(i)* shape_y(j)* shape_z(k);
Hessian(dof_map[o],1) = dshape_x(i)* dshape_y(j)* shape_z(k);
Hessian(dof_map[o],2) = dshape_x(i)* shape_y(j)* dshape_z(k);
Hessian(dof_map[o],3) = shape_x(i)*d2shape_y(j)* shape_z(k);
Hessian(dof_map[o],4) = shape_x(i)* dshape_y(j)* dshape_z(k);
Hessian(dof_map[o],5) = shape_x(i)* shape_y(j)*d2shape_z(k);
o++;
}
}
void H1_HexahedronElement::ProjectDelta(int vertex, Vector &dofs) const
{
const int p = order;
+10 -60
View File
@@ -446,7 +446,7 @@ public:
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
part of the Hessian of one shape function.
The order in 2D is {u_xx, u_xy, u_yy}.
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
The size (#dof x (#dim (#dim-1)/2) of @a Hessian must be set in advance.*/
virtual void CalcHessian (const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
@@ -504,21 +504,14 @@ public:
/** @brief Given a coefficient and a transformation, compute its projection
(approximation) in the local finite dimensional space in terms
of the degrees of freedom. */
virtual void Project(Coefficient &coeff,
ElementTransformation &Trans, Vector &dofs) const;
virtual void Project (Coefficient &coeff,
ElementTransformation &Trans, Vector &dofs) const;
/** @brief Given a vector coefficient and a transformation, compute its
projection (approximation) in the local finite dimensional space
in terms of the degrees of freedom. (VectorFiniteElements) */
virtual void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const;
/** @brief Given a vector of values at the finite element nodes and a
transformation, compute its projection (approximation) in the local
finite dimensional space in terms of the degrees of freedom. Valid for
VectorFiniteElements. */
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
Vector &dofs) const;
virtual void Project (VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const;
/** @brief Given a matrix coefficient and a transformation, compute an
approximation ("projection") in the local finite dimensional space in
@@ -804,12 +797,7 @@ protected:
VectorCoefficient &vc, ElementTransformation &Trans,
Vector &dofs) const;
/// Projects the vector of values given at FE nodes to RT space
void Project_RT(const double *nk, const Array<int> &d2n,
Vector &vc, ElementTransformation &Trans,
Vector &dofs) const;
/// Project the rows of the matrix coefficient in an RT space
// project the rows of the matrix coefficient in an RT space
void ProjectMatrixCoefficient_RT(
const double *nk, const Array<int> &d2n,
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
@@ -837,12 +825,7 @@ protected:
VectorCoefficient &vc, ElementTransformation &Trans,
Vector &dofs) const;
/// Projects the vector of values given at FE nodes to ND space
void Project_ND(const double *tk, const Array<int> &d2t,
Vector &vc, ElementTransformation &Trans,
Vector &dofs) const;
/// Project the rows of the matrix coefficient in an ND space
/// project the rows of the matrix coefficient in an ND space
void ProjectMatrixCoefficient_ND(
const double *tk, const Array<int> &d2t,
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
@@ -1867,7 +1850,6 @@ public:
Basis(const int p, const double *nodes, EvalType etype = Barycentric);
void Eval(const double x, Vector &u) const;
void Eval(const double x, Vector &u, Vector &d) const;
void Eval(const double x, Vector &u, Vector &d, Vector &d2) const;
};
private:
@@ -2118,7 +2100,7 @@ class H1_SegmentElement : public NodalTensorFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, dshape_x, d2shape_x;
mutable Vector shape_x, dshape_x;
#endif
public:
@@ -2127,8 +2109,6 @@ public:
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
@@ -2138,7 +2118,7 @@ class H1_QuadrilateralElement : public NodalTensorFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
mutable Vector shape_x, shape_y, dshape_x, dshape_y;
#endif
public:
@@ -2148,8 +2128,6 @@ public:
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
@@ -2159,8 +2137,7 @@ class H1_HexahedronElement : public NodalTensorFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z,
d2shape_x, d2shape_y, d2shape_z;
mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z;
#endif
public:
@@ -2169,8 +2146,6 @@ public:
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
@@ -2706,9 +2681,6 @@ public:
virtual void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
Vector &dofs) const
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
virtual void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
@@ -2767,9 +2739,6 @@ public:
virtual void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
Vector &dofs) const
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
virtual void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
@@ -2821,9 +2790,6 @@ public:
virtual void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
Vector &dofs) const
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
virtual void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
@@ -2881,9 +2847,6 @@ public:
virtual void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
Vector &dofs) const
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
virtual void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
@@ -2943,10 +2906,6 @@ public:
ElementTransformation &Trans, Vector &dofs) const
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
Vector &dofs) const
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
virtual void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
@@ -3006,9 +2965,6 @@ public:
virtual void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
Vector &dofs) const
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
virtual void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
@@ -3060,9 +3016,6 @@ public:
virtual void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
Vector &dofs) const
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
virtual void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
@@ -3119,9 +3072,6 @@ public:
virtual void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
Vector &dofs) const
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
virtual void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
-1
View File
@@ -19,7 +19,6 @@
#include "eltrans.hpp"
#include "coefficient.hpp"
#include "complex_fem.hpp"
#include "convergence.hpp"
#include "lininteg.hpp"
#include "nonlininteg.hpp"
#include "bilininteg.hpp"
-3
View File
@@ -440,7 +440,6 @@ void FiniteElementSpace::MarkerToList(const Array<int> &marker,
if (marker[i]) { num_marked++; }
}
list.SetSize(0);
list.HostWrite();
list.Reserve(num_marked);
for (int i = 0; i < marker.Size(); i++)
{
@@ -452,9 +451,7 @@ void FiniteElementSpace::MarkerToList(const Array<int> &marker,
void FiniteElementSpace::ListToMarker(const Array<int> &list, int marker_size,
Array<int> &marker, int mark_val)
{
list.HostRead(); // make sure we can read the array on host
marker.SetSize(marker_size);
marker.HostWrite();
marker = 0;
for (int i = 0; i < list.Size(); i++)
{
+1 -5
View File
@@ -330,11 +330,6 @@ public:
virtual const Operator *GetProlongationMatrix() const
{ return GetConformingProlongation(); }
/// Return a prolongation operator that only acts on local dofs
/** The returned operator is owned by the FiniteElementSpace. */
virtual const Operator *GetLocalProlongationMatrix() const
{ return GetConformingProlongation(); }
/// The returned SparseMatrix is owned by the FiniteElementSpace.
virtual const SparseMatrix *GetRestrictionMatrix() const
{ return GetConformingRestriction(); }
@@ -989,6 +984,7 @@ inline bool UsesTensorBasis(const FiniteElementSpace& fes)
{
return dynamic_cast<const mfem::TensorBasisElement *>(fes.GetFE(0))!=nullptr;
}
}
#endif
+124 -246
View File
@@ -1833,19 +1833,6 @@ void GridFunction::ImposeBounds(int i, const Vector &weights,
ImposeBounds(i, weights, minv, maxv);
}
void GridFunction::RestrictConforming()
{
const SparseMatrix *R = fes->GetRestrictionMatrix();
const Operator *P = fes->GetProlongationMatrix();
if (P && R)
{
Vector tmp(R->Height());
R->Mult(*this, tmp);
P->Mult(tmp, *this);
}
}
void GridFunction::GetNodalValues(Vector &nval, int vdim) const
{
int i, j;
@@ -2614,7 +2601,11 @@ double GridFunction::ComputeL2Error(
}
}
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
if (error < 0.0)
{
return -sqrt(-error);
}
return sqrt(error);
}
double GridFunction::ComputeL2Error(
@@ -2655,199 +2646,94 @@ double GridFunction::ComputeL2Error(
}
}
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
}
double GridFunction::ComputeGradError(VectorCoefficient *exgrad,
const IntegrationRule *irs[]) const
{
double error = 0.0;
const FiniteElement *fe;
ElementTransformation *Tr;
Array<int> dofs;
Vector grad;
int intorder;
int dim = fes->GetMesh()->SpaceDimension();
Vector vec(dim);
for (int i = 0; i < fes->GetNE(); i++)
if (error < 0.0)
{
fe = fes->GetFE(i);
Tr = fes->GetElementTransformation(i);
intorder = 2*fe->GetOrder() + 3; // <--------
const IntegrationRule *ir;
if (irs)
{
ir = irs[fe->GetGeomType()];
}
else
{
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
fes->GetElementDofs(i, dofs);
for (int j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
Tr->SetIntPoint(&ip);
GetGradient(*Tr,grad);
exgrad->Eval(vec,*Tr,ip);
vec-=grad;
error += ip.weight * Tr->Weight() * (vec * vec);
}
return -sqrt(-error);
}
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
return sqrt(error);
}
double GridFunction::ComputeCurlError(VectorCoefficient *excurl,
const IntegrationRule *irs[]) const
double GridFunction::ComputeH1Error(
Coefficient *exsol, VectorCoefficient *exgrad,
Coefficient *ell_coeff, double Nu, int norm_type) const
{
double error = 0.0;
const FiniteElement *fe;
ElementTransformation *Tr;
Array<int> dofs;
Vector curl;
int intorder;
int dim = fes->GetMesh()->SpaceDimension();
int n = (dim == 3) ? dim : 1;
Vector vec(n);
for (int i = 0; i < fes->GetNE(); i++)
{
fe = fes->GetFE(i);
Tr = fes->GetElementTransformation(i);
intorder = 2*fe->GetOrder() + 3;
const IntegrationRule *ir;
if (irs)
{
ir = irs[fe->GetGeomType()];
}
else
{
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
fes->GetElementDofs(i, dofs);
for (int j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
Tr->SetIntPoint(&ip);
GetCurl(*Tr,curl);
excurl->Eval(vec,*Tr,ip);
vec-=curl;
error += ip.weight * Tr->Weight() * ( vec * vec );
}
}
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
}
double GridFunction::ComputeDivError(
Coefficient *exdiv, const IntegrationRule *irs[]) const
{
double error = 0.0, a;
const FiniteElement *fe;
ElementTransformation *Tr;
Array<int> dofs;
int intorder;
for (int i = 0; i < fes->GetNE(); i++)
{
fe = fes->GetFE(i);
Tr = fes->GetElementTransformation(i);
intorder = 2*fe->GetOrder() + 3;
const IntegrationRule *ir;
if (irs)
{
ir = irs[fe->GetGeomType()];
}
else
{
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
fes->GetElementDofs(i, dofs);
for (int j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
Tr->SetIntPoint (&ip);
a = GetDivergence(*Tr) - exdiv->Eval(*Tr, ip);
error += ip.weight * Tr->Weight() * a * a;
}
}
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
}
double GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
Coefficient *ell_coeff, double Nu,
const IntegrationRule *irs[]) const
{
int fdof, dim, intorder, k;
// assuming vdim is 1
int i, fdof, dim, intorder, j, k;
Mesh *mesh;
const FiniteElement *fe;
ElementTransformation *transf;
FaceElementTransformations *face_elem_transf;
Vector shape, el_dofs, err_val, ell_coeff_val;
Vector e_grad, a_grad, shape, el_dofs, err_val, ell_coeff_val;
DenseMatrix dshape, dshapet, Jinv;
Array<int> vdofs;
IntegrationPoint eip;
double error = 0.0;
mesh = fes->GetMesh();
dim = mesh->Dimension();
e_grad.SetSize(dim);
a_grad.SetSize(dim);
Jinv.SetSize(dim);
for (int i = 0; i < mesh->GetNumFaces(); i++)
{
face_elem_transf = mesh->GetFaceElementTransformations(i, 5);
int i1 = face_elem_transf->Elem1No;
int i2 = face_elem_transf->Elem2No;
intorder = fes->GetFE(i1)->GetOrder();
if (i2 >= 0)
if ( (k = fes->GetFE(i2)->GetOrder()) > intorder )
{
intorder = k;
}
intorder = 2 * intorder; // <-------------
const IntegrationRule *ir;
if (irs)
if (norm_type & 1)
for (i = 0; i < mesh->GetNE(); i++)
{
ir = irs[face_elem_transf->GetGeometryType()];
}
else
{
ir = &(IntRules.Get(face_elem_transf->GetGeometryType(), intorder));
}
err_val.SetSize(ir->GetNPoints());
ell_coeff_val.SetSize(ir->GetNPoints());
// side 1
transf = face_elem_transf->Elem1;
fe = fes->GetFE(i1);
fdof = fe->GetDof();
fes->GetElementVDofs(i1, vdofs);
shape.SetSize(fdof);
el_dofs.SetSize(fdof);
for (k = 0; k < fdof; k++)
if (vdofs[k] >= 0)
{
el_dofs(k) = (*this)(vdofs[k]);
}
else
{
el_dofs(k) = - (*this)(-1-vdofs[k]);
}
for (int j = 0; j < ir->GetNPoints(); j++)
{
face_elem_transf->Loc1.Transform(ir->IntPoint(j), eip);
fe->CalcShape(eip, shape);
transf->SetIntPoint(&eip);
ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
}
if (i2 >= 0)
{
// side 2
face_elem_transf = mesh->GetFaceElementTransformations(i, 10);
transf = face_elem_transf->Elem2;
fe = fes->GetFE(i2);
fe = fes->GetFE(i);
fdof = fe->GetDof();
fes->GetElementVDofs(i2, vdofs);
transf = mesh->GetElementTransformation(i);
el_dofs.SetSize(fdof);
dshape.SetSize(fdof, dim);
dshapet.SetSize(fdof, dim);
intorder = 2 * fe->GetOrder(); // <----------
const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), intorder);
fes->GetElementVDofs(i, vdofs);
for (k = 0; k < fdof; k++)
if (vdofs[k] >= 0)
{
el_dofs(k) = (*this)(vdofs[k]);
}
else
{
el_dofs(k) = - (*this)(-1-vdofs[k]);
}
for (j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
fe->CalcDShape(ip, dshape);
transf->SetIntPoint(&ip);
exgrad->Eval(e_grad, *transf, ip);
CalcInverse(transf->Jacobian(), Jinv);
Mult(dshape, Jinv, dshapet);
dshapet.MultTranspose(el_dofs, a_grad);
e_grad -= a_grad;
error += (ip.weight * transf->Weight() *
ell_coeff->Eval(*transf, ip) *
(e_grad * e_grad));
}
}
if (norm_type & 2)
for (i = 0; i < mesh->GetNFaces(); i++)
{
face_elem_transf = mesh->GetFaceElementTransformations(i, 5);
int i1 = face_elem_transf->Elem1No;
int i2 = face_elem_transf->Elem2No;
intorder = fes->GetFE(i1)->GetOrder();
if (i2 >= 0)
if ( (k = fes->GetFE(i2)->GetOrder()) > intorder )
{
intorder = k;
}
intorder = 2 * intorder; // <-------------
const IntegrationRule &ir =
IntRules.Get(face_elem_transf->GetGeometryType(), intorder);
err_val.SetSize(ir.GetNPoints());
ell_coeff_val.SetSize(ir.GetNPoints());
// side 1
transf = face_elem_transf->Elem1;
fe = fes->GetFE(i1);
fdof = fe->GetDof();
fes->GetElementVDofs(i1, vdofs);
shape.SetSize(fdof);
el_dofs.SetSize(fdof);
for (k = 0; k < fdof; k++)
@@ -2859,69 +2745,60 @@ double GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
{
el_dofs(k) = - (*this)(-1-vdofs[k]);
}
for (int j = 0; j < ir->GetNPoints(); j++)
for (j = 0; j < ir.GetNPoints(); j++)
{
face_elem_transf->Loc2.Transform(ir->IntPoint(j), eip);
face_elem_transf->Loc1.Transform(ir.IntPoint(j), eip);
fe->CalcShape(eip, shape);
transf->SetIntPoint(&eip);
ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
ell_coeff_val(j) *= 0.5;
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
}
if (i2 >= 0)
{
// side 2
face_elem_transf = mesh->GetFaceElementTransformations(i, 10);
transf = face_elem_transf->Elem2;
fe = fes->GetFE(i2);
fdof = fe->GetDof();
fes->GetElementVDofs(i2, vdofs);
shape.SetSize(fdof);
el_dofs.SetSize(fdof);
for (k = 0; k < fdof; k++)
if (vdofs[k] >= 0)
{
el_dofs(k) = (*this)(vdofs[k]);
}
else
{
el_dofs(k) = - (*this)(-1-vdofs[k]);
}
for (j = 0; j < ir.GetNPoints(); j++)
{
face_elem_transf->Loc2.Transform(ir.IntPoint(j), eip);
fe->CalcShape(eip, shape);
transf->SetIntPoint(&eip);
ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
ell_coeff_val(j) *= 0.5;
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
}
}
face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
transf = face_elem_transf;
for (j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
transf->SetIntPoint(&ip);
error += (ip.weight * Nu * ell_coeff_val(j) *
pow(transf->Weight(), 1.0-1.0/(dim-1)) *
err_val(j) * err_val(j));
}
}
face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
transf = face_elem_transf;
for (int j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
transf->SetIntPoint(&ip);
error += (ip.weight * Nu * ell_coeff_val(j) *
pow(transf->Weight(), 1.0-1.0/(dim-1)) *
err_val(j) * err_val(j));
}
if (error < 0.0)
{
return -sqrt(-error);
}
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
}
double GridFunction::ComputeH1Error(Coefficient *exsol,
VectorCoefficient *exgrad,
Coefficient *ell_coef, double Nu,
int norm_type) const
{
double error1 = 0.0;
double error2 = 0.0;
if (norm_type & 1) { error1 = GridFunction::ComputeGradError(exgrad); }
if (norm_type & 2) { error2 = GridFunction::ComputeDGFaceJumpError(exsol,ell_coef,Nu); }
return sqrt(error1 * error1 + error2 * error2);
}
double GridFunction::ComputeH1Error(Coefficient *exsol,
VectorCoefficient *exgrad,
const IntegrationRule *irs[]) const
{
double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,irs);
double GradError = ComputeGradError(exgrad,irs);
return sqrt(L2error*L2error + GradError*GradError);
}
double GridFunction::ComputeHDivError(VectorCoefficient *exsol,
Coefficient *exdiv,
const IntegrationRule *irs[]) const
{
double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,NULL,irs);
double DivError = ComputeDivError(exdiv,irs);
return sqrt(L2error*L2error + DivError*DivError);
}
double GridFunction::ComputeHCurlError(VectorCoefficient *exsol,
VectorCoefficient *excurl,
const IntegrationRule *irs[]) const
{
double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,NULL,irs);
double CurlError = ComputeCurlError(excurl,irs);
return sqrt(L2error*L2error + CurlError*CurlError);
return sqrt(error);
}
double GridFunction::ComputeMaxError(
@@ -2977,6 +2854,7 @@ double GridFunction::ComputeMaxError(
}
}
}
return error;
}
-46
View File
@@ -334,11 +334,6 @@ public:
void ImposeBounds(int i, const Vector &weights,
double _min = 0.0, double _max = infinity());
/** On a non-conforming mesh, make sure the function lies in the conforming
space by multiplying with R and then with P, the conforming restriction
and prolongation matrices of the space, respectively. */
void RestrictConforming();
/** @brief Project the @a src GridFunction to @a this GridFunction, both of
which must be on the same mesh. */
/** The current implementation assumes that all elements use the same
@@ -427,7 +422,6 @@ public:
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
Array<int> &bdr_attr);
virtual double ComputeL2Error(Coefficient &exsol,
const IntegrationRule *irs[] = NULL) const
{ return ComputeLpError(2.0, exsol, NULL, irs); }
@@ -439,50 +433,10 @@ public:
const IntegrationRule *irs[] = NULL,
Array<int> *elems = NULL) const;
/// Returns ||grad u_ex - grad u_h||_L2 for H1 or L2 elements
virtual double ComputeGradError(VectorCoefficient *exgrad,
const IntegrationRule *irs[] = NULL) const;
/// Returns ||curl u_ex - curl u_h||_L2 for ND elements
virtual double ComputeCurlError(VectorCoefficient *excurl,
const IntegrationRule *irs[] = NULL) const;
/// Returns ||div u_ex - div u_h||_L2 for RT elements
virtual double ComputeDivError(Coefficient *exdiv,
const IntegrationRule *irs[] = NULL) const;
/// Returns the Face Jumps error for L2 elements
virtual double ComputeDGFaceJumpError(Coefficient *exsol,
Coefficient *ell_coeff,
double Nu,
const IntegrationRule *irs[] = NULL)
const;
/** This method is kept for backward compatibility.
Returns either the H1-seminorm, or the DG face jumps error, or both
depending on norm_type = 1, 2, 3. Additional arguments for the DG face
jumps norm: ell_coeff: mesh-depended coefficient (weight) Nu: scalar
constant weight */
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
Coefficient *ell_coef, double Nu,
int norm_type) const;
/// Returns the error measured in H1-norm for H1 elements or in "broken"
/// H1-norm for L2 elements
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
const IntegrationRule *irs[] = NULL) const;
/// Returns the error measured in H(div)-norm for RT elements
virtual double ComputeHDivError(VectorCoefficient *exsol,
Coefficient *exdiv,
const IntegrationRule *irs[] = NULL) const;
/// Returns the error measured in H(curl)-norm for ND elements
virtual double ComputeHCurlError(VectorCoefficient *exsol,
VectorCoefficient *excurl,
const IntegrationRule *irs[] = NULL) const;
virtual double ComputeMaxError(Coefficient &exsol,
const IntegrationRule *irs[] = NULL) const
{
+86 -403
View File
@@ -29,13 +29,10 @@ namespace mfem
{
FindPointsGSLIB::FindPointsGSLIB()
: mesh(NULL), meshsplit(NULL), ir_simplex(NULL),
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
avgtype(AvgType::ARITHMETIC)
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
{
gsl_comm = new comm;
cr = new crystal;
#ifdef MFEM_USE_MPI
int initialized;
MPI_Initialized(&initialized);
@@ -50,20 +47,15 @@ FindPointsGSLIB::FindPointsGSLIB()
FindPointsGSLIB::~FindPointsGSLIB()
{
delete gsl_comm;
delete cr;
delete ir_simplex;
delete meshsplit;
}
#ifdef MFEM_USE_MPI
FindPointsGSLIB::FindPointsGSLIB(MPI_Comm _comm)
: mesh(NULL), meshsplit(NULL), ir_simplex(NULL),
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
avgtype(AvgType::ARITHMETIC)
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
{
gsl_comm = new comm;
cr = new crystal;
comm_init(gsl_comm, _comm);
}
#endif
@@ -78,7 +70,6 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
// call FreeData if FindPointsGSLIB::Setup has been called already
if (setupflag) { FreeData(); }
crystal_init(cr, gsl_comm);
mesh = &m;
dim = mesh->Dimension();
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
@@ -122,16 +113,14 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
setupflag = true;
}
void FindPointsGSLIB::FindPoints(const Vector &point_pos)
void FindPointsGSLIB::FindPoints(const Vector &point_pos,
Array<unsigned int> &codes,
Array<unsigned int> &proc_ids,
Array<unsigned int> &elem_ids,
Vector &ref_pos, Vector &dist)
{
MFEM_VERIFY(setupflag, "Use FindPointsGSLIB::Setup before finding points.");
points_cnt = point_pos.Size() / dim;
gsl_code.SetSize(points_cnt);
gsl_proc.SetSize(points_cnt);
gsl_elem.SetSize(points_cnt);
gsl_ref.SetSize(points_cnt * dim);
gsl_dist.SetSize(points_cnt);
const int points_cnt = point_pos.Size() / dim;
if (dim == 2)
{
const double *xv_base[2];
@@ -140,11 +129,11 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos)
unsigned xv_stride[2];
xv_stride[0] = sizeof(double);
xv_stride[1] = sizeof(double);
findpts_2(gsl_code.GetData(), sizeof(unsigned int),
gsl_proc.GetData(), sizeof(unsigned int),
gsl_elem.GetData(), sizeof(unsigned int),
gsl_ref.GetData(), sizeof(double) * dim,
gsl_dist.GetData(), sizeof(double),
findpts_2(codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
dist.GetData(), sizeof(double),
xv_base, xv_stride, points_cnt, fdata2D);
}
else
@@ -157,27 +146,25 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos)
xv_stride[0] = sizeof(double);
xv_stride[1] = sizeof(double);
xv_stride[2] = sizeof(double);
findpts_3(gsl_code.GetData(), sizeof(unsigned int),
gsl_proc.GetData(), sizeof(unsigned int),
gsl_elem.GetData(), sizeof(unsigned int),
gsl_ref.GetData(), sizeof(double) * dim,
gsl_dist.GetData(), sizeof(double),
findpts_3(codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
dist.GetData(), sizeof(double),
xv_base, xv_stride, points_cnt, fdata3D);
}
}
// Set the element number and reference position to 0 for points not found
for (int i = 0; i < points_cnt; i++)
{
if (gsl_code[i] == 2)
{
gsl_elem[i] = 0;
for (int d = 0; d < dim; d++) { gsl_ref(i*dim + d) = -1.; }
}
}
void FindPointsGSLIB::FindPoints(const Vector &point_pos)
{
const int points_cnt = point_pos.Size() / dim;
gsl_code.SetSize(points_cnt);
gsl_proc.SetSize(points_cnt);
gsl_elem.SetSize(points_cnt);
gsl_ref.SetSize(points_cnt * dim);
gsl_dist.SetSize(points_cnt);
// Map element number for simplices, and ref_pos from [-1,1] to [0,1] for
// both simplices and quads.
MapRefPosAndElemIndices();
FindPoints(point_pos, gsl_code, gsl_proc, gsl_elem, gsl_ref, gsl_dist);
}
void FindPointsGSLIB::FindPoints(Mesh &m, const Vector &point_pos,
@@ -191,24 +178,72 @@ void FindPointsGSLIB::FindPoints(Mesh &m, const Vector &point_pos,
FindPoints(point_pos);
}
void FindPointsGSLIB::Interpolate(Array<unsigned int> &codes,
Array<unsigned int> &proc_ids,
Array<unsigned int> &elem_ids,
Vector &ref_pos, const GridFunction &field_in,
Vector &field_out)
{
FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
GridFunction field_in_scalar(&ind_fes);
Vector node_vals;
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++)
{
const int dataptrin = i*points_fld,
dataptrout = i*points_cnt;
field_in_scalar.NewDataAndSize(field_in.GetData()+dataptrin, points_fld);
GetNodeValues(field_in_scalar, node_vals);
if (dim==2)
{
findpts_eval_2(field_out.GetData()+dataptrout, sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata2D);
}
else
{
findpts_eval_3(field_out.GetData()+dataptrout, sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata3D);
}
}
}
void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
Vector &field_out)
{
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::Interpolate(const Vector &point_pos,
const GridFunction &field_in, Vector &field_out)
{
FindPoints(point_pos);
Interpolate(field_in, field_out);
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::Interpolate(Mesh &m, const Vector &point_pos,
const GridFunction &field_in, Vector &field_out)
{
FindPoints(m, point_pos);
Interpolate(field_in, field_out);
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::FreeData()
{
if (!setupflag) { return; }
crystal_free(cr);
if (dim == 2)
{
findpts_free_2(fdata2D);
@@ -217,13 +252,13 @@ void FindPointsGSLIB::FreeData()
{
findpts_free_3(fdata3D);
}
setupflag = false;
gsl_code.DeleteAll();
gsl_proc.DeleteAll();
gsl_elem.DeleteAll();
gsl_mesh.Destroy();
gsl_ref.Destroy();
gsl_dist.Destroy();
setupflag = false;
}
void FindPointsGSLIB::GetNodeValues(const GridFunction &gf_in,
@@ -323,8 +358,9 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
const Geometry::Type gt = fe->GetGeomType();
const GridFunction *nodes = mesh->GetNodes();
Mesh *meshsplit = NULL;
const int NE = mesh->GetNE();
int NEsplit = 0;
int NEsplit = -1;
// Split the reference element into a reference submesh of quads or hexes.
if (gt == Geometry::TRIANGLE)
@@ -480,361 +516,8 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
pt_id++;
}
}
}
void FindPointsGSLIB::MapRefPosAndElemIndices()
{
gsl_mfem_ref = gsl_ref;
gsl_mfem_elem = gsl_elem;
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
const Geometry::Type gt = fe->GetGeomType();
int NEsplit = 0;
gsl_mfem_ref -= -1.; // map [-1, 1] to
gsl_mfem_ref *= 0.5; // [0, 1]
if (gt == Geometry::SQUARE || gt == Geometry::CUBE) { return; }
H1_FECollection feclin(1, dim);
FiniteElementSpace nodal_fes_lin(meshsplit, &feclin, dim);
GridFunction gf_lin(&nodal_fes_lin);
if (gt == Geometry::TRIANGLE)
{
const double quad_v[7][2] =
{
{0, 0}, {0.5, 0}, {1, 0}, {0, 0.5},
{1./3., 1./3.}, {0.5, 0.5}, {0, 1}
};
for (int k = 0; k < dim; k++)
{
for (int j = 0; j < gf_lin.Size()/dim; j++)
{
gf_lin(j+k*gf_lin.Size()/dim) = quad_v[j][k];
}
}
NEsplit = 3;
}
else if (gt == Geometry::TETRAHEDRON)
{
const double hex_v[15][3] =
{
{0, 0, 0.}, {1, 0., 0.}, {0., 1., 0.}, {0, 0., 1.},
{0.5, 0., 0.}, {0.5, 0.5, 0.}, {0., 0.5, 0.},
{0., 0., 0.5}, {0.5, 0., 0.5}, {0., 0.5, 0.5},
{1./3., 0., 1./3.}, {1./3., 1./3., 1./3.}, {0, 1./3., 1./3.},
{1./3., 1./3., 0}, {0.25, 0.25, 0.25}
};
for (int k = 0; k < dim; k++)
{
for (int j = 0; j < gf_lin.Size()/dim; j++)
{
gf_lin(j+k*gf_lin.Size()/dim) = hex_v[j][k];
}
}
NEsplit = 4;
}
else if (gt == Geometry::PRISM)
{
const double hex_v[14][3] =
{
{0, 0, 0}, {0.5, 0, 0}, {1, 0, 0}, {0, 0.5, 0},
{1./3., 1./3., 0}, {0.5, 0.5, 0}, {0, 1, 0},
{0, 0, 1}, {0.5, 0, 1}, {1, 0, 1}, {0, 0.5, 1},
{1./3., 1./3., 1}, {0.5, 0.5, 1}, {0, 1, 1}
};
for (int k = 0; k < dim; k++)
{
for (int j = 0; j < gf_lin.Size()/dim; j++)
{
gf_lin(j+k*gf_lin.Size()/dim) = hex_v[j][k];
}
}
NEsplit = 3;
}
else
{
MFEM_ABORT("Element type not currently supported.");
}
// Simplices are split into quads/hexes for GSLIB. For MFEM, we need to find
// the original element number and map the rst from micro to macro element.
for (int i = 0; i < points_cnt; i++)
{
if (gsl_code[i] == 2) { continue; }
int local_elem = gsl_elem[i]%NEsplit;
gsl_mfem_elem[i] = (gsl_elem[i] - local_elem)/NEsplit; // macro element number
IntegrationPoint ip;
Vector mfem_ref(gsl_mfem_ref.GetData()+i*dim, dim);
ip.Set2(mfem_ref.GetData());
if (dim == 3) { ip.z = mfem_ref(2); }
gf_lin.GetVectorValue(local_elem, ip, mfem_ref); // map to rst of macro element
}
}
void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
Vector &field_out)
{
const int gf_order = field_in.FESpace()->GetFE(0)->GetOrder(),
mesh_order = mesh->GetNodalFESpace()->GetFE(0)->GetOrder();
const FiniteElementCollection *fec_in = field_in.FESpace()->FEColl();
const H1_FECollection *fec_h1 = dynamic_cast<const H1_FECollection *>(fec_in);
const L2_FECollection *fec_l2 = dynamic_cast<const L2_FECollection *>(fec_in);
if (fec_h1 && gf_order == mesh_order &&
fec_h1->GetBasisType() == BasisType::GaussLobatto)
{
InterpolateH1(field_in, field_out);
return;
}
else
{
InterpolateGeneral(field_in, field_out);
if (!fec_l2 || avgtype == AvgType::NONE) { return; }
}
// For points on element borders, project the L2 GridFunction to H1 and
// re-interpolate.
if (fec_l2)
{
Array<int> indl2;
for (int i = 0; i < points_cnt; i++)
{
if (gsl_code[i] == 1) { indl2.Append(i); }
}
if (indl2.Size() == 0) { return; } // no points on element borders
Vector field_out_l2(field_out.Size());
VectorGridFunctionCoefficient field_in_dg(&field_in);
int gf_order_h1 = std::max(gf_order, 1); // H1 should be at least order 1
H1_FECollection fec(gf_order_h1, dim);
const int ncomp = field_in.FESpace()->GetVDim();
FiniteElementSpace fes(mesh, &fec, ncomp);
GridFunction field_in_h1(&fes);
if (avgtype == AvgType::ARITHMETIC)
{
field_in_h1.ProjectDiscCoefficient(field_in_dg, GridFunction::ARITHMETIC);
}
else if (avgtype == AvgType::HARMONIC)
{
field_in_h1.ProjectDiscCoefficient(field_in_dg, GridFunction::HARMONIC);
}
else
{
MFEM_ABORT("Invalid averaging type.");
}
if (gf_order_h1 == mesh_order) // basis is GaussLobatto by default
{
InterpolateH1(field_in_h1, field_out_l2);
}
else
{
InterpolateGeneral(field_in_h1, field_out_l2);
}
// Copy interpolated values for the points on element border
for (int j = 0; j < ncomp; j++)
{
for (int i = 0; i < indl2.Size(); i++)
{
int idx = indl2[i] + j*points_cnt;
field_out(idx) = field_out_l2(idx);
}
}
}
}
void FindPointsGSLIB::InterpolateH1(const GridFunction &field_in,
Vector &field_out)
{
FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
GridFunction field_in_scalar(&ind_fes);
Vector node_vals;
const int ncomp = field_in.FESpace()->GetVDim(),
points_fld = field_in.Size() / ncomp,
points_cnt = gsl_code.Size();
field_out.SetSize(points_cnt*ncomp);
field_out = default_interp_value;
for (int i = 0; i < ncomp; i++)
{
const int dataptrin = i*points_fld,
dataptrout = i*points_cnt;
field_in_scalar.NewDataAndSize(field_in.GetData()+dataptrin, points_fld);
GetNodeValues(field_in_scalar, node_vals);
if (dim==2)
{
findpts_eval_2(field_out.GetData()+dataptrout, sizeof(double),
gsl_code.GetData(), sizeof(unsigned int),
gsl_proc.GetData(), sizeof(unsigned int),
gsl_elem.GetData(), sizeof(unsigned int),
gsl_ref.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata2D);
}
else
{
findpts_eval_3(field_out.GetData()+dataptrout, sizeof(double),
gsl_code.GetData(), sizeof(unsigned int),
gsl_proc.GetData(), sizeof(unsigned int),
gsl_elem.GetData(), sizeof(unsigned int),
gsl_ref.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata3D);
}
}
}
void FindPointsGSLIB::InterpolateGeneral(const GridFunction &field_in,
Vector &field_out)
{
int ncomp = field_in.VectorDim(),
nptorig = points_cnt,
npt = points_cnt;
field_out.SetSize(points_cnt*ncomp);
field_out = default_interp_value;
if (gsl_comm->np == 1) // serial
{
for (int index = 0; index < npt; index++)
{
if (gsl_code[index] == 2) { continue; }
IntegrationPoint ip;
ip.Set2(gsl_mfem_ref.GetData()+index*dim);
if (dim == 3) { ip.z = gsl_mfem_ref(index*dim + 2); }
Vector localval(ncomp);
field_in.GetVectorValue(gsl_mfem_elem[index], ip, localval);
for (int i = 0; i < ncomp; i++)
{
field_out(index + i*npt) = localval(i);
}
}
}
else // parallel
{
// Determine number of points to be sent
int nptsend = 0;
for (int index = 0; index < npt; index++)
{
if (gsl_code[index] != 2) { nptsend +=1; }
}
// Pack data to send via crystal router
struct array *outpt = new array;
struct out_pt { double r[3], ival; uint index, el, proc; };
struct out_pt *pt;
array_init(struct out_pt, outpt, nptsend);
outpt->n=nptsend;
pt = (struct out_pt *)outpt->ptr;
for (int index = 0; index < npt; index++)
{
if (gsl_code[index] == 2) { continue; }
for (int d = 0; d < dim; ++d) { pt->r[d]= gsl_mfem_ref(index*dim + d); }
pt->index = index;
pt->proc = gsl_proc[index];
pt->el = gsl_mfem_elem[index];
++pt;
}
// Transfer data to target MPI ranks
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
if (ncomp == 1)
{
// Interpolate the grid function
npt = outpt->n;
pt = (struct out_pt *)outpt->ptr;
for (int index = 0; index < npt; index++)
{
IntegrationPoint ip;
ip.Set3(&pt->r[0]);
pt->ival = field_in.GetValue(pt->el, ip, 1);
++pt;
}
// Transfer data back to source MPI rank
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
npt = outpt->n;
pt = (struct out_pt *)outpt->ptr;
for (int index = 0; index < npt; index++)
{
field_out(pt->index) = pt->ival;
++pt;
}
array_free(outpt);
delete outpt;
}
else // ncomp > 1
{
// Interpolate data and store in a Vector
npt = outpt->n;
pt = (struct out_pt *)outpt->ptr;
Vector vec_int_vals(npt*ncomp);
for (int index = 0; index < npt; index++)
{
IntegrationPoint ip;
ip.Set3(&pt->r[0]);
Vector localval(vec_int_vals.GetData()+index*ncomp, ncomp);
field_in.GetVectorValue(pt->el, ip, localval);
++pt;
}
// Save index and proc data in a struct
struct array *savpt = new array;
struct sav_pt { uint index, proc; };
struct sav_pt *spt;
array_init(struct sav_pt, savpt, npt);
savpt->n=npt;
spt = (struct sav_pt *)savpt->ptr;
pt = (struct out_pt *)outpt->ptr;
for (int index = 0; index < npt; index++)
{
spt->index = pt->index;
spt->proc = pt->proc;
++pt; ++spt;
}
array_free(outpt);
delete outpt;
// Copy data from save struct to send struct and send component wise
struct array *sendpt = new array;
struct send_pt { double ival; uint index, proc; };
struct send_pt *sdpt;
for (int j = 0; j < ncomp; j++)
{
array_init(struct send_pt, sendpt, npt);
sendpt->n=npt;
spt = (struct sav_pt *)savpt->ptr;
sdpt = (struct send_pt *)sendpt->ptr;
for (int index = 0; index < npt; index++)
{
sdpt->index = spt->index;
sdpt->proc = spt->proc;
sdpt->ival = vec_int_vals(j + index*ncomp);
++sdpt; ++spt;
}
sarray_transfer(struct send_pt, sendpt, proc, 1, cr);
sdpt = (struct send_pt *)sendpt->ptr;
for (int index = 0; index < nptorig; index++)
{
int idx = sdpt->index + j*nptorig;
field_out(idx) = sdpt->ival;
++sdpt;
}
array_free(sendpt);
}
array_free(savpt);
delete sendpt;
delete savpt;
} // ncomp > 1
} // parallel
delete meshsplit;
}
} // namespace mfem
+45 -93
View File
@@ -20,66 +20,28 @@
struct comm;
struct findpts_data_2;
struct findpts_data_3;
struct array;
struct crystal;
namespace mfem
{
/** \brief FindPointsGSLIB can robustly evaluate a GridFunction on an arbitrary
* collection of points. There are three key functions in FindPointsGSLIB:
*
* 1. Setup - constructs the internal data structures of gslib.
*
* 2. FindPoints - for any given arbitrary set of points in physical space,
* gslib finds the element number, MPI rank, and the reference space
* coordinates inside the element that each point is located in. gslib also
* returns a code that indicates whether the point was found inside an
* element, on element border, or not found in the domain.
*
* 3. Interpolate - Interpolates any grid function at the points found using 2.
*
* FindPointsGSLIB provides interface to use these functions individually or
* using a single call.
*/
class FindPointsGSLIB
{
public:
enum AvgType {NONE, ARITHMETIC, HARMONIC}; // Average type for L2 functions
protected:
Mesh *mesh, *meshsplit;
IntegrationRule *ir_simplex; // IntegrationRule to split quads/hex -> simplex
struct findpts_data_2 *fdata2D; // gslib's internal data
struct findpts_data_3 *fdata3D; // gslib's internal data
struct crystal *cr; // gslib's internal data
struct comm *gsl_comm; // gslib's internal data
int dim, points_cnt;
Array<unsigned int> gsl_code, gsl_proc, gsl_elem, gsl_mfem_elem;
Vector gsl_mesh, gsl_ref, gsl_dist, gsl_mfem_ref;
bool setupflag; // flag to indicate whether gslib data has been setup
double default_interp_value; // used for points that are not found in the mesh
AvgType avgtype; // average type used for L2 functions
Mesh *mesh;
IntegrationRule *ir_simplex;
struct findpts_data_2 *fdata2D;
struct findpts_data_3 *fdata3D;
int dim;
Array<unsigned int> gsl_code, gsl_proc, gsl_elem;
Vector gsl_mesh, gsl_ref, gsl_dist;
bool setupflag;
struct comm *gsl_comm;
/// Get GridFunction from MFEM format to GSLIB format
void GetNodeValues(const GridFunction &gf_in, Vector &node_vals);
/// Get nodal coordinates from mesh to the format expected by GSLIB for quads
/// and hexes
void GetQuadHexNodalCoordinates();
/// Convert simplices to quad/hexes and then get nodal coordinates for each
/// split element into format expected by GSLIB
void GetSimplexNodalCoordinates();
/// Use GSLIB for communication and interpolation
void InterpolateH1(const GridFunction &field_in, Vector &field_out);
/// Uses GSLIB Crystal Router for communication followed by MFEM's
/// interpolation functions
void InterpolateGeneral(const GridFunction &field_in, Vector &field_out);
/// Map {r,s,t} coordinates from [-1,1] to [0,1] for MFEM. For simplices mesh
/// find the original element number (that was split into micro quads/hexes
/// by GetSimplexNodalCoordinates())
void MapRefPosAndElemIndices();
public:
FindPointsGSLIB();
@@ -102,37 +64,45 @@ public:
void Setup(Mesh &m, const double bb_t = 0.1, const double newt_tol = 1.0e-12,
const int npt_max = 256);
/** Searches positions given in physical space by @a point_pos. These positions
must by ordered by nodes: (XXX...,YYY...,ZZZ).
This function populates the following member variables:
#gsl_code Return codes for each point: inside element (0),
element boundary (1), not found (2).
#gsl_proc MPI proc ids where the points were found.
#gsl_elem Element ids where the points were found.
Defaults to 0 for points that were not found.
#gsl_mfem_elem Element ids corresponding to MFEM-mesh where the points
were found. #gsl_mfem_elem != #gsl_elem for simplices
Defaults to 0 for points that were not found.
#gsl_ref Reference coordinates of the found point.
Ordered by vdim (XYZ,XYZ,XYZ...). Defaults to -1 for
points that were not found. Note: the gslib reference
frame is [-1,1].
#gsl_mfem_ref Reference coordinates #gsl_ref mapped to [0,1].
Defaults to 0 for points that were not found.
#gsl_dist Distance between the sought and the found point
in physical space. */
/** Searches positions given in physical space by @a point_pos. All output
Arrays and Vectors are expected to have the correct size.
@param[in] point_pos Positions to be found. Must by ordered by nodes
(XXX...,YYY...,ZZZ).
@param[out] codes Return codes for each point: inside element (0),
element boundary (1), not found (2).
@param[out] proc_ids MPI proc ids where the points were found.
@param[out] elem_ids Element ids where the points were found.
@param[out] ref_pos Reference coordinates of the found point. Ordered
by vdim (XYZ,XYZ,XYZ...).
Note: the gslib reference frame is [-1,1].
@param[out] dist Distance between the sought and the found point
in physical space. */
void FindPoints(const Vector &point_pos, Array<unsigned int> &codes,
Array<unsigned int> &proc_ids, Array<unsigned int> &elem_ids,
Vector &ref_pos, Vector &dist);
void FindPoints(const Vector &point_pos);
/// Setup FindPoints and search positions
void FindPoints(Mesh &m, const Vector &point_pos, const double bb_t = 0.1,
const double newt_tol = 1.0e-12, const int npt_max = 256);
/** Interpolation of field values at prescribed reference space positions.
@param[in] codes Return codes for each point: inside element (0),
element boundary (1), not found (2).
@param[in] proc_ids MPI proc ids where the points were found.
@param[in] elem_ids Element ids where the points were found.
@param[in] ref_pos Reference coordinates of the found point. Ordered
by vdim (XYZ,XYZ,XYZ...).
Note: the gslib reference frame is [-1,1].
@param[in] field_in Function values that will be interpolated on the
reference positions. Note: it is assumed that
@a field_in is in H1 and in the same space as the
mesh that was given to Setup().
@param[out] field_out Interpolated values. For points that are not found
the value is set to #default_interp_value. */
@param[out] field_out Interpolated values. */
void Interpolate(Array<unsigned int> &codes, Array<unsigned int> &proc_ids,
Array<unsigned int> &elem_ids, Vector &ref_pos,
const GridFunction &field_in, Vector &field_out);
void Interpolate(const GridFunction &field_in, Vector &field_out);
/** Search positions and interpolate */
void Interpolate(const Vector &point_pos, const GridFunction &field_in,
@@ -141,45 +111,27 @@ public:
void Interpolate(Mesh &m, const Vector &point_pos,
const GridFunction &field_in, Vector &field_out);
/// Average type to be used for L2 functions in-case a point is located at
/// an element boundary where the function might be multi-valued.
void SetL2AvgType(AvgType avgtype_) { avgtype = avgtype_; }
/// Set the default interpolation value for points that are not found in the
/// mesh.
void SetDefaultInterpolationValue(double interp_value_)
{
default_interp_value = interp_value_;
}
/** Cleans up memory allocated internally by gslib.
Note that in parallel, this must be called before MPI_Finalize(), as it
calls MPI_Comm_free() for internal gslib communicators. */
Note that in parallel, this must be called before MPI_Finalize(), as
it calls MPI_Comm_free() for internal gslib communicators. */
void FreeData();
/// Return code for each point searched by FindPoints: inside element (0), on
/// element boundary (1), or not found (2).
const Array<unsigned int> &GetCode() const { return gsl_code; }
/// Return element number for each point found by FindPoints.
const Array<unsigned int> &GetElem() const { return gsl_mfem_elem; }
const Array<unsigned int> &GetElem() const { return gsl_elem; }
/// Return MPI rank on which each point was found by FindPoints.
const Array<unsigned int> &GetProc() const { return gsl_proc; }
/// Return reference coordinates for each point found by FindPoints.
const Vector &GetReferencePosition() const { return gsl_mfem_ref; }
const Vector &GetReferencePosition() const { return gsl_ref; }
/// Return distance Distance between the sought and the found point
/// in physical space, for each point found by FindPoints.
const Vector &GetDist() const { return gsl_dist; }
/// Return element number for each point found by FindPoints corresponding to
/// GSLIB mesh. gsl_mfem_elem != gsl_elem for mesh with simplices.
const Array<unsigned int> &GetGSLIBElem() const { return gsl_elem; }
/// Return reference coordinates in [-1,1] (internal range in GSLIB) for each
/// point found by FindPoints.
const Vector &GetGSLIBReferencePosition() const { return gsl_ref; }
};
} // namespace mfem
#endif // MFEM_USE_GSLIB
#endif //MFEM_USE_GSLIB
#endif // MFEM_GSLIB
#endif //MFEM_GSLIB guard
+25 -202
View File
@@ -35,9 +35,6 @@ extern Ceed ceed;
std::string ceed_path;
extern CeedBasisMap ceed_basis_map;
extern CeedRestrMap ceed_restr_map;
}
void InitCeedCoeff(Coefficient* Q, CeedData* ptr)
@@ -84,9 +81,10 @@ static CeedElemTopology GetCeedTopology(Geometry::Type geom)
}
}
static void InitCeedNonTensorBasis(const FiniteElementSpace &fes,
const IntegrationRule &ir,
Ceed ceed, CeedBasis *basis)
static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes,
const IntegrationRule &ir,
Ceed ceed, CeedBasis *basis,
CeedElemRestriction *restr)
{
Mesh *mesh = fes.GetMesh();
const FiniteElement *fe = fes.GetFE(0);
@@ -99,73 +97,7 @@ static void InitCeedNonTensorBasis(const FiniteElementSpace &fes,
Vector qweight(Q);
Vector shape_i(P);
DenseMatrix grad_i(P, dim);
const Table &el_dof = fes.GetElementToDofTable();
Array<int> tp_el_dof(el_dof.Size_of_connections());
const TensorBasisElement * tfe =
dynamic_cast<const TensorBasisElement *>(fe);
if (tfe) // Lexicographic ordering using dof_map
{
const Array<int>& dof_map = tfe->GetDofMap();
for (int i = 0; i < Q; i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
qref(0,i) = ip.x;
if (dim>1) { qref(1,i) = ip.y; }
if (dim>2) { qref(2,i) = ip.z; }
qweight(i) = ip.weight;
fe->CalcShape(ip, shape_i);
fe->CalcDShape(ip, grad_i);
for (int j = 0; j < P; j++)
{
shape(j, i) = shape_i(dof_map[j]);
for (int d = 0; d < dim; ++d)
{
grad(j+i*P+d*Q*P) = grad_i(dof_map[j], d);
}
}
}
}
else // Native ordering
{
for (int i = 0; i < Q; i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
qref(0,i) = ip.x;
if (dim>1) { qref(1,i) = ip.y; }
if (dim>2) { qref(2,i) = ip.z; }
qweight(i) = ip.weight;
fe->CalcShape(ip, shape_i);
fe->CalcDShape(ip, grad_i);
for (int j = 0; j < P; j++)
{
shape(j, i) = shape_i(j);
for (int d = 0; d < dim; ++d)
{
grad(j+i*P+d*Q*P) = grad_i(j, d);
}
}
}
}
CeedBasisCreateH1(ceed, GetCeedTopology(fe->GetGeomType()), fes.GetVDim(),
fe->GetDof(), ir.GetNPoints(), shape.GetData(),
grad.GetData(), qref.GetData(), qweight.GetData(), basis);
}
static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
const IntegrationRule &ir,
Ceed ceed, CeedElemRestriction *restr)
{
Mesh *mesh = fes.GetMesh();
const FiniteElement *fe = fes.GetFE(0);
const int dim = mesh->Dimension();
const int P = fe->GetDof();
const int Q = ir.GetNPoints();
DenseMatrix shape(P, Q);
Vector grad(P*dim*Q);
DenseMatrix qref(dim, Q);
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());
@@ -192,6 +124,7 @@ static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
}
}
}
for (int i = 0; i < mesh->GetNE(); i++)
{
const int el_offset = fe->GetDof() * i;
@@ -229,6 +162,7 @@ static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
}
}
}
for (int e = 0; e < mesh->GetNE(); e++)
{
for (int i = 0; i < P; i++)
@@ -244,15 +178,19 @@ static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
}
}
}
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,
tp_el_dof.GetData(), restr);
}
static void InitCeedTensorBasis(const FiniteElementSpace &fes,
const IntegrationRule &ir,
Ceed ceed, CeedBasis *basis)
static void InitCeedTensorBasisAndRestriction(const FiniteElementSpace &fes,
const IntegrationRule &ir,
Ceed ceed, CeedBasis *basis,
CeedElemRestriction *restr)
{
Mesh *mesh = fes.GetMesh();
const FiniteElement *fe = fes.GetFE(0);
@@ -260,6 +198,7 @@ static void InitCeedTensorBasis(const FiniteElementSpace &fes,
const TensorBasisElement * tfe =
dynamic_cast<const TensorBasisElement *>(fe);
MFEM_VERIFY(tfe, "invalid FE");
const Array<int>& dof_map = tfe->GetDofMap();
const FiniteElement *fe1d =
fes.FEColl()->FiniteElementForGeometry(Geometry::SEGMENT);
DenseMatrix shape1d(fe1d->GetDof(), ir.GetNPoints());
@@ -288,28 +227,6 @@ static void InitCeedTensorBasis(const FiniteElementSpace &fes,
ir.GetNPoints(), shape1d.GetData(),
grad1d.GetData(), qref1d.GetData(),
qweight1d.GetData(), basis);
}
static void InitCeedTensorRestriction(const FiniteElementSpace &fes,
const IntegrationRule &ir,
Ceed ceed, CeedElemRestriction *restr)
{
Mesh *mesh = fes.GetMesh();
const FiniteElement *fe = fes.GetFE(0);
const TensorBasisElement * tfe =
dynamic_cast<const TensorBasisElement *>(fe);
MFEM_VERIFY(tfe, "invalid FE");
const Array<int>& dof_map = tfe->GetDofMap();
const FiniteElement *fe1d =
fes.FEColl()->FiniteElementForGeometry(Geometry::SEGMENT);
DenseMatrix shape1d(fe1d->GetDof(), ir.GetNPoints());
DenseMatrix grad1d(fe1d->GetDof(), ir.GetNPoints());
Vector qref1d(ir.GetNPoints()), qweight1d(ir.GetNPoints());
Vector shape_i(shape1d.Height());
DenseMatrix grad_i(grad1d.Height(), 1);
const H1_SegmentElement *h1_fe1d =
dynamic_cast<const H1_SegmentElement *>(fe1d);
MFEM_VERIFY(h1_fe1d, "invalid FE");
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
const Table &el_dof = fes.GetElementToDofTable();
@@ -341,52 +258,14 @@ void InitCeedBasisAndRestriction(const FiniteElementSpace &fes,
Ceed ceed, CeedBasis *basis,
CeedElemRestriction *restr)
{
// Check for FES -> basis, restriction in hash tables
const Mesh *mesh = fes.GetMesh();
const FiniteElement *fe = fes.GetFE(0);
const int P = fe->GetDof();
const int Q = irm.GetNPoints();
const int nelem = mesh->GetNE();
const int ncomp = fes.GetVDim();
CeedBasisKey basis_key(&fes, &irm, ncomp, P, Q);
auto basis_itr = internal::ceed_basis_map.find(basis_key);
CeedRestrKey restr_key(&fes, nelem, P, ncomp);
auto restr_itr = internal::ceed_restr_map.find(restr_key);
// Init or retreive key values
if (basis_itr == internal::ceed_basis_map.end())
if (UsesTensorBasis(fes))
{
if (UsesTensorBasis(fes))
{
const IntegrationRule &ir = IntRules.Get(Geometry::SEGMENT, irm.GetOrder());
InitCeedTensorBasis(fes, ir, ceed, basis);
}
else
{
InitCeedNonTensorBasis(fes, irm, ceed, basis);
}
internal::ceed_basis_map[basis_key] = *basis;
const IntegrationRule &ir = IntRules.Get(Geometry::SEGMENT, irm.GetOrder());
InitCeedTensorBasisAndRestriction(fes, ir, ceed, basis, restr);
}
else
{
*basis = basis_itr->second;
}
if (restr_itr == internal::ceed_restr_map.end())
{
if (UsesTensorBasis(fes))
{
const IntegrationRule &ir = IntRules.Get(Geometry::SEGMENT, irm.GetOrder());
InitCeedTensorRestriction(fes, ir, ceed, restr);
}
else
{
InitCeedNonTensorRestriction(fes, irm, ceed, restr);
}
internal::ceed_restr_map[restr_key] = *restr;
}
else
{
*restr = restr_itr->second;
InitCeedNonTensorBasisAndRestriction(fes, irm, ceed, basis, restr);
}
}
@@ -448,8 +327,8 @@ void CeedPAAssemble(const CeedPAOperator& op,
CeedVectorCreate(ceed, nelem * nqpts * qdatasize, &ceedData.rho);
// Context data to be passed to the 'f_build_diff' Q-function.
ceedData.build_ctx_data.dim = mesh->Dimension();
ceedData.build_ctx_data.space_dim = mesh->SpaceDimension();
ceedData.build_ctx.dim = mesh->Dimension();
ceedData.build_ctx.space_dim = mesh->SpaceDimension();
std::string qf_file = GetCeedPath() + op.header;
std::string qf;
@@ -463,7 +342,7 @@ void CeedPAAssemble(const CeedPAOperator& op,
CeedQFunctionCreateInterior(ceed, 1, op.const_qf,
qf.c_str(),
&ceedData.build_qfunc);
ceedData.build_ctx_data.coeff = ((CeedConstCoeff*)ceedData.coeff)->val;
ceedData.build_ctx.coeff = ((CeedConstCoeff*)ceedData.coeff)->val;
break;
case CeedCoeff::Grid:
qf = qf_file + op.grid_func;
@@ -479,12 +358,8 @@ void CeedPAAssemble(const CeedPAOperator& op,
CeedQFunctionAddInput(ceedData.build_qfunc, "weights", 1, CEED_EVAL_WEIGHT);
CeedQFunctionAddOutput(ceedData.build_qfunc, "qdata", qdatasize,
CEED_EVAL_NONE);
CeedQFunctionContextCreate(ceed, &ceedData.build_ctx);
CeedQFunctionContextSetData(ceedData.build_ctx, CEED_MEM_HOST, CEED_USE_POINTER,
sizeof(ceedData.build_ctx_data),
&ceedData.build_ctx_data);
CeedQFunctionSetContext(ceedData.build_qfunc, ceedData.build_ctx);
CeedQFunctionSetContext(ceedData.build_qfunc, &ceedData.build_ctx,
sizeof(ceedData.build_ctx));
// Create the operator that builds the quadrature data for the operator.
CeedOperatorCreate(ceed, ceedData.build_qfunc, NULL, NULL,
@@ -524,7 +399,8 @@ void CeedPAAssemble(const CeedPAOperator& op,
CeedQFunctionAddInput(ceedData.apply_qfunc, "qdata", qdatasize,
CEED_EVAL_NONE);
CeedQFunctionAddOutput(ceedData.apply_qfunc, "v", dimV, op.test_op);
CeedQFunctionSetContext(ceedData.apply_qfunc, ceedData.build_ctx);
CeedQFunctionSetContext(ceedData.apply_qfunc, &ceedData.build_ctx,
sizeof(ceedData.build_ctx));
// Create the diff operator.
CeedOperatorCreate(ceed, ceedData.apply_qfunc, NULL, NULL, &ceedData.oper);
@@ -539,59 +415,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
+8 -56
View File
@@ -16,11 +16,7 @@
#ifdef MFEM_USE_CEED
#include "../../general/device.hpp"
#include "../../linalg/vector.hpp"
#include <ceed.h>
#include <ceed-hash.h>
#include <tuple>
#include <unordered_map>
namespace mfem
{
@@ -30,47 +26,7 @@ class GridFunction;
class IntegrationRule;
class Coefficient;
// Hash table for CeedBasis
using CeedBasisKey =
std::tuple<const FiniteElementSpace*, const IntegrationRule*, int, int, int>;
struct CeedBasisHash
{
std::size_t operator()(const CeedBasisKey& k) const
{
return CeedHashCombine(CeedHashCombine(CeedHashInt(
reinterpret_cast<CeedHash64_t>(std::get<0>(k))),
CeedHashInt(
reinterpret_cast<CeedHash64_t>(std::get<1>(k)))),
CeedHashCombine(CeedHashCombine(CeedHashInt(std::get<2>(k)),
CeedHashInt(std::get<3>(k))),
CeedHashInt(std::get<4>(k))));
}
};
using CeedBasisMap =
std::unordered_map<const CeedBasisKey, CeedBasis, CeedBasisHash>;
// Hash table for CeedElemRestriction
using CeedRestrKey = std::tuple<const FiniteElementSpace*, int, int, int>;
struct CeedRestrHash
{
std::size_t operator()(const CeedRestrKey& k) const
{
return CeedHashCombine(CeedHashCombine(CeedHashInt(
reinterpret_cast<CeedHash64_t>(std::get<0>(k))),
CeedHashInt(std::get<1>(k))),
CeedHashCombine(CeedHashInt(std::get<2>(k)),
CeedHashInt(std::get<3>(k))));
}
};
using CeedRestrMap =
std::unordered_map<const CeedRestrKey, CeedElemRestriction, CeedRestrHash>;
namespace internal
{
extern Ceed ceed; // defined in device.cpp
extern CeedBasisMap basis_map;
extern CeedRestrMap restr_map;
}
namespace internal { extern Ceed ceed; } // defined in device.cpp
/// A structure used to pass additional data to f_build_diff and f_apply_diff
struct BuildContext { CeedInt dim, space_dim; CeedScalar coeff; };
@@ -99,8 +55,7 @@ struct CeedData
CeedVector node_coords, rho;
CeedCoeff coeff_type;
void* coeff;
CeedQFunctionContext build_ctx;
BuildContext build_ctx_data;
BuildContext build_ctx;
CeedVector u, v;
@@ -108,6 +63,10 @@ struct CeedData
{
CeedOperatorDestroy(&build_oper);
CeedOperatorDestroy(&oper);
CeedBasisDestroy(&basis);
CeedBasisDestroy(&mesh_basis);
CeedElemRestrictionDestroy(&restr);
CeedElemRestrictionDestroy(&mesh_restr);
CeedElemRestrictionDestroy(&restr_i);
CeedElemRestrictionDestroy(&mesh_restr_i);
CeedQFunctionDestroy(&apply_qfunc);
@@ -117,6 +76,8 @@ struct CeedData
if (coeff_type==CeedCoeff::Grid)
{
CeedGridCoeff* c = (CeedGridCoeff*)coeff;
CeedBasisDestroy(&c->basis);
CeedElemRestrictionDestroy(&c->restr);
CeedVectorDestroy(&c->coeffVector);
delete c;
}
@@ -183,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()
+4 -5
View File
@@ -178,11 +178,10 @@ public:
/** @brief Make the LinearForm reference external data on a new
FiniteElementSpace. */
/** This method changes the FiniteElementSpace associated with the LinearForm
@a *f and sets the data of the Vector @a v (plus the @a v_offset) as
external data in the LinearForm.
@note This version of the method will also perform bounds checks when the
build option MFEM_DEBUG is enabled. */
@a *f and sets the data of the Vector @a v (plus the @a v_offset)
as external data in the LinearForm.
@note This version of the method will also perform bounds checks when
the build option MFEM_DEBUG is enabled. */
virtual void MakeRef(FiniteElementSpace *f, Vector &v, int v_offset);
/// Return the action of the LinearForm as a linear mapping.
+39 -6
View File
@@ -457,8 +457,20 @@ void VectorFEDomainLFCurlIntegrator::AssembleRHSElementVect(
Tr.SetIntPoint (&ip);
el.CalcPhysCurlShape(Tr, curlshape);
QF->Eval(vec, Tr, ip);
switch (spaceDim)
{
case 3:
MFEM_VERIFY(QF, "VectorFunctionCoefficient not provided");
QF->Eval(vec, Tr, ip);
break;
case 2:
MFEM_VERIFY(Q, "FunctionCoefficient (Scalar) not provided");
vec[0] = Q->Eval(Tr, ip);
break;
default:
break; // This should be unreachable
}
vec *= ip.weight * Tr.Weight();
curlshape.AddMult (vec, elvect);
}
@@ -468,17 +480,38 @@ void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect(
const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
{
int spaceDim = Trans.GetSpaceDim();
MFEM_ASSERT(vec_delta != NULL,
"coefficient must be VectorDeltaCoefficient");
switch (spaceDim)
{
case 3:
MFEM_ASSERT(vec_delta != NULL,
"coefficient must be VectorDeltaCoefficient");
break;
case 2:
MFEM_ASSERT(delta != NULL,
"coefficient must be DeltaCoefficient");
break;
default:
break; // This should be unreachable
}
int dof = fe.GetDof();
int n=(spaceDim == 3)? spaceDim : 1;
vec.SetSize(n);
curlshape.SetSize(dof, n);
elvect.SetSize(dof);
fe.CalcPhysCurlShape(Trans, curlshape);
vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint());
curlshape.Mult(vec, elvect);
switch (spaceDim)
{
case 3:
vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint());
curlshape.Mult(vec, elvect);
break;
case 2:
curlshape.GetColumn(0,elvect);
elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
break;
default:
break; // This should be unreachable
}
}
void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect(
+3
View File
@@ -284,6 +284,7 @@ class VectorFEDomainLFCurlIntegrator : public DeltaLFIntegrator
{
private:
VectorCoefficient *QF=nullptr;
Coefficient *Q=nullptr;
DenseMatrix curlshape;
Vector vec;
@@ -291,6 +292,8 @@ public:
/// Constructs the domain integrator (Q, curl v)
VectorFEDomainLFCurlIntegrator(VectorCoefficient &F)
: DeltaLFIntegrator(F), QF(&F) { }
VectorFEDomainLFCurlIntegrator(Coefficient &F)
: DeltaLFIntegrator(F), Q(&F) { }
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
-7
View File
@@ -581,13 +581,6 @@ double BlockNonlinearForm::GetEnergyBlocked(const BlockVector &bx) const
}
}
// free the allocated memory
for (int i = 0; i < fes.Size(); ++i)
{
delete el_x[i];
delete vdofs[i];
}
if (fnfi.Size())
{
MFEM_ABORT("TODO: add energy contribution from interior face terms");
-47
View File
@@ -565,53 +565,6 @@ HypreParMatrix* ParDiscreteLinearOperator::ParallelAssemble() const
return RAP;
}
void ParDiscreteLinearOperator::ParallelAssemble(OperatorHandle &A)
{
// construct the rectangular block-diagonal matrix dA
OperatorHandle dA(A.Type());
dA.MakeRectangularBlockDiag(domain_fes->GetComm(),
range_fes->GlobalVSize(),
domain_fes->GlobalVSize(),
range_fes->GetDofOffsets(),
domain_fes->GetDofOffsets(),
mat);
OperatorHandle P_test(A.Type()), P_trial(A.Type());
// TODO - construct the Dof_TrueDof_Matrix directly in the required format.
P_test.ConvertFrom(range_fes->Dof_TrueDof_Matrix());
P_trial.ConvertFrom(domain_fes->Dof_TrueDof_Matrix());
A.MakeRAP(P_test, dA, P_trial);
}
//// @todo copied from ParMixedBilinearForm, should be some inheritance?
void ParDiscreteLinearOperator::FormRectangularSystemMatrix(OperatorHandle &A)
{
if (ext)
{
Array<int> empty;
ext->FormRectangularSystemOperator(empty, empty, A);
return;
}
/*
if (mat)
{
Finalize();
ParallelAssemble(p_mat);
delete mat;
mat = NULL;
delete mat_e;
mat_e = NULL;
p_mat_e = NULL;
}
A = p_mat;
*/
mfem_error("not implemented!");
}
void ParDiscreteLinearOperator::GetParBlocks(Array2D<HypreParMatrix *> &blocks)
const
{
-11
View File
@@ -160,9 +160,6 @@ public:
/// Get the parallel finite element space prolongation matrix
virtual const Operator *GetProlongation() const
{ return pfes->GetProlongationMatrix(); }
/// Get the diagonal part of the parallel finite element space prolongation matrix
virtual const Operator *GetLocalProlongation() const
{ return pfes->GetLocalProlongationMatrix(); }
/// Get the parallel finite element space restriction matrix
virtual const Operator *GetRestriction() const
{ return pfes->GetRestrictionMatrix(); }
@@ -304,18 +301,10 @@ public:
/// Returns the matrix "assembled" on the true dofs
HypreParMatrix *ParallelAssemble() const;
/** @brief Returns the matrix assembled on the true dofs, i.e.
@a A = P_test^t A_local P_trial, in the format (type id) specified by
@a A. */
void ParallelAssemble(OperatorHandle &A);
/** Extract the parallel blocks corresponding to the vector dimensions of the
domain and range parallel finite element spaces */
void GetParBlocks(Array2D<HypreParMatrix *> &blocks) const;
/** @brief Return in @a A a parallel (on truedofs) version of this operator. */
virtual void FormRectangularSystemMatrix(OperatorHandle &A);
virtual ~ParDiscreteLinearOperator() { }
};
+7 -58
View File
@@ -101,7 +101,6 @@ void ParFiniteElementSpace::ParInit(ParMesh *pm)
P = NULL;
Pconf = NULL;
Pconf_local = NULL;
R = NULL;
num_face_nbr_dofs = -1;
@@ -922,39 +921,6 @@ const Operator *ParFiniteElementSpace::GetProlongationMatrix() const
}
}
const Operator *ParFiniteElementSpace::GetLocalProlongationMatrix() const
{
if (Conforming())
{
if (Pconf_local) { return Pconf_local; }
if (NRanks == 1)
{
Pconf_local = new IdentityOperator(GetTrueVSize());
}
else
{
if (!Device::Allows(Backend::DEVICE_MASK))
{
Pconf_local = new ConformingProlongationOperator(*this, true);
}
else
{
// Pconf = new DeviceConformingProlongationOperator(*this);
mfem_error("Not implemented!");
}
}
return Pconf_local;
}
else
{
// return Dof_TrueDof_Matrix();
// just need diagonal portion, not too hard
mfem_error("Not implemented!");
return NULL;
}
}
void ParFiniteElementSpace::ExchangeFaceNbrData()
{
if (num_face_nbr_dofs >= 0) { return; }
@@ -2868,7 +2834,6 @@ void ParFiniteElementSpace::Destroy()
delete P; P = NULL;
delete Pconf; Pconf = NULL;
delete Pconf_local; Pconf_local = NULL;
delete R; R = NULL;
delete gcomm; gcomm = NULL;
@@ -2994,12 +2959,12 @@ void ParFiniteElementSpace::Update(bool want_transform)
}
}
ConformingProlongationOperator::ConformingProlongationOperator(
const ParFiniteElementSpace &pfes, bool local_)
const ParFiniteElementSpace &pfes)
: Operator(pfes.GetVSize(), pfes.GetTrueVSize()),
external_ldofs(),
gc(pfes.GroupComm()),
local(local_)
gc(pfes.GroupComm())
{
MFEM_VERIFY(pfes.Conforming(), "");
const Table &group_ldof = gc.GroupLDofTable();
@@ -3048,14 +3013,7 @@ void ConformingProlongationOperator::Mult(const Vector &x, Vector &y) const
const int m = external_ldofs.Size();
const int in_layout = 2; // 2 - input is ltdofs array
if (local)
{
y = 0.0;
}
else
{
gc.BcastBegin(const_cast<double*>(xdata), in_layout);
}
gc.BcastBegin(const_cast<double*>(xdata), in_layout);
int j = 0;
for (int i = 0; i < m; i++)
@@ -3067,10 +3025,7 @@ void ConformingProlongationOperator::Mult(const Vector &x, Vector &y) const
std::copy(xdata+j-m, xdata+Width(), ydata+j);
const int out_layout = 0; // 0 - output is ldofs array
if (!local)
{
gc.BcastEnd(ydata, out_layout);
}
gc.BcastEnd(ydata, out_layout);
}
void ConformingProlongationOperator::MultTranspose(
@@ -3083,10 +3038,7 @@ void ConformingProlongationOperator::MultTranspose(
double *ydata = y.HostWrite();
const int m = external_ldofs.Size();
if (!local)
{
gc.ReduceBegin(xdata);
}
gc.ReduceBegin(xdata);
int j = 0;
for (int i = 0; i < m; i++)
@@ -3098,10 +3050,7 @@ void ConformingProlongationOperator::MultTranspose(
std::copy(xdata+j, xdata+Height(), ydata+j-m);
const int out_layout = 2; // 2 - output is an array on all ltdofs
if (!local)
{
gc.ReduceEnd<double>(ydata, out_layout, GroupCommunicator::Sum);
}
gc.ReduceEnd<double>(ydata, out_layout, GroupCommunicator::Sum);
}
DeviceConformingProlongationOperator::DeviceConformingProlongationOperator(
+1 -7
View File
@@ -72,9 +72,6 @@ private:
mutable HypreParMatrix *P;
/// Optimized action-only prolongation operator for conforming meshes. Owned.
mutable Operator *Pconf;
/// Optimized action-only diagonal prolongation operator on ldofs for
/// conforming meshes. Owned.
mutable Operator *Pconf_local;
/// The (block-diagonal) matrix R (restriction of dof to true dof). Owned.
mutable SparseMatrix *R;
@@ -338,7 +335,6 @@ public:
HYPRE_Int GetMyTDofOffset() const;
virtual const Operator *GetProlongationMatrix() const;
virtual const Operator *GetLocalProlongationMatrix() const;
/// Get the R matrix which restricts a local dof vector to true dof vector.
virtual const SparseMatrix *GetRestrictionMatrix() const
{ Dof_TrueDof_Matrix(); return R; }
@@ -393,11 +389,9 @@ class ConformingProlongationOperator : public Operator
protected:
Array<int> external_ldofs;
const GroupCommunicator &gc;
bool local;
public:
ConformingProlongationOperator(const ParFiniteElementSpace &pfes,
bool local_=false);
ConformingProlongationOperator(const ParFiniteElementSpace &pfes);
virtual void Mult(const Vector &x, Vector &y) const;
+2 -162
View File
@@ -655,167 +655,6 @@ void ParGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
#endif
}
double ParGridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
Coefficient *ell_coeff,
double Nu,
const IntegrationRule *irs[]) const
{
const_cast<ParGridFunction *>(this)->ExchangeFaceNbrData();
int fdof, dim, intorder, k;
ElementTransformation *transf;
Vector shape, el_dofs, err_val, ell_coeff_val;
Array<int> vdofs;
IntegrationPoint eip;
double error = 0.0;
ParMesh *mesh = pfes->GetParMesh();
dim = mesh->Dimension();
std::map<int,int> local_to_shared;
for (int i = 0; i < mesh->GetNSharedFaces(); ++i)
{
int i_local = mesh->GetSharedFace(i);
local_to_shared[i_local] = i;
}
for (int i = 0; i < mesh->GetNumFaces(); i++)
{
double shared_face_factor = 1.0;
bool shared_face = false;
int iel1, iel2, info1, info2;
mesh->GetFaceElements(i, &iel1, &iel2);
mesh->GetFaceInfos(i, &info1, &info2);
intorder = fes->GetFE(iel1)->GetOrder();
FaceElementTransformations *face_elem_transf;
const FiniteElement *fe1, *fe2;
if (info2 >= 0 && iel2 < 0)
{
int ishared = local_to_shared[i];
face_elem_transf = mesh->GetSharedFaceTransformations(ishared);
iel2 = face_elem_transf->Elem2No - mesh->GetNE();
fe2 = pfes->GetFaceNbrFE(iel2);
if ( (k = fe2->GetOrder()) > intorder )
{
intorder = k;
}
shared_face = true;
shared_face_factor = 0.5;
}
else
{
face_elem_transf = mesh->GetFaceElementTransformations(i);
if (iel2 >= 0)
{
fe2 = pfes->GetFE(iel2);
if ( (k = fe2->GetOrder()) > intorder )
{
intorder = k;
}
}
else
{
fe2 = NULL;
}
}
intorder = 2 * intorder; // <-------------
const IntegrationRule *ir;
if (irs)
{
ir = irs[face_elem_transf->GetGeometryType()];
}
else
{
ir = &(IntRules.Get(face_elem_transf->GetGeometryType(), intorder));
}
err_val.SetSize(ir->GetNPoints());
ell_coeff_val.SetSize(ir->GetNPoints());
// side 1
transf = face_elem_transf->Elem1;
fe1 = fes->GetFE(iel1);
fdof = fe1->GetDof();
fes->GetElementVDofs(iel1, vdofs);
shape.SetSize(fdof);
el_dofs.SetSize(fdof);
for (k = 0; k < fdof; k++)
if (vdofs[k] >= 0)
{
el_dofs(k) = (*this)(vdofs[k]);
}
else
{
el_dofs(k) = - (*this)(-1-vdofs[k]);
}
for (int j = 0; j < ir->GetNPoints(); j++)
{
face_elem_transf->Loc1.Transform(ir->IntPoint(j), eip);
fe1->CalcShape(eip, shape);
transf->SetIntPoint(&eip);
ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
}
if (fe2 != NULL)
{
// side 2
transf = face_elem_transf->Elem2;
fdof = fe2->GetDof();
shape.SetSize(fdof);
el_dofs.SetSize(fdof);
if (shared_face)
{
pfes->GetFaceNbrElementVDofs(iel2, vdofs);
for (k = 0; k < fdof; k++)
if (vdofs[k] >= 0)
{
el_dofs(k) = face_nbr_data[vdofs[k]];
}
else
{
el_dofs(k) = - face_nbr_data[-1-vdofs[k]];
}
}
else
{
pfes->GetElementVDofs(iel2, vdofs);
for (k = 0; k < fdof; k++)
if (vdofs[k] >= 0)
{
el_dofs(k) = (*this)(vdofs[k]);
}
else
{
el_dofs(k) = - (*this)(-1 - vdofs[k]);
}
}
for (int j = 0; j < ir->GetNPoints(); j++)
{
face_elem_transf->Loc2.Transform(ir->IntPoint(j), eip);
fe2->CalcShape(eip, shape);
transf->SetIntPoint(&eip);
ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
ell_coeff_val(j) *= 0.5;
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
}
}
transf = face_elem_transf;
for (int j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
transf->SetIntPoint(&ip);
error += shared_face_factor*(ip.weight * Nu * ell_coeff_val(j) *
pow(transf->Weight(), 1.0-1.0/(dim-1)) *
err_val(j) * err_val(j));
}
}
error = (error < 0.0) ? -sqrt(-error) : sqrt(error);
return GlobalLpNorm(2.0, error, pfes->GetComm());
}
void ParGridFunction::Save(std::ostream &out) const
{
double *data_ = const_cast<double*>(HostRead());
@@ -1021,6 +860,7 @@ double GlobalLpNorm(const double p, double loc_norm, MPI_Comm comm)
return glob_norm;
}
void ParGridFunction::ComputeFlux(
BilinearFormIntegrator &blfi,
GridFunction &flux, bool wcoef, int subdomain)
@@ -1161,6 +1001,6 @@ double L2ZZErrorEstimator(BilinearFormIntegrator &flux_integrator,
return pow(glob_error, 1.0/norm_p);
}
} // namespace mfem
}
#endif // MFEM_USE_MPI
-71
View File
@@ -283,77 +283,6 @@ public:
pfes->GetComm());
}
/// Returns ||grad u_ex - grad u_h||_L2 for H1 or L2 elements
virtual double ComputeGradError(VectorCoefficient *exgrad,
const IntegrationRule *irs[] = NULL) const
{
return GlobalLpNorm(2.0, GridFunction::ComputeGradError(exgrad,irs),
pfes->GetComm());
}
/// Returns ||curl u_ex - curl u_h||_L2 for ND elements
virtual double ComputeCurlError(VectorCoefficient *excurl,
const IntegrationRule *irs[] = NULL) const
{
return GlobalLpNorm(2.0, GridFunction::ComputeCurlError(excurl,irs),
pfes->GetComm());
}
/// Returns ||div u_ex - div u_h||_L2 for RT elements
virtual double ComputeDivError(Coefficient *exdiv,
const IntegrationRule *irs[] = NULL) const
{
return GlobalLpNorm(2.0, GridFunction::ComputeDivError(exdiv,irs),
pfes->GetComm());
}
/// Returns the Face Jumps error for L2 elements
virtual double ComputeDGFaceJumpError(Coefficient *exsol,
Coefficient *ell_coeff,
double Nu,
const IntegrationRule *irs[]=NULL)
const;
/// Returns either the H1-seminorm or the DG Face Jumps error or both
/// depending on norm_type = 1, 2, 3
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
Coefficient *ell_coef, double Nu,
int norm_type) const
{
return GlobalLpNorm(2.0,
GridFunction::ComputeH1Error(exsol,exgrad,ell_coef,
Nu, norm_type),
pfes->GetComm());
}
/// Returns the error measured in H1-norm for H1 elements or in "broken"
/// H1-norm for L2 elements
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
const IntegrationRule *irs[] = NULL) const
{
return GlobalLpNorm(2.0, GridFunction::ComputeH1Error(exsol,exgrad,irs),
pfes->GetComm());
}
/// Returns the error measured H(div)-norm for RT elements
virtual double ComputeHDivError(VectorCoefficient *exsol,
Coefficient *exdiv,
const IntegrationRule *irs[] = NULL) const
{
return GlobalLpNorm(2.0, GridFunction::ComputeHDivError(exsol,exdiv,irs),
pfes->GetComm());
}
/// Returns the error measured H(curl)-norm for ND elements
virtual double ComputeHCurlError(VectorCoefficient *exsol,
VectorCoefficient *excurl,
const IntegrationRule *irs[] = NULL) const
{
return GlobalLpNorm(2.0,
GridFunction::ComputeHCurlError(exsol,excurl,irs),
pfes->GetComm());
}
virtual double ComputeMaxError(Coefficient *exsol[],
const IntegrationRule *irs[] = NULL) const
{

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