Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86b3a2e3b4 | ||
|
|
3acdce1cb5 | ||
|
|
21e6939562 | ||
|
|
d14f14323c | ||
|
|
b58c3f956d | ||
|
|
76ab9919d8 | ||
|
|
3f625c9efa |
+11
-16
@@ -23,15 +23,16 @@ install:
|
||||
- set MSMPI_LIB64=C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x64
|
||||
- set MSMPI_INC=C:\Program Files (x86)\Microsoft SDKs\MPI\Include
|
||||
|
||||
# Install METIS, use MFEM's mirror because the original source server is often
|
||||
# down and we don't support yet the new repo https://github.com/KarypisLab/METIS
|
||||
# Install METIS, use a mirror because the original source server is not always
|
||||
# up. Original url:
|
||||
# http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-5.1.0.tar.gz
|
||||
- ps: Start-FileDownload 'https://mfem.github.io/tpls/metis-5.1.0.tar.gz'
|
||||
- 7z x metis-5.1.0.tar.gz -so | 7z x -si -ttar > nul
|
||||
- cd metis-5.1.0
|
||||
- ps: ( get-content "GKlib\gk_arch.h") | % { If ($_.ReadCount -ge 52) {$_ -replace "#ifdef __MSC__","#ifdef DISABLE_THIS_ANCIENT_MSC_CHECK"} Else {$_} } | set-content "GKlib\gk_arch.h"
|
||||
- cmake -H. -Bbuild
|
||||
# -DCMAKE_BUILD_TYPE=Release
|
||||
- cmake --build build --target metis -j 4
|
||||
- cmake --build build
|
||||
- set METIS_PATH=%cd%
|
||||
- cd ..
|
||||
|
||||
@@ -40,7 +41,7 @@ install:
|
||||
- 7z x v2.19.0.tar.gz -so | 7z x -si -ttar > nul
|
||||
- cd hypre-2.19.0/src
|
||||
- cmake -H. -Bbuild
|
||||
- cmake --build build -j 4
|
||||
- cmake --build build
|
||||
- cmake --build build --target install
|
||||
- cd ../..
|
||||
|
||||
@@ -49,20 +50,14 @@ install:
|
||||
|
||||
# MFEM
|
||||
before_build:
|
||||
- cmake . -Bbuild_parallel -DMFEM_USE_MPI=TRUE -DMFEM_USE_METIS_5=TRUE -DHYPRE_DIR=%cd%\..\hypre-2.19.0\src\hypre -DMETIS_LIBRARIES=%METIS_PATH%\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%METIS_PATH%\include
|
||||
# - cmake . -Bbuild_serial -DMFEM_USE_MPI=FALSE
|
||||
- cmake . -Bbuild_shared_serial -DMFEM_USE_MPI=FALSE -DBUILD_SHARED_LIBS=ON
|
||||
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_parallel -DMFEM_USE_MPI=TRUE -DMFEM_USE_METIS_5=TRUE -DHYPRE_DIR=%cd%\..\hypre-2.19.0\src\hypre -DMETIS_LIBRARIES=%METIS_PATH%\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%METIS_PATH%\include
|
||||
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_serial -DMFEM_USE_MPI=FALSE
|
||||
|
||||
build_script:
|
||||
- cmake --build build_parallel --config Debug -j 4
|
||||
# - cmake --build build_serial --config Release -j 4
|
||||
# - cmake --build build_serial --target exec --config Release -j 4
|
||||
- cmake --build build_shared_serial --config Release -j 4
|
||||
- cmake --build build_shared_serial --target exec --config Release -j 4
|
||||
- cmake --build build_parallel --config Release -j 4
|
||||
- cmake --build build_serial --config Release -j 4
|
||||
- cmake --build build_serial --target exec --config Release -j 4
|
||||
|
||||
after_build:
|
||||
# - cd build_serial
|
||||
# - ctest -C Release --output-on-failure
|
||||
# - cd ..
|
||||
- cd build_shared_serial
|
||||
- cd build_serial
|
||||
- ctest -C Release --output-on-failure
|
||||
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
|
||||
- name: GHCR Login
|
||||
if: (github.event_name != 'pull_request')
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
||||
@@ -74,10 +74,6 @@ jobs:
|
||||
codecov: YES
|
||||
- os: windows-latest
|
||||
codecov: NO
|
||||
- os: windows-latest
|
||||
target: opt
|
||||
mpi: par
|
||||
config-opts: '-DBUILD_SHARED_LIBS=ON'
|
||||
- os: ubuntu-latest
|
||||
target: opt
|
||||
codecov: NO
|
||||
@@ -98,7 +94,7 @@ jobs:
|
||||
# This external action allows to interrupt a workflow already running on
|
||||
# the same branch to save resource
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
uses: styfle/cancel-workflow-action@0.9.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
@@ -106,7 +102,7 @@ jobs:
|
||||
# /home/runner/work/mfem/mfem/mfem
|
||||
# Note: Done now to access "install-hypre" and "install-metis" actions.
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: ${{ env.MFEM_TOP_DIR }}
|
||||
# Fetch the complete history for codecov to access commits ID
|
||||
@@ -119,25 +115,25 @@ jobs:
|
||||
if: matrix.mpi == 'par' && matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get install mpich libmpich-dev
|
||||
export MAKE_CXX_FLAG="MPICXX=mpic++"
|
||||
|
||||
- name: get lcov (Linux)
|
||||
if: matrix.codecov == 'YES' && matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get install lcov
|
||||
|
||||
# Keep the following section in case we need it again in the future,
|
||||
# see: https://github.com/mfem/mfem/pull/3385#discussion_r1058013032
|
||||
# - name: Set up Homebrew
|
||||
# if: ( matrix.mpi == 'par' || matrix.codecov == 'YES' ) && matrix.os == 'macos-latest'
|
||||
# uses: Homebrew/actions/setup-homebrew@master
|
||||
- name: Set up Homebrew
|
||||
if: ( matrix.mpi == 'par' || matrix.codecov == 'YES' ) && matrix.os == 'macos-latest'
|
||||
uses: Homebrew/actions/setup-homebrew@c4aafe8c4620bf08883dd4679c374f11e73329d3
|
||||
|
||||
- name: get MPI (MacOS)
|
||||
if: matrix.mpi == 'par' && matrix.os == 'macos-latest'
|
||||
run: |
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
brew install openmpi
|
||||
export MAKE_CXX_FLAG="MPICXX=mpic++"
|
||||
|
||||
- name: get lcov (MacOS)
|
||||
- name: get MPI (MacOS)
|
||||
if: matrix.codecov == 'YES' && matrix.os == 'macos-latest'
|
||||
run: |
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
@@ -145,14 +141,14 @@ jobs:
|
||||
|
||||
- name: get MPI (Windows)
|
||||
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
|
||||
uses: mpi4py/setup-mpi@v1.1.4
|
||||
uses: mpi4py/setup-mpi@v1.0.3
|
||||
|
||||
# Get Hypre through cache, or build it.
|
||||
# Install will only run on cache miss.
|
||||
- name: cache hypre
|
||||
id: hypre-cache
|
||||
if: matrix.mpi == 'par'
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.HYPRE_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-v2.2
|
||||
@@ -180,7 +176,7 @@ jobs:
|
||||
- name: cache metis
|
||||
id: metis-cache
|
||||
if: matrix.mpi == 'par' && matrix.os != 'windows-latest'
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.METIS_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
|
||||
@@ -194,13 +190,12 @@ jobs:
|
||||
|
||||
- name: cache vcpkg (Windows)
|
||||
id: vcpkg-cache
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: vcpkg_cache
|
||||
key: ${{ runner.os }}-${{ matrix.mpi }}-vcpkg-v1
|
||||
|
||||
- name: prepare vcpkg binary cache location (Windows)
|
||||
- name: prepare binary cache location
|
||||
if: matrix.os == 'windows-latest' && steps.vcpkg-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
mkdir -p vcpkg_cache
|
||||
@@ -214,7 +209,7 @@ jobs:
|
||||
|
||||
# MFEM build and test
|
||||
- name: build
|
||||
uses: mfem/github-actions/build-mfem@v2.3
|
||||
uses: mfem/github-actions/build-mfem@v2.2
|
||||
env:
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
|
||||
with:
|
||||
@@ -226,7 +221,7 @@ jobs:
|
||||
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
metis-dir: ${{ env.METIS_TOP_DIR }}
|
||||
mfem-dir: ${{ env.MFEM_TOP_DIR }}
|
||||
config-options: ${{ matrix.config-opts }}
|
||||
config-options: ${{ env.MFEM_EXTRA_CONFIG }}
|
||||
library-only: ${{ matrix.target == 'dbg' }}
|
||||
|
||||
# Run checks (and only checks) on debug targets
|
||||
@@ -235,7 +230,11 @@ jobs:
|
||||
run: |
|
||||
cd ${{ env.MFEM_TOP_DIR }} && make check
|
||||
|
||||
# Note: 'tests' include the unit tests
|
||||
- name: unit tests
|
||||
if: matrix.build-system == 'make' && matrix.target == 'opt'
|
||||
run: |
|
||||
cd ${{ env.MFEM_TOP_DIR }} && make unittest
|
||||
|
||||
- name: tests
|
||||
if: matrix.build-system == 'make' && matrix.target == 'opt'
|
||||
run: |
|
||||
@@ -248,7 +247,7 @@ jobs:
|
||||
cd ${{ env.MFEM_TOP_DIR }} && cmake --build build --target check --config ${CTEST_CONFIG}
|
||||
shell: bash
|
||||
|
||||
- name: cmake unit tests (Ubuntu)
|
||||
- name: cmake unit tests (Ubuntu 20.04)
|
||||
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
CTEST_CONFIG="Release"
|
||||
@@ -266,7 +265,7 @@ jobs:
|
||||
# Code coverage (process and upload reports)
|
||||
- name: codecov
|
||||
if: matrix.codecov == 'YES'
|
||||
uses: mfem/github-actions/upload-coverage@v2.2
|
||||
uses: mfem/github-actions/upload-coverage@v2.0
|
||||
with:
|
||||
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
|
||||
project_dir: ${{ env.MFEM_TOP_DIR }}
|
||||
|
||||
@@ -49,6 +49,7 @@ jobs:
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
queries: lgtm
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
|
||||
@@ -35,22 +35,23 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
uses: styfle/cancel-workflow-action@0.9.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
- name: checkout MFEM
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: mfem
|
||||
|
||||
- name: Get MPI (Linux)
|
||||
run: |
|
||||
sudo apt-get install mpich libmpich-dev
|
||||
export MAKE_CXX_FLAG="MPICXX=mpic++"
|
||||
|
||||
- name: Cache Hypre Install
|
||||
id: hypre-cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.HYPRE_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.2
|
||||
@@ -65,7 +66,7 @@ jobs:
|
||||
|
||||
- name: Cache Metis Install
|
||||
id: metis-cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.METIS_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
|
||||
|
||||
@@ -34,12 +34,12 @@ jobs:
|
||||
github.event.pull_request.head.repo.full_name != github.repository)
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
uses: styfle/cancel-workflow-action@0.9.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: copyright check
|
||||
id: copyright
|
||||
@@ -84,7 +84,7 @@ jobs:
|
||||
github.event.pull_request.head.repo.full_name != github.repository)
|
||||
steps:
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: get astyle
|
||||
run: |
|
||||
@@ -101,16 +101,13 @@ jobs:
|
||||
github.event.pull_request.head.repo.full_name != github.repository)
|
||||
steps:
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: get doxygen and graphviz
|
||||
run: |
|
||||
sudo apt-get install doxygen graphviz
|
||||
|
||||
- name: update doxygen config file
|
||||
run: |
|
||||
cd doc
|
||||
doxygen -u CodeDocumentation.conf.in
|
||||
doxygen -u CodeDocumentation.conf.in 2>/dev/null
|
||||
|
||||
- name: build documentation
|
||||
run: |
|
||||
@@ -126,7 +123,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
-10
@@ -21,9 +21,6 @@ CMakeFiles/
|
||||
# Default install location
|
||||
/mfem/
|
||||
|
||||
# Typical build directory
|
||||
/build/
|
||||
|
||||
# Generated files in main directory, config/ and docs/
|
||||
/deps.mk
|
||||
config/_config.hpp
|
||||
@@ -206,7 +203,6 @@ miniapps/meshing/mesh-explorer
|
||||
miniapps/meshing/shaper
|
||||
miniapps/meshing/extruder
|
||||
miniapps/meshing/trimmer
|
||||
miniapps/meshing/reflector
|
||||
miniapps/meshing/mesh-optimizer
|
||||
miniapps/meshing/pmesh-optimizer
|
||||
miniapps/meshing/minimal-surface
|
||||
@@ -218,12 +214,9 @@ miniapps/meshing/toroid-*.mesh
|
||||
miniapps/meshing/twist-*.mesh
|
||||
miniapps/meshing/mesh-explorer.mesh
|
||||
miniapps/meshing/partitioning.txt
|
||||
miniapps/meshing/mesh-explorer-visit*
|
||||
miniapps/meshing/mesh-explorer-paraview/
|
||||
miniapps/meshing/shaper.mesh
|
||||
miniapps/meshing/extruder.mesh
|
||||
miniapps/meshing/trimmer.mesh
|
||||
miniapps/meshing/reflected.mesh
|
||||
miniapps/meshing/optimized*
|
||||
miniapps/meshing/perturbed*
|
||||
miniapps/meshing/polar-nc.mesh
|
||||
@@ -282,8 +275,6 @@ miniapps/tools/load-dc
|
||||
miniapps/tools/convert-dc
|
||||
miniapps/tools/lor-transfer
|
||||
miniapps/tools/get-values
|
||||
miniapps/tools/check-tmop-metric
|
||||
miniapps/tools/tmop-metric-magnitude
|
||||
|
||||
miniapps/toys/automata
|
||||
miniapps/toys/life
|
||||
@@ -316,7 +307,6 @@ miniapps/solvers/sol.*
|
||||
miniapps/parelag/MultilevelHcurlHdivSolver
|
||||
miniapps/parelag/*.mesh
|
||||
|
||||
miniapps/multidomain/multidomain
|
||||
miniapps/hooke/hooke
|
||||
|
||||
# Unit test binary and outputs
|
||||
|
||||
@@ -93,7 +93,7 @@ report_baseline:
|
||||
git pull && \
|
||||
git add ${rundir} && \
|
||||
git commit -m "${msg}" && \
|
||||
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
|
||||
git push origin master
|
||||
else
|
||||
for file in ${rundir}/*; do
|
||||
echo "------------------------------"
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2010-2022, 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.
|
||||
|
||||
# Try to push to the remote 5 times. If the push fails, and the local and remote
|
||||
# have diverged, then pull from the remote to merge changes, and try pushing
|
||||
# again. If some other failure happens
|
||||
for i in {1..5}; do
|
||||
git push origin master && exit 0
|
||||
# Wait for 20 seconds in case someone else is pushing to the remote
|
||||
# concurrently
|
||||
sleep 20
|
||||
# Fetch any updates from the remote
|
||||
git remote update
|
||||
# Get the latest commit on the local branch
|
||||
LOCAL=$(git rev-parse @)
|
||||
# Get the latest commit on the remote
|
||||
REMOTE=$(git rev-parse @{u})
|
||||
# Get the common ancestor
|
||||
BASE=$(git merge-base @ @{u})
|
||||
# Have the local and remote diverged?
|
||||
if [[ $LOCAL != $REMOTE && $LOCAL != $BASE && $REMOTE != $BASE ]]; then
|
||||
git pull
|
||||
if [[ $? == 0 ]]; then
|
||||
continue
|
||||
else
|
||||
exit 1 # Something else went wrong trying to pull
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit 1 # Did not succeed in 5 attempts
|
||||
@@ -32,7 +32,7 @@ if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
|
||||
git pull && \
|
||||
git add ${rundir} && \
|
||||
git commit -m "${msg}" && \
|
||||
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
|
||||
git push origin master
|
||||
else
|
||||
for file in ${rundir}/*; do
|
||||
echo "------------------------------"
|
||||
|
||||
@@ -29,7 +29,7 @@ if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
|
||||
git pull && \
|
||||
git add ${rundir} && \
|
||||
git commit -m "${msg}" && \
|
||||
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
|
||||
git push origin master
|
||||
else
|
||||
for file in ${rundir}/*; do
|
||||
echo "------------------------------"
|
||||
|
||||
@@ -8,120 +8,31 @@
|
||||
https://mfem.org
|
||||
|
||||
|
||||
Version 4.5.1 (development)
|
||||
Version 4.4.1 (development)
|
||||
===========================
|
||||
- When using discontinuous (L2) spaces, use local (element-wise) L2 projection
|
||||
as the coarsening operator for non-conforming AMR meshes.
|
||||
|
||||
Meshing improvements
|
||||
--------------------
|
||||
- Added support for pyramids in non-conforming meshes. Currently only isotropic
|
||||
refinement is supported in this case.
|
||||
|
||||
- Updated logic in FindPointsGSLIB to ignore points found near (but outside) the
|
||||
domain boundary.
|
||||
|
||||
- Added support for pyramids in Gmsh meshes.
|
||||
|
||||
- Fixed a bug in TMOP metric 301.
|
||||
|
||||
- Added an option to auto-balance compound TMOP metrics.
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
- TBD
|
||||
|
||||
Linear and nonlinear solvers
|
||||
----------------------------
|
||||
- Added a fast normalization-based distance solver, see the Distance miniapp
|
||||
in the miniapps/shifted/ directory.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- Added a new meshing miniapp, reflector, which reflects a high-order or NURBS
|
||||
hexahedral mesh about a plane.
|
||||
|
||||
- The mesh-explorer miniapp can now save mesh files in the VisIt or ParaView
|
||||
formats using the corresponding DataCollection objects. See option 'D' in the
|
||||
main menu.
|
||||
|
||||
Integrations, testing and documentation
|
||||
---------------------------------------
|
||||
- Added support for shared Windows builds with MSVC through CMake.
|
||||
Developers note: this enhancement is facilitated by the addition of the macro
|
||||
MFEM_EXPORT, see config.hpp for more details on its usage.
|
||||
|
||||
- Removed the support for the Mesquite toolkit. We recommend using MFEM's TMOP
|
||||
functionality instead for mesh optimization. See the mesh-optimizer miniapp.
|
||||
|
||||
- The following integrations have updated minimum version requirements:
|
||||
* RAJA >= 2022.10.3
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- VisItDataCollection now correctly handles collection names containing
|
||||
underscores.
|
||||
|
||||
- VisItDataCollection::SetPadDigits() no longer alters the number of digits
|
||||
used to represent the MPI rank because VisIt seems to require 6 digits.
|
||||
This parameter can still be explicitly overridden with
|
||||
VisItDataCollection::SetPadDigitsRank().
|
||||
|
||||
API changes
|
||||
-----------
|
||||
- The implicit cast methods of class Vector to 'double *' and 'const double *'
|
||||
have been deprecated and generate deprecation warnings if used. They will be
|
||||
removed in a future release.
|
||||
|
||||
- The methods Mesh::GetFaceBaseGeometry and Mesh::GetFaceGeometryType have been
|
||||
deprecated, and Mesh::GetFaceGeometry (which provides identical functionality)
|
||||
should be used instead.
|
||||
|
||||
Version 4.5, released on October 22, 2022
|
||||
=========================================
|
||||
|
||||
Meshing improvements
|
||||
--------------------
|
||||
- Added new SubMesh and ParSubMesh classes that can be used to extract a subset
|
||||
of a given Mesh. These classes have the same functionality as Mesh and ParMesh
|
||||
and work with all existing MFEM interfaces like finite element spaces etc.
|
||||
|
||||
- Added a method, ParMesh::GetSerialMesh(), that reconstructs a partitioned
|
||||
parallel mesh on a given single rank. Also, added ParMesh::PrintAsSerial(),
|
||||
which saves the reconstructed serial mesh to a C++ stream on rank 0.
|
||||
|
||||
- Added more 3D TMOP metrics, as well as specialized metrics for mesh
|
||||
untangling and worst-case quality improvement.
|
||||
|
||||
- Added a new method, Mesh::NodesUpdated, which should be called after the mesh
|
||||
node coordinates have changed, e.g. after the mesh has moved. This is
|
||||
necessary, for example, with device assembly of linear and bilinear forms.
|
||||
|
||||
- Added support for mixed meshes and pyramids in GSLIB-FindPoints.
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
- Added support for assembling low-order-refined matrices using a GPU-enabled
|
||||
"batched" algorithm. The lor_solvers and plor_solvers now fully support GPU
|
||||
acceleration.
|
||||
|
||||
- Added support for partial assembly and fully matrix-free operators on mixed
|
||||
meshes (different element types and p-adaptivity) through libCEED, including
|
||||
device acceleration, e.g. with NVIDIA and AMD GPUs. The p-adaptivity is
|
||||
currently limited by MFEM capabilities, i.e. 2D serial meshes. All mixed
|
||||
element topologies are supported in serial and parallel: segment, triangle,
|
||||
square, tetrahedron, cube, prism, and pyramid.
|
||||
|
||||
- Added full assembly and device support for several LinearForm integrators:
|
||||
* DomainLF: (f, v)
|
||||
* VectorDomainLF: ((f1,...,fn), (v1,...,vn))
|
||||
* DomainLFGrad: (f, grad(v))
|
||||
* VectorDomainLFGrad: ((f1x,f1y,f1z,...,fnx,fny,fnz), grad(v1,...,vn))
|
||||
The device assembly of linear forms has to be explicitly enabled by calling
|
||||
LinearForm::UseFastAssembly(true), otherwise the legacy linear form assembly
|
||||
is used by default.
|
||||
|
||||
- Added support for assembling low-order-refined matrices using a GPU-enabled
|
||||
"batched" algorithm. The lor_solvers and plor_solvers now fully support GPU
|
||||
acceleration with arbitrary user-supplied coefficients.
|
||||
|
||||
- Added a new class FaceQuadratureSpace that allows for the construction of
|
||||
QuadratureFunctions on the interior or boundary faces of a mesh.
|
||||
|
||||
- Added a class CoefficientVector for efficient access of variable coefficient
|
||||
values at quadrature points (in particular for GPU/device kernels).
|
||||
|
||||
- Added support for GridFunction::GetGradients() and
|
||||
GriFunction::GetVectorGradient() on face-neighbor elements.
|
||||
|
||||
- Added WhiteGaussianNoiseDomainLFIntegrator: a LinearFormIntegrator class for
|
||||
spatial Gaussian white noise.
|
||||
@@ -129,25 +40,8 @@ Discretization improvements
|
||||
- Added a new Zienkiewicz-Zhu patch recovery-based a posteriori error estimator.
|
||||
See fem/estimators.hpp.
|
||||
|
||||
- Various fixes and improvements in LinearFormExtension.
|
||||
|
||||
Linear and nonlinear solvers
|
||||
----------------------------
|
||||
- Added a new class DGMassInverse that performs a local element-wise CG
|
||||
iteration to solve systems involving the discontinuous Galerkin mass matrix,
|
||||
including support for device/GPU acceleration.
|
||||
|
||||
- Added more flexibility to the constrained solver classes:
|
||||
* PenaltyConstrainedSolver now allows for a vector of penalty parameters
|
||||
(necessary for penalty contact)
|
||||
* PenaltyConstrainedSolver and EliminationSolver can use GMRES or PCG
|
||||
* All constraint solver classes can take a user-defined preconditioner
|
||||
|
||||
- Added functions to toggle additional options for the SuperLU_Dist and Hypre
|
||||
preconditioners (ParaSails, Euclid, ILU).
|
||||
|
||||
- Added boundary elimination with device support for `SparseMatrix` and
|
||||
`HypreParMatrix`.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
@@ -157,28 +51,12 @@ New and updated examples and miniapps
|
||||
automatic differentiation tools like a native dual number implementation or a
|
||||
third party library such as Enzyme. See miniapps/elasticity for more details.
|
||||
|
||||
- Added example for body-fitted volumetric and shape integration using the
|
||||
Algoim library in miniapps/shifted.
|
||||
|
||||
- Add a new example code, Example 33/33p, to demonstrate the solution of
|
||||
spectral fractional PDEs with MFEM.
|
||||
|
||||
Integrations, testing and documentation
|
||||
---------------------------------------
|
||||
- Added a Dockerfile for a simple MFEM container, see config/docker/README.md.
|
||||
More sophisticated developer containers are available in the new repo
|
||||
https://github.com/mfem/containers.
|
||||
|
||||
- Added support for the LLVM-based automatic differentiation tool Enzyme, see
|
||||
https://github.com/EnzymeAD/Enzyme. Build system flags and a convenience
|
||||
header are provided. The functionality and interaction are demonstrated in a
|
||||
new miniapp in miniapps/elasticity.
|
||||
|
||||
- Added support for partial assembly and fully matrix-free operators on mixed
|
||||
meshes (different element types and p-adaptivity) through libCEED, including
|
||||
device acceleration, e.g. with NVIDIA and AMD GPUs. The p-adaptivity is
|
||||
currently limited to 2D serial meshes. All mixed element topologies are
|
||||
supported in both serial and parallel.
|
||||
|
||||
- Added support for ParMoonolith, https://bitbucket.org/zulianp/par_moonolith,
|
||||
which provides parallel non-conforming, non-matching, variational, volumetric
|
||||
@@ -186,40 +64,29 @@ Integrations, testing and documentation
|
||||
between arbitrarily distributed and unrelated finite element meshes in a
|
||||
variationally consistent way.
|
||||
|
||||
- Fully encapsulated SUNDIALS `N_Vector` object within the `SundialsNVector`
|
||||
class by removing deprecated (e.g. `HypreParVector::ToNVector`) and
|
||||
non-deprecated (e.g. `Vector::ToNVector`) functions in other classes.
|
||||
- Added support for the LLVM-based automatic differentiation tool Enzyme, see
|
||||
https://github.com/EnzymeAD/Enzyme. Build system flags and a convenience
|
||||
header are provided. The functionality and interaction are demonstrated in a
|
||||
new miniapp in miniapps/elasticity.
|
||||
|
||||
- New benchmark for the different assembly levels inspired by the CEED
|
||||
Bake-Off Problems, see tests/benchmarks/bench_assembly_levels.cpp.
|
||||
- Added example for body-fitted volumetric and shape integration using the
|
||||
Algoim library.
|
||||
|
||||
- Added Windows 2022 CI testing with GitHub actions.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- The method SparseMatrix::EnsureMultTranspose() is now automatically called
|
||||
by the methods AddMultTranspose(), MultTranspose(), and AbsMultTranspose().
|
||||
Added a method with the same name to class HypreParMatrix which is also called
|
||||
automatically by the HypreParMatrix::MultTranspose() methods.
|
||||
- Various other simplifications, extensions, and bugfixes in the code.
|
||||
|
||||
- Updated various MemoryUsage methods to return 'std::size_t' instead of 'long'
|
||||
since the latter is 32-bit in Win64 builds.
|
||||
|
||||
- Added boundary elimination with device support for `SparseMatrix` and
|
||||
`HypreParMatrix`.
|
||||
|
||||
- When using `AssemblyLevel::FULL`, `FABilinearFormExtension::FormSystemMatrix`
|
||||
outputs an `OperatorHandle` containing a `SparseMatrix` in serial, and an
|
||||
`HypreParMatrix` in parallel (instead of a `ConstrainedOperator`).
|
||||
|
||||
- In various places in the library, replace the use of 'long' with 'long long'
|
||||
to better support Win64 builds where 'long' is 32-bit and 'long long' is
|
||||
64-bit. On Linux and MacOS, both types are typically 64-bit.
|
||||
|
||||
- The behavior of GridFunction::GetTrueVector() has been changed to not return
|
||||
an empty true vector.
|
||||
|
||||
- Added support for ordering search points byVDIM in FindPointsGSLIB.
|
||||
|
||||
- Various other simplifications, extensions, and bugfixes in the code.
|
||||
|
||||
- Added TMOP metrics for mesh untangling and worst-case quality improvement.
|
||||
|
||||
Version 4.4, released on March 21, 2022
|
||||
=======================================
|
||||
@@ -252,6 +119,11 @@ Meshing improvements
|
||||
- Added a simpler interface to access mesh face information, see FaceInformation
|
||||
and GetFaceInformation in the Mesh class.
|
||||
|
||||
- Added the method ParMesh::GetSerialMesh() that reconstructs a partitioned
|
||||
parallel mesh on a given single rank. Also, added the method
|
||||
ParMesh::PrintAsSerial() that saves the reconstructed serial mesh to a C++
|
||||
stream on rank 0.
|
||||
|
||||
- Gmsh meshes where all elements have zero physical tag (the default Gmsh output
|
||||
format if no physical groups are defined) are now successfully loaded, and
|
||||
elements are reassigned attribute number 1.
|
||||
@@ -341,6 +213,9 @@ Integrations, testing and documentation
|
||||
- Switched from Artistic Style (astyle) version 2.05.1 to version 3.1 for code
|
||||
formatting. See the "make style" target.
|
||||
|
||||
- New benchmark for the different assembly levels inspired by the CEED
|
||||
Bake-Off Problems, see tests/benchmarks/bench_assembly_levels.cpp.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- Added a simple singleton class, Mpi, as a replacement for MPI_Session. New
|
||||
@@ -351,6 +226,13 @@ Miscellaneous
|
||||
|
||||
- Fixed several MinGW build issues on Windows.
|
||||
|
||||
- In various places in the library, replace the use of 'long' with 'long long'
|
||||
to better support Win64 builds where 'long' is 32-bit and 'long long' is
|
||||
64-bit. On Linux and MacOS, both types are typically 64-bit.
|
||||
|
||||
- Update various "MemoryUsage" methods to return 'std::size_t' instead of 'long'
|
||||
since the latter is 32-bit in Win64 builds.
|
||||
|
||||
- Added 'double' atomicAdd implementation for previous versions of CUDA.
|
||||
|
||||
- HypreParVector and Vector now support C++ move semantics, and the copy
|
||||
|
||||
+52
-86
@@ -10,10 +10,7 @@
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# The variable CMAKE_CXX_STANDARD and related were introduced in CMake v3.1
|
||||
# Version 3.8 fixes the handling of CMAKE_CXX_STANDARD for try_compile.
|
||||
# Version 3.8 or newer is required for direct CUDA support.
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
message(STATUS "CMake version: ${CMAKE_VERSION}")
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
set(USER_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/config/user.cmake" CACHE PATH
|
||||
"Path to optional user configuration file.")
|
||||
|
||||
@@ -25,11 +22,8 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
# Load user settings before the defaults - this way the defaults will not
|
||||
# overwrite the user set options. If the user has not set all options, we still
|
||||
# have the defaults.
|
||||
include("${USER_CONFIG}" OPTIONAL RESULT_VARIABLE USER_CONFIG_LOADED)
|
||||
if (USER_CONFIG_LOADED)
|
||||
set(USER_CONFIG_LOADED "LOADED")
|
||||
endif()
|
||||
message(STATUS "Loading USER_CONFIG = ${USER_CONFIG} (${USER_CONFIG_LOADED})")
|
||||
message(STATUS "(optional) USER_CONFIG = ${USER_CONFIG}")
|
||||
include("${USER_CONFIG}" OPTIONAL)
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/config/defaults.cmake")
|
||||
|
||||
# Allow overwriting of the compiler by setting CXX/MPICXX on the command line or
|
||||
@@ -57,7 +51,7 @@ project(mfem NONE)
|
||||
# Current version of MFEM, see also `makefile`.
|
||||
# mfem_VERSION = (string)
|
||||
# MFEM_VERSION = (int) [automatically derived from mfem_VERSION]
|
||||
set(${PROJECT_NAME}_VERSION 4.5.1)
|
||||
set(${PROJECT_NAME}_VERSION 4.4.1)
|
||||
|
||||
# Prohibit in-source build
|
||||
if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR})
|
||||
@@ -72,7 +66,8 @@ set(XSDK_ENABLE_C OFF)
|
||||
set(XSDK_ENABLE_Fortran OFF)
|
||||
|
||||
# Check if we need to enable C or Fortran.
|
||||
if (MFEM_USE_CONDUIT OR
|
||||
if (CMAKE_VERSION VERSION_LESS 3.2 OR
|
||||
MFEM_USE_CONDUIT OR
|
||||
MFEM_USE_SIDRE OR
|
||||
MFEM_USE_PETSC)
|
||||
# This seems to be needed by:
|
||||
@@ -86,13 +81,7 @@ if (MFEM_USE_STRUMPACK)
|
||||
# Just needed to find the MPI_Fortran libraries to link with
|
||||
set(XSDK_ENABLE_Fortran ON)
|
||||
endif()
|
||||
# SUNDIALS, STRUMPACK, Ginkgo, RAJA and Umpire require C++14:
|
||||
if ((MFEM_USE_SUNDIALS OR
|
||||
MFEM_USE_STRUMPACK OR
|
||||
MFEM_USE_GINKGO OR
|
||||
MFEM_USE_RAJA OR
|
||||
MFEM_USE_UMPIRE) AND
|
||||
("${CMAKE_CXX_STANDARD}" LESS "14"))
|
||||
if (MFEM_USE_GINKGO AND ("${CMAKE_CXX_STANDARD}" LESS "14"))
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
|
||||
@@ -110,12 +99,17 @@ if (MFEM_USE_CUDA)
|
||||
if (MFEM_USE_HIP)
|
||||
message(FATAL_ERROR " *** MFEM_USE_HIP cannot be combined with MFEM_USE_CUDA.")
|
||||
endif()
|
||||
# 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 ${CMAKE_CXX_STANDARD})
|
||||
set(CMAKE_CUDA_STANDARD 11)
|
||||
if (MFEM_USE_GINKGO)
|
||||
set(CMAKE_CUDA_STANDARD 14)
|
||||
endif()
|
||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CUDA_EXTENSIONS OFF)
|
||||
set(CUDA_FLAGS "--expt-extended-lambda")
|
||||
@@ -138,11 +132,12 @@ if (MFEM_USE_CUDA)
|
||||
set(CUDA_FLAGS "-ccbin=${CMAKE_CXX_COMPILER} ${CUDA_FLAGS}")
|
||||
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
set(CMAKE_CUDA_FLAGS ${CMAKE_CUDA_FLAGS} ${CUDA_FLAGS})
|
||||
set(CMAKE_CUDA_FLAGS "${CUDA_FLAGS}" CACHE STRING
|
||||
"CUDA flags set for MFEM" FORCE)
|
||||
set(CUSPARSE_FOUND TRUE)
|
||||
set(CUSPARSE_LIBRARIES "cusparse")
|
||||
set(CUBLAS_FOUND TRUE)
|
||||
set(CUBLAS_LIBRARIES "cublas")
|
||||
set(CUSBLAS_LIBRARIES "cublas")
|
||||
endif()
|
||||
|
||||
if (XSDK_ENABLE_C)
|
||||
@@ -187,23 +182,6 @@ else()
|
||||
set(MFEM_DEBUG OFF)
|
||||
endif()
|
||||
|
||||
# Shared build on Windows
|
||||
if (WIN32 AND BUILD_SHARED_LIBS)
|
||||
# CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS works only with MSVC?
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON CACHE BOOL
|
||||
"Automatically export symbols for shared Windows DLL build")
|
||||
# Place all .dll and .exe files in the same sub-directory, 'bin/<config>', of
|
||||
# the build directory, so that the .exe files can find the .dll files at
|
||||
# runtime:
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
# Note: CMake tests are run from the build-tree sub-directory where the test
|
||||
# is defined, e.g. <build-dir>/tests/unit, so hard coded paths to meshes still
|
||||
# work fine.
|
||||
# Not strictly necessary:
|
||||
# set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
||||
# set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
||||
endif()
|
||||
|
||||
# AMD HIP
|
||||
if (MFEM_USE_HIP)
|
||||
if (HIP_ARCH)
|
||||
@@ -217,35 +195,15 @@ if (MFEM_USE_HIP)
|
||||
find_package(HIPSPARSE REQUIRED)
|
||||
endif()
|
||||
|
||||
# OpenMP
|
||||
if (MFEM_USE_OPENMP OR MFEM_USE_LEGACY_OPENMP)
|
||||
if (NOT MFEM_THREAD_SAFE AND MFEM_USE_LEGACY_OPENMP)
|
||||
message(FATAL_ERROR " *** MFEM_USE_LEGACY_OPENMP requires MFEM_THREAD_SAFE=ON.")
|
||||
endif()
|
||||
find_package(OpenMP REQUIRED)
|
||||
set(OPENMP_LIBRARIES ${OpenMP_CXX_LIBRARIES})
|
||||
if(APPLE)
|
||||
# On macOS, the compiler needs additional help to find the <omp.h> header.
|
||||
# See issue #2642 for more information.
|
||||
set(OPENMP_INCLUDE_DIRS ${OpenMP_CXX_INCLUDE_DIRS})
|
||||
endif(APPLE)
|
||||
if (OPENMP_FOUND)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
|
||||
if (MFEM_USE_CUDA)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler=${OpenMP_CXX_FLAGS}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# MPI -> hypre; PETSc (optional)
|
||||
if (MFEM_USE_MPI)
|
||||
find_package(MPI REQUIRED)
|
||||
set(MPI_CXX_INCLUDE_DIRS ${MPI_CXX_INCLUDE_PATH})
|
||||
if (MFEM_MPIEXEC)
|
||||
string(REPLACE " " ";" MPIEXEC ${MFEM_MPIEXEC})
|
||||
set(MPIEXEC ${MFEM_MPIEXEC})
|
||||
endif()
|
||||
if (MFEM_MPIEXEC_NP)
|
||||
string(REPLACE " " ";" MPIEXEC_NUMPROC_FLAG ${MFEM_MPIEXEC_NP})
|
||||
set(MPIEXEC_NUMPROC_FLAG ${MFEM_MPIEXEC_NP})
|
||||
endif()
|
||||
# Parallel MFEM depends on hypre
|
||||
find_package(HYPRE REQUIRED)
|
||||
@@ -302,6 +260,20 @@ if (MFEM_USE_LAPACK)
|
||||
find_package(LAPACK REQUIRED)
|
||||
endif()
|
||||
|
||||
# OpenMP
|
||||
if (MFEM_USE_OPENMP OR MFEM_USE_LEGACY_OPENMP)
|
||||
if (NOT MFEM_THREAD_SAFE AND MFEM_USE_LEGACY_OPENMP)
|
||||
message(FATAL_ERROR " *** MFEM_USE_LEGACY_OPENMP requires MFEM_THREAD_SAFE=ON.")
|
||||
endif()
|
||||
find_package(OpenMP REQUIRED)
|
||||
set(OPENMP_LIBRARIES ${OpenMP_CXX_LIBRARIES})
|
||||
if(APPLE)
|
||||
# On macOS, the compiler needs additional help to find the <omp.h> header.
|
||||
# See issue #2642 for more information.
|
||||
set(OPENMP_INCLUDE_DIRS ${OpenMP_CXX_INCLUDE_DIRS})
|
||||
endif(APPLE)
|
||||
endif()
|
||||
|
||||
# SuiteSparse (before SUNDIALS which may depend on KLU)
|
||||
if (MFEM_USE_SUITESPARSE)
|
||||
find_package(SuiteSparse REQUIRED
|
||||
@@ -320,6 +292,11 @@ if (MFEM_USE_SUNDIALS)
|
||||
find_package(SUNDIALS REQUIRED ${SUNDIALS_COMPONENTS})
|
||||
endif()
|
||||
|
||||
# Mesquite
|
||||
if (MFEM_USE_MESQUITE)
|
||||
find_package(Mesquite REQUIRED)
|
||||
endif()
|
||||
|
||||
# SuperLU_DIST can only be enabled in parallel
|
||||
if (MFEM_USE_SUPERLU)
|
||||
if (MFEM_USE_MPI)
|
||||
@@ -500,26 +477,13 @@ if (NOT DEFINED MFEM_TIMER_TYPE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Without this, CMake 3.21.1 (and 3.20.2) run into CMake Errors like the following:
|
||||
# CMake Error at config/cmake/modules/MfemCmakeUtilities.cmake:60 (add_library):
|
||||
# Target "mfem" links to target "Threads::Threads" but the target was not
|
||||
# found. Perhaps a find_package() call is missing for an IMPORTED target, or
|
||||
# an ALIAS target is missing?
|
||||
# Call Stack (most recent call first):
|
||||
# CMakeLists.txt:474 (mfem_add_library)
|
||||
#
|
||||
# NOTE: We need to figure out which TPL library adds the dependency on
|
||||
# "Threads::Threads" and call the next line only when that TPL library is
|
||||
# enabled. -V. Dobrev
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# List all possible libraries in order of dependencies.
|
||||
# [METIS < SuiteSparse]:
|
||||
# With newer versions of SuiteSparse which include METIS header using 64-bit
|
||||
# integers, the METIS header (with 32-bit indices, as used by mfem) needs to
|
||||
# be before SuiteSparse.
|
||||
set(MFEM_TPLS OPENMP HYPRE LAPACK BLAS SuperLUDist STRUMPACK METIS SuiteSparse
|
||||
SUNDIALS PETSC SLEPC MUMPS AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB
|
||||
set(MFEM_TPLS OPENMP HYPRE BLAS LAPACK SuperLUDist METIS SuiteSparse SUNDIALS
|
||||
PETSC SLEPC MESQUITE MUMPS STRUMPACK AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB
|
||||
NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
|
||||
ADIOS2 CUBLAS CUSPARSE MKL_CPARDISO AMGX CALIPER CODIPACK BENCHMARK PARELAG
|
||||
MPI_CXX HIP HIPSPARSE MOONOLITH BLITZ ALGOIM ENZYME)
|
||||
@@ -534,13 +498,18 @@ foreach(TPL IN LISTS MFEM_TPLS)
|
||||
list(APPEND TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIRS})
|
||||
endif()
|
||||
endforeach(TPL)
|
||||
list(REVERSE TPL_LIBRARIES)
|
||||
list(REMOVE_DUPLICATES TPL_LIBRARIES)
|
||||
list(REVERSE TPL_LIBRARIES)
|
||||
list(REMOVE_DUPLICATES TPL_INCLUDE_DIRS)
|
||||
# message(STATUS "TPL_INCLUDE_DIRS = ${TPL_INCLUDE_DIRS}")
|
||||
|
||||
message(STATUS "MFEM shared library: BUILD_SHARED_LIBS = ${BUILD_SHARED_LIBS}")
|
||||
if (OPENMP_FOUND)
|
||||
message(STATUS "MFEM: using package OpenMP")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
|
||||
if (MFEM_USE_CUDA)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler=${OpenMP_CXX_FLAGS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "MFEM build type: CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
|
||||
message(STATUS "MFEM version: v${MFEM_VERSION_STRING}")
|
||||
message(STATUS "MFEM git string: ${MFEM_GIT_STRING}")
|
||||
@@ -608,7 +577,6 @@ if (NOT ("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}"))
|
||||
endif()
|
||||
|
||||
# Generate configuration file in the build directory: config/_config.hpp.
|
||||
set(MFEM_SHARED_BUILD ${BUILD_SHARED_LIBS})
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/config/cmake/config.hpp.in"
|
||||
"${PROJECT_BINARY_DIR}/config/_config.hpp")
|
||||
@@ -720,8 +688,6 @@ add_subdirectory(doc)
|
||||
message(STATUS "CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}")
|
||||
set(INSTALL_INCLUDE_DIR include
|
||||
CACHE PATH "Relative path for installing header files.")
|
||||
set(INSTALL_BIN_DIR bin
|
||||
CACHE PATH "Relative path for installing the binaries.")
|
||||
set(INSTALL_LIB_DIR lib
|
||||
CACHE PATH "Relative path for installing the library.")
|
||||
# other options: "share/mfem/cmake", "lib/mfem/cmake"
|
||||
@@ -740,9 +706,7 @@ set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Development)
|
||||
# Install the library
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME_UC}Targets
|
||||
RUNTIME DESTINATION ${INSTALL_BIN_DIR}
|
||||
LIBRARY DESTINATION ${INSTALL_LIB_DIR}
|
||||
ARCHIVE DESTINATION ${INSTALL_LIB_DIR})
|
||||
DESTINATION ${INSTALL_LIB_DIR})
|
||||
|
||||
# Install the master headers
|
||||
foreach(Header mfem.hpp mfem-performance.hpp)
|
||||
@@ -780,8 +744,10 @@ endif()
|
||||
|
||||
# Install the configuration header files
|
||||
install(FILES ${PROJECT_BINARY_DIR}/config/_config.hpp
|
||||
${PROJECT_SOURCE_DIR}/config/config.hpp
|
||||
${PROJECT_SOURCE_DIR}/config/tconfig.hpp
|
||||
DESTINATION ${INSTALL_INCLUDE_DIR}/mfem/config
|
||||
RENAME config.hpp)
|
||||
|
||||
install(FILES ${PROJECT_SOURCE_DIR}/config/tconfig.hpp
|
||||
DESTINATION ${INSTALL_INCLUDE_DIR}/mfem/config)
|
||||
|
||||
# Package the whole thing up nicely
|
||||
|
||||
+2
-8
@@ -102,9 +102,7 @@ The MFEM source code has the following structure:
|
||||
.
|
||||
├── config
|
||||
│ ├── cmake
|
||||
│ ├── docker
|
||||
│ ├── githooks
|
||||
│ └── vcpkg
|
||||
│ └── githooks
|
||||
├── data
|
||||
├── doc
|
||||
├── examples
|
||||
@@ -113,7 +111,6 @@ The MFEM source code has the following structure:
|
||||
│ ├── ginkgo
|
||||
│ ├── hiop
|
||||
│ ├── jupyter
|
||||
│ ├── moonolith
|
||||
│ ├── petsc
|
||||
│ ├── pumi
|
||||
│ ├── sundials
|
||||
@@ -121,15 +118,13 @@ The MFEM source code has the following structure:
|
||||
├── fem
|
||||
│ ├── ceed
|
||||
│ ├── fe
|
||||
│ ├── lor
|
||||
│ ├── moonolith
|
||||
│ ├── qinterp
|
||||
│ ├── moonolith
|
||||
│ └── tmop
|
||||
├── general
|
||||
├── linalg
|
||||
│ └── simd
|
||||
├── mesh
|
||||
│ └── submesh
|
||||
├── miniapps
|
||||
│ ├── adjoint
|
||||
│ ├── autodiff
|
||||
@@ -139,7 +134,6 @@ The MFEM source code has the following structure:
|
||||
│ ├── hooke
|
||||
│ ├── meshing
|
||||
│ ├── mtop
|
||||
│ ├── multidomain
|
||||
│ ├── navier
|
||||
│ ├── nurbs
|
||||
│ ├── parelag
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
|
||||
https://mfem.org
|
||||
|
||||
This file provides a detailed description of how to build and install the MFEM
|
||||
library. For a simple build, see the step-by-step instructions on the website
|
||||
at https://mfem.org/building.
|
||||
|
||||
The MFEM library has a serial and an MPI-based parallel version, which largely
|
||||
share the same code base. The only prerequisite for building the serial version
|
||||
of MFEM is a (modern) C++ compiler, such as g++. The parallel version of MFEM
|
||||
@@ -20,11 +16,7 @@ requires an MPI C++ compiler, as well as the following external libraries:
|
||||
https://github.com/hypre-space/hypre
|
||||
|
||||
- METIS (a family of multilevel partitioning algorithms)
|
||||
https://github.com/mfem/tpls
|
||||
|
||||
Note: We recommend our mirror of metis-4.0.3/5.1.0 above because the METIS
|
||||
webpage, http://glaros.dtc.umn.edu/gkhome/metis/metis/overview, is often down
|
||||
and we don't support yet the new repo https://github.com/KarypisLab/METIS.
|
||||
http://glaros.dtc.umn.edu/gkhome/metis/metis/overview
|
||||
|
||||
The hypre dependency can be downloaded as a tarball from GitHub or from the
|
||||
project webpage https://www.llnl.gov/casc/hypre. For example, the 2.24.0 release
|
||||
@@ -337,6 +329,10 @@ MFEM_USE_SUNDIALS = YES/NO
|
||||
library. When enabled, this option uses the SUNDIALS_* library options,
|
||||
see below.
|
||||
|
||||
MFEM_USE_MESQUITE = YES/NO
|
||||
Enable MFEM functionality based on the Mesquite library. When enabled, this
|
||||
option uses the MESQUITE_* library options, see below.
|
||||
|
||||
MFEM_USE_SUITESPARSE = YES/NO
|
||||
Enable MFEM functionality based on the SuiteSparse library. Currently, this
|
||||
option adds the classes UMFPackSolver and KLUSolver (both sparse serial
|
||||
@@ -476,10 +472,10 @@ MFEM_USE_CODIPACK = YES/NO
|
||||
www.scicomp.uni-kl.de/codi/
|
||||
|
||||
MFEM_USE_ALGOIM = YES/NO
|
||||
Enable the usage of Algoim - a collection of high-order accurate numerical
|
||||
methods and C++ algorithms for working with implicitly-defined geometry and
|
||||
level set methods. The Algoim library requires the Blitz++ library. The MFEM
|
||||
provides interface to Algoim v1. Thus, to check out the specific state use:
|
||||
Enable the usage of Algoim - a collection of high-order accurate numerical
|
||||
methods and C++ algorithms for working with implicitly-defined geometry and
|
||||
level set methods. The Algoim library requires the Blitz++ library. The MFEM
|
||||
provides interface to Algoim v1. Thus, to check out the specific state use:
|
||||
git checkout 9c9ca0ef094d8ab0390ed36367a1151b459bbe0a
|
||||
https://algoim.github.io
|
||||
|
||||
@@ -554,7 +550,7 @@ MFEM_USE_FMS = YES/NO
|
||||
Enables support for the FMS library which consists of the DataCollection
|
||||
sub-class mfem::FMSDataCollection for I/O in FMS formats, see the header file
|
||||
fem/fmsdatacollection.hpp. In addition, this option enables in-memory
|
||||
conversion routines between FMS's FmsDataCollection structure and MFEM's
|
||||
convetion routines between FMS's FmsDataCollection structure and MFEM's
|
||||
DataCollection class, see the header file fem/fmsconvert.hpp.
|
||||
|
||||
MFEM_USE_PARELAG = YES/NO
|
||||
@@ -601,7 +597,7 @@ The specific libraries and their options are:
|
||||
|
||||
- METIS, used when MFEM_USE_METIS = YES. If using METIS 5, set
|
||||
MFEM_USE_METIS_5 = YES (default is to use METIS 4).
|
||||
URL: https://github.com/mfem/tpls (MFEM mirror, see above)
|
||||
URL: http://glaros.dtc.umn.edu/gkhome/metis/metis/overview
|
||||
Options: METIS_OPT, METIS_LIB.
|
||||
Versions: METIS 4.0.3 or 5.1.0.
|
||||
|
||||
@@ -632,6 +628,11 @@ The specific libraries and their options are:
|
||||
Options: SUNDIALS_OPT, SUNDIALS_LIB.
|
||||
Versions: SUNDIALS >= 5.0.0, SUNDIALS >= 5.4.0 for CUDA support.
|
||||
|
||||
- Mesquite (optional), used when MFEM_USE_MESQUITE = YES.
|
||||
URL: http://trilinos.org/oldsite/packages/mesquite
|
||||
Options: MESQUITE_OPT, MESQUITE_LIB.
|
||||
The Mesquite support is deprecated and will be removed in the future.
|
||||
|
||||
- SuiteSparse (optional), used when MFEM_USE_SUITESPARSE = YES.
|
||||
URL: http://faculty.cse.tamu.edu/davis/suitesparse.html
|
||||
Options: SUITESPARSE_OPT, SUITESPARSE_LIB.
|
||||
@@ -753,12 +754,12 @@ The specific libraries and their options are:
|
||||
Options: GSLIB_OPT, GSLIB_LIB.
|
||||
Versions: GSLIB >= 1.0.7.
|
||||
|
||||
- ALGOIM (optional), used when MFEM_USE_ALGOIM=YES. The library provides only
|
||||
- ALGOIM (optional), used when MFE_USE_ALGOIM=YES. The library provides only
|
||||
headers so it just needs to be downloaded at the same level as MFEM. Download
|
||||
the specific version we use as:
|
||||
"git clone https://github.com/algoim/algoim.git;
|
||||
git checkout 9c9ca0ef094d8ab0390ed36367a1151b459bbe0a"
|
||||
ALGOIM depends on BLITZ and the library must be built prior to the MFEM build.
|
||||
ALGOIM depends on BLITZ and rhe library must be built prior to the MFEM build.
|
||||
Download v1.0.2, untar it at the same level as MFEM and create a symbolic link:
|
||||
"ln -s blitz-1.0.2 blitz".
|
||||
Build Blitz using CMake as:
|
||||
@@ -793,10 +794,10 @@ The specific libraries and their options are:
|
||||
Versions: libCEED >= 0.10.
|
||||
|
||||
- RAJA (optional), used when MFEM_USE_RAJA = YES.
|
||||
Beginning with MFEM v4.5.1, only RAJA v2022.10.3+ is supported.
|
||||
Beginning with MFEM v4.3, only RAJA v0.14.0+ is supported.
|
||||
URL: https://github.com/LLNL/RAJA
|
||||
Options: RAJA_DIR, RAJA_OPT, RAJA_LIB.
|
||||
Versions: RAJA >= 2022.10.3.
|
||||
Versions: RAJA >= 0.14.0.
|
||||
|
||||
- Moonolith (optional), use when MFEM_USE_MOONOLITH = YES.
|
||||
URL: https://bitbucket.org/zulianp/par_moonolith
|
||||
@@ -960,6 +961,7 @@ MFEM_USE_LEGACY_OPENMP
|
||||
MFEM_USE_OPENMP
|
||||
MFEM_USE_MEMALLOC
|
||||
MFEM_TIMER_TYPE - Set automatically, can be overwritten.
|
||||
MFEM_USE_MESQUITE
|
||||
MFEM_USE_SUITESPARSE
|
||||
MFEM_USE_SUPERLU
|
||||
MFEM_USE_MUMPS
|
||||
@@ -1024,6 +1026,7 @@ The CMake build system adds auto-detection for the following packages/libraries:
|
||||
- HYPRE
|
||||
- METIS - The option MFEM_USE_METIS_5 is auto-detected.
|
||||
- ParMETIS
|
||||
- MESQUITE
|
||||
- SuiteSparse
|
||||
- SuperLUDist, STRUMPACK
|
||||
- Ginkgo
|
||||
|
||||
@@ -212,6 +212,10 @@ IF (DEFINED TPL_ENABLE_SUNDIALS)
|
||||
SET(MFEM_USE_SUNDIALS ${TPL_ENABLE_SUNDIALS} CACHE BOOL "Enable SUNDIALS usage" FORCE)
|
||||
ENDIF()
|
||||
|
||||
IF (DEFINED TPL_ENABLE_MESQUITE)
|
||||
SET(MFEM_USE_MESQUITE ${TPL_ENABLE_MESQUITE} CACHE BOOL "Enable MESQUITE usage" FORCE)
|
||||
ENDIF()
|
||||
|
||||
IF (DEFINED TPL_ENABLE_SUITESPARSE)
|
||||
SET(MFEM_USE_SUITESPARSE ${TPL_ENABLE_SUITESPARSE} CACHE BOOL "Enable SuiteSparse usage" FORCE)
|
||||
ENDIF()
|
||||
|
||||
@@ -29,6 +29,7 @@ set(MFEM_USE_LEGACY_OPENMP @MFEM_USE_LEGACY_OPENMP@)
|
||||
set(MFEM_USE_MEMALLOC @MFEM_USE_MEMALLOC@)
|
||||
set(MFEM_TIMER_TYPE @MFEM_TIMER_TYPE@)
|
||||
set(MFEM_USE_SUNDIALS @MFEM_USE_SUNDIALS@)
|
||||
set(MFEM_USE_MESQUITE @MFEM_USE_MESQUITE@)
|
||||
set(MFEM_USE_SUITESPARSE @MFEM_USE_SUITESPARSE@)
|
||||
set(MFEM_USE_SUPERLU @MFEM_USE_SUPERLU@)
|
||||
set(MFEM_USE_MUMPS @MFEM_USE_MUMPS@)
|
||||
|
||||
@@ -39,9 +39,6 @@
|
||||
// Description of the git commit used to build MFEM.
|
||||
#cmakedefine MFEM_GIT_STRING "@MFEM_GIT_STRING@"
|
||||
|
||||
// Enable shared library build of MFEM.
|
||||
#cmakedefine MFEM_SHARED_BUILD
|
||||
|
||||
// Build the parallel MFEM library.
|
||||
// Requires an MPI compiler, and the libraries HYPRE and METIS.
|
||||
#cmakedefine MFEM_USE_MPI
|
||||
@@ -80,6 +77,9 @@
|
||||
// Internal MFEM option: enable group/batch allocation for some small objects.
|
||||
#cmakedefine MFEM_USE_MEMALLOC
|
||||
|
||||
// Enable MFEM functionality based on the Mesquite library.
|
||||
#cmakedefine MFEM_USE_MESQUITE
|
||||
|
||||
// Enable MFEM functionality based on the SuiteSparse library.
|
||||
#cmakedefine MFEM_USE_SUITESPARSE
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(Algoim ALGOIM ALGOIM_DIR
|
||||
"include;src" "algoim_quad.hpp"
|
||||
"include" "algoim_quad.hpp"
|
||||
"" ""
|
||||
"Paths to headers required by Algoim."
|
||||
"Libraries required by Algoim.")
|
||||
"Paths to headers required by Algoim."
|
||||
"Libraries required by Algoim.")
|
||||
|
||||
@@ -16,22 +16,7 @@
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(Caliper CALIPER CALIPER_DIR
|
||||
"include" "caliper/cali.h"
|
||||
"lib" "caliper"
|
||||
"Paths to headers required by Caliper."
|
||||
"Libraries required by Caliper.")
|
||||
|
||||
# Append adiak path/lib if the user provided ADIAK_DIR
|
||||
if(ADIAK_DIR AND EXISTS ${ADIAK_DIR})
|
||||
find_package(adiak NO_DEFAULT_PATH REQUIRED PATHS ${ADIAK_DIR}/lib/cmake/adiak ${ADIAK_DIR})
|
||||
list(APPEND CALIPER_INCLUDE_DIRS ${adiak_INCLUDE_DIRS})
|
||||
list(APPEND CALIPER_LIBRARIES ${adiak_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# Append gotcha path/lib if the user provided GOTCHA_DIR
|
||||
if(GOTCHA_DIR AND EXISTS ${GOTCHA_DIR})
|
||||
find_package(gotcha NO_DEFAULT_PATH REQUIRED PATHS ${GOTCHA_DIR}/lib/cmake/gotcha ${GOTCHA_DIR})
|
||||
list(APPEND CALIPER_INCLUDE_DIRS ${gotcha_INCLUDE_DIRS})
|
||||
list(APPEND CALIPER_LIBRARIES ${gotcha_LIBRARIES})
|
||||
endif()
|
||||
|
||||
"include" "caliper/cali.h"
|
||||
"lib" "caliper"
|
||||
"Paths to headers required by Caliper."
|
||||
"Libraries required by Caliper.")
|
||||
|
||||
@@ -19,7 +19,7 @@ if(EXISTS "${ENZYME_DIR}/ClangEnzyme-${ENZYME_VERSION}.so")
|
||||
# Set ENZYME_FOUND
|
||||
set(ENZYME_FOUND TRUE CACHE BOOL "ENZYME was found." FORCE)
|
||||
|
||||
# Set CXX flags to accommodate the Enzyme Clang plugin
|
||||
# Set CXX flags to accomodate the Enzyme Clang plugin
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Xclang -load -Xclang ${ENZYME_DIR}/ClangEnzyme-${ENZYME_VERSION}.so -mllvm -enzyme-loose-types=1")
|
||||
set(MFEM_USE_ENZYME YES)
|
||||
else()
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
# Copyright (c) 2010-2022, 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.
|
||||
|
||||
# Defines the following variables:
|
||||
# - HDF5_FOUND - If HDF5 was found
|
||||
# - HDF5_LIBRARIES - The HDF5 libraries
|
||||
# - HDF5_INCLUDE_DIRS - The HDF5 include directories
|
||||
|
||||
# NOTE: Using this FindHDF5.cmake instead of the CMake provided version may lead
|
||||
# to issues with some TPL libraries that depend (or may depend) on HDF5.
|
||||
# For this reason, we should consider removing this file, or at least
|
||||
# making it use the CMake provided version by default and apply the logic
|
||||
# below only when specifically requested by a user. -V. Dobrev
|
||||
|
||||
# First Check for HDF5_DIR
|
||||
if(NOT HDF5_DIR)
|
||||
message(FATAL_ERROR
|
||||
"Could not find HDF5. HDF5 support needs explicit HDF5_DIR")
|
||||
endif()
|
||||
|
||||
if (NOT HDF5_FIND_QUIETLY)
|
||||
message(STATUS "Looking for HDF5 ...")
|
||||
message(STATUS " in HDF5_DIR = ${HDF5_DIR}")
|
||||
endif()
|
||||
|
||||
# Find includes
|
||||
find_path( HDF5_INCLUDE_DIRS hdf5.h
|
||||
PATHS ${HDF5_DIR}/include/
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_ENVIRONMENT_PATH
|
||||
NO_CMAKE_PATH
|
||||
NO_SYSTEM_ENVIRONMENT_PATH
|
||||
NO_CMAKE_SYSTEM_PATH)
|
||||
|
||||
find_library( __HDF5_LIBRARY NAMES hdf5 libhdf5 libhdf5_D libhdf5_debug
|
||||
PATHS ${HDF5_DIR}/lib
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_ENVIRONMENT_PATH
|
||||
NO_CMAKE_PATH
|
||||
NO_SYSTEM_ENVIRONMENT_PATH
|
||||
NO_CMAKE_SYSTEM_PATH)
|
||||
|
||||
find_library( __HDF5_HL_LIBRARY NAMES hdf5_hl libhdf5_hl libhdf5_hl_D libhdf5_hl_debug
|
||||
PATHS ${HDF5_DIR}/lib
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_ENVIRONMENT_PATH
|
||||
NO_CMAKE_PATH
|
||||
NO_SYSTEM_ENVIRONMENT_PATH
|
||||
NO_CMAKE_SYSTEM_PATH)
|
||||
|
||||
set(HDF5_LIBRARIES ${__HDF5_HL_LIBRARY} ${__HDF5_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
# Handle the QUIETLY and REQUIRED arguments and set HDF5_FOUND to TRUE if all
|
||||
# listed variables are TRUE
|
||||
find_package_handle_standard_args(HDF5
|
||||
" *** HDF5 not found. Please set HDF5_DIR."
|
||||
HDF5_LIBRARIES
|
||||
HDF5_INCLUDE_DIRS
|
||||
__HDF5_LIBRARY
|
||||
__HDF5_HL_LIBRARY)
|
||||
@@ -0,0 +1,20 @@
|
||||
# Copyright (c) 2010-2022, 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.
|
||||
|
||||
# Defines the following variables:
|
||||
# - MESQUITE_FOUND
|
||||
# - MESQUITE_LIBRARIES
|
||||
# - MESQUITE_INCLUDE_DIRS
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(Mesquite MESQUITE MESQUITE_DIR
|
||||
"include" "Mesquite_all_headers.hpp" "lib" "mesquite"
|
||||
"Paths to headers required by Mesquite." "Libraries required by Mesquite.")
|
||||
@@ -17,24 +17,18 @@
|
||||
include(MfemCmakeUtilities)
|
||||
|
||||
# FindHDF5.cmake uses HDF5_ROOT, so we "translate" from the MFEM convention
|
||||
# (MFEM's FindHDF5.cmake does not need HDF5_ROOT)
|
||||
# set(HDF5_ROOT ${HDF5_DIR} CACHE PATH "")
|
||||
|
||||
set(HDF5_ROOT ${HDF5_DIR} CACHE PATH "")
|
||||
# We need to guard against the case where HDF5 was already found but without
|
||||
# the HL extensions (in which case mfem_find_package will treat the package
|
||||
# as already having been found), so we reset the variable to force FindHDF5.cmake
|
||||
# to be called for a second time
|
||||
set(HDF5_FOUND OFF)
|
||||
enable_language(C) # FindHDF5.cmake uses the C compiler
|
||||
|
||||
mfem_find_package(NetCDF NETCDF NETCDF_DIR "include" netcdf.h "lib" netcdf
|
||||
"Paths to headers required by NetCDF." "Libraries required by NetCDF.")
|
||||
|
||||
# The HL extension libraries are in a separate variable and must precede
|
||||
# the "regular" hdf5 library, as hdf5_hl depends on hdf5
|
||||
# The netcdf library will always be the first element of NETCDF_LIBRARIES
|
||||
# and we need to insert after that library but before the hdf5 library, so
|
||||
# position 1 is used
|
||||
# (MFEM's FindHDF5.cmake does not set HDF5_C_LIBRARY_hdf5_hl and the HL library
|
||||
# is already added to NETCDF_LIBRARIES)
|
||||
# list(INSERT NETCDF_LIBRARIES 1 ${HDF5_C_LIBRARY_hdf5_hl})
|
||||
list(INSERT NETCDF_LIBRARIES 1 ${HDF5_C_LIBRARY_hdf5_hl})
|
||||
|
||||
@@ -14,27 +14,17 @@
|
||||
# - RAJA_LIBRARIES
|
||||
# - RAJA_INCLUDE_DIRS
|
||||
|
||||
if (RAJA_FOUND)
|
||||
return()
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(RAJA RAJA RAJA_DIR "include" "RAJA/RAJA.hpp" "lib" "RAJA"
|
||||
"Paths to headers required by RAJA." "Libraries required by RAJA.")
|
||||
|
||||
if (NOT RAJA_CONFIG_CMAKE)
|
||||
set(RAJA_CONFIG_CMAKE "${RAJA_DIR}/share/raja/cmake/raja-config.cmake")
|
||||
endif()
|
||||
message(STATUS "Looking for RAJA ...")
|
||||
if (RAJA_DIR)
|
||||
message(STATUS " in RAJA_DIR = ${RAJA_DIR}")
|
||||
find_package(RAJA CONFIG NO_DEFAULT_PATH PATHS "${RAJA_DIR}")
|
||||
endif()
|
||||
if (NOT RAJA_FOUND)
|
||||
message(STATUS " in standard CMake locations")
|
||||
find_package(RAJA CONFIG)
|
||||
endif()
|
||||
if (RAJA_FOUND)
|
||||
set(RAJA_LIBRARIES "RAJA" CACHE STRING "RAJA imported target." FORCE)
|
||||
set(RAJA_INCLUDE_DIRS "" CACHE STRING "RAJA include dirs (not used)" FORCE)
|
||||
message(STATUS
|
||||
"Found RAJA target: ${RAJA_LIBRARIES} (version: ${RAJA_VERSION})")
|
||||
else()
|
||||
set(msg STATUS)
|
||||
if (RAJA_FIND_REQUIRED)
|
||||
set(msg FATAL_ERROR)
|
||||
if (EXISTS "${RAJA_CONFIG_CMAKE}")
|
||||
include("${RAJA_CONFIG_CMAKE}")
|
||||
if (ENABLE_CUDA AND NOT MFEM_USE_CUDA)
|
||||
message(FATAL_ERROR
|
||||
"RAJA is built with CUDA: MFEM_USE_CUDA=YES is required")
|
||||
endif()
|
||||
message(${msg} "RAJA not found. Please set RAJA_DIR to the RAJA prefix.")
|
||||
endif()
|
||||
|
||||
@@ -14,23 +14,6 @@
|
||||
# - UMPIRE_LIBRARIES
|
||||
# - UMPIRE_INCLUDE_DIRS
|
||||
|
||||
if (NOT umpire_DIR AND UMPIRE_DIR)
|
||||
set(umpire_DIR ${UMPIRE_DIR}/lib/cmake/umpire)
|
||||
endif()
|
||||
message(STATUS "Looking for UMPIRE ...")
|
||||
message(STATUS " in UMPIRE_DIR = ${UMPIRE_DIR}")
|
||||
message(STATUS " umpire_DIR = ${umpire_DIR}")
|
||||
find_package(umpire CONFIG)
|
||||
set(UMPIRE_FOUND ${umpire_FOUND})
|
||||
set(UMPIRE_LIBRARIES "umpire")
|
||||
if (UMPIRE_FOUND)
|
||||
message(STATUS
|
||||
"Found UMPIRE target: ${UMPIRE_LIBRARIES} (version: ${umpire_VERSION})")
|
||||
else()
|
||||
set(msg STATUS)
|
||||
if (UMPIRE_FIND_REQUIRED)
|
||||
set(msg FATAL_ERROR)
|
||||
endif()
|
||||
message(${msg}
|
||||
"UMPIRE not found. Please set UMPIRE_DIR to the install prefix.")
|
||||
endif()
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(UMPIRE UMPIRE UMPIRE_DIR "include" "umpire/Umpire.hpp" "lib" "umpire"
|
||||
"Paths to headers required by UMPIRE." "Libraries required by UMPIRE.")
|
||||
|
||||
@@ -43,18 +43,22 @@ function(convert_filenames_to_full_paths NAMES)
|
||||
set(${NAMES} ${tmp_names} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Wrapper for add_executable
|
||||
# Wrapper for add_executable that calls the HIP wrapper if applicable
|
||||
macro(mfem_add_executable NAME)
|
||||
add_executable(${NAME} ${ARGN})
|
||||
if (MFEM_USE_CUDA)
|
||||
set_target_properties(${NAME} PROPERTIES
|
||||
CUDA_RESOLVE_DEVICE_SYMBOLS ON)
|
||||
if (MFEM_USE_HIP)
|
||||
add_executable(${NAME} ${ARGN})
|
||||
else()
|
||||
add_executable(${NAME} ${ARGN})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Wrapper for add_library
|
||||
# Wrapper for add_library that calls the HIP wrapper if applicable
|
||||
macro(mfem_add_library NAME)
|
||||
add_library(${NAME} ${ARGN})
|
||||
if (MFEM_USE_HIP)
|
||||
add_library(${NAME} ${ARGN})
|
||||
else()
|
||||
add_library(${NAME} ${ARGN})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Simple shortcut to add_custom_target() with option to add the target to the
|
||||
@@ -162,12 +166,27 @@ macro(add_mfem_miniapp MFEM_EXE_NAME)
|
||||
|
||||
# Append the additional libraries and options
|
||||
if (LIBRARIES_LIST)
|
||||
target_link_libraries(${MFEM_EXE_NAME} PRIVATE ${LIBRARIES_LIST})
|
||||
if(CMAKE_VERSION VERSION_GREATER 2.8.11)
|
||||
target_link_libraries(${MFEM_EXE_NAME} PRIVATE ${LIBRARIES_LIST})
|
||||
else()
|
||||
target_link_libraries(${MFEM_EXE_NAME} ${LIBRARIES_LIST})
|
||||
endif()
|
||||
endif()
|
||||
if (EXTRA_OPTIONS_LIST)
|
||||
string(REPLACE ";" " " EXTRA_OPTIONS_STRING "${EXTRA_OPTIONS_LIST}")
|
||||
message(STATUS "${MFEM_EXE_NAME}: add flags \"${EXTRA_OPTIONS_STRING}\"")
|
||||
target_compile_options(${MFEM_EXE_NAME} PRIVATE ${EXTRA_OPTIONS_LIST})
|
||||
if(CMAKE_VERSION VERSION_GREATER 2.8.11)
|
||||
target_compile_options(${MFEM_EXE_NAME} PRIVATE ${EXTRA_OPTIONS_LIST})
|
||||
else()
|
||||
get_target_property(THIS_COMPILE_FLAGS ${MFEM_EXE_NAME} COMPILE_FLAGS)
|
||||
if (THIS_COMPILE_FLAGS)
|
||||
set(THIS_COMPILE_FLAGS "${THIS_COMPILE_FLAGS} ${EXTRA_OPTIONS_STRING}")
|
||||
else()
|
||||
set(THIS_COMPILE_FLAGS "${EXTRA_OPTIONS_STRING}")
|
||||
endif()
|
||||
set_target_properties(${MFEM_EXE_NAME}
|
||||
PROPERTIES COMPILE_FLAGS ${THIS_COMPILE_FLAGS})
|
||||
endif()
|
||||
endif()
|
||||
if (EXTRA_DEFINES_LIST)
|
||||
target_compile_definitions(${MFEM_EXE_NAME} PRIVATE ${EXTRA_DEFINES_LIST})
|
||||
@@ -176,15 +195,17 @@ macro(add_mfem_miniapp MFEM_EXE_NAME)
|
||||
# Handle the MPI separately
|
||||
if (MFEM_USE_MPI)
|
||||
# Add MPI_CXX_LIBRARIES, in case this target does not link with mfem.
|
||||
target_link_libraries(${MFEM_EXE_NAME} PRIVATE ${MPI_CXX_LIBRARIES})
|
||||
if(CMAKE_VERSION VERSION_GREATER 2.8.11)
|
||||
target_link_libraries(${MFEM_EXE_NAME} PRIVATE ${MPI_CXX_LIBRARIES})
|
||||
else()
|
||||
target_link_libraries(${MFEM_EXE_NAME} ${MPI_CXX_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if (MPI_CXX_INCLUDE_PATH)
|
||||
target_include_directories(${MFEM_EXE_NAME} PRIVATE ${MPI_CXX_INCLUDE_PATH})
|
||||
endif()
|
||||
if (MPI_CXX_COMPILE_FLAGS)
|
||||
separate_arguments(MPI_CXX_COMPILE_ARGS UNIX_COMMAND
|
||||
"${MPI_CXX_COMPILE_FLAGS}")
|
||||
target_compile_options(${MFEM_EXE_NAME} PRIVATE ${MPI_CXX_COMPILE_ARGS})
|
||||
target_compile_options(${MFEM_EXE_NAME} PRIVATE ${MPI_CXX_COMPILE_FLAGS})
|
||||
endif()
|
||||
|
||||
if (MPI_CXX_LINK_FLAGS)
|
||||
@@ -865,7 +886,7 @@ function(mfem_export_mk_files)
|
||||
set(CONFIG_MK_BOOL_VARS MFEM_USE_MPI MFEM_USE_METIS MFEM_USE_METIS_5
|
||||
MFEM_DEBUG MFEM_USE_EXCEPTIONS MFEM_USE_ZLIB MFEM_USE_LIBUNWIND
|
||||
MFEM_USE_LAPACK MFEM_THREAD_SAFE MFEM_USE_LEGACY_OPENMP MFEM_USE_OPENMP
|
||||
MFEM_USE_MEMALLOC MFEM_USE_SUNDIALS MFEM_USE_SUITESPARSE
|
||||
MFEM_USE_MEMALLOC MFEM_USE_SUNDIALS MFEM_USE_MESQUITE MFEM_USE_SUITESPARSE
|
||||
MFEM_USE_SUPERLU MFEM_USE_SUPERLU5 MFEM_USE_MUMPS MFEM_USE_STRUMPACK
|
||||
MFEM_USE_GINKGO MFEM_USE_AMGX MFEM_USE_GNUTLS MFEM_USE_NETCDF
|
||||
MFEM_USE_PETSC MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_FMS
|
||||
|
||||
+1
-22
@@ -30,31 +30,10 @@
|
||||
#endif
|
||||
|
||||
// Windows specific options
|
||||
#if defined(_WIN32) && !defined(_USE_MATH_DEFINES)
|
||||
#ifdef _WIN32
|
||||
// Macro needed to get defines like M_PI from <cmath>. (Visual Studio C++ only?)
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
// Macro MFEM_EXPORT: this macro is used when declaring exported global
|
||||
// variables and static class variables in public header files, e.g.:
|
||||
// extern MFEM_EXPORT Geometry Geometries;
|
||||
// static MFEM_EXPORT Device device_singleton;
|
||||
// In cases where a class contains multiple static variables, instead of marking
|
||||
// all such variables with MFEM_EXPORT, one can mark the class with MFEM_EXPORT,
|
||||
// e.g.:
|
||||
// class MFEM_EXPORT MemoryManager ...
|
||||
// Note: MFEM's GitHub CI includes a shared MSVC build that will fail if a
|
||||
// variable that needs MFEM_EXPORT does not have it. However, builds with
|
||||
// optional external libraries are not tested and may require separate checks to
|
||||
// determine the necessity of MFEM_EXPORT.
|
||||
#if defined(_MSC_VER) && defined(MFEM_SHARED_BUILD)
|
||||
#ifdef mfem_EXPORTS
|
||||
#define MFEM_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define MFEM_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define MFEM_EXPORT
|
||||
#endif
|
||||
// On Cygwin the option -std=c++11 prevents the definition of M_PI. Defining
|
||||
// the following macro allows us to get M_PI and some needed functions, e.g.
|
||||
// posix_memalign(), strdup(), strerror_r().
|
||||
|
||||
@@ -39,9 +39,6 @@
|
||||
// Description of the git commit used to build MFEM.
|
||||
// #define MFEM_GIT_STRING "@MFEM_GIT_STRING@"
|
||||
|
||||
// Enable shared library build of MFEM.
|
||||
// #define MFEM_SHARED_BUILD
|
||||
|
||||
// Build the parallel MFEM library.
|
||||
// Requires an MPI compiler, and the libraries HYPRE and METIS.
|
||||
// #define MFEM_USE_MPI
|
||||
@@ -88,6 +85,9 @@
|
||||
// Enable MFEM functionality based on the SUNDIALS libraries.
|
||||
// #define MFEM_USE_SUNDIALS
|
||||
|
||||
// Enable MFEM functionality based on the Mesquite library.
|
||||
// #define MFEM_USE_MESQUITE
|
||||
|
||||
// Enable MFEM functionality based on the SuiteSparse library.
|
||||
// #define MFEM_USE_SUITESPARSE
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ MFEM_USE_OPENMP = @MFEM_USE_OPENMP@
|
||||
MFEM_USE_MEMALLOC = @MFEM_USE_MEMALLOC@
|
||||
MFEM_TIMER_TYPE = @MFEM_TIMER_TYPE@
|
||||
MFEM_USE_SUNDIALS = @MFEM_USE_SUNDIALS@
|
||||
MFEM_USE_MESQUITE = @MFEM_USE_MESQUITE@
|
||||
MFEM_USE_SUITESPARSE = @MFEM_USE_SUITESPARSE@
|
||||
MFEM_USE_SUPERLU = @MFEM_USE_SUPERLU@
|
||||
MFEM_USE_SUPERLU5 = @MFEM_USE_SUPERLU5@
|
||||
|
||||
+10
-3
@@ -19,7 +19,6 @@ if (NOT CMAKE_BUILD_TYPE)
|
||||
endif()
|
||||
|
||||
# MFEM options. Set to mimic the default "defaults.mk" file.
|
||||
option(BUILD_SHARED_LIBS "Enable shared library build of MFEM" OFF)
|
||||
option(MFEM_USE_MPI "Enable MPI parallel build" OFF)
|
||||
option(MFEM_USE_METIS "Enable METIS usage" ${MFEM_USE_MPI})
|
||||
option(MFEM_USE_EXCEPTIONS "Enable the use of exceptions" OFF)
|
||||
@@ -31,6 +30,7 @@ option(MFEM_USE_OPENMP "Enable the OpenMP backend" OFF)
|
||||
option(MFEM_USE_LEGACY_OPENMP "Enable legacy OpenMP usage" OFF)
|
||||
option(MFEM_USE_MEMALLOC "Enable the internal MEMALLOC option." ON)
|
||||
option(MFEM_USE_SUNDIALS "Enable SUNDIALS usage" OFF)
|
||||
option(MFEM_USE_MESQUITE "Enable MESQUITE usage" OFF)
|
||||
option(MFEM_USE_SUITESPARSE "Enable SuiteSparse usage" OFF)
|
||||
option(MFEM_USE_SUPERLU "Enable SuperLU_DIST usage" OFF)
|
||||
option(MFEM_USE_SUPERLU5 "Use the old SuperLU_DIST 5.1 version" OFF)
|
||||
@@ -124,6 +124,9 @@ set(SUNDIALS_DIR "${MFEM_DIR}/../sundials-5.0.0/instdir" CACHE PATH
|
||||
# set(SUNDIALS_REQUIRED_PACKAGES "SuiteSparse/KLU/AMD/BTF/COLAMD/config"
|
||||
# CACHE STRING "Additional packages required by SUNDIALS.")
|
||||
|
||||
set(MESQUITE_DIR "${MFEM_DIR}/../mesquite-2.99" CACHE PATH
|
||||
"Path to the Mesquite library.")
|
||||
|
||||
set(SuiteSparse_DIR "${MFEM_DIR}/../SuiteSparse" CACHE PATH
|
||||
"Path to the SuiteSparse library.")
|
||||
set(SuiteSparse_REQUIRED_PACKAGES "BLAS" "METIS"
|
||||
@@ -185,7 +188,6 @@ set(GNUTLS_DIR "" CACHE PATH "Path to the GnuTLS library.")
|
||||
|
||||
set(GSLIB_DIR "" CACHE PATH "Path to the GSLIB library.")
|
||||
|
||||
set(HDF5_DIR "/usr" CACHE PATH "Path to the HDF5 library.")
|
||||
set(NETCDF_DIR "" CACHE PATH "Path to the NetCDF library.")
|
||||
set(NetCDF_REQUIRED_PACKAGES "HDF5/C/HL" CACHE STRING
|
||||
"Additional packages required by NetCDF.")
|
||||
@@ -228,12 +230,17 @@ set(MKL_LIBRARY_DIR "" CACHE STRING "Custom library subdirectory")
|
||||
|
||||
set(OCCA_DIR "${MFEM_DIR}/../occa" CACHE PATH "Path to OCCA")
|
||||
set(RAJA_DIR "${MFEM_DIR}/../raja" CACHE PATH "Path to RAJA")
|
||||
# If RAJA is built with external CAMP:
|
||||
# set(RAJA_REQUIRED_PACKAGES "camp"
|
||||
# CACHE STRING "Packages that RAJA depends on.")
|
||||
# set(camp_DIR "${MFEM_DIR}/../camp/lib/cmake/camp"
|
||||
# CACHE PATH "Path to CAMP CMake files.")
|
||||
set(CEED_DIR "${MFEM_DIR}/../libCEED" CACHE PATH "Path to libCEED")
|
||||
set(UMPIRE_DIR "${MFEM_DIR}/../umpire" CACHE PATH "Path to Umpire")
|
||||
set(CALIPER_DIR "${MFEM_DIR}/../caliper" CACHE PATH "Path to Caliper")
|
||||
set(BLITZ_DIR "${MFEM_DIR}/../blitz" CACHE PATH "Path to Blitz")
|
||||
set(ALGOIM_DIR "${MFEM_DIR}/../algoim" CACHE PATH "Path to Algoim")
|
||||
set(Algoim_REQUIRED_PACKAGES "Blitz" CACHE STRING
|
||||
set(ALGOIM_REQUIRED_PACKAGES "BLITZ" CACHE STRING
|
||||
"Packages that ALGOIM depends on.")
|
||||
|
||||
set(BENCHMARK_DIR "${MFEM_DIR}/../google-benchmark" CACHE PATH
|
||||
|
||||
+16
-36
@@ -131,6 +131,7 @@ MFEM_USE_LEGACY_OPENMP = NO
|
||||
MFEM_USE_MEMALLOC = YES
|
||||
MFEM_TIMER_TYPE = $(if $(NOTMAC),2,4)
|
||||
MFEM_USE_SUNDIALS = NO
|
||||
MFEM_USE_MESQUITE = NO
|
||||
MFEM_USE_SUITESPARSE = NO
|
||||
MFEM_USE_SUPERLU = NO
|
||||
MFEM_USE_SUPERLU5 = NO
|
||||
@@ -178,7 +179,7 @@ ifeq ($(MFEM_USE_MPI)$(MFEM_USE_HIP),YESYES)
|
||||
endif
|
||||
|
||||
# ROCM/HIP directory such that ROCM/HIP libraries like rocsparse and rocrand are
|
||||
# found in $(HIP_DIR)/lib, usually as links. Typically, this directory is of
|
||||
# found in $(HIP_DIR)/lib, usually as links. Typically, this directoory is of
|
||||
# the form /opt/rocm-X.Y.Z which is called ROCM_PATH by hipconfig.
|
||||
ifeq ($(MFEM_USE_HIP),YES)
|
||||
HIP_DIR := $(patsubst %/,%,$(dir $(shell which $(HIP_CXX))))
|
||||
@@ -250,16 +251,12 @@ POSIX_CLOCKS_LIB = -lrt
|
||||
# SUNDIALS library configuration
|
||||
# For sundials_nvecmpiplusx and nvecparallel remember to build with MPI_ENABLE=ON
|
||||
# and modify cmake variables for hypre for sundials
|
||||
SUNDIALS_DIR = @MFEM_DIR@/../sundials-5.0.0/instdir
|
||||
# SUNDIALS >= 6.4.0 requires C++14:
|
||||
ifeq ($(MFEM_USE_SUNDIALS),YES)
|
||||
BASE_FLAGS = -std=c++14
|
||||
endif
|
||||
SUNDIALS_OPT = -I$(SUNDIALS_DIR)/include
|
||||
SUNDIALS_LIB = $(XLINKER)-rpath,$(SUNDIALS_DIR)/lib64\
|
||||
$(XLINKER)-rpath,$(SUNDIALS_DIR)/lib\
|
||||
-L$(SUNDIALS_DIR)/lib64 -L$(SUNDIALS_DIR)/lib\
|
||||
SUNDIALS_DIR = @MFEM_DIR@/../sundials-5.0.0/instdir
|
||||
SUNDIALS_OPT = -I$(SUNDIALS_DIR)/include
|
||||
SUNDIALS_LIBDIR = $(wildcard $(SUNDIALS_DIR)/lib*)
|
||||
SUNDIALS_LIB = $(XLINKER)-rpath,$(SUNDIALS_LIBDIR) -L$(SUNDIALS_LIBDIR)\
|
||||
-lsundials_arkode -lsundials_cvodes -lsundials_nvecserial -lsundials_kinsol
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),YES)
|
||||
SUNDIALS_LIB += -lsundials_nvecparallel -lsundials_nvecmpiplusx
|
||||
endif
|
||||
@@ -269,6 +266,11 @@ endif
|
||||
# If SUNDIALS was built with KLU:
|
||||
# MFEM_USE_SUITESPARSE = YES
|
||||
|
||||
# MESQUITE library configuration
|
||||
MESQUITE_DIR = @MFEM_DIR@/../mesquite-2.99
|
||||
MESQUITE_OPT = -I$(MESQUITE_DIR)/include
|
||||
MESQUITE_LIB = -L$(MESQUITE_DIR)/lib -lmesquite
|
||||
|
||||
# SuiteSparse library configuration
|
||||
LIB_RT = $(if $(NOTMAC),-lrt,)
|
||||
SUITESPARSE_DIR = @MFEM_DIR@/../SuiteSparse
|
||||
@@ -307,7 +309,7 @@ SCALAPACK_LIB = -L$(SCALAPACK_DIR)/lib -lscalapack $(LAPACK_LIB)
|
||||
MPI_FORTRAN_LIB = -lmpifort
|
||||
# OpenMPI:
|
||||
# MPI_FORTRAN_LIB = -lmpi_mpifh
|
||||
# Additional Fortran library:
|
||||
# Additional Fortan library:
|
||||
# MPI_FORTRAN_LIB += -lgfortran
|
||||
|
||||
# MUMPS library configuration
|
||||
@@ -318,9 +320,6 @@ MUMPS_LIB = $(XLINKER)-rpath,$(MUMPS_DIR)/lib -L$(MUMPS_DIR)/lib -ldmumps\
|
||||
|
||||
# STRUMPACK library configuration
|
||||
STRUMPACK_DIR = @MFEM_DIR@/../STRUMPACK-build
|
||||
ifeq ($(MFEM_USE_STRUMPACK),YES)
|
||||
BASE_FLAGS = -std=c++14
|
||||
endif
|
||||
STRUMPACK_OPT = -I$(STRUMPACK_DIR)/include $(SCOTCH_OPT)
|
||||
# If STRUMPACK was build with OpenMP support, the following may be need:
|
||||
# STRUMPACK_OPT += $(OPENMP_OPT)
|
||||
@@ -473,17 +472,7 @@ OCCA_LIB = $(XLINKER)-rpath,$(OCCA_DIR)/lib -L$(OCCA_DIR)/lib -locca
|
||||
# CALIPER library configuration
|
||||
CALIPER_DIR = @MFEM_DIR@/../caliper
|
||||
CALIPER_OPT = -I$(CALIPER_DIR)/include
|
||||
CALIPER_LIB = $(XLINKER)-rpath,$(CALIPER_DIR)/lib64 $(XLINKER)-rpath,$(CALIPER_DIR)/lib -L$(CALIPER_DIR)/lib64 -L$(CALIPER_DIR)/lib -lcaliper
|
||||
|
||||
ifdef ADIAK_DIR
|
||||
CALIPER_OPT += -I$(ADIAK_DIR)/include
|
||||
CALIPER_LIB += $(XLINKER)-rpath,$(ADIAK_DIR)/lib64 $(XLINKER)-rpath,$(ADIAK_DIR)/lib -L$(ADIAK_DIR)/lib64 -L$(ADIAK_DIR)/lib -ladiak
|
||||
endif
|
||||
ifdef GOTCHA_DIR
|
||||
CALIPER_OPT += -I$(GOTCHA_DIR)/include
|
||||
CALIPER_LIB += $(XLINKER)-rpath,$(GOTCHA_DIR)/lib64 $(XLINKER)-rpath,$(GOTCHA_DIR)/lib -L$(GOTCHA_DIR)/lib64 -L$(GOTCHA_DIR)/lib -lgotcha
|
||||
endif
|
||||
|
||||
CALIPER_LIB = $(XLINKER)-rpath,$(CALIPER_DIR)/lib64 -L$(CALIPER_DIR)/lib64 -lcaliper
|
||||
|
||||
# BLITZ library configuration
|
||||
BLITZ_DIR = @MFEM_DIR@/../blitz
|
||||
@@ -506,29 +495,20 @@ CEED_OPT = -I$(CEED_DIR)/include
|
||||
CEED_LIB = $(XLINKER)-rpath,$(CEED_DIR)/lib -L$(CEED_DIR)/lib -lceed
|
||||
|
||||
# RAJA library configuration
|
||||
ifeq ($(MFEM_USE_RAJA),YES)
|
||||
BASE_FLAGS = -std=c++14
|
||||
endif
|
||||
RAJA_DIR = @MFEM_DIR@/../raja
|
||||
RAJA_OPT = -I$(RAJA_DIR)/include
|
||||
ifdef CUB_DIR
|
||||
RAJA_OPT += -I$(CUB_DIR)
|
||||
endif
|
||||
|
||||
CAMP_LIB = -lcamp
|
||||
ifdef CAMP_DIR
|
||||
RAJA_OPT += -I$(CAMP_DIR)/include
|
||||
CAMP_LIB = $(XLINKER)-rpath,$(CAMP_DIR)/lib -L$(CAMP_DIR)/lib -lcamp
|
||||
endif
|
||||
RAJA_LIB = $(XLINKER)-rpath,$(RAJA_DIR)/lib -L$(RAJA_DIR)/lib -lRAJA $(CAMP_LIB)
|
||||
RAJA_LIB = $(XLINKER)-rpath,$(RAJA_DIR)/lib -L$(RAJA_DIR)/lib -lRAJA
|
||||
|
||||
# UMPIRE library configuration
|
||||
ifeq ($(MFEM_USE_UMPIRE),YES)
|
||||
BASE_FLAGS = -std=c++14
|
||||
endif
|
||||
UMPIRE_DIR = @MFEM_DIR@/../umpire
|
||||
UMPIRE_OPT = -I$(UMPIRE_DIR)/include $(if $(CAMP_DIR), -I$(CAMP_DIR)/include)
|
||||
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -lumpire $(CAMP_LIB)
|
||||
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -lumpire
|
||||
|
||||
# MKL CPardiso library configuration
|
||||
MKL_CPARDISO_DIR ?=
|
||||
|
||||
@@ -554,14 +554,15 @@ function go()
|
||||
local cmd_line="${1##+( )}"
|
||||
cmd_line="${cmd_line%%+( )}"
|
||||
shopt -u extglob
|
||||
eval local cmd=(${cmd_line})
|
||||
local res=""
|
||||
echo $sep
|
||||
echo "<${group}>" "${cmd_line}"
|
||||
echo $sep
|
||||
if [ "${timing}" == "yes" ]; then
|
||||
timed_run eval "${cmd_line}"
|
||||
timed_run "${cmd[@]}"
|
||||
else
|
||||
eval "${cmd_line}"
|
||||
"${cmd[@]}"
|
||||
fi
|
||||
if [ "$?" -eq 0 ]; then
|
||||
res="${green} OK ${none}"
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"version-string": "5.1.0",
|
||||
"port-version": 0,
|
||||
"description": "Serial Graph Partitioning and Fill-reducing Matrix Ordering",
|
||||
"homepage": "http://glaros.dtc.umn.edu/gkhome/metis/metis/overview"
|
||||
"homepage": "https://glaros.dtc.umn.edu/gkhome/metis/metis/overview"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
# MFEM Geomety Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = "MFEM"
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = v4.5.1
|
||||
PROJECT_NUMBER = v4.4.1
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
@@ -763,54 +763,36 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
|
||||
@MFEM_SOURCE_DIR@/config \
|
||||
@MFEM_SOURCE_DIR@/general \
|
||||
@MFEM_SOURCE_DIR@/linalg \
|
||||
@MFEM_SOURCE_DIR@/linalg/simd \
|
||||
@MFEM_SOURCE_DIR@/mesh \
|
||||
@MFEM_SOURCE_DIR@/mesh/submesh \
|
||||
@MFEM_SOURCE_DIR@/fem \
|
||||
@MFEM_SOURCE_DIR@/fem/ceed \
|
||||
@MFEM_SOURCE_DIR@/fem/ceed/integrators \
|
||||
@MFEM_SOURCE_DIR@/fem/ceed/integrators/convection \
|
||||
@MFEM_SOURCE_DIR@/fem/ceed/integrators/diffusion \
|
||||
@MFEM_SOURCE_DIR@/fem/ceed/integrators/mass \
|
||||
@MFEM_SOURCE_DIR@/fem/ceed/integrators/nlconvection \
|
||||
@MFEM_SOURCE_DIR@/fem/ceed/interface \
|
||||
@MFEM_SOURCE_DIR@/fem/ceed/solvers \
|
||||
@MFEM_SOURCE_DIR@/fem/moonolith \
|
||||
@MFEM_SOURCE_DIR@/fem/fe \
|
||||
@MFEM_SOURCE_DIR@/fem/lor \
|
||||
@MFEM_SOURCE_DIR@/fem/moonolith \
|
||||
@MFEM_SOURCE_DIR@/fem/qinterp \
|
||||
@MFEM_SOURCE_DIR@/fem/tmop \
|
||||
@MFEM_SOURCE_DIR@/examples \
|
||||
@MFEM_SOURCE_DIR@/examples/amgx \
|
||||
@MFEM_SOURCE_DIR@/examples/caliper \
|
||||
@MFEM_SOURCE_DIR@/examples/amgx \
|
||||
@MFEM_SOURCE_DIR@/examples/ginkgo \
|
||||
@MFEM_SOURCE_DIR@/examples/hiop \
|
||||
@MFEM_SOURCE_DIR@/examples/moonolith \
|
||||
@MFEM_SOURCE_DIR@/examples/hiop \
|
||||
@MFEM_SOURCE_DIR@/examples/petsc \
|
||||
@MFEM_SOURCE_DIR@/examples/pumi \
|
||||
@MFEM_SOURCE_DIR@/examples/sundials \
|
||||
@MFEM_SOURCE_DIR@/examples/superlu \
|
||||
@MFEM_SOURCE_DIR@/miniapps/adjoint \
|
||||
@MFEM_SOURCE_DIR@/miniapps/autodiff \
|
||||
@MFEM_SOURCE_DIR@/miniapps/common \
|
||||
@MFEM_SOURCE_DIR@/miniapps/electromagnetics \
|
||||
@MFEM_SOURCE_DIR@/miniapps/gslib \
|
||||
@MFEM_SOURCE_DIR@/miniapps/hooke \
|
||||
@MFEM_SOURCE_DIR@/miniapps/hooke/kernels \
|
||||
@MFEM_SOURCE_DIR@/miniapps/hooke/materials \
|
||||
@MFEM_SOURCE_DIR@/miniapps/hooke/operators \
|
||||
@MFEM_SOURCE_DIR@/miniapps/hooke/preconditioners \
|
||||
@MFEM_SOURCE_DIR@/miniapps/meshing \
|
||||
@MFEM_SOURCE_DIR@/miniapps/mtop \
|
||||
@MFEM_SOURCE_DIR@/miniapps/multidomain \
|
||||
@MFEM_SOURCE_DIR@/miniapps/autodiff \
|
||||
@MFEM_SOURCE_DIR@/miniapps/navier \
|
||||
@MFEM_SOURCE_DIR@/miniapps/nurbs \
|
||||
@MFEM_SOURCE_DIR@/miniapps/parelag \
|
||||
@MFEM_SOURCE_DIR@/miniapps/performance \
|
||||
@MFEM_SOURCE_DIR@/miniapps/shifted \
|
||||
@MFEM_SOURCE_DIR@/miniapps/solvers \
|
||||
@MFEM_SOURCE_DIR@/miniapps/tools \
|
||||
@MFEM_SOURCE_DIR@/miniapps/toys
|
||||
@MFEM_SOURCE_DIR@/miniapps/toys \
|
||||
@MFEM_SOURCE_DIR@/miniapps/parelag
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
|
||||
@@ -33,13 +33,13 @@ add_mfem_examples(CALIPER_EXE_SRCS ${PREFIX})
|
||||
if (MFEM_ENABLE_TESTING)
|
||||
foreach(SRC_FILE ${CALIPER_EXE_SRCS})
|
||||
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
|
||||
string(REPLACE ".cpp" "" TEST_NAME ${PREFIX}${SRC_FILENAME})
|
||||
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
|
||||
|
||||
set(THIS_TEST_OPTIONS "-no-vis")
|
||||
|
||||
if (NOT (${TEST_NAME} MATCHES ".*p$"))
|
||||
add_test(NAME ${TEST_NAME}_ser
|
||||
COMMAND $<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS})
|
||||
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
|
||||
else()
|
||||
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
|
||||
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
|
||||
|
||||
+2
-9
@@ -30,7 +30,7 @@
|
||||
//
|
||||
// Device sample runs:
|
||||
// ex1 -pa -d cuda
|
||||
// ex1 -fa -d cuda
|
||||
// * ex1 -fa -d cuda
|
||||
// ex1 -pa -d raja-cuda
|
||||
// * ex1 -pa -d raja-hip
|
||||
// ex1 -pa -d occa-cuda
|
||||
@@ -192,14 +192,7 @@ int main(int argc, char *argv[])
|
||||
// domain integrator.
|
||||
BilinearForm a(&fespace);
|
||||
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
if (fa)
|
||||
{
|
||||
a.SetAssemblyLevel(AssemblyLevel::FULL);
|
||||
// Sort the matrix column indices when running on GPU or with OpenMP (i.e.
|
||||
// when Device::IsEnabled() returns true). This makes the results
|
||||
// bit-for-bit deterministic at the cost of somewhat longer run time.
|
||||
a.EnableSparseMatrixSorting(Device::IsEnabled());
|
||||
}
|
||||
if (fa) { a.SetAssemblyLevel(AssemblyLevel::FULL); }
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
|
||||
// 10. Assemble the bilinear form and the corresponding linear system,
|
||||
|
||||
+2
-9
@@ -30,7 +30,7 @@
|
||||
//
|
||||
// Device sample runs:
|
||||
// mpirun -np 4 ex1p -pa -d cuda
|
||||
// mpirun -np 4 ex1p -fa -d cuda
|
||||
// * mpirun -np 4 ex1p -fa -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
|
||||
@@ -219,14 +219,7 @@ int main(int argc, char *argv[])
|
||||
// Diffusion domain integrator.
|
||||
ParBilinearForm a(&fespace);
|
||||
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
if (fa)
|
||||
{
|
||||
a.SetAssemblyLevel(AssemblyLevel::FULL);
|
||||
// Sort the matrix column indices when running on GPU or with OpenMP (i.e.
|
||||
// when Device::IsEnabled() returns true). This makes the results
|
||||
// bit-for-bit deterministic at the cost of somewhat longer run time.
|
||||
a.EnableSparseMatrixSorting(Device::IsEnabled());
|
||||
}
|
||||
if (fa) { a.SetAssemblyLevel(AssemblyLevel::FULL); }
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
|
||||
// 12. Assemble the parallel bilinear form and the corresponding linear
|
||||
|
||||
+1
-1
@@ -469,7 +469,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
Operator *pc_r = nullptr;
|
||||
Operator *pc_i = nullptr;
|
||||
double s = (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0;
|
||||
int s = (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0;
|
||||
if (pa)
|
||||
{
|
||||
// Jacobi Smoother
|
||||
|
||||
+1
-1
@@ -195,7 +195,7 @@ int main(int argc, char *argv[])
|
||||
Array<int> ess_tdof_list(0);
|
||||
if (h1 && pmesh.bdr_attributes.Size())
|
||||
{
|
||||
// For a continuous basis the linear system must be modified to enforce an
|
||||
// For a continuous basis the linear system must be modifed to enforce an
|
||||
// essential (Dirichlet) boundary condition. In the DG case this is not
|
||||
// necessary as the boundary condition will only be enforced weakly.
|
||||
fespace.GetEssentialTrueDofs(dbc_bdr, ess_tdof_list);
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ int main(int argc, char *argv[])
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
int order = 1;
|
||||
int nc_limit = 1;
|
||||
int max_elems = 100*1000;
|
||||
int max_elems = 1e5;
|
||||
double double_max_elems = double(max_elems);
|
||||
bool visualization = true;
|
||||
double osc_threshold = 1e-3;
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 2. Compute the rational expansion coefficients that define the
|
||||
// integer-order PDEs.
|
||||
const int power_of_laplace = (int)floor(alpha);
|
||||
const int power_of_laplace = floor(alpha);
|
||||
double exponent_to_approximate = alpha - power_of_laplace;
|
||||
bool integer_order = false;
|
||||
// Check if alpha is an integer or not.
|
||||
|
||||
@@ -197,6 +197,7 @@ int main(int argc, char *argv[])
|
||||
SparseMatrix &M(mVarf->SpMat());
|
||||
SparseMatrix &B(bVarf->SpMat());
|
||||
B *= -1.;
|
||||
B.EnsureMultTranspose();
|
||||
Bt = new TransposeOperator(&B);
|
||||
|
||||
darcyOp.SetBlock(0,0, &M);
|
||||
|
||||
@@ -187,6 +187,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI and HYPRE.
|
||||
Mpi::Init(argc, argv);
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
|
||||
+6
-10
@@ -248,10 +248,7 @@ int main(int argc, char *argv[])
|
||||
// constraints for non-conforming AMR, static condensation, etc.
|
||||
if (myid == 0) { cout << "matrix ... " << flush; }
|
||||
if (static_cond) { a->EnableStaticCondensation(); }
|
||||
// Here we want to try out block-size aware AMG solver in PETSc.
|
||||
// For that to work properly, we need a fully-compliant block-size
|
||||
// structure and we do not skip zeros when assembling.
|
||||
a->Assemble(use_petsc ? 0 : 1);
|
||||
a->Assemble();
|
||||
|
||||
Vector B, X;
|
||||
if (!use_petsc)
|
||||
@@ -297,14 +294,13 @@ int main(int argc, char *argv[])
|
||||
cout << "done." << endl;
|
||||
cout << "Size of linear system: " << A.M() << endl;
|
||||
}
|
||||
// Tell PETSc the matrix has a block structure
|
||||
A.SetBlockSize(dim);
|
||||
|
||||
// The preconditioner for the PCG solver can be specified in the
|
||||
// PETSc config file
|
||||
PetscPCGSolver *pcg = new PetscPCGSolver(A);
|
||||
|
||||
// The preconditioner for the PCG solver defined below is specified in the
|
||||
// PETSc config file, rc_ex2p, since a Krylov solver in PETSc can also
|
||||
// customize its preconditioner.
|
||||
PetscPreconditioner *prec = NULL;
|
||||
if (use_nonoverlapping) // Specialized BDDC construction
|
||||
if (use_nonoverlapping)
|
||||
{
|
||||
// Compute dofs belonging to the natural boundary
|
||||
Array<int> nat_tdof_list, nat_bdr(pmesh->bdr_attributes.Max());
|
||||
|
||||
@@ -450,7 +450,7 @@ int main(int argc, char *argv[])
|
||||
for (int ti = 0; !done; )
|
||||
{
|
||||
// We cannot match exactly the time history of the Run method
|
||||
// since we are explicitly telling PETSc to use a time step
|
||||
// since we are explictly telling PETSc to use a time step
|
||||
double dt_real = min(dt, t_final - t);
|
||||
ode_solver->Step(*U, t, dt_real);
|
||||
ti++;
|
||||
|
||||
@@ -78,7 +78,6 @@ EX1_ARGS_CUDA := -m ../../data/star.mesh --usepetsc --partial-assembly -
|
||||
EX1_ARGS_CUDAAMG := -m ../../data/star.mesh --usepetsc --device cuda --petscopts rc_ex1p_cudaamg
|
||||
EX2_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p
|
||||
EX2_ARGS_BDDC := -m ../../data/beam-tri.mesh --usepetsc --nonoverlapping --petscopts rc_ex2p_bddc
|
||||
EX2_ARGS_ASM := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p_asm
|
||||
EX3_ARGS := -m ../../data/klein-bottle.mesh -o 2 -f 0.1 --usepetsc --petscopts rc_ex3p_bddc --nonoverlapping
|
||||
EX4_ARGS := -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping
|
||||
EX4_HYB_ARGS := -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping --hybridization
|
||||
@@ -110,7 +109,6 @@ endif
|
||||
ex2p-test-par: ex2p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX2_ARGS))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX2_ARGS_BDDC))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX2_ARGS_ASM))
|
||||
ex3p-test-par: ex3p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX3_ARGS))
|
||||
ex4p-test-par: ex4p
|
||||
|
||||
@@ -14,5 +14,4 @@
|
||||
-mg_levels_esteig_ksp_type cg
|
||||
-mg_levels_esteig_ksp_max_it 10
|
||||
-mg_levels_ksp_chebyshev_esteig 0,0.05,0,1.05
|
||||
-pc_gamg_use_sa_esteig 0
|
||||
-mg_levels_pc_type sor
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
-ksp_converged_reason
|
||||
|
||||
# GAMG is still not used at its best,
|
||||
# since we are not exploiting the RBMs
|
||||
# since we are not exploiting the
|
||||
# block size (Ordering::byVDIM) and the RBMs
|
||||
|
||||
-ksp_view
|
||||
-pc_type gamg
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# Additive Schwarz with Overlap
|
||||
# This is not a good solver for elasticity
|
||||
# These options are here only to describe
|
||||
# the setup of the solver
|
||||
-ksp_converged_reason
|
||||
-ksp_view
|
||||
-ksp_max_it 10
|
||||
-pc_type asm
|
||||
-pc_asm_overlap 1
|
||||
-sub_pc_type icc
|
||||
@@ -210,9 +210,6 @@ void visualize(ostream &os, Mesh *mesh, GridFunction *deformed_nodes,
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 0. Initialize SUNDIALS.
|
||||
Sundials::Init();
|
||||
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../../data/beam-quad.mesh";
|
||||
int ref_levels = 2;
|
||||
|
||||
@@ -215,11 +215,10 @@ void visualize(ostream &os, ParMesh *mesh, ParGridFunction *deformed_nodes,
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI, HYPRE, and SUNDIALS.
|
||||
// 1. Initialize MPI and HYPRE.
|
||||
Mpi::Init(argc, argv);
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
Sundials::Init();
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../../data/beam-quad.mesh";
|
||||
|
||||
@@ -109,9 +109,6 @@ double InitialTemperature(const Vector &x);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 0. Initialize SUNDIALS.
|
||||
Sundials::Init();
|
||||
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../../data/star.mesh";
|
||||
int ref_levels = 2;
|
||||
@@ -293,10 +290,7 @@ int main(int argc, char *argv[])
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 11)
|
||||
{
|
||||
arkode->SetERKTableNum(ARKODE_FEHLBERG_13_7_8);
|
||||
}
|
||||
if (ode_solver_type == 11) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
|
||||
ode_solver = arkode; break;
|
||||
case 12:
|
||||
arkode = new ARKStepSolver(ARKStepSolver::IMPLICIT);
|
||||
|
||||
@@ -101,12 +101,11 @@ double InitialTemperature(const Vector &x);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI, HYPRE, and SUNDIALS.
|
||||
// 1. Initialize MPI and HYPRE.
|
||||
Mpi::Init(argc, argv);
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
Sundials::Init();
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../../data/star.mesh";
|
||||
@@ -328,10 +327,7 @@ int main(int argc, char *argv[])
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 11)
|
||||
{
|
||||
arkode->SetERKTableNum(ARKODE_FEHLBERG_13_7_8);
|
||||
}
|
||||
if (ode_solver_type == 11) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
|
||||
ode_solver = arkode; break;
|
||||
case 12:
|
||||
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::IMPLICIT);
|
||||
|
||||
@@ -140,9 +140,6 @@ public:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 0. Initialize SUNDIALS.
|
||||
Sundials::Init();
|
||||
|
||||
// 1. Parse command-line options.
|
||||
problem = 0;
|
||||
const char *mesh_file = "../../data/periodic-hexagon.mesh";
|
||||
@@ -411,7 +408,7 @@ int main(int argc, char *argv[])
|
||||
arkode->Init(adv);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
arkode->SetERKTableNum(ARKODE_FEHLBERG_13_7_8);
|
||||
arkode->SetERKTableNum(FEHLBERG_13_7_8);
|
||||
ode_solver = arkode; break;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,12 +152,11 @@ public:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI, HYPRE, and SUNDIALS.
|
||||
// 1. Initialize MPI and HYPRE.
|
||||
Mpi::Init(argc, argv);
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
Sundials::Init();
|
||||
|
||||
// 2. Parse command-line options.
|
||||
problem = 0;
|
||||
@@ -488,10 +487,7 @@ int main(int argc, char *argv[])
|
||||
arkode->Init(adv);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 9)
|
||||
{
|
||||
arkode->SetERKTableNum(ARKODE_FEHLBERG_13_7_8);
|
||||
}
|
||||
if (ode_solver_type == 9) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
|
||||
ode_solver = arkode; break;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ add_mfem_examples(SUPERLU_EXAMPLES_SRCS ${PFX} "" test_superlu)
|
||||
if (MFEM_ENABLE_TESTING)
|
||||
# Command line options for the tests.
|
||||
# Example 1: Test SuperLU on the simple Poisson problem
|
||||
set(EX1_COMMON_OPTS -m ../../data/star.mesh)
|
||||
set(EX1_COMMON_OPTS -m ../../data/star.mesh -p 2)
|
||||
set(EX1P_TEST_OPTS ${EX1_COMMON_OPTS})
|
||||
|
||||
# Add the tests: one test per source file.
|
||||
|
||||
@@ -39,7 +39,6 @@ set(SRCS
|
||||
complex_fem.cpp
|
||||
convergence.cpp
|
||||
datacollection.cpp
|
||||
dgmassinv.cpp
|
||||
doftrans.cpp
|
||||
eltrans.cpp
|
||||
estimators.cpp
|
||||
@@ -73,7 +72,6 @@ set(SRCS
|
||||
linearform.cpp
|
||||
linearform_ext.cpp
|
||||
lininteg.cpp
|
||||
lininteg_boundary.cpp
|
||||
lininteg_domain.cpp
|
||||
lininteg_domain_grad.cpp
|
||||
lor/lor.cpp
|
||||
@@ -90,7 +88,6 @@ set(SRCS
|
||||
fespacehierarchy.cpp
|
||||
nonlininteg_vectorconvection.cpp
|
||||
nonlininteg_vectorconvection_mf.cpp
|
||||
qfunction.cpp
|
||||
qinterp/det.cpp
|
||||
qinterp/eval_by_nodes.cpp
|
||||
qinterp/eval_by_vdim.cpp
|
||||
@@ -98,7 +95,6 @@ set(SRCS
|
||||
qinterp/grad_by_vdim.cpp
|
||||
qinterp/grad_phys_by_nodes.cpp
|
||||
qinterp/grad_phys_by_vdim.cpp
|
||||
qspace.cpp
|
||||
quadinterpolator.cpp
|
||||
quadinterpolator_face.cpp
|
||||
restriction.cpp
|
||||
@@ -140,13 +136,10 @@ set(HDRS
|
||||
bilinearform.hpp
|
||||
bilinearform_ext.hpp
|
||||
bilininteg.hpp
|
||||
bilininteg_mass_pa.hpp
|
||||
coefficient.hpp
|
||||
complex_fem.hpp
|
||||
convergence.hpp
|
||||
datacollection.hpp
|
||||
dgmassinv.hpp
|
||||
dgmassinv_kernels.hpp
|
||||
doftrans.hpp
|
||||
eltrans.hpp
|
||||
estimators.hpp
|
||||
@@ -196,11 +189,9 @@ set(HDRS
|
||||
nonlinearform.hpp
|
||||
nonlinearform_ext.hpp
|
||||
nonlininteg.hpp
|
||||
qfunction.hpp
|
||||
qinterp/dispatch.hpp
|
||||
qinterp/eval.hpp
|
||||
qinterp/grad.hpp
|
||||
qspace.hpp
|
||||
quadinterpolator.hpp
|
||||
quadinterpolator_face.hpp
|
||||
restriction.hpp
|
||||
|
||||
@@ -124,7 +124,6 @@ void BilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
|
||||
case AssemblyLevel::LEGACY:
|
||||
break;
|
||||
case AssemblyLevel::FULL:
|
||||
SetDiagonalPolicy( DIAG_ONE ); // Only diagonal policy supported on device
|
||||
ext = new FABilinearFormExtension(this);
|
||||
break;
|
||||
case AssemblyLevel::ELEMENT:
|
||||
@@ -137,7 +136,7 @@ void BilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
|
||||
ext = new MFBilinearFormExtension(this);
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("BilinearForm: unknown assembly level");
|
||||
mfem_error("Unknown assembly level");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -993,7 +992,6 @@ void BilinearForm::EliminateVDofs(const Array<int> &vdofs_,
|
||||
mat_e = new SparseMatrix(height);
|
||||
}
|
||||
|
||||
vdofs_.HostRead();
|
||||
for (int i = 0; i < vdofs_.Size(); i++)
|
||||
{
|
||||
int vdof = vdofs_[i];
|
||||
|
||||
+4
-23
@@ -26,8 +26,7 @@ namespace mfem
|
||||
{
|
||||
|
||||
/** @brief Enumeration defining the assembly level for bilinear and nonlinear
|
||||
form classes derived from Operator. For more details, see
|
||||
https://mfem.org/howto/assembly_levels */
|
||||
form classes derived from Operator. */
|
||||
enum class AssemblyLevel
|
||||
{
|
||||
/// In the case of a BilinearForm LEGACY corresponds to a fully assembled
|
||||
@@ -80,9 +79,6 @@ protected:
|
||||
/** @brief Extension for supporting Full Assembly (FA), Element Assembly (EA),
|
||||
Partial Assembly (PA), or Matrix Free assembly (MF). */
|
||||
BilinearFormExtension *ext;
|
||||
/** Indicates if the sparse matrix is sorted after assembly when using
|
||||
Full Assembly (FA). */
|
||||
bool sort_sparse_matrix = false;
|
||||
|
||||
/** @brief Indicates the Mesh::sequence corresponding to the current state of
|
||||
the BilinearForm. */
|
||||
@@ -181,24 +177,9 @@ public:
|
||||
- AssemblyLevel::ELEMENT
|
||||
- AssemblyLevel::NONE
|
||||
|
||||
If used, this method must be called before assembly. */
|
||||
This method must be called before assembly. */
|
||||
void SetAssemblyLevel(AssemblyLevel assembly_level);
|
||||
|
||||
/** @brief Force the sparse matrix column indices to be sorted when using
|
||||
AssemblyLevel::FULL.
|
||||
|
||||
When assembling on device the assembly algorithm uses atomic operations
|
||||
to insert values in the sparse matrix, which can result in different
|
||||
column index orderings across runs. Calling this method with @a enable_it
|
||||
set to @a true forces a sorting algorithm to be called at the end of the
|
||||
assembly procedure to ensure sorted column indices (and therefore
|
||||
deterministic results).
|
||||
*/
|
||||
void EnableSparseMatrixSorting(bool enable_it)
|
||||
{
|
||||
sort_sparse_matrix = enable_it;
|
||||
}
|
||||
|
||||
/// Returns the assembly level
|
||||
AssemblyLevel GetAssemblyLevel() const { return assembly; }
|
||||
|
||||
@@ -352,7 +333,7 @@ public:
|
||||
|
||||
|
||||
/** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer
|
||||
to it. Used for transferring ownership. */
|
||||
to it. Used for transfering ownership. */
|
||||
SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; }
|
||||
|
||||
/** @brief Returns a const reference to the sparse matrix of eliminated b.c.:
|
||||
@@ -793,7 +774,7 @@ public:
|
||||
SparseMatrix &SpMat() { return *mat; }
|
||||
|
||||
/** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer
|
||||
to it. Used for transferring ownership. */
|
||||
to it. Used for transfering ownership. */
|
||||
SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; }
|
||||
|
||||
/// Adds a domain integrator. Assumes ownership of @a bfi.
|
||||
|
||||
+13
-20
@@ -160,7 +160,7 @@ void MFBilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
intFaceIntegrators[i]->AddMultMF(int_face_X, int_face_Y);
|
||||
}
|
||||
int_face_restrict_lex->AddMultTransposeInPlace(int_face_Y, y);
|
||||
int_face_restrict_lex->AddMultTranspose(int_face_Y, y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ void MFBilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
bdrFaceIntegrators[i]->AddMultMF(bdr_face_X, bdr_face_Y);
|
||||
}
|
||||
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
|
||||
bdr_face_restrict_lex->AddMultTranspose(bdr_face_Y, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,7 +217,7 @@ void MFBilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
|
||||
{
|
||||
intFaceIntegrators[i]->AddMultTransposeMF(int_face_X, int_face_Y);
|
||||
}
|
||||
int_face_restrict_lex->AddMultTransposeInPlace(int_face_Y, y);
|
||||
int_face_restrict_lex->AddMultTranspose(int_face_Y, y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ void MFBilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
|
||||
{
|
||||
bdrFaceIntegrators[i]->AddMultTransposeMF(bdr_face_X, bdr_face_Y);
|
||||
}
|
||||
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
|
||||
bdr_face_restrict_lex->AddMultTranspose(bdr_face_Y, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -418,7 +418,7 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
intFaceIntegrators[i]->AddMultPA(int_face_X, int_face_Y);
|
||||
}
|
||||
int_face_restrict_lex->AddMultTransposeInPlace(int_face_Y, y);
|
||||
int_face_restrict_lex->AddMultTranspose(int_face_Y, y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +434,7 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
bdrFaceIntegrators[i]->AddMultPA(bdr_face_X, bdr_face_Y);
|
||||
}
|
||||
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
|
||||
bdr_face_restrict_lex->AddMultTranspose(bdr_face_Y, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -475,7 +475,7 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
|
||||
{
|
||||
intFaceIntegrators[i]->AddMultTransposePA(int_face_X, int_face_Y);
|
||||
}
|
||||
int_face_restrict_lex->AddMultTransposeInPlace(int_face_Y, y);
|
||||
int_face_restrict_lex->AddMultTranspose(int_face_Y, y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,7 +491,7 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
|
||||
{
|
||||
bdrFaceIntegrators[i]->AddMultTransposePA(bdr_face_X, bdr_face_Y);
|
||||
}
|
||||
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
|
||||
bdr_face_restrict_lex->AddMultTranspose(bdr_face_Y, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -529,7 +529,7 @@ void EABilinearFormExtension::Assemble()
|
||||
}
|
||||
|
||||
faceDofs = trial_fes ->
|
||||
GetTraceElement(0, trial_fes->GetMesh()->GetFaceGeometry(0)) ->
|
||||
GetTraceElement(0, trial_fes->GetMesh()->GetFaceBaseGeometry(0)) ->
|
||||
GetDof();
|
||||
|
||||
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
|
||||
@@ -668,7 +668,7 @@ void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
Y(j, 0, f) += res;
|
||||
});
|
||||
// Apply the Interior Face Restriction transposed
|
||||
int_face_restrict_lex->AddMultTransposeInPlace(int_face_Y, y);
|
||||
int_face_restrict_lex->AddMultTranspose(int_face_Y, y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,7 +699,7 @@ void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
Y(j, f) += res;
|
||||
});
|
||||
// Apply the Boundary Face Restriction transposed
|
||||
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
|
||||
bdr_face_restrict_lex->AddMultTranspose(bdr_face_Y, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -796,7 +796,7 @@ void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
|
||||
Y(j, 0, f) += res;
|
||||
});
|
||||
// Apply the Interior Face Restriction transposed
|
||||
int_face_restrict_lex->AddMultTransposeInPlace(int_face_Y, y);
|
||||
int_face_restrict_lex->AddMultTranspose(int_face_Y, y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -827,7 +827,7 @@ void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
|
||||
Y(j, f) += res;
|
||||
});
|
||||
// Apply the Boundary Face Restriction transposed
|
||||
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
|
||||
bdr_face_restrict_lex->AddMultTranspose(bdr_face_Y, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -955,10 +955,6 @@ void FABilinearFormExtension::Assemble()
|
||||
}
|
||||
a->mat = mat;
|
||||
}
|
||||
if ( a->sort_sparse_matrix )
|
||||
{
|
||||
a->mat->SortColumnIndices();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -979,9 +975,6 @@ void FABilinearFormExtension::RAP(OperatorHandle &A)
|
||||
void FABilinearFormExtension::EliminateBC(const Array<int> &ess_dofs,
|
||||
OperatorHandle &A)
|
||||
{
|
||||
MFEM_VERIFY(a->diag_policy == DiagonalPolicy::DIAG_ONE,
|
||||
"Only DiagonalPolicy::DIAG_ONE supported with"
|
||||
" FABilinearFormExtension.");
|
||||
#ifdef MFEM_USE_MPI
|
||||
if ( dynamic_cast<ParBilinearForm*>(a) )
|
||||
{
|
||||
|
||||
@@ -208,6 +208,10 @@ public:
|
||||
Vector &x, Vector &b,
|
||||
OperatorHandle &A, Vector &X, Vector &B) = 0;
|
||||
|
||||
virtual void AddMult(const Vector &x, Vector &y, const double c=1.0) const = 0;
|
||||
virtual void AddMultTranspose(const Vector &x, Vector &y,
|
||||
const double c=1.0) const = 0;
|
||||
|
||||
virtual void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const = 0;
|
||||
|
||||
virtual void Update() = 0;
|
||||
@@ -283,7 +287,7 @@ public:
|
||||
/// Partial assembly of all internal integrators
|
||||
void Assemble();
|
||||
|
||||
void AddMult(const Vector &x, Vector &y, const double c=1.0) const;
|
||||
void AddMult(const Vector &x, Vector &y, const double c) const;
|
||||
|
||||
void AddMultTranspose(const Vector &x, Vector &y, const double c=1.0) const;
|
||||
|
||||
|
||||
+2
-205
@@ -2003,83 +2003,6 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
}
|
||||
}
|
||||
|
||||
void CurlCurlIntegrator::AssembleElementMatrix2(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
int tr_nd = trial_fe.GetDof();
|
||||
int te_nd = test_fe.GetDof();
|
||||
dim = trial_fe.GetDim();
|
||||
int dimc = trial_fe.GetCurlDim();
|
||||
double w;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector D;
|
||||
DenseMatrix curlshape(tr_nd,dimc), curlshape_dFt(tr_nd,dimc), M;
|
||||
DenseMatrix te_curlshape(te_nd,dimc), te_curlshape_dFt(te_nd,dimc);
|
||||
#else
|
||||
curlshape.SetSize(tr_nd,dimc);
|
||||
curlshape_dFt.SetSize(tr_nd,dimc);
|
||||
te_curlshape.SetSize(te_nd,dimc);
|
||||
te_curlshape_dFt.SetSize(te_nd,dimc);
|
||||
#endif
|
||||
elmat.SetSize(te_nd, tr_nd);
|
||||
|
||||
if (MQ) { M.SetSize(dimc); }
|
||||
if (DQ) { D.SetSize(dimc); }
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order;
|
||||
if (trial_fe.Space() == FunctionSpace::Pk)
|
||||
{
|
||||
order = test_fe.GetOrder() + trial_fe.GetOrder() - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
order = test_fe.GetOrder() + trial_fe.GetOrder() + trial_fe.GetDim() - 1;
|
||||
}
|
||||
ir = &IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
Trans.SetIntPoint(&ip);
|
||||
|
||||
w = ip.weight * Trans.Weight();
|
||||
trial_fe.CalcPhysCurlShape(Trans, curlshape_dFt);
|
||||
test_fe.CalcPhysCurlShape(Trans, te_curlshape_dFt);
|
||||
|
||||
if (MQ)
|
||||
{
|
||||
MQ->Eval(M, Trans, ip);
|
||||
M *= w;
|
||||
Mult(te_curlshape_dFt, M, te_curlshape);
|
||||
AddMultABt(te_curlshape, curlshape_dFt, elmat);
|
||||
}
|
||||
else if (DQ)
|
||||
{
|
||||
DQ->Eval(D, Trans, ip);
|
||||
D *= w;
|
||||
AddMultADBt(te_curlshape_dFt,D,curlshape_dFt,elmat);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Q)
|
||||
{
|
||||
w *= Q->Eval(Trans, ip);
|
||||
}
|
||||
curlshape_dFt *= w;
|
||||
AddMultABt(te_curlshape_dFt, curlshape_dFt, elmat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CurlCurlIntegrator
|
||||
::ComputeElementFlux(const FiniteElement &el, ElementTransformation &Trans,
|
||||
Vector &u, const FiniteElement &fluxelem, Vector &flux,
|
||||
@@ -2317,84 +2240,6 @@ double VectorCurlCurlIntegrator::GetElementEnergy(
|
||||
return 0.5 * energy;
|
||||
}
|
||||
|
||||
void MixedCurlIntegrator::AssembleElementMatrix2(
|
||||
const FiniteElement &trial_fe, const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans, DenseMatrix &elmat)
|
||||
{
|
||||
int dim = trial_fe.GetDim();
|
||||
int trial_dof = trial_fe.GetDof();
|
||||
int test_dof = test_fe.GetDof();
|
||||
int dimc = (dim == 3) ? 3 : 1;
|
||||
|
||||
MFEM_VERIFY(trial_fe.GetMapType() == mfem::FiniteElement::H_CURL ||
|
||||
(dim == 2 && trial_fe.GetMapType() == mfem::FiniteElement::VALUE),
|
||||
"Trial finite element must be either 2D/3D H(Curl) or 2D H1");
|
||||
MFEM_VERIFY(test_fe.GetMapType() == mfem::FiniteElement::VALUE ||
|
||||
test_fe.GetMapType() == mfem::FiniteElement::INTEGRAL,
|
||||
"Test finite element must be in H1/L2");
|
||||
|
||||
bool spaceH1 = (trial_fe.GetMapType() == mfem::FiniteElement::VALUE);
|
||||
|
||||
if (spaceH1)
|
||||
{
|
||||
dshape.SetSize(trial_dof,dim);
|
||||
curlshape.SetSize(trial_dof,dim);
|
||||
dimc = dim;
|
||||
}
|
||||
else
|
||||
{
|
||||
curlshape.SetSize(trial_dof,dimc);
|
||||
elmat_comp.SetSize(test_dof, trial_dof);
|
||||
}
|
||||
elmat.SetSize(dimc * test_dof, trial_dof);
|
||||
shape.SetSize(test_dof);
|
||||
elmat = 0.0;
|
||||
|
||||
double c;
|
||||
Vector d_col;
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderJ();
|
||||
ir = &IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint(&ip);
|
||||
if (spaceH1)
|
||||
{
|
||||
trial_fe.CalcPhysDShape(Trans, dshape);
|
||||
dshape.GradToVectorCurl2D(curlshape);
|
||||
}
|
||||
else
|
||||
{
|
||||
trial_fe.CalcPhysCurlShape(Trans, curlshape);
|
||||
}
|
||||
test_fe.CalcPhysShape(Trans, shape);
|
||||
c = ip.weight*Trans.Weight();
|
||||
if (Q)
|
||||
{
|
||||
c *= Q->Eval(Trans, ip);
|
||||
}
|
||||
shape *= c;
|
||||
|
||||
for (int d = 0; d < dimc; ++d)
|
||||
{
|
||||
double * curldata = &(curlshape.GetData())[d*trial_dof];
|
||||
for (int jj = 0; jj < trial_dof; ++jj)
|
||||
{
|
||||
for (int ii = 0; ii < test_dof; ++ii)
|
||||
{
|
||||
elmat(d * test_dof + ii, jj) += shape(ii) * curldata[jj];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VectorFEMassIntegrator::AssembleElementMatrix(
|
||||
const FiniteElement &el,
|
||||
@@ -2741,54 +2586,6 @@ void DivDivIntegrator::AssembleElementMatrix(
|
||||
}
|
||||
}
|
||||
|
||||
void DivDivIntegrator::AssembleElementMatrix2(
|
||||
const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
int tr_nd = trial_fe.GetDof();
|
||||
int te_nd = test_fe.GetDof();
|
||||
double c;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector divshape(tr_nd);
|
||||
Vector te_divshape(te_nd);
|
||||
#else
|
||||
divshape.SetSize(tr_nd);
|
||||
te_divshape.SetSize(te_nd);
|
||||
#endif
|
||||
elmat.SetSize(te_nd,tr_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = 2 * max(test_fe.GetOrder(),
|
||||
trial_fe.GetOrder()) - 2; // <--- OK for RTk
|
||||
ir = &IntRules.Get(test_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
|
||||
for (int i = 0; i < ir -> GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
trial_fe.CalcDivShape(ip,divshape);
|
||||
test_fe.CalcDivShape(ip,te_divshape);
|
||||
|
||||
Trans.SetIntPoint (&ip);
|
||||
c = ip.weight / Trans.Weight();
|
||||
|
||||
if (Q)
|
||||
{
|
||||
c *= Q -> Eval (Trans, ip);
|
||||
}
|
||||
|
||||
te_divshape *= c;
|
||||
AddMultVWt(te_divshape, divshape, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
void VectorDiffusionIntegrator::AssembleElementMatrix(
|
||||
const FiniteElement &el,
|
||||
@@ -3983,7 +3780,7 @@ void NormalTraceJumpIntegrator::AssembleFaceMatrix(
|
||||
for (i = 0; i < ndof1; i++)
|
||||
for (j = 0; j < face_ndof; j++)
|
||||
{
|
||||
elmat(i, j) += shape1_n(i) * face_shape(j);
|
||||
elmat(i, j) -= shape1_n(i) * face_shape(j);
|
||||
}
|
||||
if (ndof2)
|
||||
{
|
||||
@@ -3991,7 +3788,7 @@ void NormalTraceJumpIntegrator::AssembleFaceMatrix(
|
||||
for (i = 0; i < ndof2; i++)
|
||||
for (j = 0; j < face_ndof; j++)
|
||||
{
|
||||
elmat(ndof1+i, j) -= shape2_n(i) * face_shape(j);
|
||||
elmat(ndof1+i, j) += shape2_n(i) * face_shape(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-49
@@ -215,10 +215,10 @@ public:
|
||||
function by any coefficients describing the
|
||||
integrator.
|
||||
@param[in] ir If passed (the default value is NULL), the implementation
|
||||
of the method will ignore the integration rule provided
|
||||
by the @a fluxelem parameter and, instead, compute the
|
||||
discrete flux at the points specified by the integration
|
||||
rule @a ir.
|
||||
of the method will ignore the integration rule provided
|
||||
by the @a fluxelem parameter and, instead, compute the
|
||||
discrete flux at the points specified by the integration
|
||||
rule @a ir.
|
||||
*/
|
||||
virtual void ComputeElementFlux(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
@@ -2174,7 +2174,6 @@ public:
|
||||
/** Class for local mass matrix assembling a(u,v) := (Q u, v) */
|
||||
class MassIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
friend class DGMassInverse;
|
||||
protected:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector shape, te_shape;
|
||||
@@ -2525,7 +2524,6 @@ private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector D;
|
||||
DenseMatrix curlshape, curlshape_dFt, M;
|
||||
DenseMatrix te_curlshape, te_curlshape_dFt;
|
||||
DenseMatrix vshape, projcurl;
|
||||
#endif
|
||||
|
||||
@@ -2559,11 +2557,6 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
virtual void ComputeElementFlux(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
Vector &u, const FiniteElement &fluxelem,
|
||||
@@ -2609,35 +2602,6 @@ public:
|
||||
const Vector &elfun);
|
||||
};
|
||||
|
||||
/** Class for integrating the bilinear form a(u,v) := (Q curl u, v) where Q is
|
||||
an optional scalar coefficient, and v is a vector with components v_i in
|
||||
the L2 or H1 space. This integrator handles 3 cases:
|
||||
(a) u ∈ H(curl) in 3D, v is a 3D vector with components v_i in L^2 or H^1
|
||||
(b) u ∈ H(curl) in 2D, v is a scalar field in L^2 or H^1
|
||||
(c) u is a scalar field in H^1, i.e, curl u := [0 1;-1 0]grad u and v is a
|
||||
2D vector field with components v_i in L^2 or H^1 space.
|
||||
Note: Case (b) can also be handled by MixedScalarCurlIntegrator */
|
||||
class MixedCurlIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
|
||||
private:
|
||||
Vector shape;
|
||||
DenseMatrix dshape;
|
||||
DenseMatrix curlshape;
|
||||
DenseMatrix elmat_comp;
|
||||
public:
|
||||
MixedCurlIntegrator() : Q{NULL} { }
|
||||
MixedCurlIntegrator(Coefficient *q_) : Q{q_} { }
|
||||
MixedCurlIntegrator(Coefficient &q) : Q{&q} { }
|
||||
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
};
|
||||
|
||||
/** Integrator for (Q u, v), where Q is an optional coefficient (of type scalar,
|
||||
vector (diagonal matrix), or matrix), trial function u is in H(Curl) or
|
||||
H(Div), and test function v is in H(Curl), H(Div), or v=(v1,...,vn), where
|
||||
@@ -2761,7 +2725,7 @@ protected:
|
||||
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector divshape, te_divshape;
|
||||
Vector divshape;
|
||||
#endif
|
||||
|
||||
// PA extension
|
||||
@@ -2779,12 +2743,6 @@ public:
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
const Coefficient *GetCoefficient() const { return Q; }
|
||||
};
|
||||
|
||||
@@ -3059,8 +3017,8 @@ public:
|
||||
|
||||
/** Integrator for the DG form:
|
||||
|
||||
- < {(Q grad(u)).n}, [v] > + sigma < [u], {(Q grad(v)).n} >
|
||||
+ kappa < {h^{-1} Q} [u], [v] >
|
||||
- < {(Q grad(u)).n}, [v] > + sigma < [u], {(Q grad(v)).n} >
|
||||
+ kappa < {h^{-1} Q} [u], [v] >,
|
||||
|
||||
where Q is a scalar or matrix diffusion coefficient and u, v are the trial
|
||||
and test spaces, respectively. The parameters sigma and kappa determine the
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "../general/forall.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "qfunction.hpp"
|
||||
#include "ceed/integrators/convection/convection.hpp"
|
||||
#include "quadinterpolator.hpp"
|
||||
|
||||
@@ -1409,10 +1408,66 @@ void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
pa_data.SetSize(symmDims * nq * ne, mt);
|
||||
Vector vel;
|
||||
if (VectorConstantCoefficient *cQ =
|
||||
dynamic_cast<VectorConstantCoefficient*>(Q))
|
||||
{
|
||||
vel = cQ->GetVec();
|
||||
}
|
||||
else if (VectorGridFunctionCoefficient *vgfQ =
|
||||
dynamic_cast<VectorGridFunctionCoefficient*>(Q))
|
||||
{
|
||||
vel.SetSize(dim * nq * ne, mt);
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector vel(*Q, qs, CoefficientStorage::COMPRESSED);
|
||||
const GridFunction *gf = vgfQ->GetGridFunction();
|
||||
const FiniteElementSpace &gf_fes = *gf->FESpace();
|
||||
const QuadratureInterpolator *qi(gf_fes.GetQuadratureInterpolator(*ir));
|
||||
const bool use_tensor_products = UsesTensorBasis(gf_fes);
|
||||
const ElementDofOrdering ordering = use_tensor_products ?
|
||||
ElementDofOrdering::LEXICOGRAPHIC :
|
||||
ElementDofOrdering::NATIVE;
|
||||
const Operator *R = gf_fes.GetElementRestriction(ordering);
|
||||
|
||||
Vector xe(R->Height(), mt);
|
||||
xe.UseDevice(true);
|
||||
|
||||
R->Mult(*gf, xe);
|
||||
qi->SetOutputLayout(QVectorLayout::byVDIM);
|
||||
qi->DisableTensorProducts(!use_tensor_products);
|
||||
qi->Values(xe,vel);
|
||||
}
|
||||
else if (VectorQuadratureFunctionCoefficient* vqfQ =
|
||||
dynamic_cast<VectorQuadratureFunctionCoefficient*>(Q))
|
||||
{
|
||||
const QuadratureFunction &qFun = vqfQ->GetQuadFunction();
|
||||
MFEM_VERIFY(qFun.Size() == dim * nq * ne,
|
||||
"Incompatible QuadratureFunction dimension \n");
|
||||
|
||||
MFEM_VERIFY(ir == &qFun.GetSpace()->GetElementIntRule(0),
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
|
||||
qFun.Read();
|
||||
vel.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
|
||||
}
|
||||
else
|
||||
{
|
||||
vel.SetSize(dim * nq * ne);
|
||||
auto C = Reshape(vel.HostWrite(), dim, nq, ne);
|
||||
DenseMatrix MQ_ir;
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
ElementTransformation& T = *fes.GetElementTransformation(e);
|
||||
Q->Eval(MQ_ir, T, *ir);
|
||||
for (int q = 0; q < nq; ++q)
|
||||
{
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
C(i,q,e) = MQ_ir(i,q);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PAConvectionSetup(dim, nq, ne, ir->GetWeights(), geom->J,
|
||||
vel, alpha, pa_data);
|
||||
}
|
||||
|
||||
+104
-38
@@ -12,7 +12,6 @@
|
||||
#include "../general/forall.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "qfunction.hpp"
|
||||
#include "restriction.hpp"
|
||||
|
||||
using namespace std;
|
||||
@@ -145,7 +144,7 @@ void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement &el =
|
||||
*fes.GetTraceElement(0, fes.GetMesh()->GetFaceGeometry(0));
|
||||
*fes.GetTraceElement(0, fes.GetMesh()->GetFaceBaseGeometry(0));
|
||||
FaceElementTransformations &T0 =
|
||||
*fes.GetMesh()->GetFaceElementTransformations(0);
|
||||
const IntegrationRule *ir = IntRule?
|
||||
@@ -162,24 +161,88 @@ void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
pa_data.SetSize(symmDims * nq * nf, Device::GetMemoryType());
|
||||
|
||||
FaceQuadratureSpace qs(*mesh, *ir, type);
|
||||
CoefficientVector vel(*u, qs, CoefficientStorage::COMPRESSED);
|
||||
|
||||
CoefficientVector r(qs, CoefficientStorage::COMPRESSED);
|
||||
if (rho == nullptr)
|
||||
Vector vel;
|
||||
if (VectorConstantCoefficient *c_u = dynamic_cast<VectorConstantCoefficient*>
|
||||
(u))
|
||||
{
|
||||
r.SetConstant(1.0);
|
||||
vel = c_u->GetVec();
|
||||
}
|
||||
else if (ConstantCoefficient *const_rho = dynamic_cast<ConstantCoefficient*>
|
||||
(rho))
|
||||
else if (VectorQuadratureFunctionCoefficient* qf_u =
|
||||
dynamic_cast<VectorQuadratureFunctionCoefficient*>(u))
|
||||
{
|
||||
r.SetConstant(const_rho->constant);
|
||||
// Assumed to be in lexicographical ordering
|
||||
const QuadratureFunction &qFun = qf_u->GetQuadFunction();
|
||||
MFEM_VERIFY(qFun.Size() == dim * nq * nf,
|
||||
"Incompatible QuadratureFunction dimension \n");
|
||||
|
||||
MFEM_VERIFY(ir == &qFun.GetSpace()->GetElementIntRule(0),
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
qFun.Read();
|
||||
vel.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
|
||||
}
|
||||
else
|
||||
{
|
||||
vel.SetSize(dim * nq * nf);
|
||||
auto C = Reshape(vel.HostWrite(), dim, nq, nf);
|
||||
Vector Vq(dim);
|
||||
int f_ind = 0;
|
||||
for (int f = 0; f < mesh->GetNumFacesWithGhost(); ++f)
|
||||
{
|
||||
Mesh::FaceInformation face = mesh->GetFaceInformation(f);
|
||||
if (face.IsNonconformingCoarse())
|
||||
{
|
||||
// We skip nonconforming coarse faces as they are treated
|
||||
// by the corresponding nonconforming fine faces.
|
||||
continue;
|
||||
}
|
||||
else if ( face.IsOfFaceType(type) )
|
||||
{
|
||||
const int mask = FaceElementTransformations::HAVE_ELEM1 |
|
||||
FaceElementTransformations::HAVE_LOC1;
|
||||
FaceElementTransformations &T =
|
||||
*fes.GetMesh()->GetFaceElementTransformations(f, mask);
|
||||
for (int q = 0; q < nq; ++q)
|
||||
{
|
||||
// Convert to lexicographic ordering
|
||||
int iq = ToLexOrdering(dim, face.element[0].local_face_id,
|
||||
quad1D, q);
|
||||
T.SetAllIntPoints(&ir->IntPoint(q));
|
||||
const IntegrationPoint &eip1 = T.GetElement1IntPoint();
|
||||
u->Eval(Vq, *T.Elem1, eip1);
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
C(i,iq,f_ind) = Vq(i);
|
||||
}
|
||||
}
|
||||
f_ind++;
|
||||
}
|
||||
}
|
||||
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* qf_rho =
|
||||
dynamic_cast<QuadratureFunctionCoefficient*>(rho))
|
||||
{
|
||||
r.MakeRef(qf_rho->GetQuadFunction());
|
||||
const QuadratureFunction &qFun = qf_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
|
||||
{
|
||||
@@ -191,42 +254,45 @@ void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
|
||||
for (int f = 0; f < mesh->GetNumFacesWithGhost(); ++f)
|
||||
{
|
||||
Mesh::FaceInformation face = mesh->GetFaceInformation(f);
|
||||
if (face.IsNonconformingCoarse() || !face.IsOfFaceType(type))
|
||||
if (face.IsNonconformingCoarse())
|
||||
{
|
||||
// We skip nonconforming coarse faces as they are treated
|
||||
// by the corresponding nonconforming fine faces.
|
||||
continue;
|
||||
}
|
||||
FaceElementTransformations &T =
|
||||
*fes.GetMesh()->GetFaceElementTransformations(f);
|
||||
for (int q = 0; q < nq; ++q)
|
||||
else if ( face.IsOfFaceType(type) )
|
||||
{
|
||||
// Convert to lexicographic ordering
|
||||
int iq = ToLexOrdering(dim, face.element[0].local_face_id,
|
||||
quad1D, q);
|
||||
|
||||
T.SetAllIntPoints(&ir->IntPoint(q));
|
||||
const IntegrationPoint &eip1 = T.GetElement1IntPoint();
|
||||
const IntegrationPoint &eip2 = T.GetElement2IntPoint();
|
||||
double rq;
|
||||
|
||||
if (face.IsBoundary())
|
||||
FaceElementTransformations &T =
|
||||
*fes.GetMesh()->GetFaceElementTransformations(f);
|
||||
for (int q = 0; q < nq; ++q)
|
||||
{
|
||||
rq = rho->Eval(*T.Elem1, eip1);
|
||||
}
|
||||
else
|
||||
{
|
||||
double udotn = 0.0;
|
||||
for (int d=0; d<dim; ++d)
|
||||
// Convert to lexicographic ordering
|
||||
int iq = ToLexOrdering(dim, face.element[0].local_face_id,
|
||||
quad1D, q);
|
||||
|
||||
T.SetAllIntPoints(&ir->IntPoint(q));
|
||||
const IntegrationPoint &eip1 = T.GetElement1IntPoint();
|
||||
const IntegrationPoint &eip2 = T.GetElement2IntPoint();
|
||||
double rq;
|
||||
|
||||
if ( face.IsBoundary() )
|
||||
{
|
||||
udotn += C_vel(d,iq,f_ind)*n(iq,d,f_ind);
|
||||
rq = rho->Eval(*T.Elem1, eip1);
|
||||
}
|
||||
if (udotn >= 0.0) { rq = rho->Eval(*T.Elem2, eip2); }
|
||||
else { rq = 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) { rq = rho->Eval(*T.Elem2, eip2); }
|
||||
else { rq = rho->Eval(*T.Elem1, eip1); }
|
||||
}
|
||||
C(iq,f_ind) = rq;
|
||||
}
|
||||
C(iq,f_ind) = rq;
|
||||
f_ind++;
|
||||
}
|
||||
f_ind++;
|
||||
}
|
||||
MFEM_VERIFY(f_ind==nf, "Incorrect number of faces.");
|
||||
}
|
||||
|
||||
+110
-12
@@ -12,7 +12,6 @@
|
||||
#include "../general/forall.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "qfunction.hpp"
|
||||
#include "ceed/integrators/diffusion/diffusion.hpp"
|
||||
|
||||
using namespace std;
|
||||
@@ -391,21 +390,120 @@ void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
int coeffDim = 1;
|
||||
Vector coeff;
|
||||
const int MQfullDim = MQ ? MQ->GetHeight() * MQ->GetWidth() : 0;
|
||||
if (auto *SMQ = dynamic_cast<SymmetricMatrixCoefficient *>(MQ))
|
||||
{
|
||||
MFEM_VERIFY(SMQ->GetSize() == dim, "");
|
||||
coeffDim = symmDims;
|
||||
coeff.SetSize(symmDims * nq * ne);
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(qs, CoefficientStorage::COMPRESSED);
|
||||
DenseSymmetricMatrix sym_mat;
|
||||
sym_mat.SetSize(dim);
|
||||
|
||||
if (MQ) { coeff.ProjectTranspose(*MQ); }
|
||||
else if (VQ) { coeff.Project(*VQ); }
|
||||
else if (Q) { coeff.Project(*Q); }
|
||||
else { coeff.SetConstant(1.0); }
|
||||
auto C = Reshape(coeff.HostWrite(), symmDims, nq, ne);
|
||||
|
||||
const int coeff_dim = coeff.GetVDim();
|
||||
symmetric = (coeff_dim != dims*dims);
|
||||
const int pa_size = symmetric ? symmDims : dims*dims;
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
SMQ->Eval(sym_mat, *tr, ir->IntPoint(p));
|
||||
int cnt = 0;
|
||||
for (int i=0; i<dim; ++i)
|
||||
for (int j=i; j<dim; ++j, ++cnt)
|
||||
{
|
||||
C(cnt, p, e) = sym_mat(i,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (MQ)
|
||||
{
|
||||
symmetric = false;
|
||||
MFEM_VERIFY(MQ->GetHeight() == dim && MQ->GetWidth() == dim, "");
|
||||
|
||||
pa_data.SetSize(pa_size * nq * ne, mt);
|
||||
PADiffusionSetup(dim, sdim, dofs1D, quad1D, coeff_dim, ne, ir->GetWeights(),
|
||||
coeffDim = MQfullDim;
|
||||
|
||||
coeff.SetSize(MQfullDim * nq * ne);
|
||||
|
||||
DenseMatrix mat;
|
||||
mat.SetSize(dim);
|
||||
|
||||
auto C = Reshape(coeff.HostWrite(), MQfullDim, nq, ne);
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
MQ->Eval(mat, *tr, ir->IntPoint(p));
|
||||
for (int i=0; i<dim; ++i)
|
||||
for (int j=0; j<dim; ++j)
|
||||
{
|
||||
C(j+(i*dim), p, e) = mat(i,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (VQ)
|
||||
{
|
||||
MFEM_VERIFY(VQ->GetVDim() == dim, "");
|
||||
coeffDim = VQ->GetVDim();
|
||||
coeff.SetSize(coeffDim * nq * ne);
|
||||
auto C = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
|
||||
Vector DM(coeffDim);
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
VQ->Eval(DM, *tr, ir->IntPoint(p));
|
||||
for (int i=0; i<coeffDim; ++i)
|
||||
{
|
||||
C(i, p, e) = DM[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Q == nullptr)
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = 1.0;
|
||||
}
|
||||
else if (ConstantCoefficient* cQ = dynamic_cast<ConstantCoefficient*>(Q))
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = cQ->constant;
|
||||
}
|
||||
else if (QuadratureFunctionCoefficient* qfQ =
|
||||
dynamic_cast<QuadratureFunctionCoefficient*>(Q))
|
||||
{
|
||||
const QuadratureFunction &qFun = qfQ->GetQuadFunction();
|
||||
MFEM_VERIFY(qFun.Size() == ne*nq,
|
||||
"Incompatible QuadratureFunction dimension \n");
|
||||
|
||||
MFEM_VERIFY(ir == &qFun.GetSpace()->GetElementIntRule(0),
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
qFun.Read();
|
||||
coeff.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
|
||||
}
|
||||
else
|
||||
{
|
||||
coeff.SetSize(nq * ne);
|
||||
auto C = Reshape(coeff.HostWrite(), nq, ne);
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
ElementTransformation& T = *fes.GetElementTransformation(e);
|
||||
for (int q = 0; q < nq; ++q)
|
||||
{
|
||||
C(q,e) = Q->Eval(T, ir->IntPoint(q));
|
||||
}
|
||||
}
|
||||
}
|
||||
pa_data.SetSize((symmetric ? symmDims : MQfullDim) * nq * ne, mt);
|
||||
PADiffusionSetup(dim, sdim, dofs1D, quad1D, coeffDim, ne, ir->GetWeights(),
|
||||
geom->J, coeff, pa_data);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "../general/forall.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "qfunction.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -210,8 +209,44 @@ void GradientIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
"PA requires test and trial space to have same number of quadrature points!");
|
||||
pa_data.SetSize(nq * dimsToStore * ne, Device::GetMemoryType());
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(Q, qs, CoefficientStorage::COMPRESSED);
|
||||
Vector coeff;
|
||||
|
||||
if (Q == nullptr)
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = 1.0;
|
||||
}
|
||||
else if (ConstantCoefficient* cQ = dynamic_cast<ConstantCoefficient*>(Q))
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = cQ->constant;
|
||||
}
|
||||
else if (QuadratureFunctionCoefficient* qfQ =
|
||||
dynamic_cast<QuadratureFunctionCoefficient*>(Q))
|
||||
{
|
||||
const QuadratureFunction &qFun = qfQ->GetQuadFunction();
|
||||
MFEM_VERIFY(qFun.Size() == ne*nq,
|
||||
"Incompatible QuadratureFunction dimension \n");
|
||||
|
||||
MFEM_VERIFY(ir == &qFun.GetSpace()->GetElementIntRule(0),
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
qFun.Read();
|
||||
coeff.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
|
||||
}
|
||||
else
|
||||
{
|
||||
coeff.SetSize(nq * ne);
|
||||
auto C = Reshape(coeff.HostWrite(), nq, ne);
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
ElementTransformation& T = *trial_fes.GetElementTransformation(e);
|
||||
for (int q = 0; q < nq; ++q)
|
||||
{
|
||||
C(q,e) = Q->Eval(T, ir->IntPoint(q));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PAGradientSetup(dim, trial_dofs1D, test_dofs1D, quad1D,
|
||||
ne, ir->GetWeights(), geom->J, coeff, pa_data);
|
||||
@@ -830,3 +865,4 @@ void GradientIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
|
||||
+169
-33
@@ -12,7 +12,6 @@
|
||||
#include "../general/forall.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "qspace.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -968,6 +967,8 @@ void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
dim = mesh->Dimension();
|
||||
MFEM_VERIFY(dim == 2 || dim == 3, "");
|
||||
|
||||
const int dimc = (dim == 3) ? 3 : 1;
|
||||
|
||||
ne = fes.GetNE();
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
|
||||
mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
@@ -977,19 +978,88 @@ void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
|
||||
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(qs, CoefficientStorage::SYMMETRIC);
|
||||
if (Q) { coeff.Project(*Q); }
|
||||
else if (MQ) { coeff.ProjectTranspose(*MQ); }
|
||||
else if (DQ) { coeff.Project(*DQ); }
|
||||
else { coeff.SetConstant(1.0); }
|
||||
auto SMQ = dynamic_cast<SymmetricMatrixCoefficient *>(MQ);
|
||||
|
||||
const int coeff_dim = coeff.GetVDim();
|
||||
symmetric = (coeff_dim != dim*dim);
|
||||
const int sym_dims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
|
||||
const int ndata = (dim == 2) ? 1 : (symmetric ? sym_dims : dim*dim);
|
||||
const int MQsymmDim = SMQ ? (SMQ->GetSize() * (SMQ->GetSize() + 1)) / 2 : 0;
|
||||
const int MQfullDim = MQ ? (MQ->GetHeight() * MQ->GetWidth()) : 0;
|
||||
const int MQdim = SMQ ? MQsymmDim : MQfullDim;
|
||||
const int coeffDim = MQ ? MQdim : (DQ ? DQ->GetVDim() : 1);
|
||||
|
||||
symmetric = (SMQ || MQ == NULL);
|
||||
|
||||
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
|
||||
const int ndata = (dim == 2) ? 1 : (symmetric ? symmDims : MQfullDim);
|
||||
pa_data.SetSize(ndata * nq * ne, Device::GetMemoryType());
|
||||
|
||||
Vector coeff(coeffDim * ne * nq);
|
||||
coeff = 1.0;
|
||||
auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
|
||||
if (Q || DQ || MQ)
|
||||
{
|
||||
Vector DM(DQ ? coeffDim : 0);
|
||||
DenseMatrix GM;
|
||||
DenseSymmetricMatrix SM;
|
||||
|
||||
if (DQ)
|
||||
{
|
||||
MFEM_VERIFY(coeffDim == dimc, "");
|
||||
}
|
||||
if (SMQ)
|
||||
{
|
||||
SM.SetSize(dimc);
|
||||
MFEM_VERIFY(SMQ->GetSize() == dimc, "");
|
||||
}
|
||||
else if (MQ)
|
||||
{
|
||||
GM.SetSize(dimc);
|
||||
MFEM_VERIFY(coeffDim == MQdim, "");
|
||||
MFEM_VERIFY(MQ->GetHeight() == dimc && MQ->GetWidth() == dimc, "");
|
||||
}
|
||||
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
if (SMQ)
|
||||
{
|
||||
SMQ->Eval(SM, *tr, ir->IntPoint(p));
|
||||
|
||||
int cnt = 0;
|
||||
for (int i=0; i<dimc; ++i)
|
||||
for (int j=i; j<dimc; ++j, ++cnt)
|
||||
{
|
||||
coeffh(cnt, p, e) = SM(i,j);
|
||||
}
|
||||
|
||||
}
|
||||
else if (MQ)
|
||||
{
|
||||
MQ->Eval(GM, *tr, ir->IntPoint(p));
|
||||
|
||||
for (int i=0; i<dimc; ++i)
|
||||
for (int j=0; j<dimc; ++j)
|
||||
{
|
||||
coeffh(j+(i*dimc), p, e) = GM(i,j);
|
||||
}
|
||||
|
||||
}
|
||||
else if (DQ)
|
||||
{
|
||||
DQ->Eval(DM, *tr, ir->IntPoint(p));
|
||||
for (int i=0; i<coeffDim; ++i)
|
||||
{
|
||||
coeffh(i, p, e) = DM[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
coeffh(0, p, e) = Q->Eval(*tr, ir->IntPoint(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (el->GetDerivType() != mfem::FiniteElement::CURL)
|
||||
{
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
@@ -997,7 +1067,7 @@ void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
|
||||
if (dim == 3)
|
||||
{
|
||||
PACurlCurlSetup3D(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J, coeff,
|
||||
PACurlCurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J, coeff,
|
||||
pa_data);
|
||||
}
|
||||
else
|
||||
@@ -2710,7 +2780,7 @@ void CurlCurlIntegrator::AssembleDiagonalPA(Vector& diag)
|
||||
}
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H^1 (trial), whose gradients are
|
||||
// Apply to x corresponding to DOF's in H^1 (trial), whose gradients are
|
||||
// integrated against H(curl) test functions corresponding to y.
|
||||
void PAHcurlH1Apply3D(const int D1D,
|
||||
const int Q1D,
|
||||
@@ -2900,7 +2970,7 @@ void PAHcurlH1Apply3D(const int D1D,
|
||||
}); // end of element loop
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H(curl), integrated
|
||||
// Apply to x corresponding to DOF's in H(curl), integrated
|
||||
// against gradients of H^1 functions corresponding to y.
|
||||
void PAHcurlH1ApplyTranspose3D(const int D1D,
|
||||
const int Q1D,
|
||||
@@ -3099,7 +3169,7 @@ void PAHcurlH1ApplyTranspose3D(const int D1D,
|
||||
}); // end of element loop
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H^1 (trial), whose gradients are
|
||||
// Apply to x corresponding to DOF's in H^1 (trial), whose gradients are
|
||||
// integrated against H(curl) test functions corresponding to y.
|
||||
void PAHcurlH1Apply2D(const int D1D,
|
||||
const int Q1D,
|
||||
@@ -3223,7 +3293,7 @@ void PAHcurlH1Apply2D(const int D1D,
|
||||
}); // end of element loop
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H(curl), integrated
|
||||
// Apply to x corresponding to DOF's in H(curl), integrated
|
||||
// against gradients of H^1 functions corresponding to y.
|
||||
void PAHcurlH1ApplyTranspose2D(const int D1D,
|
||||
const int Q1D,
|
||||
@@ -3419,8 +3489,20 @@ void MixedScalarCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
|
||||
pa_data.SetSize(nq * ne, Device::GetMemoryType());
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(Q, qs, CoefficientStorage::FULL);
|
||||
Vector coeff(ne * nq);
|
||||
coeff = 1.0;
|
||||
auto coeffh = Reshape(coeff.HostWrite(), nq, ne);
|
||||
if (Q)
|
||||
{
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
coeffh(p, e) = Q->Eval(*tr, ir->IntPoint(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
@@ -3511,11 +3593,38 @@ void MixedVectorCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
const int ndata = curlSpaces ? (coeffDim == 1 ? 1 : 9) : symmDims;
|
||||
pa_data.SetSize(ndata * nq * ne, Device::GetMemoryType());
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(qs, CoefficientStorage::FULL);
|
||||
if (Q) { coeff.Project(*Q); }
|
||||
else if (DQ) { coeff.Project(*DQ); }
|
||||
else { coeff.SetConstant(1.0); }
|
||||
Vector coeff(coeffDim * nq * ne);
|
||||
coeff = 1.0;
|
||||
auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
|
||||
if (Q || DQ)
|
||||
{
|
||||
Vector V(coeffDim);
|
||||
if (DQ)
|
||||
{
|
||||
MFEM_VERIFY(DQ->GetVDim() == coeffDim, "");
|
||||
}
|
||||
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
if (DQ)
|
||||
{
|
||||
DQ->Eval(V, *tr, ir->IntPoint(p));
|
||||
for (int i=0; i<coeffDim; ++i)
|
||||
{
|
||||
coeffh(i, p, e) = V[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
coeffh(0, p, e) = Q->Eval(*tr, ir->IntPoint(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (testType == mfem::FiniteElement::CURL &&
|
||||
trialType == mfem::FiniteElement::CURL && dim == 3)
|
||||
@@ -3543,7 +3652,7 @@ void MixedVectorCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
}
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H(curl) (trial), whose curl is
|
||||
// Apply to x corresponding to DOF's in H(curl) (trial), whose curl is
|
||||
// integrated against H(curl) test functions corresponding to y.
|
||||
template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
|
||||
static void PAHcurlL2Apply3D(const int D1D,
|
||||
@@ -3906,7 +4015,7 @@ static void PAHcurlL2Apply3D(const int D1D,
|
||||
}); // end of element loop
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H(curl) (trial), whose curl is
|
||||
// Apply to x corresponding to DOF's in H(curl) (trial), whose curl is
|
||||
// integrated against H(curl) test functions corresponding to y.
|
||||
template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
|
||||
static void SmemPAHcurlL2Apply3D(const int D1D,
|
||||
@@ -4216,7 +4325,7 @@ static void SmemPAHcurlL2Apply3D(const int D1D,
|
||||
ForallWrap<3>(true, NE, device_kernel, host_kernel, Q1D, Q1D, Q1D);
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H(curl) (trial), whose curl is
|
||||
// Apply to x corresponding to DOF's in H(curl) (trial), whose curl is
|
||||
// integrated against H(div) test functions corresponding to y.
|
||||
template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
|
||||
static void PAHcurlHdivApply3D(const int D1D,
|
||||
@@ -4572,7 +4681,7 @@ static void PAHcurlHdivApply3D(const int D1D,
|
||||
}); // end of element loop
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H(div) (test), integrated against the
|
||||
// Apply to x corresponding to DOF's in H(div) (test), integrated against the
|
||||
// curl of H(curl) trial functions corresponding to y.
|
||||
template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
|
||||
static void PAHcurlHdivApply3DTranspose(const int D1D,
|
||||
@@ -5037,11 +5146,38 @@ void MixedVectorWeakCurlIntegrator::AssemblePA(const FiniteElementSpace
|
||||
|
||||
pa_data.SetSize(ndata * nq * ne, Device::GetMemoryType());
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(qs, CoefficientStorage::FULL);
|
||||
if (Q) { coeff.Project(*Q); }
|
||||
else if (DQ) { coeff.Project(*DQ); }
|
||||
else { coeff.SetConstant(1.0); }
|
||||
Vector coeff(coeffDim * nq * ne);
|
||||
coeff = 1.0;
|
||||
auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
|
||||
if (Q || DQ)
|
||||
{
|
||||
Vector V(coeffDim);
|
||||
if (DQ)
|
||||
{
|
||||
MFEM_VERIFY(DQ->GetVDim() == coeffDim, "");
|
||||
}
|
||||
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
if (DQ)
|
||||
{
|
||||
DQ->Eval(V, *tr, ir->IntPoint(p));
|
||||
for (int i=0; i<coeffDim; ++i)
|
||||
{
|
||||
coeffh(i, p, e) = V[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
coeffh(0, p, e) = Q->Eval(*tr, ir->IntPoint(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trialType == mfem::FiniteElement::CURL && dim == 3)
|
||||
{
|
||||
@@ -5067,7 +5203,7 @@ void MixedVectorWeakCurlIntegrator::AssemblePA(const FiniteElementSpace
|
||||
}
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H(curl) (trial), integrated against curl
|
||||
// Apply to x corresponding to DOF's in H(curl) (trial), integrated against curl
|
||||
// of H(curl) test functions corresponding to y.
|
||||
template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
|
||||
static void PAHcurlL2Apply3DTranspose(const int D1D,
|
||||
|
||||
+28
-7
@@ -12,7 +12,6 @@
|
||||
#include "../general/forall.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "qspace.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -1514,8 +1513,19 @@ void DivDivIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
|
||||
pa_data.SetSize(nq * ne, Device::GetMemoryType());
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(Q, qs, CoefficientStorage::FULL);
|
||||
Vector coeff(ne * nq);
|
||||
coeff = 1.0;
|
||||
if (Q)
|
||||
{
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 3)
|
||||
{
|
||||
@@ -1773,8 +1783,19 @@ VectorFEDivergenceIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
|
||||
pa_data.SetSize(nq * ne, Device::GetMemoryType());
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(Q, qs, CoefficientStorage::FULL);
|
||||
Vector coeff(ne * nq);
|
||||
coeff = 1.0;
|
||||
if (Q)
|
||||
{
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (test_el->GetMapType() == FiniteElement::INTEGRAL)
|
||||
{
|
||||
@@ -1797,7 +1818,7 @@ VectorFEDivergenceIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
}
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H(div) (trial), whose divergence is
|
||||
// Apply to x corresponding to DOF's in H(div) (trial), whose divergence is
|
||||
// integrated against L_2 test functions corresponding to y.
|
||||
static void PAHdivL2Apply3D(const int D1D,
|
||||
const int Q1D,
|
||||
@@ -1960,7 +1981,7 @@ static void PAHdivL2Apply3D(const int D1D,
|
||||
}); // end of element loop
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H(div) (trial), whose divergence is
|
||||
// Apply to x corresponding to DOF's in H(div) (trial), whose divergence is
|
||||
// integrated against L_2 test functions corresponding to y.
|
||||
static void PAHdivL2Apply2D(const int D1D,
|
||||
const int Q1D,
|
||||
|
||||
+565
-40
@@ -12,9 +12,7 @@
|
||||
#include "../general/forall.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "qfunction.hpp"
|
||||
#include "ceed/integrators/mass/mass.hpp"
|
||||
#include "bilininteg_mass_pa.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -56,15 +54,49 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
dim = mesh->Dimension();
|
||||
ne = fes.GetMesh()->GetNE();
|
||||
nq = ir->GetNPoints();
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::DETERMINANTS, mt);
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::COORDINATES |
|
||||
GeometricFactors::JACOBIANS, mt);
|
||||
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
pa_data.SetSize(ne*nq, mt);
|
||||
Vector coeff;
|
||||
if (Q == nullptr)
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = 1.0;
|
||||
}
|
||||
else if (ConstantCoefficient* cQ = dynamic_cast<ConstantCoefficient*>(Q))
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = cQ->constant;
|
||||
}
|
||||
else if (QuadratureFunctionCoefficient* qfQ =
|
||||
dynamic_cast<QuadratureFunctionCoefficient*>(Q))
|
||||
{
|
||||
const QuadratureFunction &qFun = qfQ->GetQuadFunction();
|
||||
MFEM_VERIFY(qFun.Size() == nq * ne,
|
||||
"Incompatible QuadratureFunction dimension \n");
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(Q, qs, CoefficientStorage::COMPRESSED);
|
||||
|
||||
MFEM_VERIFY(ir == &qFun.GetSpace()->GetElementIntRule(0),
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
qFun.Read();
|
||||
coeff.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
|
||||
}
|
||||
else
|
||||
{
|
||||
coeff.SetSize(nq * ne);
|
||||
auto C = Reshape(coeff.HostWrite(), nq, ne);
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
ElementTransformation& T = *fes.GetElementTransformation(e);
|
||||
for (int q = 0; q < nq; ++q)
|
||||
{
|
||||
C(q,e) = Q->Eval(T, ir->IntPoint(q));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim==1) { MFEM_ABORT("Not supported yet... stay tuned!"); }
|
||||
if (dim==2)
|
||||
{
|
||||
@@ -73,7 +105,7 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
const bool by_val = map_type == FiniteElement::VALUE;
|
||||
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
|
||||
const auto J = Reshape(geom->detJ.Read(), Q1D,Q1D,NE);
|
||||
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);
|
||||
@@ -83,7 +115,11 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
const double detJ = J(qx,qy,e);
|
||||
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 * (by_val ? detJ : 1.0/detJ);
|
||||
}
|
||||
@@ -97,7 +133,7 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
const bool by_val = map_type == FiniteElement::VALUE;
|
||||
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D,Q1D);
|
||||
const auto J = Reshape(geom->detJ.Read(), Q1D,Q1D,Q1D,NE);
|
||||
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);
|
||||
@@ -109,7 +145,18 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
const double detJ = J(qx,qy,qz,e);
|
||||
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 * (by_val ? detJ : 1.0/detJ);
|
||||
}
|
||||
@@ -543,18 +590,85 @@ static void PAMassApply2D(const int NE,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= MAX_D1D, "");
|
||||
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= MAX_Q1D, "");
|
||||
|
||||
const auto B = b_.Read();
|
||||
const auto Bt = bt_.Read();
|
||||
const auto D = d_.Read();
|
||||
const auto X = x_.Read();
|
||||
auto Y = y_.ReadWrite();
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
auto B = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt_.Read(), D1D, Q1D);
|
||||
auto D = Reshape(d_.Read(), Q1D, Q1D, NE);
|
||||
auto X = Reshape(x_.Read(), D1D, D1D, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
internal::PAMassApply2D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
|
||||
const int D1D = T_D1D ? T_D1D : d1d; // nvcc workaround
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
double sol_xy[max_Q1D][max_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
double sol_x[max_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
sol_x[qy] = 0.0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double s = X(dx,dy,e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_x[qx] += B(qx,dx)* s;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double d2q = B(qy,dy);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] += d2q * sol_x[qx];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] *= D(qx,qy,e);
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double sol_x[max_D1D];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double s = sol_xy[qy][qx];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] += Bt(dx,qx) * s;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double q2d = Bt(dy,qy);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
Y(dx,dy,e) += q2d * sol_x[dx];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -576,13 +690,108 @@ static void SmemPAMassApply2D(const int NE,
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= MD1, "");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "");
|
||||
const auto b = b_.Read();
|
||||
const auto D = d_.Read();
|
||||
const auto x = x_.Read();
|
||||
auto Y = y_.ReadWrite();
|
||||
auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto D = Reshape(d_.Read(), Q1D, Q1D, NE);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
internal::SmemPAMassApply2D_Element<T_D1D,T_Q1D,T_NBZ>(e, NE, b, D, x, Y, d1d, q1d);
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
MFEM_SHARED double BBt[MQ1*MD1];
|
||||
double (*B)[MD1] = (double (*)[MD1]) BBt;
|
||||
double (*Bt)[MQ1] = (double (*)[MQ1]) BBt;
|
||||
MFEM_SHARED double sm0[NBZ][MDQ*MDQ];
|
||||
MFEM_SHARED double sm1[NBZ][MDQ*MDQ];
|
||||
double (*X)[MD1] = (double (*)[MD1]) (sm0 + tidz);
|
||||
double (*DQ)[MQ1] = (double (*)[MQ1]) (sm1 + tidz);
|
||||
double (*QQ)[MQ1] = (double (*)[MQ1]) (sm0 + tidz);
|
||||
double (*QD)[MD1] = (double (*)[MD1]) (sm1 + tidz);
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
X[dy][dx] = x(dx,dy,e);
|
||||
}
|
||||
}
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B[q][dy] = b(q,dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double dq = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
dq += X[dy][dx] * B[qx][dx];
|
||||
}
|
||||
DQ[dy][qx] = dq;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double qq = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
qq += DQ[dy][qx] * B[qy][dy];
|
||||
}
|
||||
QQ[qy][qx] = qq * D(qx, qy, e);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
Bt[dy][q] = b(q,dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double dq = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
dq += QQ[qy][qx] * Bt[dx][qx];
|
||||
}
|
||||
QD[qy][dx] = dq;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double dd = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
dd += (QD[qy][dx] * Bt[dy][qy]);
|
||||
}
|
||||
Y(dx, dy, e) += dd;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -596,18 +805,134 @@ static void PAMassApply3D(const int NE,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= MAX_D1D, "");
|
||||
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= MAX_Q1D, "");
|
||||
|
||||
const auto B = b_.Read();
|
||||
const auto Bt = bt_.Read();
|
||||
const auto D = d_.Read();
|
||||
const auto X = x_.Read();
|
||||
auto Y = y_.ReadWrite();
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
auto B = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(bt_.Read(), D1D, Q1D);
|
||||
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(e, NE,
|
||||
{
|
||||
internal::PAMassApply3D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
double sol_xyz[max_Q1D][max_Q1D][max_Q1D];
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xyz[qz][qy][qx] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
double sol_xy[max_Q1D][max_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
double sol_x[max_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_x[qx] = 0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double s = X(dx,dy,dz,e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_x[qx] += B(qx,dx) * s;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double wy = B(qy,dy);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] += wy * sol_x[qx];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const double wz = B(qz,dz);
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xyz[qz][qy][qx] += wz * sol_xy[qy][qx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xyz[qz][qy][qx] *= D(qx,qy,qz,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
double sol_xy[max_D1D][max_D1D];
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_xy[dy][dx] = 0;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double sol_x[max_D1D];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] = 0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double s = sol_xyz[qz][qy][qx];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] += Bt(dx,qx) * s;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double wy = Bt(dy,qy);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_xy[dy][dx] += wy * sol_x[dx];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
const double wz = Bt(dz,qz);
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
Y(dx,dy,dz,e) += wz * sol_xy[dy][dx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -628,13 +953,213 @@ static void SmemPAMassApply3D(const int NE,
|
||||
constexpr int M1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= M1D, "");
|
||||
MFEM_VERIFY(Q1D <= M1Q, "");
|
||||
auto b = b_.Read();
|
||||
auto d = d_.Read();
|
||||
auto x = x_.Read();
|
||||
auto y = y_.ReadWrite();
|
||||
auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
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, 1,
|
||||
{
|
||||
internal::SmemPAMassApply3D_Element<T_D1D,T_Q1D>(e, NE, b, d, x, y, d1d, q1d);
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
MFEM_SHARED double sDQ[MQ1*MD1];
|
||||
double (*B)[MD1] = (double (*)[MD1]) sDQ;
|
||||
double (*Bt)[MQ1] = (double (*)[MQ1]) sDQ;
|
||||
MFEM_SHARED double sm0[MDQ*MDQ*MDQ];
|
||||
MFEM_SHARED double sm1[MDQ*MDQ*MDQ];
|
||||
double (*X)[MD1][MD1] = (double (*)[MD1][MD1]) sm0;
|
||||
double (*DDQ)[MD1][MQ1] = (double (*)[MD1][MQ1]) sm1;
|
||||
double (*DQQ)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) sm0;
|
||||
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(dy,y,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);
|
||||
}
|
||||
}
|
||||
MFEM_FOREACH_THREAD(dx,x,Q1D)
|
||||
{
|
||||
B[dx][dy] = b(dx,dy);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u[D1D];
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; dz++)
|
||||
{
|
||||
u[dz] = 0;
|
||||
}
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
u[dz] += X[dz][dy][dx] * B[qx][dx];
|
||||
}
|
||||
}
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
DDQ[dz][dy][qx] = u[dz];
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u[D1D];
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; dz++)
|
||||
{
|
||||
u[dz] = 0;
|
||||
}
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; dz++)
|
||||
{
|
||||
u[dz] += DDQ[dz][dy][qx] * B[qy][dy];
|
||||
}
|
||||
}
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; dz++)
|
||||
{
|
||||
DQQ[dz][qy][qx] = u[dz];
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u[Q1D];
|
||||
MFEM_UNROLL(MQ1)
|
||||
for (int qz = 0; qz < Q1D; qz++)
|
||||
{
|
||||
u[qz] = 0;
|
||||
}
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
MFEM_UNROLL(MQ1)
|
||||
for (int qz = 0; qz < Q1D; qz++)
|
||||
{
|
||||
u[qz] += DQQ[dz][qy][qx] * B[qz][dz];
|
||||
}
|
||||
}
|
||||
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(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
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)
|
||||
{
|
||||
u[qz] = 0;
|
||||
}
|
||||
MFEM_UNROLL(MQ1)
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
MFEM_UNROLL(MQ1)
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
u[qz] += QQQ[qz][qy][qx] * Bt[dx][qx];
|
||||
}
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,632 +0,0 @@
|
||||
// Copyright (c) 2010-2022, 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_BILININTEG_MASS_PA_HPP
|
||||
#define MFEM_BILININTEG_MASS_PA_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <bool ACCUMULATE = true>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void PAMassApply2D_Element(const int e,
|
||||
const int NE,
|
||||
const double *b_,
|
||||
const double *bt_,
|
||||
const double *d_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = d1d;
|
||||
const int Q1D = q1d;
|
||||
auto B = ConstDeviceMatrix(b_, Q1D, D1D);
|
||||
auto Bt = ConstDeviceMatrix(bt_, D1D, Q1D);
|
||||
auto D = ConstDeviceCube(d_, Q1D, Q1D, NE);
|
||||
auto X = ConstDeviceCube(x_, D1D, D1D, NE);
|
||||
auto Y = DeviceCube(y_, D1D, D1D, NE);
|
||||
|
||||
if (!ACCUMULATE)
|
||||
{
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
Y(dx, dy, e) = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr int max_D1D = MAX_D1D;
|
||||
constexpr int max_Q1D = MAX_Q1D;
|
||||
double sol_xy[max_Q1D][max_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
double sol_x[max_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
sol_x[qy] = 0.0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double s = X(dx,dy,e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_x[qx] += B(qx,dx)* s;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double d2q = B(qy,dy);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] += d2q * sol_x[qx];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] *= D(qx,qy,e);
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double sol_x[max_D1D];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double s = sol_xy[qy][qx];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] += Bt(dx,qx) * s;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double q2d = Bt(dy,qy);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
Y(dx,dy,e) += q2d * sol_x[dx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int T_D1D, int T_Q1D, int T_NBZ, bool ACCUMULATE = true>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void SmemPAMassApply2D_Element(const int e,
|
||||
const int NE,
|
||||
const double *b_,
|
||||
const double *d_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
int d1d = 0,
|
||||
int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
|
||||
auto b = ConstDeviceMatrix(b_, Q1D, D1D);
|
||||
auto D = ConstDeviceCube(d_, Q1D, Q1D, NE);
|
||||
auto x = ConstDeviceCube(x_, D1D, D1D, NE);
|
||||
auto Y = DeviceCube(y_, D1D, D1D, NE);
|
||||
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
|
||||
MFEM_SHARED double BBt[MQ1*MD1];
|
||||
double (*B)[MD1] = (double (*)[MD1]) BBt;
|
||||
double (*Bt)[MQ1] = (double (*)[MQ1]) BBt;
|
||||
MFEM_SHARED double sm0[NBZ][MDQ*MDQ];
|
||||
MFEM_SHARED double sm1[NBZ][MDQ*MDQ];
|
||||
double (*X)[MD1] = (double (*)[MD1]) (sm0 + tidz);
|
||||
double (*DQ)[MQ1] = (double (*)[MQ1]) (sm1 + tidz);
|
||||
double (*QQ)[MQ1] = (double (*)[MQ1]) (sm0 + tidz);
|
||||
double (*QD)[MD1] = (double (*)[MD1]) (sm1 + tidz);
|
||||
|
||||
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
X[dy][dx] = x(dx,dy,e);
|
||||
}
|
||||
}
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B[q][dy] = b(q,dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double dq = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
dq += X[dy][dx] * B[qx][dx];
|
||||
}
|
||||
DQ[dy][qx] = dq;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double qq = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
qq += DQ[dy][qx] * B[qy][dy];
|
||||
}
|
||||
QQ[qy][qx] = qq * D(qx, qy, e);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
Bt[dy][q] = b(q,dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double dq = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
dq += QQ[qy][qx] * Bt[dx][qx];
|
||||
}
|
||||
QD[qy][dx] = dq;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double dd = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
dd += (QD[qy][dx] * Bt[dy][qy]);
|
||||
}
|
||||
if (ACCUMULATE)
|
||||
{
|
||||
Y(dx, dy, e) += dd;
|
||||
}
|
||||
else
|
||||
{
|
||||
Y(dx, dy, e) = dd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool ACCUMULATE = true>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void PAMassApply3D_Element(const int e,
|
||||
const int NE,
|
||||
const double *b_,
|
||||
const double *bt_,
|
||||
const double *d_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
const int D1D = d1d;
|
||||
const int Q1D = q1d;
|
||||
auto B = ConstDeviceMatrix(b_, Q1D, D1D);
|
||||
auto Bt = ConstDeviceMatrix(bt_, D1D, Q1D);
|
||||
auto D = DeviceTensor<4,const double>(d_, Q1D, Q1D, Q1D, NE);
|
||||
auto X = DeviceTensor<4,const double>(x_, D1D, D1D, D1D, NE);
|
||||
auto Y = DeviceTensor<4,double>(y_, D1D, D1D, D1D, NE);
|
||||
|
||||
if (!ACCUMULATE)
|
||||
{
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
Y(dx, dy, dz, e) = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr int max_D1D = MAX_D1D;
|
||||
constexpr int max_Q1D = MAX_Q1D;
|
||||
double sol_xyz[max_Q1D][max_Q1D][max_Q1D];
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xyz[qz][qy][qx] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
double sol_xy[max_Q1D][max_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
double sol_x[max_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_x[qx] = 0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double s = X(dx,dy,dz,e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_x[qx] += B(qx,dx) * s;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double wy = B(qy,dy);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] += wy * sol_x[qx];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const double wz = B(qz,dz);
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xyz[qz][qy][qx] += wz * sol_xy[qy][qx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xyz[qz][qy][qx] *= D(qx,qy,qz,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
double sol_xy[max_D1D][max_D1D];
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_xy[dy][dx] = 0;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double sol_x[max_D1D];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] = 0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double s = sol_xyz[qz][qy][qx];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] += Bt(dx,qx) * s;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double wy = Bt(dy,qy);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_xy[dy][dx] += wy * sol_x[dx];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
const double wz = Bt(dz,qz);
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
Y(dx,dy,dz,e) += wz * sol_xy[dy][dx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int T_D1D, int T_Q1D, bool ACCUMULATE = true>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void SmemPAMassApply3D_Element(const int e,
|
||||
const int NE,
|
||||
const double *b_,
|
||||
const double *d_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
constexpr int D1D = T_D1D ? T_D1D : d1d;
|
||||
constexpr int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
|
||||
auto b = ConstDeviceMatrix(b_, Q1D, D1D);
|
||||
auto d = DeviceTensor<4,const double>(d_, Q1D, Q1D, Q1D, NE);
|
||||
auto x = DeviceTensor<4,const double>(x_, D1D, D1D, D1D, NE);
|
||||
auto y = DeviceTensor<4,double>(y_, D1D, D1D, D1D, NE);
|
||||
|
||||
MFEM_SHARED double sDQ[MQ1*MD1];
|
||||
double (*B)[MD1] = (double (*)[MD1]) sDQ;
|
||||
double (*Bt)[MQ1] = (double (*)[MQ1]) sDQ;
|
||||
MFEM_SHARED double sm0[MDQ*MDQ*MDQ];
|
||||
MFEM_SHARED double sm1[MDQ*MDQ*MDQ];
|
||||
double (*X)[MD1][MD1] = (double (*)[MD1][MD1]) sm0;
|
||||
double (*DDQ)[MD1][MQ1] = (double (*)[MD1][MQ1]) sm1;
|
||||
double (*DQQ)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) sm0;
|
||||
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(dy,y,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);
|
||||
}
|
||||
}
|
||||
MFEM_FOREACH_THREAD(dx,x,Q1D)
|
||||
{
|
||||
B[dx][dy] = b(dx,dy);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u[D1D];
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; dz++)
|
||||
{
|
||||
u[dz] = 0;
|
||||
}
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
u[dz] += X[dz][dy][dx] * B[qx][dx];
|
||||
}
|
||||
}
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
DDQ[dz][dy][qx] = u[dz];
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u[D1D];
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; dz++)
|
||||
{
|
||||
u[dz] = 0;
|
||||
}
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; dz++)
|
||||
{
|
||||
u[dz] += DDQ[dz][dy][qx] * B[qy][dy];
|
||||
}
|
||||
}
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; dz++)
|
||||
{
|
||||
DQQ[dz][qy][qx] = u[dz];
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u[Q1D];
|
||||
MFEM_UNROLL(MQ1)
|
||||
for (int qz = 0; qz < Q1D; qz++)
|
||||
{
|
||||
u[qz] = 0;
|
||||
}
|
||||
MFEM_UNROLL(MD1)
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
MFEM_UNROLL(MQ1)
|
||||
for (int qz = 0; qz < Q1D; qz++)
|
||||
{
|
||||
u[qz] += DQQ[dz][qy][qx] * B[qz][dz];
|
||||
}
|
||||
}
|
||||
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(di,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
Bt[di][q] = b(q,di);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
u[qz] = 0;
|
||||
}
|
||||
MFEM_UNROLL(MQ1)
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
MFEM_UNROLL(MQ1)
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
u[qz] += QQQ[qz][qy][qx] * Bt[dx][qx];
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (ACCUMULATE)
|
||||
{
|
||||
y(dx,dy,dz,e) += u[dz];
|
||||
}
|
||||
else
|
||||
{
|
||||
y(dx,dy,dz,e) = u[dz];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
@@ -75,7 +75,7 @@ void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
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()->GetFaceGeometry(0))->GetDof();
|
||||
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);
|
||||
@@ -102,7 +102,7 @@ void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
{
|
||||
bfi->AssembleEAInteriorFaces(fes, ea_data_int, ea_data_ext, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
|
||||
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,
|
||||
@@ -146,7 +146,7 @@ void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
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()->GetFaceGeometry(0))->GetDof();
|
||||
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,
|
||||
@@ -165,7 +165,7 @@ void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
{
|
||||
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
{
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "../general/forall.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "qfunction.hpp"
|
||||
#include "ceed/integrators/diffusion/diffusion.hpp"
|
||||
|
||||
using namespace std;
|
||||
@@ -176,9 +175,43 @@ void VectorDiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
|
||||
MFEM_VERIFY(!VQ && !MQ,
|
||||
"Only scalar coefficient supported for partial assembly for VectorDiffusionIntegrator");
|
||||
Vector coeff;
|
||||
if (Q == nullptr)
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = 1.0;
|
||||
}
|
||||
else if (ConstantCoefficient* cQ = dynamic_cast<ConstantCoefficient*>(Q))
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = cQ->constant;
|
||||
}
|
||||
else if (QuadratureFunctionCoefficient* qfQ =
|
||||
dynamic_cast<QuadratureFunctionCoefficient*>(Q))
|
||||
{
|
||||
const QuadratureFunction &qFun = qfQ->GetQuadFunction();
|
||||
MFEM_VERIFY(qFun.Size() == ne*nq,
|
||||
"Incompatible QuadratureFunction dimension \n");
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(Q, qs, CoefficientStorage::COMPRESSED);
|
||||
MFEM_VERIFY(ir == &qFun.GetSpace()->GetElementIntRule(0),
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
qFun.Read();
|
||||
coeff.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
|
||||
}
|
||||
else
|
||||
{
|
||||
coeff.SetSize(nq * ne);
|
||||
auto Co = Reshape(coeff.HostWrite(), nq, ne);
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
ElementTransformation& T = *fes.GetElementTransformation(e);
|
||||
for (int q = 0; q < nq; ++q)
|
||||
{
|
||||
Co(q,e) = Q->Eval(T, ir->IntPoint(q));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Array<double> &w = ir->GetWeights();
|
||||
const Vector &j = geom->J;
|
||||
|
||||
+110
-23
@@ -11,7 +11,6 @@
|
||||
|
||||
#include "../general/forall.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
#include "qspace.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
|
||||
namespace mfem
|
||||
@@ -794,63 +793,140 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
trial_fetype = trial_el->GetDerivType();
|
||||
test_fetype = test_el->GetDerivType();
|
||||
|
||||
auto SMQ = dynamic_cast<SymmetricMatrixCoefficient *>(MQ);
|
||||
|
||||
const int MQsymmDim = SMQ ? (SMQ->GetSize() * (SMQ->GetSize() + 1)) / 2 : 0;
|
||||
const int MQfullDim = MQ ? (MQ->GetHeight() * MQ->GetWidth()) : 0;
|
||||
const int MQdim = SMQ ? MQsymmDim : MQfullDim;
|
||||
const int coeffDim = MQ ? MQdim : (DQ ? DQ->GetVDim() : 1);
|
||||
|
||||
symmetric = (SMQ || MQ == NULL);
|
||||
|
||||
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);
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(qs, CoefficientStorage::SYMMETRIC);
|
||||
if (Q) { coeff.Project(*Q); }
|
||||
else if (MQ) { coeff.ProjectTranspose(*MQ); }
|
||||
else if (DQ) { coeff.Project(*DQ); }
|
||||
else { coeff.SetConstant(1.0); }
|
||||
|
||||
const int coeff_dim = coeff.GetVDim();
|
||||
symmetric = (coeff_dim != dim*dim);
|
||||
|
||||
if ((trial_curl && test_div) || (trial_div && test_curl))
|
||||
pa_data.SetSize((coeff_dim == 1 ? 1 : dim*dim) * nq * ne,
|
||||
pa_data.SetSize((coeffDim == 1 ? 1 : dim*dim) * nq * ne,
|
||||
Device::GetMemoryType());
|
||||
else
|
||||
pa_data.SetSize((symmetric ? symmDims : dims*dims) * nq * ne,
|
||||
pa_data.SetSize((symmetric ? symmDims : MQfullDim) * nq * ne,
|
||||
Device::GetMemoryType());
|
||||
|
||||
Vector coeff;
|
||||
|
||||
auto *qf_c = dynamic_cast<QuadratureFunctionCoefficient*>(Q);
|
||||
if (qf_c)
|
||||
{
|
||||
const QuadratureFunction &qf = qf_c->GetQuadFunction();
|
||||
qf.Read();
|
||||
coeff.MakeRef(const_cast<QuadratureFunction&>(qf), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
coeff.SetSize(coeffDim * ne * nq);
|
||||
coeff = 1.0;
|
||||
auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
|
||||
if (Q || DQ || MQ)
|
||||
{
|
||||
Vector DM(DQ ? coeffDim : 0);
|
||||
DenseMatrix M;
|
||||
DenseSymmetricMatrix SM;
|
||||
|
||||
if (DQ)
|
||||
{
|
||||
MFEM_VERIFY(coeffDim == dim, "");
|
||||
}
|
||||
if (SMQ)
|
||||
{
|
||||
MFEM_VERIFY(SMQ->GetSize() == dim, "");
|
||||
SM.SetSize(dim);
|
||||
}
|
||||
else if (MQ)
|
||||
{
|
||||
MFEM_VERIFY(coeffDim == MQdim, "");
|
||||
MFEM_VERIFY(MQ->GetHeight() == dim && MQ->GetWidth() == dim, "");
|
||||
M.SetSize(dim);
|
||||
}
|
||||
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
if (SMQ)
|
||||
{
|
||||
SMQ->Eval(SM, *tr, ir->IntPoint(p));
|
||||
int cnt = 0;
|
||||
for (int i=0; i<dim; ++i)
|
||||
for (int j=i; j<dim; ++j, ++cnt)
|
||||
{
|
||||
coeffh(cnt, p, e) = SM(i,j);
|
||||
}
|
||||
}
|
||||
else if (MQ)
|
||||
{
|
||||
MQ->Eval(M, *tr, ir->IntPoint(p));
|
||||
|
||||
for (int i=0; i<dim; ++i)
|
||||
for (int j=0; j<dim; ++j)
|
||||
{
|
||||
coeffh(j+(i*dim), p, e) = M(i,j);
|
||||
}
|
||||
}
|
||||
else if (DQ)
|
||||
{
|
||||
DQ->Eval(DM, *tr, ir->IntPoint(p));
|
||||
for (int i=0; i<coeffDim; ++i)
|
||||
{
|
||||
coeffh(i, p, e) = DM[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
coeffh(0, p, e) = Q->Eval(*tr, ir->IntPoint(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trial_curl && test_curl && dim == 3)
|
||||
{
|
||||
PADiffusionSetup3D(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J,
|
||||
PADiffusionSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
|
||||
coeff, pa_data);
|
||||
}
|
||||
else if (trial_curl && test_curl && dim == 2)
|
||||
{
|
||||
PADiffusionSetup2D<2>(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J,
|
||||
PADiffusionSetup2D<2>(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
|
||||
coeff, pa_data);
|
||||
}
|
||||
else if (trial_div && test_div && dim == 3)
|
||||
{
|
||||
PAHdivSetup3D(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J,
|
||||
PAHdivSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
|
||||
coeff, pa_data);
|
||||
}
|
||||
else if (trial_div && test_div && dim == 2)
|
||||
{
|
||||
PAHdivSetup2D(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J,
|
||||
PAHdivSetup2D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
|
||||
coeff, pa_data);
|
||||
}
|
||||
else if (((trial_curl && test_div) || (trial_div && test_curl)) &&
|
||||
test_fel->GetOrder() == trial_fel->GetOrder())
|
||||
{
|
||||
if (coeff_dim == 1)
|
||||
if (coeffDim == 1)
|
||||
{
|
||||
PAHcurlL2Setup(nq, coeff_dim, ne, ir->GetWeights(), coeff, pa_data);
|
||||
PAHcurlL2Setup(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool tr = (trial_div && test_curl);
|
||||
if (dim == 3)
|
||||
PAHcurlHdivSetup3D(quad1D, coeff_dim, ne, tr, ir->GetWeights(),
|
||||
PAHcurlHdivSetup3D(quad1D, coeffDim, ne, tr, ir->GetWeights(),
|
||||
geom->J, coeff, pa_data);
|
||||
else
|
||||
PAHcurlHdivSetup2D(quad1D, coeff_dim, ne, tr, ir->GetWeights(),
|
||||
PAHcurlHdivSetup2D(quad1D, coeffDim, ne, tr, ir->GetWeights(),
|
||||
geom->J, coeff, pa_data);
|
||||
}
|
||||
}
|
||||
@@ -1092,8 +1168,19 @@ void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
|
||||
|
||||
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
|
||||
|
||||
QuadratureSpace qs(*mesh, *ir);
|
||||
CoefficientVector coeff(Q, qs, CoefficientStorage::FULL);
|
||||
Vector coeff(ne * nq);
|
||||
coeff = 1.0;
|
||||
if (Q)
|
||||
{
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use the same setup functions as VectorFEMassIntegrator.
|
||||
if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
|
||||
|
||||
@@ -112,7 +112,7 @@ static void InitBasisImpl(const FiniteElementSpace &fes,
|
||||
const bool tensor = dynamic_cast<const mfem::TensorBasisElement *>
|
||||
(&fe) != nullptr;
|
||||
|
||||
// Init or retrieve key values
|
||||
// Init or retreive key values
|
||||
if (basis_itr == mfem::internal::ceed_basis_map.end())
|
||||
{
|
||||
if ( tensor )
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "../../../linalg/dtensor.hpp"
|
||||
#include "../../../mesh/mesh.hpp"
|
||||
#include "../../gridfunc.hpp"
|
||||
#include "../../qfunction.hpp"
|
||||
#include "util.hpp"
|
||||
#include "ceed.hpp"
|
||||
|
||||
@@ -122,7 +121,7 @@ void InitCoefficient(mfem::Coefficient *Q, mfem::Mesh &mesh,
|
||||
MFEM_VERIFY(qFun.Size() == nq * ne,
|
||||
"Incompatible QuadratureFunction dimension \n");
|
||||
|
||||
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetIntRule(0),
|
||||
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetElementIntRule(0),
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
qFun.Read();
|
||||
@@ -196,7 +195,7 @@ void InitCoefficient(mfem::VectorCoefficient *VQ, mfem::Mesh &mesh,
|
||||
MFEM_VERIFY(qFun.Size() == dim * nq * ne,
|
||||
"Incompatible QuadratureFunction dimension \n");
|
||||
|
||||
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetIntRule(0),
|
||||
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetElementIntRule(0),
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
qFun.Read();
|
||||
@@ -280,7 +279,7 @@ void InitCoefficientWithIndices(mfem::Coefficient *Q, mfem::Mesh &mesh,
|
||||
MFEM_VERIFY(qFun.Size() == nq * ne,
|
||||
"Incompatible QuadratureFunction dimension \n");
|
||||
|
||||
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetIntRule(0),
|
||||
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetElementIntRule(0),
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
ceedCoeff->coeff.SetSize(nq * nelem);
|
||||
@@ -370,7 +369,7 @@ void InitCoefficientWithIndices(mfem::VectorCoefficient *VQ, mfem::Mesh &mesh,
|
||||
MFEM_VERIFY(qFun.Size() == dim * nq * ne,
|
||||
"Incompatible QuadratureFunction dimension \n");
|
||||
|
||||
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetIntRule(0),
|
||||
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetElementIntRule(0),
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
ceedCoeff->coeff.SetSize(dim * nq * nelem);
|
||||
|
||||
@@ -69,11 +69,9 @@ void Operator::Mult(const mfem::Vector &x, mfem::Vector &y) const
|
||||
#endif
|
||||
}
|
||||
|
||||
void Operator::AddMult(const mfem::Vector &x, mfem::Vector &y,
|
||||
const double a) const
|
||||
void Operator::AddMult(const mfem::Vector &x, mfem::Vector &y) const
|
||||
{
|
||||
#ifdef MFEM_USE_CEED
|
||||
MFEM_VERIFY(a == 1.0, "General coefficient case is not yet supported!");
|
||||
const CeedScalar *x_ptr;
|
||||
CeedScalar *y_ptr;
|
||||
CeedMemType mem;
|
||||
|
||||
@@ -38,8 +38,7 @@ public:
|
||||
Operator(CeedOperator op);
|
||||
#endif
|
||||
void Mult(const mfem::Vector &x, mfem::Vector &y) const override;
|
||||
void AddMult(const mfem::Vector &x, mfem::Vector &y,
|
||||
const double a = 1.0) const override;
|
||||
void AddMult(const mfem::Vector &x, mfem::Vector &y) const;
|
||||
void GetDiagonal(mfem::Vector &diag) const;
|
||||
using mfem::Operator::SetupRAP;
|
||||
virtual ~Operator()
|
||||
|
||||
@@ -232,7 +232,7 @@ void InitRestriction(const FiniteElementSpace &fes,
|
||||
RestrKey restr_key(&fes, nelem, P, ncomp, restr_type::Standard);
|
||||
auto restr_itr = mfem::internal::ceed_restr_map.find(restr_key);
|
||||
|
||||
// Init or retrieve key values
|
||||
// Init or retreive key values
|
||||
if (restr_itr == mfem::internal::ceed_restr_map.end())
|
||||
{
|
||||
InitRestrictionImpl(fes, ceed, restr);
|
||||
@@ -257,7 +257,7 @@ void InitRestrictionWithIndices(const FiniteElementSpace &fes,
|
||||
RestrKey restr_key(&fes, nelem, P, ncomp, restr_type::Standard);
|
||||
auto restr_itr = mfem::internal::ceed_restr_map.find(restr_key);
|
||||
|
||||
// Init or retrieve key values
|
||||
// Init or retreive key values
|
||||
if (restr_itr == mfem::internal::ceed_restr_map.end())
|
||||
{
|
||||
InitRestrictionWithIndicesImpl(fes, nelem, indices, ceed, restr);
|
||||
@@ -281,7 +281,7 @@ void InitCoeffRestrictionWithIndices(const FiniteElementSpace &fes,
|
||||
RestrKey restr_key(&fes, nelem, nquads, ncomp, restr_type::Coeff);
|
||||
auto restr_itr = mfem::internal::ceed_restr_map.find(restr_key);
|
||||
|
||||
// Init or retrieve key values
|
||||
// Init or retreive key values
|
||||
if (restr_itr == mfem::internal::ceed_restr_map.end())
|
||||
{
|
||||
InitCoeffRestrictionWithIndicesImpl(fes, nelem, indices, nquads, ncomp,
|
||||
|
||||
@@ -47,7 +47,6 @@ void InitRestrictionWithIndices(const FiniteElementSpace &fes,
|
||||
|
||||
/** @brief Initialize a strided CeedElemRestriction
|
||||
|
||||
@param[in] fes Input finite element space.
|
||||
@param[in] nelem is the number of elements.
|
||||
@param[in] nqpts is the total number of quadrature points.
|
||||
@param[in] qdatasize is the number of data per quadrature point.
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if !defined(_WIN32) || !defined(_MSC_VER)
|
||||
#ifndef _WIN32
|
||||
typedef struct stat struct_stat;
|
||||
#else
|
||||
#define stat(dir, buf) _stat(dir, buf)
|
||||
#define S_ISDIR(mode) (((mode) & _S_IFMT) == _S_IFDIR)
|
||||
#define S_ISDIR(mode) _S_IFDIR(mode)
|
||||
typedef struct _stat struct_stat;
|
||||
#endif
|
||||
|
||||
@@ -140,11 +140,7 @@ int CeedOperatorGetActiveField(CeedOperator oper, CeedOperatorField *field)
|
||||
CeedOperator *subops;
|
||||
if (isComposite)
|
||||
{
|
||||
#if CEED_VERSION_GE(0, 10, 2)
|
||||
ierr = CeedCompositeOperatorGetSubList(oper, &subops); CeedChk(ierr);
|
||||
#else
|
||||
ierr = CeedOperatorGetSubList(oper, &subops); CeedChk(ierr);
|
||||
#endif
|
||||
ierr = CeedOperatorGetQFunction(subops[0], &qf); CeedChk(ierr);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -275,14 +275,9 @@ CeedOperator CoarsenCeedCompositeOperator(
|
||||
&op_coarse); PCeedChk(ierr);
|
||||
|
||||
int nsub;
|
||||
CeedOperator *subops;
|
||||
#if CEED_VERSION_GE(0, 10, 2)
|
||||
ierr = CeedCompositeOperatorGetNumSub(op, &nsub); PCeedChk(ierr);
|
||||
ierr = CeedCompositeOperatorGetSubList(op, &subops); PCeedChk(ierr);
|
||||
#else
|
||||
ierr = CeedOperatorGetNumSub(op, &nsub); PCeedChk(ierr);
|
||||
CeedOperator *subops;
|
||||
ierr = CeedOperatorGetSubList(op, &subops); PCeedChk(ierr);
|
||||
#endif
|
||||
for (int isub=0; isub<nsub; ++isub)
|
||||
{
|
||||
CeedOperator subop = subops[isub];
|
||||
@@ -681,6 +676,7 @@ AlgebraicSpaceHierarchy::AlgebraicSpaceHierarchy(FiniteElementSpace &fes)
|
||||
const SparseMatrix *R = fespaces[ilevel+1]->GetRestrictionMatrix();
|
||||
if (R)
|
||||
{
|
||||
R->EnsureMultTranspose();
|
||||
R_tr[ilevel] = new TransposeOperator(*R);
|
||||
}
|
||||
else
|
||||
@@ -749,7 +745,7 @@ ParAlgebraicCoarseSpace::ParAlgebraicCoarseSpace(
|
||||
ldof_group.SetSize(lsize);
|
||||
ldof_group = 0;
|
||||
|
||||
const GroupTopology &group_topo = gc_fine->GetGroupTopology();
|
||||
GroupTopology &group_topo = gc_fine->GetGroupTopology();
|
||||
gc = new GroupCommunicator(group_topo);
|
||||
Table &group_ldof = gc->GroupLDofTable();
|
||||
group_ldof.MakeI(group_ldof_fine.Size());
|
||||
@@ -826,11 +822,11 @@ HypreParMatrix *ParAlgebraicCoarseSpace::GetProlongationHypreParMatrix()
|
||||
|
||||
ParMesh *pmesh = dynamic_cast<ParMesh*>(mesh);
|
||||
MFEM_VERIFY(pmesh != NULL, "");
|
||||
Array<HYPRE_BigInt> dof_offsets, tdof_offsets, tdof_nb_offsets;
|
||||
Array<HYPRE_BigInt> *offsets[2] = {&dof_offsets, &tdof_offsets};
|
||||
Array<HYPRE_Int> dof_offsets, tdof_offsets, tdof_nb_offsets;
|
||||
Array<HYPRE_Int> *offsets[2] = {&dof_offsets, &tdof_offsets};
|
||||
int lsize = P->Height();
|
||||
int ltsize = P->Width();
|
||||
HYPRE_BigInt loc_sizes[2] = {lsize, ltsize};
|
||||
HYPRE_Int loc_sizes[2] = {lsize, ltsize};
|
||||
pmesh->GenerateOffsets(2, loc_sizes, offsets);
|
||||
|
||||
MPI_Comm comm = pmesh->GetComm();
|
||||
@@ -874,12 +870,12 @@ HypreParMatrix *ParAlgebraicCoarseSpace::GetProlongationHypreParMatrix()
|
||||
HYPRE_Int *j_offd = Memory<HYPRE_Int>(lsize-ltsize);
|
||||
int offd_counter;
|
||||
|
||||
HYPRE_BigInt *cmap = Memory<HYPRE_BigInt>(lsize-ltsize);
|
||||
HYPRE_Int *cmap = Memory<HYPRE_Int>(lsize-ltsize);
|
||||
|
||||
HYPRE_BigInt *col_starts = tdof_offsets;
|
||||
HYPRE_BigInt *row_starts = dof_offsets;
|
||||
HYPRE_Int *col_starts = tdof_offsets;
|
||||
HYPRE_Int *row_starts = dof_offsets;
|
||||
|
||||
Array<Pair<HYPRE_BigInt, int> > cmap_j_offd(lsize-ltsize);
|
||||
Array<Pair<HYPRE_Int, int> > cmap_j_offd(lsize-ltsize);
|
||||
|
||||
i_diag[0] = i_offd[0] = 0;
|
||||
diag_counter = offd_counter = 0;
|
||||
@@ -913,7 +909,7 @@ HypreParMatrix *ParAlgebraicCoarseSpace::GetProlongationHypreParMatrix()
|
||||
i_offd[i_ldof+1] = offd_counter;
|
||||
}
|
||||
|
||||
SortPairs<HYPRE_BigInt, int>(cmap_j_offd, offd_counter);
|
||||
SortPairs<HYPRE_Int, int>(cmap_j_offd, offd_counter);
|
||||
|
||||
for (int i = 0; i < offd_counter; i++)
|
||||
{
|
||||
|
||||
@@ -310,13 +310,8 @@ int CeedOperatorFullAssemble(CeedOperator op, SparseMatrix **mat)
|
||||
{
|
||||
CeedInt numsub;
|
||||
CeedOperator *subops;
|
||||
#if CEED_VERSION_GE(0, 10, 2)
|
||||
CeedCompositeOperatorGetNumSub(op, &numsub);
|
||||
ierr = CeedCompositeOperatorGetSubList(op, &subops); CeedChk(ierr);
|
||||
#else
|
||||
CeedOperatorGetNumSub(op, &numsub);
|
||||
ierr = CeedOperatorGetSubList(op, &subops); CeedChk(ierr);
|
||||
#endif
|
||||
for (int i = 0; i < numsub; ++i)
|
||||
{
|
||||
ierr = CeedSingleOperatorFullAssemble(subops[i], out); CeedChk(ierr);
|
||||
|
||||
@@ -66,7 +66,6 @@ int CeedBasisATPMGCoarsen(CeedBasis basisin, CeedBasis* basisout,
|
||||
@param[in] coarse_er CeedElemRestriction for coarse operator
|
||||
(see CeedATPMGElemRestriction)
|
||||
@param[out] coarse_basis_out CeedBasis for coarser operator
|
||||
@param[out] basis_ctof_out CeedBasis describing interpolation from coarse to fine
|
||||
@param[out] out coarsened CeedOperator
|
||||
*/
|
||||
int CeedATPMGOperator(CeedOperator oper, int order_reduction,
|
||||
|
||||
+3
-316
@@ -48,31 +48,6 @@ ElementTransformation *RefinedToCoarse(
|
||||
return coarse_T;
|
||||
}
|
||||
|
||||
void Coefficient::Project(QuadratureFunction &qf)
|
||||
{
|
||||
QuadratureSpaceBase &qspace = *qf.GetSpace();
|
||||
const int ne = qspace.GetNE();
|
||||
Vector values;
|
||||
for (int iel = 0; iel < ne; ++iel)
|
||||
{
|
||||
qf.GetValues(iel, values);
|
||||
const IntegrationRule &ir = qspace.GetIntRule(iel);
|
||||
ElementTransformation& T = *qspace.GetTransformation(iel);
|
||||
for (int iq = 0; iq < ir.Size(); ++iq)
|
||||
{
|
||||
const IntegrationPoint &ip = ir[iq];
|
||||
T.SetIntPoint(&ip);
|
||||
const int iq_p = qspace.GetPermutedIndex(iel, iq);
|
||||
values[iq_p] = Eval(T, ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantCoefficient::Project(QuadratureFunction &qf)
|
||||
{
|
||||
qf = constant;
|
||||
}
|
||||
|
||||
double PWConstCoefficient::Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
@@ -160,11 +135,6 @@ double GridFunctionCoefficient::Eval (ElementTransformation &T,
|
||||
}
|
||||
}
|
||||
|
||||
void GridFunctionCoefficient::Project(QuadratureFunction &qf)
|
||||
{
|
||||
qf.ProjectGridFunction(*GridF);
|
||||
}
|
||||
|
||||
void TransformedCoefficient::SetTime(double t)
|
||||
{
|
||||
if (Q1) { Q1->SetTime(t); }
|
||||
@@ -233,29 +203,6 @@ void VectorCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
|
||||
}
|
||||
}
|
||||
|
||||
void VectorCoefficient::Project(QuadratureFunction &qf)
|
||||
{
|
||||
MFEM_VERIFY(vdim == qf.GetVDim(), "Wrong sizes.");
|
||||
QuadratureSpaceBase &qspace = *qf.GetSpace();
|
||||
const int ne = qspace.GetNE();
|
||||
DenseMatrix values;
|
||||
Vector col;
|
||||
for (int iel = 0; iel < ne; ++iel)
|
||||
{
|
||||
qf.GetValues(iel, values);
|
||||
const IntegrationRule &ir = qspace.GetIntRule(iel);
|
||||
ElementTransformation& T = *qspace.GetTransformation(iel);
|
||||
for (int iq = 0; iq < ir.Size(); ++iq)
|
||||
{
|
||||
const IntegrationPoint &ip = ir[iq];
|
||||
T.SetIntPoint(&ip);
|
||||
const int iq_p = qspace.GetPermutedIndex(iel, iq);
|
||||
values.GetColumnReference(iq_p, col);
|
||||
Eval(col, T, ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PWVectorCoefficient::InitMap(const Array<int> & attr,
|
||||
const Array<VectorCoefficient*> & coefs)
|
||||
{
|
||||
@@ -421,11 +368,6 @@ void VectorGridFunctionCoefficient::Eval(
|
||||
}
|
||||
}
|
||||
|
||||
void VectorGridFunctionCoefficient::Project(QuadratureFunction &qf)
|
||||
{
|
||||
qf.ProjectGridFunction(*GridFunc);
|
||||
}
|
||||
|
||||
GradientGridFunctionCoefficient::GradientGridFunctionCoefficient (
|
||||
const GridFunction *gf)
|
||||
: VectorCoefficient((gf) ?
|
||||
@@ -575,29 +517,6 @@ void VectorRestrictedCoefficient::Eval(
|
||||
}
|
||||
}
|
||||
|
||||
void MatrixCoefficient::Project(QuadratureFunction &qf, bool transpose)
|
||||
{
|
||||
MFEM_VERIFY(qf.GetVDim() == height*width, "Wrong sizes.");
|
||||
QuadratureSpaceBase &qspace = *qf.GetSpace();
|
||||
const int ne = qspace.GetNE();
|
||||
DenseMatrix values, matrix;
|
||||
for (int iel = 0; iel < ne; ++iel)
|
||||
{
|
||||
qf.GetValues(iel, values);
|
||||
const IntegrationRule &ir = qspace.GetIntRule(iel);
|
||||
ElementTransformation& T = *qspace.GetTransformation(iel);
|
||||
for (int iq = 0; iq < ir.Size(); ++iq)
|
||||
{
|
||||
const IntegrationPoint &ip = ir[iq];
|
||||
T.SetIntPoint(&ip);
|
||||
const int iq_p = qspace.GetPermutedIndex(iel, iq);
|
||||
matrix.UseExternalData(&values(0, iq_p), height, width);
|
||||
Eval(matrix, T, ip);
|
||||
if (transpose) { matrix.Transpose(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PWMatrixCoefficient::InitMap(const Array<int> & attr,
|
||||
const Array<MatrixCoefficient*> & coefs)
|
||||
{
|
||||
@@ -750,31 +669,6 @@ void MatrixFunctionCoefficient::EvalSymmetric(Vector &K,
|
||||
}
|
||||
}
|
||||
|
||||
void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
|
||||
{
|
||||
const int vdim = qf.GetVDim();
|
||||
MFEM_VERIFY(vdim == height*(height+1)/2, "Wrong sizes.");
|
||||
|
||||
QuadratureSpaceBase &qspace = *qf.GetSpace();
|
||||
const int ne = qspace.GetNE();
|
||||
DenseMatrix values;
|
||||
DenseSymmetricMatrix matrix;
|
||||
for (int iel = 0; iel < ne; ++iel)
|
||||
{
|
||||
qf.GetValues(iel, values);
|
||||
const IntegrationRule &ir = qspace.GetIntRule(iel);
|
||||
ElementTransformation& T = *qspace.GetTransformation(iel);
|
||||
for (int iq = 0; iq < ir.Size(); ++iq)
|
||||
{
|
||||
const IntegrationPoint &ip = ir[iq];
|
||||
T.SetIntPoint(&ip);
|
||||
matrix.UseExternalData(&values(0, iq), vdim);
|
||||
Eval(matrix, T, ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SymmetricMatrixCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
@@ -1543,12 +1437,12 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V,
|
||||
|
||||
if (index == 0 && vdim == QuadF.GetVDim())
|
||||
{
|
||||
QuadF.GetValues(T.ElementNo, ip.index, V);
|
||||
QuadF.GetElementValues(T.ElementNo, ip.index, V);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector temp;
|
||||
QuadF.GetValues(T.ElementNo, ip.index, temp);
|
||||
QuadF.GetElementValues(T.ElementNo, ip.index, temp);
|
||||
V.SetSize(vdim);
|
||||
for (int i = 0; i < vdim; i++)
|
||||
{
|
||||
@@ -1559,11 +1453,6 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V,
|
||||
return;
|
||||
}
|
||||
|
||||
void VectorQuadratureFunctionCoefficient::Project(QuadratureFunction &qf)
|
||||
{
|
||||
qf = QuadF;
|
||||
}
|
||||
|
||||
QuadratureFunctionCoefficient::QuadratureFunctionCoefficient(
|
||||
QuadratureFunction &qf) : QuadF(qf)
|
||||
{
|
||||
@@ -1575,210 +1464,8 @@ double QuadratureFunctionCoefficient::Eval(ElementTransformation &T,
|
||||
{
|
||||
QuadF.HostRead();
|
||||
Vector temp(1);
|
||||
QuadF.GetValues(T.ElementNo, ip.index, temp);
|
||||
QuadF.GetElementValues(T.ElementNo, ip.index, temp);
|
||||
return temp[0];
|
||||
}
|
||||
|
||||
void QuadratureFunctionCoefficient::Project(QuadratureFunction &qf)
|
||||
{
|
||||
qf = QuadF;
|
||||
}
|
||||
|
||||
|
||||
CoefficientVector::CoefficientVector(
|
||||
QuadratureSpaceBase &qs_, CoefficientStorage storage_)
|
||||
: Vector(), storage(storage_), vdim(0), qs(qs_), qf(NULL)
|
||||
{
|
||||
UseDevice(true);
|
||||
}
|
||||
|
||||
CoefficientVector::CoefficientVector(Coefficient *coeff,
|
||||
QuadratureSpaceBase &qs_,
|
||||
CoefficientStorage storage_)
|
||||
: CoefficientVector(qs_, storage_)
|
||||
{
|
||||
if (coeff == NULL)
|
||||
{
|
||||
SetConstant(1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Project(*coeff);
|
||||
}
|
||||
}
|
||||
|
||||
CoefficientVector::CoefficientVector(Coefficient &coeff,
|
||||
QuadratureSpaceBase &qs_,
|
||||
CoefficientStorage storage_)
|
||||
: CoefficientVector(qs_, storage_)
|
||||
{
|
||||
Project(coeff);
|
||||
}
|
||||
|
||||
CoefficientVector::CoefficientVector(VectorCoefficient &coeff,
|
||||
QuadratureSpaceBase &qs_,
|
||||
CoefficientStorage storage_)
|
||||
: CoefficientVector(qs_, storage_)
|
||||
{
|
||||
Project(coeff);
|
||||
}
|
||||
|
||||
CoefficientVector::CoefficientVector(MatrixCoefficient &coeff,
|
||||
QuadratureSpaceBase &qs_,
|
||||
CoefficientStorage storage_)
|
||||
: CoefficientVector(qs_, storage_)
|
||||
{
|
||||
Project(coeff);
|
||||
}
|
||||
|
||||
void CoefficientVector::Project(Coefficient &coeff)
|
||||
{
|
||||
vdim = 1;
|
||||
if (auto *const_coeff = dynamic_cast<ConstantCoefficient*>(&coeff))
|
||||
{
|
||||
SetConstant(const_coeff->constant);
|
||||
}
|
||||
else if (auto *qf_coeff = dynamic_cast<QuadratureFunctionCoefficient*>(&coeff))
|
||||
{
|
||||
MakeRef(qf_coeff->GetQuadFunction());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (qf == nullptr) { qf = new QuadratureFunction(qs); }
|
||||
qf->SetVDim(1);
|
||||
coeff.Project(*qf);
|
||||
Vector::MakeRef(*qf, 0, qf->Size());
|
||||
}
|
||||
}
|
||||
|
||||
void CoefficientVector::Project(VectorCoefficient &coeff)
|
||||
{
|
||||
vdim = coeff.GetVDim();
|
||||
if (auto *const_coeff = dynamic_cast<VectorConstantCoefficient*>(&coeff))
|
||||
{
|
||||
SetConstant(const_coeff->GetVec());
|
||||
}
|
||||
else if (auto *qf_coeff =
|
||||
dynamic_cast<VectorQuadratureFunctionCoefficient*>(&coeff))
|
||||
{
|
||||
MakeRef(qf_coeff->GetQuadFunction());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (qf == nullptr) { qf = new QuadratureFunction(qs, vdim); }
|
||||
qf->SetVDim(vdim);
|
||||
coeff.Project(*qf);
|
||||
Vector::MakeRef(*qf, 0, qf->Size());
|
||||
}
|
||||
}
|
||||
|
||||
void CoefficientVector::Project(MatrixCoefficient &coeff, bool transpose)
|
||||
{
|
||||
if (auto *const_coeff = dynamic_cast<MatrixConstantCoefficient*>(&coeff))
|
||||
{
|
||||
SetConstant(const_coeff->GetMatrix());
|
||||
}
|
||||
else if (auto *const_sym_coeff =
|
||||
dynamic_cast<SymmetricMatrixConstantCoefficient*>(&coeff))
|
||||
{
|
||||
SetConstant(const_sym_coeff->GetMatrix());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto *sym_coeff = dynamic_cast<SymmetricMatrixCoefficient*>(&coeff);
|
||||
const bool sym = sym_coeff && (storage & CoefficientStorage::SYMMETRIC);
|
||||
const int height = coeff.GetHeight();
|
||||
const int width = coeff.GetWidth();
|
||||
vdim = sym ? height*(height + 1)/2 : width*height;
|
||||
|
||||
if (qf == nullptr) { qf = new QuadratureFunction(qs, vdim); }
|
||||
qf->SetVDim(vdim);
|
||||
if (sym) { sym_coeff->ProjectSymmetric(*qf); }
|
||||
else { coeff.Project(*qf, transpose); }
|
||||
Vector::MakeRef(*qf, 0, qf->Size());
|
||||
}
|
||||
}
|
||||
|
||||
void CoefficientVector::ProjectTranspose(MatrixCoefficient &coeff)
|
||||
{
|
||||
Project(coeff, true);
|
||||
}
|
||||
|
||||
void CoefficientVector::MakeRef(const QuadratureFunction &qf_)
|
||||
{
|
||||
vdim = qf_.GetVDim();
|
||||
const QuadratureSpaceBase *qs2 = qf_.GetSpace();
|
||||
MFEM_CONTRACT_VAR(qs2); // qs2 used only for asserts
|
||||
MFEM_VERIFY(qs2 != NULL, "Invalid QuadratureSpace.")
|
||||
MFEM_VERIFY(qs2->GetMesh() == qs.GetMesh(), "Meshes differ.");
|
||||
MFEM_VERIFY(qs2->GetOrder() == qs.GetOrder(), "Orders differ.");
|
||||
Vector::MakeRef(const_cast<QuadratureFunction&>(qf_), 0, qf_.Size());
|
||||
}
|
||||
|
||||
void CoefficientVector::SetConstant(double constant)
|
||||
{
|
||||
const int nq = (storage & CoefficientStorage::CONSTANTS) ? 1 : qs.GetSize();
|
||||
vdim = 1;
|
||||
SetSize(nq);
|
||||
Vector::operator=(constant);
|
||||
}
|
||||
|
||||
void CoefficientVector::SetConstant(const Vector &constant)
|
||||
{
|
||||
const int nq = (storage & CoefficientStorage::CONSTANTS) ? 1 : qs.GetSize();
|
||||
vdim = constant.Size();
|
||||
SetSize(nq*vdim);
|
||||
for (int iq = 0; iq < nq; ++iq)
|
||||
{
|
||||
for (int vd = 0; vd<vdim; ++vd)
|
||||
{
|
||||
(*this)[vd + iq*vdim] = constant[vd];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CoefficientVector::SetConstant(const DenseMatrix &constant)
|
||||
{
|
||||
const int nq = (storage & CoefficientStorage::CONSTANTS) ? 1 : qs.GetSize();
|
||||
const int width = constant.Width();
|
||||
const int height = constant.Height();
|
||||
vdim = width*height;
|
||||
SetSize(nq*vdim);
|
||||
for (int iq = 0; iq < nq; ++iq)
|
||||
{
|
||||
for (int j = 0; j < width; ++j)
|
||||
{
|
||||
for (int i = 0; i < height; ++i)
|
||||
{
|
||||
(*this)[i + j*height + iq*vdim] = constant(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CoefficientVector::SetConstant(const DenseSymmetricMatrix &constant)
|
||||
{
|
||||
const int nq = (storage & CoefficientStorage::CONSTANTS) ? 1 : qs.GetSize();
|
||||
const int height = constant.Height();
|
||||
const bool sym = storage & CoefficientStorage::SYMMETRIC;
|
||||
vdim = sym ? height*(height + 1)/2 : height*height;
|
||||
SetSize(nq*vdim);
|
||||
for (int iq = 0; iq < nq; ++iq)
|
||||
{
|
||||
for (int vd = 0; vd < vdim; ++vd)
|
||||
{
|
||||
const double value = sym ? constant.GetData()[vd] : constant(vd % height,
|
||||
vd / height);
|
||||
(*this)[vd + iq*vdim] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CoefficientVector::GetVDim() const { return vdim; }
|
||||
|
||||
CoefficientVector::~CoefficientVector()
|
||||
{
|
||||
delete qf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-171
@@ -23,8 +23,6 @@ namespace mfem
|
||||
{
|
||||
|
||||
class Mesh;
|
||||
class QuadratureSpaceBase;
|
||||
class QuadratureFunction;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
class ParMesh;
|
||||
@@ -72,10 +70,6 @@ public:
|
||||
return Eval(T, ip);
|
||||
}
|
||||
|
||||
/// @brief Fill the QuadratureFunction @a qf by evaluating the coefficient at
|
||||
/// the quadrature points.
|
||||
virtual void Project(QuadratureFunction &qf);
|
||||
|
||||
virtual ~Coefficient() { }
|
||||
};
|
||||
|
||||
@@ -93,9 +87,6 @@ public:
|
||||
virtual double Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{ return (constant); }
|
||||
|
||||
/// Fill the QuadratureFunction @a qf with the constant value.
|
||||
void Project(QuadratureFunction &qf);
|
||||
};
|
||||
|
||||
/** @brief A piecewise constant coefficient with the constants keyed
|
||||
@@ -283,13 +274,6 @@ public:
|
||||
/// Evaluate the coefficient at @a ip.
|
||||
virtual double Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
/// @brief Fill the QuadratureFunction @a qf by evaluating the coefficient at
|
||||
/// the quadrature points.
|
||||
///
|
||||
/// This function uses the efficient QuadratureFunction::ProjectGridFunction
|
||||
/// to fill the QuadratureFunction.
|
||||
virtual void Project(QuadratureFunction &qf);
|
||||
};
|
||||
|
||||
|
||||
@@ -487,13 +471,6 @@ public:
|
||||
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
|
||||
const IntegrationRule &ir);
|
||||
|
||||
/// @brief Fill the QuadratureFunction @a qf by evaluating the coefficient at
|
||||
/// the quadrature points.
|
||||
///
|
||||
/// The @a vdim of the VectorCoefficient should be equal to the @a vdim of
|
||||
/// the QuadratureFunction.
|
||||
virtual void Project(QuadratureFunction &qf);
|
||||
|
||||
virtual ~VectorCoefficient() { }
|
||||
};
|
||||
|
||||
@@ -514,7 +491,7 @@ public:
|
||||
const IntegrationPoint &ip) { V = vec; }
|
||||
|
||||
/// Return a reference to the constant vector in this class.
|
||||
const Vector& GetVec() const { return vec; }
|
||||
const Vector& GetVec() { return vec; }
|
||||
};
|
||||
|
||||
/** @brief A piecewise vector-valued coefficient with the pieces keyed off the
|
||||
@@ -711,13 +688,6 @@ public:
|
||||
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
|
||||
const IntegrationRule &ir);
|
||||
|
||||
/// @brief Fill the QuadratureFunction @a qf by evaluating the coefficient at
|
||||
/// the quadrature points.
|
||||
///
|
||||
/// This function uses the efficient QuadratureFunction::ProjectGridFunction
|
||||
/// to fill the QuadratureFunction.
|
||||
virtual void Project(QuadratureFunction &qf);
|
||||
|
||||
virtual ~VectorGridFunctionCoefficient() { }
|
||||
};
|
||||
|
||||
@@ -945,14 +915,6 @@ public:
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip) = 0;
|
||||
|
||||
/// @brief Fill the QuadratureFunction @a qf by evaluating the coefficient at
|
||||
/// the quadrature points. The matrix will be transposed or not according to
|
||||
/// the boolean argument @a transpose.
|
||||
///
|
||||
/// The @a vdim of the QuadratureFunction should be equal to the height times
|
||||
/// the width of the matrix.
|
||||
virtual void Project(QuadratureFunction &qf, bool transpose=false);
|
||||
|
||||
/// (DEPRECATED) Evaluate a symmetric matrix coefficient.
|
||||
/** @brief Evaluate the upper triangular entries of the matrix coefficient
|
||||
in the symmetric case, similarly to Eval. Matrix entry (i,j) is stored
|
||||
@@ -981,8 +943,6 @@ public:
|
||||
/// Evaluate the matrix coefficient at @a ip.
|
||||
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
|
||||
const IntegrationPoint &ip) { M = mat; }
|
||||
/// Return a reference to the constant matrix.
|
||||
const DenseMatrix& GetMatrix() { return mat; }
|
||||
};
|
||||
|
||||
|
||||
@@ -1186,8 +1146,6 @@ public:
|
||||
can be overridden with the @a own parameter. */
|
||||
void Set(int i, int j, Coefficient * c, bool own=true);
|
||||
|
||||
using MatrixCoefficient::Eval;
|
||||
|
||||
/// Evaluate coefficient located at (i,j) in the matrix using integration
|
||||
/// point @a ip.
|
||||
double Eval(int i, int j, ElementTransformation &T, const IntegrationPoint &ip)
|
||||
@@ -1302,15 +1260,6 @@ public:
|
||||
/// Get the size of the matrix.
|
||||
int GetSize() const { return height; }
|
||||
|
||||
/// @brief Fill the QuadratureFunction @a qf by evaluating the coefficient at
|
||||
/// the quadrature points.
|
||||
///
|
||||
/// @note As opposed to MatrixCoefficient::Project, this function stores only
|
||||
/// the @a symmetric part of the matrix at each quadrature point.
|
||||
///
|
||||
/// The @a vdim of the coefficient should be equal to height*(height+1)/2.
|
||||
virtual void ProjectSymmetric(QuadratureFunction &qf);
|
||||
|
||||
/** @brief Evaluate the matrix coefficient in the element described by @a T
|
||||
at the point @a ip, storing the result as a symmetric matrix @a K. */
|
||||
/** @note When this method is called, the caller must make sure that the
|
||||
@@ -1319,6 +1268,7 @@ public:
|
||||
virtual void Eval(DenseSymmetricMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip) = 0;
|
||||
|
||||
using MatrixCoefficient::Eval;
|
||||
/** @brief Evaluate the matrix coefficient in the element described by @a T
|
||||
at the point @a ip, storing the result as a dense matrix @a K. */
|
||||
/** This function allows the use of SymmetricMatrixCoefficient in situations
|
||||
@@ -1330,9 +1280,6 @@ public:
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
/// Return a reference to the constant matrix.
|
||||
const DenseSymmetricMatrix& GetMatrix() { return mat; }
|
||||
|
||||
virtual ~SymmetricMatrixCoefficient() { }
|
||||
};
|
||||
|
||||
@@ -1347,6 +1294,7 @@ public:
|
||||
///Construct using matrix @a m for the constant.
|
||||
SymmetricMatrixConstantCoefficient(const DenseSymmetricMatrix &m)
|
||||
: SymmetricMatrixCoefficient(m.Height()), mat(m) { }
|
||||
using MatrixCoefficient::Eval;
|
||||
using SymmetricMatrixCoefficient::Eval;
|
||||
/// Evaluate the matrix coefficient at @a ip.
|
||||
virtual void Eval(DenseSymmetricMatrix &M, ElementTransformation &T,
|
||||
@@ -1398,6 +1346,7 @@ public:
|
||||
/// Set the time for internally stored coefficients
|
||||
void SetTime(double t);
|
||||
|
||||
using MatrixCoefficient::Eval;
|
||||
using SymmetricMatrixCoefficient::Eval;
|
||||
/// Evaluate the matrix coefficient at @a ip.
|
||||
virtual void Eval(DenseSymmetricMatrix &K, ElementTransformation &T,
|
||||
@@ -2100,6 +2049,8 @@ public:
|
||||
};
|
||||
///@}
|
||||
|
||||
class QuadratureFunction;
|
||||
|
||||
/** @brief Vector quadrature function coefficient which requires that the
|
||||
quadrature rules used for this vector coefficient be the same as those that
|
||||
live within the supplied QuadratureFunction. */
|
||||
@@ -2124,8 +2075,6 @@ public:
|
||||
virtual void Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
virtual void Project(QuadratureFunction &qf);
|
||||
|
||||
virtual ~VectorQuadratureFunctionCoefficient() { }
|
||||
};
|
||||
|
||||
@@ -2145,123 +2094,9 @@ public:
|
||||
|
||||
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
|
||||
|
||||
virtual void Project(QuadratureFunction &qf);
|
||||
|
||||
virtual ~QuadratureFunctionCoefficient() { }
|
||||
};
|
||||
|
||||
/// Flags that determine what storage optimizations to use in CoefficientVector
|
||||
enum class CoefficientStorage : int
|
||||
{
|
||||
FULL = 0, ///< Store the coefficient as a full QuadratureFunction.
|
||||
CONSTANTS = 1 << 0, ///< Store constants using only @a vdim entries.
|
||||
SYMMETRIC = 1 << 1, ///< Store the triangular part of symmetric matrices.
|
||||
COMPRESSED = CONSTANTS | SYMMETRIC ///< Enable all above compressions.
|
||||
};
|
||||
|
||||
inline CoefficientStorage operator|(CoefficientStorage a, CoefficientStorage b)
|
||||
{
|
||||
return CoefficientStorage(int(a) | int(b));
|
||||
}
|
||||
|
||||
inline int operator&(CoefficientStorage a, CoefficientStorage b)
|
||||
{
|
||||
return int(a) & int(b);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Class to represent a coefficient evaluated at quadrature points.
|
||||
///
|
||||
/// In the general case, a CoefficientVector is the same as a QuadratureFunction
|
||||
/// with a coefficient projected onto it.
|
||||
///
|
||||
/// This class allows for some "compression" of the coefficient data, according
|
||||
/// to the storage flags given by CoefficientStorage. For example, constant
|
||||
/// coefficients can be stored using only @a vdim values, and symmetric matrices
|
||||
/// can be stored using e.g. the upper triangular part of the matrix.
|
||||
class CoefficientVector : public Vector
|
||||
{
|
||||
protected:
|
||||
CoefficientStorage storage; ///< Storage optimizations (see CoefficientStorage).
|
||||
int vdim; ///< Number of values per quadrature point.
|
||||
QuadratureSpaceBase &qs; ///< Associated QuadratureSpaceBase.
|
||||
QuadratureFunction *qf; ///< Internal QuadratureFunction (owned, may be NULL).
|
||||
public:
|
||||
/// Create an empty CoefficientVector.
|
||||
CoefficientVector(QuadratureSpaceBase &qs_,
|
||||
CoefficientStorage storage_ = CoefficientStorage::FULL);
|
||||
|
||||
/// @brief Create a CoefficientVector from the given Coefficient and
|
||||
/// QuadratureSpaceBase.
|
||||
///
|
||||
/// If @a coeff is NULL, it will be interpreted as a constant with value one.
|
||||
/// @sa CoefficientStorage for a description of @a storage_.
|
||||
CoefficientVector(Coefficient *coeff, QuadratureSpaceBase &qs,
|
||||
CoefficientStorage storage_ = CoefficientStorage::FULL);
|
||||
|
||||
/// @brief Create a CoefficientVector from the given Coefficient and
|
||||
/// QuadratureSpaceBase.
|
||||
///
|
||||
/// @sa CoefficientStorage for a description of @a storage_.
|
||||
CoefficientVector(Coefficient &coeff, QuadratureSpaceBase &qs,
|
||||
CoefficientStorage storage_ = CoefficientStorage::FULL);
|
||||
|
||||
/// @brief Create a CoefficientVector from the given VectorCoefficient and
|
||||
/// QuadratureSpaceBase.
|
||||
///
|
||||
/// @sa CoefficientStorage for a description of @a storage_.
|
||||
CoefficientVector(VectorCoefficient &coeff, QuadratureSpaceBase &qs,
|
||||
CoefficientStorage storage_ = CoefficientStorage::FULL);
|
||||
|
||||
/// @brief Create a CoefficientVector from the given MatrixCoefficient and
|
||||
/// QuadratureSpaceBase.
|
||||
///
|
||||
/// @sa CoefficientStorage for a description of @a storage_.
|
||||
CoefficientVector(MatrixCoefficient &coeff, QuadratureSpaceBase &qs,
|
||||
CoefficientStorage storage_ = CoefficientStorage::FULL);
|
||||
|
||||
/// @brief Evaluate the given Coefficient at the quadrature points defined by
|
||||
/// @ref qs.
|
||||
void Project(Coefficient &coeff);
|
||||
|
||||
/// @brief Evaluate the given VectorCoefficient at the quadrature points
|
||||
/// defined by @ref qs.
|
||||
///
|
||||
/// @sa CoefficientVector for a description of the @a compress argument.
|
||||
void Project(VectorCoefficient &coeff);
|
||||
|
||||
/// @brief Evaluate the given MatrixCoefficient at the quadrature points
|
||||
/// defined by @ref qs.
|
||||
///
|
||||
/// @sa CoefficientVector for a description of the @a compress argument.
|
||||
void Project(MatrixCoefficient &coeff, bool transpose=false);
|
||||
|
||||
/// @brief Project the transpose of @a coeff.
|
||||
///
|
||||
/// @sa Project(MatrixCoefficient&, QuadratureSpace&, bool, bool)
|
||||
void ProjectTranspose(MatrixCoefficient &coeff);
|
||||
|
||||
/// Make this vector a reference to the given QuadratureFunction.
|
||||
void MakeRef(const QuadratureFunction &qf_);
|
||||
|
||||
/// Set this vector to the given constant.
|
||||
void SetConstant(double constant);
|
||||
|
||||
/// Set this vector to the given constant vector.
|
||||
void SetConstant(const Vector &constant);
|
||||
|
||||
/// Set this vector to the given constant matrix.
|
||||
void SetConstant(const DenseMatrix &constant);
|
||||
|
||||
/// Set this vector to the given constant symmetric matrix.
|
||||
void SetConstant(const DenseSymmetricMatrix &constant);
|
||||
|
||||
/// Return the number of values per quadrature point.
|
||||
int GetVDim() const;
|
||||
|
||||
~CoefficientVector();
|
||||
};
|
||||
|
||||
/** @brief Compute the Lp norm of a function f.
|
||||
\f$ \| f \|_{Lp} = ( \int_\Omega | f |^p d\Omega)^{1/p} \f$ */
|
||||
double ComputeLpNorm(double p, Coefficient &coeff, Mesh &mesh,
|
||||
|
||||
+19
-22
@@ -110,8 +110,8 @@ DataCollection::DataCollection(const std::string& collection_name, Mesh *mesh_)
|
||||
precision = precision_default;
|
||||
pad_digits_cycle = pad_digits_rank = pad_digits_default;
|
||||
format = SERIAL_FORMAT; // use serial mesh format
|
||||
compression = 0;
|
||||
error = No_Error;
|
||||
compression = false;
|
||||
error = NO_ERROR;
|
||||
}
|
||||
|
||||
void DataCollection::SetMesh(Mesh *new_mesh)
|
||||
@@ -442,7 +442,7 @@ void VisItDataCollection::RegisterQField(const std::string& name,
|
||||
{
|
||||
int locLOD = GlobGeometryRefiner.GetRefinementLevelFromElems(
|
||||
mesh->GetElementBaseGeometry(e),
|
||||
qf->GetIntRule(e).GetNPoints());
|
||||
qf->GetElementIntRule(e).GetNPoints());
|
||||
|
||||
LOD = std::max(LOD,locLOD);
|
||||
}
|
||||
@@ -494,7 +494,7 @@ void VisItDataCollection::Load(int cycle_)
|
||||
{
|
||||
DeleteAll();
|
||||
time_step = 0.0;
|
||||
error = No_Error;
|
||||
error = NO_ERROR;
|
||||
cycle = cycle_;
|
||||
std::string root_name = prefix_path + name + "_" +
|
||||
to_padded_string(cycle, pad_digits_cycle) +
|
||||
@@ -724,7 +724,7 @@ void VisItDataCollection::ParseVisItRootString(const std::string& json)
|
||||
|
||||
// Set the DataCollection::name using the mesh path
|
||||
std::string path = mesh.get("path").get<std::string>();
|
||||
size_t right_sep = path.rfind('_');
|
||||
size_t right_sep = path.find('_');
|
||||
if (right_sep == std::string::npos)
|
||||
{
|
||||
error = READ_ERROR;
|
||||
@@ -767,13 +767,10 @@ ParaViewDataCollection::ParaViewDataCollection(const std::string&
|
||||
high_order_output(false),
|
||||
restart_mode(false)
|
||||
{
|
||||
cycle = 0; // always include a valid cycle index in file names
|
||||
|
||||
compression_level = -1; // default zlib compression level, equivalent to 6
|
||||
#ifdef MFEM_USE_ZLIB
|
||||
compression = true; // if we have zlib, enable compression
|
||||
compression = -1; // default zlib compression level, equivalent to 6
|
||||
#else
|
||||
compression = false; // otherwise, disable compression
|
||||
compression = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -922,7 +919,7 @@ void ParaViewDataCollection::Save()
|
||||
{
|
||||
const std::string &field_name = qfield.first;
|
||||
std::ofstream os(vtu_prefix + GenerateVTUFileName(field_name, myid));
|
||||
qfield.second->SaveVTU(os, pv_data_format, GetCompressionLevel());
|
||||
qfield.second->SaveVTU(os, pv_data_format, compression);
|
||||
}
|
||||
|
||||
// MPI rank 0 also creates a "PVTU" file that points to all of the separately
|
||||
@@ -1036,13 +1033,13 @@ void ParaViewDataCollection::WritePVTUFooter(std::ostream &os,
|
||||
void ParaViewDataCollection::SaveDataVTU(std::ostream &os, int ref)
|
||||
{
|
||||
os << "<VTKFile type=\"UnstructuredGrid\"";
|
||||
if (GetCompressionLevel() != 0)
|
||||
if (compression != 0)
|
||||
{
|
||||
os << " compressor=\"vtkZLibDataCompressor\"";
|
||||
}
|
||||
os << " version=\"0.1\" byte_order=\"" << VTKByteOrder() << "\">\n";
|
||||
os << "<UnstructuredGrid>\n";
|
||||
mesh->PrintVTU(os,ref,pv_data_format,high_order_output,GetCompressionLevel());
|
||||
mesh->PrintVTU(os,ref,pv_data_format,high_order_output,compression);
|
||||
|
||||
// dump out the grid functions as point data
|
||||
os << "<PointData >\n";
|
||||
@@ -1106,7 +1103,7 @@ void ParaViewDataCollection::SaveGFieldVTU(std::ostream &os, int ref_,
|
||||
|
||||
if (IsBinaryFormat())
|
||||
{
|
||||
WriteVTKEncodedCompressed(os,buf.data(),buf.size(),GetCompressionLevel());
|
||||
WriteVTKEncodedCompressed(os,buf.data(),buf.size(),compression);
|
||||
os << '\n';
|
||||
}
|
||||
os << "</DataArray>" << std::endl;
|
||||
@@ -1131,13 +1128,18 @@ void ParaViewDataCollection::SetCompressionLevel(int compression_level_)
|
||||
{
|
||||
MFEM_ASSERT(compression_level_ >= -1 && compression_level_ <= 9,
|
||||
"Compression level must be between -1 and 9 (inclusive).");
|
||||
compression_level = compression_level_;
|
||||
compression = compression_level_ != 0;
|
||||
compression = compression_level_;
|
||||
}
|
||||
|
||||
void ParaViewDataCollection::SetCompression(bool compression_)
|
||||
{
|
||||
compression = compression_;
|
||||
// If we are enabling compression, and it was disabled previously, use the
|
||||
// default compression level. Otherwise, leave the compression level
|
||||
// unchanged.
|
||||
if (compression_ && compression == 0)
|
||||
{
|
||||
SetCompressionLevel(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void ParaViewDataCollection::UseRestartMode(bool restart_mode_)
|
||||
@@ -1169,9 +1171,4 @@ const char *ParaViewDataCollection::GetDataTypeString() const
|
||||
}
|
||||
}
|
||||
|
||||
int ParaViewDataCollection::GetCompressionLevel() const
|
||||
{
|
||||
return compression ? compression_level : 0;
|
||||
}
|
||||
|
||||
} // end namespace MFEM
|
||||
|
||||
+18
-55
@@ -14,7 +14,6 @@
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "qfunction.hpp"
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include "pgridfunc.hpp"
|
||||
#endif
|
||||
@@ -338,12 +337,11 @@ public:
|
||||
/// Set the precision (number of digits) used for the text output of doubles
|
||||
void SetPrecision(int prec) { precision = prec; }
|
||||
/// Set the number of digits used for both the cycle and the MPI rank
|
||||
virtual void SetPadDigits(int digits)
|
||||
{ pad_digits_cycle=pad_digits_rank = digits; }
|
||||
void SetPadDigits(int digits) { pad_digits_cycle=pad_digits_rank = digits; }
|
||||
/// Set the number of digits used for the cycle
|
||||
virtual void SetPadDigitsCycle(int digits) { pad_digits_cycle = digits; }
|
||||
void SetPadDigitsCycle(int digits) { pad_digits_cycle = digits; }
|
||||
/// Set the number of digits used for the MPI rank in filenames
|
||||
virtual void SetPadDigitsRank(int digits) { pad_digits_rank = digits; }
|
||||
void SetPadDigitsRank(int digits) { pad_digits_rank = digits; }
|
||||
/// Set the desired output mesh and data format.
|
||||
/** See the enumeration #Format for valid options. Derived classes can define
|
||||
their own format enumerations and override this method to perform input
|
||||
@@ -378,24 +376,12 @@ public:
|
||||
virtual ~DataCollection();
|
||||
|
||||
/// Errors returned by Error()
|
||||
enum
|
||||
{
|
||||
// Workaround for use with headers that define NO_ERROR as a macro,
|
||||
// e.g. winerror.h (which is included by Windows.h):
|
||||
#ifndef NO_ERROR
|
||||
NO_ERROR = 0,
|
||||
#endif
|
||||
// Use the following identifier if NO_ERROR is defined as a macro,
|
||||
// e.g. winerror.h (which is included by Windows.h):
|
||||
No_Error = 0,
|
||||
READ_ERROR = 1,
|
||||
WRITE_ERROR = 2
|
||||
};
|
||||
enum { NO_ERROR = 0, READ_ERROR = 1, WRITE_ERROR = 2 };
|
||||
|
||||
/// Get the current error state
|
||||
int Error() const { return error; }
|
||||
/// Reset the error state
|
||||
void ResetError(int err_state = No_Error) { error = err_state; }
|
||||
void ResetError(int err_state = NO_ERROR) { error = err_state; }
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
friend class ParMesh;
|
||||
@@ -454,29 +440,21 @@ public:
|
||||
#endif
|
||||
|
||||
/// Set/change the mesh associated with the collection
|
||||
virtual void SetMesh(Mesh *new_mesh) override;
|
||||
virtual void SetMesh(Mesh *new_mesh);
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
/// Set/change the mesh associated with the collection.
|
||||
virtual void SetMesh(MPI_Comm comm, Mesh *new_mesh) override;
|
||||
virtual void SetMesh(MPI_Comm comm, Mesh *new_mesh);
|
||||
#endif
|
||||
|
||||
/// Add a grid function to the collection and update the root file
|
||||
virtual void RegisterField(const std::string& field_name,
|
||||
GridFunction *gf) override;
|
||||
virtual void RegisterField(const std::string& field_name, GridFunction *gf);
|
||||
|
||||
/// Add a quadrature function to the collection and update the root file.
|
||||
/** Visualization of quadrature function is not supported in VisIt(3.12).
|
||||
A patch has been sent to VisIt developers in June 2020. */
|
||||
virtual void RegisterQField(const std::string& q_field_name,
|
||||
QuadratureFunction *qf) override;
|
||||
|
||||
/// Set the number of digits used for both the cycle and the MPI rank
|
||||
/// @note VisIt seems to require 6 pad digits for the MPI rank. Therefore,
|
||||
/// this function uses this default value. This behavior can be overridden
|
||||
/// by calling SetPadDigitsCycle() and SetPadDigitsRank() instead.
|
||||
virtual void SetPadDigits(int digits) override
|
||||
{ pad_digits_cycle=digits; pad_digits_rank=6; }
|
||||
QuadratureFunction *qf);
|
||||
|
||||
/// Set VisIt parameter: default levels of detail for the MultiresControl
|
||||
void SetLevelsOfDetail(int levels_of_detail);
|
||||
@@ -489,13 +467,13 @@ public:
|
||||
void DeleteAll();
|
||||
|
||||
/// Save the collection and a VisIt root file
|
||||
virtual void Save() override;
|
||||
virtual void Save();
|
||||
|
||||
/// Save a VisIt root file for the collection
|
||||
void SaveRootFile();
|
||||
|
||||
/// Load the collection based on its VisIt data (described in its root file)
|
||||
virtual void Load(int cycle_ = 0) override;
|
||||
virtual void Load(int cycle_ = 0);
|
||||
|
||||
/// We will delete the mesh and fields if we own them
|
||||
virtual ~VisItDataCollection() {}
|
||||
@@ -507,7 +485,6 @@ class ParaViewDataCollection : public DataCollection
|
||||
{
|
||||
private:
|
||||
int levels_of_detail;
|
||||
int compression_level;
|
||||
std::fstream pvd_stream;
|
||||
VTKFormat pv_data_format;
|
||||
bool high_order_output;
|
||||
@@ -520,9 +497,6 @@ protected:
|
||||
void SaveGFieldVTU(std::ostream& out, int ref_, const FieldMapIterator& it);
|
||||
const char *GetDataFormatString() const;
|
||||
const char *GetDataTypeString() const;
|
||||
/// @brief If compression is enabled, return the compression level, otherwise
|
||||
/// return 0.
|
||||
int GetCompressionLevel() const;
|
||||
|
||||
std::string GenerateCollectionPath();
|
||||
std::string GenerateVTUFileName(const std::string &prefix, int rank);
|
||||
@@ -541,7 +515,7 @@ public:
|
||||
mfem::Mesh *mesh_ = NULL);
|
||||
|
||||
/// Set refinement levels - every element is uniformly split based on
|
||||
/// levels_of_detail_. The initial value is 1.
|
||||
/// levels_of_detail_
|
||||
void SetLevelsOfDetail(int levels_of_detail_);
|
||||
|
||||
/// Save the collection - the directory name is constructed based on the
|
||||
@@ -552,27 +526,18 @@ public:
|
||||
/// VTKFormat::ASCII, VTKFormat::BINARY, and VTKFormat::BINARY32.
|
||||
/// The ASCII and BINARY options output double precision data, whereas the
|
||||
/// BINARY32 option outputs single precision data.
|
||||
///
|
||||
/// The initial format is VTKFormat::BINARY.
|
||||
void SetDataFormat(VTKFormat fmt);
|
||||
|
||||
/// @brief Set the zlib compression level.
|
||||
///
|
||||
/// 0 indicates no compression, -1 indicates the default compression level.
|
||||
/// Otherwise, specify a number between 1 and 9, 1 being the fastest, and 9
|
||||
/// being the best compression. Compression only takes effect if the output
|
||||
/// format is BINARY or BINARY32. MFEM must be compiled with MFEM_USE_ZLIB =
|
||||
/// YES.
|
||||
///
|
||||
/// The initial compression level is 0 if MFEM is compiled with MFEM_USE_ZLIB
|
||||
/// turned off, and -1 otherwise.
|
||||
///
|
||||
/// Any nonzero compression level will enable compression.
|
||||
/// Set the zlib compression level. 0 indicates no compression, -1 indicates
|
||||
/// the default compression level. Otherwise, specify a number between 1 and
|
||||
/// 9, 1 being the fastest, and 9 being the best compression. Compression
|
||||
/// only takes effect if the output format is BINARY or BINARY32. MFEM must
|
||||
/// be compiled with MFEM_USE_ZLIB = YES.
|
||||
void SetCompressionLevel(int compression_level_);
|
||||
|
||||
/// Enable or disable zlib compression. If the input is true, use the default
|
||||
/// zlib compression level (unless the compression level has previously been
|
||||
/// set by calling SetCompressionLevel()).
|
||||
/// set by calling SetCompressionLevel).
|
||||
void SetCompression(bool compression_) override;
|
||||
|
||||
/// Returns true if the output format is BINARY or BINARY32, false if ASCII.
|
||||
@@ -585,8 +550,6 @@ public:
|
||||
/// Enable or disable restart mode. If restart is enabled, new writes will
|
||||
/// preserve timestep metadata for any solutions prior to the currently
|
||||
/// defined time.
|
||||
///
|
||||
/// Initially, restart mode is disabled.
|
||||
void UseRestartMode(bool restart_mode_);
|
||||
|
||||
/// Load the collection - not implemented in the ParaView writer
|
||||
|
||||
@@ -1,315 +0,0 @@
|
||||
// Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "dgmassinv.hpp"
|
||||
#include "bilinearform.hpp"
|
||||
#include "dgmassinv_kernels.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
DGMassInverse::DGMassInverse(FiniteElementSpace &fes_orig, Coefficient *coeff,
|
||||
const IntegrationRule *ir,
|
||||
int btype)
|
||||
: Solver(fes_orig.GetTrueVSize()),
|
||||
fec(fes_orig.GetMaxElementOrder(),
|
||||
fes_orig.GetMesh()->Dimension(),
|
||||
btype,
|
||||
fes_orig.GetFE(0)->GetMapType()),
|
||||
fes(fes_orig.GetMesh(), &fec)
|
||||
{
|
||||
MFEM_VERIFY(fes.IsDGSpace(), "Space must be DG.");
|
||||
MFEM_VERIFY(!fes.IsVariableOrder(), "Variable orders not supported.");
|
||||
|
||||
const int btype_orig =
|
||||
static_cast<const L2_FECollection*>(fes_orig.FEColl())->GetBasisType();
|
||||
|
||||
if (btype_orig == btype)
|
||||
{
|
||||
// No change of basis required
|
||||
d2q = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// original basis to solver basis
|
||||
const auto mode = DofToQuad::TENSOR;
|
||||
d2q = &fes_orig.GetFE(0)->GetDofToQuad(fes.GetFE(0)->GetNodes(), mode);
|
||||
|
||||
int n = d2q->ndof;
|
||||
Array<double> B_inv = d2q->B; // deep copy
|
||||
Array<int> ipiv(n);
|
||||
// solver basis to original
|
||||
LUFactors lu(B_inv.HostReadWrite(), ipiv.HostWrite());
|
||||
lu.Factor(n);
|
||||
B_.SetSize(n*n);
|
||||
lu.GetInverseMatrix(n, B_.HostWrite());
|
||||
Bt_.SetSize(n*n);
|
||||
DenseMatrix B_matrix(B_.HostReadWrite(), n, n);
|
||||
DenseMatrix Bt_matrix(Bt_.HostWrite(), n, n);
|
||||
Bt_matrix.Transpose(B_matrix);
|
||||
}
|
||||
|
||||
if (coeff) { m = new MassIntegrator(*coeff, ir); }
|
||||
else { m = new MassIntegrator(ir); }
|
||||
|
||||
diag_inv.SetSize(height);
|
||||
// Workspace vectors used for CG
|
||||
r_.SetSize(height);
|
||||
d_.SetSize(height);
|
||||
z_.SetSize(height);
|
||||
// Only need transformed RHS if basis is different
|
||||
if (btype_orig != btype) { b2_.SetSize(height); }
|
||||
|
||||
M = new BilinearForm(&fes);
|
||||
M->AddDomainIntegrator(m); // M assumes ownership of m
|
||||
M->SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
|
||||
// Assemble the bilinear form and its diagonal (for preconditioning).
|
||||
Update();
|
||||
}
|
||||
|
||||
DGMassInverse::DGMassInverse(FiniteElementSpace &fes_, Coefficient &coeff,
|
||||
int btype)
|
||||
: DGMassInverse(fes_, &coeff, nullptr, btype) { }
|
||||
|
||||
DGMassInverse::DGMassInverse(FiniteElementSpace &fes_, Coefficient &coeff,
|
||||
const IntegrationRule &ir, int btype)
|
||||
: DGMassInverse(fes_, &coeff, &ir, btype) { }
|
||||
|
||||
DGMassInverse::DGMassInverse(FiniteElementSpace &fes_,
|
||||
const IntegrationRule &ir, int btype)
|
||||
: DGMassInverse(fes_, nullptr, &ir, btype) { }
|
||||
|
||||
DGMassInverse::DGMassInverse(FiniteElementSpace &fes_, int btype)
|
||||
: DGMassInverse(fes_, nullptr, nullptr, btype) { }
|
||||
|
||||
void DGMassInverse::SetOperator(const Operator &op)
|
||||
{
|
||||
MFEM_ABORT("SetOperator not supported with DGMassInverse.")
|
||||
}
|
||||
|
||||
void DGMassInverse::SetRelTol(const double rel_tol_) { rel_tol = rel_tol_; }
|
||||
|
||||
void DGMassInverse::SetAbsTol(const double abs_tol_) { abs_tol = abs_tol_; }
|
||||
|
||||
void DGMassInverse::SetMaxIter(const double max_iter_) { max_iter = max_iter_; }
|
||||
|
||||
void DGMassInverse::Update()
|
||||
{
|
||||
M->Assemble();
|
||||
M->AssembleDiagonal(diag_inv);
|
||||
internal::MakeReciprocal(diag_inv.Size(), diag_inv.ReadWrite());
|
||||
}
|
||||
|
||||
DGMassInverse::~DGMassInverse()
|
||||
{
|
||||
delete M;
|
||||
}
|
||||
|
||||
template<int DIM, int D1D, int Q1D>
|
||||
void DGMassInverse::DGMassCGIteration(const Vector &b_, Vector &u_) const
|
||||
{
|
||||
using namespace internal; // host/device kernel functions
|
||||
|
||||
const int NE = fes.GetNE();
|
||||
const int d1d = m->dofs1D;
|
||||
const int q1d = m->quad1D;
|
||||
|
||||
const int ND = static_cast<int>(pow(d1d, DIM));
|
||||
|
||||
const auto B = m->maps->B.Read();
|
||||
const auto Bt = m->maps->Bt.Read();
|
||||
const auto pa_data = m->pa_data.Read();
|
||||
const auto dinv = diag_inv.Read();
|
||||
auto r = r_.Write();
|
||||
auto d = d_.Write();
|
||||
auto z = z_.Write();
|
||||
auto u = u_.ReadWrite();
|
||||
|
||||
const double RELTOL = rel_tol;
|
||||
const double ABSTOL = abs_tol;
|
||||
const double MAXIT = max_iter;
|
||||
const bool IT_MODE = iterative_mode;
|
||||
const bool CHANGE_BASIS = (d2q != nullptr);
|
||||
|
||||
// b is the right-hand side (if no change of basis, this just points to the
|
||||
// incoming RHS vector, if we have to change basis, this points to the
|
||||
// internal b2 vector where we put the transformed RHS)
|
||||
const double *b;
|
||||
// the following are non-null if we have to change basis
|
||||
double *b2 = nullptr; // non-const access to b2
|
||||
const double *b_orig = nullptr; // RHS vector in "original" basis
|
||||
const double *d2q_B = nullptr; // matrix to transform initial guess
|
||||
const double *q2d_B = nullptr; // matrix to transform solution
|
||||
const double *q2d_Bt = nullptr; // matrix to transform RHS
|
||||
if (CHANGE_BASIS)
|
||||
{
|
||||
d2q_B = d2q->B.Read();
|
||||
q2d_B = B_.Read();
|
||||
q2d_Bt = Bt_.Read();
|
||||
|
||||
b2 = b2_.Write();
|
||||
b_orig = b_.Read();
|
||||
b = b2;
|
||||
}
|
||||
else
|
||||
{
|
||||
b = b_.Read();
|
||||
}
|
||||
|
||||
constexpr int NB = Q1D ? Q1D : 1; // block size
|
||||
|
||||
MFEM_FORALL_2D(e, NE, NB, NB, 1,
|
||||
{
|
||||
constexpr int NB = Q1D ? Q1D : 1; // redefine here for some compilers
|
||||
|
||||
// Perform change of basis if needed
|
||||
if (CHANGE_BASIS)
|
||||
{
|
||||
// Transform RHS
|
||||
DGMassBasis<DIM,D1D,MAX_D1D>(e, NE, q2d_Bt, b_orig, b2, d1d);
|
||||
if (IT_MODE)
|
||||
{
|
||||
// Transform initial guess
|
||||
DGMassBasis<DIM,D1D,MAX_D1D>(e, NE, d2q_B, u, u, d1d);
|
||||
}
|
||||
}
|
||||
|
||||
const int tid = MFEM_THREAD_ID(x) + NB*MFEM_THREAD_ID(y);
|
||||
|
||||
// Compute first residual
|
||||
if (IT_MODE)
|
||||
{
|
||||
DGMassApply<DIM,D1D,Q1D>(e, NE, B, Bt, pa_data, u, r, d1d, q1d);
|
||||
DGMassAxpy(e, NE, ND, 1.0, b, -1.0, r, r); // r = b - r
|
||||
}
|
||||
else
|
||||
{
|
||||
// if not in iterative mode, use zero initial guess
|
||||
const int BX = MFEM_THREAD_SIZE(x);
|
||||
const int BY = MFEM_THREAD_SIZE(y);
|
||||
const int bxy = BX*BY;
|
||||
const auto B = ConstDeviceMatrix(b, ND, NE);
|
||||
auto U = DeviceMatrix(u, ND, NE);
|
||||
auto R = DeviceMatrix(r, ND, NE);
|
||||
for (int i = tid; i < ND; i += bxy)
|
||||
{
|
||||
U(i, e) = 0.0;
|
||||
R(i, e) = B(i, e);
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
|
||||
DGMassPreconditioner(e, NE, ND, dinv, r, z);
|
||||
DGMassAxpy(e, NE, ND, 1.0, z, 0.0, z, d); // d = z
|
||||
|
||||
double nom = DGMassDot<NB>(e, NE, ND, d, r);
|
||||
if (nom < 0.0) { return; /* Not positive definite */ }
|
||||
double r0 = fmax(nom*RELTOL*RELTOL, ABSTOL*ABSTOL);
|
||||
if (nom <= r0) { return; /* Converged */ }
|
||||
|
||||
DGMassApply<DIM,D1D,Q1D>(e, NE, B, Bt, pa_data, d, z, d1d, q1d);
|
||||
double den = DGMassDot<NB>(e, NE, ND, z, d);
|
||||
if (den <= 0.0)
|
||||
{
|
||||
DGMassDot<NB>(e, NE, ND, d, d);
|
||||
// d2 > 0 => not positive definite
|
||||
if (den == 0.0) { return; }
|
||||
}
|
||||
|
||||
// start iteration
|
||||
int i = 1;
|
||||
while (true)
|
||||
{
|
||||
const double alpha = nom/den;
|
||||
DGMassAxpy(e, NE, ND, 1.0, u, alpha, d, u); // u = u + alpha*d
|
||||
DGMassAxpy(e, NE, ND, 1.0, r, -alpha, z, r); // r = r - alpha*A*d
|
||||
|
||||
DGMassPreconditioner(e, NE, ND, dinv, r, z);
|
||||
|
||||
double betanom = DGMassDot<NB>(e, NE, ND, r, z);
|
||||
if (betanom < 0.0) { return; /* Not positive definite */ }
|
||||
if (betanom <= r0) { break; /* Converged */ }
|
||||
|
||||
if (++i > MAXIT) { break; }
|
||||
|
||||
const double beta = betanom/nom;
|
||||
DGMassAxpy(e, NE, ND, 1.0, z, beta, d, d); // d = z + beta*d
|
||||
DGMassApply<DIM,D1D,Q1D>(e, NE, B, Bt, pa_data, d, z, d1d, q1d); // z = A d
|
||||
den = DGMassDot<NB>(e, NE, ND, d, z);
|
||||
if (den <= 0.0)
|
||||
{
|
||||
DGMassDot<NB>(e, NE, ND, d, d);
|
||||
// d2 > 0 => not positive definite
|
||||
if (den == 0.0) { break; }
|
||||
}
|
||||
nom = betanom;
|
||||
}
|
||||
|
||||
if (CHANGE_BASIS)
|
||||
{
|
||||
DGMassBasis<DIM,D1D,MAX_D1D>(e, NE, q2d_B, u, u, d1d);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void DGMassInverse::Mult(const Vector &Mu, Vector &u) const
|
||||
{
|
||||
// Dispatch to templated version based on dim, d1d, and q1d.
|
||||
const int dim = fes.GetMesh()->Dimension();
|
||||
const int d1d = m->dofs1D;
|
||||
const int q1d = m->quad1D;
|
||||
|
||||
const int id = (d1d << 4) | q1d;
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x11: return DGMassCGIteration<2,1,1>(Mu, u);
|
||||
case 0x22: return DGMassCGIteration<2,2,2>(Mu, u);
|
||||
case 0x33: return DGMassCGIteration<2,3,3>(Mu, u);
|
||||
case 0x35: return DGMassCGIteration<2,3,5>(Mu, u);
|
||||
case 0x44: return DGMassCGIteration<2,4,4>(Mu, u);
|
||||
case 0x46: return DGMassCGIteration<2,4,6>(Mu, u);
|
||||
case 0x55: return DGMassCGIteration<2,5,5>(Mu, u);
|
||||
case 0x57: return DGMassCGIteration<2,5,7>(Mu, u);
|
||||
case 0x66: return DGMassCGIteration<2,6,6>(Mu, u);
|
||||
case 0x68: return DGMassCGIteration<2,6,8>(Mu, u);
|
||||
default: return DGMassCGIteration<2>(Mu, u); // Fallback
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x22: return DGMassCGIteration<3,2,2>(Mu, u);
|
||||
case 0x23: return DGMassCGIteration<3,2,3>(Mu, u);
|
||||
case 0x33: return DGMassCGIteration<3,3,3>(Mu, u);
|
||||
case 0x34: return DGMassCGIteration<3,3,4>(Mu, u);
|
||||
case 0x35: return DGMassCGIteration<3,3,5>(Mu, u);
|
||||
case 0x44: return DGMassCGIteration<3,4,4>(Mu, u);
|
||||
case 0x45: return DGMassCGIteration<3,4,5>(Mu, u);
|
||||
case 0x46: return DGMassCGIteration<3,4,6>(Mu, u);
|
||||
case 0x48: return DGMassCGIteration<3,4,8>(Mu, u);
|
||||
case 0x55: return DGMassCGIteration<3,5,5>(Mu, u);
|
||||
case 0x56: return DGMassCGIteration<3,5,6>(Mu, u);
|
||||
case 0x57: return DGMassCGIteration<3,5,7>(Mu, u);
|
||||
case 0x58: return DGMassCGIteration<3,5,8>(Mu, u);
|
||||
case 0x66: return DGMassCGIteration<3,6,6>(Mu, u);
|
||||
case 0x67: return DGMassCGIteration<3,6,7>(Mu, u);
|
||||
default: return DGMassCGIteration<3>(Mu, u); // Fallback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,112 +0,0 @@
|
||||
// Copyright (c) 2010-2022, 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_DGMASSINV_HPP
|
||||
#define MFEM_DGMASSINV_HPP
|
||||
|
||||
#include "../linalg/operator.hpp"
|
||||
#include "fespace.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// @brief Solver for the discontinuous Galerkin mass matrix.
|
||||
///
|
||||
/// This class performs a @a local (diagonally preconditioned) conjugate
|
||||
/// gradient iteration for each element. Optionally, a change of basis is
|
||||
/// performed to iterate on a better-conditioned system. This class fully
|
||||
/// supports execution on device (GPU).
|
||||
class DGMassInverse : public Solver
|
||||
{
|
||||
protected:
|
||||
DG_FECollection fec; ///< FE collection in requested basis.
|
||||
FiniteElementSpace fes; ///< FE space in requested basis.
|
||||
const DofToQuad *d2q; ///< Change of basis. Not owned.
|
||||
Array<double> B_; ///< Inverse of change of basis.
|
||||
Array<double> Bt_; ///< Inverse of change of basis, transposed.
|
||||
class BilinearForm *M; ///< Mass bilinear form, owned.
|
||||
class MassIntegrator *m; ///< Mass integrator, owned by the form @ref M.
|
||||
Vector diag_inv; ///< Jacobi preconditioner.
|
||||
double rel_tol = 1e-12; ///< Relative CG tolerance.
|
||||
double abs_tol = 1e-12; ///< Absolute CG tolerance.
|
||||
int max_iter = 100; ///< Maximum number of CG iterations;
|
||||
|
||||
/// @name Intermediate vectors needed for CG three-term recurrence.
|
||||
///@{
|
||||
mutable Vector r_, d_, z_, b2_;
|
||||
///@}
|
||||
|
||||
/// @brief Protected constructor, used internally.
|
||||
///
|
||||
/// Custom coefficient and integration rule are used if @a coeff and @a ir
|
||||
/// are non-NULL.
|
||||
DGMassInverse(FiniteElementSpace &fes_, Coefficient *coeff,
|
||||
const IntegrationRule *ir, int btype);
|
||||
public:
|
||||
/// @brief Construct the DG inverse mass operator for @a fes_.
|
||||
///
|
||||
/// The basis type @a btype determines which basis should be used internally
|
||||
/// in the solver. This <b>does not</b> have to be the same basis as @a fes_.
|
||||
/// The best choice is typically BasisType::GaussLegendre because it is
|
||||
/// well-preconditioned by its diagonal.
|
||||
///
|
||||
/// The solution and right-hand side used for the solver are not affected by
|
||||
/// this basis (they correspond to the basis of @a fes_). @a btype is only
|
||||
/// used internally, and only has an effect on the convergence rate.
|
||||
DGMassInverse(FiniteElementSpace &fes_, int btype=BasisType::GaussLegendre);
|
||||
/// @brief Construct the DG inverse mass operator for @a fes_ with
|
||||
/// Coefficient @a coeff.
|
||||
///
|
||||
/// @sa DGMassInverse(FiniteElementSpace&, int) for information about @a
|
||||
/// btype.
|
||||
DGMassInverse(FiniteElementSpace &fes_, Coefficient &coeff,
|
||||
int btype=BasisType::GaussLegendre);
|
||||
/// @brief Construct the DG inverse mass operator for @a fes_ with
|
||||
/// Coefficient @a coeff and IntegrationRule @a ir.
|
||||
///
|
||||
/// @sa DGMassInverse(FiniteElementSpace&, int) for information about @a
|
||||
/// btype.
|
||||
DGMassInverse(FiniteElementSpace &fes_, Coefficient &coeff,
|
||||
const IntegrationRule &ir, int btype=BasisType::GaussLegendre);
|
||||
/// @brief Construct the DG inverse mass operator for @a fes_ with
|
||||
/// IntegrationRule @a ir.
|
||||
///
|
||||
/// @sa DGMassInverse(FiniteElementSpace&, int) for information about @a
|
||||
/// btype.
|
||||
DGMassInverse(FiniteElementSpace &fes_, const IntegrationRule &ir,
|
||||
int btype=BasisType::GaussLegendre);
|
||||
/// @brief Solve the system M b = u.
|
||||
///
|
||||
/// If @ref iterative_mode is @a true, @a u is used as an initial guess.
|
||||
void Mult(const Vector &b, Vector &u) const;
|
||||
/// Not implemented. Aborts.
|
||||
void SetOperator(const Operator &op);
|
||||
/// Set the relative tolerance.
|
||||
void SetRelTol(const double rel_tol_);
|
||||
/// Set the absolute tolerance.
|
||||
void SetAbsTol(const double abs_tol_);
|
||||
/// Set the maximum number of iterations.
|
||||
void SetMaxIter(const double max_iter_);
|
||||
/// Recompute operator and preconditioner (when coefficient or mesh changes).
|
||||
void Update();
|
||||
|
||||
~DGMassInverse();
|
||||
|
||||
/// @brief Solve the system M b = u. <b>Not part of the public interface.</b>
|
||||
/// @note This member function must be public because it contains an
|
||||
/// MFEM_FORALL kernel (nvcc limitation)
|
||||
template<int DIM, int D1D = 0, int Q1D = 0>
|
||||
void DGMassCGIteration(const Vector &b_, Vector &u_) const;
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
@@ -1,295 +0,0 @@
|
||||
// Copyright (c) 2010-2022, 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_DGMASSINV_KERNELS_HPP
|
||||
#define MFEM_DGMASSINV_KERNELS_HPP
|
||||
|
||||
#include "bilininteg_mass_pa.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
#include "kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
void MakeReciprocal(int n, double *x)
|
||||
{
|
||||
MFEM_FORALL(i, n, x[i] = 1.0/x[i]; );
|
||||
}
|
||||
|
||||
template <int DIM, int D1D, int Q1D>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void DGMassApply(const int e,
|
||||
const int NE,
|
||||
const double *B,
|
||||
const double *Bt,
|
||||
const double *pa_data,
|
||||
const double *x,
|
||||
double *y,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
constexpr bool use_smem = (D1D > 0 && Q1D > 0);
|
||||
constexpr bool ACCUM = false;
|
||||
constexpr int NBZ = 1;
|
||||
if (use_smem)
|
||||
{
|
||||
// cannot specialize functions below with D1D or Q1D equal to zero
|
||||
// (this branch only runs with D1D and Q1D are both positive)
|
||||
constexpr int TD1D = D1D ? D1D : 1;
|
||||
constexpr int TQ1D = Q1D ? Q1D : 1;
|
||||
if (DIM == 2)
|
||||
{
|
||||
SmemPAMassApply2D_Element<TD1D,TQ1D,NBZ,ACCUM>(e, NE, B, pa_data, x, y);
|
||||
}
|
||||
else if (DIM == 3)
|
||||
{
|
||||
SmemPAMassApply3D_Element<TD1D,TQ1D,ACCUM>(e, NE, B, pa_data, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT_KERNEL("Unsupported dimension.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DIM == 2)
|
||||
{
|
||||
PAMassApply2D_Element<ACCUM>(e, NE, B, Bt, pa_data, x, y, d1d, q1d);
|
||||
}
|
||||
else if (DIM == 3)
|
||||
{
|
||||
PAMassApply3D_Element<ACCUM>(e, NE, B, Bt, pa_data, x, y, d1d, q1d);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT_KERNEL("Unsupported dimension.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline
|
||||
void DGMassPreconditioner(const int e,
|
||||
const int NE,
|
||||
const int ND,
|
||||
const double *dinv,
|
||||
const double *x,
|
||||
double *y)
|
||||
{
|
||||
const auto X = ConstDeviceMatrix(x, ND, NE);
|
||||
const auto D = ConstDeviceMatrix(dinv, ND, NE);
|
||||
auto Y = DeviceMatrix(y, ND, NE);
|
||||
|
||||
const int tid = MFEM_THREAD_ID(x) + MFEM_THREAD_SIZE(x)*MFEM_THREAD_ID(y);
|
||||
const int bxy = MFEM_THREAD_SIZE(x)*MFEM_THREAD_SIZE(y);
|
||||
|
||||
for (int i = tid; i < ND; i += bxy)
|
||||
{
|
||||
Y(i, e) = D(i, e)*X(i, e);
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline
|
||||
void DGMassAxpy(const int e,
|
||||
const int NE,
|
||||
const int ND,
|
||||
const double a,
|
||||
const double *x,
|
||||
const double b,
|
||||
const double *y,
|
||||
double *z)
|
||||
{
|
||||
const auto X = ConstDeviceMatrix(x, ND, NE);
|
||||
const auto Y = ConstDeviceMatrix(y, ND, NE);
|
||||
auto Z = DeviceMatrix(z, ND, NE);
|
||||
|
||||
const int tid = MFEM_THREAD_ID(x) + MFEM_THREAD_SIZE(x)*MFEM_THREAD_ID(y);
|
||||
const int bxy = MFEM_THREAD_SIZE(x)*MFEM_THREAD_SIZE(y);
|
||||
|
||||
for (int i = tid; i < ND; i += bxy)
|
||||
{
|
||||
Z(i, e) = a*X(i, e) + b*Y(i, e);
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
|
||||
template <int NB>
|
||||
MFEM_HOST_DEVICE inline
|
||||
double DGMassDot(const int e,
|
||||
const int NE,
|
||||
const int ND,
|
||||
const double *x,
|
||||
const double *y)
|
||||
{
|
||||
const auto X = ConstDeviceMatrix(x, ND, NE);
|
||||
const auto Y = ConstDeviceMatrix(y, ND, NE);
|
||||
|
||||
const int tid = MFEM_THREAD_ID(x) + MFEM_THREAD_SIZE(x)*MFEM_THREAD_ID(y);
|
||||
const int bxy = MFEM_THREAD_SIZE(x)*MFEM_THREAD_SIZE(y);
|
||||
|
||||
MFEM_SHARED double s_dot[NB*NB];
|
||||
s_dot[tid] = 0.0;
|
||||
|
||||
for (int i = tid; i < ND; i += bxy) { s_dot[tid] += X(i,e)*Y(i,e); }
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
if (bxy > 512 && tid + 512 < bxy) { s_dot[tid] += s_dot[tid + 512]; }
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
if (bxy > 256 && tid < 256 && tid + 256 < bxy) { s_dot[tid] += s_dot[tid + 256]; }
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
if (bxy > 128 && tid < 128 && tid + 128 < bxy) { s_dot[tid] += s_dot[tid + 128]; }
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
if (bxy > 64 && tid < 64 && tid + 64 < bxy) { s_dot[tid] += s_dot[tid + 64]; }
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
if (bxy > 32 && tid < 32 && tid + 32 < bxy) { s_dot[tid] += s_dot[tid + 32]; }
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
if (bxy > 16 && tid < 16 && tid + 16 < bxy) { s_dot[tid] += s_dot[tid + 16]; }
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
if (bxy > 8 && tid < 8 && tid + 8 < bxy) { s_dot[tid] += s_dot[tid + 8]; }
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
if (bxy > 4 && tid < 4 && tid + 4 < bxy) { s_dot[tid] += s_dot[tid + 4]; }
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
if (bxy > 2 && tid < 2 && tid + 2 < bxy) { s_dot[tid] += s_dot[tid + 2]; }
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
if (bxy > 1 && tid < 1 && tid + 1 < bxy) { s_dot[tid] += s_dot[tid + 1]; }
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
return s_dot[0];
|
||||
}
|
||||
|
||||
template<int T_D1D = 0, int MAX_D1D = 0>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void DGMassBasis2D(const int e,
|
||||
const int NE,
|
||||
const double *b_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int d1d = 0)
|
||||
{
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
|
||||
const auto b = Reshape(b_, D1D, D1D);
|
||||
const auto x = Reshape(x_, D1D, D1D, NE);
|
||||
auto y = Reshape(y_, D1D, D1D, NE);
|
||||
|
||||
MFEM_SHARED double sB[MD1*MD1];
|
||||
MFEM_SHARED double sm0[MD1*MD1];
|
||||
MFEM_SHARED double sm1[MD1*MD1];
|
||||
|
||||
kernels::internal::LoadB<MD1,MD1>(D1D,D1D,b,sB);
|
||||
|
||||
ConstDeviceMatrix B(sB, D1D,D1D);
|
||||
DeviceMatrix DD(sm0, MD1, MD1);
|
||||
DeviceMatrix DQ(sm1, MD1, MD1);
|
||||
DeviceMatrix QQ(sm0, MD1, MD1);
|
||||
|
||||
kernels::internal::LoadX(e,D1D,x,DD);
|
||||
kernels::internal::EvalX(D1D,D1D,B,DD,DQ);
|
||||
kernels::internal::EvalY(D1D,D1D,B,DQ,QQ);
|
||||
MFEM_SYNC_THREAD; // sync here to allow in-place evaluations
|
||||
MFEM_FOREACH_THREAD(qy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,D1D)
|
||||
{
|
||||
y(qx,qy,e) = QQ(qx,qy);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
|
||||
template<int T_D1D = 0, int MAX_D1D = 0>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void DGMassBasis3D(const int e,
|
||||
const int NE,
|
||||
const double *b_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int d1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
|
||||
const auto b = Reshape(b_, D1D, D1D);
|
||||
const auto x = Reshape(x_, D1D, D1D, D1D, NE);
|
||||
auto y = Reshape(y_, D1D, D1D, D1D, NE);
|
||||
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
|
||||
MFEM_SHARED double sB[MD1*MD1];
|
||||
MFEM_SHARED double sm0[MD1*MD1*MD1];
|
||||
MFEM_SHARED double sm1[MD1*MD1*MD1];
|
||||
|
||||
kernels::internal::LoadB<MD1,MD1>(D1D,D1D,b,sB);
|
||||
|
||||
ConstDeviceMatrix B(sB, D1D,D1D);
|
||||
DeviceCube DDD(sm0, MD1,MD1,MD1);
|
||||
DeviceCube DDQ(sm1, MD1,MD1,MD1);
|
||||
DeviceCube DQQ(sm0, MD1,MD1,MD1);
|
||||
DeviceCube QQQ(sm1, MD1,MD1,MD1);
|
||||
|
||||
kernels::internal::LoadX(e,D1D,x,DDD);
|
||||
kernels::internal::EvalX(D1D,D1D,B,DDD,DDQ);
|
||||
kernels::internal::EvalY(D1D,D1D,B,DDQ,DQQ);
|
||||
kernels::internal::EvalZ(D1D,D1D,B,DQQ,QQQ);
|
||||
MFEM_SYNC_THREAD; // sync here to allow in-place evaluation
|
||||
MFEM_FOREACH_THREAD(qz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,D1D)
|
||||
{
|
||||
for (int qx = 0; qx < D1D; ++qx)
|
||||
{
|
||||
y(qx,qy,qz,e) = QQQ(qz,qy,qx);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
|
||||
template<int DIM, int T_D1D = 0, int MAX_D1D = 0>
|
||||
MFEM_HOST_DEVICE inline
|
||||
void DGMassBasis(const int e,
|
||||
const int NE,
|
||||
const double *b_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int d1d = 0)
|
||||
{
|
||||
if (DIM == 2)
|
||||
{
|
||||
DGMassBasis2D<T_D1D, MAX_D1D>(e, NE, b_, x_, y_, d1d);
|
||||
}
|
||||
else if (DIM == 3)
|
||||
{
|
||||
DGMassBasis3D<T_D1D, MAX_D1D>(e, NE, b_, x_, y_, d1d);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT_KERNEL("Dimension not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
+4
-10
@@ -339,11 +339,8 @@ ND_TriDofTransformation::TransformDual(double *v) const
|
||||
void
|
||||
ND_TriDofTransformation::InvTransformDual(double *v) const
|
||||
{
|
||||
// Return immediately when no face DoFs are present
|
||||
if (nfdofs < 2) { return; }
|
||||
|
||||
MFEM_VERIFY(Fo.Size() >= 1,
|
||||
"Face orientations are unset in ND_TriDofTransformation");
|
||||
int nedofs = order; // number of DoFs per edge
|
||||
int nfdofs = order*(order-1); // number of DoFs per face
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
@@ -435,11 +432,8 @@ ND_TetDofTransformation::TransformDual(double *v) const
|
||||
void
|
||||
ND_TetDofTransformation::InvTransformDual(double *v) const
|
||||
{
|
||||
// Return immediately when no face DoFs are present
|
||||
if (nfdofs < 2) { return; }
|
||||
|
||||
MFEM_VERIFY(Fo.Size() >= 4,
|
||||
"Face orientations are unset in ND_TetDofTransformation");
|
||||
int nedofs = order; // number of DoFs per edge
|
||||
int nfdofs = order*(order-1); // number of DoFs per face
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
|
||||
+2
-2
@@ -159,7 +159,7 @@ void KellyErrorEstimator::ComputeEstimates()
|
||||
// the FaceInfo class [1]. Also, the FaceElementTransformations
|
||||
// documentation [2] may be helpful to grasp what is going on. Note
|
||||
// that the FaceElementTransformations also works in the non-
|
||||
// conforming case to transfer the Gauss points from the slave to
|
||||
// conforming case to transfer the gauss points from the slave to
|
||||
// the master element.
|
||||
// [1]
|
||||
// https://github.com/mfem/mfem/blob/02d0bfe9c18ce049c3c93a6a4208080fcfc96991/mesh/mesh.hpp#L94
|
||||
@@ -417,7 +417,7 @@ void KellyErrorEstimator::ComputeEstimates()
|
||||
Vector val(flux_space->GetVDim());
|
||||
flux->GetVectorValue(FT->Elem2No, ip, val);
|
||||
|
||||
// Evaluate Gauss point
|
||||
// Evaluate gauss point
|
||||
Vector normal(mesh->SpaceDimension());
|
||||
FT->Face->SetIntPoint(&fip);
|
||||
if (mesh->Dimension() == mesh->SpaceDimension())
|
||||
|
||||
+226
-226
@@ -36,19 +36,19 @@ FiniteElement::FiniteElement(int D, Geometry::Type G,
|
||||
#endif
|
||||
}
|
||||
|
||||
void FiniteElement::CalcVShape(
|
||||
void FiniteElement::CalcVShape (
|
||||
const IntegrationPoint &ip, DenseMatrix &shape) const
|
||||
{
|
||||
MFEM_ABORT("method is not implemented for this class");
|
||||
}
|
||||
|
||||
void FiniteElement::CalcVShape(
|
||||
void FiniteElement::CalcVShape (
|
||||
ElementTransformation &Trans, DenseMatrix &shape) const
|
||||
{
|
||||
MFEM_ABORT("method is not implemented for this class");
|
||||
}
|
||||
|
||||
void FiniteElement::CalcDivShape(
|
||||
void FiniteElement::CalcDivShape (
|
||||
const IntegrationPoint &ip, Vector &divshape) const
|
||||
{
|
||||
MFEM_ABORT("method is not implemented for this class");
|
||||
@@ -97,14 +97,14 @@ void FiniteElement::GetFaceDofs(int face, int **dofs, int *ndofs) const
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
}
|
||||
|
||||
void FiniteElement::CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &h) const
|
||||
void FiniteElement::CalcHessian (const IntegrationPoint &ip,
|
||||
DenseMatrix &h) const
|
||||
{
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
}
|
||||
|
||||
void FiniteElement::GetLocalInterpolation(ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
void FiniteElement::GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
}
|
||||
@@ -122,13 +122,13 @@ void FiniteElement::GetTransferMatrix(const FiniteElement &fe,
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
}
|
||||
|
||||
void FiniteElement::Project(
|
||||
void FiniteElement::Project (
|
||||
Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
}
|
||||
|
||||
void FiniteElement::Project(
|
||||
void FiniteElement::Project (
|
||||
VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
@@ -137,7 +137,7 @@ void FiniteElement::Project(
|
||||
void FiniteElement::ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{
|
||||
mfem_error("FiniteElement::ProjectFromNodes() (vector) is not overloaded!");
|
||||
mfem_error ("FiniteElement::ProjectFromNodes() (vector) is not overloaded!");
|
||||
}
|
||||
|
||||
void FiniteElement::ProjectMatrixCoefficient(
|
||||
@@ -239,6 +239,7 @@ void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Assume a linear mapping
|
||||
void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
|
||||
Vector &Laplacian) const
|
||||
@@ -249,7 +250,7 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
|
||||
DenseMatrix Gij(dim,dim);
|
||||
Vector scale(size);
|
||||
|
||||
CalcHessian(Trans.GetIntPoint(), hess);
|
||||
CalcHessian (Trans.GetIntPoint(), hess);
|
||||
MultAAt(Trans.InverseJacobian(), Gij);
|
||||
|
||||
if (dim == 3)
|
||||
@@ -282,6 +283,7 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
|
||||
Laplacian[nd] += hess(nd,ii)*scale[ii];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
|
||||
@@ -361,128 +363,11 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
|
||||
Mult( hess, lhm, Hessian);
|
||||
}
|
||||
|
||||
const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &,
|
||||
DofToQuad::Mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode == DofToQuad::FULL, "invalid mode requested");
|
||||
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix vshape(dof, dim);
|
||||
#endif
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const int nqpt = ir.GetNPoints();
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = dof;
|
||||
d2q->nqpt = nqpt;
|
||||
if (range_type == SCALAR)
|
||||
{
|
||||
d2q->B.SetSize(nqpt*dof);
|
||||
d2q->Bt.SetSize(dof*nqpt);
|
||||
|
||||
Vector shape;
|
||||
vshape.GetColumnReference(0, shape);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcShape(ip, shape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = shape(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
d2q->B.SetSize(nqpt*dim*dof);
|
||||
d2q->Bt.SetSize(dof*nqpt*dim);
|
||||
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcVShape(ip, vshape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*(d+dim*j)] = d2q->Bt[j+dof*(i+nqpt*d)] = vshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (deriv_type)
|
||||
{
|
||||
case GRAD:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*dim*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt*dim);
|
||||
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcDShape(ip, vshape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt);
|
||||
|
||||
Vector divshape;
|
||||
vshape.GetColumnReference(0, divshape);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcDivShape(ip, divshape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+dof*i] = divshape(j);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CURL:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*cdim*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt*cdim);
|
||||
|
||||
DenseMatrix curlshape(vshape.GetData(), dof, cdim); // cdim <= dim
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcCurlShape(ip, curlshape);
|
||||
for (int d = 0; d < cdim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = curlshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NONE:
|
||||
default:
|
||||
MFEM_ABORT("invalid finite element derivative type");
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
MFEM_ABORT("method is not implemented for this element");
|
||||
return *dof2quad_array[0]; // suppress a warning
|
||||
}
|
||||
|
||||
FiniteElement::~FiniteElement()
|
||||
@@ -494,19 +379,16 @@ FiniteElement::~FiniteElement()
|
||||
}
|
||||
|
||||
|
||||
void ScalarFiniteElement::NodalLocalInterpolation(
|
||||
void ScalarFiniteElement::NodalLocalInterpolation (
|
||||
ElementTransformation &Trans, DenseMatrix &I,
|
||||
const ScalarFiniteElement &fine_fe) const
|
||||
{
|
||||
double v[Geometry::MaxDim];
|
||||
Vector vv(v, dim);
|
||||
Vector vv (v, dim);
|
||||
IntegrationPoint f_ip;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape(dof);
|
||||
#else
|
||||
Vector shape;
|
||||
vshape.GetColumnReference(0, shape);
|
||||
Vector c_shape(dof);
|
||||
#endif
|
||||
|
||||
MFEM_ASSERT(map_type == fine_fe.GetMapType(), "");
|
||||
@@ -516,10 +398,10 @@ void ScalarFiniteElement::NodalLocalInterpolation(
|
||||
{
|
||||
Trans.Transform(fine_fe.Nodes.IntPoint(i), vv);
|
||||
f_ip.Set(v, dim);
|
||||
CalcShape(f_ip, shape);
|
||||
CalcShape(f_ip, c_shape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
if (fabs(I(i,j) = shape(j)) < 1.0e-12)
|
||||
if (fabs(I(i,j) = c_shape(j)) < 1.0e-12)
|
||||
{
|
||||
I(i,j) = 0.0;
|
||||
}
|
||||
@@ -540,7 +422,7 @@ void ScalarFiniteElement::ScalarLocalInterpolation(
|
||||
// General "interpolation", defined by L2 projection
|
||||
|
||||
double v[Geometry::MaxDim];
|
||||
Vector vv(v, dim);
|
||||
Vector vv (v, dim);
|
||||
IntegrationPoint f_ip;
|
||||
|
||||
const int fs = fine_fe.GetDof(), cs = this->GetDof();
|
||||
@@ -574,13 +456,14 @@ void ScalarFiniteElement::ScalarLocalInterpolation(
|
||||
}
|
||||
}
|
||||
|
||||
void ScalarFiniteElement::ScalarLocalL2Restriction(
|
||||
void ScalarFiniteElement::ScalarLocalRestriction(
|
||||
ElementTransformation &Trans, DenseMatrix &R,
|
||||
const ScalarFiniteElement &coarse_fe) const
|
||||
{
|
||||
// General "restriction", defined by L2 projection
|
||||
double v[Geometry::MaxDim];
|
||||
Vector vv(v, dim);
|
||||
Vector vv (v, dim);
|
||||
IntegrationPoint f_ip;
|
||||
|
||||
const int cs = coarse_fe.GetDof(), fs = this->GetDof();
|
||||
R.SetSize(cs, fs);
|
||||
@@ -589,27 +472,16 @@ void ScalarFiniteElement::ScalarLocalL2Restriction(
|
||||
const int ir_order = GetOrder() + coarse_fe.GetOrder();
|
||||
const IntegrationRule &ir = IntRules.Get(coarse_fe.GetGeomType(), ir_order);
|
||||
|
||||
// integrate coarse_mass in the coarse space
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &c_ip = ir.IntPoint(i);
|
||||
coarse_fe.CalcShape(c_ip, coarse_shape);
|
||||
AddMult_a_VVt(c_ip.weight, coarse_shape, coarse_mass);
|
||||
}
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
this->CalcShape(ip, fine_shape);
|
||||
Trans.Transform(ip, vv);
|
||||
f_ip.Set(v, dim);
|
||||
coarse_fe.CalcShape(f_ip, coarse_shape);
|
||||
|
||||
// integrate coarse_fine_mass in the fine space
|
||||
Trans.SetIntPoint(&Geometries.GetCenter(geom_type));
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &f_ip = ir.IntPoint(i);
|
||||
this->CalcShape(f_ip, fine_shape);
|
||||
Trans.Transform(f_ip, vv);
|
||||
|
||||
IntegrationPoint c_ip;
|
||||
c_ip.Set(v, dim);
|
||||
coarse_fe.CalcShape(c_ip, coarse_shape);
|
||||
AddMult_a_VWt(f_ip.weight*Trans.Weight(), coarse_shape, fine_shape,
|
||||
coarse_fine_mass);
|
||||
AddMult_a_VVt(ip.weight, coarse_shape, coarse_mass);
|
||||
AddMult_a_VWt(ip.weight, coarse_shape, fine_shape, coarse_fine_mass);
|
||||
}
|
||||
|
||||
DenseMatrixInverse coarse_mass_inv(coarse_mass);
|
||||
@@ -622,6 +494,95 @@ void ScalarFiniteElement::ScalarLocalL2Restriction(
|
||||
R *= 1.0 / Trans.Weight();
|
||||
}
|
||||
}
|
||||
const DofToQuad &ScalarFiniteElement::GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode == DofToQuad::FULL, "invalid mode requested");
|
||||
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const int nqpt = ir.GetNPoints();
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = dof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*dof);
|
||||
d2q->Bt.SetSize(dof*nqpt);
|
||||
d2q->G.SetSize(nqpt*dim*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt*dim);
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector c_shape(dof);
|
||||
DenseMatrix vshape(dof, dim);
|
||||
#endif
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcShape(ip, c_shape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = c_shape(j);
|
||||
}
|
||||
CalcDShape(ip, vshape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
// protected method
|
||||
const DofToQuad &ScalarFiniteElement::GetTensorDofToQuad(
|
||||
const TensorBasisElement &tb,
|
||||
const IntegrationRule &ir, DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
|
||||
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const Poly_1D::Basis &basis_1d = tb.GetBasis1D();
|
||||
const int ndof = order + 1;
|
||||
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5);
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = ndof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*ndof);
|
||||
d2q->Bt.SetSize(ndof*nqpt);
|
||||
d2q->G.SetSize(nqpt*ndof);
|
||||
d2q->Gt.SetSize(ndof*nqpt);
|
||||
Vector val(ndof), grad(ndof);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
|
||||
// of the 1D rule.
|
||||
basis_1d.Eval(ir.IntPoint(i).x, val, grad);
|
||||
for (int j = 0; j < ndof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
|
||||
}
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
|
||||
void NodalFiniteElement::ProjectCurl_2D(
|
||||
const FiniteElement &fe, ElementTransformation &Trans,
|
||||
@@ -657,7 +618,7 @@ void InvertLinearTrans(ElementTransformation &trans,
|
||||
|
||||
double store[3];
|
||||
Vector v(store, x.Size());
|
||||
pt.Get(store, x.Size());
|
||||
pt.Get(v, x.Size());
|
||||
v -= x;
|
||||
|
||||
trans.InverseJacobian().Mult(v, x);
|
||||
@@ -670,10 +631,7 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans,
|
||||
Vector pt(&ipt.x, dim);
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape(dof);
|
||||
#else
|
||||
Vector shape;
|
||||
vshape.GetColumnReference(0, shape);
|
||||
Vector c_shape(dof);
|
||||
#endif
|
||||
|
||||
Trans.SetIntPoint(&Nodes[0]);
|
||||
@@ -683,8 +641,8 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans,
|
||||
InvertLinearTrans(Trans, Nodes[j], pt);
|
||||
if (Geometries.CheckPoint(geom_type, ipt)) // do we need an epsilon here?
|
||||
{
|
||||
CalcShape(ipt, shape);
|
||||
R.SetRow(j, shape);
|
||||
CalcShape(ipt, c_shape);
|
||||
R.SetRow(j, c_shape);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -695,7 +653,7 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans,
|
||||
R.Threshold(1e-12);
|
||||
}
|
||||
|
||||
void NodalFiniteElement::Project(
|
||||
void NodalFiniteElement::Project (
|
||||
Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
for (int i = 0; i < dof; i++)
|
||||
@@ -704,7 +662,7 @@ void NodalFiniteElement::Project(
|
||||
// some coefficients expect that Trans.IntPoint is the same
|
||||
// as the second argument of Eval
|
||||
Trans.SetIntPoint(&ip);
|
||||
dofs(i) = coeff.Eval(Trans, ip);
|
||||
dofs(i) = coeff.Eval (Trans, ip);
|
||||
if (map_type == INTEGRAL)
|
||||
{
|
||||
dofs(i) *= Trans.Weight();
|
||||
@@ -712,7 +670,7 @@ void NodalFiniteElement::Project(
|
||||
}
|
||||
}
|
||||
|
||||
void NodalFiniteElement::Project(
|
||||
void NodalFiniteElement::Project (
|
||||
VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
MFEM_ASSERT(dofs.Size() == vc.GetVDim()*dof, "");
|
||||
@@ -891,18 +849,18 @@ VectorFiniteElement::VectorFiniteElement(int D, Geometry::Type G,
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcShape(
|
||||
void VectorFiniteElement::CalcShape (
|
||||
const IntegrationPoint &ip, Vector &shape ) const
|
||||
{
|
||||
mfem_error("Error: Cannot use scalar CalcShape(...) function with\n"
|
||||
" VectorFiniteElements!");
|
||||
mfem_error ("Error: Cannot use scalar CalcShape(...) function with\n"
|
||||
" VectorFiniteElements!");
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcDShape(
|
||||
void VectorFiniteElement::CalcDShape (
|
||||
const IntegrationPoint &ip, DenseMatrix &dshape ) const
|
||||
{
|
||||
mfem_error("Error: Cannot use scalar CalcDShape(...) function with\n"
|
||||
" VectorFiniteElements!");
|
||||
mfem_error ("Error: Cannot use scalar CalcDShape(...) function with\n"
|
||||
" VectorFiniteElements!");
|
||||
}
|
||||
|
||||
void VectorFiniteElement::SetDerivMembers()
|
||||
@@ -942,7 +900,7 @@ void VectorFiniteElement::SetDerivMembers()
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcVShape_RT(
|
||||
void VectorFiniteElement::CalcVShape_RT (
|
||||
ElementTransformation &Trans, DenseMatrix &shape) const
|
||||
{
|
||||
MFEM_ASSERT(map_type == H_DIV, "");
|
||||
@@ -954,7 +912,7 @@ void VectorFiniteElement::CalcVShape_RT(
|
||||
shape *= (1.0 / Trans.Weight());
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcVShape_ND(
|
||||
void VectorFiniteElement::CalcVShape_ND (
|
||||
ElementTransformation &Trans, DenseMatrix &shape) const
|
||||
{
|
||||
MFEM_ASSERT(map_type == H_CURL, "");
|
||||
@@ -996,8 +954,8 @@ void VectorFiniteElement::Project_RT(
|
||||
{
|
||||
Trans.SetIntPoint(&Nodes.IntPoint(k));
|
||||
// dof_k = nk^t adj(J) xk
|
||||
dofs(k) = Trans.AdjugateJacobian().InnerProduct(
|
||||
&vc[k*sdim], nk + d2n[k]*dim);
|
||||
Vector vk(vc.GetData()+k*sdim, sdim);
|
||||
dofs(k) = Trans.AdjugateJacobian().InnerProduct(vk, nk + d2n[k]*dim);
|
||||
if (!square_J) { dofs(k) /= Trans.Weight(); }
|
||||
}
|
||||
}
|
||||
@@ -1213,8 +1171,9 @@ void VectorFiniteElement::Project_ND(
|
||||
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, &vc[k*dim]);
|
||||
dofs(k) = Trans.Jacobian().InnerProduct(tk + d2t[k]*dim, vk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1361,7 +1320,7 @@ void VectorFiniteElement::LocalL2Projection_RT(
|
||||
double w = ip.weight;
|
||||
this->CalcVShape(ip, fine_shape);
|
||||
Trans.Transform(ip, v);
|
||||
tr_ip.Set(v.GetData(), dim);
|
||||
tr_ip.Set(v, dim);
|
||||
cfe.CalcVShape(tr_ip, coarse_shape);
|
||||
|
||||
AddMult_a_AAt(w, fine_shape, fine_mass);
|
||||
@@ -1448,7 +1407,7 @@ void VectorFiniteElement::LocalL2Projection_ND(
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
this->CalcVShape(ip, fine_shape);
|
||||
Trans.Transform(ip, v);
|
||||
tr_ip.Set(v.GetData(), dim);
|
||||
tr_ip.Set(v, dim);
|
||||
cfe.CalcVShape(tr_ip, coarse_shape);
|
||||
|
||||
AddMult_a_AAt(ip.weight, fine_shape, fine_mass);
|
||||
@@ -2444,46 +2403,6 @@ TensorBasisElement::TensorBasisElement(const int dims, const int p,
|
||||
}
|
||||
}
|
||||
|
||||
const DofToQuad &TensorBasisElement::GetTensorDofToQuad(
|
||||
const FiniteElement &fe, const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode, const Poly_1D::Basis &basis, bool closed,
|
||||
Array<DofToQuad*> &dof2quad_array)
|
||||
{
|
||||
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
|
||||
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const int ndof = closed ? fe.GetOrder() + 1 : fe.GetOrder();
|
||||
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/fe.GetDim()) + 0.5);
|
||||
d2q->FE = &fe;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = ndof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*ndof);
|
||||
d2q->Bt.SetSize(ndof*nqpt);
|
||||
d2q->G.SetSize(nqpt*ndof);
|
||||
d2q->Gt.SetSize(ndof*nqpt);
|
||||
Vector val(ndof), grad(ndof);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
|
||||
// of the 1D rule.
|
||||
basis.Eval(ir.IntPoint(i).x, val, grad);
|
||||
for (int j = 0; j < ndof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
|
||||
}
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
NodalTensorFiniteElement::NodalTensorFiniteElement(const int dims,
|
||||
const int p,
|
||||
@@ -2518,7 +2437,8 @@ VectorTensorFiniteElement::VectorTensorFiniteElement(const int dims,
|
||||
const DofMapType dmtype)
|
||||
: VectorFiniteElement(dims, GetTensorProductGeometry(dims), d,
|
||||
p, M, FunctionSpace::Qk),
|
||||
TensorBasisElement(dims, p, VerifyNodal(VerifyClosed(cbtype)), dmtype),
|
||||
TensorBasisElement(dims, p, VerifyNodal(cbtype), dmtype),
|
||||
cbasis1d(poly1d.GetBasis(p, VerifyClosed(cbtype))),
|
||||
obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(obtype)))
|
||||
{
|
||||
MFEM_VERIFY(dims > 1, "Constructor for VectorTensorFiniteElement with both "
|
||||
@@ -2533,13 +2453,93 @@ VectorTensorFiniteElement::VectorTensorFiniteElement(const int dims,
|
||||
const DofMapType dmtype)
|
||||
: VectorFiniteElement(dims, GetTensorProductGeometry(dims), d,
|
||||
p, M, FunctionSpace::Pk),
|
||||
TensorBasisElement(dims, p, VerifyOpen(obtype), dmtype),
|
||||
TensorBasisElement(dims, p, obtype, dmtype),
|
||||
cbasis1d(poly1d.GetBasis(p, VerifyOpen(obtype))),
|
||||
obasis1d(poly1d.GetBasis(p, VerifyOpen(obtype)))
|
||||
{
|
||||
MFEM_VERIFY(dims == 1, "Constructor for VectorTensorFiniteElement without "
|
||||
"closed basis is only valid for 1D elements.");
|
||||
}
|
||||
|
||||
const DofToQuad &VectorTensorFiniteElement::GetDofToQuad(
|
||||
const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
|
||||
|
||||
return GetTensorDofToQuad(ir, mode, true);
|
||||
}
|
||||
|
||||
const DofToQuad &VectorTensorFiniteElement::GetDofToQuadOpen(
|
||||
const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
|
||||
|
||||
return GetTensorDofToQuad(ir, mode, false);
|
||||
}
|
||||
|
||||
const DofToQuad &VectorTensorFiniteElement::GetTensorDofToQuad(
|
||||
const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode,
|
||||
const bool closed) const
|
||||
{
|
||||
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
|
||||
|
||||
for (int i = 0;
|
||||
i < (closed ? dof2quad_array.Size() : dof2quad_array_open.Size());
|
||||
i++)
|
||||
{
|
||||
const DofToQuad &d2q = closed ? *dof2quad_array[i] : *dof2quad_array_open[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const int ndof = closed ? order + 1 : order;
|
||||
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5);
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = ndof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*ndof);
|
||||
d2q->Bt.SetSize(ndof*nqpt);
|
||||
d2q->G.SetSize(nqpt*ndof);
|
||||
d2q->Gt.SetSize(ndof*nqpt);
|
||||
Vector val(ndof), grad(ndof);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
|
||||
// of the 1D rule.
|
||||
|
||||
if (closed)
|
||||
{
|
||||
cbasis1d.Eval(ir.IntPoint(i).x, val, grad);
|
||||
}
|
||||
else
|
||||
{
|
||||
obasis1d.Eval(ir.IntPoint(i).x, val, grad);
|
||||
}
|
||||
|
||||
for (int j = 0; j < ndof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (closed)
|
||||
{
|
||||
dof2quad_array.Append(d2q);
|
||||
}
|
||||
else
|
||||
{
|
||||
dof2quad_array_open.Append(d2q);
|
||||
}
|
||||
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
VectorTensorFiniteElement::~VectorTensorFiniteElement()
|
||||
{
|
||||
for (int i = 0; i < dof2quad_array_open.Size(); i++)
|
||||
|
||||
+83
-100
@@ -127,6 +127,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @brief Structure representing the matrices/tensors needed to evaluate (in
|
||||
reference space) the values, gradients, divergences, or curls of a
|
||||
FiniteElement at a the quadrature points of a given IntegrationRule. */
|
||||
@@ -156,7 +157,8 @@ public:
|
||||
dimensions using 1D number of quadrature points and degrees of
|
||||
freedom. */
|
||||
/** When representing a vector-valued FiniteElement, two DofToQuad objects
|
||||
are used to describe the "closed" and "open" 1D basis functions. */
|
||||
are used to describe the "closed" and "open" 1D basis functions
|
||||
(TODO). */
|
||||
TENSOR
|
||||
};
|
||||
|
||||
@@ -174,7 +176,7 @@ public:
|
||||
/// Basis functions evaluated at quadrature points.
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #nqpt x #ndof, for scalar elements, or
|
||||
- #nqpt x dim x #ndof, for vector elements,
|
||||
- #nqpt x dim x #ndof, for vector elements, (TODO)
|
||||
|
||||
where
|
||||
|
||||
@@ -185,15 +187,15 @@ public:
|
||||
/// Transpose of #B.
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #ndof x #nqpt, for scalar elements, or
|
||||
- #ndof x #nqpt x dim, for vector elements. */
|
||||
- #ndof x #nqpt x dim, for vector elements (TODO). */
|
||||
Array<double> Bt;
|
||||
|
||||
/** @brief Gradients/divergences/curls of basis functions evaluated at
|
||||
quadrature points. */
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #nqpt x dim x #ndof, for scalar elements, or
|
||||
- #nqpt x #ndof, for H(div) vector elements, or
|
||||
- #nqpt x cdim x #ndof, for H(curl) vector elements,
|
||||
- #nqpt x #ndof, for H(div) vector elements (TODO), or
|
||||
- #nqpt x cdim x #ndof, for H(curl) vector elements (TODO),
|
||||
|
||||
where
|
||||
|
||||
@@ -206,11 +208,12 @@ public:
|
||||
/// Transpose of #G.
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #ndof x #nqpt x dim, for scalar elements, or
|
||||
- #ndof x #nqpt, for H(div) vector elements, or
|
||||
- #ndof x #nqpt x cdim, for H(curl) vector elements. */
|
||||
- #ndof x #nqpt, for H(div) vector elements (TODO), or
|
||||
- #ndof x #nqpt x cdim, for H(curl) vector elements (TODO). */
|
||||
Array<double> Gt;
|
||||
};
|
||||
|
||||
|
||||
/// Describes the function space on each element
|
||||
class FunctionSpace
|
||||
{
|
||||
@@ -244,7 +247,7 @@ protected:
|
||||
mutable int orders[Geometry::MaxDim]; ///< Anisotropic orders
|
||||
IntegrationRule Nodes;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable DenseMatrix vshape; // Dof x Dim
|
||||
mutable DenseMatrix vshape; // Dof x VDim
|
||||
#endif
|
||||
/// Container for all DofToQuad objects created by the FiniteElement.
|
||||
/** Multiple DofToQuad objects may be needed when different quadrature rules
|
||||
@@ -253,7 +256,7 @@ protected:
|
||||
|
||||
public:
|
||||
/// Enumeration for range_type and deriv_range_type
|
||||
enum RangeType { UNKNOWN_RANGE_TYPE = -1, SCALAR, VECTOR };
|
||||
enum RangeType { SCALAR, VECTOR };
|
||||
|
||||
/** @brief Enumeration for MapType: defines how reference functions are
|
||||
mapped to physical space.
|
||||
@@ -267,8 +270,6 @@ public:
|
||||
*/
|
||||
enum MapType
|
||||
{
|
||||
UNKNOWN_MAP_TYPE = -1, /**< Used to distinguish an unset MapType variable
|
||||
from the known values below. */
|
||||
VALUE, /**< For scalar fields; preserves point values
|
||||
\f$ u(x) = \hat u(\hat x) \f$ */
|
||||
INTEGRAL, /**< For scalar fields; preserves volume integrals
|
||||
@@ -347,6 +348,7 @@ public:
|
||||
H_DIV, H_CURL}. */
|
||||
int GetMapType() const { return map_type; }
|
||||
|
||||
|
||||
/** @brief Returns the FiniteElement::DerivType of the element describing the
|
||||
spatial derivative method implemented, one of {NONE, GRAD,
|
||||
DIV, CURL}. */
|
||||
@@ -453,8 +455,8 @@ public:
|
||||
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.*/
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
virtual void CalcHessian (const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
|
||||
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
|
||||
element in reference space at the given point @a ip. */
|
||||
@@ -575,7 +577,6 @@ public:
|
||||
/** See the documentation for DofToQuad for more details. */
|
||||
virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const;
|
||||
|
||||
/// Deconstruct the FiniteElement
|
||||
virtual ~FiniteElement();
|
||||
|
||||
@@ -622,11 +623,16 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @brief Class for finite elements with basis functions
|
||||
that return scalar values. */
|
||||
class ScalarFiniteElement : public FiniteElement
|
||||
{
|
||||
protected:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector c_shape;
|
||||
#endif
|
||||
|
||||
static const ScalarFiniteElement &CheckScalarFE(const FiniteElement &fe)
|
||||
{
|
||||
MFEM_VERIFY(fe.GetRangeType() == SCALAR,
|
||||
@@ -634,6 +640,10 @@ protected:
|
||||
return static_cast<const ScalarFiniteElement &>(fe);
|
||||
}
|
||||
|
||||
const DofToQuad &GetTensorDofToQuad(const class TensorBasisElement &tb,
|
||||
const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const;
|
||||
|
||||
public:
|
||||
/** @brief Construct ScalarFiniteElement with given
|
||||
@param D Reference space dimension
|
||||
@@ -644,8 +654,13 @@ public:
|
||||
*/
|
||||
ScalarFiniteElement(int D, Geometry::Type G, int Do, int O,
|
||||
int F = FunctionSpace::Pk)
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
: FiniteElement(D, G, Do, O, F)
|
||||
{ deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; }
|
||||
#else
|
||||
: FiniteElement(D, G, Do, O, F), c_shape(dof)
|
||||
{ deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; }
|
||||
#endif
|
||||
|
||||
/** @brief Set the FiniteElement::MapType of the element to either VALUE or
|
||||
INTEGRAL. Also sets the FiniteElement::DerivType to GRAD if the
|
||||
@@ -657,6 +672,7 @@ public:
|
||||
deriv_type = (M == VALUE) ? GRAD : NONE;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Get the matrix @a I that defines nodal interpolation
|
||||
@a between this element and the refined element @a fine_fe. */
|
||||
void NodalLocalInterpolation(ElementTransformation &Trans,
|
||||
@@ -677,11 +693,15 @@ public:
|
||||
/** If the "fine" elements cannot represent all basis functions of the
|
||||
"coarse" element, then boundary values from different sub-elements are
|
||||
generally different. */
|
||||
void ScalarLocalL2Restriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R,
|
||||
const ScalarFiniteElement &coarse_fe) const;
|
||||
void ScalarLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R,
|
||||
const ScalarFiniteElement &coarse_fe) const;
|
||||
|
||||
virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const;
|
||||
};
|
||||
|
||||
|
||||
/// Class for standard nodal finite elements.
|
||||
class NodalFiniteElement : public ScalarFiniteElement
|
||||
{
|
||||
@@ -703,38 +723,38 @@ public:
|
||||
int F = FunctionSpace::Pk)
|
||||
: ScalarFiniteElement(D, G, Do, O, F) { }
|
||||
|
||||
void GetLocalInterpolation(ElementTransformation &Trans,
|
||||
DenseMatrix &I) const override
|
||||
virtual void GetLocalInterpolation(ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{ NodalLocalInterpolation(Trans, I, *this); }
|
||||
|
||||
void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const override;
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const;
|
||||
|
||||
void GetTransferMatrix(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const override
|
||||
virtual void GetTransferMatrix(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{ CheckScalarFE(fe).NodalLocalInterpolation(Trans, I, *this); }
|
||||
|
||||
void Project(Coefficient &coeff,
|
||||
ElementTransformation &Trans, Vector &dofs) const override;
|
||||
virtual void Project (Coefficient &coeff,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const override;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
// (mc.height x mc.width) @ DOFs -> (Dof x mc.width x mc.height) in dofs
|
||||
void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const override;
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
|
||||
|
||||
void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const override;
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const override;
|
||||
virtual void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
|
||||
void ProjectDiv(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &div) const override;
|
||||
virtual void ProjectDiv(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &div) const;
|
||||
|
||||
/** @brief Get an Array<int> that maps lexicographically ordered indices to
|
||||
the indices of the respective nodes/dofs/basis functions.
|
||||
@@ -768,12 +788,12 @@ class VectorFiniteElement : public FiniteElement
|
||||
// Hide the scalar functions CalcShape and CalcDShape.
|
||||
private:
|
||||
/// Overrides the scalar CalcShape function to print an error.
|
||||
void CalcShape(const IntegrationPoint &ip,
|
||||
Vector &shape) const override;
|
||||
virtual void CalcShape(const IntegrationPoint &ip,
|
||||
Vector &shape) const;
|
||||
|
||||
/// Overrides the scalar CalcDShape function to print an error.
|
||||
void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const override;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
|
||||
protected:
|
||||
bool is_nodal;
|
||||
@@ -932,10 +952,11 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
VectorFiniteElement(int D, Geometry::Type G, int Do, int O, int M,
|
||||
int F = FunctionSpace::Pk);
|
||||
VectorFiniteElement (int D, Geometry::Type G, int Do, int O, int M,
|
||||
int F = FunctionSpace::Pk);
|
||||
};
|
||||
|
||||
|
||||
/// @brief Class for computing 1D special polynomials and their associated basis
|
||||
/// functions
|
||||
class Poly_1D
|
||||
@@ -1070,11 +1091,6 @@ public:
|
||||
// { CalcLegendre(p, x, u); }
|
||||
{ CalcChebyshev(p, x, u); }
|
||||
|
||||
/** @brief Evaluate the values of a hierarchical 1D basis at point x
|
||||
hierarchical = k-th basis function is degree k polynomial */
|
||||
static void CalcBasis(const int p, const double x, Vector &u)
|
||||
{ CalcBasis(p, x, u.GetData()); }
|
||||
|
||||
/// Evaluate the values and derivatives of a hierarchical 1D basis at point @a x
|
||||
static void CalcBasis(const int p, const double x, double *u, double *d)
|
||||
// { CalcMono(p, x, u, d); }
|
||||
@@ -1082,11 +1098,6 @@ public:
|
||||
// { CalcLegendre(p, x, u, d); }
|
||||
{ CalcChebyshev(p, x, u, d); }
|
||||
|
||||
/** @brief Evaluate the values and derivatives of a hierarchical 1D basis at
|
||||
point @a x. */
|
||||
static void CalcBasis(const int p, const double x, Vector &u, Vector &d)
|
||||
{ CalcBasis(p, x, u.GetData(), d.GetData()); }
|
||||
|
||||
/// Evaluate the values, derivatives and second derivatives of a hierarchical 1D basis at point x
|
||||
static void CalcBasis(const int p, const double x, double *u, double *d,
|
||||
double *dd)
|
||||
@@ -1095,12 +1106,6 @@ public:
|
||||
// { CalcLegendre(p, x, u, d); }
|
||||
{ CalcChebyshev(p, x, u, d, dd); }
|
||||
|
||||
/** @brief Evaluate the values, derivatives and second derivatives of a
|
||||
hierarchical 1D basis at point @a x. */
|
||||
static void CalcBasis(const int p, const double x, Vector &u, Vector &d,
|
||||
Vector &dd)
|
||||
{ CalcBasis(p, x, u.GetData(), d.GetData(), dd.GetData()); }
|
||||
|
||||
/// Evaluate a representation of a Delta function at point x
|
||||
static double CalcDelta(const int p, const double x)
|
||||
{ return pow(x, (double) p); }
|
||||
@@ -1130,31 +1135,20 @@ public:
|
||||
static void CalcBernstein(const int p, const double x, double *u)
|
||||
{ CalcBinomTerms(p, x, 1. - x, u); }
|
||||
|
||||
/** @brief Compute the values of the Bernstein basis functions of order
|
||||
@a p at coordinate @a x and store the results in the already allocated
|
||||
@a u array. */
|
||||
static void CalcBernstein(const int p, const double x, Vector &u)
|
||||
{ CalcBernstein(p, x, u.GetData()); }
|
||||
|
||||
/** @brief Compute the values and derivatives of the Bernstein basis functions
|
||||
of order @a p at coordinate @a x and store the results in the already allocated
|
||||
@a u and @a d arrays. */
|
||||
static void CalcBernstein(const int p, const double x, double *u, double *d)
|
||||
{ CalcBinomTerms(p, x, 1. - x, u, d); }
|
||||
|
||||
/** @brief Compute the values and derivatives of the Bernstein basis
|
||||
functions of order @a p at coordinate @a x and store the results in the
|
||||
already allocated @a u and @a d arrays. */
|
||||
static void CalcBernstein(const int p, const double x, Vector &u, Vector &d)
|
||||
{ CalcBernstein(p, x, u.GetData(), d.GetData()); }
|
||||
|
||||
static void CalcLegendre(const int p, const double x, double *u);
|
||||
static void CalcLegendre(const int p, const double x, double *u, double *d);
|
||||
|
||||
~Poly_1D();
|
||||
};
|
||||
|
||||
extern MFEM_EXPORT Poly_1D poly1d;
|
||||
extern Poly_1D poly1d;
|
||||
|
||||
|
||||
/// An element defined as an ND tensor product of 1D elements on a segment,
|
||||
/// square, or cube
|
||||
@@ -1179,7 +1173,7 @@ public:
|
||||
|
||||
int GetBasisType() const { return b_type; }
|
||||
|
||||
const Poly_1D::Basis &GetBasis1D() const { return basis1d; }
|
||||
const Poly_1D::Basis& GetBasis1D() const { return basis1d; }
|
||||
|
||||
/** @brief Get an Array<int> that maps lexicographically ordered indices to
|
||||
the indices of the respective nodes/dofs/basis functions. If the dofs are
|
||||
@@ -1211,11 +1205,6 @@ public:
|
||||
default: MFEM_ABORT("invalid dimension: " << dim); return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static const DofToQuad &GetTensorDofToQuad(
|
||||
const FiniteElement &fe, const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode, const Poly_1D::Basis &basis, bool closed,
|
||||
Array<DofToQuad*> &dof2quad_array);
|
||||
};
|
||||
|
||||
class NodalTensorFiniteElement : public NodalFiniteElement,
|
||||
@@ -1226,18 +1215,18 @@ public:
|
||||
const DofMapType dmtype);
|
||||
|
||||
const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const override
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
return (mode == DofToQuad::FULL) ?
|
||||
FiniteElement::GetDofToQuad(ir, mode) :
|
||||
GetTensorDofToQuad(*this, ir, mode, basis1d, true, dof2quad_array);
|
||||
ScalarFiniteElement::GetDofToQuad(ir, mode) :
|
||||
ScalarFiniteElement::GetTensorDofToQuad(*this, ir, mode);
|
||||
}
|
||||
|
||||
void SetMapType(const int map_type_) override;
|
||||
virtual void SetMapType(const int map_type_);
|
||||
|
||||
void GetTransferMatrix(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const override
|
||||
virtual void GetTransferMatrix(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{
|
||||
if (basis1d.IsIntegratedType())
|
||||
{
|
||||
@@ -1257,7 +1246,7 @@ private:
|
||||
mutable Array<DofToQuad*> dof2quad_array_open;
|
||||
|
||||
protected:
|
||||
Poly_1D::Basis &obasis1d;
|
||||
Poly_1D::Basis &cbasis1d, &obasis1d;
|
||||
|
||||
public:
|
||||
VectorTensorFiniteElement(const int dims, const int d, const int p,
|
||||
@@ -1270,22 +1259,16 @@ public:
|
||||
const DofMapType dmtype);
|
||||
|
||||
const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const override
|
||||
{
|
||||
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
|
||||
return GetTensorDofToQuad(*this, ir, mode, basis1d, true,
|
||||
dof2quad_array);
|
||||
}
|
||||
DofToQuad::Mode mode) const;
|
||||
|
||||
const DofToQuad &GetDofToQuadOpen(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
|
||||
return GetTensorDofToQuad(*this, ir, mode, obasis1d, false,
|
||||
dof2quad_array_open);
|
||||
}
|
||||
DofToQuad::Mode mode) const;
|
||||
|
||||
virtual ~VectorTensorFiniteElement();
|
||||
const DofToQuad &GetTensorDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode,
|
||||
const bool closed) const;
|
||||
|
||||
~VectorTensorFiniteElement();
|
||||
};
|
||||
|
||||
void InvertLinearTrans(ElementTransformation &trans,
|
||||
|
||||
@@ -32,11 +32,6 @@ public:
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ ScalarLocalL2Restriction(Trans, R, *this); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -60,11 +55,6 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const
|
||||
{ ProjectCurl_2D(fe, Trans, curl); }
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ ScalarLocalL2Restriction(Trans, R, *this); }
|
||||
|
||||
using FiniteElement::Project;
|
||||
virtual void ProjectDiv(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
@@ -90,11 +80,6 @@ public:
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ ScalarLocalL2Restriction(Trans, R, *this); }
|
||||
|
||||
using FiniteElement::Project;
|
||||
virtual void ProjectDiv(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
@@ -126,11 +111,6 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const
|
||||
{ ProjectCurl_2D(fe, Trans, curl); }
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ ScalarLocalL2Restriction(Trans, R, *this); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -153,11 +133,6 @@ public:
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ ScalarLocalL2Restriction(Trans, R, *this); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
+17
-21
@@ -314,16 +314,14 @@ void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p);
|
||||
Vector shape_cz(p + 1), shape_oz(p);
|
||||
Vector dshape_cx, dshape_cy, dshape_cz;
|
||||
#endif
|
||||
|
||||
if (obasis1d.IsIntegratedType())
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector dshape_cx(p + 1), dshape_cy(p + 1), dshape_cz(p + 1);
|
||||
#endif
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
basis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
|
||||
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
|
||||
@@ -331,9 +329,9 @@ void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
|
||||
}
|
||||
else
|
||||
{
|
||||
basis1d.Eval(ip.x, shape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy);
|
||||
basis1d.Eval(ip.z, shape_cz);
|
||||
cbasis1d.Eval(ip.x, shape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy);
|
||||
cbasis1d.Eval(ip.z, shape_cz);
|
||||
obasis1d.Eval(ip.x, shape_ox);
|
||||
obasis1d.Eval(ip.y, shape_oy);
|
||||
obasis1d.Eval(ip.z, shape_oz);
|
||||
@@ -407,9 +405,9 @@ void ND_HexahedronElement::CalcCurlShape(const IntegrationPoint &ip,
|
||||
Vector dshape_cx(p + 1), dshape_cy(p + 1), dshape_cz(p + 1);
|
||||
#endif
|
||||
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
basis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
if (obasis1d.IsIntegratedType())
|
||||
{
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
@@ -658,23 +656,21 @@ void ND_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip,
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p);
|
||||
Vector dshape_cx, dshape_cy;
|
||||
#endif
|
||||
|
||||
if (obasis1d.IsIntegratedType())
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector dshape_cx(p + 1), dshape_cy(p + 1);
|
||||
#endif
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
|
||||
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
|
||||
}
|
||||
else
|
||||
{
|
||||
basis1d.Eval(ip.x, shape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy);
|
||||
cbasis1d.Eval(ip.x, shape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy);
|
||||
obasis1d.Eval(ip.x, shape_ox);
|
||||
obasis1d.Eval(ip.y, shape_oy);
|
||||
}
|
||||
@@ -724,8 +720,8 @@ void ND_QuadrilateralElement::CalcCurlShape(const IntegrationPoint &ip,
|
||||
Vector dshape_cx(p + 1), dshape_cy(p + 1);
|
||||
#endif
|
||||
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
if (obasis1d.IsIntegratedType())
|
||||
{
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
|
||||
+5
-6
@@ -13,7 +13,6 @@
|
||||
|
||||
#include "fe_pos.hpp"
|
||||
#include "../bilininteg.hpp"
|
||||
#include "../lininteg.hpp"
|
||||
#include "../coefficient.hpp"
|
||||
|
||||
namespace mfem
|
||||
@@ -213,7 +212,7 @@ void BiQuadPos2DFiniteElement::GetLocalInterpolation(
|
||||
void BiQuadPos2DFiniteElement::Project(
|
||||
Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
double *d = dofs.GetData();
|
||||
double *d = dofs;
|
||||
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
@@ -383,8 +382,8 @@ void H1Pos_QuadrilateralElement::CalcShape(const IntegrationPoint &ip,
|
||||
Vector shape_x(p+1), shape_y(p+1);
|
||||
#endif
|
||||
|
||||
Poly_1D::CalcBernstein(p, ip.x, shape_x);
|
||||
Poly_1D::CalcBernstein(p, ip.y, shape_y);
|
||||
Poly_1D::CalcBernstein(p, ip.x, shape_x.GetData() );
|
||||
Poly_1D::CalcBernstein(p, ip.y, shape_y.GetData() );
|
||||
|
||||
// Reorder so that vertices are at the beginning of the list
|
||||
for (int o = 0, j = 0; j <= p; j++)
|
||||
@@ -403,8 +402,8 @@ void H1Pos_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
|
||||
Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1);
|
||||
#endif
|
||||
|
||||
Poly_1D::CalcBernstein(p, ip.x, shape_x, dshape_x);
|
||||
Poly_1D::CalcBernstein(p, ip.y, shape_y, dshape_y);
|
||||
Poly_1D::CalcBernstein(p, ip.x, shape_x.GetData(), dshape_x.GetData() );
|
||||
Poly_1D::CalcBernstein(p, ip.y, shape_y.GetData(), dshape_y.GetData() );
|
||||
|
||||
// Reorder so that vertices are at the beginning of the list
|
||||
for (int o = 0, j = 0; j <= p; j++)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user