Compare commits

..
632 changed files with 23809 additions and 58626 deletions
@@ -1,6 +1,7 @@
name: "Docker"
on:
# Always have a base image ready to go - this is a nightly build
schedule:
- cron: 0 3 * * *
@@ -25,6 +26,7 @@ jobs:
strategy:
fail-fast: false
matrix:
# Dockerfiles to build, a matrix supports future expanded builds
container: [["config/docker/Dockerfile.base", "ghcr.io/mfem/mfem-ubuntu-base"],
["config/docker/Dockerfile", "ghcr.io/mfem/mfem-ubuntu"]]
@@ -32,20 +34,15 @@ jobs:
runs-on: ubuntu-latest
name: Build
steps:
- name: Run Actions Cleaner
uses: easimon/maximize-build-space@v8
with:
overprovision-lvm: 'true'
remove-dotnet: 'true'
remove-android: 'true'
remove-haskell: 'true'
remove-codeql: 'true'
remove-docker-images: 'true'
- name: Checkout
uses: actions/checkout@v3
# It's easier to reference named variables than indexes of the matrix
- name: Make Space For Build
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
# It's easier to reference named variables than indexes of the matrix
- name: Set Environment
env:
dockerfile: ${{ matrix.container[0] }}
+157 -168
View File
@@ -65,16 +65,13 @@ jobs:
# - Add a new combination.
# 'build-system: cmake' and 'hypre-target: int64'
#
# Note: we will gather coverage info for any non-debug run except the
# note: we will gather coverage info for any non-debug run except the
# CMake build.
include:
- target: dbg
codecov: NO
- target: opt
codecov: YES
- os: ubuntu-latest
target: dbg
config-opts: 'CPPFLAGS+=-Og'
- os: windows-latest
codecov: NO
- os: windows-latest
@@ -101,189 +98,181 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
# This external action allows to interrupt a workflow already running on
# the same branch to save resources.
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
# 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
with:
access_token: ${{ github.token }}
# Fix 'No space left on device' errors for Ubuntu builds.
- name: Run Actions Cleaner
if: matrix.os == 'ubuntu-latest'
uses: easimon/maximize-build-space@v8
with:
overprovision-lvm: 'true'
remove-android: 'true'
# Checkout MFEM in "mfem" subdirectory. Final path:
# /home/runner/work/mfem/mfem/mfem
# Note: Done now to access "install-hypre" and "install-metis" actions.
- name: checkout mfem
uses: actions/checkout@v3
with:
path: ${{ env.MFEM_TOP_DIR }}
# Fetch the complete history for codecov to access commits ID
fetch-depth: 0
# Checkout MFEM in "mfem" subdirectory. Final path:
# /home/runner/work/mfem/mfem/mfem
# Note: Done now to access "install-hypre" and "install-metis" actions.
- name: checkout mfem
uses: actions/checkout@v3
with:
path: ${{ env.MFEM_TOP_DIR }}
# Fetch the complete history for codecov to access commits ID
fetch-depth: 0
# Only get MPI if defined for the job.
# TODO: It would be nice to have only one step, e.g. with a dedicated
# action, but I (@adrienbernede) don't see how at the moment.
- name: get MPI (Linux)
if: matrix.mpi == 'par' && matrix.os == 'ubuntu-latest'
run: |
sudo apt-get install mpich libmpich-dev
# Only get MPI if defined for the job.
# TODO: It would be nice to have only one step, e.g. with a dedicated
# action, but I (@adrienbernede) don't see how at the moment.
- name: get MPI (Linux)
if: matrix.mpi == 'par' && matrix.os == 'ubuntu-latest'
run: |
sudo apt-get install mpich libmpich-dev
- name: get lcov (Linux)
if: matrix.codecov == 'YES' && matrix.os == 'ubuntu-latest'
run: |
sudo apt-get install lcov
- 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
# 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: get MPI (MacOS)
if: matrix.mpi == 'par' && matrix.os == 'macos-latest'
run: |
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install openmpi
- name: get MPI (MacOS)
if: matrix.mpi == 'par' && matrix.os == 'macos-latest'
run: |
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install openmpi
- name: get lcov (MacOS)
if: matrix.codecov == 'YES' && matrix.os == 'macos-latest'
run: |
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install lcov
- name: get lcov (MacOS)
if: matrix.codecov == 'YES' && matrix.os == 'macos-latest'
run: |
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install lcov
- name: get MPI (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
uses: mpi4py/setup-mpi@v1.1.4
- name: get MPI (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
uses: mpi4py/setup-mpi@v1.1.4
# 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
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-v2.2
# 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
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-v2.2
- name: get hypre
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os != 'windows-latest'
uses: mfem/github-actions/build-hypre@v2.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: make
- name: get hypre
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os != 'windows-latest'
uses: mfem/github-actions/build-hypre@v2.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: make
- name: get hypre (Windows)
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os == 'windows-latest'
uses: mfem/github-actions/build-hypre@v2.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: cmake
- name: get hypre (Windows)
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os == 'windows-latest'
uses: mfem/github-actions/build-hypre@v2.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: cmake
# Get Metis through cache, or build it.
# Install will only run on cache miss.
- name: cache metis
id: metis-cache
if: matrix.mpi == 'par' && matrix.os != 'windows-latest'
uses: actions/cache@v3
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
# Get Metis through cache, or build it.
# Install will only run on cache miss.
- name: cache metis
id: metis-cache
if: matrix.mpi == 'par' && matrix.os != 'windows-latest'
uses: actions/cache@v3
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
- name: install metis
if: matrix.mpi == 'par' && matrix.os != 'windows-latest' && steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.4
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
- name: install metis
if: matrix.mpi == 'par' && matrix.os != 'windows-latest' && steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.4
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
- 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: 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)
if: matrix.os == 'windows-latest' && steps.vcpkg-cache.outputs.cache-hit != 'true'
run: |
mkdir -p vcpkg_cache
- name: prepare vcpkg binary cache location (Windows)
if: matrix.os == 'windows-latest' && steps.vcpkg-cache.outputs.cache-hit != 'true'
run: |
mkdir -p vcpkg_cache
- name: install metis (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
run: |
vcpkg install metis-mfem --triplet=x64-windows-static --overlay-ports=${{ env.MFEM_TOP_DIR }}/config/vcpkg/ports
- name: install metis (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
run: |
vcpkg install metis-mfem --triplet=x64-windows-static --overlay-ports=${{ env.MFEM_TOP_DIR }}/config/vcpkg/ports
# MFEM build and test
- name: build
uses: mfem/github-actions/build-mfem@v2.4
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
with:
os: ${{ matrix.os }}
target: ${{ matrix.target }}
codecov: ${{ matrix.codecov }}
mpi: ${{ matrix.mpi }}
build-system: ${{ matrix.build-system }}
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
mfem-dir: ${{ env.MFEM_TOP_DIR }}
config-options: ${{ matrix.config-opts }}
library-only: ${{ matrix.target == 'dbg' }}
# MFEM build and test
- name: build
uses: mfem/github-actions/build-mfem@v2.4
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
with:
os: ${{ matrix.os }}
target: ${{ matrix.target }}
codecov: ${{ matrix.codecov }}
mpi: ${{ matrix.mpi }}
build-system: ${{ matrix.build-system }}
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
mfem-dir: ${{ env.MFEM_TOP_DIR }}
config-options: ${{ matrix.config-opts }}
library-only: ${{ matrix.target == 'dbg' && matrix.os != 'ubuntu-latest' }}
# Run checks (and only checks) on debug targets
- name: checks
if: matrix.build-system == 'make' && matrix.target == 'dbg'
run: |
cd ${{ env.MFEM_TOP_DIR }} && make check
# Run checks (and only checks) on debug targets
- name: checks
if: matrix.build-system == 'make' && matrix.target == 'dbg'
run: |
cd ${{ env.MFEM_TOP_DIR }} && make check
# Note: 'tests' include the unit tests
- name: tests
if: matrix.build-system == 'make' && matrix.target == 'opt'
run: |
cd ${{ env.MFEM_TOP_DIR }} && make test
# Note: 'tests' include the unit tests
- name: tests
if: matrix.build-system == 'make' && (matrix.target == 'opt' || matrix.os == 'ubuntu-latest')
run: |
cd ${{ env.MFEM_TOP_DIR }} && make test
- name: cmake checks
if: matrix.build-system == 'cmake' && matrix.target == 'dbg'
run: |
CTEST_CONFIG="Debug"
cd ${{ env.MFEM_TOP_DIR }} && cmake --build build --target check --config ${CTEST_CONFIG}
shell: bash
- name: cmake checks
if: matrix.build-system == 'cmake' && matrix.target == 'dbg'
run: |
CTEST_CONFIG="Debug"
cd ${{ env.MFEM_TOP_DIR }} && cmake --build build --target check --config ${CTEST_CONFIG}
shell: bash
- name: cmake unit tests (Ubuntu)
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os == 'ubuntu-latest'
run: |
CTEST_CONFIG="Release"
[[ ${{ matrix.target }} == 'dbg' ]] && CTEST_CONFIG="Debug"
cd ${{ env.MFEM_TOP_DIR }}/build/tests/unit && ctest --output-on-failure -C ${CTEST_CONFIG}
shell: bash
- name: cmake unit tests (Ubuntu)
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os == 'ubuntu-latest'
run: |
CTEST_CONFIG="Release"
[[ ${{ matrix.target }} == 'dbg' ]] && CTEST_CONFIG="Debug"
cd ${{ env.MFEM_TOP_DIR }}/build/tests/unit && ctest --output-on-failure -C ${CTEST_CONFIG}
shell: bash
- name: cmake tests
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os != 'ubuntu-latest'
run: |
CTEST_CONFIG="Release"
cd ${{ env.MFEM_TOP_DIR }}/build && \
ctest --output-on-failure -C ${CTEST_CONFIG} || \
ctest --rerun-failed --output-on-failure -C ${CTEST_CONFIG}
shell: bash
- name: cmake tests
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os != 'ubuntu-latest'
run: |
CTEST_CONFIG="Release"
cd ${{ env.MFEM_TOP_DIR }}/build && \
ctest --output-on-failure -C ${CTEST_CONFIG} || \
ctest --rerun-failed --output-on-failure -C ${CTEST_CONFIG}
shell: bash
# Code coverage (process and upload reports)
- name: codecov
if: matrix.codecov == 'YES'
uses: mfem/github-actions/upload-coverage@v2.4
with:
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
project_dir: ${{ env.MFEM_TOP_DIR }}
directories: "fem general linalg mesh"
# Code coverage (process and upload reports)
- name: codecov
if: matrix.codecov == 'YES'
uses: mfem/github-actions/upload-coverage@v2.4
with:
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
project_dir: ${{ env.MFEM_TOP_DIR }}
directories: "fem general linalg mesh"
+28 -27
View File
@@ -13,10 +13,10 @@ name: "Static Analysis"
on:
push:
branches: ["master", "next"]
branches: [ "master", "next"]
pull_request:
# The branches below must be a subset of the branches above
branches: ["master"]
branches: [ "master" ]
jobs:
analyze:
@@ -35,35 +35,36 @@ jobs:
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# 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
# 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
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
+55 -55
View File
@@ -34,67 +34,67 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: checkout MFEM
uses: actions/checkout@v3
with:
path: mfem
- name: checkout MFEM
uses: actions/checkout@v3
with:
path: mfem
- name: Get MPI (Linux)
run: |
sudo apt-get install mpich libmpich-dev
- name: Get MPI (Linux)
run: |
sudo apt-get install mpich libmpich-dev
- name: Cache Hypre Install
id: hypre-cache
uses: actions/cache@v3
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.2
- name: Cache Hypre Install
id: hypre-cache
uses: actions/cache@v3
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.2
- name: Get Hypre
if: steps.hypre-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-hypre@v2.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: int32
- name: Get Hypre
if: steps.hypre-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-hypre@v2.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: int32
- name: Cache Metis Install
id: metis-cache
uses: actions/cache@v3
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
- name: Cache Metis Install
id: metis-cache
uses: actions/cache@v3
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
- name: Install Metis
if: steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.4
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
- name: Install Metis
if: steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.4
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
# MFEM build and test
- name: build-mfem
uses: mfem/github-actions/build-mfem@v2.4
with:
os: ${{ runner.os }}
target: opt
codecov: NO
mpi: par
build-system: make
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
mfem-dir: mfem
# MFEM build and test
- name: build-mfem
uses: mfem/github-actions/build-mfem@v2.4
with:
os: ${{ runner.os }}
target: opt
codecov: NO
mpi: par
build-system: make
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
mfem-dir: mfem
- name: test (no clean)
run: |
cd mfem && make test-noclean
- name: test (no clean)
run: |
cd mfem && make test-noclean
- name: gitignore
run: |
cd mfem/tests/scripts
./runtest gitignore
- name: gitignore
run: |
cd mfem/tests/scripts
./runtest gitignore
+37 -37
View File
@@ -27,44 +27,44 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: MFEM Checkout
uses: actions/checkout@v3
with:
path: mfem
- name: MFEM Checkout
uses: actions/checkout@v3
with:
path: mfem
- name: MFEM Build
uses: mfem/github-actions/build-mfem@v2.4
with:
os: ${{ runner.os }}
target: opt
mpi: seq
hypre-dir: unused-hypre-dir
metis-dir: unused-metis-dir
mfem-dir: mfem
build-system: make
library-only: false
config-options:
CXX="clang++-14"
CXXFLAGS="-g -O1 -std=c++11
-fsanitize=address
-fno-omit-frame-pointer
-fsanitize-address-use-after-scope"
- name: MFEM Build
uses: mfem/github-actions/build-mfem@v2.4
with:
os: ${{ runner.os }}
target: opt
mpi: seq
hypre-dir: unused-hypre-dir
metis-dir: unused-metis-dir
mfem-dir: mfem
build-system: make
library-only: false
config-options:
CXX="clang++-14"
CXXFLAGS="-g -O1 -std=c++11
-fsanitize=address
-fno-omit-frame-pointer
-fsanitize-address-use-after-scope"
- name: MFEM Info
working-directory: mfem
run: make info
- name: MFEM Info
working-directory: mfem
run: make info
- name: MFEM Sanitize
working-directory: mfem
run:
ASAN_OPTIONS="detect_leaks=1,
strict_init_order=1,
strict_string_checks=1,
check_initialization_order=1,
detect_stack_use_after_return=1"
make test
- name: MFEM Sanitize
working-directory: mfem
run:
ASAN_OPTIONS="detect_leaks=1,
strict_init_order=1,
strict_string_checks=1,
check_initialization_order=1,
detect_stack_use_after_return=1"
make test
+70 -70
View File
@@ -33,49 +33,49 @@ jobs:
(github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: checkout mfem
uses: actions/checkout@v3
- name: checkout mfem
uses: actions/checkout@v3
- name: copyright check
id: copyright
run: |
./config/githooks/pre-push --copyright
- name: copyright check
id: copyright
run: |
./config/githooks/pre-push --copyright
continue-on-error: true
continue-on-error: true
- name: license check
id: license
run: |
./config/githooks/pre-push --license
continue-on-error: true
- name: license check
id: license
run: |
./config/githooks/pre-push --license
continue-on-error: true
- name: release check
id: release
run: |
./config/githooks/pre-push --release
continue-on-error: true
- name: release check
id: release
run: |
./config/githooks/pre-push --release
continue-on-error: true
- name: wrap-up
if: |
steps.copyright.outcome != 'success' ||
steps.license.outcome != 'success' ||
steps.release.outcome != 'success'
run: |
if [[ "${{ steps.copyright.outcome }}" != "success" ]]; then
echo "copyright check failed, unroll log for details"
fi
if [[ "${{ steps.license.outcome }}" != "success" ]]; then
echo "license check failed, unroll log for details"
fi
if [[ "${{ steps.release.outcome }}" != "success" ]]; then
echo "release check failed, unroll log for details"
fi
exit 1
- name: wrap-up
if: |
steps.copyright.outcome != 'success' ||
steps.license.outcome != 'success' ||
steps.release.outcome != 'success'
run: |
if [[ "${{ steps.copyright.outcome }}" != "success" ]]; then
echo "copyright check failed, unroll log for details"
fi
if [[ "${{ steps.license.outcome }}" != "success" ]]; then
echo "license check failed, unroll log for details"
fi
if [[ "${{ steps.release.outcome }}" != "success" ]]; then
echo "release check failed, unroll log for details"
fi
exit 1
code-style:
runs-on: ubuntu-latest
@@ -83,16 +83,16 @@ jobs:
(github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v3
- name: checkout mfem
uses: actions/checkout@v3
- name: get astyle
run: |
sudo apt-get install astyle
- name: get astyle
run: |
sudo apt-get install astyle
- name: style check
run: |
./config/githooks/pre-push --style
- name: style check
run: |
./config/githooks/pre-push --style
documentation:
runs-on: ubuntu-latest
@@ -100,22 +100,22 @@ jobs:
(github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v3
- name: checkout mfem
uses: actions/checkout@v3
- name: get doxygen and graphviz
run: |
sudo apt-get install doxygen graphviz
- 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
- name: update doxygen config file
run: |
cd doc
doxygen -u CodeDocumentation.conf.in
- name: build documentation
run: |
cd tests/scripts
./runtest documentation
- name: build documentation
run: |
cd tests/scripts
./runtest documentation
branch-history:
if: |
@@ -125,16 +125,16 @@ jobs:
github.event.pull_request.head.repo.full_name != github.repository)
runs-on: ubuntu-latest
steps:
- name: checkout mfem
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: checkout mfem
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: branch-history
run: |
# We override origin to make sure we point to the main repo.
# This is to have consistent test results on PRs from forks.
git remote remove origin
git remote add origin https://github.com/mfem/mfem.git
git checkout -b gh-actions-branch-history
./config/githooks/pre-push --history
- name: branch-history
run: |
# We override origin to make sure we point to the main repo.
# This is to have consistent test results on PRs from forks.
git remote remove origin
git remote add origin https://github.com/mfem/mfem.git
git checkout -b gh-actions-branch-history
./config/githooks/pre-push --history
+1 -30
View File
@@ -113,12 +113,6 @@ examples/ex25p-*.*
examples/ex28_*
examples/ex28p_*
examples/flux.*
examples/dsol.*
examples/cond.*
examples/cond_j.*
examples/cond_mesh.*
examples/port_mesh.*
examples/port_mode.*
examples/amgx/ex1
examples/amgx/ex1p
@@ -128,13 +122,6 @@ examples/amgx/sol.gf
examples/amgx/mesh.*
examples/amgx/sol.*
examples/caliper/ex1
examples/caliper/ex1p
examples/caliper/refined.mesh
examples/caliper/sol.gf
examples/caliper/mesh.*
examples/caliper/sol.*
examples/ginkgo/ex1
examples/ginkgo/refined.mesh
examples/ginkgo/sol.gf
@@ -220,7 +207,6 @@ miniapps/meshing/twist
miniapps/meshing/mesh-explorer
miniapps/meshing/shaper
miniapps/meshing/extruder
miniapps/meshing/fit-node-position
miniapps/meshing/trimmer
miniapps/meshing/reflector
miniapps/meshing/mesh-optimizer
@@ -273,20 +259,11 @@ miniapps/navier/*_output
miniapps/nurbs/nurbs_ex1
miniapps/nurbs/nurbs_ex1p
miniapps/nurbs/nurbs_ex11p
miniapps/nurbs/nurbs_printfunc
miniapps/nurbs/nurbs_patch_ex1
miniapps/nurbs/nurbs_curveint
miniapps/nurbs/refined.mesh
miniapps/nurbs/mesh.*
miniapps/nurbs/sol.*
miniapps/nurbs/mode_*
miniapps/nurbs/Example1*
miniapps/nurbs/sin-fit.mesh
miniapps/nurbs/CurveInt
miniapps/nurbs/nurbs_naca_cmesh
miniapps/nurbs/naca-cmesh.mesh
miniapps/nurbs/glvis_naca-cmesh.mesh
miniapps/nurbs/Naca_cmesh
miniapps/performance/ex1
miniapps/performance/ex1p
@@ -309,14 +286,9 @@ miniapps/tools/display-basis
miniapps/tools/load-dc
miniapps/tools/convert-dc
miniapps/tools/lor-transfer
miniapps/tools/plor-transfer
miniapps/tools/get-values
miniapps/tools/tmop-check-metric
miniapps/tools/check-tmop-metric
miniapps/tools/tmop-metric-magnitude
miniapps/tools/nodal-transfer
miniapps/tools/ParaView
miniapps/tools/gridfunc_*
miniapps/tools/mesh_*
miniapps/toys/automata
miniapps/toys/life
@@ -342,7 +314,6 @@ miniapps/toys/mondrian.mesh
miniapps/solvers/block-solvers
miniapps/solvers/lor_solvers
miniapps/solvers/plor_solvers
miniapps/solvers/lor_elast
miniapps/solvers/ParaView
miniapps/solvers/mesh.*
miniapps/solvers/sol.*
+44 -146
View File
@@ -8,179 +8,77 @@
https://mfem.org
Version 4.6.1 (development)
Version 4.5.3 (development)
===========================
Discretization improvements
---------------------------
- Introduced support for higher order non conformal Nedelec elements on
simplices in ParMesh.
- Introduced support for internal boundary elements in nonconformal adapted
meshes.
- Added functionality for construction of cut-surface and cut-volume
IntegrationRules through a moment-fitting approach. The cut is specified by
the zero level set of a Coefficient. See fem/intrules_cut.hpp and Example 38.
GPU support
----------------------------
- Added support for full assembly on simplices.
- Added functionality for BilinearFormIntegrators to use kernels that work for both
tensor and unstructured elements.
- Added partial assembly for linear elasticity. Does not use sum factorization for now.
New and updated examples and miniapps
-------------------------------------
- Added miniapp to demonstrate new elasticity integrator and unstructured element GPU support,
and a block diagonal preconditioner using low order refinement. Allows comparison with
currently existing legacy mode integrator. See miniapps/solvers/lor_elast.
- Added a new miniapp, Mesh Quality, for evaluating mesh quality using size,
skewness, and aspect-ratio computed from the Jacobian of the transformation.
Miscellaneous
-------------
- Added support for single and double precision, with corresponding hypre build.
Generalized the floating point type from `double` to `real_t`.
- The ReadCubit Genesis mesh importer has been rewritten to improve readability.
- Updated the Doxygen documentation style, which now requires Doxygen version
1.9.8 or later. See the doc/ directory.
- Improved thread safety for global variables in the library, for example
IntegrationRules IntRules, RefinedIntRules, GeometryRefiner
GlobGeometryRefiner, and FiniteElement::dof2quad_array.
Version 4.6, released on September 27, 2023
===========================================
- MFEM is now available in Homebrew and can be installed on a Mac with just
"brew install mfem". See https://formulae.brew.sh/formula/mfem.
Meshing improvements
--------------------
- Added asymptotically-balanced TMOP compound metrics 90, 94, 328, 338. A new
tool, tmop-metric-magnitude, can be used to track how metrics change under
geometric perturbations. See miniapps/tools.
- Several NURBS meshing improvements:
* Support for free connectivity of NURBS patches allowing for more complex
patch configurations such as C-meshes.
* New methods to set and get attributes on NURBS patches and patch boundaries.
* The edge to knot map for NURBS meshes can be determined automatically. It is
no longer needed to specify this in the NURBS mesh.
* Added curve interpolation method for NURBS.
* Added new small miniapp for printing of shape functions of a KnotVector
* See miniapps/nurbs for example meshes and miniapps.
Discretization improvements
---------------------------
- SubMesh and ParSubMesh have been extended to support the transfer of
Nedelec and Raviart-Thomas finite element spaces.
- Added support for partial assembly on NURBS patches, and NURBS-patch sparse
matrix assembly. Patch matrix assembly includes the option to use reduced
approximate integration rules, computed by the newly implemented non-negative
least-squares (NNLS) solver.
- Support for parallel transfer of H1 fields using the low-order refined (LOR)
transfer operators in L2ProjectionGridTransfer
- Added KDTree class for 2D/3D set of points, which is then utilized in the new
KDTreeNodalProjection class to project a function defined on an arbitrary set
of points onto an MFEM grid function. This functionality is demonstrated in
the nodal-transfer miniapp. The current implementation is serial only. Further
extensions can include search in arbitrary dimensional spaces.
- Added support for p-refined meshes in GSLIB-FindPoints.
- Device kernels can now access device-specific DOF and quadrature limits using
the DofQuadLimits structure, allowing increased limits when executing on CPU.
The limits for the runtime selected device can be accessed in host code using
DeviceDofQuadLimits::Get(). The global constants MAX_D1D and MAX_Q1D are no
longer available.
- Face restriction operators for Nedelec and Raviart-Thomas finite element
spaces are now supported through the ConformingFaceRestriction class.
- VectorFEBoundaryFluxLFIntegrator is now supported on device/GPU.
Linear and nonlinear solvers
----------------------------
- Updated the MUMPS interface to support multiple right-hand sides, block
low-rank compression, builds using 64-bit integers, and other improvements.
- Added an interface to the MKL Pardiso sparse direct solver developed by Intel.
The interface provides a serial (OpenMP shared memory) version of Pardiso for
use with SparseMatrix. This complements the existing parallel (MPI distributed
memory) version already available through the CPardiso MFEM integration.
- Added HIP support to the PETSc and SUNDIALS interfaces.
- Efficient GPU-accelerated LOR assembly now supports surface meshes.
New and updated examples and miniapps
-------------------------------------
- Added a new H(div) solver miniapp demonstrating the use of a matrix-free
saddle-point solver methodology, suitable for high-order discretizations and
for GPU acceleration. Examples illustrating the solution of Darcy and grad-div
problems are included. See miniapps/hdiv-linear-solver.
- Added a new miniapp for interface and boundary fitting to implicit domains
defined using level-set functions. See miniapps/meshing/pmesh-fitting.cpp
- Added new Discontinuous Petrov-Galerkin (DPG) miniapp which includes serial
and parallel examples for diffusion, convection-diffusion, acoustics and
Maxwell equations. The miniapp includes new classes such as (Par)DPGWeakForm,
(Par)ComplexDPGWeakForm and (Complex)BlockStaticCondensation. Three new
integrators are added in support of DPG systems: TraceIntegrator,
NormalTraceIntegrator and TangentTraceIntegrator. See miniapps/dpg.
NormalTraceIntegrator and TangentTraceIntegrator.
- Added a new miniapp that implements the SPDE method for generating Gaussian
random fields of Matern covariance. The resulting random field can be used,
e.g., to model material uncertainties. See miniapps/spde.
- Added a new parallel LOR transfer miniapp, plor-transfer, which mirrors the
functionality of the serial LOR transfer miniapp. See miniapps/tools.
- New serial miniapp, nodal-transfer, demonstrating the use of KDTree to map a
parallel grid function to a different parallel partitioning of the same mesh.
- Added 3 additional TMOP miniapps in miniapps/meshing:
* Mesh-Quality evaluates quality using size, skewness, and aspect-ratio
computed from the Jacobian of the transformation.
* Mesh-Fitting can be used for interface and boundary fitting to implicit
domains defined using level-set functions.
* Fit-Node-Position fits selected mesh nodes to specified positions, while
maintaining overall mesh quality.
- Added 4 new example codes:
* Example 34/34p solves a simple magnetostatic problem where source terms and
boundary conditions are transferred with SubMesh objects.
* Example 35p implements H1, H(curl) and H(div) variants of a damped harmonic
oscillator with field transfer using SubMesh objects.
* Example 36/36p demonstrates the solution of the obstacle problem with a new
finite element method (proximal Galerkin).
* Example 37/37p demonstrates topology optimization with MFEM.
- Added a new H(div) solvers miniapp in miniapps/hdiv-linear-solver,
demonstrating the use of a matrix-free saddle-point solver methodology,
suitable for high-order discretizations and for GPU acceleration. Examples
illustrating the solution of Darcy and grad-div problems are included.
- Added a random refinement option to the mesh-explorer miniapp to assist users
in experimenting with nonconforming meshes.
- Moved the distance solver methods from miniapps/shifted to miniapps/common.
Meshing improvements
--------------------
- Added new methods in the Mesh class to set and get attributes on NURBS patches
and patch boundaries.
- TMOP improvement: added asymptotically-balanced compound metrics 90, 94, 328,
338. Added the tmop-metric-magnitude tool for tracking how metrics change
under geometric perturbations.
Discretization improvements
---------------------------
- Face restriction operators for Nedelec and Raviart-Thomas finite element
spaces are now supported through the ConformingFaceRestriction class.
- VectorFEBoundaryFluxLFIntegrator is now supported on device/GPU.
- Added support for p-refined meshes in FindPointsGSLIB.
Linear and nonlinear solvers
----------------------------
- Updated interface to MUMPS direct solver to support multiple right-hand
sides, block low-rank compression, builds using 64-bit integers, and other
improvements.
- Added an interface to the MKL Pardiso sparse direct solver developed by Intel.
This interface provides a serial (OpenMP shared memory) version of Pardiso for
use with SparseMatrix. This complements the existing parallel (MPI distributed
memory) version already available through the CPardiso MFEM integration.
Integrations, testing and documentation
---------------------------------------
- Added an address sanitizer GitHub action for a serial build/test on Ubuntu,
based on Clang/LLVM (https://clang.llvm.org/docs/AddressSanitizer.html).
Miscellaneous
-------------
- Improved lambda body debugging with the addition of mfem::forall functions.
These functions can take the place of the MFEM_FORALL macros, which have been
preserved for backwards compatibility.
- Added an address sanitizer GitHub action for a serial build/test on Ubuntu,
based on Clang/LLVM (https://clang.llvm.org/docs/AddressSanitizer.html).
- Reorganized files for bilinear form, linear form, and nonlinear form integrators
in the fem/integ/ subdirectory.
- FiniteElementSpace::GetFE has been updated to abort instead of returning NULL for
an empty partition.
- Various other simplifications, extensions, and bugfixes in the code.
Version 4.5.2, released on March 23, 2023
=========================================
+8 -28
View File
@@ -57,7 +57,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.6.1)
set(${PROJECT_NAME}_VERSION 4.5.3)
# Prohibit in-source build
if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR})
@@ -138,10 +138,11 @@ 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}")
find_package(CUDAToolkit REQUIRED)
set(CMAKE_CUDA_FLAGS ${CMAKE_CUDA_FLAGS} ${CUDA_FLAGS})
set(CUSPARSE_FOUND TRUE)
get_target_property(CUSPARSE_LIBRARIES CUDA::cusparse LOCATION)
set(CUSPARSE_LIBRARIES "cusparse")
set(CUBLAS_FOUND TRUE)
set(CUBLAS_LIBRARIES "cublas")
endif()
if (XSDK_ENABLE_C)
@@ -316,9 +317,6 @@ if (MFEM_USE_SUNDIALS)
if (MFEM_USE_CUDA)
list(APPEND SUNDIALS_COMPONENTS NVector_Cuda)
endif()
if (MFEM_USE_HIP)
list(APPEND SUNDIALS_COMPONENTS NVector_Hip)
endif()
find_package(SUNDIALS REQUIRED ${SUNDIALS_COMPONENTS})
endif()
@@ -530,7 +528,7 @@ find_package(Threads REQUIRED)
set(MFEM_TPLS OPENMP HYPRE LAPACK BLAS SuperLUDist STRUMPACK METIS SuiteSparse
SUNDIALS PETSC SLEPC MUMPS AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB
NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
ADIOS2 CUSPARSE MKL_CPARDISO MKL_PARDISO AMGX CALIPER CODIPACK
ADIOS2 CUBLAS CUSPARSE MKL_CPARDISO MKL_PARDISO AMGX CALIPER CODIPACK
BENCHMARK PARELAG MPI_CXX HIP HIPSPARSE MOONOLITH BLITZ ALGOIM ENZYME)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
@@ -640,34 +638,16 @@ if (NOT ("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}"))
foreach(Header mfem.hpp mfem-performance.hpp)
message(STATUS
"Writing substitute header --> \"${Header}\"")
file(WRITE "${PROJECT_BINARY_DIR}/${Header}.tmp"
file(WRITE "${PROJECT_BINARY_DIR}/${Header}"
"// Auto-generated file.
#define MFEM_CONFIG_FILE \"${PROJECT_BINARY_DIR}/config/_config.hpp\"
#include \"${PROJECT_SOURCE_DIR}/${Header}\"
")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${PROJECT_BINARY_DIR}/${Header}.tmp"
"${PROJECT_BINARY_DIR}/${Header}"
)
execute_process(COMMAND ${CMAKE_COMMAND} -E remove
"${PROJECT_BINARY_DIR}/${Header}.tmp"
)
# This version will be installed in the top include directory:
file(WRITE "${PROJECT_BINARY_DIR}/InstallHeaders/${Header}.tmp"
file(WRITE "${PROJECT_BINARY_DIR}/InstallHeaders/${Header}"
"// Auto-generated file.
#include \"mfem/${Header}\"
")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${PROJECT_BINARY_DIR}/InstallHeaders/${Header}.tmp"
"${PROJECT_BINARY_DIR}/InstallHeaders/${Header}"
)
execute_process(COMMAND ${CMAKE_COMMAND} -E remove
"${PROJECT_BINARY_DIR}/InstallHeaders/${Header}.tmp"
)
endforeach()
endif()
-4
View File
@@ -135,7 +135,6 @@ The MFEM source code has the following structure:
│ ├── adjoint
│ ├── autodiff
│ ├── common
│ ├── dpg
│ ├── electromagnetics
│ ├── gslib
│ ├── hdiv-linear-solver
@@ -149,7 +148,6 @@ The MFEM source code has the following structure:
│ ├── performance
│ ├── shifted
│ ├── solvers
│ ├── spde
│ ├── tools
│ └── toys
└── tests
@@ -359,8 +357,6 @@ Before you can start, you need a GitHub account, here are a few suggestions:
conflicted files in the commit message.
- All significant new features and changes should be documented in CHANGELOG.
- New examples and miniapps should have documentation on the MFEM webpage.
- The general floating-point type `real_t` should be used, rather than
`float` or `double`, except in special cases where only one is possible.
### Pull Requests
+7 -13
View File
@@ -628,13 +628,9 @@ The specific libraries and their options are:
both MPI and hypre.
If MFEM_USE_CUDA is enabled, we expect that SUNDIALS is built with support
for CUDA.
If MFEM_USE_HIP is enabled, we expect that SUNDIALS is built with support
for HIP.
URL: http://computing.llnl.gov/projects/sundials/sundials-software
URL: http://computation.llnl.gov/projects/sundials/sundials-software
Options: SUNDIALS_OPT, SUNDIALS_LIB.
Versions: SUNDIALS >= 5.0.0,
SUNDIALS >= 5.4.0 for CUDA support, and
SUNDIALS >= 5.7.0 for HIP support.
Versions: SUNDIALS >= 5.0.0, SUNDIALS >= 5.4.0 for CUDA support.
- SuiteSparse (optional), used when MFEM_USE_SUITESPARSE = YES.
URL: http://faculty.cse.tamu.edu/davis/suitesparse.html
@@ -659,7 +655,8 @@ The specific libraries and their options are:
requires the PT-Scotch and Scalapack libraries as well as ParMETIS, which
includes METIS 5 in its distribution. Starting with STRUMPACK v2.2.0, ParMETIS
and PT-Scotch are optional dependencies.
The support for STRUMPACK was added in MFEM v3.3.2.
The support for STRUMPACK was added in MFEM v3.3.2 and it requires STRUMPACK
2.0.0 or later.
URL: http://portal.nersc.gov/project/sparse/strumpack
Options: STRUMPACK_OPT, STRUMPACK_LIB.
Versions: STRUMPACK >= 3.0.0.
@@ -698,15 +695,12 @@ The specific libraries and their options are:
PETSc has been cloned on the same level as mfem and hypre:
./configure --download-fblaslapack=yes --download-scalapack=yes \
--download-mumps=yes --download-suitesparse=yes \
--with-hypre-dir=../hypre/src/hypre \
--with-hypre-dir=../hypre-2.10.0b/src/hypre \
--with-shared-libraries=0
When building PETSc with HIP, one may need to add a flag like -std=c2x to
CFLAGS to allow proper parsing of the hipsparse header under C.
URL: https://www.mcs.anl.gov/petsc
Options: PETSC_OPT, PETSC_LIB.
Versions: PETSc >= 3.8.0 (PETSc build without CUDA/HIP)
Versions: PETSc >= 3.8.0 (PETSc build without CUDA)
PETSc >= 3.15.0 (PETSc built with CUDA)
PETSc >= 3.19.0 (PETSc built with HIP, older versions may work too)
- SLEPc (optional), used when MFEM_USE_SLEPC = YES. SLEPc depends on PETSc and
uses some of the PETSc options when compiled.
@@ -796,7 +790,7 @@ The specific libraries and their options are:
URL: https://github.com/CEED/libCEED
https://ceed.exascaleproject.org/libceed
Options: CEED_DIR, CEED_OPT, CEED_LIB.
Versions: libCEED >= 0.12.
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.
-4
View File
@@ -55,16 +55,12 @@ set(MFEM_USE_SIMD @MFEM_USE_SIMD@)
set(MFEM_USE_ADIOS2 @MFEM_USE_ADIOS2@)
set(MFEM_USE_MOONOLITH @MFEM_USE_MOONOLITH@)
set(MFEM_USE_CODIPACK @MFEM_USE_CODIPACK@)
set(MFEM_USE_MKL_CPARDISO @MFEM_USE_MKL_CPARDISO@)
set(MFEM_USE_MKL_PARDISO @MFEM_USE_MKL_PARDISO@)
set(MFEM_USE_ADFORWARD @MFEM_USE_ADFORWARD@)
set(MFEM_USE_CALIPER @MFEM_USE_CALIPER@)
set(MFEM_USE_ALGOIM @MFEM_USE_ALGOIM@)
set(MFEM_USE_BENCHMARK @MFEM_USE_BENCHMARK@)
set(MFEM_USE_PARELAG @MFEM_USE_PARELAG@)
set(MFEM_USE_ENZYME @MFEM_USE_ENZYME@)
set(MFEM_USE_DOUBLE @MFEM_USE_DOUBLE@)
set(MFEM_USE_SINGLE @MFEM_USE_SINGLE@)
set(MFEM_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
set(MFEM_CXX_FLAGS "@CMAKE_CXX_FLAGS@")
-9
View File
@@ -186,9 +186,6 @@
// Enable interface to the MKL CPardiso library.
#cmakedefine MFEM_USE_MKL_CPARDISO
// Enable interface to the MKL Pardiso library.
#cmakedefine MFEM_USE_MKL_PARDISO
// Use forward mode for automatic differentiation.
#cmakedefine MFEM_USE_ADFORWARD
@@ -201,10 +198,4 @@
// Enable Enzyme for AD
#cmakedefine MFEM_USE_ENZYME
// Use double-precision floating point type
#cmakedefine MFEM_USE_DOUBLE
// Use single-precision floating point type
#cmakedefine MFEM_USE_SINGLE
#endif // MFEM_CONFIG_HEADER
-28
View File
@@ -14,13 +14,9 @@
# - HYPRE_LIBRARIES
# - HYPRE_INCLUDE_DIRS
# - HYPRE_VERSION
# - HYPRE_USING_CUDA (internal)
# - HYPRE_USING_HIP (internal)
if (HYPRE_FOUND)
if (HYPRE_USING_CUDA)
find_package(CUDAToolkit REQUIRED)
endif()
if (HYPRE_USING_HIP)
find_package(rocsparse REQUIRED)
find_package(rocrand REQUIRED)
@@ -31,20 +27,6 @@ endif()
include(MfemCmakeUtilities)
mfem_find_package(HYPRE HYPRE HYPRE_DIR "include" "HYPRE.h" "lib" "HYPRE"
"Paths to headers required by HYPRE." "Libraries required by HYPRE."
CHECK_BUILD HYPRE_USING_CUDA FALSE
"
#undef HYPRE_USING_CUDA
#include <HYPRE_config.h>
#ifndef HYPRE_USING_CUDA
#error HYPRE is built without CUDA.
#endif
int main()
{
return 0;
}
"
CHECK_BUILD HYPRE_USING_HIP FALSE
"
#undef HYPRE_USING_HIP
@@ -75,16 +57,6 @@ if (HYPRE_FOUND AND (NOT HYPRE_VERSION))
endif()
endif()
if (HYPRE_FOUND AND HYPRE_USING_CUDA)
find_package(CUDAToolkit REQUIRED)
get_target_property(CUSPARSE_LIBRARIES CUDA::cusparse LOCATION)
get_target_property(CURAND_LIBRARIES CUDA::curand LOCATION)
list(APPEND HYPRE_LIBRARIES ${CUSPARSE_LIBRARIES} ${CURAND_LIBRARIES})
set(HYPRE_LIBRARIES ${HYPRE_LIBRARIES} CACHE STRING
"HYPRE libraries + dependencies." FORCE)
message(STATUS "Updated HYPRE_LIBRARIES: ${HYPRE_LIBRARIES}")
endif()
if (HYPRE_FOUND AND HYPRE_USING_HIP)
find_package(rocsparse REQUIRED)
find_package(rocrand REQUIRED)
+2 -2
View File
@@ -22,8 +22,8 @@ mfem_find_package(SUNDIALS SUNDIALS SUNDIALS_DIR
"include" nvector/nvector_serial.h "lib" sundials_nvecserial
ADD_COMPONENT NVector_Cuda
"include" nvector/nvector_cuda.h "lib" sundials_nveccuda
ADD_COMPONENT NVector_Hip
"include" nvector/nvector_hip.h "lib" sundials_nvechip
ADD_COMPONENT NVector_ParHyp
"include" nvector/nvector_parhyp.h "lib" sundials_nvecparhyp
ADD_COMPONENT NVector_Parallel
"include" nvector/nvector_parallel.h "lib" sundials_nvecparallel
ADD_COMPONENT NVector_MPIPlusX
-6
View File
@@ -201,10 +201,4 @@
// Enable the Enzyme LLVM plugin
// #define MFEM_USE_ENZYME
// Use double-precision floating point type
// #define MFEM_USE_DOUBLE
// Use single-precision floating point type
// #define MFEM_USE_SINGLE
#endif // MFEM_CONFIG_HEADER
-2
View File
@@ -64,8 +64,6 @@ MFEM_USE_CODIPACK = @MFEM_USE_CODIPACK@
MFEM_USE_BENCHMARK = @MFEM_USE_BENCHMARK@
MFEM_USE_PARELAG = @MFEM_USE_PARELAG@
MFEM_USE_ENZYME = @MFEM_USE_ENZYME@
MFEM_USE_DOUBLE = @MFEM_USE_DOUBLE@
MFEM_USE_SINGLE = @MFEM_USE_SINGLE@
# Compiler, compile options, and link options
MFEM_CXX = @MFEM_CXX@
+7 -5
View File
@@ -66,8 +66,6 @@ option(MFEM_USE_CODIPACK "Enable automatic differentiation (AD) using CoDiPack"
option(MFEM_USE_BENCHMARK "Enable Google Benchmark" OFF)
option(MFEM_USE_PARELAG "Enable ParELAG" OFF)
option(MFEM_USE_ENZYME "Enable Enzyme" OFF)
option(MFEM_USE_DOUBLE "Double precision" ON)
option(MFEM_USE_SINGLE "Single precision" OFF)
# Optional overrides for autodetected MPIEXEC and MPIEXEC_NUMPROC_FLAG
# set(MFEM_MPIEXEC "mpirun" CACHE STRING "Command for running MPI tests")
@@ -108,7 +106,12 @@ set(HYPRE_DIR "${MFEM_DIR}/../hypre/src/hypre" CACHE PATH
# If hypre was compiled to depend on BLAS and LAPACK:
# set(HYPRE_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
# "Packages that HYPRE depends on.")
# CUDA and HIP dependencies for HYPRE are handled in FindHYPRE.cmake.
if (MFEM_USE_CUDA)
# This is only necessary when hypre is built with cuda:
set(HYPRE_REQUIRED_LIBRARIES "-lcusparse" "-lcurand" CACHE STRING
"Libraries that HYPRE depends on.")
endif()
# HIP dependency for HYPRE is handled in FindHYPRE.cmake.
set(METIS_DIR "${MFEM_DIR}/../metis-4.0" CACHE PATH "Path to the METIS library.")
@@ -154,8 +157,7 @@ set(STRUMPACK_DIR "${MFEM_DIR}/../STRUMPACK-build" CACHE PATH
# STRUMPACK may also depend on "OpenMP", depending on how it was compiled.
# Starting with v2.2.0 of STRUMPACK, ParMETIS and Scotch are optional.
set(STRUMPACK_REQUIRED_PACKAGES "MPI" "MPI_Fortran" "ParMETIS" "METIS"
"Scotch/ptscotch/ptscotcherr/scotch/scotcherr"
"ScaLAPACK" "LAPACK" "BLAS" CACHE STRING
"ScaLAPACK" "Scotch/ptscotch/ptscotcherr/scotch/scotcherr" CACHE STRING
"Additional packages required by STRUMPACK.")
# If the MPI package does not find all required Fortran libraries:
# set(STRUMPACK_REQUIRED_LIBRARIES "gfortran" "mpi_mpifh" CACHE STRING
+5 -25
View File
@@ -167,8 +167,6 @@ MFEM_USE_CODIPACK = NO
MFEM_USE_BENCHMARK = NO
MFEM_USE_PARELAG = NO
MFEM_USE_ENZYME = NO
MFEM_USE_DOUBLE = YES
MFEM_USE_SINGLE = NO
# MPI library compile and link flags
# These settings are used only when building MFEM with MPI + HIP
@@ -269,9 +267,6 @@ endif
ifeq ($(MFEM_USE_CUDA),YES)
SUNDIALS_LIB += -lsundials_nveccuda
endif
ifeq ($(MFEM_USE_HIP),YES)
SUNDIALS_LIB += -lsundials_nvechip
endif
# If SUNDIALS was built with KLU:
# MFEM_USE_SUITESPARSE = YES
@@ -333,30 +328,16 @@ STRUMPACK_OPT = -I$(STRUMPACK_DIR)/include $(SCOTCH_OPT)
STRUMPACK_LIB = -L$(STRUMPACK_DIR)/lib -lstrumpack $(MPI_FORTRAN_LIB)\
$(SCOTCH_LIB) $(SCALAPACK_LIB)
# Ginkgo library configuration
# Ginkgo library configuration (currently not needed)
GINKGO_DIR = @MFEM_DIR@/../ginkgo/install
GINKGO_SEARCH_DIR = $(subst @MFEM_DIR@,$(MFEM_DIR),$(GINKGO_DIR))
GINKGO_BUILD_TYPE=Release
ifeq ($(MFEM_USE_GINKGO),YES)
BASE_FLAGS = -std=c++14
endif
GINKGO_OPT = -isystem $(GINKGO_DIR)/include
GINKGO_LIB_DIR = $(sort $(dir $(wildcard\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*.a\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*.so\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*.dylib\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*.dll)))
GINKGO_LINK_LIB_DIR = $(GINKGO_DIR)$(subst $(GINKGO_SEARCH_DIR),,$(GINKGO_LIB_DIR))
ALL_GINKGO_LIBS_DEBUG = $(notdir $(basename $(wildcard\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*d.a\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*d.so\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*d.dylib\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*d.dll)))
ALL_GINKGO_LIBS = $(notdir $(basename $(wildcard\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*.a\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*.so\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*.dylib\
$(GINKGO_SEARCH_DIR)/lib*/libginkgo*.dll)))
GINKGO_LIB_DIR = $(sort $(dir $(wildcard $(GINKGO_DIR)/lib*/libginkgo*.a $(GINKGO_DIR)/lib*/libginkgo*.so $(GINKGO_DIR)/lib*/libginkgo*.dylib $(GINKGO_DIR)/lib*/libginkgo*.dll)))
ALL_GINKGO_LIBS_DEBUG = $(notdir $(basename $(wildcard $(GINKGO_DIR)/lib*/libginkgo*d.a $(GINKGO_DIR)/lib*/libginkgo*d.so $(GINKGO_DIR)/lib*/libginkgo*d.dylib $(GINKGO_DIR)/lib*/libginkgo*d.dll)))
ALL_GINKGO_LIBS = $(notdir $(basename $(wildcard $(GINKGO_DIR)/lib*/libginkgo*.a $(GINKGO_DIR)/lib*/libginkgo*.so $(GINKGO_DIR)/lib*/libginkgo*.dylib $(GINKGO_DIR)/lib*/libginkgo*.dll)))
ALL_GINKGO_LIBS_RELEASE = $(filter-out $(ALL_GINKGO_LIBS_DEBUG),$(ALL_GINKGO_LIBS))
GINKGO_LINK = $(subst libginkgo,-lginkgo,$(ALL_GINKGO_LIBS_RELEASE))
ifeq ($(GINKGO_BUILD_TYPE),Debug)
@@ -365,8 +346,7 @@ ifeq ($(GINKGO_BUILD_TYPE),Debug)
endif
else
endif
GINKGO_LIB = $(XLINKER)-rpath,$(GINKGO_LINK_LIB_DIR) -L$(GINKGO_LINK_LIB_DIR)\
$(GINKGO_LINK)
GINKGO_LIB = $(XLINKER)-rpath,$(GINKGO_LIB_DIR) -L$(GINKGO_LIB_DIR) $(GINKGO_LINK)
# AmgX library configuration
AMGX_DIR = @MFEM_DIR@/../amgx
+2
View File
@@ -19,7 +19,9 @@ RUN apt-get update && \
apt-get install -y libcurl4-openssl-dev libssl-dev
ENV PATH=$PATH:/opt/mfem-view/bin
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/mfem-view/lib:/opt/mfem-view/lib64
ENV DEBIAN_FRONTEND=noninteractive
# The user will see the view on shell into the container
WORKDIR /opt/mfem-view
ENTRYPOINT ["/bin/bash"]
+6 -6
View File
@@ -34,14 +34,14 @@ RUN cd /opt/mfem-env && \
. /opt/spack/share/spack/setup-env.sh && \
spack env activate . && \
spack develop --path /code mfem@master+examples+miniapps && \
spack add mfem@master+examples+miniapps && \
spack install
spack add mfem@master+examples+miniapps # && \
# spack install
# ensure mfem always on various paths
RUN cd /opt/mfem-env && \
spack env activate --sh -d . >> /etc/profile.d/z10_spack_environment.sh
#RUN cd /opt/mfem-env && \
# spack env activate --sh -d . >> /etc/profile.d/z10_spack_environment.sh
# Present the software install when we shell in
# The view is at /opt/mfem-env/.spack-env/view
WORKDIR /opt/software
ENTRYPOINT ["/bin/bash", "--rcfile", "/etc/profile", "-l", "-c"]
#WORKDIR /opt/software
#ENTRYPOINT ["/bin/bash", "--rcfile", "/etc/profile", "-l", "-c"]
+46 -108
View File
@@ -7,31 +7,21 @@ You can use this image for a demo of using mfem! 🎉️
Updated containers are built and deployed on merges to the main branch and releases.
If you want to request a build on demand, you can [manually run the workflow](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow) thanks to the workflow dispatch event.
## Usage
### Usage
We provide two containers, which you can either build or use directly from
[GitHub packages](https://github.com/orgs/mfem/packages?repo_name=mfem).
- `ghcr.io/mfem/mfem-ubuntu-base`: a "build from scratch" for mfem
- `ghcr.io/mfem/mfem-ubuntu`: a quick build that uses the base container
In the above, "ghcr.io" means "GitHub Container Registry" and
Here is how to build the container. Note that we build so it belongs to the same
namespace as the repository here. "ghcr.io" means "GitHub Container Registry" and
is the [GitHub packages](https://github.com/features/packages) registry that supports
Docker images and other OCI artifacts.
### Ubuntu
> Use or build this container for a multi-stage, slimmer base to develop on top of mfem
Note that this container is provided on GitHub packages [here](https://github.com/mfem/mfem/pkgs/container/mfem-ubuntu)
so you don't need to build it. However, if you want to, you can do the following:
Docker images and other OCI artifacts. From the root of the repository:
```bash
$ docker build -f config/docker/Dockerfile -t ghcr.io/mfem/mfem-ubuntu .
$ docker build -f config/docker/Dockerfile.base -t ghcr.io/mfem/mfem-ubuntu-base .
```
Note that this will pull the base image. If you want to rebuild it, see [ubuntu base](#ubuntu-base)
below. Once you have built (or prefer to pull) you can shell into the container as follows:
### Shell Ubuntu
To shell into the container:
```bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu
@@ -47,13 +37,39 @@ bin etc include lib libexec sbin share var
- Examples are in share/mfem/examples
- Examples are in share/mfem/miniapps
Using this container, if you want to develop a tool that _uses_ mfem, you can find the libraries / includes in:
You can read more about interaction with these examples and miniapps below.
### Shell Ubuntu Base
To shell into the container:
```bash
$ ls include/ | grep mfem
mfem
mfem-performance.hpp
mfem.hpp
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base bash
```
Off the bat, you can see mfem libraries are in your path so you can jump into development:
```bash
env | grep mfem
```
```bash
PKG_CONFIG_PATH=/opt/mfem-env/.spack-env/view/lib/pkgconfig:/opt/mfem-env/.spack-env/view/share/pkgconfig:/opt/mfem-env/.spack-env/view/lib64/pkgconfig
PWD=/opt/mfem-env
MANPATH=/opt/mfem-env/.spack-env/view/share/man:/opt/mfem-env/.spack-env/view/man:
CMAKE_PREFIX_PATH=/opt/mfem-env/.spack-env/view
SPACK_ENV=/opt/mfem-env
ACLOCAL_PATH=/opt/mfem-env/.spack-env/view/share/aclocal
LD_LIBRARY_PATH=/opt/mfem-env/.spack-env/view/lib:/opt/mfem-env/.spack-env/view/lib64
PATH=/opt/mfem-env/.spack-env/view/bin:/opt/view/bin:/opt/spack/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
```
#### Examples and MiniApps
If you want to develop a tool that _uses_ mfem, you can find the built libraries in:
```
$ ls /opt/mfem-env/.spack-env/view/
bin etc include lib libexec sbin share var
```
And yes, this is the working directory when you shell into the container!
@@ -63,16 +79,6 @@ You can find the examples here:
```bash
cd share/mfem/examples
```
Try quickly setting the `LD_LIBRARY_PATH` so we can see the shared libraries
we need:
```bash
export LD_LIBRARY_PATH=/opt/mfem-view/lib:$LD_LIBRARY_PATH
```
And then run:
```bash
$ ./ex0
Options used:
@@ -91,6 +97,7 @@ Number of unknowns: 101
Average reduction factor = 0.140201
```
Try running a few, and look at the associated .cpp file for the source code!
You can also explore the "mini apps," also in share/mfem, but under miniapps.
```bash
@@ -123,87 +130,18 @@ Rule:
Applying rule...done.
```
Have fun! As a reminder, this container is ideal for developing your own
applications that might use mfem, or having a nice environment to test out
examples.
Have fun!
### Ubuntu Base
> Use this build for a development environment with spack and mfem
This container is also [provided on GitHub packages](https://github.com/mfem/mfem/pkgs/container/mfem-ubuntu-base),
however you can build it locally too:
#### Your own App
If you want to develop with your own code base
(and mfem as is in the container) you can bind to somewhere else in the container (e.g., src)
```bash
$ docker build -f config/docker/Dockerfile.base -t ghcr.io/mfem/mfem-ubuntu-base .
```
To shell into the container:
```bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base bash
```
Change directory to the mfem environment, setup spack, and activate the environment:
```bash
source /opt/spack/share/spack/setup-env.sh
cd /opt/mfem-env/
spack env activate .
```
Note that this environment is installing to the view at `/opt/view`. Since the environment
knows to install mfem from `/code` this means that you could make changes in the container (or bind
`/code` to your container) and then update spack:
```bash
# Note that concretization takes a hot minute!
$ spack install
```
And if you want to load mfem:
```bash
$ spack load mfem
$ env | grep mfem
```
In this development container, you can find the examples and miniapps alongside
mfem under `/code`:
```bash
cd /code/examples
```
```bash
$ ./ex0
```
```console
Options used:
--mesh ../data/star.mesh
--order 1
Number of unknowns: 101
Iteration : 0 (B r, r) = 0.184259
Iteration : 1 (B r, r) = 0.102754
Iteration : 2 (B r, r) = 0.00558141
Iteration : 3 (B r, r) = 1.5247e-05
Iteration : 4 (B r, r) = 1.13807e-07
Iteration : 5 (B r, r) = 6.27231e-09
Iteration : 6 (B r, r) = 3.76268e-11
Iteration : 7 (B r, r) = 6.07423e-13
Iteration : 8 (B r, r) = 4.10615e-15
Average reduction factor = 0.140201
```
This container is likely ideal for someone that wants to develop mfem itself.
For other use cases, we recommend using the slimmer image. As an example,
if you want to develop with your own code base (and mfem as is in the container)
you can bind to somewhere else in the container (e.g., src)
```bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base -v $PWD:/code bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base -v $PWD:/src bash
```
In the above, we can pretend your project is in the present working directory (PWD) and we are
binding to source. You can then use the mfem in the container for development, and if you
want to distribute your library or app in a container, you can use the mfem container as the base.
+2 -3
View File
@@ -38,14 +38,14 @@ all: header config-mk
MPI = $(MFEM_USE_MPI:NO=)
GHV_CXX ?= $(MFEM_CXX)
GHV = get_hypre_version
GHV_FLAGS = $(MFEM_CXXFLAGS) $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(HYPRE_OPT))
GHV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(HYPRE_OPT))
SMX = $(if $(MFEM_USE_PUMI:NO=),MFEM_USE_SIMMETRIX)
SMX_PATH = $(PUMI_DIR)/include/gmi_sim.h
SMX_FILE = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(SMX_PATH))
MUMPS = $(MFEM_USE_MUMPS:NO=)
GMV_CXX ?= $(MFEM_CXX)
GMV = get_mumps_version
GMV_FLAGS = $(MFEM_CXXFLAGS) $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(MUMPS_OPT))
GMV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(MUMPS_OPT))
$(GHV): $(SRC)$(GHV).cpp
$(call mfem-info, Determining HYPRE version ...)
@@ -110,4 +110,3 @@ config-mk:
clean:
rm -f $(CONFIG_HPP) $(CONFIG_MK) sample-runs-build.log
rm -f $(GHV) $(GHV).out $(GMV) $(GMV).out
+1 -1
View File
@@ -315,7 +315,7 @@ function extract_sample_runs()
sruns=`grep -v "^//.* mpirun .* ${app}" "${src}" |
grep "^//.* ${app}" |
sed -e "s/.* ${app}/${vg_app}/g"`
runs="${sruns}"$'\n'"${pruns}"
runs="${sruns}${pruns}"
if [ "$skip_gen_meshes" == "yes" ]; then
runs=`printf "%s" "$runs" | grep -v ".* -m .*\.gen"`
fi
-37
View File
@@ -1,37 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
1
elements
4
1 1 0 1
1 1 1 2
1 1 2 3
1 1 3 4
boundary
2
1 0 0
2 0 4
vertices
5
2
0 0
0.25 0.25
0.50 0.50
0.75 0.75
1 1
-37
View File
@@ -1,37 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
1
elements
4
1 1 0 1
1 1 1 2
1 1 2 3
1 1 3 4
boundary
2
1 0 0
2 0 4
vertices
5
3
0 0 0
0.25 0.25 0.25
0.50 0.50 0.50
0.75 0.75 0.75
1 1 1
-48
View File
@@ -1,48 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
2
elements
6
1 3 0 1 4 3
1 3 2 3 6 5
1 2 3 4 8
1 2 4 7 8
1 2 7 6 8
1 2 6 3 8
boundary
8
1 1 0 1
2 1 1 4
3 1 4 7
4 1 7 6
5 1 6 5
6 1 5 2
7 1 2 3
8 1 3 0
vertices
9
2
0.5 0
1 0
0 0.5
0.5 0.5
1 0.5
0 1
0.5 1
1 1
0.75 0.75
-44
View File
@@ -1,44 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
2
elements
3
1 3 0 1 4 3
1 3 2 3 6 5
1 3 3 4 7 6
boundary
8
1 1 0 1
2 1 1 4
3 1 4 7
4 1 7 6
5 1 6 5
6 1 5 2
7 1 2 3
8 1 3 0
vertices
8
2
0.5 0
1 0
0 0.5
0.5 0.5
1 0.5
0 1
0.5 1
1 1
-322
View File
@@ -1,322 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
# PYRAMID = 7
#
dimension
2
elements
26
1 2 1 18 0
1 3 1 3 19 18
2 3 3 6 20 19
1 3 6 9 21 20
2 3 9 12 22 21
1 3 12 15 23 22
2 2 23 15 24
1 2 1 4 3
2 3 4 7 6 3
1 3 7 10 9 6
2 3 10 13 12 9
1 3 13 16 15 12
2 3 16 25 24 15
1 3 2 5 4 1
1 3 5 8 7 4
1 3 8 11 10 7
1 3 11 14 13 10
1 3 14 17 16 13
1 2 25 16 17
1 3 18 19 27 26
2 3 19 20 28 27
1 3 20 21 29 28
2 3 21 22 30 29
1 3 22 23 31 30
2 3 23 24 32 31
1 3 24 25 33 32
boundary
18
1 1 28 27
2 1 30 29
3 1 32 31
4 1 0 1
4 1 1 2
4 1 2 5
4 1 5 8
4 1 8 11
4 1 11 14
4 1 14 17
4 1 17 25
4 1 25 33
4 1 33 32
4 1 31 30
4 1 29 28
4 1 27 26
4 1 26 18
4 1 18 0
vertices
34
nodes
FiniteElementSpace
FiniteElementCollection: H1_2D_P3
VDim: 2
Ordering: 1
0 0
0.53125 0
1 0
0.53125 0.09375
0.5625 0.09375
1 0.09375
0.53125 0.21875
0.6875 0.21875
1 0.1875
0.53125 0.25
0.71875 0.25
1 0.25
0.53125 0.375
0.84375 0.375
1 0.34375
0.53125 0.40625
0.875 0.40625
1 0.40625
0 0.53125
0.09375 0.53125
0.21875 0.53125
0.25 0.53125
0.375 0.53125
0.40625 0.53125
0.53125 0.53125
1 0.53125
0 1
0.09375 1
0.21875 1
0.25 1
0.375 1
0.40625 1
0.53125 1
1 1
0.33175106835972 0.094168845750364
0.094168845750364 0.33175106835972
-5.1759634627347e-17 0.14683388869532
6.5255471622478e-17 0.38441611130468
0.14683388869532 6.0713766400335e-17
0.38441611130468 8.2458945395444e-19
0.53125 0.025911862710939
0.53125 0.067838137289061
0.34721731046049 0.13433915461926
0.13433915461926 0.34721731046049
0.025911862710939 0.53125
0.067838137289061 0.53125
0.53125 0.12829915028125
0.53125 0.18420084971875
0.39979807890035 0.24774225329947
0.24774225329947 0.39979807890035
0.12829915028125 0.53125
0.18420084971875 0.53125
0.53125 0.22738728757031
0.53125 0.24136271242969
0.41294327101031 0.27609302796952
0.27609302796952 0.41294327101031
0.22738728757031 0.53125
0.24136271242969 0.53125
0.53125 0.28454915028125
0.53125 0.34045084971875
0.46552403945017 0.38949612664974
0.38949612664974 0.46552403945017
0.28454915028125 0.53125
0.34045084971875 0.53125
0.53125 0.38363728757031
0.53125 0.39761271242969
0.47866923156014 0.41784690131979
0.41784690131979 0.47866923156014
0.38363728757031 0.53125
0.39761271242969 0.53125
0.53125 0.44079915028125
0.53125 0.49670084971875
0.44079915028125 0.53125
0.49670084971875 0.53125
0.53988728757031 0.025911862710939
0.55386271242969 0.067838137289061
0.53988728757031 0.09375
0.55386271242969 0.09375
0.59704915028125 0.12829915028125
0.65295084971875 0.18420084971875
0.57443643785157 0.21875
0.64431356214843 0.21875
0.69613728757031 0.22738728757031
0.71011271242969 0.24136271242969
0.58307372542188 0.25
0.66692627457812 0.25
0.75329915028125 0.28454915028125
0.80920084971875 0.34045084971875
0.61762287570313 0.375
0.75737712429687 0.375
0.85238728757031 0.38363728757031
0.86636271242969 0.39761271242969
0.62626016327344 0.40625
0.77998983672656 0.40625
0.90954915028125 0.44079915028125
0.96545084971875 0.49670084971875
0.6608093135547 0.53125
0.8704406864453 0.53125
1 0.025911862710939
1 0.067838137289061
0.68342202598438 0.09375
0.87907797401562 0.09375
0.6608093135547 0
0.8704406864453 0
1 0.11966186271094
1 0.16158813728906
0.77387287570313 0.21011271242969
0.91362712429687 0.19613728757031
1 0.20477457514063
1 0.23272542485937
0.79648558813282 0.25
0.92226441186718 0.25
1 0.27591186271094
1 0.31783813728906
0.88693643785157 0.36636271242969
0.95681356214843 0.35238728757031
1 0.36102457514063
1 0.38897542485937
0.90954915028125 0.40625
0.96545084971875 0.40625
1 0.44079915028125
1 0.49670084971875
0.09375 0.6608093135547
0.09375 0.8704406864453
0.025911862710939 1
0.067838137289061 1
0 0.6608093135547
0 0.8704406864453
0.21875 0.6608093135547
0.21875 0.8704406864453
0.12829915028125 1
0.18420084971875 1
0.25 0.6608093135547
0.25 0.8704406864453
0.22738728757031 1
0.24136271242969 1
0.375 0.6608093135547
0.375 0.8704406864453
0.28454915028125 1
0.34045084971875 1
0.40625 0.6608093135547
0.40625 0.8704406864453
0.38363728757031 1
0.39761271242969 1
0.53125 0.6608093135547
0.53125 0.8704406864453
0.44079915028125 1
0.49670084971875 1
1 0.6608093135547
1 0.8704406864453
0.6608093135547 1
0.8704406864453 1
0.14782497614169 0.14782497614169
0.3364183509774 0.10629113008478
0.3439701728879 0.12590539815918
0.10629113008478 0.3364183509774
0.12590539815918 0.3439701728879
0.36175027742635 0.16568300020856
0.38526511193449 0.21639840771017
0.16568300020856 0.36175027742635
0.21639840771017 0.38526511193449
0.40343132064181 0.2555782146968
0.40931002926885 0.2682570665722
0.2555782146968 0.40343132064181
0.2682570665722 0.40931002926885
0.42747623797617 0.30743687355882
0.45099107248431 0.35815228106044
0.30743687355882 0.42747623797617
0.35815228106044 0.45099107248431
0.46915728119164 0.39733208804706
0.47503598981867 0.41001093992246
0.39733208804706 0.46915728119164
0.41001093992246 0.47503598981867
0.47232443490112 0.47232443490112
0.54166666666667 0.0625
0.57886271242969 0.12829915028125
0.61931356214843 0.18420084971875
0.54943643785157 0.12829915028125
0.56488728757031 0.18420084971875
0.65056356214843 0.22738728757031
0.66067627457812 0.24136271242969
0.57682372542188 0.22738728757031
0.58068643785157 0.24136271242969
0.69192627457812 0.28454915028125
0.73237712429687 0.34045084971875
0.59262287570313 0.28454915028125
0.60807372542188 0.34045084971875
0.76362712429687 0.38363728757031
0.77373983672656 0.39761271242969
0.62001016327344 0.38363728757031
0.62387287570313 0.39761271242969
0.80498983672656 0.44079915028125
0.8454406864453 0.49670084971875
0.6358093135547 0.44079915028125
0.65126016327344 0.49670084971875
0.87282797401562 0.025911862710939
0.8766906864453 0.067838137289061
0.6670593135547 0.025911862710939
0.67717202598438 0.067838137289061
0.88862712429687 0.12204915028125
0.90407797401562 0.16783813728906
0.70842202598438 0.12591186271094
0.74887287570313 0.17795084971875
0.91601441186718 0.21102457514063
0.91987712429687 0.23511271242969
0.78012287570313 0.22113728757031
0.79023558813282 0.23897542485937
0.93181356214843 0.27829915028125
0.94726441186718 0.32408813728906
0.82148558813282 0.28216186271094
0.86193643785157 0.33420084971875
0.95920084971875 0.36727457514063
0.96306356214843 0.39136271242969
0.89318643785157 0.37738728757031
0.90329915028125 0.39522542485937
0.95833333333333 0.44791666666667
0.025911862710939 0.6608093135547
0.067838137289061 0.6608093135547
0.025911862710939 0.8704406864453
0.067838137289061 0.8704406864453
0.12829915028125 0.6608093135547
0.18420084971875 0.6608093135547
0.12829915028125 0.8704406864453
0.18420084971875 0.8704406864453
0.22738728757031 0.6608093135547
0.24136271242969 0.6608093135547
0.22738728757031 0.8704406864453
0.24136271242969 0.8704406864453
0.28454915028125 0.6608093135547
0.34045084971875 0.6608093135547
0.28454915028125 0.8704406864453
0.34045084971875 0.8704406864453
0.38363728757031 0.6608093135547
0.39761271242969 0.6608093135547
0.38363728757031 0.8704406864453
0.39761271242969 0.8704406864453
0.44079915028125 0.6608093135547
0.49670084971875 0.6608093135547
0.44079915028125 0.8704406864453
0.49670084971875 0.8704406864453
0.6608093135547 0.6608093135547
0.8704406864453 0.6608093135547
0.6608093135547 0.8704406864453
0.8704406864453 0.8704406864453
File diff suppressed because it is too large Load Diff
-9
View File
@@ -105,14 +105,6 @@ namespace mfem {
* - <a class="el" href="ex32p_8cpp_source.html">Example 32p</a>: parallel anisotropic Maxwell eigensolver
* - <a class="el" href="ex33_8cpp_source.html">Example 33</a>: nodal H1 FEM for the fractional Laplacian problem
* - <a class="el" href="ex33p_8cpp_source.html">Example 33p</a>: parallel nodal H1 FEM for the fractional Laplacian problem
* - <a class="el" href="ex34_8cpp_source.html">Example 34</a>: multi-domain magnetostatics
* - <a class="el" href="ex34p_8cpp_source.html">Example 34p</a>: parallel multi-domain magnetostatics
* - <a class="el" href="ex35p_8cpp_source.html">Example 35p</a>: parallel multi-domain damped harmonic oscillators
* - <a class="el" href="ex36_8cpp_source.html">Example 36</a>: Proximal Galerkin FEM for the obstacle problem
* - <a class="el" href="ex36p_8cpp_source.html">Example 36p</a>: parallel Proximal Galerkin FEM for the obstacle problem
* - <a class="el" href="ex37_8cpp_source.html">Example 37</a>: Topology optimization
* - <a class="el" href="ex37p_8cpp_source.html">Example 37p</a>: parallel topology optimization
* - <a class="el" href="ex38_8cpp_source.html">Example 38</a>: cut-surface and cut-volume integration
*
* <H4>AmgX Examples</H4>
* - Variants of Examples
@@ -216,7 +208,6 @@ namespace mfem {
* - <a class="el" href="generate__random__field_8cpp_source.html">SPDE Solvers</a>: SPDE solver random field generation
* - <a class="el" href="pdiffusion_8cpp_source.html">DPG Diffusion example</a>: DPG formulation for the diffusion problem
* - <a class="el" href="pmaxwell_8cpp_source.html">DPG Maxwell example</a>: DPG formulation for the indefinite Maxwell problem
* - <a class="el" href="lor__elast_8cpp_source.html">LOR Elasticity</a>: solve linear elasticity with LOR preconditioning on GPUs
*
* See also the <a class="el" href="https://mfem.org/examples/">examples documentation</a> online.
*/
+1 -1
View File
@@ -14,7 +14,7 @@ If not already available, Doxygen can be downloaded from
http://www.doxygen.org
We recommend using version 1.9.8 or later.
We recommend using version 1.8 or later.
To build the documentation, simply type "make" in the doc/ directory. This will
create the file CodeDocumentation.html, which can be viewed in any web browser.
-3
View File
@@ -1,3 +0,0 @@
html {
--content-maxwidth: auto;
}
File diff suppressed because it is too large Load Diff
-78
View File
@@ -1,78 +0,0 @@
<!-- HTML header for doxygen 1.9.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN FULL_SIDEBAR-->
<script type="text/javascript">var page_layout=1;</script>
<!--END FULL_SIDEBAR-->
<!--END DISABLE_INDEX-->
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
$treeview
$search
$mathjax
$darkmode
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
<script type="text/javascript">
DoxygenAwesomeDarkModeToggle.init()
</script>
</head>
<body>
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN FULL_SIDEBAR-->
<div id="side-nav" class="ui-resizable side-nav-resizable"><!-- do not remove this div, it is closed by doxygen! -->
<!--END FULL_SIDEBAR-->
<!--END DISABLE_INDEX-->
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr id="projectrow">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td id="projectalign">
<div id="projectname">$projectname<!--BEGIN PROJECT_NUMBER--><span id="projectnumber">&#160;$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<td>
<div id="projectbrief">$projectbrief</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<!--BEGIN !FULL_SIDEBAR-->
<td>$searchbox</td>
<!--END !FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
<!--BEGIN SEARCHENGINE-->
<!--BEGIN FULL_SIDEBAR-->
<tr><td colspan="2">$searchbox</td></tr>
<!--END FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->
-157
View File
@@ -1,157 +0,0 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeDarkModeToggle extends HTMLElement {
// SVG icons from https://fonts.google.com/icons
// Licensed under the Apache 2.0 license:
// https://www.apache.org/licenses/LICENSE-2.0.html
static lightModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FCBF00"><rect fill="none" height="24" width="24"/><circle cx="12" cy="12" opacity=".3" r="3"/><path d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"/></svg>`
static darkModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FE9700"><rect fill="none" height="24" width="24"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27 C17.45,17.19,14.93,19,12,19c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z" opacity=".3"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"/></svg>`
static title = "Toggle Light/Dark Mode"
static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode"
static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode"
static _staticConstructor = function() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference)
// Update the color scheme when the browsers preference changes
// without user interaction on the website.
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
})
// Update the color scheme when the tab is made visible again.
// It is possible that the appearance was changed in another tab
// while this tab was in the background.
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
}
});
}()
static init() {
$(function() {
$(document).ready(function() {
const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle')
toggleButton.title = DoxygenAwesomeDarkModeToggle.title
toggleButton.updateIcon()
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
toggleButton.updateIcon()
})
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
toggleButton.updateIcon()
}
});
$(document).ready(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
$(window).resize(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
})
})
}
constructor() {
super();
this.onclick=this.toggleDarkMode
}
/**
* @returns `true` for dark-mode, `false` for light-mode system preference
*/
static get systemPreference() {
return window.matchMedia('(prefers-color-scheme: dark)').matches
}
/**
* @returns `true` for dark-mode, `false` for light-mode user preference
*/
static get userPreference() {
return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) ||
(DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey))
}
static set userPreference(userPreference) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference
if(!userPreference) {
if(DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)
}
} else {
if(!DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)
}
}
DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged()
}
static enableDarkMode(enable) {
if(enable) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = true
document.documentElement.classList.add("dark-mode")
document.documentElement.classList.remove("light-mode")
} else {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = false
document.documentElement.classList.remove("dark-mode")
document.documentElement.classList.add("light-mode")
}
}
static onSystemPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
static onUserPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
toggleDarkMode() {
DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference
this.updateIcon()
}
updateIcon() {
if(DoxygenAwesomeDarkModeToggle.darkModeEnabled) {
this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon
} else {
this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon
}
}
}
customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 12 KiB

+1 -1
View File
@@ -16,7 +16,7 @@ DOXYGEN_CONF = CodeDocumentation.conf
# doxygen uses: graphviz, latex
html: $(DOXYGEN_CONF)
@# Generate the html documentation
@( cat $(DOXYGEN_CONF) ; printf "$(MFEM_DOXYGEN_FLAGS)\n" ) | doxygen -
@( cat $(DOXYGEN_CONF) ; echo "$(MFEM_DOXYGEN_FLAGS)" ) | doxygen -
@echo "<meta http-equiv=\"REFRESH\" content=\"0;URL=CodeDocumentation/html/index.html\">" > CodeDocumentation.html
@cat warnings.log 1>&2
@# Generate the log of undocumented methods
+3 -17
View File
@@ -41,16 +41,9 @@ list(APPEND ALL_EXE_SRCS
ex31.cpp
ex33.cpp
ex34.cpp
ex36.cpp
ex37.cpp
ex35.cpp
)
if(MFEM_USE_LAPACK)
list(APPEND ALL_EXE_SRCS
ex38.cpp
)
endif()
if (MFEM_USE_MPI)
list(APPEND ALL_EXE_SRCS
ex0p.cpp
@@ -86,10 +79,6 @@ if (MFEM_USE_MPI)
ex31p.cpp
ex32p.cpp
ex33p.cpp
ex34p.cpp
ex35p.cpp
ex36p.cpp
ex37p.cpp
)
endif()
@@ -115,8 +104,6 @@ if (MFEM_ENABLE_TESTING)
list(APPEND THIS_TEST_OPTIONS "-e" "1")
elseif(${TEST_NAME} MATCHES "ex27p*")
list(APPEND THIS_TEST_OPTIONS "-dg")
elseif(${TEST_NAME} MATCHES "ex37p*")
list(APPEND THIS_TEST_OPTIONS "-mi" "3")
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
@@ -134,10 +121,9 @@ if (MFEM_ENABLE_TESTING)
# Add CUDA/HIP tests.
set(DEVICE_EXAMPLES
# serial examples with device support:
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26
# parallel examples with device support:
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p
ex34p ex35p)
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p)
set(MFEM_TEST_DEVICE)
if (MFEM_USE_CUDA)
set(MFEM_TEST_DEVICE "cuda")
+1 -1
View File
@@ -22,7 +22,7 @@ using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Parse command line options.
string mesh_file = "../data/star.mesh";
const char *mesh_file = "../data/star.mesh";
int order = 1;
OptionsParser args(argc, argv);
+1 -1
View File
@@ -26,7 +26,7 @@ int main(int argc, char *argv[])
Hypre::Init();
// 2. Parse command line options.
string mesh_file = "../data/star.mesh";
const char *mesh_file = "../data/star.mesh";
int order = 1;
OptionsParser args(argc, argv);
+30 -34
View File
@@ -62,7 +62,7 @@ protected:
BilinearForm M, S;
NonlinearForm H;
real_t viscosity;
double viscosity;
HyperelasticModel *model;
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
@@ -84,16 +84,16 @@ protected:
public:
HyperelasticOperator(FiniteElementSpace &f, Array<int> &ess_bdr,
real_t visc, real_t mu, real_t K);
double visc, double mu, double K);
/// Compute the right-hand side of the ODE system.
virtual void Mult(const Vector &vx, Vector &dvx_dt) const;
/** Solve the Backward-Euler equation: k = f(x + dt*k, t), for the unknown k.
This is the only requirement for high-order SDIRK implicit integration.*/
virtual void ImplicitSolve(const real_t dt, const Vector &x, Vector &k);
virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k);
real_t ElasticEnergy(const Vector &x) const;
real_t KineticEnergy(const Vector &v) const;
double ElasticEnergy(const Vector &x) const;
double KineticEnergy(const Vector &v) const;
void GetElasticEnergyDensity(const GridFunction &x, GridFunction &w) const;
virtual ~HyperelasticOperator();
@@ -109,7 +109,7 @@ private:
BilinearForm *M, *S;
NonlinearForm *H;
mutable SparseMatrix *Jacobian;
real_t dt;
double dt;
const Vector *v, *x;
mutable Vector w, z;
@@ -117,7 +117,7 @@ public:
ReducedSystemOperator(BilinearForm *M_, BilinearForm *S_, NonlinearForm *H_);
/// Set current dt, v, x values - needed to compute action and Jacobian.
void SetParameters(real_t dt_, const Vector *v_, const Vector *x_);
void SetParameters(double dt_, const Vector *v_, const Vector *x_);
/// Compute y = H(x + dt (v + dt k)) + M k + S (v + dt k).
virtual void Mult(const Vector &k, Vector &y) const;
@@ -141,7 +141,7 @@ private:
public:
ElasticEnergyCoefficient(HyperelasticModel &m, const GridFunction &x_)
: model(m), x(x_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
virtual ~ElasticEnergyCoefficient() { }
};
@@ -161,11 +161,11 @@ int main(int argc, char *argv[])
int ref_levels = 2;
int order = 2;
int ode_solver_type = 3;
real_t t_final = 300.0;
real_t dt = 3.0;
real_t visc = 1e-2;
real_t mu = 0.25;
real_t K = 5.0;
double t_final = 300.0;
double dt = 3.0;
double visc = 1e-2;
double mu = 0.25;
double K = 5.0;
bool visualization = true;
int vis_steps = 1;
@@ -205,10 +205,6 @@ int main(int argc, char *argv[])
}
args.PrintOptions(cout);
#ifdef MFEM_USE_SINGLE
MFEM_ABORT("This example is not supported in single precision.");
#endif
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral and hexahedral meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
@@ -313,13 +309,13 @@ int main(int argc, char *argv[])
<< " Press space (in the GLVis window) to resume it.\n";
}
real_t ee0 = oper.ElasticEnergy(x.GetTrueVector());
real_t ke0 = oper.KineticEnergy(v.GetTrueVector());
double ee0 = oper.ElasticEnergy(x.GetTrueVector());
double ke0 = oper.KineticEnergy(v.GetTrueVector());
cout << "initial elastic energy (EE) = " << ee0 << endl;
cout << "initial kinetic energy (KE) = " << ke0 << endl;
cout << "initial total energy (TE) = " << (ee0 + ke0) << endl;
real_t t = 0.0;
double t = 0.0;
oper.SetTime(t);
ode_solver->Init(oper);
@@ -328,7 +324,7 @@ int main(int argc, char *argv[])
bool last_step = false;
for (int ti = 1; !last_step; ti++)
{
real_t dt_real = min(dt, t_final - t);
double dt_real = min(dt, t_final - t);
ode_solver->Step(vx, t, dt_real);
@@ -336,8 +332,8 @@ int main(int argc, char *argv[])
if (last_step || (ti % vis_steps) == 0)
{
real_t ee = oper.ElasticEnergy(x.GetTrueVector());
real_t ke = oper.KineticEnergy(v.GetTrueVector());
double ee = oper.ElasticEnergy(x.GetTrueVector());
double ke = oper.KineticEnergy(v.GetTrueVector());
cout << "step " << ti << ", t = " << t << ", EE = " << ee << ", KE = "
<< ke << ", ΔTE = " << (ee+ke)-(ee0+ke0) << endl;
@@ -423,7 +419,7 @@ ReducedSystemOperator::ReducedSystemOperator(
dt(0.0), v(NULL), x(NULL), w(height), z(height)
{ }
void ReducedSystemOperator::SetParameters(real_t dt_, const Vector *v_,
void ReducedSystemOperator::SetParameters(double dt_, const Vector *v_,
const Vector *x_)
{
dt = dt_; v = v_; x = x_;
@@ -457,16 +453,16 @@ ReducedSystemOperator::~ReducedSystemOperator()
HyperelasticOperator::HyperelasticOperator(FiniteElementSpace &f,
Array<int> &ess_bdr, real_t visc,
real_t mu, real_t K)
: TimeDependentOperator(2*f.GetTrueVSize(), (real_t) 0.0), fespace(f),
Array<int> &ess_bdr, double visc,
double mu, double K)
: TimeDependentOperator(2*f.GetTrueVSize(), 0.0), fespace(f),
M(&fespace), S(&fespace), H(&fespace),
viscosity(visc), z(height/2)
{
const real_t rel_tol = 1e-8;
const double rel_tol = 1e-8;
const int skip_zero_entries = 0;
const real_t ref_density = 1.0; // density in the reference configuration
const double ref_density = 1.0; // density in the reference configuration
ConstantCoefficient rho0(ref_density);
M.AddDomainIntegrator(new VectorMassIntegrator(rho0));
M.Assemble(skip_zero_entries);
@@ -537,7 +533,7 @@ void HyperelasticOperator::Mult(const Vector &vx, Vector &dvx_dt) const
dx_dt = v;
}
void HyperelasticOperator::ImplicitSolve(const real_t dt,
void HyperelasticOperator::ImplicitSolve(const double dt,
const Vector &vx, Vector &dvx_dt)
{
int sc = height/2;
@@ -559,12 +555,12 @@ void HyperelasticOperator::ImplicitSolve(const real_t dt,
add(v, dt, dv_dt, dx_dt);
}
real_t HyperelasticOperator::ElasticEnergy(const Vector &x) const
double HyperelasticOperator::ElasticEnergy(const Vector &x) const
{
return H.GetEnergy(x);
}
real_t HyperelasticOperator::KineticEnergy(const Vector &v) const
double HyperelasticOperator::KineticEnergy(const Vector &v) const
{
return 0.5*M.InnerProduct(v, v);
}
@@ -585,7 +581,7 @@ HyperelasticOperator::~HyperelasticOperator()
}
real_t ElasticEnergyCoefficient::Eval(ElementTransformation &T,
double ElasticEnergyCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
model.SetTransformation(T);
@@ -605,7 +601,7 @@ void InitialDeformation(const Vector &x, Vector &y)
void InitialVelocity(const Vector &x, Vector &v)
{
const int dim = x.Size();
const real_t s = 0.1/64.;
const double s = 0.1/64.;
v = 0.0;
v(dim-1) = s*x(0)*x(0)*(8.0-x(0));
+34 -38
View File
@@ -63,7 +63,7 @@ protected:
ParBilinearForm M, S;
ParNonlinearForm H;
real_t viscosity;
double viscosity;
HyperelasticModel *model;
HypreParMatrix *Mmat; // Mass matrix from ParallelAssemble()
@@ -86,16 +86,16 @@ protected:
public:
HyperelasticOperator(ParFiniteElementSpace &f, Array<int> &ess_bdr,
real_t visc, real_t mu, real_t K);
double visc, double mu, double K);
/// Compute the right-hand side of the ODE system.
virtual void Mult(const Vector &vx, Vector &dvx_dt) const;
/** Solve the Backward-Euler equation: k = f(x + dt*k, t), for the unknown k.
This is the only requirement for high-order SDIRK implicit integration.*/
virtual void ImplicitSolve(const real_t dt, const Vector &x, Vector &k);
virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k);
real_t ElasticEnergy(const ParGridFunction &x) const;
real_t KineticEnergy(const ParGridFunction &v) const;
double ElasticEnergy(const ParGridFunction &x) const;
double KineticEnergy(const ParGridFunction &v) const;
void GetElasticEnergyDensity(const ParGridFunction &x,
ParGridFunction &w) const;
@@ -112,7 +112,7 @@ private:
ParBilinearForm *M, *S;
ParNonlinearForm *H;
mutable HypreParMatrix *Jacobian;
real_t dt;
double dt;
const Vector *v, *x;
mutable Vector w, z;
const Array<int> &ess_tdof_list;
@@ -122,7 +122,7 @@ public:
ParNonlinearForm *H_, const Array<int> &ess_tdof_list);
/// Set current dt, v, x values - needed to compute action and Jacobian.
void SetParameters(real_t dt_, const Vector *v_, const Vector *x_);
void SetParameters(double dt_, const Vector *v_, const Vector *x_);
/// Compute y = H(x + dt (v + dt k)) + M k + S (v + dt k).
virtual void Mult(const Vector &k, Vector &y) const;
@@ -146,7 +146,7 @@ private:
public:
ElasticEnergyCoefficient(HyperelasticModel &m, const ParGridFunction &x_)
: model(m), x(x_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
virtual ~ElasticEnergyCoefficient() { }
};
@@ -173,11 +173,11 @@ int main(int argc, char *argv[])
int par_ref_levels = 0;
int order = 2;
int ode_solver_type = 3;
real_t t_final = 300.0;
real_t dt = 3.0;
real_t visc = 1e-2;
real_t mu = 0.25;
real_t K = 5.0;
double t_final = 300.0;
double dt = 3.0;
double visc = 1e-2;
double mu = 0.25;
double K = 5.0;
bool adaptive_lin_rtol = true;
bool visualization = true;
int vis_steps = 1;
@@ -229,10 +229,6 @@ int main(int argc, char *argv[])
args.PrintOptions(cout);
}
#ifdef MFEM_USE_SINGLE
MFEM_ABORT("This example is not supported in single precision.");
#endif
// 3. Read the serial mesh from the given mesh file on all processors. We can
// handle triangular, quadrilateral, tetrahedral and hexahedral meshes
// with the same code.
@@ -362,8 +358,8 @@ int main(int argc, char *argv[])
}
}
real_t ee0 = oper.ElasticEnergy(x_gf);
real_t ke0 = oper.KineticEnergy(v_gf);
double ee0 = oper.ElasticEnergy(x_gf);
double ke0 = oper.KineticEnergy(v_gf);
if (myid == 0)
{
cout << "initial elastic energy (EE) = " << ee0 << endl;
@@ -371,7 +367,7 @@ int main(int argc, char *argv[])
cout << "initial total energy (TE) = " << (ee0 + ke0) << endl;
}
real_t t = 0.0;
double t = 0.0;
oper.SetTime(t);
ode_solver->Init(oper);
@@ -380,7 +376,7 @@ int main(int argc, char *argv[])
bool last_step = false;
for (int ti = 1; !last_step; ti++)
{
real_t dt_real = min(dt, t_final - t);
double dt_real = min(dt, t_final - t);
ode_solver->Step(vx, t, dt_real);
@@ -390,8 +386,8 @@ int main(int argc, char *argv[])
{
v_gf.SetFromTrueVector(); x_gf.SetFromTrueVector();
real_t ee = oper.ElasticEnergy(x_gf);
real_t ke = oper.KineticEnergy(v_gf);
double ee = oper.ElasticEnergy(x_gf);
double ke = oper.KineticEnergy(v_gf);
if (myid == 0)
{
@@ -489,7 +485,7 @@ ReducedSystemOperator::ReducedSystemOperator(
ess_tdof_list(ess_tdof_list_)
{ }
void ReducedSystemOperator::SetParameters(real_t dt_, const Vector *v_,
void ReducedSystemOperator::SetParameters(double dt_, const Vector *v_,
const Vector *x_)
{
dt = dt_; v = v_; x = x_;
@@ -527,17 +523,17 @@ ReducedSystemOperator::~ReducedSystemOperator()
HyperelasticOperator::HyperelasticOperator(ParFiniteElementSpace &f,
Array<int> &ess_bdr, real_t visc,
real_t mu, real_t K)
: TimeDependentOperator(2*f.TrueVSize(), (real_t) 0.0), fespace(f),
Array<int> &ess_bdr, double visc,
double mu, double K)
: TimeDependentOperator(2*f.TrueVSize(), 0.0), fespace(f),
M(&fespace), S(&fespace), H(&fespace),
viscosity(visc), M_solver(f.GetComm()), newton_solver(f.GetComm()),
z(height/2)
{
const real_t rel_tol = 1e-8;
const double rel_tol = 1e-8;
const int skip_zero_entries = 0;
const real_t ref_density = 1.0; // density in the reference configuration
const double ref_density = 1.0; // density in the reference configuration
ConstantCoefficient rho0(ref_density);
M.AddDomainIntegrator(new VectorMassIntegrator(rho0));
M.Assemble(skip_zero_entries);
@@ -611,7 +607,7 @@ void HyperelasticOperator::Mult(const Vector &vx, Vector &dvx_dt) const
dx_dt = v;
}
void HyperelasticOperator::ImplicitSolve(const real_t dt,
void HyperelasticOperator::ImplicitSolve(const double dt,
const Vector &vx, Vector &dvx_dt)
{
int sc = height/2;
@@ -633,17 +629,17 @@ void HyperelasticOperator::ImplicitSolve(const real_t dt,
add(v, dt, dv_dt, dx_dt);
}
real_t HyperelasticOperator::ElasticEnergy(const ParGridFunction &x) const
double HyperelasticOperator::ElasticEnergy(const ParGridFunction &x) const
{
return H.GetEnergy(x);
}
real_t HyperelasticOperator::KineticEnergy(const ParGridFunction &v) const
double HyperelasticOperator::KineticEnergy(const ParGridFunction &v) const
{
real_t loc_energy = 0.5*M.InnerProduct(v, v);
real_t energy;
MPI_Allreduce(&loc_energy, &energy, 1, MPITypeMap<real_t>::mpi_type,
MPI_SUM, fespace.GetComm());
double loc_energy = 0.5*M.InnerProduct(v, v);
double energy;
MPI_Allreduce(&loc_energy, &energy, 1, MPI_DOUBLE, MPI_SUM,
fespace.GetComm());
return energy;
}
@@ -664,7 +660,7 @@ HyperelasticOperator::~HyperelasticOperator()
}
real_t ElasticEnergyCoefficient::Eval(ElementTransformation &T,
double ElasticEnergyCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
model.SetTransformation(T);
@@ -684,7 +680,7 @@ void InitialDeformation(const Vector &x, Vector &y)
void InitialVelocity(const Vector &x, Vector &v)
{
const int dim = x.Size();
const real_t s = 0.1/64.;
const double s = 0.1/64.;
v = 0.0;
v(dim-1) = s*x(0)*x(0)*(8.0-x(0));
+4 -5
View File
@@ -211,7 +211,7 @@ int main(int argc, char *argv[])
m->AddDomainIntegrator(new MassIntegrator(one));
m->Assemble();
// shift the eigenvalue corresponding to eliminated dofs to a large value
m->EliminateEssentialBCDiag(ess_bdr, numeric_limits<real_t>::min());
m->EliminateEssentialBCDiag(ess_bdr, numeric_limits<double>::min());
m->Finalize();
HypreParMatrix *A = a->ParallelAssemble();
@@ -262,13 +262,12 @@ int main(int argc, char *argv[])
#ifdef MFEM_USE_STRUMPACK
if (sp_solver)
{
STRUMPACKSolver * strumpack = new STRUMPACKSolver(MPI_COMM_WORLD, argc, argv);
STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv, MPI_COMM_WORLD);
strumpack->SetPrintFactorStatistics(true);
strumpack->SetPrintSolveStatistics(false);
strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
strumpack->SetMatching(strumpack::MatchingJob::NONE);
strumpack->SetCompression(strumpack::CompressionType::NONE);
strumpack->DisableMatching();
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
precond = strumpack;
@@ -300,7 +299,7 @@ int main(int argc, char *argv[])
// 9. Compute the eigenmodes and extract the array of eigenvalues. Define a
// parallel grid function to represent each of the eigenmodes returned by
// the solver.
Array<real_t> eigenvalues;
Array<double> eigenvalues;
lobpcg->Solve();
lobpcg->GetEigenvalues(eigenvalues);
ParGridFunction x(fespace);
+2 -2
View File
@@ -206,7 +206,7 @@ int main(int argc, char *argv[])
m->AddDomainIntegrator(new VectorMassIntegrator());
m->Assemble();
// shift the eigenvalue corresponding to eliminated dofs to a large value
m->EliminateEssentialBCDiag(ess_bdr, numeric_limits<real_t>::min());
m->EliminateEssentialBCDiag(ess_bdr, numeric_limits<double>::min());
m->Finalize();
if (myid == 0)
{
@@ -247,7 +247,7 @@ int main(int argc, char *argv[])
// 10. Compute the eigenmodes and extract the array of eigenvalues. Define a
// parallel grid function to represent each of the eigenmodes returned by
// the solver.
Array<real_t> eigenvalues;
Array<double> eigenvalues;
lobpcg->Solve();
lobpcg->GetEigenvalues(eigenvalues);
ParGridFunction x(fespace);
+2 -11
View File
@@ -5,7 +5,6 @@
// Sample runs: mpirun -np 4 ex13p -m ../data/star.mesh
// mpirun -np 4 ex13p -m ../data/square-disc.mesh -o 2 -n 4
// mpirun -np 4 ex13p -m ../data/beam-tet.mesh
// mpirun -np 4 ex13p -m ../data/beam-tet.mesh -nc -o 2 -rs 1
// mpirun -np 4 ex13p -m ../data/beam-hex.mesh
// mpirun -np 4 ex13p -m ../data/escher.mesh
// mpirun -np 4 ex13p -m ../data/fichera.mesh
@@ -55,7 +54,6 @@ int main(int argc, char *argv[])
int par_ref_levels = 1;
int order = 1;
int nev = 5;
bool nc = false;
bool visualization = 1;
const char *device_config = "cpu";
@@ -71,9 +69,6 @@ int main(int argc, char *argv[])
" isoparametric space.");
args.AddOption(&nev, "-n", "--num-eigs",
"Number of desired eigenmodes.");
args.AddOption(&nc, "-nc", "--non-conforming", "-c",
"--conforming",
"Mark the mesh as nonconforming before partitioning.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -103,10 +98,6 @@ int main(int argc, char *argv[])
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
if (nc)
{
mesh->EnsureNCMesh(true);
}
// 5. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement (2 by default, or
@@ -170,7 +161,7 @@ int main(int argc, char *argv[])
m->AddDomainIntegrator(new VectorFEMassIntegrator(one));
m->Assemble();
// shift the eigenvalue corresponding to eliminated dofs to a large value
m->EliminateEssentialBCDiag(ess_bdr, numeric_limits<real_t>::min());
m->EliminateEssentialBCDiag(ess_bdr, numeric_limits<double>::min());
m->Finalize();
HypreParMatrix *A = a->ParallelAssemble();
@@ -198,7 +189,7 @@ int main(int argc, char *argv[])
// 10. Compute the eigenmodes and extract the array of eigenvalues. Define a
// parallel grid function to represent each of the eigenmodes returned by
// the solver.
Array<real_t> eigenvalues;
Array<double> eigenvalues;
ame->Solve();
ame->GetEigenvalues(eigenvalues);
ParGridFunction x(fespace);
+3 -3
View File
@@ -43,9 +43,9 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/star.mesh";
int ref_levels = -1;
int order = 1;
real_t sigma = -1.0;
real_t kappa = -1.0;
real_t eta = 0.0;
double sigma = -1.0;
double kappa = -1.0;
double eta = 0.0;
bool visualization = 1;
OptionsParser args(argc, argv);
+4 -4
View File
@@ -44,7 +44,7 @@ public:
pmesh(m),
pgf(f) {}
void MonitorSolution(int i, real_t norm, const Vector &x, bool final)
void MonitorSolution(int i, double norm, const Vector &x, bool final)
{
char vishost[] = "localhost";
int visport = 19916;
@@ -81,9 +81,9 @@ int main(int argc, char *argv[])
int ser_ref_levels = -1;
int par_ref_levels = 2;
int order = 1;
real_t sigma = -1.0;
real_t kappa = -1.0;
real_t eta = 0.0;
double sigma = -1.0;
double kappa = -1.0;
double eta = 0.0;
bool visualization = 1;
OptionsParser args(argc, argv);
+30 -30
View File
@@ -63,8 +63,8 @@ int problem;
int nfeatures;
// Prescribed time-dependent boundary and right-hand side functions.
real_t bdr_func(const Vector &pt, real_t t);
real_t rhs_func(const Vector &pt, real_t t);
double bdr_func(const Vector &pt, double t);
double rhs_func(const Vector &pt, double t);
// Update the finite element space, interpolate the solution and perform
// parallel load balancing.
@@ -79,9 +79,9 @@ int main(int argc, char *argv[])
nfeatures = 1;
const char *mesh_file = "../data/star-hilbert.mesh";
int order = 2;
real_t t_final = 1.0;
real_t max_elem_error = 5.0e-3;
real_t hysteresis = 0.15; // derefinement safety coefficient
double t_final = 1.0;
double max_elem_error = 5.0e-3;
double hysteresis = 0.15; // derefinement safety coefficient
int ref_levels = 0;
int nc_limit = 3; // maximum level of hanging nodes
bool visualization = true;
@@ -247,7 +247,7 @@ int main(int argc, char *argv[])
// refine the mesh as many times as necessary. Then we derefine any
// elements which have very small errors.
x = 0.0;
for (real_t time = 0.0; time < t_final + 1e-10; time += 0.01)
for (double time = 0.0; time < t_final + 1e-10; time += 0.01)
{
cout << "\nTime " << time << "\n\nRefinement:" << endl;
@@ -366,47 +366,47 @@ void UpdateProblem(Mesh &mesh, FiniteElementSpace &fespace,
}
const real_t alpha = 0.02;
const double alpha = 0.02;
// Spherical front with a Gaussian cross section and radius t
real_t front(real_t x, real_t y, real_t z, real_t t, int)
double front(double x, double y, double z, double t, int)
{
real_t r = sqrt(x*x + y*y + z*z);
double r = sqrt(x*x + y*y + z*z);
return exp(-0.5*pow((r - t)/alpha, 2));
}
real_t front_laplace(real_t x, real_t y, real_t z, real_t t, int dim)
double front_laplace(double x, double y, double z, double t, int dim)
{
real_t x2 = x*x, y2 = y*y, z2 = z*z, t2 = t*t;
real_t r = sqrt(x2 + y2 + z2);
real_t a2 = alpha*alpha, a4 = a2*a2;
double x2 = x*x, y2 = y*y, z2 = z*z, t2 = t*t;
double r = sqrt(x2 + y2 + z2);
double a2 = alpha*alpha, a4 = a2*a2;
return -exp(-0.5*pow((r - t)/alpha, 2)) / a4 *
(-2*t*(x2 + y2 + z2 - (dim-1)*a2/2)/r + x2 + y2 + z2 + t2 - dim*a2);
}
// Smooth spherical step function with radius t
real_t ball(real_t x, real_t y, real_t z, real_t t, int)
double ball(double x, double y, double z, double t, int)
{
real_t r = sqrt(x*x + y*y + z*z);
double r = sqrt(x*x + y*y + z*z);
return -atan(2*(r - t)/alpha);
}
real_t ball_laplace(real_t x, real_t y, real_t z, real_t t, int dim)
double ball_laplace(double x, double y, double z, double t, int dim)
{
real_t x2 = x*x, y2 = y*y, z2 = z*z, t2 = 4*t*t;
real_t r = sqrt(x2 + y2 + z2);
real_t a2 = alpha*alpha;
real_t den = pow(-a2 - 4*(x2 + y2 + z2 - 2*r*t) - t2, 2.0);
double x2 = x*x, y2 = y*y, z2 = z*z, t2 = 4*t*t;
double r = sqrt(x2 + y2 + z2);
double a2 = alpha*alpha;
double den = pow(-a2 - 4*(x2 + y2 + z2 - 2*r*t) - t2, 2.0);
return (dim == 2) ? 2*alpha*(a2 + t2 - 4*x2 - 4*y2)/r/den
/* */ : 4*alpha*(a2 + t2 - 4*r*t)/r/den;
}
// Composes several features into one function
template<typename F0, typename F1>
real_t composite_func(const Vector &pt, real_t t, F0 f0, F1 f1)
double composite_func(const Vector &pt, double t, F0 f0, F1 f1)
{
int dim = pt.Size();
real_t x = pt(0), y = pt(1), z = 0.0;
double x = pt(0), y = pt(1), z = 0.0;
if (dim == 3) { z = pt(2); }
if (problem == 0)
@@ -417,11 +417,11 @@ real_t composite_func(const Vector &pt, real_t t, F0 f0, F1 f1)
}
else
{
real_t sum = 0.0;
double sum = 0.0;
for (int i = 0; i < nfeatures; i++)
{
real_t x0 = 0.5*cos(2*M_PI * i / nfeatures);
real_t y0 = 0.5*sin(2*M_PI * i / nfeatures);
double x0 = 0.5*cos(2*M_PI * i / nfeatures);
double y0 = 0.5*sin(2*M_PI * i / nfeatures);
sum += f0(x - x0, y - y0, z, t, dim);
}
return sum;
@@ -429,11 +429,11 @@ real_t composite_func(const Vector &pt, real_t t, F0 f0, F1 f1)
}
else
{
real_t sum = 0.0;
double sum = 0.0;
for (int i = 0; i < nfeatures; i++)
{
real_t x0 = 0.5*cos(2*M_PI * i / nfeatures + M_PI*t);
real_t y0 = 0.5*sin(2*M_PI * i / nfeatures + M_PI*t);
double x0 = 0.5*cos(2*M_PI * i / nfeatures + M_PI*t);
double y0 = 0.5*sin(2*M_PI * i / nfeatures + M_PI*t);
sum += f1(x - x0, y - y0, z, 0.25, dim);
}
return sum;
@@ -441,13 +441,13 @@ real_t composite_func(const Vector &pt, real_t t, F0 f0, F1 f1)
}
// Exact solution, used for the Dirichlet BC.
real_t bdr_func(const Vector &pt, real_t t)
double bdr_func(const Vector &pt, double t)
{
return composite_func(pt, t, front, ball);
}
// Laplace of the exact solution, used for the right hand side.
real_t rhs_func(const Vector &pt, real_t t)
double rhs_func(const Vector &pt, double t)
{
return composite_func(pt, t, front_laplace, ball_laplace);
}
+30 -31
View File
@@ -13,7 +13,6 @@
// mpirun -np 4 ex15p -m ../data/square-disc-nurbs.mesh
// mpirun -np 4 ex15p -m ../data/disc-nurbs.mesh
// mpirun -np 4 ex15p -m ../data/fichera.mesh -tf 0.5
// mpirun -np 4 ex15p -m ../data/fichera-mixed.mesh -tf 0.5
// mpirun -np 4 ex15p -m ../data/ball-nurbs.mesh -tf 0.5
// mpirun -np 4 ex15p -m ../data/mobius-strip.mesh
// mpirun -np 4 ex15p -m ../data/amr-quad.mesh
@@ -68,8 +67,8 @@ int problem;
int nfeatures;
// Prescribed time-dependent boundary and right-hand side functions.
real_t bdr_func(const Vector &pt, real_t t);
real_t rhs_func(const Vector &pt, real_t t);
double bdr_func(const Vector &pt, double t);
double rhs_func(const Vector &pt, double t);
// Update the finite element space, interpolate the solution and perform
// parallel load balancing.
@@ -91,9 +90,9 @@ int main(int argc, char *argv[])
nfeatures = 1;
const char *mesh_file = "../data/star-hilbert.mesh";
int order = 2;
real_t t_final = 1.0;
real_t max_elem_error = 1.0e-4;
real_t hysteresis = 0.25; // derefinement safety coefficient
double t_final = 1.0;
double max_elem_error = 1.0e-4;
double hysteresis = 0.25; // derefinement safety coefficient
int ref_levels = 0;
int nc_limit = 3; // maximum level of hanging nodes
bool visualization = true;
@@ -282,7 +281,7 @@ int main(int argc, char *argv[])
// solve the problem on the current mesh, visualize the solution and
// refine the mesh as many times as necessary. Then we derefine any
// elements which have very small errors.
for (real_t time = 0.0; time < t_final + 1e-10; time += 0.01)
for (double time = 0.0; time < t_final + 1e-10; time += 0.01)
{
if (myid == 0)
{
@@ -427,47 +426,47 @@ void UpdateAndRebalance(ParMesh &pmesh, ParFiniteElementSpace &fespace,
}
const real_t alpha = 0.02;
const double alpha = 0.02;
// Spherical front with a Gaussian cross section and radius t
real_t front(real_t x, real_t y, real_t z, real_t t, int)
double front(double x, double y, double z, double t, int)
{
real_t r = sqrt(x*x + y*y + z*z);
double r = sqrt(x*x + y*y + z*z);
return exp(-0.5*pow((r - t)/alpha, 2));
}
real_t front_laplace(real_t x, real_t y, real_t z, real_t t, int dim)
double front_laplace(double x, double y, double z, double t, int dim)
{
real_t x2 = x*x, y2 = y*y, z2 = z*z, t2 = t*t;
real_t r = sqrt(x2 + y2 + z2);
real_t a2 = alpha*alpha, a4 = a2*a2;
double x2 = x*x, y2 = y*y, z2 = z*z, t2 = t*t;
double r = sqrt(x2 + y2 + z2);
double a2 = alpha*alpha, a4 = a2*a2;
return -exp(-0.5*pow((r - t)/alpha, 2)) / a4 *
(-2*t*(x2 + y2 + z2 - (dim-1)*a2/2)/r + x2 + y2 + z2 + t2 - dim*a2);
}
// Smooth spherical step function with radius t
real_t ball(real_t x, real_t y, real_t z, real_t t, int)
double ball(double x, double y, double z, double t, int)
{
real_t r = sqrt(x*x + y*y + z*z);
double r = sqrt(x*x + y*y + z*z);
return -atan(2*(r - t)/alpha);
}
real_t ball_laplace(real_t x, real_t y, real_t z, real_t t, int dim)
double ball_laplace(double x, double y, double z, double t, int dim)
{
real_t x2 = x*x, y2 = y*y, z2 = z*z, t2 = 4*t*t;
real_t r = sqrt(x2 + y2 + z2);
real_t a2 = alpha*alpha;
real_t den = pow(-a2 - 4*(x2 + y2 + z2 - 2*r*t) - t2, 2.0);
double x2 = x*x, y2 = y*y, z2 = z*z, t2 = 4*t*t;
double r = sqrt(x2 + y2 + z2);
double a2 = alpha*alpha;
double den = pow(-a2 - 4*(x2 + y2 + z2 - 2*r*t) - t2, 2.0);
return (dim == 2) ? 2*alpha*(a2 + t2 - 4*x2 - 4*y2)/r/den
/* */ : 4*alpha*(a2 + t2 - 4*r*t)/r/den;
}
// Composes several features into one function
template<typename F0, typename F1>
real_t composite_func(const Vector &pt, real_t t, F0 f0, F1 f1)
double composite_func(const Vector &pt, double t, F0 f0, F1 f1)
{
int dim = pt.Size();
real_t x = pt(0), y = pt(1), z = 0.0;
double x = pt(0), y = pt(1), z = 0.0;
if (dim == 3) { z = pt(2); }
if (problem == 0)
@@ -478,11 +477,11 @@ real_t composite_func(const Vector &pt, real_t t, F0 f0, F1 f1)
}
else
{
real_t sum = 0.0;
double sum = 0.0;
for (int i = 0; i < nfeatures; i++)
{
real_t x0 = 0.5*cos(2*M_PI * i / nfeatures);
real_t y0 = 0.5*sin(2*M_PI * i / nfeatures);
double x0 = 0.5*cos(2*M_PI * i / nfeatures);
double y0 = 0.5*sin(2*M_PI * i / nfeatures);
sum += f0(x - x0, y - y0, z, t, dim);
}
return sum;
@@ -490,11 +489,11 @@ real_t composite_func(const Vector &pt, real_t t, F0 f0, F1 f1)
}
else
{
real_t sum = 0.0;
double sum = 0.0;
for (int i = 0; i < nfeatures; i++)
{
real_t x0 = 0.5*cos(2*M_PI * i / nfeatures + M_PI*t);
real_t y0 = 0.5*sin(2*M_PI * i / nfeatures + M_PI*t);
double x0 = 0.5*cos(2*M_PI * i / nfeatures + M_PI*t);
double y0 = 0.5*sin(2*M_PI * i / nfeatures + M_PI*t);
sum += f1(x - x0, y - y0, z, 0.25, dim);
}
return sum;
@@ -502,13 +501,13 @@ real_t composite_func(const Vector &pt, real_t t, F0 f0, F1 f1)
}
// Exact solution, used for the Dirichlet BC.
real_t bdr_func(const Vector &pt, real_t t)
double bdr_func(const Vector &pt, double t)
{
return composite_func(pt, t, front, ball);
}
// Laplace of the exact solution, used for the right hand side.
real_t rhs_func(const Vector &pt, real_t t)
double rhs_func(const Vector &pt, double t)
{
return composite_func(pt, t, front_laplace, ball_laplace);
}
+17 -17
View File
@@ -60,7 +60,7 @@ protected:
SparseMatrix Mmat, Kmat;
SparseMatrix *T; // T = M + dt K
real_t current_dt;
double current_dt;
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
DSmoother M_prec; // Preconditioner for the mass matrix M
@@ -68,18 +68,18 @@ protected:
CGSolver T_solver; // Implicit solver for T = M + dt K
DSmoother T_prec; // Preconditioner for the implicit solver
real_t alpha, kappa;
double alpha, kappa;
mutable Vector z; // auxiliary vector
public:
ConductionOperator(FiniteElementSpace &f, real_t alpha, real_t kappa,
ConductionOperator(FiniteElementSpace &f, double alpha, double kappa,
const Vector &u);
virtual void Mult(const Vector &u, Vector &du_dt) const;
/** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
This is the only requirement for high-order SDIRK implicit integration.*/
virtual void ImplicitSolve(const real_t dt, const Vector &u, Vector &k);
virtual void ImplicitSolve(const double dt, const Vector &u, Vector &k);
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
void SetParameters(const Vector &u);
@@ -87,7 +87,7 @@ public:
virtual ~ConductionOperator();
};
real_t InitialTemperature(const Vector &x);
double InitialTemperature(const Vector &x);
int main(int argc, char *argv[])
{
@@ -96,10 +96,10 @@ int main(int argc, char *argv[])
int ref_levels = 2;
int order = 2;
int ode_solver_type = 3;
real_t t_final = 0.5;
real_t dt = 1.0e-2;
real_t alpha = 1.0e-2;
real_t kappa = 0.5;
double t_final = 0.5;
double dt = 1.0e-2;
double alpha = 1.0e-2;
double kappa = 0.5;
bool visualization = true;
bool visit = false;
int vis_steps = 5;
@@ -246,7 +246,7 @@ int main(int argc, char *argv[])
// 8. Perform time-integration (looping over the time iterations, ti, with a
// time-step dt).
ode_solver->Init(oper);
real_t t = 0.0;
double t = 0.0;
bool last_step = false;
for (int ti = 1; !last_step; ti++)
@@ -293,12 +293,12 @@ int main(int argc, char *argv[])
return 0;
}
ConductionOperator::ConductionOperator(FiniteElementSpace &f, real_t al,
real_t kap, const Vector &u)
: TimeDependentOperator(f.GetTrueVSize(), (real_t) 0.0), fespace(f),
M(NULL), K(NULL), T(NULL), current_dt(0.0), z(height)
ConductionOperator::ConductionOperator(FiniteElementSpace &f, double al,
double kap, const Vector &u)
: TimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL), K(NULL),
T(NULL), current_dt(0.0), z(height)
{
const real_t rel_tol = 1e-8;
const double rel_tol = 1e-8;
M = new BilinearForm(&fespace);
M->AddDomainIntegrator(new MassIntegrator());
@@ -336,7 +336,7 @@ void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
M_solver.Mult(z, du_dt);
}
void ConductionOperator::ImplicitSolve(const real_t dt,
void ConductionOperator::ImplicitSolve(const double dt,
const Vector &u, Vector &du_dt)
{
// Solve the equation:
@@ -382,7 +382,7 @@ ConductionOperator::~ConductionOperator()
delete K;
}
real_t InitialTemperature(const Vector &x)
double InitialTemperature(const Vector &x)
{
if (x.Norml2() < 0.5)
{
+17 -17
View File
@@ -62,7 +62,7 @@ protected:
HypreParMatrix Mmat;
HypreParMatrix Kmat;
HypreParMatrix *T; // T = M + dt K
real_t current_dt;
double current_dt;
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
HypreSmoother M_prec; // Preconditioner for the mass matrix M
@@ -70,18 +70,18 @@ protected:
CGSolver T_solver; // Implicit solver for T = M + dt K
HypreSmoother T_prec; // Preconditioner for the implicit solver
real_t alpha, kappa;
double alpha, kappa;
mutable Vector z; // auxiliary vector
public:
ConductionOperator(ParFiniteElementSpace &f, real_t alpha, real_t kappa,
ConductionOperator(ParFiniteElementSpace &f, double alpha, double kappa,
const Vector &u);
virtual void Mult(const Vector &u, Vector &du_dt) const;
/** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
This is the only requirement for high-order SDIRK implicit integration.*/
virtual void ImplicitSolve(const real_t dt, const Vector &u, Vector &k);
virtual void ImplicitSolve(const double dt, const Vector &u, Vector &k);
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
void SetParameters(const Vector &u);
@@ -89,7 +89,7 @@ public:
virtual ~ConductionOperator();
};
real_t InitialTemperature(const Vector &x);
double InitialTemperature(const Vector &x);
int main(int argc, char *argv[])
{
@@ -105,10 +105,10 @@ int main(int argc, char *argv[])
int par_ref_levels = 1;
int order = 2;
int ode_solver_type = 3;
real_t t_final = 0.5;
real_t dt = 1.0e-2;
real_t alpha = 1.0e-2;
real_t kappa = 0.5;
double t_final = 0.5;
double dt = 1.0e-2;
double alpha = 1.0e-2;
double kappa = 0.5;
bool visualization = true;
bool visit = false;
int vis_steps = 5;
@@ -313,7 +313,7 @@ int main(int argc, char *argv[])
// 10. Perform time-integration (looping over the time iterations, ti, with a
// time-step dt).
ode_solver->Init(oper);
real_t t = 0.0;
double t = 0.0;
bool last_step = false;
for (int ti = 1; !last_step; ti++)
@@ -382,13 +382,13 @@ int main(int argc, char *argv[])
return 0;
}
ConductionOperator::ConductionOperator(ParFiniteElementSpace &f, real_t al,
real_t kap, const Vector &u)
: TimeDependentOperator(f.GetTrueVSize(), (real_t) 0.0), fespace(f),
M(NULL), K(NULL), T(NULL), current_dt(0.0),
ConductionOperator::ConductionOperator(ParFiniteElementSpace &f, double al,
double kap, const Vector &u)
: TimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL), K(NULL),
T(NULL), current_dt(0.0),
M_solver(f.GetComm()), T_solver(f.GetComm()), z(height)
{
const real_t rel_tol = 1e-8;
const double rel_tol = 1e-8;
M = new ParBilinearForm(&fespace);
M->AddDomainIntegrator(new MassIntegrator());
@@ -427,7 +427,7 @@ void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
M_solver.Mult(z, du_dt);
}
void ConductionOperator::ImplicitSolve(const real_t dt,
void ConductionOperator::ImplicitSolve(const double dt,
const Vector &u, Vector &du_dt)
{
// Solve the equation:
@@ -473,7 +473,7 @@ ConductionOperator::~ConductionOperator()
delete K;
}
real_t InitialTemperature(const Vector &x)
double InitialTemperature(const Vector &x)
{
if (x.Norml2() < 0.5)
{
+8 -8
View File
@@ -69,7 +69,7 @@ public:
void SetDisplacement(GridFunction &u_) { u = &u_; }
void SetComponent(int i, int j) { si = i; sj = j; }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
};
// Simple GLVis visualization manager.
@@ -104,8 +104,8 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/beam-tri.mesh";
int ref_levels = -1;
int order = 1;
real_t alpha = -1.0;
real_t kappa = -1.0;
double alpha = -1.0;
double kappa = -1.0;
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -245,7 +245,7 @@ int main(int argc, char *argv[])
// solve the system Ax=b with PCG for the symmetric formulation, or GMRES
// for the non-symmetric.
GSSmoother M(A);
const real_t rtol = 1e-6;
const double rtol = 1e-6;
if (alpha == -1.0)
{
PCG(A, M, B, X, 3, 5000, rtol*rtol, 0.0);
@@ -337,17 +337,17 @@ void InitDisplacement(const Vector &x, Vector &u)
}
real_t StressCoefficient::Eval(ElementTransformation &T,
double StressCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(u != NULL, "displacement field is not set");
real_t L = lambda.Eval(T, ip);
real_t M = mu.Eval(T, ip);
double L = lambda.Eval(T, ip);
double M = mu.Eval(T, ip);
u->GetVectorGradient(T, grad);
if (si == sj)
{
real_t div_u = grad.Trace();
double div_u = grad.Trace();
return L*div_u + 2*M*grad(si,si);
}
else
+8 -8
View File
@@ -69,7 +69,7 @@ public:
void SetDisplacement(GridFunction &u_) { u = &u_; }
void SetComponent(int i, int j) { si = i; sj = j; }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
};
// Simple GLVis visualization manager.
@@ -108,8 +108,8 @@ int main(int argc, char *argv[])
int ser_ref_levels = -1;
int par_ref_levels = 1;
int order = 1;
real_t alpha = -1.0;
real_t kappa = -1.0;
double alpha = -1.0;
double kappa = -1.0;
bool amg_elast = false;
bool visualization = 1;
@@ -268,7 +268,7 @@ int main(int argc, char *argv[])
// 11. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system Ax=b with PCG for the symmetric formulation, or GMRES
// for the non-symmetric.
const real_t rtol = 1e-6;
const double rtol = 1e-6;
HypreBoomerAMG amg(A);
if (amg_elast)
{
@@ -376,17 +376,17 @@ void InitDisplacement(const Vector &x, Vector &u)
}
real_t StressCoefficient::Eval(ElementTransformation &T,
double StressCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(u != NULL, "displacement field is not set");
real_t L = lambda.Eval(T, ip);
real_t M = mu.Eval(T, ip);
double L = lambda.Eval(T, ip);
double M = mu.Eval(T, ip);
u->GetVectorGradient(T, grad);
if (si == sj)
{
real_t div_u = grad.Trace();
double div_u = grad.Trace();
return L*div_u + 2*M*grad(si,si);
}
else
+10 -10
View File
@@ -52,11 +52,11 @@ int problem;
// Equation constant parameters.
const int num_equation = 4;
const real_t specific_heat_ratio = 1.4;
const real_t gas_constant = 1.0;
const double specific_heat_ratio = 1.4;
const double gas_constant = 1.0;
// Maximum characteristic speed (updated by integrators)
real_t max_char_speed;
double max_char_speed;
int main(int argc, char *argv[])
{
@@ -66,9 +66,9 @@ int main(int argc, char *argv[])
int ref_levels = 1;
int order = 3;
int ode_solver_type = 4;
real_t t_final = 2.0;
real_t dt = -0.01;
real_t cfl = 0.3;
double t_final = 2.0;
double dt = -0.01;
double cfl = 0.3;
bool visualization = true;
int vis_steps = 50;
@@ -228,7 +228,7 @@ int main(int argc, char *argv[])
}
// Determine the minimum element size.
real_t hmin = 0.0;
double hmin = 0.0;
if (cfl > 0)
{
hmin = mesh.GetElementSize(0, 1);
@@ -242,7 +242,7 @@ int main(int argc, char *argv[])
tic_toc.Clear();
tic_toc.Start();
real_t t = 0.0;
double t = 0.0;
euler.SetTime(t);
ode_solver->Init(euler);
@@ -260,7 +260,7 @@ int main(int argc, char *argv[])
bool done = false;
for (int ti = 0; !done; )
{
real_t dt_real = min(dt, t_final - t);
double dt_real = min(dt, t_final - t);
ode_solver->Step(sol, t, dt_real);
if (cfl > 0)
@@ -298,7 +298,7 @@ int main(int argc, char *argv[])
// 10. Compute the L2 solution error summed for all components.
if (t_final == 2.0)
{
const real_t error = sol.ComputeLpError(2, u0);
const double error = sol.ComputeLpError(2, u0);
cout << "Solution error: " << error << endl;
}
+50 -50
View File
@@ -9,11 +9,11 @@ using namespace mfem;
extern int problem;
// Maximum characteristic speed (updated by integrators)
extern real_t max_char_speed;
extern double max_char_speed;
extern const int num_equation;
extern const real_t specific_heat_ratio;
extern const real_t gas_constant;
extern const double specific_heat_ratio;
extern const double gas_constant;
// Time-dependent operator for the right-hand side of the ODE representing the
// DG weak form.
@@ -52,7 +52,7 @@ private:
public:
RiemannSolver();
real_t Eval(const Vector &state1, const Vector &state2,
double Eval(const Vector &state1, const Vector &state2,
const Vector &nor, Vector &flux);
};
@@ -149,13 +149,13 @@ void FE_Evolution::Mult(const Vector &x, Vector &y) const
bool StateIsPhysical(const Vector &state, const int dim);
// Pressure (EOS) computation
inline real_t ComputePressure(const Vector &state, int dim)
inline double ComputePressure(const Vector &state, int dim)
{
const real_t den = state(0);
const double den = state(0);
const Vector den_vel(state.GetData() + 1, dim);
const real_t den_energy = state(1 + dim);
const double den_energy = state(1 + dim);
real_t den_vel2 = 0;
double den_vel2 = 0;
for (int d = 0; d < dim; d++) { den_vel2 += den_vel(d) * den_vel(d); }
den_vel2 /= den;
@@ -165,13 +165,13 @@ inline real_t ComputePressure(const Vector &state, int dim)
// Compute the vector flux F(u)
void ComputeFlux(const Vector &state, int dim, DenseMatrix &flux)
{
const real_t den = state(0);
const double den = state(0);
const Vector den_vel(state.GetData() + 1, dim);
const real_t den_energy = state(1 + dim);
const double den_energy = state(1 + dim);
MFEM_ASSERT(StateIsPhysical(state, dim), "");
const real_t pres = ComputePressure(state, dim);
const double pres = ComputePressure(state, dim);
for (int d = 0; d < dim; d++)
{
@@ -183,7 +183,7 @@ void ComputeFlux(const Vector &state, int dim, DenseMatrix &flux)
flux(1+d, d) += pres;
}
const real_t H = (den_energy + pres) / den;
const double H = (den_energy + pres) / den;
for (int d = 0; d < dim; d++)
{
flux(1+dim, d) = den_vel(d) * H;
@@ -196,15 +196,15 @@ void ComputeFluxDotN(const Vector &state, const Vector &nor,
{
// NOTE: nor in general is not a unit normal
const int dim = nor.Size();
const real_t den = state(0);
const double den = state(0);
const Vector den_vel(state.GetData() + 1, dim);
const real_t den_energy = state(1 + dim);
const double den_energy = state(1 + dim);
MFEM_ASSERT(StateIsPhysical(state, dim), "");
const real_t pres = ComputePressure(state, dim);
const double pres = ComputePressure(state, dim);
real_t den_velN = 0;
double den_velN = 0;
for (int d = 0; d < dim; d++) { den_velN += den_vel(d) * nor(d); }
fluxN(0) = den_velN;
@@ -213,23 +213,23 @@ void ComputeFluxDotN(const Vector &state, const Vector &nor,
fluxN(1+d) = den_velN * den_vel(d) / den + pres * nor(d);
}
const real_t H = (den_energy + pres) / den;
const double H = (den_energy + pres) / den;
fluxN(1 + dim) = den_velN * H;
}
// Compute the maximum characteristic speed.
inline real_t ComputeMaxCharSpeed(const Vector &state, const int dim)
inline double ComputeMaxCharSpeed(const Vector &state, const int dim)
{
const real_t den = state(0);
const double den = state(0);
const Vector den_vel(state.GetData() + 1, dim);
real_t den_vel2 = 0;
double den_vel2 = 0;
for (int d = 0; d < dim; d++) { den_vel2 += den_vel(d) * den_vel(d); }
den_vel2 /= den;
const real_t pres = ComputePressure(state, dim);
const real_t sound = sqrt(specific_heat_ratio * pres / den);
const real_t vel = sqrt(den_vel2 / den);
const double pres = ComputePressure(state, dim);
const double sound = sqrt(specific_heat_ratio * pres / den);
const double vel = sqrt(den_vel2 / den);
return vel + sound;
}
@@ -254,7 +254,7 @@ void FE_Evolution::GetFlux(const DenseMatrix &x_, DenseTensor &flux_) const
}
// Update max char speed
const real_t mcs = ComputeMaxCharSpeed(state, flux_dim);
const double mcs = ComputeMaxCharSpeed(state, flux_dim);
if (mcs > max_char_speed) { max_char_speed = mcs; }
}
}
@@ -264,7 +264,7 @@ RiemannSolver::RiemannSolver() :
flux1(num_equation),
flux2(num_equation) { }
real_t RiemannSolver::Eval(const Vector &state1, const Vector &state2,
double RiemannSolver::Eval(const Vector &state1, const Vector &state2,
const Vector &nor, Vector &flux)
{
// NOTE: nor in general is not a unit normal
@@ -273,15 +273,15 @@ real_t RiemannSolver::Eval(const Vector &state1, const Vector &state2,
MFEM_ASSERT(StateIsPhysical(state1, dim), "");
MFEM_ASSERT(StateIsPhysical(state2, dim), "");
const real_t maxE1 = ComputeMaxCharSpeed(state1, dim);
const real_t maxE2 = ComputeMaxCharSpeed(state2, dim);
const double maxE1 = ComputeMaxCharSpeed(state1, dim);
const double maxE2 = ComputeMaxCharSpeed(state2, dim);
const real_t maxE = max(maxE1, maxE2);
const double maxE = max(maxE1, maxE2);
ComputeFluxDotN(state1, nor, flux1);
ComputeFluxDotN(state2, nor, flux2);
real_t normag = 0;
double normag = 0;
for (int i = 0; i < dim; i++)
{
normag += nor(i) * nor(i);
@@ -359,7 +359,7 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
// Get the normal vector and the flux on the face
CalcOrtho(Tr.Jacobian(), nor);
const real_t mcs = rsolver.Eval(funval1, funval2, nor, fluxN);
const double mcs = rsolver.Eval(funval1, funval2, nor, fluxN);
// Update max char speed
if (mcs > max_char_speed) { max_char_speed = mcs; }
@@ -382,9 +382,9 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
// Check that the state is physical - enabled in debug mode
bool StateIsPhysical(const Vector &state, const int dim)
{
const real_t den = state(0);
const double den = state(0);
const Vector den_vel(state.GetData() + 1, dim);
const real_t den_energy = state(1 + dim);
const double den_energy = state(1 + dim);
if (den < 0)
{
@@ -407,11 +407,11 @@ bool StateIsPhysical(const Vector &state, const int dim)
return false;
}
real_t den_vel2 = 0;
double den_vel2 = 0;
for (int i = 0; i < dim; i++) { den_vel2 += den_vel(i) * den_vel(i); }
den_vel2 /= den;
const real_t pres = (specific_heat_ratio - 1.0) * (den_energy - 0.5 * den_vel2);
const double pres = (specific_heat_ratio - 1.0) * (den_energy - 0.5 * den_vel2);
if (pres <= 0)
{
@@ -431,7 +431,7 @@ void InitialCondition(const Vector &x, Vector &y)
{
MFEM_ASSERT(x.Size() == 2, "");
real_t radius = 0, Minf = 0, beta = 0;
double radius = 0, Minf = 0, beta = 0;
if (problem == 1)
{
// "Fast vortex"
@@ -452,36 +452,36 @@ void InitialCondition(const Vector &x, Vector &y)
"Options are: 1 - fast vortex, 2 - slow vortex");
}
const real_t xc = 0.0, yc = 0.0;
const double xc = 0.0, yc = 0.0;
// Nice units
const real_t vel_inf = 1.;
const real_t den_inf = 1.;
const double vel_inf = 1.;
const double den_inf = 1.;
// Derive remainder of background state from this and Minf
const real_t pres_inf = (den_inf / specific_heat_ratio) * (vel_inf / Minf) *
const double pres_inf = (den_inf / specific_heat_ratio) * (vel_inf / Minf) *
(vel_inf / Minf);
const real_t temp_inf = pres_inf / (den_inf * gas_constant);
const double temp_inf = pres_inf / (den_inf * gas_constant);
real_t r2rad = 0.0;
double r2rad = 0.0;
r2rad += (x(0) - xc) * (x(0) - xc);
r2rad += (x(1) - yc) * (x(1) - yc);
r2rad /= (radius * radius);
const real_t shrinv1 = 1.0 / (specific_heat_ratio - 1.);
const double shrinv1 = 1.0 / (specific_heat_ratio - 1.);
const real_t velX = vel_inf * (1 - beta * (x(1) - yc) / radius * exp(
const double velX = vel_inf * (1 - beta * (x(1) - yc) / radius * exp(
-0.5 * r2rad));
const real_t velY = vel_inf * beta * (x(0) - xc) / radius * exp(-0.5 * r2rad);
const real_t vel2 = velX * velX + velY * velY;
const double velY = vel_inf * beta * (x(0) - xc) / radius * exp(-0.5 * r2rad);
const double vel2 = velX * velX + velY * velY;
const real_t specific_heat = gas_constant * specific_heat_ratio * shrinv1;
const real_t temp = temp_inf - 0.5 * (vel_inf * beta) *
const double specific_heat = gas_constant * specific_heat_ratio * shrinv1;
const double temp = temp_inf - 0.5 * (vel_inf * beta) *
(vel_inf * beta) / specific_heat * exp(-r2rad);
const real_t den = den_inf * pow(temp/temp_inf, shrinv1);
const real_t pres = den * gas_constant * temp;
const real_t energy = shrinv1 * pres / den + 0.5 * vel2;
const double den = den_inf * pow(temp/temp_inf, shrinv1);
const double pres = den * gas_constant * temp;
const double energy = shrinv1 * pres / den + 0.5 * vel2;
y(0) = den;
y(1) = den * velX;
+18 -19
View File
@@ -52,11 +52,11 @@ int problem;
// Equation constant parameters.
const int num_equation = 4;
const real_t specific_heat_ratio = 1.4;
const real_t gas_constant = 1.0;
const double specific_heat_ratio = 1.4;
const double gas_constant = 1.0;
// Maximum characteristic speed (updated by integrators)
real_t max_char_speed;
double max_char_speed;
int main(int argc, char *argv[])
{
@@ -71,9 +71,9 @@ int main(int argc, char *argv[])
int par_ref_levels = 1;
int order = 3;
int ode_solver_type = 4;
real_t t_final = 2.0;
real_t dt = -0.01;
real_t cfl = 0.3;
double t_final = 2.0;
double dt = -0.01;
double cfl = 0.3;
bool visualization = true;
int vis_steps = 50;
@@ -270,24 +270,23 @@ int main(int argc, char *argv[])
}
// Determine the minimum element size.
real_t hmin;
double hmin;
if (cfl > 0)
{
real_t my_hmin = pmesh.GetElementSize(0, 1);
double my_hmin = pmesh.GetElementSize(0, 1);
for (int i = 1; i < pmesh.GetNE(); i++)
{
my_hmin = min(pmesh.GetElementSize(i, 1), my_hmin);
}
// Reduce to find the global minimum element size
MPI_Allreduce(&my_hmin, &hmin, 1, MPITypeMap<real_t>::mpi_type,
MPI_MIN, pmesh.GetComm());
MPI_Allreduce(&my_hmin, &hmin, 1, MPI_DOUBLE, MPI_MIN, pmesh.GetComm());
}
// Start the timer.
tic_toc.Clear();
tic_toc.Start();
real_t t = 0.0;
double t = 0.0;
euler.SetTime(t);
ode_solver->Init(euler);
@@ -300,9 +299,9 @@ int main(int argc, char *argv[])
A.Mult(sol, z);
// Reduce to find the global maximum wave speed
{
real_t all_max_char_speed;
MPI_Allreduce(&max_char_speed, &all_max_char_speed, 1,
MPITypeMap<real_t>::mpi_type, MPI_MAX, pmesh.GetComm());
double all_max_char_speed;
MPI_Allreduce(&max_char_speed, &all_max_char_speed,
1, MPI_DOUBLE, MPI_MAX, pmesh.GetComm());
max_char_speed = all_max_char_speed;
}
dt = cfl * hmin / max_char_speed / (2*order+1);
@@ -312,16 +311,16 @@ int main(int argc, char *argv[])
bool done = false;
for (int ti = 0; !done; )
{
real_t dt_real = min(dt, t_final - t);
double dt_real = min(dt, t_final - t);
ode_solver->Step(sol, t, dt_real);
if (cfl > 0)
{
// Reduce to find the global maximum wave speed
{
real_t all_max_char_speed;
MPI_Allreduce(&max_char_speed, &all_max_char_speed, 1,
MPITypeMap<real_t>::mpi_type, MPI_MAX, pmesh.GetComm());
double all_max_char_speed;
MPI_Allreduce(&max_char_speed, &all_max_char_speed,
1, MPI_DOUBLE, MPI_MAX, pmesh.GetComm());
max_char_speed = all_max_char_speed;
}
dt = cfl * hmin / max_char_speed / (2*order+1);
@@ -367,7 +366,7 @@ int main(int argc, char *argv[])
// 12. Compute the L2 solution error summed for all components.
if (t_final == 2.0)
{
const real_t error = sol.ComputeLpError(2, u0);
const double error = sol.ComputeLpError(2, u0);
if (Mpi::Root())
{
cout << "Solution error: " << error << endl;
+10 -10
View File
@@ -48,15 +48,15 @@ public:
print_level = print_lvl;
}
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final);
virtual void MonitorResidual(int it, double norm, const Vector &r, bool final);
private:
const std::string prefix;
int print_level;
mutable real_t norm0;
mutable double norm0;
};
void GeneralResidualMonitor::MonitorResidual(int it, real_t norm,
void GeneralResidualMonitor::MonitorResidual(int it, double norm,
const Vector &r, bool final)
{
if (print_level == 1 || (print_level == 3 && (final || it == 0)))
@@ -103,7 +103,7 @@ protected:
BlockOperator *jacobian;
// Scaling factor for the pressure mass matrix in the block preconditioner
real_t gamma;
double gamma;
// Objects for the block preconditioner application
SparseMatrix *pressure_mass;
@@ -157,7 +157,7 @@ protected:
public:
RubberOperator(Array<FiniteElementSpace *> &fes, Array<Array<int> *>&ess_bdr,
Array<int> &block_trueOffsets, real_t rel_tol, real_t abs_tol,
Array<int> &block_trueOffsets, double rel_tol, double abs_tol,
int iter, Coefficient &mu);
// Required to use the native newton solver
@@ -187,10 +187,10 @@ int main(int argc, char *argv[])
int ref_levels = 0;
int order = 2;
bool visualization = true;
real_t newton_rel_tol = 1e-4;
real_t newton_abs_tol = 1e-6;
double newton_rel_tol = 1e-4;
double newton_abs_tol = 1e-6;
int newton_iter = 500;
real_t mu = 1.0;
double mu = 1.0;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -449,8 +449,8 @@ JacobianPreconditioner::~JacobianPreconditioner()
RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
Array<Array<int> *> &ess_bdr,
Array<int> &offsets,
real_t rel_tol,
real_t abs_tol,
double rel_tol,
double abs_tol,
int iter,
Coefficient &c_mu)
: Operator(fes[0]->GetTrueVSize() + fes[1]->GetTrueVSize()),
+10 -10
View File
@@ -62,15 +62,15 @@ public:
#endif
}
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final);
virtual void MonitorResidual(int it, double norm, const Vector &r, bool final);
private:
const std::string prefix;
int print_level;
mutable real_t norm0;
mutable double norm0;
};
void GeneralResidualMonitor::MonitorResidual(int it, real_t norm,
void GeneralResidualMonitor::MonitorResidual(int it, double norm,
const Vector &r, bool final)
{
if (print_level == 1 || (print_level == 3 && (final || it == 0)))
@@ -117,7 +117,7 @@ protected:
BlockOperator *jacobian;
// Scaling factor for the pressure mass matrix in the block preconditioner
real_t gamma;
double gamma;
// Objects for the block preconditioner application
Operator *pressure_mass;
@@ -171,7 +171,7 @@ protected:
public:
RubberOperator(Array<ParFiniteElementSpace *> &fes, Array<Array<int> *>&ess_bdr,
Array<int> &block_trueOffsets, real_t rel_tol, real_t abs_tol,
Array<int> &block_trueOffsets, double rel_tol, double abs_tol,
int iter, Coefficient &mu);
// Required to use the native newton solver
@@ -214,10 +214,10 @@ int main(int argc, char *argv[])
int par_ref_levels = 0;
int order = 2;
bool visualization = true;
real_t newton_rel_tol = 1e-4;
real_t newton_abs_tol = 1e-6;
double newton_rel_tol = 1e-4;
double newton_abs_tol = 1e-6;
int newton_iter = 500;
real_t mu = 1.0;
double mu = 1.0;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -524,8 +524,8 @@ JacobianPreconditioner::~JacobianPreconditioner()
RubberOperator::RubberOperator(Array<ParFiniteElementSpace *> &fes,
Array<Array<int> *> &ess_bdr,
Array<int> &trueOffsets,
real_t rel_tol,
real_t abs_tol,
double rel_tol,
double abs_tol,
int iter,
Coefficient &c_mu)
: Operator(fes[0]->TrueVSize() + fes[1]->TrueVSize()),
+10 -10
View File
@@ -69,11 +69,11 @@ using namespace mfem;
// Constants used in the Hamiltonian
static int prob_ = 0;
static real_t m_ = 1.0;
static real_t k_ = 1.0;
static double m_ = 1.0;
static double k_ = 1.0;
// Hamiltonian functional, see below for implementation
real_t hamiltonian(real_t q, real_t p, real_t t);
double hamiltonian(double q, double p, double t);
class GradT : public Operator
{
@@ -94,7 +94,7 @@ int main(int argc, char *argv[])
// 1. Parse command-line options.
int order = 1;
int nsteps = 100;
real_t dt = 0.1;
double dt = 0.1;
bool visualization = true;
bool gnuplot = false;
@@ -136,7 +136,7 @@ int main(int argc, char *argv[])
siaSolver.Init(P,F);
// 3. Set the initial conditions
real_t t = 0.0;
double t = 0.0;
Vector q(1), p(1);
Vector e(nsteps+1);
q(0) = 0.0;
@@ -160,7 +160,7 @@ int main(int argc, char *argv[])
Vector x1(3); x1 = 0.0;
// 6. Perform time-stepping
real_t e_mean = 0.0;
double e_mean = 0.0;
for (int i = 0; i < nsteps; i++)
{
@@ -210,13 +210,13 @@ int main(int argc, char *argv[])
// 7. Compute and display mean and standard deviation of the energy
e_mean /= (nsteps + 1);
real_t e_var = 0.0;
double e_var = 0.0;
for (int i=0; i<=nsteps; i++)
{
e_var += pow(e[i] - e_mean, 2);
}
e_var /= (nsteps + 1);
real_t e_sd = sqrt(e_var);
double e_sd = sqrt(e_var);
cout << endl << "Mean and standard deviation of the energy" << endl;
cout << e_mean << "\t" << e_sd << endl;
@@ -256,9 +256,9 @@ int main(int argc, char *argv[])
}
}
real_t hamiltonian(real_t q, real_t p, real_t t)
double hamiltonian(double q, double p, double t)
{
real_t h = 1.0 - 0.5 / m_ + 0.5 * p * p / m_;
double h = 1.0 - 0.5 / m_ + 0.5 * p * p / m_;
switch (prob_)
{
case 1:
+15 -16
View File
@@ -74,11 +74,11 @@ using namespace mfem;
// Constants used in the Hamiltonian
static int prob_ = 0;
static real_t m_ = 1.0;
static real_t k_ = 1.0;
static double m_ = 1.0;
static double k_ = 1.0;
// Hamiltonian functional, see below for implementation
real_t hamiltonian(real_t q, real_t p, real_t t);
double hamiltonian(double q, double p, double t);
class GradT : public Operator
{
@@ -106,7 +106,7 @@ int main(int argc, char *argv[])
// 2. Parse command-line options.
int order = 1;
int nsteps = 100;
real_t dt = 0.1;
double dt = 0.1;
bool visualization = true;
bool gnuplot = false;
@@ -154,11 +154,11 @@ int main(int argc, char *argv[])
siaSolver.Init(P,F);
// 4. Set the initial conditions
real_t t = 0.0;
double t = 0.0;
Vector q(1), p(1);
Vector e(nsteps+1);
q(0) = sin(2.0*M_PI*(real_t)myid/num_procs);
p(0) = cos(2.0*M_PI*(real_t)myid/num_procs);
q(0) = sin(2.0*M_PI*(double)myid/num_procs);
p(0) = cos(2.0*M_PI*(double)myid/num_procs);
// 5. Prepare GnuPlot output file if needed
ostringstream oss;
@@ -181,7 +181,7 @@ int main(int argc, char *argv[])
Vector x1(3); x1 = 0.0;
// 7. Perform time-stepping
real_t e_mean = 0.0;
double e_mean = 0.0;
for (int i = 0; i < nsteps; i++)
{
@@ -238,21 +238,20 @@ int main(int argc, char *argv[])
// 8. Compute and display mean and standard deviation of the energy
e_mean /= (nsteps + 1);
real_t e_var = 0.0;
double e_var = 0.0;
for (int i = 0; i <= nsteps; i++)
{
e_var += pow(e[i] - e_mean, 2);
}
e_var /= (nsteps + 1);
real_t e_sd = sqrt(e_var);
double e_sd = sqrt(e_var);
real_t e_loc_stats[2];
real_t *e_stats = (myid == 0) ? new real_t[2 * num_procs] : (real_t*)NULL;
double e_loc_stats[2];
double *e_stats = (myid == 0) ? new double[2 * num_procs] : (double*)NULL;
e_loc_stats[0] = e_mean;
e_loc_stats[1] = e_sd;
MPI_Gather(e_loc_stats, 2, MPITypeMap<real_t>::mpi_type, e_stats, 2,
MPITypeMap<real_t>::mpi_type, 0, comm);
MPI_Gather(e_loc_stats, 2, MPI_DOUBLE, e_stats, 2, MPI_DOUBLE, 0, comm);
if (myid == 0)
{
@@ -325,9 +324,9 @@ int main(int argc, char *argv[])
}
}
real_t hamiltonian(real_t q, real_t p, real_t t)
double hamiltonian(double q, double p, double t)
{
real_t h = 1.0 - 0.5 / m_ + 0.5 * p * p / m_;
double h = 1.0 - 0.5 / m_ + 0.5 * p * p / m_;
switch (prob_)
{
case 1:
+18 -18
View File
@@ -57,13 +57,13 @@
using namespace std;
using namespace mfem;
static real_t mu_ = 1.0;
static real_t epsilon_ = 1.0;
static real_t sigma_ = 20.0;
static real_t omega_ = 10.0;
static double mu_ = 1.0;
static double epsilon_ = 1.0;
static double sigma_ = 20.0;
static double omega_ = 10.0;
real_t u0_real_exact(const Vector &);
real_t u0_imag_exact(const Vector &);
double u0_real_exact(const Vector &);
double u0_imag_exact(const Vector &);
void u1_real_exact(const Vector &, Vector &);
void u1_imag_exact(const Vector &, Vector &);
@@ -80,8 +80,8 @@ int main(int argc, char *argv[])
int ref_levels = 0;
int order = 1;
int prob = 0;
real_t freq = -1.0;
real_t a_coef = 0.0;
double freq = -1.0;
double a_coef = 0.0;
bool visualization = 1;
bool herm_conv = true;
bool exact_sol = true;
@@ -412,7 +412,7 @@ int main(int argc, char *argv[])
break; // This should be unreachable
}
}
real_t s = (prob != 1) ? 1.0 : -1.0;
double s = (prob != 1) ? 1.0 : -1.0;
pc_i = new ScaledOperator(pc_r,
(conv == ComplexOperator::HERMITIAN) ?
s:-s);
@@ -436,8 +436,8 @@ int main(int argc, char *argv[])
if (exact_sol)
{
real_t err_r = -1.0;
real_t err_i = -1.0;
double err_r = -1.0;
double err_i = -1.0;
switch (prob)
{
@@ -524,7 +524,7 @@ int main(int argc, char *argv[])
int i = 0;
while (sol_sock)
{
real_t t = (real_t)(i % num_frames) / num_frames;
double t = (double)(i % num_frames) / num_frames;
ostringstream oss;
oss << "Harmonic Solution (t = " << t << " T)";
@@ -555,21 +555,21 @@ bool check_for_inline_mesh(const char * mesh_file)
return s0 == "inline-";
}
complex<real_t> u0_exact(const Vector &x)
complex<double> u0_exact(const Vector &x)
{
int dim = x.Size();
complex<real_t> i(0.0, 1.0);
complex<real_t> alpha = (epsilon_ * omega_ - i * sigma_);
complex<real_t> kappa = std::sqrt(mu_ * omega_* alpha);
complex<double> i(0.0, 1.0);
complex<double> alpha = (epsilon_ * omega_ - i * sigma_);
complex<double> kappa = std::sqrt(mu_ * omega_* alpha);
return std::exp(-i * kappa * x[dim - 1]);
}
real_t u0_real_exact(const Vector &x)
double u0_real_exact(const Vector &x)
{
return u0_exact(x).real();
}
real_t u0_imag_exact(const Vector &x)
double u0_imag_exact(const Vector &x)
{
return u0_exact(x).imag();
}
+17 -17
View File
@@ -57,13 +57,13 @@
using namespace std;
using namespace mfem;
static real_t mu_ = 1.0;
static real_t epsilon_ = 1.0;
static real_t sigma_ = 20.0;
static real_t omega_ = 10.0;
static double mu_ = 1.0;
static double epsilon_ = 1.0;
static double sigma_ = 20.0;
static double omega_ = 10.0;
real_t u0_real_exact(const Vector &);
real_t u0_imag_exact(const Vector &);
double u0_real_exact(const Vector &);
double u0_imag_exact(const Vector &);
void u1_real_exact(const Vector &, Vector &);
void u1_imag_exact(const Vector &, Vector &);
@@ -87,8 +87,8 @@ int main(int argc, char *argv[])
int par_ref_levels = 1;
int order = 1;
int prob = 0;
real_t freq = -1.0;
real_t a_coef = 0.0;
double freq = -1.0;
double a_coef = 0.0;
bool visualization = 1;
bool herm_conv = true;
bool exact_sol = true;
@@ -475,8 +475,8 @@ int main(int argc, char *argv[])
if (exact_sol)
{
real_t err_r = -1.0;
real_t err_i = -1.0;
double err_r = -1.0;
double err_i = -1.0;
switch (prob)
{
@@ -576,7 +576,7 @@ int main(int argc, char *argv[])
int i = 0;
while (sol_sock)
{
real_t t = (real_t)(i % num_frames) / num_frames;
double t = (double)(i % num_frames) / num_frames;
ostringstream oss;
oss << "Harmonic Solution (t = " << t << " T)";
@@ -608,21 +608,21 @@ bool check_for_inline_mesh(const char * mesh_file)
return s0 == "inline-";
}
complex<real_t> u0_exact(const Vector &x)
complex<double> u0_exact(const Vector &x)
{
int dim = x.Size();
complex<real_t> i(0.0, 1.0);
complex<real_t> alpha = (epsilon_ * omega_ - i * sigma_);
complex<real_t> kappa = std::sqrt(mu_ * omega_* alpha);
complex<double> i(0.0, 1.0);
complex<double> alpha = (epsilon_ * omega_ - i * sigma_);
complex<double> kappa = std::sqrt(mu_ * omega_* alpha);
return std::exp(-i * kappa * x[dim - 1]);
}
real_t u0_real_exact(const Vector &x)
double u0_real_exact(const Vector &x)
{
return u0_exact(x).real();
}
real_t u0_imag_exact(const Vector &x)
double u0_imag_exact(const Vector &x)
{
return u0_exact(x).imag();
}
+21 -19
View File
@@ -26,12 +26,13 @@
using namespace std;
using namespace mfem;
/** After spatial discretization, the wave model can be written as:
/** After spatial discretization, the conduction model can be written as:
*
* d^2u/dt^2 = M^{-1}(-Ku)
*
* where u is the vector representing the temperature, M is the mass,
* and K is the stiffness matrix.
* where u is the vector representing the temperature, M is the mass matrix,
* and K is the diffusion operator with diffusivity depending on u:
* (\kappa + \alpha u).
*
* Class WaveOperator represents the right-hand side of the above ODE.
*/
@@ -46,7 +47,7 @@ protected:
SparseMatrix Mmat, Kmat, Kmat0;
SparseMatrix *T; // T = M + dt K
real_t current_dt;
double current_dt;
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
DSmoother M_prec; // Preconditioner for the mass matrix M
@@ -58,7 +59,7 @@ protected:
mutable Vector z; // auxiliary vector
public:
WaveOperator(FiniteElementSpace &f, Array<int> &ess_bdr, real_t speed);
WaveOperator(FiniteElementSpace &f, Array<int> &ess_bdr,double speed);
using SecondOrderTimeDependentOperator::Mult;
virtual void Mult(const Vector &u, const Vector &du_dt,
@@ -68,7 +69,7 @@ public:
d2udt2 = f(u + fac0*d2udt2,dudt + fac1*d2udt2, t),
for the unknown d2udt2. */
using SecondOrderTimeDependentOperator::ImplicitSolve;
virtual void ImplicitSolve(const real_t fac0, const real_t fac1,
virtual void ImplicitSolve(const double fac0, const double fac1,
const Vector &u, const Vector &dudt, Vector &d2udt2);
///
@@ -79,11 +80,12 @@ public:
WaveOperator::WaveOperator(FiniteElementSpace &f,
Array<int> &ess_bdr, real_t speed)
: SecondOrderTimeDependentOperator(f.GetTrueVSize(), (real_t) 0.0),
fespace(f), M(NULL), K(NULL), T(NULL), current_dt(0.0), z(height)
Array<int> &ess_bdr, double speed)
: SecondOrderTimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL),
K(NULL),
T(NULL), current_dt(0.0), z(height)
{
const real_t rel_tol = 1e-8;
const double rel_tol = 1e-8;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
@@ -131,7 +133,7 @@ void WaveOperator::Mult(const Vector &u, const Vector &du_dt,
M_solver.Mult(z, d2udt2);
}
void WaveOperator::ImplicitSolve(const real_t fac0, const real_t fac1,
void WaveOperator::ImplicitSolve(const double fac0, const double fac1,
const Vector &u, const Vector &dudt, Vector &d2udt2)
{
// Solve the equation:
@@ -166,12 +168,12 @@ WaveOperator::~WaveOperator()
delete c2;
}
real_t InitialSolution(const Vector &x)
double InitialSolution(const Vector &x)
{
return exp(-x.Norml2()*x.Norml2()*30);
}
real_t InitialRate(const Vector &x)
double InitialRate(const Vector &x)
{
return 0.0;
}
@@ -185,9 +187,9 @@ int main(int argc, char *argv[])
int ref_levels = 2;
int order = 2;
int ode_solver_type = 10;
real_t t_final = 0.5;
real_t dt = 1.0e-2;
real_t speed = 1.0;
double t_final = 0.5;
double dt = 1.0e-2;
double speed = 1.0;
bool visualization = true;
bool visit = true;
bool dirichlet = true;
@@ -299,7 +301,7 @@ int main(int argc, char *argv[])
Vector dudt;
dudt_gf.GetTrueDofs(dudt);
// 7. Initialize the wave operator and the visualization.
// 7. Initialize the conduction operator and the visualization.
Array<int> ess_bdr;
if (mesh->bdr_attributes.Size())
{
@@ -354,7 +356,7 @@ int main(int argc, char *argv[])
else
{
sout.precision(precision);
sout << "solution\n" << *mesh << u_gf;
sout << "solution\n" << *mesh << dudt_gf;
sout << "pause\n";
sout << flush;
cout << "GLVis visualization paused."
@@ -365,7 +367,7 @@ int main(int argc, char *argv[])
// 8. Perform time-integration (looping over the time iterations, ti, with a
// time-step dt).
ode_solver->Init(oper);
real_t t = 0.0;
double t = 0.0;
bool last_step = false;
for (int ti = 1; !last_step; ti++)
+14 -14
View File
@@ -44,14 +44,14 @@
using namespace std;
using namespace mfem;
real_t p_exact(const Vector &x);
double p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
real_t div_gradp_exact(const Vector &x);
double div_gradp_exact(const Vector &x);
void v_exact(const Vector &x, Vector &v);
void curlv_exact(const Vector &x, Vector &cv);
int dim;
real_t freq = 1.0, kappa;
double freq = 1.0, kappa;
int main(int argc, char *argv[])
{
@@ -304,9 +304,9 @@ int main(int argc, char *argv[])
// 12. Compute and print the L_2 norm of the error.
if (prob == 0)
{
real_t errSol = x.ComputeL2Error(gradp_coef);
real_t errInterp = discreteInterpolant.ComputeL2Error(gradp_coef);
real_t errProj = exact_proj.ComputeL2Error(gradp_coef);
double errSol = x.ComputeL2Error(gradp_coef);
double errInterp = discreteInterpolant.ComputeL2Error(gradp_coef);
double errProj = exact_proj.ComputeL2Error(gradp_coef);
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in H(curl): "
"|| E_h - grad p ||_{L_2} = " << errSol << '\n' << endl;
@@ -317,9 +317,9 @@ int main(int argc, char *argv[])
}
else if (prob == 1)
{
real_t errSol = x.ComputeL2Error(curlv_coef);
real_t errInterp = discreteInterpolant.ComputeL2Error(curlv_coef);
real_t errProj = exact_proj.ComputeL2Error(curlv_coef);
double errSol = x.ComputeL2Error(curlv_coef);
double errInterp = discreteInterpolant.ComputeL2Error(curlv_coef);
double errProj = exact_proj.ComputeL2Error(curlv_coef);
cout << "\n Solution of (E_h,w) = (curl v_h,w) for E_h and w in H(div): "
"|| E_h - curl v ||_{L_2} = " << errSol << '\n' << endl;
@@ -337,9 +337,9 @@ int main(int argc, char *argv[])
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t errSol = x.ComputeL2Error(divgradp_coef, irs);
real_t errInterp = discreteInterpolant.ComputeL2Error(divgradp_coef, irs);
real_t errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
double errSol = x.ComputeL2Error(divgradp_coef, irs);
double errInterp = discreteInterpolant.ComputeL2Error(divgradp_coef, irs);
double errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
cout << "\n Solution of (f_h,q) = (div v_h,q) for f_h and q in L_2: "
"|| f_h - div v ||_{L_2} = " << errSol << '\n' << endl;
@@ -376,7 +376,7 @@ int main(int argc, char *argv[])
return 0;
}
real_t p_exact(const Vector &x)
double p_exact(const Vector &x)
{
if (dim == 3)
{
@@ -406,7 +406,7 @@ void gradp_exact(const Vector &x, Vector &f)
}
}
real_t div_gradp_exact(const Vector &x)
double div_gradp_exact(const Vector &x)
{
if (dim == 3)
{
+14 -14
View File
@@ -44,14 +44,14 @@
using namespace std;
using namespace mfem;
real_t p_exact(const Vector &x);
double p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
real_t div_gradp_exact(const Vector &x);
double div_gradp_exact(const Vector &x);
void v_exact(const Vector &x, Vector &v);
void curlv_exact(const Vector &x, Vector &cv);
int dim;
real_t freq = 1.0, kappa;
double freq = 1.0, kappa;
int main(int argc, char *argv[])
{
@@ -352,9 +352,9 @@ int main(int argc, char *argv[])
// 14. Compute and print the L_2 norm of the error.
if (prob == 0)
{
real_t errSol = x.ComputeL2Error(gradp_coef);
real_t errInterp = discreteInterpolant.ComputeL2Error(gradp_coef);
real_t errProj = exact_proj.ComputeL2Error(gradp_coef);
double errSol = x.ComputeL2Error(gradp_coef);
double errInterp = discreteInterpolant.ComputeL2Error(gradp_coef);
double errProj = exact_proj.ComputeL2Error(gradp_coef);
if (myid == 0)
{
@@ -368,9 +368,9 @@ int main(int argc, char *argv[])
}
else if (prob == 1)
{
real_t errSol = x.ComputeL2Error(curlv_coef);
real_t errInterp = discreteInterpolant.ComputeL2Error(curlv_coef);
real_t errProj = exact_proj.ComputeL2Error(curlv_coef);
double errSol = x.ComputeL2Error(curlv_coef);
double errInterp = discreteInterpolant.ComputeL2Error(curlv_coef);
double errProj = exact_proj.ComputeL2Error(curlv_coef);
if (myid == 0)
{
@@ -391,9 +391,9 @@ int main(int argc, char *argv[])
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t errSol = x.ComputeL2Error(divgradp_coef, irs);
real_t errInterp = discreteInterpolant.ComputeL2Error(divgradp_coef, irs);
real_t errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
double errSol = x.ComputeL2Error(divgradp_coef, irs);
double errInterp = discreteInterpolant.ComputeL2Error(divgradp_coef, irs);
double errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
if (myid == 0)
{
@@ -441,7 +441,7 @@ int main(int argc, char *argv[])
return 0;
}
real_t p_exact(const Vector &x)
double p_exact(const Vector &x)
{
if (dim == 3)
{
@@ -471,7 +471,7 @@ void gradp_exact(const Vector &x, Vector &f)
}
}
real_t div_gradp_exact(const Vector &x)
double div_gradp_exact(const Vector &x)
{
if (dim == 3)
{
+101 -101
View File
@@ -53,13 +53,13 @@ private:
int dim;
// Length of the PML Region in each direction
Array2D<real_t> length;
Array2D<double> length;
// Computational Domain Boundary
Array2D<real_t> comp_dom_bdr;
Array2D<double> comp_dom_bdr;
// Domain Boundary
Array2D<real_t> dom_bdr;
Array2D<double> dom_bdr;
// Integer Array identifying elements in the PML
// 0: in the PML, 1: not in the PML
@@ -70,13 +70,13 @@ private:
public:
// Constructor
PML(Mesh *mesh_,Array2D<real_t> length_);
PML(Mesh *mesh_,Array2D<double> length_);
// Return Computational Domain Boundary
Array2D<real_t> GetCompDomainBdr() {return comp_dom_bdr;}
Array2D<double> GetCompDomainBdr() {return comp_dom_bdr;}
// Return Domain Boundary
Array2D<real_t> GetDomainBdr() {return dom_bdr;}
Array2D<double> GetDomainBdr() {return dom_bdr;}
// Return Markers list for elements
Array<int> * GetMarkedPMLElements() {return &elems;}
@@ -85,7 +85,7 @@ public:
void SetAttributes(Mesh *mesh_);
// PML complex stretching function
void StretchFunction(const Vector &x, vector<complex<real_t>> &dxs);
void StretchFunction(const Vector &x, vector<complex<double>> &dxs);
};
// Class for returning the PML coefficients of the bilinear form
@@ -106,7 +106,7 @@ public:
virtual void Eval(Vector &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
real_t x[3];
double x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
K.SetSize(vdim);
@@ -114,7 +114,7 @@ public:
}
};
void maxwell_solution(const Vector &x, vector<complex<real_t>> &Eval);
void maxwell_solution(const Vector &x, vector<complex<double>> &Eval);
void E_bdr_data_Re(const Vector &x, Vector &E);
void E_bdr_data_Im(const Vector &x, Vector &E);
@@ -134,12 +134,12 @@ void detJ_inv_JT_J_Re(const Vector &x, PML * pml, Vector &D);
void detJ_inv_JT_J_Im(const Vector &x, PML * pml, Vector &D);
void detJ_inv_JT_J_abs(const Vector &x, PML * pml, Vector &D);
Array2D<real_t> comp_domain_bdr;
Array2D<real_t> domain_bdr;
Array2D<double> comp_domain_bdr;
Array2D<double> domain_bdr;
real_t mu = 1.0;
real_t epsilon = 1.0;
real_t omega;
double mu = 1.0;
double epsilon = 1.0;
double omega;
int dim;
bool exact_known = false;
@@ -160,7 +160,7 @@ int main(int argc, char *argv[])
int order = 1;
int ref_levels = 3;
int iprob = 4;
real_t freq = 5.0;
double freq = 5.0;
bool herm_conv = true;
bool umf_solver = false;
bool visualization = 1;
@@ -244,7 +244,7 @@ int main(int argc, char *argv[])
omega = 2.0 * M_PI * freq;
// Setup PML length
Array2D<real_t> length(dim, 2); length = 0.0;
Array2D<double> length(dim, 2); length = 0.0;
// 4. Setup the Cartesian PML region.
switch (prob)
@@ -470,7 +470,7 @@ int main(int argc, char *argv[])
std::unique_ptr<Operator> pc_r;
std::unique_ptr<Operator> pc_i;
real_t s = (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0;
double s = (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0;
if (pa)
{
// Jacobi Smoother
@@ -519,14 +519,14 @@ int main(int argc, char *argv[])
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t L2Error_Re = x.real().ComputeL2Error(E_ex_Re, irs,
double L2Error_Re = x.real().ComputeL2Error(E_ex_Re, irs,
pml->GetMarkedPMLElements());
real_t L2Error_Im = x.imag().ComputeL2Error(E_ex_Im, irs,
double L2Error_Im = x.imag().ComputeL2Error(E_ex_Im, irs,
pml->GetMarkedPMLElements());
ComplexGridFunction x_gf0(fespace);
x_gf0 = 0.0;
real_t norm_E_Re, norm_E_Im;
double norm_E_Re, norm_E_Im;
norm_E_Re = x_gf0.real().ComputeL2Error(E_ex_Re, irs,
pml->GetMarkedPMLElements());
norm_E_Im = x_gf0.imag().ComputeL2Error(E_ex_Im, irs,
@@ -593,7 +593,7 @@ int main(int argc, char *argv[])
int i = 0;
while (sol_sock)
{
real_t t = (real_t)(i % num_frames) / num_frames;
double t = (double)(i % num_frames) / num_frames;
ostringstream oss;
oss << "Harmonic Solution (t = " << t << " T)";
@@ -617,20 +617,20 @@ int main(int argc, char *argv[])
void source(const Vector &x, Vector &f)
{
Vector center(dim);
real_t r = 0.0;
double r = 0.0;
for (int i = 0; i < dim; ++i)
{
center(i) = 0.5 * (comp_domain_bdr(i, 0) + comp_domain_bdr(i, 1));
r += pow(x[i] - center[i], 2.);
}
real_t n = 5.0 * omega * sqrt(epsilon * mu) / M_PI;
real_t coeff = pow(n, 2) / M_PI;
real_t alpha = -pow(n, 2) * r;
double n = 5.0 * omega * sqrt(epsilon * mu) / M_PI;
double coeff = pow(n, 2) / M_PI;
double alpha = -pow(n, 2) * r;
f = 0.0;
f[0] = coeff * exp(alpha);
}
void maxwell_solution(const Vector &x, vector<complex<real_t>> &E)
void maxwell_solution(const Vector &x, vector<complex<double>> &E)
{
// Initialize
for (int i = 0; i < dim; ++i)
@@ -638,8 +638,8 @@ void maxwell_solution(const Vector &x, vector<complex<real_t>> &E)
E[i] = 0.0;
}
complex<real_t> zi = complex<real_t>(0., 1.);
real_t k = omega * sqrt(epsilon * mu);
complex<double> zi = complex<double>(0., 1.);
double k = omega * sqrt(epsilon * mu);
switch (prob)
{
case disc:
@@ -654,58 +654,58 @@ void maxwell_solution(const Vector &x, vector<complex<real_t>> &E)
if (dim == 2)
{
real_t x0 = x(0) + shift(0);
real_t x1 = x(1) + shift(1);
real_t r = sqrt(x0 * x0 + x1 * x1);
real_t beta = k * r;
double x0 = x(0) + shift(0);
double x1 = x(1) + shift(1);
double r = sqrt(x0 * x0 + x1 * x1);
double beta = k * r;
// Bessel functions
complex<real_t> Ho, Ho_r, Ho_rr;
Ho = jn(0, beta) + (complex<double>) zi * yn(0, beta);
Ho_r = -k * complex<real_t>(jn(1, beta) + (complex<double>) zi * yn(1, beta));
Ho_rr = -k * k * (real_t(1) / beta *
complex<real_t>(jn(1, beta) + (complex<double>) zi * yn(1, beta)) -
complex<real_t>(jn(2, beta) + (complex<double>) zi * yn(2, beta)));
complex<double> Ho, Ho_r, Ho_rr;
Ho = jn(0, beta) + zi * yn(0, beta);
Ho_r = -k * (jn(1, beta) + zi * yn(1, beta));
Ho_rr = -k * k * (1.0 / beta *
(jn(1, beta) + zi * yn(1, beta)) -
(jn(2, beta) + zi * yn(2, beta)));
// First derivatives
real_t r_x = x0 / r;
real_t r_y = x1 / r;
real_t r_xy = -(r_x / r) * r_y;
real_t r_xx = (1.0 / r) * (1.0 - r_x * r_x);
double r_x = x0 / r;
double r_y = x1 / r;
double r_xy = -(r_x / r) * r_y;
double r_xx = (1.0 / r) * (1.0 - r_x * r_x);
complex<real_t> val, val_xx, val_xy;
val = real_t(0.25) * zi * Ho;
val_xx = real_t(0.25) * zi * (r_xx * Ho_r + r_x * r_x * Ho_rr);
val_xy = real_t(0.25) * zi * (r_xy * Ho_r + r_x * r_y * Ho_rr);
complex<double> val, val_xx, val_xy;
val = 0.25 * zi * Ho;
val_xx = 0.25 * zi * (r_xx * Ho_r + r_x * r_x * Ho_rr);
val_xy = 0.25 * zi * (r_xy * Ho_r + r_x * r_y * Ho_rr);
E[0] = zi / k * (k * k * val + val_xx);
E[1] = zi / k * val_xy;
}
else if (dim == 3)
{
real_t x0 = x(0) + shift(0);
real_t x1 = x(1) + shift(1);
real_t x2 = x(2) + shift(2);
real_t r = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
double x0 = x(0) + shift(0);
double x1 = x(1) + shift(1);
double x2 = x(2) + shift(2);
double r = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
real_t r_x = x0 / r;
real_t r_y = x1 / r;
real_t r_z = x2 / r;
real_t r_xx = (1.0 / r) * (1.0 - r_x * r_x);
real_t r_yx = -(r_y / r) * r_x;
real_t r_zx = -(r_z / r) * r_x;
double r_x = x0 / r;
double r_y = x1 / r;
double r_z = x2 / r;
double r_xx = (1.0 / r) * (1.0 - r_x * r_x);
double r_yx = -(r_y / r) * r_x;
double r_zx = -(r_z / r) * r_x;
complex<real_t> val, val_r, val_rr;
complex<double> val, val_r, val_rr;
val = exp(zi * k * r) / r;
val_r = val / r * (zi * k * r - real_t(1));
val_r = val / r * (zi * k * r - 1.0);
val_rr = val / (r * r) * (-k * k * r * r
- real_t(2) * zi * k * r + real_t(2));
- 2.0 * zi * k * r + 2.0);
complex<real_t> val_xx, val_yx, val_zx;
complex<double> val_xx, val_yx, val_zx;
val_xx = val_rr * r_x * r_x + val_r * r_xx;
val_yx = val_rr * r_x * r_y + val_r * r_yx;
val_zx = val_rr * r_x * r_z + val_r * r_zx;
complex<real_t> alpha = zi * k / real_t(4) / (real_t) M_PI / k / k;
complex<double> alpha = zi * k / 4.0 / M_PI / k / k;
E[0] = alpha * (k * k * val + val_xx);
E[1] = alpha * val_yx;
E[2] = alpha * val_zx;
@@ -717,12 +717,12 @@ void maxwell_solution(const Vector &x, vector<complex<real_t>> &E)
// T_10 mode
if (dim == 3)
{
real_t k10 = sqrt(k * k - M_PI * M_PI);
E[1] = -zi * k / (real_t) M_PI * sin((real_t) M_PI*x(2))*exp(zi * k10 * x(0));
double k10 = sqrt(k * k - M_PI * M_PI);
E[1] = -zi * k / M_PI * sin(M_PI*x(2))*exp(zi * k10 * x(0));
}
else if (dim == 2)
{
E[1] = -zi * k / (real_t) M_PI * exp(zi * k * x(0));
E[1] = -zi * k / M_PI * exp(zi * k * x(0));
}
break;
}
@@ -733,7 +733,7 @@ void maxwell_solution(const Vector &x, vector<complex<real_t>> &E)
void E_exact_Re(const Vector &x, Vector &E)
{
vector<complex<real_t>> Eval(E.Size());
vector<complex<double>> Eval(E.Size());
maxwell_solution(x, Eval);
for (int i = 0; i < dim; ++i)
{
@@ -743,7 +743,7 @@ void E_exact_Re(const Vector &x, Vector &E)
void E_exact_Im(const Vector &x, Vector &E)
{
vector<complex<real_t>> Eval(E.Size());
vector<complex<double>> Eval(E.Size());
maxwell_solution(x, Eval);
for (int i = 0; i < dim; ++i)
{
@@ -768,7 +768,7 @@ void E_bdr_data_Re(const Vector &x, Vector &E)
}
if (!in_pml)
{
vector<complex<real_t>> Eval(E.Size());
vector<complex<double>> Eval(E.Size());
maxwell_solution(x, Eval);
for (int i = 0; i < dim; ++i)
{
@@ -795,7 +795,7 @@ void E_bdr_data_Im(const Vector &x, Vector &E)
}
if (!in_pml)
{
vector<complex<real_t>> Eval(E.Size());
vector<complex<double>> Eval(E.Size());
maxwell_solution(x, Eval);
for (int i = 0; i < dim; ++i)
{
@@ -806,8 +806,8 @@ void E_bdr_data_Im(const Vector &x, Vector &E)
void detJ_JT_J_inv_Re(const Vector &x, PML * pml, Vector &D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det(1.0, 0.0);
vector<complex<double>> dxs(dim);
complex<double> det(1.0, 0.0);
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -817,14 +817,14 @@ void detJ_JT_J_inv_Re(const Vector &x, PML * pml, Vector &D)
for (int i = 0; i < dim; ++i)
{
D(i) = (det / pow(dxs[i], real_t(2))).real();
D(i) = (det / pow(dxs[i], 2)).real();
}
}
void detJ_JT_J_inv_Im(const Vector &x, PML * pml, Vector &D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det = 1.0;
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -834,14 +834,14 @@ void detJ_JT_J_inv_Im(const Vector &x, PML * pml, Vector &D)
for (int i = 0; i < dim; ++i)
{
D(i) = (det / pow(dxs[i], real_t(2))).imag();
D(i) = (det / pow(dxs[i], 2)).imag();
}
}
void detJ_JT_J_inv_abs(const Vector &x, PML * pml, Vector &D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det = 1.0;
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -851,14 +851,14 @@ void detJ_JT_J_inv_abs(const Vector &x, PML * pml, Vector &D)
for (int i = 0; i < dim; ++i)
{
D(i) = abs(det / pow(dxs[i], real_t(2)));
D(i) = abs(det / pow(dxs[i], 2));
}
}
void detJ_inv_JT_J_Re(const Vector &x, PML * pml, Vector &D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det(1.0, 0.0);
vector<complex<double>> dxs(dim);
complex<double> det(1.0, 0.0);
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -869,21 +869,21 @@ void detJ_inv_JT_J_Re(const Vector &x, PML * pml, Vector &D)
// in the 2D case the coefficient is scalar 1/det(J)
if (dim == 2)
{
D = (real_t(1) / det).real();
D = (1.0 / det).real();
}
else
{
for (int i = 0; i < dim; ++i)
{
D(i) = (pow(dxs[i], real_t(2)) / det).real();
D(i) = (pow(dxs[i], 2) / det).real();
}
}
}
void detJ_inv_JT_J_Im(const Vector &x, PML * pml, Vector &D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det = 1.0;
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -893,21 +893,21 @@ void detJ_inv_JT_J_Im(const Vector &x, PML * pml, Vector &D)
if (dim == 2)
{
D = (real_t(1) / det).imag();
D = (1.0 / det).imag();
}
else
{
for (int i = 0; i < dim; ++i)
{
D(i) = (pow(dxs[i], real_t(2)) / det).imag();
D(i) = (pow(dxs[i], 2) / det).imag();
}
}
}
void detJ_inv_JT_J_abs(const Vector &x, PML * pml, Vector &D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det = 1.0;
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -917,18 +917,18 @@ void detJ_inv_JT_J_abs(const Vector &x, PML * pml, Vector &D)
if (dim == 2)
{
D = abs(real_t(1) / det);
D = abs(1.0 / det);
}
else
{
for (int i = 0; i < dim; ++i)
{
D(i) = abs(pow(dxs[i], real_t(2)) / det);
D(i) = abs(pow(dxs[i], 2) / det);
}
}
}
PML::PML(Mesh *mesh_, Array2D<real_t> length_)
PML::PML(Mesh *mesh_, Array2D<double> length_)
: mesh(mesh_), length(length_)
{
dim = mesh->Dimension();
@@ -979,7 +979,7 @@ void PML::SetAttributes(Mesh *mesh_)
for (int iv = 0; iv < nrvert; ++iv)
{
int vert_idx = vertices[iv];
real_t *coords = mesh_->GetVertex(vert_idx);
double *coords = mesh_->GetVertex(vert_idx);
for (int comp = 0; comp < dim; ++comp)
{
if (coords[comp] > comp_dom_bdr(comp, 1) ||
@@ -1000,14 +1000,14 @@ void PML::SetAttributes(Mesh *mesh_)
}
void PML::StretchFunction(const Vector &x,
vector<complex<real_t>> &dxs)
vector<complex<double>> &dxs)
{
complex<real_t> zi = complex<real_t>(0., 1.);
complex<double> zi = complex<double>(0., 1.);
real_t n = 2.0;
real_t c = 5.0;
real_t coeff;
real_t k = omega * sqrt(epsilon * mu);
double n = 2.0;
double c = 5.0;
double coeff;
double k = omega * sqrt(epsilon * mu);
// Stretch in each direction independently
for (int i = 0; i < dim; ++i)
@@ -1016,14 +1016,14 @@ void PML::StretchFunction(const Vector &x,
if (x(i) >= comp_domain_bdr(i, 1))
{
coeff = n * c / k / pow(length(i, 1), n);
dxs[i] = real_t(1) + zi * coeff *
abs(pow(x(i) - comp_domain_bdr(i, 1), n - real_t(1)));
dxs[i] = 1.0 + zi * coeff *
abs(pow(x(i) - comp_domain_bdr(i, 1), n - 1.0));
}
if (x(i) <= comp_domain_bdr(i, 0))
{
coeff = n * c / k / pow(length(i, 0), n);
dxs[i] = real_t(1) + zi * coeff *
abs(pow(x(i) - comp_domain_bdr(i, 0), n - real_t(1)));
dxs[i] = 1.0 + zi * coeff *
abs(pow(x(i) - comp_domain_bdr(i, 0), n - 1.0));
}
}
}
+104 -129
View File
@@ -52,13 +52,13 @@ private:
int dim;
// Length of the PML Region in each direction
Array2D<real_t> length;
Array2D<double> length;
// Computational Domain Boundary
Array2D<real_t> comp_dom_bdr;
Array2D<double> comp_dom_bdr;
// Domain Boundary
Array2D<real_t> dom_bdr;
Array2D<double> dom_bdr;
// Integer Array identifying elements in the PML
// 0: in the PML, 1: not in the PML
@@ -69,13 +69,13 @@ private:
public:
// Constructor
PML(Mesh *mesh_,Array2D<real_t> length_);
PML(Mesh *mesh_,Array2D<double> length_);
// Return Computational Domain Boundary
Array2D<real_t> GetCompDomainBdr() {return comp_dom_bdr;}
Array2D<double> GetCompDomainBdr() {return comp_dom_bdr;}
// Return Domain Boundary
Array2D<real_t> GetDomainBdr() {return dom_bdr;}
Array2D<double> GetDomainBdr() {return dom_bdr;}
// Return Markers list for elements
Array<int> * GetMarkedPMLElements() {return &elems;}
@@ -84,7 +84,7 @@ public:
void SetAttributes(ParMesh *pmesh);
// PML complex stretching function
void StretchFunction(const Vector &x, vector<complex<real_t>> &dxs);
void StretchFunction(const Vector &x, vector<complex<double>> &dxs);
};
// Class for returning the PML coefficients of the bilinear form
@@ -105,7 +105,7 @@ public:
virtual void Eval(Vector &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
real_t x[3];
double x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
K.SetSize(vdim);
@@ -113,7 +113,7 @@ public:
}
};
void maxwell_solution(const Vector &x, vector<complex<real_t>> &Eval);
void maxwell_solution(const Vector &x, vector<complex<double>> &Eval);
void E_bdr_data_Re(const Vector &x, Vector &E);
void E_bdr_data_Im(const Vector &x, Vector &E);
@@ -133,12 +133,12 @@ void detJ_inv_JT_J_Re(const Vector &x, PML * pml, Vector & D);
void detJ_inv_JT_J_Im(const Vector &x, PML * pml, Vector & D);
void detJ_inv_JT_J_abs(const Vector &x, PML * pml, Vector & D);
Array2D<real_t> comp_domain_bdr;
Array2D<real_t> domain_bdr;
Array2D<double> comp_domain_bdr;
Array2D<double> domain_bdr;
real_t mu = 1.0;
real_t epsilon = 1.0;
real_t omega;
double mu = 1.0;
double epsilon = 1.0;
double omega;
int dim;
bool exact_known = false;
@@ -166,11 +166,10 @@ int main(int argc, char *argv[])
int ref_levels = 1;
int par_ref_levels = 2;
int iprob = 4;
real_t freq = 5.0;
double freq = 5.0;
bool herm_conv = true;
bool slu_solver = false;
bool mumps_solver = false;
bool strumpack_solver = false;
bool visualization = 1;
bool pa = false;
const char *device_config = "cpu";
@@ -201,11 +200,6 @@ int main(int argc, char *argv[])
#ifdef MFEM_USE_MUMPS
args.AddOption(&mumps_solver, "-mumps", "--mumps-solver", "-no-mumps",
"--no-mumps-solver", "Use the MUMPS Solver.");
#endif
#ifdef MFEM_USE_STRUMPACK
args.AddOption(&strumpack_solver, "-strumpack", "--strumpack-solver",
"-no-strumpack", "--no-strumpack-solver",
"Use the STRUMPACK Solver.");
#endif
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
@@ -215,14 +209,13 @@ int main(int argc, char *argv[])
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.Parse();
if (slu_solver + mumps_solver + strumpack_solver > 1)
if (slu_solver && mumps_solver)
{
if (myid == 0)
cout << "WARNING: More than one of SuperLU, MUMPS, and STRUMPACK have"
<< " been selected, please choose only one." << endl
cout << "WARNING: Both SuperLU and MUMPS have been selected,"
<< " please choose either one." << endl
<< " Defaulting to SuperLU." << endl;
mumps_solver = false;
strumpack_solver = false;
}
if (iprob > 4) { iprob = 4; }
@@ -278,7 +271,7 @@ int main(int argc, char *argv[])
omega = 2.0 * M_PI * freq;
// Setup PML length
Array2D<real_t> length(dim, 2); length = 0.0;
Array2D<double> length(dim, 2); length = 0.0;
// 5. Setup the Cartesian PML region.
switch (prob)
@@ -481,24 +474,6 @@ int main(int argc, char *argv[])
delete A;
}
#endif
#ifdef MFEM_USE_STRUMPACK
if (!pa && strumpack_solver)
{
HypreParMatrix *A = Ah.As<ComplexHypreParMatrix>()->GetSystemMatrix();
STRUMPACKRowLocMatrix SA(*A);
STRUMPACKSolver strumpack(MPI_COMM_WORLD, argc, argv);
strumpack.SetPrintFactorStatistics(false);
strumpack.SetPrintSolveStatistics(false);
strumpack.SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
strumpack.SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
strumpack.SetMatching(strumpack::MatchingJob::NONE);
strumpack.SetCompression(strumpack::CompressionType::NONE);
strumpack.SetFromCommandLine();
strumpack.SetOperator(SA);
strumpack.Mult(B, X);
delete A;
}
#endif
#ifdef MFEM_USE_MUMPS
if (!pa && mumps_solver)
{
@@ -518,7 +493,7 @@ int main(int argc, char *argv[])
//
// In PML: 1/mu (abs(1/det(J) J^T J) Curl E, Curl F)
// + omega^2 * epsilon (abs(det(J) * (J^T J)^-1) * E, F)
if (pa || (!slu_solver && !mumps_solver && !strumpack_solver))
if (pa || (!slu_solver && !mumps_solver))
{
ConstantCoefficient absomeg(pow(omega, 2) * epsilon);
RestrictedCoefficient restr_absomeg(absomeg,attr);
@@ -599,14 +574,14 @@ int main(int argc, char *argv[])
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t L2Error_Re = x.real().ComputeL2Error(E_ex_Re, irs,
double L2Error_Re = x.real().ComputeL2Error(E_ex_Re, irs,
pml->GetMarkedPMLElements());
real_t L2Error_Im = x.imag().ComputeL2Error(E_ex_Im, irs,
double L2Error_Im = x.imag().ComputeL2Error(E_ex_Im, irs,
pml->GetMarkedPMLElements());
ParComplexGridFunction x_gf0(fespace);
x_gf0 = 0.0;
real_t norm_E_Re, norm_E_Im;
double norm_E_Re, norm_E_Im;
norm_E_Re = x_gf0.real().ComputeL2Error(E_ex_Re, irs,
pml->GetMarkedPMLElements());
norm_E_Im = x_gf0.imag().ComputeL2Error(E_ex_Im, irs,
@@ -694,7 +669,7 @@ int main(int argc, char *argv[])
int i = 0;
while (sol_sock)
{
real_t t = (real_t)(i % num_frames) / num_frames;
double t = (double)(i % num_frames) / num_frames;
ostringstream oss;
oss << "Harmonic Solution (t = " << t << " T)";
@@ -718,20 +693,20 @@ int main(int argc, char *argv[])
void source(const Vector &x, Vector &f)
{
Vector center(dim);
real_t r = 0.0;
double r = 0.0;
for (int i = 0; i < dim; ++i)
{
center(i) = 0.5 * (comp_domain_bdr(i, 0) + comp_domain_bdr(i, 1));
r += pow(x[i] - center[i], 2.);
}
real_t n = 5.0 * omega * sqrt(epsilon * mu) / M_PI;
real_t coeff = pow(n, 2) / M_PI;
real_t alpha = -pow(n, 2) * r;
double n = 5.0 * omega * sqrt(epsilon * mu) / M_PI;
double coeff = pow(n, 2) / M_PI;
double alpha = -pow(n, 2) * r;
f = 0.0;
f[0] = coeff * exp(alpha);
}
void maxwell_solution(const Vector &x, vector<complex<real_t>> &E)
void maxwell_solution(const Vector &x, vector<complex<double>> &E)
{
// Initialize
for (int i = 0; i < dim; ++i)
@@ -739,8 +714,8 @@ void maxwell_solution(const Vector &x, vector<complex<real_t>> &E)
E[i] = 0.0;
}
complex<real_t> zi = complex<real_t>(0., 1.);
real_t k = omega * sqrt(epsilon * mu);
complex<double> zi = complex<double>(0., 1.);
double k = omega * sqrt(epsilon * mu);
switch (prob)
{
case disc:
@@ -755,58 +730,58 @@ void maxwell_solution(const Vector &x, vector<complex<real_t>> &E)
if (dim == 2)
{
real_t x0 = x(0) + shift(0);
real_t x1 = x(1) + shift(1);
real_t r = sqrt(x0 * x0 + x1 * x1);
real_t beta = k * r;
double x0 = x(0) + shift(0);
double x1 = x(1) + shift(1);
double r = sqrt(x0 * x0 + x1 * x1);
double beta = k * r;
// Bessel functions
complex<real_t> Ho, Ho_r, Ho_rr;
Ho = jn(0, beta) + (complex<double>) zi * yn(0, beta);
Ho_r = -k * complex<real_t>(jn(1, beta) + (complex<double>) zi * yn(1, beta));
Ho_rr = -k * k * complex<real_t>(1.0 / beta *
(jn(1, beta) + (complex<double>) zi * yn(1, beta)) -
(jn(2, beta) + (complex<double>) zi * yn(2, beta)));
complex<double> Ho, Ho_r, Ho_rr;
Ho = jn(0, beta) + zi * yn(0, beta);
Ho_r = -k * (jn(1, beta) + zi * yn(1, beta));
Ho_rr = -k * k * (1.0 / beta *
(jn(1, beta) + zi * yn(1, beta)) -
(jn(2, beta) + zi * yn(2, beta)));
// First derivatives
real_t r_x = x0 / r;
real_t r_y = x1 / r;
real_t r_xy = -(r_x / r) * r_y;
real_t r_xx = (1.0 / r) * (1.0 - r_x * r_x);
double r_x = x0 / r;
double r_y = x1 / r;
double r_xy = -(r_x / r) * r_y;
double r_xx = (1.0 / r) * (1.0 - r_x * r_x);
complex<real_t> val, val_xx, val_xy;
val = real_t(0.25) * zi * Ho;
val_xx = real_t(0.25) * zi * (r_xx * Ho_r + r_x * r_x * Ho_rr);
val_xy = real_t(0.25) * zi * (r_xy * Ho_r + r_x * r_y * Ho_rr);
complex<double> val, val_xx, val_xy;
val = 0.25 * zi * Ho;
val_xx = 0.25 * zi * (r_xx * Ho_r + r_x * r_x * Ho_rr);
val_xy = 0.25 * zi * (r_xy * Ho_r + r_x * r_y * Ho_rr);
E[0] = zi / k * (k * k * val + val_xx);
E[1] = zi / k * val_xy;
}
else if (dim == 3)
{
real_t x0 = x(0) + shift(0);
real_t x1 = x(1) + shift(1);
real_t x2 = x(2) + shift(2);
real_t r = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
double x0 = x(0) + shift(0);
double x1 = x(1) + shift(1);
double x2 = x(2) + shift(2);
double r = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
real_t r_x = x0 / r;
real_t r_y = x1 / r;
real_t r_z = x2 / r;
real_t r_xx = (1.0 / r) * (1.0 - r_x * r_x);
real_t r_yx = -(r_y / r) * r_x;
real_t r_zx = -(r_z / r) * r_x;
double r_x = x0 / r;
double r_y = x1 / r;
double r_z = x2 / r;
double r_xx = (1.0 / r) * (1.0 - r_x * r_x);
double r_yx = -(r_y / r) * r_x;
double r_zx = -(r_z / r) * r_x;
complex<real_t> val, val_r, val_rr;
complex<double> val, val_r, val_rr;
val = exp(zi * k * r) / r;
val_r = val / r * (zi * k * r - real_t(1));
val_r = val / r * (zi * k * r - 1.0);
val_rr = val / (r * r) * (-k * k * r * r
- real_t(2) * zi * k * r + real_t(2));
- 2.0 * zi * k * r + 2.0);
complex<real_t> val_xx, val_yx, val_zx;
complex<double> val_xx, val_yx, val_zx;
val_xx = val_rr * r_x * r_x + val_r * r_xx;
val_yx = val_rr * r_x * r_y + val_r * r_yx;
val_zx = val_rr * r_x * r_z + val_r * r_zx;
complex<real_t> alpha = zi * k / real_t(4) / (real_t) M_PI / k / k;
complex<double> alpha = zi * k / 4.0 / M_PI / k / k;
E[0] = alpha * (k * k * val + val_xx);
E[1] = alpha * val_yx;
E[2] = alpha * val_zx;
@@ -818,12 +793,12 @@ void maxwell_solution(const Vector &x, vector<complex<real_t>> &E)
// T_10 mode
if (dim == 3)
{
real_t k10 = sqrt(k * k - M_PI * M_PI);
E[1] = -zi * k / (real_t) M_PI * sin((real_t) M_PI*x(2))*exp(zi * k10 * x(0));
double k10 = sqrt(k * k - M_PI * M_PI);
E[1] = -zi * k / M_PI * sin(M_PI*x(2))*exp(zi * k10 * x(0));
}
else if (dim == 2)
{
E[1] = -zi * k / (real_t) M_PI * exp(zi * k * x(0));
E[1] = -zi * k / M_PI * exp(zi * k * x(0));
}
break;
}
@@ -834,7 +809,7 @@ void maxwell_solution(const Vector &x, vector<complex<real_t>> &E)
void E_exact_Re(const Vector &x, Vector &E)
{
vector<complex<real_t>> Eval(E.Size());
vector<complex<double>> Eval(E.Size());
maxwell_solution(x, Eval);
for (int i = 0; i < dim; ++i)
{
@@ -844,7 +819,7 @@ void E_exact_Re(const Vector &x, Vector &E)
void E_exact_Im(const Vector &x, Vector &E)
{
vector<complex<real_t>> Eval(E.Size());
vector<complex<double>> Eval(E.Size());
maxwell_solution(x, Eval);
for (int i = 0; i < dim; ++i)
{
@@ -869,7 +844,7 @@ void E_bdr_data_Re(const Vector &x, Vector &E)
}
if (!in_pml)
{
vector<complex<real_t>> Eval(E.Size());
vector<complex<double>> Eval(E.Size());
maxwell_solution(x, Eval);
for (int i = 0; i < dim; ++i)
{
@@ -896,7 +871,7 @@ void E_bdr_data_Im(const Vector &x, Vector &E)
}
if (!in_pml)
{
vector<complex<real_t>> Eval(E.Size());
vector<complex<double>> Eval(E.Size());
maxwell_solution(x, Eval);
for (int i = 0; i < dim; ++i)
{
@@ -907,8 +882,8 @@ void E_bdr_data_Im(const Vector &x, Vector &E)
void detJ_JT_J_inv_Re(const Vector &x, PML * pml, Vector & D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det(1.0, 0.0);
vector<complex<double>> dxs(dim);
complex<double> det(1.0, 0.0);
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -918,14 +893,14 @@ void detJ_JT_J_inv_Re(const Vector &x, PML * pml, Vector & D)
for (int i = 0; i < dim; ++i)
{
D(i) = (det / pow(dxs[i], real_t(2))).real();
D(i) = (det / pow(dxs[i], 2)).real();
}
}
void detJ_JT_J_inv_Im(const Vector &x, PML * pml, Vector & D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det = 1.0;
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -935,14 +910,14 @@ void detJ_JT_J_inv_Im(const Vector &x, PML * pml, Vector & D)
for (int i = 0; i < dim; ++i)
{
D(i) = (det / pow(dxs[i], real_t(2))).imag();
D(i) = (det / pow(dxs[i], 2)).imag();
}
}
void detJ_JT_J_inv_abs(const Vector &x, PML * pml, Vector & D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det = 1.0;
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -952,14 +927,14 @@ void detJ_JT_J_inv_abs(const Vector &x, PML * pml, Vector & D)
for (int i = 0; i < dim; ++i)
{
D(i) = abs(det / pow(dxs[i], real_t(2)));
D(i) = abs(det / pow(dxs[i], 2));
}
}
void detJ_inv_JT_J_Re(const Vector &x, PML * pml, Vector & D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det(1.0, 0.0);
vector<complex<double>> dxs(dim);
complex<double> det(1.0, 0.0);
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -970,21 +945,21 @@ void detJ_inv_JT_J_Re(const Vector &x, PML * pml, Vector & D)
// in the 2D case the coefficient is scalar 1/det(J)
if (dim == 2)
{
D = (real_t(1) / det).real();
D = (1.0 / det).real();
}
else
{
for (int i = 0; i < dim; ++i)
{
D(i) = (pow(dxs[i], real_t(2)) / det).real();
D(i) = (pow(dxs[i], 2) / det).real();
}
}
}
void detJ_inv_JT_J_Im(const Vector &x, PML * pml, Vector & D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det = 1.0;
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -994,21 +969,21 @@ void detJ_inv_JT_J_Im(const Vector &x, PML * pml, Vector & D)
if (dim == 2)
{
D = (real_t(1) / det).imag();
D = (1.0 / det).imag();
}
else
{
for (int i = 0; i < dim; ++i)
{
D(i) = (pow(dxs[i], real_t(2)) / det).imag();
D(i) = (pow(dxs[i], 2) / det).imag();
}
}
}
void detJ_inv_JT_J_abs(const Vector &x, PML * pml, Vector & D)
{
vector<complex<real_t>> dxs(dim);
complex<real_t> det = 1.0;
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i)
@@ -1018,18 +993,18 @@ void detJ_inv_JT_J_abs(const Vector &x, PML * pml, Vector & D)
if (dim == 2)
{
D = abs(real_t(1) / det);
D = abs(1.0 / det);
}
else
{
for (int i = 0; i < dim; ++i)
{
D(i) = abs(pow(dxs[i], real_t(2)) / det);
D(i) = abs(pow(dxs[i], 2) / det);
}
}
}
PML::PML(Mesh *mesh_, Array2D<real_t> length_)
PML::PML(Mesh *mesh_, Array2D<double> length_)
: mesh(mesh_), length(length_)
{
dim = mesh->Dimension();
@@ -1081,7 +1056,7 @@ void PML::SetAttributes(ParMesh *pmesh)
for (int iv = 0; iv < nrvert; ++iv)
{
int vert_idx = vertices[iv];
real_t *coords = pmesh->GetVertex(vert_idx);
double *coords = pmesh->GetVertex(vert_idx);
for (int comp = 0; comp < dim; ++comp)
{
if (coords[comp] > comp_dom_bdr(comp, 1) ||
@@ -1102,14 +1077,14 @@ void PML::SetAttributes(ParMesh *pmesh)
}
void PML::StretchFunction(const Vector &x,
vector<complex<real_t>> &dxs)
vector<complex<double>> &dxs)
{
complex<real_t> zi = complex<real_t>(0., 1.);
complex<double> zi = complex<double>(0., 1.);
real_t n = 2.0;
real_t c = 5.0;
real_t coeff;
real_t k = omega * sqrt(epsilon * mu);
double n = 2.0;
double c = 5.0;
double coeff;
double k = omega * sqrt(epsilon * mu);
// Stretch in each direction independently
for (int i = 0; i < dim; ++i)
@@ -1118,14 +1093,14 @@ void PML::StretchFunction(const Vector &x,
if (x(i) >= comp_domain_bdr(i, 1))
{
coeff = n * c / k / pow(length(i, 1), n);
dxs[i] = real_t(1) + zi * coeff *
abs(pow(x(i) - comp_domain_bdr(i, 1), n - real_t(1)));
dxs[i] = 1.0 + zi * coeff *
abs(pow(x(i) - comp_domain_bdr(i, 1), n - 1.0));
}
if (x(i) <= comp_domain_bdr(i, 0))
{
coeff = n * c / k / pow(length(i, 0), n);
dxs[i] = real_t(1) + zi * coeff *
abs(pow(x(i) - comp_domain_bdr(i, 0), n - real_t(1)));
dxs[i] = 1.0 + zi * coeff *
abs(pow(x(i) - comp_domain_bdr(i, 0), n - 1.0));
}
}
}
+32 -32
View File
@@ -63,7 +63,7 @@
using namespace std;
using namespace mfem;
static real_t a_ = 0.2;
static double a_ = 0.2;
// Normal to hole with boundary attribute 4
void n4Vec(const Vector &x, Vector &n) { n = x; n[0] -= 0.5; n /= -n.Norml2(); }
@@ -73,25 +73,25 @@ Mesh * GenerateSerialMesh(int ref);
// Compute the average value of alpha*n.Grad(sol) + beta*sol over the boundary
// attributes marked in bdr_marker. Also computes the L2 norm of
// alpha*n.Grad(sol) + beta*sol - gamma over the same boundary.
real_t IntegrateBC(const GridFunction &sol, const Array<int> &bdr_marker,
real_t alpha, real_t beta, real_t gamma,
real_t &error);
double IntegrateBC(const GridFunction &sol, const Array<int> &bdr_marker,
double alpha, double beta, double gamma,
double &error);
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
int ser_ref_levels = 2;
int order = 1;
real_t sigma = -1.0;
real_t kappa = -1.0;
double sigma = -1.0;
double kappa = -1.0;
bool h1 = true;
bool visualization = true;
real_t mat_val = 1.0;
real_t dbc_val = 0.0;
real_t nbc_val = 1.0;
real_t rbc_a_val = 1.0; // du/dn + a * u = b
real_t rbc_b_val = 1.0;
double mat_val = 1.0;
double dbc_val = 0.0;
double nbc_val = 1.0;
double rbc_a_val = 1.0; // du/dn + a * u = b
double rbc_b_val = 1.0;
OptionsParser args(argc, argv);
args.AddOption(&h1, "-h1", "--continuous", "-dg", "--discontinuous",
@@ -302,7 +302,7 @@ int main(int argc, char *argv[])
{
// Integrate the solution on the Dirichlet boundary and compare to the
// expected value.
real_t error, avg = IntegrateBC(u, dbc_bdr, 0.0, 1.0, dbc_val, error);
double error, avg = IntegrateBC(u, dbc_bdr, 0.0, 1.0, dbc_val, error);
bool hom_dbc = (dbc_val == 0.0);
error /= hom_dbc ? 1.0 : fabs(dbc_val);
@@ -314,7 +314,7 @@ int main(int argc, char *argv[])
{
// Integrate n.Grad(u) on the inhomogeneous Neumann boundary and compare
// to the expected value.
real_t error, avg = IntegrateBC(u, nbc_bdr, 1.0, 0.0, nbc_val, error);
double error, avg = IntegrateBC(u, nbc_bdr, 1.0, 0.0, nbc_val, error);
bool hom_nbc = (nbc_val == 0.0);
error /= hom_nbc ? 1.0 : fabs(nbc_val);
@@ -330,7 +330,7 @@ int main(int argc, char *argv[])
nbc0_bdr = 0;
nbc0_bdr[3] = 1;
real_t error, avg = IntegrateBC(u, nbc0_bdr, 1.0, 0.0, 0.0, error);
double error, avg = IntegrateBC(u, nbc0_bdr, 1.0, 0.0, 0.0, error);
bool hom_nbc = true;
mfem::out << "Average of n.Grad(u) on Gamma_nbc0:\t"
@@ -341,8 +341,8 @@ int main(int argc, char *argv[])
{
// Integrate n.Grad(u) + a * u on the Robin boundary and compare to the
// expected value.
real_t error;
real_t avg = IntegrateBC(u, rbc_bdr, 1.0, rbc_a_val, rbc_b_val, error);
double error;
double avg = IntegrateBC(u, rbc_bdr, 1.0, rbc_a_val, rbc_b_val, error);
bool hom_rbc = (rbc_b_val == 0.0);
error /= hom_rbc ? 1.0 : fabs(rbc_b_val);
@@ -383,22 +383,22 @@ int main(int argc, char *argv[])
return 0;
}
void quad_trans(real_t u, real_t v, real_t &x, real_t &y, bool log = false)
void quad_trans(double u, double v, double &x, double &y, bool log = false)
{
real_t a = a_; // Radius of disc
double a = a_; // Radius of disc
real_t d = 4.0 * a * (M_SQRT2 - 2.0 * a) * (1.0 - 2.0 * v);
double d = 4.0 * a * (M_SQRT2 - 2.0 * a) * (1.0 - 2.0 * v);
real_t v0 = (1.0 + M_SQRT2) * (M_SQRT2 * a - 2.0 * v) *
double v0 = (1.0 + M_SQRT2) * (M_SQRT2 * a - 2.0 * v) *
((4.0 - 3 * M_SQRT2) * a +
(8.0 * (M_SQRT2 - 1.0) * a - 2.0) * v) / d;
real_t r = 2.0 * ((M_SQRT2 - 1.0) * a * a * (1.0 - 4.0 *v) +
double r = 2.0 * ((M_SQRT2 - 1.0) * a * a * (1.0 - 4.0 *v) +
2.0 * (1.0 + M_SQRT2 *
(1.0 + 2.0 * (2.0 * a - M_SQRT2 - 1.0) * a)) * v * v
) / d;
real_t t = asin(v / r) * u / v;
double t = asin(v / r) * u / v;
if (log)
{
mfem::out << "u, v, r, v0, t "
@@ -411,7 +411,7 @@ void quad_trans(real_t u, real_t v, real_t &x, real_t &y, bool log = false)
void trans(const Vector &u, Vector &x)
{
real_t tol = 1e-4;
double tol = 1e-4;
if (u[1] > 0.5 - tol || u[1] < -0.5 + tol)
{
@@ -542,8 +542,8 @@ Mesh * GenerateSerialMesh(int ref)
vi[0] = o + 3; vi[1] = o + 4; mesh->AddBdrSegment(vi, 3 + i);
}
real_t d[2];
real_t a = a_ / M_SQRT2;
double d[2];
double a = a_ / M_SQRT2;
d[0] = -1.0; d[1] = -0.5; mesh->AddVertex(d);
d[0] = -1.0; d[1] = 0.0; mesh->AddVertex(d);
@@ -636,12 +636,12 @@ Mesh * GenerateSerialMesh(int ref)
return mesh;
}
real_t IntegrateBC(const GridFunction &x, const Array<int> &bdr,
real_t alpha, real_t beta, real_t gamma,
real_t &error)
double IntegrateBC(const GridFunction &x, const Array<int> &bdr,
double alpha, double beta, double gamma,
double &error)
{
real_t nrm = 0.0;
real_t avg = 0.0;
double nrm = 0.0;
double avg = 0.0;
error = 0.0;
const bool a_is_zero = alpha == 0.0;
@@ -683,8 +683,8 @@ real_t IntegrateBC(const GridFunction &x, const Array<int> &bdr,
IntegrationPoint eip;
FTr->Loc1.Transform(ip, eip);
FTr->Face->SetIntPoint(&ip);
real_t face_weight = FTr->Face->Weight();
real_t val = 0.0;
double face_weight = FTr->Face->Weight();
double val = 0.0;
if (!a_is_zero)
{
FTr->Elem1->SetIntPoint(&eip);
+37 -38
View File
@@ -63,7 +63,7 @@
using namespace std;
using namespace mfem;
static real_t a_ = 0.2;
static double a_ = 0.2;
// Normal to hole with boundary attribute 4
void n4Vec(const Vector &x, Vector &n) { n = x; n[0] -= 0.5; n /= -n.Norml2(); }
@@ -73,9 +73,9 @@ Mesh * GenerateSerialMesh(int ref);
// Compute the average value of alpha*n.Grad(sol) + beta*sol over the boundary
// attributes marked in bdr_marker. Also computes the L2 norm of
// alpha*n.Grad(sol) + beta*sol - gamma over the same boundary.
real_t IntegrateBC(const ParGridFunction &sol, const Array<int> &bdr_marker,
real_t alpha, real_t beta, real_t gamma,
real_t &error);
double IntegrateBC(const ParGridFunction &sol, const Array<int> &bdr_marker,
double alpha, double beta, double gamma,
double &error);
int main(int argc, char *argv[])
{
@@ -88,16 +88,16 @@ int main(int argc, char *argv[])
int ser_ref_levels = 2;
int par_ref_levels = 1;
int order = 1;
real_t sigma = -1.0;
real_t kappa = -1.0;
double sigma = -1.0;
double kappa = -1.0;
bool h1 = true;
bool visualization = true;
real_t mat_val = 1.0;
real_t dbc_val = 0.0;
real_t nbc_val = 1.0;
real_t rbc_a_val = 1.0; // du/dn + a * u = b
real_t rbc_b_val = 1.0;
double mat_val = 1.0;
double dbc_val = 0.0;
double nbc_val = 1.0;
double rbc_a_val = 1.0; // du/dn + a * u = b
double rbc_b_val = 1.0;
OptionsParser args(argc, argv);
args.AddOption(&h1, "-h1", "--continuous", "-dg", "--discontinuous",
@@ -322,7 +322,7 @@ int main(int argc, char *argv[])
{
// Integrate the solution on the Dirichlet boundary and compare to the
// expected value.
real_t error, avg = IntegrateBC(u, dbc_bdr, 0.0, 1.0, dbc_val, error);
double error, avg = IntegrateBC(u, dbc_bdr, 0.0, 1.0, dbc_val, error);
bool hom_dbc = (dbc_val == 0.0);
error /= hom_dbc ? 1.0 : fabs(dbc_val);
@@ -334,7 +334,7 @@ int main(int argc, char *argv[])
{
// Integrate n.Grad(u) on the inhomogeneous Neumann boundary and compare
// to the expected value.
real_t error, avg = IntegrateBC(u, nbc_bdr, 1.0, 0.0, nbc_val, error);
double error, avg = IntegrateBC(u, nbc_bdr, 1.0, 0.0, nbc_val, error);
bool hom_nbc = (nbc_val == 0.0);
error /= hom_nbc ? 1.0 : fabs(nbc_val);
@@ -350,7 +350,7 @@ int main(int argc, char *argv[])
nbc0_bdr = 0;
nbc0_bdr[3] = 1;
real_t error, avg = IntegrateBC(u, nbc0_bdr, 1.0, 0.0, 0.0, error);
double error, avg = IntegrateBC(u, nbc0_bdr, 1.0, 0.0, 0.0, error);
bool hom_nbc = true;
mfem::out << "Average of n.Grad(u) on Gamma_nbc0:\t"
@@ -361,7 +361,7 @@ int main(int argc, char *argv[])
{
// Integrate n.Grad(u) + a * u on the Robin boundary and compare to the
// expected value.
real_t error, avg = IntegrateBC(u, rbc_bdr, 1.0, rbc_a_val, rbc_b_val,
double error, avg = IntegrateBC(u, rbc_bdr, 1.0, rbc_a_val, rbc_b_val,
error);
bool hom_rbc = (rbc_b_val == 0.0);
@@ -409,22 +409,22 @@ int main(int argc, char *argv[])
return 0;
}
void quad_trans(real_t u, real_t v, real_t &x, real_t &y, bool log = false)
void quad_trans(double u, double v, double &x, double &y, bool log = false)
{
real_t a = a_; // Radius of disc
double a = a_; // Radius of disc
real_t d = 4.0 * a * (M_SQRT2 - 2.0 * a) * (1.0 - 2.0 * v);
double d = 4.0 * a * (M_SQRT2 - 2.0 * a) * (1.0 - 2.0 * v);
real_t v0 = (1.0 + M_SQRT2) * (M_SQRT2 * a - 2.0 * v) *
double v0 = (1.0 + M_SQRT2) * (M_SQRT2 * a - 2.0 * v) *
((4.0 - 3 * M_SQRT2) * a +
(8.0 * (M_SQRT2 - 1.0) * a - 2.0) * v) / d;
real_t r = 2.0 * ((M_SQRT2 - 1.0) * a * a * (1.0 - 4.0 *v) +
double r = 2.0 * ((M_SQRT2 - 1.0) * a * a * (1.0 - 4.0 *v) +
2.0 * (1.0 + M_SQRT2 *
(1.0 + 2.0 * (2.0 * a - M_SQRT2 - 1.0) * a)) * v * v
) / d;
real_t t = asin(v / r) * u / v;
double t = asin(v / r) * u / v;
if (log)
{
mfem::out << "u, v, r, v0, t "
@@ -437,7 +437,7 @@ void quad_trans(real_t u, real_t v, real_t &x, real_t &y, bool log = false)
void trans(const Vector &u, Vector &x)
{
real_t tol = 1e-4;
double tol = 1e-4;
if (u[1] > 0.5 - tol || u[1] < -0.5 + tol)
{
@@ -568,8 +568,8 @@ Mesh * GenerateSerialMesh(int ref)
vi[0] = o + 3; vi[1] = o + 4; mesh->AddBdrSegment(vi, 3 + i);
}
real_t d[2];
real_t a = a_ / M_SQRT2;
double d[2];
double a = a_ / M_SQRT2;
d[0] = -1.0; d[1] = -0.5; mesh->AddVertex(d);
d[0] = -1.0; d[1] = 0.0; mesh->AddVertex(d);
@@ -662,14 +662,14 @@ Mesh * GenerateSerialMesh(int ref)
return mesh;
}
real_t IntegrateBC(const ParGridFunction &x, const Array<int> &bdr,
real_t alpha, real_t beta, real_t gamma,
real_t &glb_err)
double IntegrateBC(const ParGridFunction &x, const Array<int> &bdr,
double alpha, double beta, double gamma,
double &glb_err)
{
real_t loc_vals[3];
real_t &nrm = loc_vals[0];
real_t &avg = loc_vals[1];
real_t &error = loc_vals[2];
double loc_vals[3];
double &nrm = loc_vals[0];
double &avg = loc_vals[1];
double &error = loc_vals[2];
nrm = 0.0;
avg = 0.0;
@@ -714,8 +714,8 @@ real_t IntegrateBC(const ParGridFunction &x, const Array<int> &bdr,
IntegrationPoint eip;
FTr->Loc1.Transform(ip, eip);
FTr->Face->SetIntPoint(&ip);
real_t face_weight = FTr->Face->Weight();
real_t val = 0.0;
double face_weight = FTr->Face->Weight();
double val = 0.0;
if (!a_is_zero)
{
FTr->Elem1->SetIntPoint(&eip);
@@ -741,12 +741,11 @@ real_t IntegrateBC(const ParGridFunction &x, const Array<int> &bdr,
}
}
real_t glb_vals[3];
MPI_Allreduce(loc_vals, glb_vals, 3, MPITypeMap<real_t>::mpi_type,
MPI_SUM, fes.GetComm());
double glb_vals[3];
MPI_Allreduce(loc_vals, glb_vals, 3, MPI_DOUBLE, MPI_SUM, fes.GetComm());
real_t glb_nrm = glb_vals[0];
real_t glb_avg = glb_vals[1];
double glb_nrm = glb_vals[0];
double glb_avg = glb_vals[1];
glb_err = glb_vals[2];
// Normalize by the length of the boundary
+3 -3
View File
@@ -35,7 +35,7 @@ using namespace mfem;
// Return a mesh with a single element with vertices (0, 0), (1, 0), (1, 1),
// (offset, 1) to demonstrate boundary conditions on a surface that is not
// axis-aligned.
Mesh * build_trapezoid_mesh(real_t offset)
Mesh * build_trapezoid_mesh(double offset)
{
MFEM_VERIFY(offset < 0.9, "offset is too large!");
@@ -45,7 +45,7 @@ Mesh * build_trapezoid_mesh(real_t offset)
Mesh * mesh = new Mesh(dimension, nvt, 1, nbe);
// vertices
real_t vc[dimension];
double vc[dimension];
vc[0] = 0.0; vc[1] = 0.0;
mesh->AddVertex(vc);
vc[0] = 1.0; vc[1] = 0.0;
@@ -81,7 +81,7 @@ int main(int argc, char *argv[])
// 1. Parse command-line options.
int order = 1;
bool visualization = 1;
real_t offset = 0.3;
double offset = 0.3;
bool visit = false;
OptionsParser args(argc, argv);
+4 -4
View File
@@ -38,7 +38,7 @@ using namespace mfem;
// Return a mesh with a single element with vertices (0, 0), (1, 0), (1, 1),
// (offset, 1) to demonstrate boundary conditions on a surface that is not
// axis-aligned.
Mesh * build_trapezoid_mesh(real_t offset)
Mesh * build_trapezoid_mesh(double offset)
{
MFEM_VERIFY(offset < 0.9, "offset is too large!");
@@ -48,7 +48,7 @@ Mesh * build_trapezoid_mesh(real_t offset)
Mesh * mesh = new Mesh(dimension, nvt, 1, nbe);
// vertices
real_t vc[dimension];
double vc[dimension];
vc[0] = 0.0; vc[1] = 0.0;
mesh->AddVertex(vc);
vc[0] = 1.0; vc[1] = 0.0;
@@ -97,9 +97,9 @@ int main(int argc, char *argv[])
int order = 1;
bool visualization = 1;
bool reorder_space = false;
real_t offset = 0.3;
double offset = 0.3;
bool visit = false;
real_t penalty = 0.0;
double penalty = 0.0;
OptionsParser args(argc, argv);
args.AddOption(&order, "-o", "--order",
+6 -6
View File
@@ -34,7 +34,7 @@ void trans(const Vector &x, Vector &r);
void sigmaFunc(const Vector &x, DenseMatrix &s);
real_t uExact(const Vector &x)
double uExact(const Vector &x)
{
return (0.25 * (2.0 + x[0]) - x[2]) * (x[2] + 0.25 * (2.0 + x[0]));
}
@@ -167,7 +167,7 @@ int main(int argc, char *argv[])
// 13. Compute error in the solution and its flux
FunctionCoefficient uCoef(uExact);
real_t error = x.ComputeL2Error(uCoef);
double error = x.ComputeL2Error(uCoef);
cout << "|u - u_h|_2 = " << error << endl;
@@ -176,7 +176,7 @@ int main(int argc, char *argv[])
x.ComputeFlux(*integ, flux); flux *= -1.0;
VectorFunctionCoefficient fluxCoef(3, fluxExact);
real_t flux_err = flux.ComputeL2Error(fluxCoef);
double flux_err = flux.ComputeL2Error(fluxCoef);
cout << "|f - f_h|_2 = " << flux_err << endl;
@@ -304,8 +304,8 @@ void trans(const Vector &x, Vector &r)
{
r.SetSize(3);
real_t tol = 1e-6;
real_t theta = 0.0;
double tol = 1e-6;
double theta = 0.0;
if (fabs(x[1] + 1.0) < tol)
{
theta = 0.25 * M_PI * (x[0] - 2.0);
@@ -337,7 +337,7 @@ void trans(const Vector &x, Vector &r)
void sigmaFunc(const Vector &x, DenseMatrix &s)
{
s.SetSize(3);
real_t a = 17.0 - 2.0 * x[0] * (1.0 + x[0]);
double a = 17.0 - 2.0 * x[0] * (1.0 + x[0]);
s(0,0) = 0.5 + x[0] * x[0] * (8.0 / a - 0.5);
s(0,1) = x[0] * x[1] * (8.0 / a - 0.5);
s(0,2) = 0.0;
+6 -6
View File
@@ -34,7 +34,7 @@ void trans(const Vector &x, Vector &r);
void sigmaFunc(const Vector &x, DenseMatrix &s);
real_t uExact(const Vector &x)
double uExact(const Vector &x)
{
return (0.25 * (2.0 + x[0]) - x[2]) * (x[2] + 0.25 * (2.0 + x[0]));
}
@@ -201,7 +201,7 @@ int main(int argc, char *argv[])
// 15. Compute error in the solution and its flux
FunctionCoefficient uCoef(uExact);
real_t error = x.ComputeL2Error(uCoef);
double error = x.ComputeL2Error(uCoef);
if (myid == 0) { cout << "|u - u_h|_2 = " << error << endl; }
@@ -210,7 +210,7 @@ int main(int argc, char *argv[])
x.ComputeFlux(*integ, flux); flux *= -1.0;
VectorFunctionCoefficient fluxCoef(3, fluxExact);
real_t flux_err = flux.ComputeL2Error(fluxCoef);
double flux_err = flux.ComputeL2Error(fluxCoef);
if (myid == 0) { cout << "|f - f_h|_2 = " << flux_err << endl; }
@@ -349,8 +349,8 @@ void trans(const Vector &x, Vector &r)
{
r.SetSize(3);
real_t tol = 1e-6;
real_t theta = 0.0;
double tol = 1e-6;
double theta = 0.0;
if (fabs(x[1] + 1.0) < tol)
{
theta = 0.25 * M_PI * (x[0] - 2.0);
@@ -382,7 +382,7 @@ void trans(const Vector &x, Vector &r)
void sigmaFunc(const Vector &x, DenseMatrix &s)
{
s.SetSize(3);
real_t a = 17.0 - 2.0 * x[0] * (1.0 + x[0]);
double a = 17.0 - 2.0 * x[0] * (1.0 + x[0]);
s(0,0) = 0.5 + x[0] * x[0] * (8.0 / a - 0.5);
s(0,1) = x[0] * x[1] * (8.0 / a - 0.5);
s(0,2) = 0.0;
+1 -10
View File
@@ -53,7 +53,7 @@ using namespace mfem;
// Exact solution, E, and r.h.s., f. See below for implementation.
void E_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
real_t freq = 1.0, kappa;
double freq = 1.0, kappa;
int dim;
int main(int argc, char *argv[])
@@ -63,7 +63,6 @@ int main(int argc, char *argv[])
int order = 1;
bool static_cond = false;
bool pa = false;
bool nc = false;
const char *device_config = "cpu";
bool visualization = 1;
@@ -78,9 +77,6 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&nc, "-nc", "--non-conforming", "-c",
"--conforming",
"Mark the mesh as nonconforming before partitioning.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
@@ -106,11 +102,6 @@ int main(int argc, char *argv[])
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
if (nc)
{
// Can set to false to use conformal refinement for simplices.
mesh->EnsureNCMesh(true);
}
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
+14 -14
View File
@@ -42,9 +42,9 @@ using namespace std;
using namespace mfem;
// Piecewise-affine function which is sometimes mesh-conforming
real_t affine_function(const Vector &p)
double affine_function(const Vector &p)
{
real_t x = p(0), y = p(1);
double x = p(0), y = p(1);
if (x < 0.0)
{
return 1.0 + x + y;
@@ -56,7 +56,7 @@ real_t affine_function(const Vector &p)
}
// Piecewise-constant function which is never mesh-conforming
real_t jump_function(const Vector &p)
double jump_function(const Vector &p)
{
if (p.Normlp(2.0) > 0.4 && p.Normlp(2.0) < 0.6)
{
@@ -70,17 +70,17 @@ real_t jump_function(const Vector &p)
// Singular function derived from the Laplacian of the "steep wavefront" problem
// in [2].
real_t singular_function(const Vector &p)
double singular_function(const Vector &p)
{
real_t x = p(0), y = p(1);
real_t alpha = 1000.0;
real_t xc = 0.75, yc = 0.5;
real_t r0 = 0.7;
real_t r = sqrt(pow(x - xc,2.0) + pow(y - yc,2.0));
real_t num = - ( alpha - pow(alpha,3) * (pow(r,2) - pow(r0,2)) );
real_t denom = pow(r * ( pow(alpha,2) * pow(r0,2) + pow(alpha,2) * pow(r,2) \
double x = p(0), y = p(1);
double alpha = 1000.0;
double xc = 0.75, yc = 0.5;
double r0 = 0.7;
double r = sqrt(pow(x - xc,2.0) + pow(y - yc,2.0));
double num = - ( alpha - pow(alpha,3) * (pow(r,2) - pow(r0,2)) );
double denom = pow(r * ( pow(alpha,2) * pow(r0,2) + pow(alpha,2) * pow(r,2) \
- 2 * pow(alpha,2) * r0 * r + 1.0 ),2);
denom = std::max(denom, (real_t) 1.0e-8);
denom = max(denom,1e-8);
return num / denom;
}
@@ -91,9 +91,9 @@ int main(int argc, char *argv[])
int order = 1;
int nc_limit = 1;
int max_elems = 100*1000;
real_t double_max_elems = real_t(max_elems);
double double_max_elems = double(max_elems);
bool visualization = true;
real_t osc_threshold = 1e-3;
double osc_threshold = 1e-3;
int enriched_order = 5;
OptionsParser args(argc, argv);
+15 -15
View File
@@ -42,9 +42,9 @@ using namespace std;
using namespace mfem;
// Piecewise-affine function which is sometimes mesh-conforming
real_t affine_function(const Vector &p)
double affine_function(const Vector &p)
{
real_t x = p(0), y = p(1);
double x = p(0), y = p(1);
if (x < 0.0)
{
return 1.0 + x + y;
@@ -56,7 +56,7 @@ real_t affine_function(const Vector &p)
}
// Piecewise-constant function which is never mesh-conforming
real_t jump_function(const Vector &p)
double jump_function(const Vector &p)
{
if (p.Normlp(2.0) > 0.4 && p.Normlp(2.0) < 0.6)
{
@@ -70,17 +70,17 @@ real_t jump_function(const Vector &p)
// Singular function derived from the Laplacian of the "steep wavefront" problem
// in [2].
real_t singular_function(const Vector &p)
double singular_function(const Vector &p)
{
real_t x = p(0), y = p(1);
real_t alpha = 1000.0;
real_t xc = 0.75, yc = 0.5;
real_t r0 = 0.7;
real_t r = sqrt(pow(x - xc,2.0) + pow(y - yc,2.0));
real_t num = - ( alpha - pow(alpha,3) * (pow(r,2) - pow(r0,2)) );
real_t denom = pow(r * ( pow(alpha,2) * pow(r0,2) + pow(alpha,2) * pow(r,2) \
double x = p(0), y = p(1);
double alpha = 1000.0;
double xc = 0.75, yc = 0.5;
double r0 = 0.7;
double r = sqrt(pow(x - xc,2.0) + pow(y - yc,2.0));
double num = - ( alpha - pow(alpha,3) * (pow(r,2) - pow(r0,2)) );
double denom = pow(r * ( pow(alpha,2) * pow(r0,2) + pow(alpha,2) * pow(r,2) \
- 2 * pow(alpha,2) * r0 * r + 1.0 ),2);
denom = std::max(denom, (real_t) 1.0e-8);
denom = max(denom,1e-8);
return num / denom;
}
@@ -97,10 +97,10 @@ int main(int argc, char *argv[])
int order = 1;
int nc_limit = 1;
int max_elems = 1e5;
real_t double_max_elems = real_t(max_elems);
double double_max_elems = double(max_elems);
bool visualization = true;
bool nc_simplices = true;
real_t osc_threshold = 1e-3;
double osc_threshold = 1e-3;
int enriched_order = 5;
OptionsParser args(argc, argv);
@@ -199,7 +199,7 @@ int main(int argc, char *argv[])
coeffrefiner.PreprocessMesh(pmesh);
int globalNE = pmesh.GetGlobalNE();
real_t osc = coeffrefiner.GetOsc();
double osc = coeffrefiner.GetOsc();
if (myid == 0)
{
mfem::out << "\n";
+28 -28
View File
@@ -39,7 +39,7 @@ using namespace mfem;
void E_exact(const Vector &, Vector &);
void CurlE_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
real_t freq = 1.0, kappa;
double freq = 1.0, kappa;
int dim;
int main(int argc, char *argv[])
@@ -177,7 +177,7 @@ int main(int argc, char *argv[])
// 13. Compute and print the H(Curl) norm of the error.
{
real_t error = sol.ComputeHCurlError(&E, &CurlE);
double error = sol.ComputeHCurlError(&E, &CurlE);
cout << "\n|| E_h - E ||_{H(Curl)} = " << error << '\n' << endl;
}
@@ -376,8 +376,8 @@ void CurlE_exact(const Vector &x, Vector &dE)
{
if (dim == 1)
{
real_t c4 = cos(kappa * x(0) + 0.4 * M_PI);
real_t c9 = cos(kappa * x(0) + 0.9 * M_PI);
double c4 = cos(kappa * x(0) + 0.4 * M_PI);
double c9 = cos(kappa * x(0) + 0.9 * M_PI);
dE(0) = 0.0;
dE(1) = -1.3 * c9;
@@ -386,9 +386,9 @@ void CurlE_exact(const Vector &x, Vector &dE)
}
else if (dim == 2)
{
real_t c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
double c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
dE(0) = 1.3 * c9;
dE(1) = -1.3 * c9;
@@ -397,13 +397,13 @@ void CurlE_exact(const Vector &x, Vector &dE)
}
else
{
real_t s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
real_t sk = sin(kappa * x(2));
real_t ck = cos(kappa * x(2));
double s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
double sk = sin(kappa * x(2));
double ck = cos(kappa * x(2));
dE(0) = 1.2 * s4 * sk + 1.3 * M_SQRT1_2 * c9 * ck;
dE(1) = -1.1 * s0 * sk - 1.3 * M_SQRT1_2 * c9 * ck;
@@ -416,9 +416,9 @@ void f_exact(const Vector &x, Vector &f)
{
if (dim == 1)
{
real_t s0 = sin(kappa * x(0) + 0.0 * M_PI);
real_t s4 = sin(kappa * x(0) + 0.4 * M_PI);
real_t s9 = sin(kappa * x(0) + 0.9 * M_PI);
double s0 = sin(kappa * x(0) + 0.0 * M_PI);
double s4 = sin(kappa * x(0) + 0.4 * M_PI);
double s9 = sin(kappa * x(0) + 0.9 * M_PI);
f(0) = 2.2 * s0 + 1.2 * M_SQRT1_2 * s4;
f(1) = 1.2 * (2.0 + kappa * kappa) * s4 +
@@ -427,9 +427,9 @@ void f_exact(const Vector &x, Vector &f)
}
else if (dim == 2)
{
real_t s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t s9 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
double s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double s9 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
f(0) = 0.55 * (4.0 + kappa * kappa) * s0 +
0.6 * (M_SQRT2 - kappa * kappa) * s4;
@@ -440,14 +440,14 @@ void f_exact(const Vector &x, Vector &f)
}
else
{
real_t s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t s9 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
real_t c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
real_t sk = sin(kappa * x(2));
real_t ck = cos(kappa * x(2));
double s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double s9 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
double c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
double sk = sin(kappa * x(2));
double ck = cos(kappa * x(2));
f(0) = 0.55 * (4.0 + 3.0 * kappa * kappa) * s0 * ck +
0.6 * (M_SQRT2 - kappa * kappa) * s4 * ck -
+28 -28
View File
@@ -39,7 +39,7 @@ using namespace mfem;
void E_exact(const Vector &, Vector &);
void CurlE_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
real_t freq = 1.0, kappa;
double freq = 1.0, kappa;
int dim;
int main(int argc, char *argv[])
@@ -224,7 +224,7 @@ int main(int argc, char *argv[])
// 14. Compute and print the H(Curl) norm of the error.
{
real_t error = sol.ComputeHCurlError(&E, &CurlE);
double error = sol.ComputeHCurlError(&E, &CurlE);
if (Mpi::Root())
{
cout << "\n|| E_h - E ||_{H(Curl)} = " << error << '\n' << endl;
@@ -442,8 +442,8 @@ void CurlE_exact(const Vector &x, Vector &dE)
{
if (dim == 1)
{
real_t c4 = cos(kappa * x(0) + 0.4 * M_PI);
real_t c9 = cos(kappa * x(0) + 0.9 * M_PI);
double c4 = cos(kappa * x(0) + 0.4 * M_PI);
double c9 = cos(kappa * x(0) + 0.9 * M_PI);
dE(0) = 0.0;
dE(1) = -1.3 * c9;
@@ -452,9 +452,9 @@ void CurlE_exact(const Vector &x, Vector &dE)
}
else if (dim == 2)
{
real_t c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
double c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
dE(0) = 1.3 * c9;
dE(1) = -1.3 * c9;
@@ -463,13 +463,13 @@ void CurlE_exact(const Vector &x, Vector &dE)
}
else
{
real_t s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
real_t sk = sin(kappa * x(2));
real_t ck = cos(kappa * x(2));
double s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
double sk = sin(kappa * x(2));
double ck = cos(kappa * x(2));
dE(0) = 1.2 * s4 * sk + 1.3 * M_SQRT1_2 * c9 * ck;
dE(1) = -1.1 * s0 * sk - 1.3 * M_SQRT1_2 * c9 * ck;
@@ -482,9 +482,9 @@ void f_exact(const Vector &x, Vector &f)
{
if (dim == 1)
{
real_t s0 = sin(kappa * x(0) + 0.0 * M_PI);
real_t s4 = sin(kappa * x(0) + 0.4 * M_PI);
real_t s9 = sin(kappa * x(0) + 0.9 * M_PI);
double s0 = sin(kappa * x(0) + 0.0 * M_PI);
double s4 = sin(kappa * x(0) + 0.4 * M_PI);
double s9 = sin(kappa * x(0) + 0.9 * M_PI);
f(0) = 2.2 * s0 + 1.2 * M_SQRT1_2 * s4;
f(1) = 1.2 * (2.0 + kappa * kappa) * s4 +
@@ -493,9 +493,9 @@ void f_exact(const Vector &x, Vector &f)
}
else if (dim == 2)
{
real_t s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t s9 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
double s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double s9 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
f(0) = 0.55 * (4.0 + kappa * kappa) * s0 +
0.6 * (M_SQRT2 - kappa * kappa) * s4;
@@ -506,14 +506,14 @@ void f_exact(const Vector &x, Vector &f)
}
else
{
real_t s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
real_t s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
real_t s9 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
real_t c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
real_t sk = sin(kappa * x(2));
real_t ck = cos(kappa * x(2));
double s0 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double c0 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.0 * M_PI);
double s4 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double c4 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.4 * M_PI);
double s9 = sin(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
double c9 = cos(kappa * M_SQRT1_2 * (x(0) + x(1)) + 0.9 * M_PI);
double sk = sin(kappa * x(2));
double ck = cos(kappa * x(2));
f(0) = 0.55 * (4.0 + 3.0 * kappa * kappa) * s0 * ck +
0.6 * (M_SQRT2 - kappa * kappa) * s4 * ck -
+18 -18
View File
@@ -35,8 +35,8 @@
using namespace std;
using namespace mfem;
real_t GetVectorMax(int vdim, const ParGridFunction &x);
real_t GetScalarMax(const ParGridFunction &x);
double GetVectorMax(int vdim, const ParGridFunction &x);
double GetScalarMax(const ParGridFunction &x);
int main(int argc, char *argv[])
{
@@ -140,7 +140,7 @@ int main(int argc, char *argv[])
// extract the corresponding parallel matrices A and M.
HypreParMatrix *A = NULL;
HypreParMatrix *M = NULL;
real_t shift = 0.0;
double shift = 0.0;
{
DenseMatrix epsilonMat(3);
epsilonMat(0,0) = 2.0; epsilonMat(1,1) = 2.0; epsilonMat(2,2) = 2.0;
@@ -178,7 +178,7 @@ int main(int argc, char *argv[])
m.AddDomainIntegrator(new VectorFEMassIntegrator(epsilon));
m.Assemble();
// shift the eigenvalue corresponding to eliminated dofs to a large value
m.EliminateEssentialBCDiag(ess_bdr, numeric_limits<real_t>::min());
m.EliminateEssentialBCDiag(ess_bdr, numeric_limits<double>::min());
m.Finalize();
A = a.ParallelAssemble();
@@ -204,7 +204,7 @@ int main(int argc, char *argv[])
// 9. Compute the eigenmodes and extract the array of eigenvalues. Define
// parallel grid functions to represent each of the eigenmodes returned by
// the solver and their derivatives.
Array<real_t> eigenvalues;
Array<double> eigenvalues;
ame->Solve();
ame->GetEigenvalues(eigenvalues);
ParGridFunction x(&fespace_nd);
@@ -308,10 +308,10 @@ int main(int argc, char *argv[])
yComp.ProjectCoefficient(yCoef);
zComp.ProjectCoefficient(zCoef);
real_t max_x = GetScalarMax(xComp);
real_t max_y = GetScalarMax(yComp);
real_t max_z = GetScalarMax(zComp);
real_t max_r = std::max(max_x, std::max(max_y, max_z));
double max_x = GetScalarMax(xComp);
double max_y = GetScalarMax(yComp);
double max_z = GetScalarMax(zComp);
double max_r = std::max(max_x, std::max(max_y, max_z));
ostringstream x_cmd;
x_cmd << " window_title 'Eigenmode " << i+1 << '/' << nev
@@ -368,7 +368,7 @@ int main(int argc, char *argv[])
dyComp.ProjectCoefficient(dyCoef);
dzComp.ProjectCoefficient(dzCoef);
real_t min_d = max_r / (bbMax[0] - bbMin[0]);
double min_d = max_r / (bbMax[0] - bbMin[0]);
max_y = GetScalarMax(dyComp);
max_z = GetScalarMax(dzComp);
@@ -480,9 +480,9 @@ int main(int argc, char *argv[])
xyComp.ProjectCoefficient(xyCoef);
zComp.ProjectCoefficient(zCoef);
real_t max_v = GetVectorMax(2, xyComp);
real_t max_s = GetScalarMax(zComp);
real_t max_r = std::max(max_v, max_s);
double max_v = GetVectorMax(2, xyComp);
double max_s = GetScalarMax(zComp);
double max_r = std::max(max_v, max_s);
ostringstream xy_cmd;
xy_cmd << " window_title 'Eigenmode " << i+1 << '/' << nev
@@ -523,7 +523,7 @@ int main(int argc, char *argv[])
dxyComp.ProjectCoefficient(dxyCoef);
dzComp.ProjectCoefficient(dzCoef);
real_t min_d = max_r / std::min(bbMax[0] - bbMin[0],
double min_d = max_r / std::min(bbMax[0] - bbMin[0],
bbMax[1] - bbMin[1]);
max_v = GetVectorMax(2, dxyComp);
@@ -649,17 +649,17 @@ int main(int argc, char *argv[])
return 0;
}
real_t GetVectorMax(int vdim, const ParGridFunction &x)
double GetVectorMax(int vdim, const ParGridFunction &x)
{
Vector zeroVec(vdim); zeroVec = 0.0;
VectorConstantCoefficient zero(zeroVec);
real_t nrm = x.ComputeMaxError(zero);
double nrm = x.ComputeMaxError(zero);
return nrm;
}
real_t GetScalarMax(const ParGridFunction &x)
double GetScalarMax(const ParGridFunction &x)
{
ConstantCoefficient zero(0.0);
real_t nrm = x.ComputeMaxError(zero);
double nrm = x.ComputeMaxError(zero);
return nrm;
}
+7 -11
View File
@@ -90,7 +90,7 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/star.mesh";
int order = 1;
int num_refs = 3;
real_t alpha = 0.5;
double alpha = 0.5;
bool visualization = true;
bool verification = false;
@@ -118,17 +118,13 @@ int main(int argc, char *argv[])
}
args.PrintOptions(cout);
#ifdef MFEM_USE_SINGLE
MFEM_ABORT("This example is not supported in single precision.");
#endif
Array<real_t> coeffs, poles;
Array<double> coeffs, poles;
int progress_steps = 1;
// 2. Compute the rational expansion coefficients that define the
// integer-order PDEs.
const int power_of_laplace = (int)floor(alpha);
real_t exponent_to_approximate = alpha - power_of_laplace;
double exponent_to_approximate = alpha - power_of_laplace;
bool integer_order = false;
// Check if alpha is an integer or not.
if (abs(exponent_to_approximate) > 1e-12)
@@ -139,7 +135,7 @@ int main(int argc, char *argv[])
ComputePartialFractionApproximation(exponent_to_approximate, coeffs,
poles);
// If the example is built without LAPACK, the exponent_to_approximate
// If the example is build without LAPACK, the exponent_to_approximate
// might be modified by the function call above.
alpha = exponent_to_approximate + power_of_laplace;
}
@@ -177,7 +173,7 @@ int main(int argc, char *argv[])
// 7. Define diffusion coefficient, load, and solution GridFunction.
auto func = [&alpha](const Vector &x)
{
real_t val = 1.0;
double val = 1.0;
for (int i=0; i<x.Size(); i++)
{
val *= sin(M_PI*x(i));
@@ -368,7 +364,7 @@ int main(int argc, char *argv[])
{
auto solution = [] (const Vector &x)
{
real_t val = 1.0;
double val = 1.0;
for (int i=0; i<x.Size(); i++)
{
val *= sin(M_PI*x(i));
@@ -376,7 +372,7 @@ int main(int argc, char *argv[])
return val;
};
FunctionCoefficient sol(solution);
real_t l2_error = u.ComputeL2Error(sol);
double l2_error = u.ComputeL2Error(sol);
string analytic_solution,expected_mesh;
switch (dim)
+28 -28
View File
@@ -50,8 +50,8 @@ using namespace mfem;
See pg. A1501 of Nakatsukasa et al. [1]. */
void RationalApproximation_AAA(const Vector &val, const Vector &pt,
Array<real_t> &z, Array<real_t> &f, Vector &w,
real_t tol, int max_order)
Array<double> &z, Array<double> &f, Vector &w,
double tol, int max_order)
{
// number of sample points
@@ -67,11 +67,11 @@ void RationalApproximation_AAA(const Vector &val, const Vector &pt,
DenseMatrix C, Ctemp, A, Am;
// auxiliary arrays and vectors
Vector f_vec;
Array<real_t> c_i;
Array<double> c_i;
// mean of the value vector
Vector R(val.Size());
real_t mean_val = val.Sum()/size;
double mean_val = val.Sum()/size;
for (int i = 0; i<R.Size(); i++) { R(i) = mean_val; }
@@ -79,10 +79,10 @@ void RationalApproximation_AAA(const Vector &val, const Vector &pt,
{
// select next support point
int idx = 0;
real_t tmp_max = 0;
double tmp_max = 0;
for (int j = 0; j < size; j++)
{
real_t tmp = abs(val(j)-R(j));
double tmp = abs(val(j)-R(j));
if (tmp > tmp_max)
{
tmp_max = tmp;
@@ -98,7 +98,7 @@ void RationalApproximation_AAA(const Vector &val, const Vector &pt,
J.DeleteFirst(idx);
// next column in Cauchy matrix
Array<real_t> C_tmp(size);
Array<double> C_tmp(size);
for (int j = 0; j < size; j++)
{
C_tmp[j] = 1.0/(pt(j)-pt(idx));
@@ -173,7 +173,7 @@ void RationalApproximation_AAA(const Vector &val, const Vector &pt,
See pg. A1501 of Nakatsukasa et al. [1]. */
void ComputePolesAndZeros(const Vector &z, const Vector &f, const Vector &w,
Array<real_t> & poles, Array<real_t> & zeros, real_t &scale)
Array<double> & poles, Array<double> & zeros, double &scale)
{
// Initialization
poles.SetSize(0);
@@ -242,8 +242,8 @@ void ComputePolesAndZeros(const Vector &z, const Vector &f, const Vector &w,
@param[in] zeros Array of zeros
@param[in] scale Scaling constant
@param[out] coeffs Coefficients c_i */
void PartialFractionExpansion(real_t scale, Array<real_t> & poles,
Array<real_t> & zeros, Array<real_t> & coeffs)
void PartialFractionExpansion(double scale, Array<double> & poles,
Array<double> & zeros, Array<double> & coeffs)
{
int psize = poles.Size();
int zsize = zeros.Size();
@@ -259,13 +259,13 @@ void PartialFractionExpansion(real_t scale, Array<real_t> & poles,
for (int i=0; i<psize; i++)
{
real_t tmp_numer=1.0;
double tmp_numer=1.0;
for (int j=0; j<zsize; j++)
{
tmp_numer *= poles[i]-zeros[j];
}
real_t tmp_denom=1.0;
double tmp_denom=1.0;
for (int k=0; k<psize; k++)
{
if (k != i) { tmp_denom *= poles[i]-poles[k]; }
@@ -292,10 +292,10 @@ void PartialFractionExpansion(real_t scale, Array<real_t> & poles,
@a alpha != 0.99, then @a alpha = 0.5 is used by default.
See pg. A1501 of Nakatsukasa et al. [1]. */
void ComputePartialFractionApproximation(real_t & alpha,
Array<real_t> & coeffs, Array<real_t> & poles,
real_t lmax = 1000.,
real_t tol=1e-10, int npoints = 1000,
void ComputePartialFractionApproximation(double & alpha,
Array<double> & coeffs, Array<double> & poles,
double lmax = 1000.,
double tol=1e-10, int npoints = 1000,
int max_order = 100)
{
MFEM_VERIFY(alpha < 1., "alpha must be less than 1");
@@ -320,26 +320,26 @@ void ComputePartialFractionApproximation(real_t & alpha,
<< "\nThe default is alpha = 0.5.\n" << string(80, '=') << "\n"
<< endl;
}
const real_t eps = std::numeric_limits<real_t>::epsilon();
const double eps = std::numeric_limits<double>::epsilon();
if (abs(alpha - 0.33) < eps)
{
coeffs = Array<real_t> ({1.821898e+03, 9.101221e+01, 2.650611e+01,
coeffs = Array<double> ({1.821898e+03, 9.101221e+01, 2.650611e+01,
1.174937e+01, 6.140444e+00, 3.441713e+00,
1.985735e+00, 1.162634e+00, 6.891560e-01,
4.111574e-01, 2.298736e-01});
poles = Array<real_t> ({-4.155583e+04, -2.956285e+03, -8.331715e+02,
poles = Array<double> ({-4.155583e+04, -2.956285e+03, -8.331715e+02,
-3.139332e+02, -1.303448e+02, -5.563385e+01,
-2.356255e+01, -9.595516e+00, -3.552160e+00,
-1.032136e+00, -1.241480e-01});
}
else if (abs(alpha - 0.99) < eps)
{
coeffs = Array<real_t>({2.919591e-02, 1.419750e-02, 1.065798e-02,
coeffs = Array<double>({2.919591e-02, 1.419750e-02, 1.065798e-02,
9.395094e-03, 8.915329e-03, 8.822991e-03,
9.058247e-03, 9.814521e-03, 1.180396e-02,
1.834554e-02, 9.840482e-01});
poles = Array<real_t> ({-1.069683e+04, -1.769370e+03, -5.718374e+02,
poles = Array<double> ({-1.069683e+04, -1.769370e+03, -5.718374e+02,
-2.242095e+02, -9.419132e+01, -4.031012e+01,
-1.701525e+01, -6.810088e+00, -2.382810e+00,
-5.700059e-01, -1.384324e-03});
@@ -350,11 +350,11 @@ void ComputePartialFractionApproximation(real_t & alpha,
{
alpha = 0.5;
}
coeffs = Array<real_t>({2.290262e+02, 2.641819e+01, 1.005566e+01,
coeffs = Array<double>({2.290262e+02, 2.641819e+01, 1.005566e+01,
5.390411e+00, 3.340725e+00, 2.211205e+00,
1.508883e+00, 1.049474e+00, 7.462709e-01,
5.482686e-01, 4.232510e-01, 3.578967e-01});
poles = Array<real_t>({-3.168211e+04, -3.236077e+03, -9.868287e+02,
poles = Array<double>({-3.168211e+04, -3.236077e+03, -9.868287e+02,
-3.945597e+02, -1.738889e+02, -7.925178e+01,
-3.624992e+01, -1.629196e+01, -6.982956e+00,
-2.679984e+00, -7.782607e-01, -7.649166e-02});
@@ -372,15 +372,15 @@ void ComputePartialFractionApproximation(real_t & alpha,
Vector x(npoints);
Vector val(npoints);
real_t dx = lmax / (real_t)(npoints-1);
double dx = lmax / (double)(npoints-1);
for (int i = 0; i<npoints; i++)
{
x(i) = dx * (real_t)i;
x(i) = dx * (double)i;
val(i) = pow(x(i),1.-alpha);
}
// Apply triple-A algorithm to f(x) = x^{1-a}
Array<real_t> z, f;
Array<double> z, f;
Vector w;
RationalApproximation_AAA(val,x,z,f,w,tol,max_order);
@@ -389,8 +389,8 @@ void ComputePartialFractionApproximation(real_t & alpha,
vecf.SetDataAndSize(f.GetData(), f.Size());
// Compute poles and zeros for RA of f(x) = x^{1-a}
real_t scale;
Array<real_t> zeros;
double scale;
Array<double> zeros;
ComputePolesAndZeros(vecz, vecf, w, poles, zeros, scale);
// Remove the zero at x=0, thus, delivering a RA for f(x) = x^{-a}
+6 -10
View File
@@ -96,7 +96,7 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/star.mesh";
int order = 1;
int num_refs = 3;
real_t alpha = 0.5;
double alpha = 0.5;
bool visualization = true;
bool verification = false;
@@ -127,17 +127,13 @@ int main(int argc, char *argv[])
args.PrintOptions(cout);
}
#ifdef MFEM_USE_SINGLE
MFEM_ABORT("This example is not supported in single precision.");
#endif
Array<real_t> coeffs, poles;
Array<double> coeffs, poles;
int progress_steps = 1;
// 2. Compute the rational expansion coefficients that define the
// integer-order PDEs.
const int power_of_laplace = floor(alpha);
real_t exponent_to_approximate = alpha - power_of_laplace;
double exponent_to_approximate = alpha - power_of_laplace;
bool integer_order = false;
// Check if alpha is an integer or not.
if (abs(exponent_to_approximate) > 1e-12)
@@ -197,7 +193,7 @@ int main(int argc, char *argv[])
// 7. Define diffusion coefficient, load, and solution GridFunction.
auto func = [&alpha](const Vector &x)
{
real_t val = 1.0;
double val = 1.0;
for (int i=0; i<x.Size(); i++)
{
val *= sin(M_PI*x(i));
@@ -402,7 +398,7 @@ int main(int argc, char *argv[])
{
auto solution = [] (const Vector &x)
{
real_t val = 1.0;
double val = 1.0;
for (int i=0; i<x.Size(); i++)
{
val *= sin(M_PI*x(i));
@@ -410,7 +406,7 @@ int main(int argc, char *argv[])
return val;
};
FunctionCoefficient sol(solution);
real_t l2_error = u.ComputeL2Error(sol);
double l2_error = u.ComputeL2Error(sol);
if (Mpi::Root())
{
+319 -528
View File
@@ -2,43 +2,17 @@
//
// Compile with: make ex34
//
// Sample runs: ex34 -o 2
// ex34 -o 2 -pa -hex
// Sample runs: ex34
//
// Device sample runs:
// ex34 -o 2 -pa -hex -d cuda
// ex34 -o 2 -no-pa -d cuda
// Description: This example code demonstrates the use of MFEM to define a
// discontinuous Galerkin (DG) finite element discretization of
// the Laplace problem -Delta u = f with Dirichlet boundary
// conditions. Finite element spaces of any order, including zero
// on regular grids, are supported. The example highlights the
// use of coupling solution domains though custom physics defined
// on internal boundaries.
//
// Description: This example code solves a simple magnetostatic problem
// curl curl A = J where the current density J is computed on a
// subset of the domain as J = -sigma grad phi. We discretize the
// vector potential with Nedelec finite elements, the scalar
// potential with Lagrange finite elements, and the current
// density with Raviart-Thomas finite elements.
//
// The example demonstrates the use of a SubMesh to compute the
// scalar potential and its associated current density which is
// then transferred to the original mesh and used as a source
// function.
//
// Note that this example takes certain liberties with the
// current density which is not necessarily divergence free
// as it should be. This was done to focus on the use of the
// SubMesh to transfer information between a full mesh and a
// sub-domain. A more rigorous implementation might employ an
// H(div) saddle point solver to obtain a divergence free J on
// the SubMesh. It would then also need to ensure that the r.h.s.
// of curl curl A = J does in fact lie in the range of the weak
// curl operator by performing a divergence cleaning procedure
// before the solve. After divergence cleaning the delta
// parameter would probably not be needed.
//
// This example is designed to make use of a specific mesh which
// has a known configuration of elements and boundary attributes.
// Other meshes could be used but extra care would be required to
// properly define the SubMesh and the necessary boundaries.
//
// We recommend viewing examples 1 and 3 before viewing this
// We recommend viewing examples 1 and 14 before viewing this
// example.
#include "mfem.hpp"
@@ -48,574 +22,391 @@
using namespace std;
using namespace mfem;
static bool pa_ = false;
static bool algebraic_ceed_ = false;
class InteriorLFIntegrator : public LinearFormIntegrator
{
public:
InteriorLFIntegrator(Coefficient &Q)
: Q(Q)
{}
void ComputeCurrentDensityOnSubMesh(int order,
const Array<int> &phi0_attr,
const Array<int> &phi1_attr,
const Array<int> &jn_zero_attr,
GridFunction &j_cond);
void AssembleRHSElementVect(const FiniteElement &el1,
const FiniteElement &el2,
FaceElementTransformations &trans,
Vector &mesh_coords_bar) override;
void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &trans,
Vector &elvect) override
{
mfem_error("AssembleRHSElementVect(...)");
}
private:
Coefficient &Q;
#ifndef MFEM_THREAD_SAFE
Vector shape1;
Vector shape2;
#endif
};
Mesh generate_mesh(int ref, int internal_bdr_attr = 5);
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../data/fichera-mixed.mesh";
Array<int> cond_attr;
Array<int> submesh_elems;
Array<int> sym_plane_attr;
Array<int> phi0_attr;
Array<int> phi1_attr;
Array<int> jn_zero_attr;
int ref_levels = 1;
int ref_levels = 0;
int order = 1;
real_t delta_const = 1e-6;
bool mixed = true;
bool static_cond = false;
const char *device_config = "cpu";
bool visualization = true;
int sol_order = 3;
double jump = -2;
double sigma = -1.0;
double kappa = -1.0;
double eta = 0.0;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&delta_const, "-mc", "--magnetic-cond",
"Magnetic Conductivity");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&mixed, "-mixed", "--mixed-mesh", "-hex",
"--hex-mesh", "Mixed mesh of hexahedral mesh.");
args.AddOption(&pa_, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
#ifdef MFEM_USE_CEED
args.AddOption(&algebraic_ceed_, "-a", "--algebraic", "-no-a", "--no-algebraic",
"Use algebraic Ceed solver");
#endif
"Finite element order (polynomial degree) >= 0.");
args.AddOption(&sigma, "-s", "--sigma",
"One of the three DG penalty parameters, typically +1/-1."
" See the documentation of class DGDiffusionIntegrator.");
args.AddOption(&kappa, "-k", "--kappa",
"One of the three DG penalty parameters, should be positive."
" Negative values are replaced with (order+1)^2.");
args.AddOption(&eta, "-e", "--eta", "BR2 penalty parameter.");
args.AddOption(&sol_order, "-so", "--solution_order",
"Polynomial order of the exact solution >= 0.");
args.AddOption(&jump, "-j", "--jump",
"Value of the discontinuity between the material regions.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
if (kappa < 0)
{
kappa = (order+1)*(order+1);
}
if (sol_order < 0)
{
sol_order = 1;
}
args.PrintOptions(cout);
if (!mixed || pa_)
{
mesh_file = "../data/fichera.mesh";
}
// 2. Construct the (serial) mesh and refine it if requested.
auto mesh = generate_mesh(ref_levels);
if (submesh_elems.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0)
{
submesh_elems.SetSize(5);
submesh_elems[0] = 0;
submesh_elems[1] = 2;
submesh_elems[2] = 3;
submesh_elems[3] = 4;
submesh_elems[4] = 9;
}
else if (strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
submesh_elems.SetSize(7);
submesh_elems[0] = 10;
submesh_elems[1] = 14;
submesh_elems[2] = 34;
submesh_elems[3] = 36;
submesh_elems[4] = 37;
submesh_elems[5] = 38;
submesh_elems[6] = 39;
}
}
if (sym_plane_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
sym_plane_attr.SetSize(8);
sym_plane_attr[0] = 9;
sym_plane_attr[1] = 10;
sym_plane_attr[2] = 11;
sym_plane_attr[3] = 12;
sym_plane_attr[4] = 13;
sym_plane_attr[5] = 14;
sym_plane_attr[6] = 15;
sym_plane_attr[7] = 16;
}
}
if (phi0_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
phi0_attr.Append(2);
}
}
if (phi1_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
phi1_attr.Append(23);
}
}
if (jn_zero_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
jn_zero_attr.Append(25);
}
for (int i=0; i<sym_plane_attr.Size(); i++)
{
jn_zero_attr.Append(sym_plane_attr[i]);
}
}
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
if (!mixed || pa_)
if (mesh.NURBSext)
{
mesh.UniformRefinement();
mesh.SetCurvature(max(order, 1));
}
if (ref_levels > 0)
// 3. Define a finite element space on the mesh. Here we use discontinuous
// finite elements of the specified order >= 0.
DG_FECollection fec(order, dim);
FiniteElementSpace fespace(&mesh, &fec);
cout << "Number of unknowns: " << fespace.GetVSize() << endl;
// 4. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system.
LinearForm b(&fespace);
Array<int> p1_attr_marker(mesh.attributes.Max());
p1_attr_marker = 0;
p1_attr_marker[0] = 1;
FunctionCoefficient p1_source([sol_order](const Vector &p)
{
const double x = p(0);
const double val = -(sol_order - 1)*sol_order*pow(x, sol_order-2);
return val;
});
b.AddDomainIntegrator(new DomainLFIntegrator(p1_source), p1_attr_marker);
Array<int> p2_attr_marker(mesh.attributes.Max());
p2_attr_marker = 0;
p2_attr_marker[1] = 1;
FunctionCoefficient p2_source([sol_order](const Vector &p)
{
const double x = p(0);
double val = -(sol_order - 1)*sol_order*pow(x - 2, sol_order-2);
if (sol_order % 2 == 0)
{
ref_levels--;
val *= -1.0;
}
}
return val;
});
b.AddDomainIntegrator(new DomainLFIntegrator(p2_source), p2_attr_marker);
int submesh_attr = -1;
if (cond_attr.Size() == 0 && submesh_elems.Size() > 0)
{
int max_attr = mesh.attributes.Max();
submesh_attr = max_attr + 1;
ConstantCoefficient one(1.0);
for (int i=0; i<submesh_elems.Size(); i++)
{
mesh.SetAttribute(submesh_elems[i], submesh_attr);
}
mesh.SetAttributes();
Array<int> p1_bdr_attr_marker(mesh.bdr_attributes.Max());
p1_bdr_attr_marker = 0;
p1_bdr_attr_marker[0] = 1;
if (cond_attr.Size() == 0)
{
cond_attr.Append(submesh_attr);
}
}
ConstantCoefficient left_bc_val(0.0);
b.AddBdrFaceIntegrator(
new DGDirichletLFIntegrator(left_bc_val, one, sigma, kappa),
p1_bdr_attr_marker);
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement.
{
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
}
Array<int> p2_bdr_attr_marker(mesh.bdr_attributes.Max());
p2_bdr_attr_marker = 0;
p2_bdr_attr_marker[1] = 1;
// 5b. Extract a submesh covering a portion of the domain
SubMesh mesh_cond(SubMesh::CreateFromDomain(mesh, cond_attr));
ConstantCoefficient right_bc_val(2.0 + jump);
b.AddBdrFaceIntegrator(
new DGDirichletLFIntegrator(right_bc_val, one, sigma, kappa),
p2_bdr_attr_marker);
// 6. Define a suitable finite element space on the SubMesh and compute
// the current density as an H(div) field.
RT_FECollection fec_cond_rt(order - 1, dim);
FiniteElementSpace fes_cond_rt(&mesh_cond, &fec_cond_rt);
GridFunction j_cond(&fes_cond_rt);
Array<int> internal_bdr_attr_marker(mesh.bdr_attributes.Max());
internal_bdr_attr_marker = 0;
internal_bdr_attr_marker[4] = 1;
ComputeCurrentDensityOnSubMesh(order, phi0_attr, phi1_attr, jn_zero_attr,
j_cond);
ConstantCoefficient interface_flux(sol_order);
b.AddInternalBoundaryFaceIntegrator(
new InteriorLFIntegrator(interface_flux),
internal_bdr_attr_marker);
// 6a. Save the SubMesh and associated current density in parallel. This
// output can be viewed later using GLVis:
// "glvis -np <np> -m cond_mesh -g cond_j"
{
ostringstream mesh_name, cond_name;
mesh_name << "cond.mesh";
cond_name << "cond_j.gf";
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
mesh_cond.Print(mesh_ofs);
ofstream cond_ofs(cond_name.str().c_str());
cond_ofs.precision(8);
j_cond.Save(cond_ofs);
}
// 6b. Send the current density, computed on the SubMesh, to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream port_sock(vishost, visport);
port_sock.precision(8);
port_sock << "solution\n" << mesh_cond << j_cond
<< "window_title 'Conductor J'"
<< "window_geometry 400 0 400 350" << flush;
}
// 7. Define a parallel finite element space on the full mesh. Here we use
// the H(curl) finite elements for the vector potential and H(div) for the
// current density.
ND_FECollection fec_nd(order, dim);
RT_FECollection fec_rt(order - 1, dim);
FiniteElementSpace fespace_nd(&mesh, &fec_nd);
FiniteElementSpace fespace_rt(&mesh, &fec_rt);
GridFunction j_full(&fespace_rt);
j_full = 0.0;
mesh_cond.Transfer(j_cond, j_full);
// 7a. Send the transferred current density to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << mesh << j_full
<< "window_title 'J Full'"
<< "window_geometry 400 430 400 350" << flush;
}
// 8. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined by
// marking all the boundary attributes except for those on a symmetry
// plane as essential (Dirichlet) and converting them to a list of true
// dofs.
Array<int> ess_tdof_list;
Array<int> ess_bdr;
if (mesh.bdr_attributes.Size())
{
ess_bdr.SetSize(mesh.bdr_attributes.Max());
ess_bdr = 1;
for (int i=0; i<sym_plane_attr.Size(); i++)
{
ess_bdr[sym_plane_attr[i]-1] = 0;
}
fespace_nd.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 9. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (J,W_i) where J is given by the function H(div) field transferred
// from the SubMesh and W_i are the basis functions in the finite
// element fespace.
VectorGridFunctionCoefficient jCoef(&j_full);
LinearForm b(&fespace_nd);
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(jCoef));
b.Assemble();
// 10. Define the solution vector x as a parallel finite element grid
// function corresponding to fespace. Initialize x to zero.
GridFunction x(&fespace_nd);
// 5. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero.
GridFunction x(&fespace);
x = 0.0;
// 11. Set up the parallel bilinear form corresponding to the EM diffusion
// operator curl muinv curl + delta I, by adding the curl-curl and the
// mass domain integrators. For standard magnetostatics equations choose
// delta << 1. Larger values of delta should make the linear system
// easier to solve at the expense of resembling a diffusive quasistatic
// magnetic field. A reasonable balance must be found whenever the mesh
// or problem setup is altered.
ConstantCoefficient muinv(1.0);
ConstantCoefficient delta(delta_const);
BilinearForm a(&fespace_nd);
if (pa_) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a.AddDomainIntegrator(new CurlCurlIntegrator(muinv));
a.AddDomainIntegrator(new VectorFEMassIntegrator(delta));
// 6. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator and the interior and boundary DG face integrators.
// Note that boundary conditions are imposed weakly in the form, so there
// is no need for dof elimination. After assembly and finalizing we
// extract the corresponding sparse matrix A.
BilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator(one));
// 12. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a.EnableStaticCondensation(); }
a.Assemble();
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
// 13. Solve the system AX=B
if (pa_) // Jacobi preconditioning in partial assembly mode
a.AddInteriorFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
a.AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa),
p1_bdr_attr_marker);
a.AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa),
p2_bdr_attr_marker);
if (eta > 0)
{
cout << "\nSolving for magnetic vector potential "
<< "using CG with a Jacobi preconditioner" << endl;
a.AddInteriorFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta));
a.AddBdrFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta));
}
OperatorJacobiSmoother M(a, ess_tdof_list);
PCG(*A, M, B, X, 1, 1000, 1e-12, 0.0);
// 7. Negate the DG interface terms along the internal boundary so that the
// only coupling between domains is from the chosen model (constant flux
// in this case).
ProductCoefficient neg_one(-1.0, one);
a.AddInternalBoundaryFaceIntegrator(new DGDiffusionIntegrator(neg_one, sigma,
kappa),
internal_bdr_attr_marker);
if (eta > 0)
{
a.AddInternalBoundaryFaceIntegrator(new DGDiffusionBR2Integrator(fespace,
neg_one, eta),
internal_bdr_attr_marker);
}
a.Assemble();
a.Finalize();
const SparseMatrix &A = a.SpMat();
#ifndef MFEM_USE_SUITESPARSE
// 8. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system Ax=b with PCG in the symmetric case, and GMRES in the
// non-symmetric one.
GSSmoother M(A);
if (sigma == -1.0)
{
PCG(A, M, b, x, 1, 500, 1e-12, 0.0);
}
else
{
#ifndef MFEM_USE_SUITESPARSE
cout << "\nSolving for magnetic vector potential "
<< "using CG with a Gauss-Seidel preconditioner" << endl;
// 13a. Define a simple symmetric Gauss-Seidel preconditioner and use
// it to solve the system Ax=b with PCG.
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 1, 500, 1e-12, 0.0);
GMRES(A, M, b, x, 1, 500, 500, 1e-24, 0.0);
}
#else
cout << "\nSolving for magnetic vector potential "
<< "using UMFPack" << endl;
// 13a. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the
// system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(*A);
umf_solver.Mult(B, X);
// 8. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(b, x);
#endif
}
// 14. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a.RecoverFEMSolution(X, b, x);
// 9. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh.Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "refined.mesh";
sol_name << "sol.gf";
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
mesh.Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
// 10. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << mesh << x
<< "window_title 'Vector Potential'"
<< "window_geometry 800 0 400 350" << flush;
sol_sock << "solution\n" << mesh << x << flush;
}
// 17. Compute the magnetic flux as the curl of the solution
DiscreteLinearOperator curl(&fespace_nd, &fespace_rt);
curl.AddDomainInterpolator(new CurlInterpolator);
curl.Assemble();
curl.Finalize();
GridFunction dx(&fespace_rt);
curl.Mult(x, dx);
// 18. Save the curl of the solution in parallel. This output can be viewed
// later using GLVis: "glvis -np <np> -m mesh -g dsol".
{
ostringstream dsol_name;
dsol_name << "dsol.gf";
ofstream dsol_ofs(dsol_name.str().c_str());
dsol_ofs.precision(8);
dx.Save(dsol_ofs);
}
// 19. Send the curl of the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << mesh << dx
<< "window_title 'Magnetic Flux'"
<< "window_geometry 1200 0 400 350" << flush;
}
// 20. Clean exit
return 0;
}
void ComputeCurrentDensityOnSubMesh(int order,
const Array<int> &phi0_attr,
const Array<int> &phi1_attr,
const Array<int> &jn_zero_attr,
GridFunction &j_cond)
void InteriorLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el1,
const FiniteElement &el2,
FaceElementTransformations &trans,
Vector &elvect)
{
// Extract the finite element space and mesh on which j_cond is defined
FiniteElementSpace &fes_cond_rt = *j_cond.FESpace();
Mesh &mesh_cond = *fes_cond_rt.GetMesh();
int dim = mesh_cond.Dimension();
int ndof1 = el1.GetDof();
int ndof2 = el2.GetDof();
int ndof = ndof1 + ndof2;
// Define a parallel finite element space on the SubMesh. Here we use the H1
// finite elements for the electrostatic potential.
H1_FECollection fec_h1(order, dim);
FiniteElementSpace fes_cond_h1(&mesh_cond, &fec_h1);
// Define the conductivity coefficient and the boundaries associated with the
// fixed potentials phi0 and phi1 which will drive the current.
ConstantCoefficient sigmaCoef(1.0);
Array<int> ess_bdr_phi(mesh_cond.bdr_attributes.Max());
Array<int> ess_bdr_j(mesh_cond.bdr_attributes.Max());
Array<int> ess_bdr_tdof_phi;
ess_bdr_phi = 0;
ess_bdr_j = 0;
for (int i=0; i<phi0_attr.Size(); i++)
{
ess_bdr_phi[phi0_attr[i]-1] = 1;
}
for (int i=0; i<phi1_attr.Size(); i++)
{
ess_bdr_phi[phi1_attr[i]-1] = 1;
}
for (int i=0; i<jn_zero_attr.Size(); i++)
{
ess_bdr_j[jn_zero_attr[i]-1] = 1;
}
fes_cond_h1.GetEssentialTrueDofs(ess_bdr_phi, ess_bdr_tdof_phi);
// Setup the bilinear form corresponding to -Div(sigma Grad phi)
BilinearForm a_h1(&fes_cond_h1);
a_h1.AddDomainIntegrator(new DiffusionIntegrator(sigmaCoef));
a_h1.Assemble();
// Set the r.h.s. to zero
LinearForm b_h1(&fes_cond_h1);
b_h1 = 0.0;
// Setup the boundary conditions on phi
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
GridFunction phi_h1(&fes_cond_h1);
phi_h1 = 0.0;
Array<int> bdr0(mesh_cond.bdr_attributes.Max()); bdr0 = 0;
for (int i=0; i<phi0_attr.Size(); i++)
{
bdr0[phi0_attr[i]-1] = 1;
}
phi_h1.ProjectBdrCoefficient(zero, bdr0);
Array<int> bdr1(mesh_cond.bdr_attributes.Max()); bdr1 = 0;
for (int i=0; i<phi1_attr.Size(); i++)
{
bdr1[phi1_attr[i]-1] = 1;
}
phi_h1.ProjectBdrCoefficient(one, bdr1);
{
OperatorPtr A;
Vector B, X;
a_h1.FormLinearSystem(ess_bdr_tdof_phi, phi_h1, b_h1, A, X, B);
// Solve the linear system
if (!pa_)
{
#ifndef MFEM_USE_SUITESPARSE
cout << "\nSolving for electric potential using PCG "
<< "with a Gauss-Seidel preconditioner" << endl;
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 1, 200, 1e-12, 0.0);
#else
cout << "\nSolving for electric potential using UMFPack" << endl;
// If MFEM was compiled with SuiteSparse,
// use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(*A);
umf_solver.Mult(B, X);
#ifdef MFEM_THREAD_SAFE
Vector shape1;
Vector shape2;
#endif
}
else
{
cout << "\nSolving for electric potential using CG" << endl;
shape1.SetSize(ndof1);
shape2.SetSize(ndof2);
if (UsesTensorBasis(fes_cond_h1))
const auto *ir = IntRule;
if (ir == NULL)
{
int order = 2 * max(el1.GetOrder(), el2.GetOrder());
ir = &IntRules.Get(trans.GetGeometryType(), order);
}
elvect.SetSize(ndof);
Vector elvect1(elvect.GetData(), ndof1);
Vector elvect2(elvect.GetData() + ndof1, ndof2);
elvect = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const auto &ip = ir->IntPoint(i);
// Set the integration point in the face and the neighboring element
trans.SetAllIntPoints(&ip);
const double w = ip.weight * trans.Weight();
// Access the neighboring element's integration point
const auto &eip1 = trans.GetElement1IntPoint();
const auto &eip2 = trans.GetElement2IntPoint();
double Q_val = Q.Eval(trans, ip);
el1.CalcShape(eip1, shape1);
el2.CalcShape(eip2, shape2);
elvect1.Add(Q_val * w, shape1);
elvect2.Add(-Q_val * w, shape2);
}
}
Mesh generate_mesh(int ref, int internal_bdr_attr)
{
int nxy = 4 * (ref+1);
auto mesh = Mesh::MakeCartesian2D(nxy, nxy, Element::TRIANGLE, true, 2.0, 1.0);
// auto mesh = Mesh::MakeCartesian2D(nxy, nxy, Element::QUADRILATERAL, true, 2.0, 1.0);
// assign element attributes to left and right sides
for (int i = 0; i < mesh.GetNE(); ++i)
{
auto *elem = mesh.GetElement(i);
Array<int> verts;
elem->GetVertices(verts);
bool left = true;
for (int j = 0; j < verts.Size(); ++j)
{
auto *vtx = mesh.GetVertex(verts[j]);
if (vtx[0] <= 1.0)
{
if (algebraic_ceed_)
{
ceed::AlgebraicSolver M(a_h1, ess_bdr_tdof_phi);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
else
{
OperatorJacobiSmoother M(a_h1, ess_bdr_tdof_phi);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
continue;
}
else
{
CG(*A, B, X, 1, 400, 1e-12, 0.0);
left = false;
}
}
a_h1.RecoverFEMSolution(X, b_h1, phi_h1);
if (left)
{
elem->SetAttribute(1);
}
else
{
elem->SetAttribute(2);
}
}
// assign boundary element attributes to left and right sides
for (int i = 0; i < mesh.GetNBE(); ++i)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream port_sock(vishost, visport);
port_sock.precision(8);
port_sock << "solution\n" << mesh_cond << phi_h1
<< "window_title 'Conductor Potential'"
<< "window_geometry 0 0 400 350" << flush;
auto *elem = mesh.GetBdrElement(i);
Array<int> verts;
elem->GetVertices(verts);
bool left = true;
bool right = true;
bool top = true;
bool bottom = true;
for (int j = 0; j < verts.Size(); ++j)
{
auto *vtx = mesh.GetVertex(verts[j]);
left = left && abs(vtx[0] - 0.0) < 1e-12;
right = right && abs(vtx[0] - 2.0) < 1e-12;
top = top && abs(vtx[1] - 1.0) < 1e-12;
bottom = bottom && abs(vtx[1] - 0.0) < 1e-12;
}
if (left)
{
elem->SetAttribute(1);
}
else if (right)
{
elem->SetAttribute(2);
}
else if (top)
{
elem->SetAttribute(3);
}
else if (bottom)
{
elem->SetAttribute(4);
}
}
// Solve for the current density J = -sigma Grad phi with boundary conditions
// J.n = 0 on the walls of the conductor but not on the ports where phi=0 and
// phi=1.
// add internal boundary elements
for (int i = 0; i < mesh.GetNumFaces(); ++i)
{
int e1, e2;
mesh.GetFaceElements(i, &e1, &e2);
if (e1 >= 0 && e2 >= 0 && mesh.GetAttribute(e1) != mesh.GetAttribute(e2))
{
// This is the internal face between attributes.
auto *new_elem = mesh.GetFace(i)->Duplicate(&mesh);
new_elem->SetAttribute(internal_bdr_attr);
mesh.AddBdrElement(new_elem);
}
}
// J will be computed in H(div) so we need an RT mass matrix
BilinearForm m_rt(&fes_cond_rt);
m_rt.AddDomainIntegrator(new VectorFEMassIntegrator);
m_rt.Assemble();
mesh.FinalizeTopology(); // Finalize to build relevant tables
mesh.Finalize();
mesh.SetAttributes();
// Assemble the (sigma Grad phi) operator
MixedBilinearForm d_h1(&fes_cond_h1, &fes_cond_rt);
d_h1.AddDomainIntegrator(new MixedVectorGradientIntegrator(sigmaCoef));
d_h1.Assemble();
// Compute the r.h.s, b_rt = sigma E = -sigma Grad phi
LinearForm b_rt(&fes_cond_rt);
d_h1.Mult(phi_h1, b_rt);
b_rt *= -1.0;
// Apply the necessary boundary conditions and solve for J in H(div)
cout << "\nSolving for current density in H(Div) "
<< "using diagonally scaled CG" << endl;
cout << "Size of linear system: "
<< fes_cond_rt.GetTrueVSize() << endl;
Array<int> ess_bdr_tdof_rt;
OperatorPtr M;
Vector B, X;
fes_cond_rt.GetEssentialTrueDofs(ess_bdr_j, ess_bdr_tdof_rt);
j_cond = 0.0;
m_rt.FormLinearSystem(ess_bdr_tdof_rt, j_cond, b_rt, M, X, B);
CGSolver cg;
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
cg.SetOperator(*M);
cg.Mult(B, X);
m_rt.RecoverFEMSolution(X, b_rt, j_cond);
}
return mesh;
}
-648
View File
@@ -1,648 +0,0 @@
// MFEM Example 34 - Parallel Version
//
// Compile with: make ex34p
//
// Sample runs: mpirun -np 4 ex34p -o 2
// mpirun -np 4 ex34p -o 2 -hex -pa
//
// Device sample runs:
// mpirun -np 4 ex34p -o 2 -hex -pa -d cuda
// mpirun -np 4 ex34p -o 2 -no-pa -d cuda
//
// Description: This example code solves a simple magnetostatic problem
// curl curl A = J where the current density J is computed on a
// subset of the domain as J = -sigma grad phi. We discretize the
// vector potential with Nedelec finite elements, the scalar
// potential with Lagrange finite elements, and the current
// density with Raviart-Thomas finite elements.
//
// The example demonstrates the use of a SubMesh to compute the
// scalar potential and its associated current density which is
// then transferred to the original mesh and used as a source
// function.
//
// Note that this example takes certain liberties with the
// current density which is not necessarily divergence free
// as it should be. This was done to focus on the use of the
// SubMesh to transfer information between a full mesh and a
// sub-domain. A more rigorous implementation might employ an
// H(div) saddle point solver to obtain a divergence free J on
// the SubMesh. It would then also need to ensure that the r.h.s.
// of curl curl A = J does in fact lie in the range of the weak
// curl operator by performing a divergence cleaning procedure
// before the solve. After divergence cleaning the delta
// parameter would probably not be needed.
//
// This example is designed to make use of a specific mesh which
// has a known configuration of elements and boundary attributes.
// Other meshes could be used but extra care would be required to
// properly define the SubMesh and the necessary boundaries.
//
// We recommend viewing examples 1 and 3 before viewing this
// example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
void ComputeCurrentDensityOnSubMesh(int order,
const Array<int> &phi0_attr,
const Array<int> &phi1_attr,
const Array<int> &jn_zero_attr,
ParGridFunction &j_cond);
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();
// 2. Parse command-line options.
const char *mesh_file = "../data/fichera-mixed.mesh";
Array<int> cond_attr;
Array<int> submesh_elems;
Array<int> sym_plane_attr;
Array<int> phi0_attr;
Array<int> phi1_attr;
Array<int> jn_zero_attr;
int ser_ref_levels = 1;
int par_ref_levels = 1;
int order = 1;
real_t delta_const = 1e-6;
bool mixed = true;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
#ifdef MFEM_USE_AMGX
bool useAmgX = false;
#endif
OptionsParser args(argc, argv);
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
"Number of times to refine the mesh uniformly in parallel.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&delta_const, "-mc", "--magnetic-cond",
"Magnetic Conductivity");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&mixed, "-mixed", "--mixed-mesh", "-hex",
"--hex-mesh", "Mixed mesh of hexahedral mesh.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
#ifdef MFEM_USE_AMGX
args.AddOption(&useAmgX, "-amgx", "--useAmgX", "-no-amgx",
"--no-useAmgX",
"Enable or disable AmgX in MatrixFreeAMS.");
#endif
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
if (!mixed || pa)
{
mesh_file = "../data/fichera.mesh";
}
if (submesh_elems.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0)
{
submesh_elems.SetSize(5);
submesh_elems[0] = 0;
submesh_elems[1] = 2;
submesh_elems[2] = 3;
submesh_elems[3] = 4;
submesh_elems[4] = 9;
}
else if (strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
submesh_elems.SetSize(7);
submesh_elems[0] = 10;
submesh_elems[1] = 14;
submesh_elems[2] = 34;
submesh_elems[3] = 36;
submesh_elems[4] = 37;
submesh_elems[5] = 38;
submesh_elems[6] = 39;
}
}
if (sym_plane_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
sym_plane_attr.SetSize(8);
sym_plane_attr[0] = 9;
sym_plane_attr[1] = 10;
sym_plane_attr[2] = 11;
sym_plane_attr[3] = 12;
sym_plane_attr[4] = 13;
sym_plane_attr[5] = 14;
sym_plane_attr[6] = 15;
sym_plane_attr[7] = 16;
}
}
if (phi0_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
phi0_attr.Append(2);
}
}
if (phi1_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
phi1_attr.Append(23);
}
}
if (jn_zero_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
jn_zero_attr.Append(25);
}
for (int i=0; i<sym_plane_attr.Size(); i++)
{
jn_zero_attr.Append(sym_plane_attr[i]);
}
}
// 3. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
if (!mixed || pa)
{
mesh->UniformRefinement();
if (ser_ref_levels > 0)
{
ser_ref_levels--;
}
else
{
par_ref_levels--;
}
}
int submesh_attr = -1;
if (cond_attr.Size() == 0 && submesh_elems.Size() > 0)
{
int max_attr = mesh->attributes.Max();
submesh_attr = max_attr + 1;
for (int i=0; i<submesh_elems.Size(); i++)
{
mesh->SetAttribute(submesh_elems[i], submesh_attr);
}
mesh->SetAttributes();
if (cond_attr.Size() == 0)
{
cond_attr.Append(submesh_attr);
}
}
// 5. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement.
{
int ref_levels = ser_ref_levels;
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
delete mesh;
{
for (int l = 0; l < par_ref_levels; l++)
{
pmesh.UniformRefinement();
}
}
// 6b. Extract a submesh covering a portion of the domain
ParSubMesh pmesh_cond(ParSubMesh::CreateFromDomain(pmesh, cond_attr));
// 7. Define a suitable finite element space on the SubMesh and compute
// the current density as an H(div) field.
RT_FECollection fec_cond_rt(order - 1, dim);
ParFiniteElementSpace fes_cond_rt(&pmesh_cond, &fec_cond_rt);
ParGridFunction j_cond(&fes_cond_rt);
ComputeCurrentDensityOnSubMesh(order, phi0_attr, phi1_attr, jn_zero_attr,
j_cond);
// 7a. Save the SubMesh and associated current density in parallel. This
// output can be viewed later using GLVis:
// "glvis -np <np> -m cond_mesh -g cond_j"
{
ostringstream mesh_name, cond_name;
mesh_name << "cond_mesh." << setfill('0') << setw(6) << myid;
cond_name << "cond_j." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh_cond.Print(mesh_ofs);
ofstream cond_ofs(cond_name.str().c_str());
cond_ofs.precision(8);
j_cond.Save(cond_ofs);
}
// 7b. Send the current density, computed on the SubMesh, to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream port_sock(vishost, visport);
port_sock << "parallel " << num_procs << " " << myid << "\n";
port_sock.precision(8);
port_sock << "solution\n" << pmesh_cond << j_cond
<< "window_title 'Conductor J'"
<< "window_geometry 400 0 400 350" << flush;
}
// 8. Define a parallel finite element space on the full mesh. Here we use
// the H(curl) finite elements for the vector potential and H(div) for the
// current density.
ND_FECollection fec_nd(order, dim);
RT_FECollection fec_rt(order - 1, dim);
ParFiniteElementSpace fespace_nd(&pmesh, &fec_nd);
ParFiniteElementSpace fespace_rt(&pmesh, &fec_rt);
ParGridFunction j_full(&fespace_rt);
j_full = 0.0;
pmesh_cond.Transfer(j_cond, j_full);
// 8a. Send the transferred current density to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << j_full
<< "window_title 'J Full'"
<< "window_geometry 400 430 400 350" << flush;
}
// 9. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes except for those on a symmetry
// plane as essential (Dirichlet) and converting them to a list of
// true dofs.
Array<int> ess_tdof_list;
Array<int> ess_bdr;
if (pmesh.bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh.bdr_attributes.Max());
ess_bdr = 1;
for (int i=0; i<sym_plane_attr.Size(); i++)
{
ess_bdr[sym_plane_attr[i]-1] = 0;
}
fespace_nd.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 10. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (J,W_i) where J is given by the function H(div) field transferred
// from the SubMesh and W_i are the basis functions in the finite
// element fespace.
VectorGridFunctionCoefficient jCoef(&j_full);
ParLinearForm b(&fespace_nd);
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(jCoef));
b.Assemble();
// 11. Define the solution vector x as a parallel finite element grid
// function corresponding to fespace. Initialize x to zero.
ParGridFunction x(&fespace_nd);
x = 0.0;
// 12. Set up the parallel bilinear form corresponding to the EM diffusion
// operator curl muinv curl + delta I, by adding the curl-curl and the
// mass domain integrators. For standard magnetostatics equations choose
// delta << 1. Larger values of delta should make the linear system
// easier to solve at the expense of resembling a diffusive quasistatic
// magnetic field. A reasonable balance must be found whenever the mesh
// or problem setup is altered.
ConstantCoefficient muinv(1.0);
ConstantCoefficient delta(delta_const);
ParBilinearForm a(&fespace_nd);
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a.AddDomainIntegrator(new CurlCurlIntegrator(muinv));
a.AddDomainIntegrator(new VectorFEMassIntegrator(delta));
// 13. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a.EnableStaticCondensation(); }
a.Assemble();
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
if (myid == 0)
{
cout << "\nSolving for magnetic vector potential "
<< "using CG with AMS" << endl;
}
// 14. Solve the system AX=B using PCG with an AMS preconditioner.
if (pa)
{
#ifdef MFEM_USE_AMGX
MatrixFreeAMS ams(a, *A, fespace_nd, &muinv, &delta, NULL, ess_bdr,
useAmgX);
#else
MatrixFreeAMS ams(a, *A, fespace_nd, &muinv, &delta, NULL, ess_bdr);
#endif
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(1000);
cg.SetPrintLevel(1);
cg.SetOperator(*A);
cg.SetPreconditioner(ams);
cg.Mult(B, X);
}
else
{
if (myid == 0)
{
cout << "Size of linear system: "
<< A.As<HypreParMatrix>()->GetGlobalNumRows() << endl;
}
ParFiniteElementSpace *prec_fespace =
(a.StaticCondensationIsEnabled() ? a.SCParFESpace() : &fespace_nd);
HypreAMS ams(*A.As<HypreParMatrix>(), prec_fespace);
HyprePCG pcg(*A.As<HypreParMatrix>());
pcg.SetTol(1e-12);
pcg.SetMaxIter(500);
pcg.SetPrintLevel(2);
pcg.SetPreconditioner(ams);
pcg.Mult(B, X);
}
// 15. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a.RecoverFEMSolution(X, b, x);
// 16. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh.Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << x
<< "window_title 'Vector Potential'"
<< "window_geometry 800 0 400 350" << flush;
}
// 18. Compute the magnetic flux as the curl of the solution
ParDiscreteLinearOperator curl(&fespace_nd, &fespace_rt);
curl.AddDomainInterpolator(new CurlInterpolator);
curl.Assemble();
curl.Finalize();
ParGridFunction dx(&fespace_rt);
curl.Mult(x, dx);
// 19. Save the curl of the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g dsol".
{
ostringstream dsol_name;
dsol_name << "dsol." << setfill('0') << setw(6) << myid;
ofstream dsol_ofs(dsol_name.str().c_str());
dsol_ofs.precision(8);
dx.Save(dsol_ofs);
}
// 20. Send the curl of the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << dx
<< "window_title 'Magnetic Flux'"
<< "window_geometry 1200 0 400 350" << flush;
}
// 21. Clean exit
return 0;
}
void ComputeCurrentDensityOnSubMesh(int order,
const Array<int> &phi0_attr,
const Array<int> &phi1_attr,
const Array<int> &jn_zero_attr,
ParGridFunction &j_cond)
{
// Extract the finite element space and mesh on which j_cond is defined
ParFiniteElementSpace &fes_cond_rt = *j_cond.ParFESpace();
ParMesh &pmesh_cond = *fes_cond_rt.GetParMesh();
int myid = fes_cond_rt.GetMyRank();
int dim = pmesh_cond.Dimension();
// Define a parallel finite element space on the SubMesh. Here we use the
// H1 finite elements for the electrostatic potential.
H1_FECollection fec_h1(order, dim);
ParFiniteElementSpace fes_cond_h1(&pmesh_cond, &fec_h1);
// Define the conductivity coefficient and the boundaries associated with the
// fixed potentials phi0 and phi1 which will drive the current.
ConstantCoefficient sigmaCoef(1.0);
Array<int> ess_bdr_phi(pmesh_cond.bdr_attributes.Max());
Array<int> ess_bdr_j(pmesh_cond.bdr_attributes.Max());
Array<int> ess_bdr_tdof_phi;
ess_bdr_phi = 0;
ess_bdr_j = 0;
for (int i=0; i<phi0_attr.Size(); i++)
{
ess_bdr_phi[phi0_attr[i]-1] = 1;
}
for (int i=0; i<phi1_attr.Size(); i++)
{
ess_bdr_phi[phi1_attr[i]-1] = 1;
}
for (int i=0; i<jn_zero_attr.Size(); i++)
{
ess_bdr_j[jn_zero_attr[i]-1] = 1;
}
fes_cond_h1.GetEssentialTrueDofs(ess_bdr_phi, ess_bdr_tdof_phi);
// Setup the bilinear form corresponding to -Div(sigma Grad phi)
ParBilinearForm a_h1(&fes_cond_h1);
a_h1.AddDomainIntegrator(new DiffusionIntegrator(sigmaCoef));
a_h1.Assemble();
// Set the r.h.s. to zero
ParLinearForm b_h1(&fes_cond_h1);
b_h1 = 0.0;
// Setup the boundary conditions on phi
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
ParGridFunction phi_h1(&fes_cond_h1);
phi_h1 = 0.0;
Array<int> bdr0(pmesh_cond.bdr_attributes.Max()); bdr0 = 0;
for (int i=0; i<phi0_attr.Size(); i++)
{
bdr0[phi0_attr[i]-1] = 1;
}
phi_h1.ProjectBdrCoefficient(zero, bdr0);
Array<int> bdr1(pmesh_cond.bdr_attributes.Max()); bdr1 = 0;
for (int i=0; i<phi1_attr.Size(); i++)
{
bdr1[phi1_attr[i]-1] = 1;
}
phi_h1.ProjectBdrCoefficient(one, bdr1);
// Solve the linear system using algebraic multigrid
{
if (myid == 0)
{
cout << "\nSolving for electric potential "
<< "using CG with AMG" << endl;
}
OperatorPtr A;
Vector B, X;
a_h1.FormLinearSystem(ess_bdr_tdof_phi, phi_h1, b_h1, A, X, B);
HypreBoomerAMG prec;
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
cg.SetPreconditioner(prec);
cg.SetOperator(*A);
cg.Mult(B, X);
a_h1.RecoverFEMSolution(X, b_h1, phi_h1);
}
{
int num_procs = fes_cond_h1.GetNRanks();
char vishost[] = "localhost";
int visport = 19916;
socketstream port_sock(vishost, visport);
port_sock << "parallel " << num_procs << " " << myid << "\n";
port_sock.precision(8);
port_sock << "solution\n" << pmesh_cond << phi_h1
<< "window_title 'Conductor Potential'"
<< "window_geometry 0 0 400 350" << flush;
}
// Solve for the current density J = -sigma Grad phi with boundary conditions
// J.n = 0 on the walls of the conductor but not on the ports where phi=0 and
// phi=1.
// J will be computed in H(div) so we need an RT mass matrix
ParBilinearForm m_rt(&fes_cond_rt);
m_rt.AddDomainIntegrator(new VectorFEMassIntegrator);
m_rt.Assemble();
// Assemble the (sigma Grad phi) operator
ParMixedBilinearForm d_h1(&fes_cond_h1, &fes_cond_rt);
d_h1.AddDomainIntegrator(new MixedVectorGradientIntegrator(sigmaCoef));
d_h1.Assemble();
// Compute the r.h.s, b_rt = sigma E = -sigma Grad phi
ParLinearForm b_rt(&fes_cond_rt);
d_h1.Mult(phi_h1, b_rt);
b_rt *= -1.0;
// Apply the necessary boundary conditions and solve for J in H(div)
HYPRE_BigInt glb_size_rt = fes_cond_rt.GlobalTrueVSize();
if (myid == 0)
{
cout << "\nSolving for current density in H(Div) "
<< "using diagonally scaled CG" << endl;
cout << "Size of linear system: "
<< glb_size_rt << endl;
}
Array<int> ess_bdr_tdof_rt;
OperatorPtr M;
Vector B, X;
fes_cond_rt.GetEssentialTrueDofs(ess_bdr_j, ess_bdr_tdof_rt);
j_cond = 0.0;
m_rt.FormLinearSystem(ess_bdr_tdof_rt, j_cond, b_rt, M, X, B);
HypreDiagScale prec;
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
cg.SetPreconditioner(prec);
cg.SetOperator(*M);
cg.Mult(B, X);
m_rt.RecoverFEMSolution(X, b_rt, j_cond);
}
+451
View File
@@ -0,0 +1,451 @@
// MFEM Example 36
//
// Compile with: make ex36
//
// Sample runs: ex36
//
// Description: This example code demonstrates the use of MFEM to define a
// discontinuous Galerkin (DG) finite element discretization of
// the Laplace problem -Delta u = f with Dirichlet boundary
// conditions. Finite element spaces of any order, including zero
// on regular grids, are supported. The example highlights the
// use of coupling solution domains though custom physics defined
// on internal boundaries.
//
// We recommend viewing examples 1, 14, and 34 before viewing this
// example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
class InteriorMassIntegrator : public BilinearFormIntegrator
{
public:
InteriorMassIntegrator(Coefficient &Q)
: Q(Q)
{}
void AssembleFaceMatrix(const FiniteElement &el1,
const FiniteElement &el2,
FaceElementTransformations &trans,
DenseMatrix &elmat) override;
using BilinearFormIntegrator::AssembleFaceMatrix;
private:
Coefficient &Q;
#ifndef MFEM_THREAD_SAFE
Vector shape1;
Vector shape2;
DenseMatrix elmat11;
DenseMatrix elmat12;
DenseMatrix elmat21;
DenseMatrix elmat22;
#endif
};
Mesh generate_mesh(int ref, int internal_bdr_attr = 5);
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
int ref_levels = 0;
int order = 1;
int sol_order = 3;
double jump = -2;
double sigma = -1.0;
double kappa = -1.0;
double eta = 0.0;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) >= 0.");
args.AddOption(&sigma, "-s", "--sigma",
"One of the three DG penalty parameters, typically +1/-1."
" See the documentation of class DGDiffusionIntegrator.");
args.AddOption(&kappa, "-k", "--kappa",
"One of the three DG penalty parameters, should be positive."
" Negative values are replaced with (order+1)^2.");
args.AddOption(&eta, "-e", "--eta", "BR2 penalty parameter.");
args.AddOption(&sol_order, "-so", "--solution_order",
"Polynomial order of the exact solution >= 0.");
args.AddOption(&jump, "-j", "--jump",
"Value of the discontinuity between the material regions.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
if (kappa < 0)
{
kappa = (order+1)*(order+1);
}
if (sol_order < 0)
{
sol_order = 1;
}
args.PrintOptions(cout);
// 2. Construct the (serial) mesh and refine it if requested.
auto mesh = generate_mesh(ref_levels);
int dim = mesh.Dimension();
if (mesh.NURBSext)
{
mesh.SetCurvature(max(order, 1));
}
// 3. Define a finite element space on the mesh. Here we use discontinuous
// finite elements of the specified order >= 0.
DG_FECollection fec(order, dim);
FiniteElementSpace fespace(&mesh, &fec);
cout << "Number of unknowns: " << fespace.GetVSize() << endl;
// 4. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system.
LinearForm b(&fespace);
Array<int> p1_attr_marker(mesh.attributes.Max());
p1_attr_marker = 0;
p1_attr_marker[0] = 1;
FunctionCoefficient p1_source([sol_order](const Vector &p)
{
const double x = p(0);
const double val = -(sol_order - 1)*sol_order*pow(x, sol_order-2);
return val;
});
b.AddDomainIntegrator(new DomainLFIntegrator(p1_source), p1_attr_marker);
Array<int> p2_attr_marker(mesh.attributes.Max());
p2_attr_marker = 0;
p2_attr_marker[1] = 1;
FunctionCoefficient p2_source([sol_order](const Vector &p)
{
const double x = p(0);
double val = -(sol_order - 1)*sol_order*pow(x - 2, sol_order-2);
if (sol_order % 2 == 0)
{
val *= -1.0;
}
return val;
});
b.AddDomainIntegrator(new DomainLFIntegrator(p2_source), p2_attr_marker);
ConstantCoefficient one(1.0);
Array<int> p1_bdr_attr_marker(mesh.bdr_attributes.Max());
p1_bdr_attr_marker = 0;
p1_bdr_attr_marker[0] = 1;
ConstantCoefficient left_bc_val(0.0);
b.AddBdrFaceIntegrator(
new DGDirichletLFIntegrator(left_bc_val, one, sigma, kappa),
p1_bdr_attr_marker);
Array<int> p2_bdr_attr_marker(mesh.bdr_attributes.Max());
p2_bdr_attr_marker = 0;
p2_bdr_attr_marker[1] = 1;
ConstantCoefficient right_bc_val(2.0 + jump);
b.AddBdrFaceIntegrator(
new DGDirichletLFIntegrator(right_bc_val, one, sigma, kappa),
p2_bdr_attr_marker);
b.Assemble();
// 5. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero.
GridFunction x(&fespace);
x = 0.0;
// 6. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator and the interior and boundary DG face integrators.
// Note that boundary conditions are imposed weakly in the form, so there
// is no need for dof elimination. After assembly and finalizing we
// extract the corresponding sparse matrix A.
BilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator(one));
a.AddInteriorFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
a.AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa),
p1_bdr_attr_marker);
a.AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa),
p2_bdr_attr_marker);
if (eta > 0)
{
a.AddInteriorFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta));
a.AddBdrFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta));
}
// 7. Negate the DG interface terms along the internal boundary so that the
// only coupling between domains is from the chosen model (constant flux
// in this case).
Array<int> internal_bdr_attr_marker(mesh.bdr_attributes.Max());
internal_bdr_attr_marker = 0;
internal_bdr_attr_marker[4] = 1;
ProductCoefficient neg_one(-1.0, one);
a.AddInternalBoundaryFaceIntegrator(new DGDiffusionIntegrator(neg_one, sigma,
kappa),
internal_bdr_attr_marker);
if (eta > 0)
{
a.AddInternalBoundaryFaceIntegrator(new DGDiffusionBR2Integrator(fespace,
neg_one, eta),
internal_bdr_attr_marker);
}
ConstantCoefficient mass_coeff(sol_order / jump);
a.AddInternalBoundaryFaceIntegrator(new InteriorMassIntegrator(mass_coeff),
internal_bdr_attr_marker);
a.Assemble();
a.Finalize();
const SparseMatrix &A = a.SpMat();
#ifndef MFEM_USE_SUITESPARSE
// 8. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system Ax=b with PCG in the symmetric case, and GMRES in the
// non-symmetric one.
GSSmoother M(A);
if (sigma == -1.0 && !(jump < 0))
{
PCG(A, M, b, x, 1, 500, 1e-12, 0.0);
}
else
{
GMRES(A, M, b, x, 1, 500, 500, 1e-24, 0.0);
}
#else
// 8. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(b, x);
#endif
// 9. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh.Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
// 10. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << mesh << x << flush;
}
return 0;
}
void InteriorMassIntegrator::AssembleFaceMatrix(
const FiniteElement &el1,
const FiniteElement &el2,
FaceElementTransformations &trans,
DenseMatrix &elmat)
{
int ndof1 = el1.GetDof();
int ndof2 = el2.GetDof();
int ndof = ndof1 + ndof2;
#ifdef MFEM_THREAD_SAFE
Vector shape1;
Vector shape2;
DenseMatrix elmat11;
DenseMatrix elmat12;
DenseMatrix elmat21;
DenseMatrix elmat22;
#endif
shape1.SetSize(ndof1);
shape2.SetSize(ndof2);
elmat11.SetSize(ndof1);
elmat12.SetSize(ndof1, ndof2);
elmat21.SetSize(ndof2, ndof1);
elmat22.SetSize(ndof2);
const auto *ir = IntRule;
if (ir == NULL)
{
int order = 2 * max(el1.GetOrder(), el2.GetOrder());
ir = &IntRules.Get(trans.GetGeometryType(), order);
}
elmat.SetSize(ndof);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const auto &ip = ir->IntPoint(i);
// Set the integration point in the face and the neighboring element
trans.SetAllIntPoints(&ip);
const double w = ip.weight * trans.Weight();
// Access the neighboring element's integration point
const auto &eip1 = trans.GetElement1IntPoint();
const auto &eip2 = trans.GetElement2IntPoint();
el1.CalcShape(eip1, shape1);
el2.CalcShape(eip2, shape2);
const double Q_val = Q.Eval(trans, ip);
elmat11 = 0.0;
AddMult_a_VVt(Q_val * w, shape1, elmat11);
elmat12 = 0.0;
AddMult_a_VWt(-Q_val * w, shape2, shape1, elmat12);
elmat21 = 0.0;
AddMult_a_VWt(-Q_val * w, shape1, shape2, elmat21);
elmat22 = 0.0;
AddMult_a_VVt(Q_val * w, shape2, elmat22);
for (int j = 0; j < ndof1; ++j)
{
for (int k = 0; k < ndof1; ++k)
{
elmat(j, k) += elmat11(j, k);
}
}
for (int j = 0; j < ndof1; ++j)
{
for (int k = 0; k < ndof2; ++k)
{
elmat(j, k + ndof1) += elmat12(j, k);
elmat(k + ndof1, j) += elmat21(k, j);
}
}
for (int j = 0; j < ndof2; ++j)
{
for (int k = 0; k < ndof2; ++k)
{
elmat(j + ndof1, k + ndof1) += elmat22(j, k);
}
}
}
}
Mesh generate_mesh(int ref, int internal_bdr_attr)
{
int nxy = 4 * (ref+1);
auto mesh = Mesh::MakeCartesian2D(nxy, nxy, Element::TRIANGLE, true, 2.0, 1.0);
// auto mesh = Mesh::MakeCartesian2D(nxy, nxy, Element::QUADRILATERAL, true, 2.0, 1.0);
// assign element attributes to left and right sides
for (int i = 0; i < mesh.GetNE(); ++i)
{
auto *elem = mesh.GetElement(i);
Array<int> verts;
elem->GetVertices(verts);
bool left = true;
for (int j = 0; j < verts.Size(); ++j)
{
auto *vtx = mesh.GetVertex(verts[j]);
if (vtx[0] <= 1.0)
{
continue;
}
else
{
left = false;
}
}
if (left)
{
elem->SetAttribute(1);
}
else
{
elem->SetAttribute(2);
}
}
// assign boundary element attributes to left and right sides
for (int i = 0; i < mesh.GetNBE(); ++i)
{
auto *elem = mesh.GetBdrElement(i);
Array<int> verts;
elem->GetVertices(verts);
bool left = true;
bool right = true;
bool top = true;
bool bottom = true;
for (int j = 0; j < verts.Size(); ++j)
{
auto *vtx = mesh.GetVertex(verts[j]);
left = left && abs(vtx[0] - 0.0) < 1e-12;
right = right && abs(vtx[0] - 2.0) < 1e-12;
top = top && abs(vtx[1] - 1.0) < 1e-12;
bottom = bottom && abs(vtx[1] - 0.0) < 1e-12;
}
if (left)
{
elem->SetAttribute(1);
}
else if (right)
{
elem->SetAttribute(2);
}
else if (top)
{
elem->SetAttribute(3);
}
else if (bottom)
{
elem->SetAttribute(4);
}
}
// add internal boundary elements
for (int i = 0; i < mesh.GetNumFaces(); ++i)
{
int e1, e2;
mesh.GetFaceElements(i, &e1, &e2);
if (e1 >= 0 && e2 >= 0 && mesh.GetAttribute(e1) != mesh.GetAttribute(e2))
{
// This is the internal face between attributes.
auto *new_elem = mesh.GetFace(i)->Duplicate(&mesh);
new_elem->SetAttribute(internal_bdr_attr);
mesh.AddBdrElement(new_elem);
}
}
mesh.FinalizeTopology(); // Finalize to build relevant tables
mesh.Finalize();
mesh.SetAttributes();
return mesh;
}
-815
View File
@@ -1,815 +0,0 @@
// MFEM Example 35 - Parallel Version
//
// Compile with: make ex35p
//
// Sample runs: mpirun -np 4 ex35p -p 0 -o 2
// mpirun -np 4 ex35p -p 0 -o 2 -pbc '22 23 24' -em 0
// mpirun -np 4 ex35p -p 1 -o 1 -rp 2
// mpirun -np 4 ex35p -p 1 -o 2
// mpirun -np 4 ex35p -p 2 -o 1 -rp 2 -c 15
//
// Device sample runs:
//
// Description: This example code demonstrates the use of MFEM to define and
// solve simple complex-valued linear systems. It implements three
// variants of a damped harmonic oscillator:
//
// 1) A scalar H1 field
// -Div(a Grad u) - omega^2 b u + i omega c u = 0
//
// 2) A vector H(Curl) field
// Curl(a Curl u) - omega^2 b u + i omega c u = 0
//
// 3) A vector H(Div) field
// -Grad(a Div u) - omega^2 b u + i omega c u = 0
//
// In each case the field is driven by a forced oscillation, with
// angular frequency omega, imposed at the boundary or a portion
// of the boundary. The spatial variation of the boundary
// condition is computed as an eigenmode of an appropriate
// operator defined on a portion of the boundary i.e. a port
// boundary condition.
//
// In electromagnetics the coefficients are typically named the
// permeability, mu = 1/a, permittivity, epsilon = b, and
// conductivity, sigma = c. The user can specify these constants
// using either set of names.
//
// This example demonstrates how to transfer fields computed on a
// boundary generated SubMesh to the full mesh and apply them as
// boundary conditions. The default mesh and corresponding
// boundary attributes were chosen to verify proper behavior on
// both triangular and quadrilateral faces of tetrahedral,
// wedge-shaped, and hexahedral elements.
//
// The example also demonstrates how to display a time-varying
// solution as a sequence of fields sent to a single GLVis socket.
//
// We recommend viewing examples 11, 13, and 22 before viewing
// this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
static real_t mu_ = 1.0;
static real_t epsilon_ = 1.0;
static real_t sigma_ = 2.0;
void SetPortBC(int prob, int dim, int mode, ParGridFunction &port_bc);
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();
// 2. Parse command-line options.
const char *mesh_file = "../data/fichera-mixed.mesh";
int ser_ref_levels = 1;
int par_ref_levels = 1;
int order = 1;
Array<int> port_bc_attr;
int prob = 0;
int mode = 1;
real_t freq = -1.0;
real_t omega = 2.0 * M_PI;
real_t a_coef = 0.0;
bool herm_conv = true;
bool slu_solver = false;
bool visualization = 1;
bool mixed = true;
bool pa = false;
const char *device_config = "cpu";
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
"Number of times to refine the mesh uniformly in parallel.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: H_1, 1: H(Curl), or 2: H(Div) "
"damped harmonic oscillator.");
args.AddOption(&mode, "-em", "--eigenmode",
"Choose the index of the port eigenmode.");
args.AddOption(&a_coef, "-a", "--stiffness-coef",
"Stiffness coefficient (spring constant or 1/mu).");
args.AddOption(&epsilon_, "-b", "--mass-coef",
"Mass coefficient (or epsilon).");
args.AddOption(&sigma_, "-c", "--damping-coef",
"Damping coefficient (or sigma).");
args.AddOption(&mu_, "-mu", "--permeability",
"Permeability of free space (or 1/(spring constant)).");
args.AddOption(&epsilon_, "-eps", "--permittivity",
"Permittivity of free space (or mass constant).");
args.AddOption(&sigma_, "-sigma", "--conductivity",
"Conductivity (or damping constant).");
args.AddOption(&freq, "-f", "--frequency",
"Frequency (in Hz).");
args.AddOption(&port_bc_attr, "-pbc", "--port-bc-attr",
"Attributes of port boundary condition");
args.AddOption(&herm_conv, "-herm", "--hermitian", "-no-herm",
"--no-hermitian", "Use convention for Hermitian operators.");
#ifdef MFEM_USE_SUPERLU
args.AddOption(&slu_solver, "-slu", "--superlu", "-no-slu",
"--no-superlu", "Use the SuperLU Solver.");
#endif
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&mixed, "-mixed", "--mixed-mesh", "-hex",
"--hex-mesh", "Mixed mesh of hexahedral mesh.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (!mixed || pa)
{
mesh_file = "../data/fichera.mesh";
}
if ( a_coef != 0.0 )
{
mu_ = 1.0 / a_coef;
}
if ( freq > 0.0 )
{
omega = 2.0 * M_PI * freq;
}
if (port_bc_attr.Size() == 0 &&
(strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0))
{
port_bc_attr.SetSize(4);
port_bc_attr[0] = 7;
port_bc_attr[1] = 8;
port_bc_attr[2] = 11;
port_bc_attr[3] = 12;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
MFEM_VERIFY(prob >= 0 && prob <=2,
"Unrecognized problem type: " << prob);
ComplexOperator::Convention conv =
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
// 3. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 5. Refine the serial mesh on all processors to increase the resolution.
for (int l = 0; l < ser_ref_levels; l++)
{
mesh->UniformRefinement();
}
// 6a. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
delete mesh;
for (int l = 0; l < par_ref_levels; l++)
{
pmesh.UniformRefinement();
}
// 6b. Extract a submesh covering a portion of the boundary
ParSubMesh pmesh_port(ParSubMesh::CreateFromBoundary(pmesh, port_bc_attr));
// 7a. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange, Nedelec, or Raviart-Thomas finite elements
// of the specified order.
if (dim == 1 && prob != 0 )
{
if (myid == 0)
{
cout << "Switching to problem type 0, H1 basis functions, "
<< "for 1 dimensional mesh." << endl;
}
prob = 0;
}
FiniteElementCollection *fec = NULL;
switch (prob)
{
case 0: fec = new H1_FECollection(order, dim); break;
case 1: fec = new ND_FECollection(order, dim); break;
case 2: fec = new RT_FECollection(order - 1, dim); break;
default: break; // This should be unreachable
}
ParFiniteElementSpace fespace(&pmesh, fec);
HYPRE_BigInt size = fespace.GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7b. Define a parallel finite element space on the sub-mesh. Here we
// use continuous Lagrange, Nedelec, or L2 finite elements of
// the specified order.
FiniteElementCollection *fec_port = NULL;
switch (prob)
{
case 0: fec_port = new H1_FECollection(order, dim-1); break;
case 1:
if (dim == 3)
{
fec_port = new ND_FECollection(order, dim-1);
}
else
{
fec_port = new L2_FECollection(order - 1, dim-1,
BasisType::GaussLegendre,
FiniteElement::INTEGRAL);
}
break;
case 2: fec_port = new L2_FECollection(order - 1, dim-1,
BasisType::GaussLegendre,
FiniteElement::INTEGRAL); break;
default: break; // This should be unreachable
}
ParFiniteElementSpace fespace_port(&pmesh_port, fec_port);
HYPRE_BigInt size_port = fespace_port.GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element port BC unknowns: " << size_port
<< endl;
}
// 8a. Define a parallel grid function on the SubMesh which will contain
// the field to be applied as a port boundary condition.
ParGridFunction port_bc(&fespace_port);
port_bc = 0.0;
SetPortBC(prob, dim, mode, port_bc);
// 8b. Save the SubMesh and associated port boundary condition in parallel.
// This output can be viewed later using GLVis:
// "glvis -np <np> -m port_mesh -g port_mode"
{
ostringstream mesh_name, port_name;
mesh_name << "port_mesh." << setfill('0') << setw(6) << myid;
port_name << "port_mode." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh_port.Print(mesh_ofs);
ofstream port_ofs(port_name.str().c_str());
port_ofs.precision(8);
port_bc.Save(port_ofs);
}
// 8c. Send the port bc, computed on the SubMesh, to a GLVis server.
if (visualization && dim == 3)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream port_sock(vishost, visport);
port_sock << "parallel " << num_procs << " " << myid << "\n";
port_sock.precision(8);
port_sock << "solution\n" << pmesh_port << port_bc
<< "window_title 'Port BC'"
<< "window_geometry 0 0 400 350" << flush;
}
// 9. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// using an eigenmode of the appropriate type computed on the SubMesh.
Array<int> ess_tdof_list;
Array<int> ess_bdr;
if (pmesh.bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh.bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 10. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system.
ParComplexLinearForm b(&fespace, conv);
b.Vector::operator=(0.0);
// 11a. Define the solution vector u as a parallel complex finite element
// grid function corresponding to fespace. Initialize u to equal zero.
ParComplexGridFunction u(&fespace);
u = 0.0;
pmesh_port.Transfer(port_bc, u.real());
// 11b. Send the transferred port bc field to a GLVis server.
{
ParGridFunction full_bc(&fespace);
ParTransferMap port_to_full(port_bc, full_bc);
full_bc = 0.0;
port_to_full.Transfer(port_bc, full_bc);
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream full_sock(vishost, visport);
full_sock << "parallel " << num_procs << " " << myid << "\n";
full_sock.precision(8);
full_sock << "solution\n" << pmesh << full_bc
<< "window_title 'Transferred BC'"
<< "window_geometry 400 0 400 350"<< flush;
}
}
// 12. Set up the parallel sesquilinear form a(.,.) on the finite element
// space corresponding to the damped harmonic oscillator operator of the
// appropriate type:
//
// 0) A scalar H1 field
// -Div(a Grad) - omega^2 b + i omega c
//
// 1) A vector H(Curl) field
// Curl(a Curl) - omega^2 b + i omega c
//
// 2) A vector H(Div) field
// -Grad(a Div) - omega^2 b + i omega c
//
ConstantCoefficient stiffnessCoef(1.0/mu_);
ConstantCoefficient massCoef(-omega * omega * epsilon_);
ConstantCoefficient lossCoef(omega * sigma_);
ConstantCoefficient negMassCoef(omega * omega * epsilon_);
ParSesquilinearForm a(&fespace, conv);
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
switch (prob)
{
case 0:
a.AddDomainIntegrator(new DiffusionIntegrator(stiffnessCoef),
NULL);
a.AddDomainIntegrator(new MassIntegrator(massCoef),
new MassIntegrator(lossCoef));
break;
case 1:
a.AddDomainIntegrator(new CurlCurlIntegrator(stiffnessCoef),
NULL);
a.AddDomainIntegrator(new VectorFEMassIntegrator(massCoef),
new VectorFEMassIntegrator(lossCoef));
break;
case 2:
a.AddDomainIntegrator(new DivDivIntegrator(stiffnessCoef),
NULL);
a.AddDomainIntegrator(new VectorFEMassIntegrator(massCoef),
new VectorFEMassIntegrator(lossCoef));
break;
default: break; // This should be unreachable
}
// 13. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, etc.
a.Assemble();
OperatorHandle A;
Vector B, U;
a.FormLinearSystem(ess_tdof_list, u, b, A, U, B);
if (myid == 0)
{
cout << "Size of linear system: "
<< 2 * size << endl << endl;
}
if (!slu_solver)
{
// 14a. Set up the parallel bilinear form for the preconditioner
// corresponding to the appropriate operator
//
// 0) A scalar H1 field
// -Div(a Grad) - omega^2 b + i omega c
//
// 1) A vector H(Curl) field
// Curl(a Curl) + omega^2 b + i omega c
//
// 2) A vector H(Div) field
// -Grad(a Div) - omega^2 b + i omega c
ParBilinearForm pcOp(&fespace);
if (pa) { pcOp.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
switch (prob)
{
case 0:
pcOp.AddDomainIntegrator(new DiffusionIntegrator(stiffnessCoef));
pcOp.AddDomainIntegrator(new MassIntegrator(massCoef));
pcOp.AddDomainIntegrator(new MassIntegrator(lossCoef));
break;
case 1:
pcOp.AddDomainIntegrator(new CurlCurlIntegrator(stiffnessCoef));
pcOp.AddDomainIntegrator(new VectorFEMassIntegrator(negMassCoef));
pcOp.AddDomainIntegrator(new VectorFEMassIntegrator(lossCoef));
break;
case 2:
pcOp.AddDomainIntegrator(new DivDivIntegrator(stiffnessCoef));
pcOp.AddDomainIntegrator(new VectorFEMassIntegrator(massCoef));
pcOp.AddDomainIntegrator(new VectorFEMassIntegrator(lossCoef));
break;
default: break; // This should be unreachable
}
pcOp.Assemble();
// 14b. Define and apply a parallel FGMRES solver for AU=B with a block
// diagonal preconditioner based on the appropriate multigrid
// preconditioner from hypre.
Array<int> blockTrueOffsets;
blockTrueOffsets.SetSize(3);
blockTrueOffsets[0] = 0;
blockTrueOffsets[1] = A->Height() / 2;
blockTrueOffsets[2] = A->Height() / 2;
blockTrueOffsets.PartialSum();
BlockDiagonalPreconditioner BDP(blockTrueOffsets);
Operator * pc_r = NULL;
Operator * pc_i = NULL;
if (pa)
{
pc_r = new OperatorJacobiSmoother(pcOp, ess_tdof_list);
}
else
{
OperatorHandle PCOp;
pcOp.FormSystemMatrix(ess_tdof_list, PCOp);
switch (prob)
{
case 0:
pc_r = new HypreBoomerAMG(*PCOp.As<HypreParMatrix>());
break;
case 1:
pc_r = new HypreAMS(*PCOp.As<HypreParMatrix>(), &fespace);
break;
case 2:
if (dim == 2 )
{
pc_r = new HypreAMS(*PCOp.As<HypreParMatrix>(), &fespace);
}
else
{
pc_r = new HypreADS(*PCOp.As<HypreParMatrix>(), &fespace);
}
break;
default: break; // This should be unreachable
}
}
pc_i = new ScaledOperator(pc_r,
(conv == ComplexOperator::HERMITIAN) ?
-1.0:1.0);
BDP.SetDiagonalBlock(0, pc_r);
BDP.SetDiagonalBlock(1, pc_i);
BDP.owns_blocks = 1;
FGMRESSolver fgmres(MPI_COMM_WORLD);
fgmres.SetPreconditioner(BDP);
fgmres.SetOperator(*A.Ptr());
fgmres.SetRelTol(1e-6);
fgmres.SetMaxIter(1000);
fgmres.SetPrintLevel(1);
fgmres.Mult(B, U);
}
#ifdef MFEM_USE_SUPERLU
else
{
// 14. Solve using a direct solver
// Transform to monolithic HypreParMatrix
HypreParMatrix *A_hyp = A.As<ComplexHypreParMatrix>()->GetSystemMatrix();
SuperLURowLocMatrix SA(*A_hyp);
SuperLUSolver superlu(MPI_COMM_WORLD);
superlu.SetPrintStatistics(true);
superlu.SetSymmetricPattern(false);
superlu.SetColumnPermutation(superlu::PARMETIS);
superlu.SetOperator(SA);
superlu.Mult(B, U);
delete A_hyp;
}
#endif
// 15. Recover the parallel grid function corresponding to U. This is the
// local finite element solution on each processor.
a.RecoverFEMSolution(U, b, u);
// 16. Save the refined mesh and the solution in parallel. This output can be
// viewed later using GLVis: "glvis -np <np> -m mesh -g sol_r" or
// "glvis -np <np> -m mesh -g sol_i".
{
ostringstream mesh_name, sol_r_name, sol_i_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_r_name << "sol_r." << setfill('0') << setw(6) << myid;
sol_i_name << "sol_i." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh.Print(mesh_ofs);
ofstream sol_r_ofs(sol_r_name.str().c_str());
ofstream sol_i_ofs(sol_i_name.str().c_str());
sol_r_ofs.precision(8);
sol_i_ofs.precision(8);
u.real().Save(sol_r_ofs);
u.imag().Save(sol_i_ofs);
}
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock_r(vishost, visport);
sol_sock_r << "parallel " << num_procs << " " << myid << "\n";
sol_sock_r.precision(8);
sol_sock_r << "solution\n" << pmesh << u.real()
<< "window_title 'Solution: Real Part'"
<< "window_geometry 800 0 400 350" << flush;
MPI_Barrier(MPI_COMM_WORLD);
socketstream sol_sock_i(vishost, visport);
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i.precision(8);
sol_sock_i << "solution\n" << pmesh << u.imag()
<< "window_title 'Solution: Imaginary Part'"
<< "window_geometry 1200 0 400 350" << flush;
}
if (visualization)
{
ParGridFunction u_t(&fespace);
u_t = u.real();
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << u_t
<< "window_title 'Harmonic Solution (t = 0.0 T)'"
<< "window_geometry 0 432 600 450"
<< "pause\n" << flush;
if (myid == 0)
cout << "GLVis visualization paused."
<< " Press space (in the GLVis window) to resume it.\n";
int num_frames = 32;
int i = 0;
while (sol_sock)
{
real_t t = (real_t)(i % num_frames) / num_frames;
ostringstream oss;
oss << "Harmonic Solution (t = " << t << " T)";
add(cos( 2.0 * M_PI * t), u.real(),
sin(-2.0 * M_PI * t), u.imag(), u_t);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock << "solution\n" << pmesh << u_t
<< "window_title '" << oss.str() << "'" << flush;
i++;
}
}
// 18. Free the used memory.
delete fec_port;
delete fec;
return 0;
}
/**
Solves the eigenvalue problem -Div(Grad x) = lambda x with homogeneous
Dirichlet boundary conditions on the boundary of the domain. Returns mode
number "mode" (counting from zero) in the ParGridFunction "x".
*/
void ScalarWaveGuide(int mode, ParGridFunction &x)
{
int nev = std::max(mode + 2, 5);
int seed = 75;
ParFiniteElementSpace &fespace = *x.ParFESpace();
ParMesh &pmesh = *fespace.GetParMesh();
Array<int> ess_bdr;
if (pmesh.bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh.bdr_attributes.Max());
ess_bdr = 1;
}
ParBilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator);
a.Assemble();
a.EliminateEssentialBCDiag(ess_bdr, 1.0);
a.Finalize();
ParBilinearForm m(&fespace);
m.AddDomainIntegrator(new MassIntegrator);
m.Assemble();
// shift the eigenvalue corresponding to eliminated dofs to a large value
m.EliminateEssentialBCDiag(ess_bdr, numeric_limits<real_t>::min());
m.Finalize();
HypreParMatrix *A = a.ParallelAssemble();
HypreParMatrix *M = m.ParallelAssemble();
HypreBoomerAMG amg(*A);
amg.SetPrintLevel(0);
HypreLOBPCG lobpcg(MPI_COMM_WORLD);
lobpcg.SetNumModes(nev);
lobpcg.SetRandomSeed(seed);
lobpcg.SetPreconditioner(amg);
lobpcg.SetMaxIter(200);
lobpcg.SetTol(1e-8);
lobpcg.SetPrecondUsageMode(1);
lobpcg.SetPrintLevel(1);
lobpcg.SetMassMatrix(*M);
lobpcg.SetOperator(*A);
lobpcg.Solve();
x = lobpcg.GetEigenvector(mode);
delete A;
delete M;
}
/**
Solves the eigenvalue problem -Curl(Curl x) = lambda x with homogeneous
Dirichlet boundary conditions, on the tangential component of x, on the
boundary of the domain. Returns mode number "mode" (counting from zero) in
the ParGridFunction "x".
*/
void VectorWaveGuide(int mode, ParGridFunction &x)
{
int nev = std::max(mode + 2, 5);
ParFiniteElementSpace &fespace = *x.ParFESpace();
ParMesh &pmesh = *fespace.GetParMesh();
Array<int> ess_bdr;
if (pmesh.bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh.bdr_attributes.Max());
ess_bdr = 1;
}
ParBilinearForm a(&fespace);
a.AddDomainIntegrator(new CurlCurlIntegrator);
a.Assemble();
a.EliminateEssentialBCDiag(ess_bdr, 1.0);
a.Finalize();
ParBilinearForm m(&fespace);
m.AddDomainIntegrator(new VectorFEMassIntegrator);
m.Assemble();
// shift the eigenvalue corresponding to eliminated dofs to a large value
m.EliminateEssentialBCDiag(ess_bdr, numeric_limits<real_t>::min());
m.Finalize();
HypreParMatrix *A = a.ParallelAssemble();
HypreParMatrix *M = m.ParallelAssemble();
HypreAMS ams(*A,&fespace);
ams.SetPrintLevel(0);
ams.SetSingularProblem();
HypreAME ame(MPI_COMM_WORLD);
ame.SetNumModes(nev);
ame.SetPreconditioner(ams);
ame.SetMaxIter(100);
ame.SetTol(1e-8);
ame.SetPrintLevel(1);
ame.SetMassMatrix(*M);
ame.SetOperator(*A);
ame.Solve();
x = ame.GetEigenvector(mode);
delete A;
delete M;
}
/**
Solves the eigenvalue problem -Div(Grad x) = lambda x with homogeneous
Neumann boundary conditions on the boundary of the domain. Returns mode
number "mode" (counting from zero) in the ParGridFunction "x_l2". Note that
mode 0 is a constant field so higher mode numbers are often more
interesting. The eigenmode is solved using continuous H1 basis of the
appropriate order and then projected onto the L2 basis and returned.
*/
void PseudoScalarWaveGuide(int mode, ParGridFunction &x_l2)
{
int nev = std::max(mode + 2, 5);
int seed = 75;
ParFiniteElementSpace &fespace_l2 = *x_l2.ParFESpace();
ParMesh &pmesh = *fespace_l2.GetParMesh();
int order_l2 = fespace_l2.FEColl()->GetOrder();
H1_FECollection fec(order_l2+1, pmesh.Dimension());
ParFiniteElementSpace fespace(&pmesh, &fec);
ParGridFunction x(&fespace);
x = 0.0;
GridFunctionCoefficient xCoef(&x);
if (mode == 0)
{
x = 1.0;
x_l2.ProjectCoefficient(xCoef);
return;
}
ParBilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator);
a.AddDomainIntegrator(new MassIntegrator); // Shift eigenvalues by 1
a.Assemble();
a.Finalize();
ParBilinearForm m(&fespace);
m.AddDomainIntegrator(new MassIntegrator);
m.Assemble();
m.Finalize();
HypreParMatrix *A = a.ParallelAssemble();
HypreParMatrix *M = m.ParallelAssemble();
HypreBoomerAMG amg(*A);
amg.SetPrintLevel(0);
HypreLOBPCG lobpcg(MPI_COMM_WORLD);
lobpcg.SetNumModes(nev);
lobpcg.SetRandomSeed(seed);
lobpcg.SetPreconditioner(amg);
lobpcg.SetMaxIter(200);
lobpcg.SetTol(1e-8);
lobpcg.SetPrecondUsageMode(1);
lobpcg.SetPrintLevel(1);
lobpcg.SetMassMatrix(*M);
lobpcg.SetOperator(*A);
lobpcg.Solve();
x = lobpcg.GetEigenvector(mode);
x_l2.ProjectCoefficient(xCoef);
delete A;
delete M;
}
// Compute eigenmode "mode" of either a Dirichlet or Neumann Laplacian or of a
// Dirichlet curl curl operator based on the problem type and dimension of the
// domain.
void SetPortBC(int prob, int dim, int mode, ParGridFunction &port_bc)
{
switch (prob)
{
case 0:
ScalarWaveGuide(mode, port_bc);
break;
case 1:
if (dim == 3)
{
VectorWaveGuide(mode, port_bc);
}
else
{
PseudoScalarWaveGuide(mode, port_bc);
}
break;
case 2:
PseudoScalarWaveGuide(mode, port_bc);
break;
}
}
-459
View File
@@ -1,459 +0,0 @@
// MFEM Example 36
//
// Compile with: make ex36
//
// Sample runs: ex36 -o 2
// ex36 -o 2 -r 4
//
// Description: This example code demonstrates the use of MFEM to solve the
// bound-constrained energy minimization problem
//
// minimize ||∇u||² subject to u ≥ ϕ in H¹₀.
//
// This is known as the obstacle problem, and it is a simple
// mathematical model for contact mechanics.
//
// In this example, the obstacle ϕ is a half-sphere centered
// at the origin of a circular domain Ω. After solving to a
// specified tolerance, the numerical solution is compared to
// a closed-form exact solution to assess accuracy.
//
// The problem is discretized and solved using the proximal
// Galerkin finite element method, introduced by Keith and
// Surowiec [1].
//
// This example highlights the ability of MFEM to deliver high-
// order solutions to variation inequality problems and
// showcases how to set up and solve nonlinear mixed methods.
//
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
real_t spherical_obstacle(const Vector &pt);
real_t exact_solution_obstacle(const Vector &pt);
void exact_solution_gradient_obstacle(const Vector &pt, Vector &grad);
class LogarithmGridFunctionCoefficient : public Coefficient
{
protected:
GridFunction *u; // grid function
Coefficient *obstacle;
real_t min_val;
public:
LogarithmGridFunctionCoefficient(GridFunction &u_, Coefficient &obst_,
real_t min_val_=-36)
: u(&u_), obstacle(&obst_), min_val(min_val_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
};
class ExponentialGridFunctionCoefficient : public Coefficient
{
protected:
GridFunction *u;
Coefficient *obstacle;
real_t min_val;
real_t max_val;
public:
ExponentialGridFunctionCoefficient(GridFunction &u_, Coefficient &obst_,
real_t min_val_=0.0, real_t max_val_=1e6)
: u(&u_), obstacle(&obst_), min_val(min_val_), max_val(max_val_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
};
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
int order = 1;
int max_it = 10;
int ref_levels = 3;
real_t alpha = 1.0;
real_t tol = 1e-5;
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&ref_levels, "-r", "--refs",
"Number of h-refinements.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of iterations");
args.AddOption(&tol, "-tol", "--tol",
"Stopping criteria based on the difference between"
"successive solution updates");
args.AddOption(&alpha, "-step", "--step",
"Step size alpha");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the mesh from the mesh file.
const char *mesh_file = "../data/disc-nurbs.mesh";
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
// 3. Postprocess the mesh.
// 3A. Refine the mesh to increase the resolution.
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
// 3B. Interpolate the geometry after refinement to control geometry error.
// NOTE: Minimum second-order interpolation is used to improve the accuracy.
int curvature_order = max(order,2);
mesh.SetCurvature(curvature_order);
// 3C. Rescale the domain to a unit circle (radius = 1).
GridFunction *nodes = mesh.GetNodes();
real_t scale = 2*sqrt(2);
*nodes /= scale;
// 4. Define the necessary finite element spaces on the mesh.
H1_FECollection H1fec(order+1, dim);
FiniteElementSpace H1fes(&mesh, &H1fec);
L2_FECollection L2fec(order-1, dim);
FiniteElementSpace L2fes(&mesh, &L2fec);
cout << "Number of H1 finite element unknowns: "
<< H1fes.GetTrueVSize() << endl;
cout << "Number of L2 finite element unknowns: "
<< L2fes.GetTrueVSize() << endl;
Array<int> offsets(3);
offsets[0] = 0;
offsets[1] = H1fes.GetVSize();
offsets[2] = L2fes.GetVSize();
offsets.PartialSum();
BlockVector x(offsets), rhs(offsets);
x = 0.0; rhs = 0.0;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
Array<int> ess_bdr;
if (mesh.bdr_attributes.Size())
{
ess_bdr.SetSize(mesh.bdr_attributes.Max());
ess_bdr = 1;
}
// 6. Define an initial guess for the solution.
auto IC_func = [](const Vector &x)
{
real_t r0 = 1.0;
real_t rr = 0.0;
for (int i=0; i<x.Size(); i++)
{
rr += x(i)*x(i);
}
return r0*r0 - rr;
};
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
// 7. Define the solution vectors as a finite element grid functions
// corresponding to the fespaces.
GridFunction u_gf, delta_psi_gf;
u_gf.MakeRef(&H1fes,x,offsets[0]);
delta_psi_gf.MakeRef(&L2fes,x,offsets[1]);
delta_psi_gf = 0.0;
GridFunction u_old_gf(&H1fes);
GridFunction psi_old_gf(&L2fes);
GridFunction psi_gf(&L2fes);
u_old_gf = 0.0;
psi_old_gf = 0.0;
// 8. Define the function coefficients for the solution and use them to
// initialize the initial guess
FunctionCoefficient exact_coef(exact_solution_obstacle);
VectorFunctionCoefficient exact_grad_coef(dim,exact_solution_gradient_obstacle);
FunctionCoefficient IC_coef(IC_func);
ConstantCoefficient f(0.0);
FunctionCoefficient obstacle(spherical_obstacle);
u_gf.ProjectCoefficient(IC_coef);
u_old_gf = u_gf;
// 9. Initialize the slack variable ψₕ = ln(uₕ)
LogarithmGridFunctionCoefficient ln_u(u_gf, obstacle);
psi_gf.ProjectCoefficient(ln_u);
psi_old_gf = psi_gf;
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock;
if (visualization)
{
sol_sock.open(vishost,visport);
sol_sock.precision(8);
}
// 10. Iterate
int k;
int total_iterations = 0;
real_t increment_u = 0.1;
for (k = 0; k < max_it; k++)
{
GridFunction u_tmp(&H1fes);
u_tmp = u_old_gf;
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
int j;
for ( j = 0; j < 10; j++)
{
total_iterations++;
ConstantCoefficient alpha_cf(alpha);
LinearForm b0,b1;
b0.Update(&H1fes,rhs.GetBlock(0),0);
b1.Update(&L2fes,rhs.GetBlock(1),0);
ExponentialGridFunctionCoefficient exp_psi(psi_gf, zero);
ProductCoefficient neg_exp_psi(-1.0,exp_psi);
GradientGridFunctionCoefficient grad_u_old(&u_old_gf);
ProductCoefficient alpha_f(alpha, f);
GridFunctionCoefficient psi_cf(&psi_gf);
GridFunctionCoefficient psi_old_cf(&psi_old_gf);
SumCoefficient psi_old_minus_psi(psi_old_cf, psi_cf, 1.0, -1.0);
b0.AddDomainIntegrator(new DomainLFIntegrator(alpha_f));
b0.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
b0.Assemble();
b1.AddDomainIntegrator(new DomainLFIntegrator(exp_psi));
b1.AddDomainIntegrator(new DomainLFIntegrator(obstacle));
b1.Assemble();
BilinearForm a00(&H1fes);
a00.SetDiagonalPolicy(mfem::Operator::DIAG_ONE);
a00.AddDomainIntegrator(new DiffusionIntegrator(alpha_cf));
a00.Assemble();
a00.EliminateEssentialBC(ess_bdr,x.GetBlock(0),rhs.GetBlock(0),
mfem::Operator::DIAG_ONE);
a00.Finalize();
SparseMatrix &A00 = a00.SpMat();
MixedBilinearForm a10(&H1fes,&L2fes);
a10.AddDomainIntegrator(new MixedScalarMassIntegrator());
a10.Assemble();
a10.EliminateTrialDofs(ess_bdr, x.GetBlock(0), rhs.GetBlock(1));
a10.Finalize();
SparseMatrix &A10 = a10.SpMat();
SparseMatrix *A01 = Transpose(A10);
BilinearForm a11(&L2fes);
a11.AddDomainIntegrator(new MassIntegrator(neg_exp_psi));
// NOTE: Shift the spectrum of the Hessian matrix for additional
// stability (Quasi-Newton).
ConstantCoefficient eps_cf(-1e-6);
if (order == 1)
{
// NOTE: ∇ₕuₕ = 0 for constant functions.
// Therefore, we use the mass matrix to shift the spectrum
a11.AddDomainIntegrator(new MassIntegrator(eps_cf));
}
else
{
a11.AddDomainIntegrator(new DiffusionIntegrator(eps_cf));
}
a11.Assemble();
a11.Finalize();
SparseMatrix &A11 = a11.SpMat();
BlockOperator A(offsets);
A.SetBlock(0,0,&A00);
A.SetBlock(1,0,&A10);
A.SetBlock(0,1,A01);
A.SetBlock(1,1,&A11);
BlockDiagonalPreconditioner prec(offsets);
prec.SetDiagonalBlock(0,new GSSmoother(A00));
prec.SetDiagonalBlock(1,new GSSmoother(A11));
prec.owns_blocks = 1;
GMRES(A,prec,rhs,x,0,10000,500,1e-12,0.0);
u_gf.MakeRef(&H1fes, x.GetBlock(0), 0);
delta_psi_gf.MakeRef(&L2fes, x.GetBlock(1), 0);
u_tmp -= u_gf;
real_t Newton_update_size = u_tmp.ComputeL2Error(zero);
u_tmp = u_gf;
real_t gamma = 1.0;
delta_psi_gf *= gamma;
psi_gf += delta_psi_gf;
if (visualization)
{
sol_sock << "solution\n" << mesh << u_gf << "window_title 'Discrete solution'"
<< flush;
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
}
delete A01;
if (Newton_update_size < increment_u)
{
break;
}
}
u_tmp = u_gf;
u_tmp -= u_old_gf;
increment_u = u_tmp.ComputeL2Error(zero);
mfem::out << "Number of Newton iterations = " << j+1 << endl;
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
u_old_gf = u_gf;
psi_old_gf = psi_gf;
if (increment_u < tol || k == max_it-1)
{
break;
}
real_t H1_error = u_gf.ComputeH1Error(&exact_coef,&exact_grad_coef);
mfem::out << "H1-error (|| u - uₕᵏ||) = " << H1_error << endl;
}
mfem::out << "\n Outer iterations: " << k+1
<< "\n Total iterations: " << total_iterations
<< "\n Total dofs: " << H1fes.GetTrueVSize() + L2fes.GetTrueVSize()
<< endl;
// 11. Exact solution.
if (visualization)
{
socketstream err_sock(vishost, visport);
err_sock.precision(8);
GridFunction error_gf(&H1fes);
error_gf.ProjectCoefficient(exact_coef);
error_gf -= u_gf;
err_sock << "solution\n" << mesh << error_gf << "window_title 'Error'" <<
flush;
}
{
real_t L2_error = u_gf.ComputeL2Error(exact_coef);
real_t H1_error = u_gf.ComputeH1Error(&exact_coef,&exact_grad_coef);
ExponentialGridFunctionCoefficient u_alt_cf(psi_gf,obstacle);
GridFunction u_alt_gf(&L2fes);
u_alt_gf.ProjectCoefficient(u_alt_cf);
real_t L2_error_alt = u_alt_gf.ComputeL2Error(exact_coef);
mfem::out << "\n Final L2-error (|| u - uₕ||) = " << L2_error <<
endl;
mfem::out << " Final H1-error (|| u - uₕ||) = " << H1_error << endl;
mfem::out << " Final L2-error (|| u - ϕ - exp(ψₕ)||) = " << L2_error_alt <<
endl;
}
return 0;
}
real_t LogarithmGridFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(u != NULL, "grid function is not set");
real_t val = u->GetValue(T, ip) - obstacle->Eval(T, ip);
return max(min_val, log(val));
}
real_t ExponentialGridFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(u != NULL, "grid function is not set");
real_t val = u->GetValue(T, ip);
return min(max_val, max(min_val, exp(val) + obstacle->Eval(T, ip)));
}
real_t spherical_obstacle(const Vector &pt)
{
real_t x = pt(0), y = pt(1);
real_t r = sqrt(x*x + y*y);
real_t r0 = 0.5;
real_t beta = 0.9;
real_t b = r0*beta;
real_t tmp = sqrt(r0*r0 - b*b);
real_t B = tmp + b*b/tmp;
real_t C = -b/tmp;
if (r > b)
{
return B + r * C;
}
else
{
return sqrt(r0*r0 - r*r);
}
}
real_t exact_solution_obstacle(const Vector &pt)
{
real_t x = pt(0), y = pt(1);
real_t r = sqrt(x*x + y*y);
real_t r0 = 0.5;
real_t a = 0.348982574111686;
real_t A = -0.340129705945858;
if (r > a)
{
return A * log(r);
}
else
{
return sqrt(r0*r0-r*r);
}
}
void exact_solution_gradient_obstacle(const Vector &pt, Vector &grad)
{
real_t x = pt(0), y = pt(1);
real_t r = sqrt(x*x + y*y);
real_t r0 = 0.5;
real_t a = 0.348982574111686;
real_t A = -0.340129705945858;
if (r > a)
{
grad(0) = A * x / (r*r);
grad(1) = A * y / (r*r);
}
else
{
grad(0) = - x / sqrt( r0*r0 - r*r );
grad(1) = - y / sqrt( r0*r0 - r*r );
}
}
-523
View File
@@ -1,523 +0,0 @@
// MFEM Example 36 - Parallel Version
//
// Compile with: make ex36p
//
// Sample runs: mpirun -np 4 ex36p -o 2
// mpirun -np 4 ex36p -o 2 -r 4
//
// Description: This example code demonstrates the use of MFEM to solve the
// bound-constrained energy minimization problem
//
// minimize ||∇u||² subject to u ≥ ϕ in H¹₀.
//
// This is known as the obstacle problem, and it is a simple
// mathematical model for contact mechanics.
//
// In this example, the obstacle ϕ is a half-sphere centered
// at the origin of a circular domain Ω. After solving to a
// specified tolerance, the numerical solution is compared to
// a closed-form exact solution to assess accuracy.
//
// The problem is discretized and solved using the proximal
// Galerkin finite element method, introduced by Keith and
// Surowiec [1].
//
// This example highlights the ability of MFEM to deliver high-
// order solutions to variation inequality problems and
// showcases how to set up and solve nonlinear mixed methods.
//
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
real_t spherical_obstacle(const Vector &pt);
real_t exact_solution_obstacle(const Vector &pt);
void exact_solution_gradient_obstacle(const Vector &pt, Vector &grad);
class LogarithmGridFunctionCoefficient : public Coefficient
{
protected:
GridFunction *u; // grid function
Coefficient *obstacle;
real_t min_val;
public:
LogarithmGridFunctionCoefficient(GridFunction &u_, Coefficient &obst_,
real_t min_val_=-36)
: u(&u_), obstacle(&obst_), min_val(min_val_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
};
class ExponentialGridFunctionCoefficient : public Coefficient
{
protected:
GridFunction *u;
Coefficient *obstacle;
real_t min_val;
real_t max_val;
public:
ExponentialGridFunctionCoefficient(GridFunction &u_, Coefficient &obst_,
real_t min_val_=0.0, real_t max_val_=1e6)
: u(&u_), obstacle(&obst_), min_val(min_val_), max_val(max_val_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
};
int main(int argc, char *argv[])
{
// 0. Initialize MPI and HYPRE.
Mpi::Init();
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
// 1. Parse command-line options.
int order = 1;
int max_it = 10;
int ref_levels = 3;
real_t alpha = 1.0;
real_t tol = 1e-5;
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&ref_levels, "-r", "--refs",
"Number of h-refinements.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of iterations");
args.AddOption(&tol, "-tol", "--tol",
"Stopping criteria based on the difference between"
"successive solution updates");
args.AddOption(&alpha, "-step", "--step",
"Step size alpha");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 2. Read the mesh from the mesh file.
const char *mesh_file = "../data/disc-nurbs.mesh";
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
// 3. Postprocess the mesh.
// 3A. Refine the mesh to increase the resolution.
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
// 3B. Interpolate the geometry after refinement to control geometry error.
// NOTE: Minimum second-order interpolation is used to improve the accuracy.
int curvature_order = max(order,2);
mesh.SetCurvature(curvature_order);
// 3C. Rescale the domain to a unit circle (radius = 1).
GridFunction *nodes = mesh.GetNodes();
real_t scale = 2*sqrt(2);
*nodes /= scale;
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
// 4. Define the necessary finite element spaces on the mesh.
H1_FECollection H1fec(order+1, dim);
ParFiniteElementSpace H1fes(&pmesh, &H1fec);
L2_FECollection L2fec(order-1, dim);
ParFiniteElementSpace L2fes(&pmesh, &L2fec);
int num_dofs_H1 = H1fes.GetTrueVSize();
MPI_Allreduce(MPI_IN_PLACE, &num_dofs_H1, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
int num_dofs_L2 = L2fes.GetTrueVSize();
MPI_Allreduce(MPI_IN_PLACE, &num_dofs_L2, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
if (myid == 0)
{
cout << "Number of H1 finite element unknowns: "
<< num_dofs_H1 << endl;
cout << "Number of L2 finite element unknowns: "
<< num_dofs_L2 << endl;
}
Array<int> offsets(3);
offsets[0] = 0;
offsets[1] = H1fes.GetVSize();
offsets[2] = L2fes.GetVSize();
offsets.PartialSum();
Array<int> toffsets(3);
toffsets[0] = 0;
toffsets[1] = H1fes.GetTrueVSize();
toffsets[2] = L2fes.GetTrueVSize();
toffsets.PartialSum();
BlockVector x(offsets), rhs(offsets);
x = 0.0; rhs = 0.0;
BlockVector tx(toffsets), trhs(toffsets);
tx = 0.0; trhs = 0.0;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
Array<int> empty;
Array<int> ess_tdof_list;
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
H1fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 6. Define an initial guess for the solution.
auto IC_func = [](const Vector &x)
{
real_t r0 = 1.0;
real_t rr = 0.0;
for (int i=0; i<x.Size(); i++)
{
rr += x(i)*x(i);
}
return r0*r0 - rr;
};
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
// 7. Define the solution vectors as a finite element grid functions
// corresponding to the fespaces.
ParGridFunction u_gf, delta_psi_gf;
u_gf.MakeRef(&H1fes,x,offsets[0]);
delta_psi_gf.MakeRef(&L2fes,x,offsets[1]);
delta_psi_gf = 0.0;
ParGridFunction u_old_gf(&H1fes);
ParGridFunction psi_old_gf(&L2fes);
ParGridFunction psi_gf(&L2fes);
u_old_gf = 0.0;
psi_old_gf = 0.0;
// 8. Define the function coefficients for the solution and use them to
// initialize the initial guess
FunctionCoefficient exact_coef(exact_solution_obstacle);
VectorFunctionCoefficient exact_grad_coef(dim,exact_solution_gradient_obstacle);
FunctionCoefficient IC_coef(IC_func);
ConstantCoefficient f(0.0);
FunctionCoefficient obstacle(spherical_obstacle);
u_gf.ProjectCoefficient(IC_coef);
u_old_gf = u_gf;
// 9. Initialize the slack variable ψₕ = ln(uₕ)
LogarithmGridFunctionCoefficient ln_u(u_gf, obstacle);
psi_gf.ProjectCoefficient(ln_u);
psi_old_gf = psi_gf;
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock;
if (visualization)
{
sol_sock.open(vishost,visport);
sol_sock.precision(8);
}
// 10. Iterate
int k;
int total_iterations = 0;
real_t increment_u = 0.1;
for (k = 0; k < max_it; k++)
{
ParGridFunction u_tmp(&H1fes);
u_tmp = u_old_gf;
if (myid == 0)
{
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
}
int j;
for ( j = 0; j < 10; j++)
{
total_iterations++;
ConstantCoefficient alpha_cf(alpha);
ParLinearForm b0,b1;
b0.Update(&H1fes,rhs.GetBlock(0),0);
b1.Update(&L2fes,rhs.GetBlock(1),0);
ExponentialGridFunctionCoefficient exp_psi(psi_gf, zero);
ProductCoefficient neg_exp_psi(-1.0,exp_psi);
GradientGridFunctionCoefficient grad_u_old(&u_old_gf);
ProductCoefficient alpha_f(alpha, f);
GridFunctionCoefficient psi_cf(&psi_gf);
GridFunctionCoefficient psi_old_cf(&psi_old_gf);
SumCoefficient psi_old_minus_psi(psi_old_cf, psi_cf, 1.0, -1.0);
b0.AddDomainIntegrator(new DomainLFIntegrator(alpha_f));
b0.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
b0.Assemble();
b1.AddDomainIntegrator(new DomainLFIntegrator(exp_psi));
b1.AddDomainIntegrator(new DomainLFIntegrator(obstacle));
b1.Assemble();
ParBilinearForm a00(&H1fes);
a00.SetDiagonalPolicy(mfem::Operator::DIAG_ONE);
a00.AddDomainIntegrator(new DiffusionIntegrator(alpha_cf));
a00.Assemble();
HypreParMatrix A00;
a00.FormLinearSystem(ess_tdof_list, x.GetBlock(0), rhs.GetBlock(0),
A00, tx.GetBlock(0), trhs.GetBlock(0));
ParMixedBilinearForm a10(&H1fes,&L2fes);
a10.AddDomainIntegrator(new MixedScalarMassIntegrator());
a10.Assemble();
HypreParMatrix A10;
a10.FormRectangularLinearSystem(ess_tdof_list, empty, x.GetBlock(0),
rhs.GetBlock(1),
A10, tx.GetBlock(0), trhs.GetBlock(1));
HypreParMatrix *A01 = A10.Transpose();
ParBilinearForm a11(&L2fes);
a11.AddDomainIntegrator(new MassIntegrator(neg_exp_psi));
// NOTE: Shift the spectrum of the Hessian matrix for additional
// stability (Quasi-Newton).
ConstantCoefficient eps_cf(-1e-6);
if (order == 1)
{
// NOTE: ∇ₕuₕ = 0 for constant functions.
// Therefore, we use the mass matrix to shift the spectrum
a11.AddDomainIntegrator(new MassIntegrator(eps_cf));
}
else
{
a11.AddDomainIntegrator(new DiffusionIntegrator(eps_cf));
}
a11.Assemble();
a11.Finalize();
HypreParMatrix A11;
a11.FormSystemMatrix(empty, A11);
BlockOperator A(toffsets);
A.SetBlock(0,0,&A00);
A.SetBlock(1,0,&A10);
A.SetBlock(0,1,A01);
A.SetBlock(1,1,&A11);
BlockDiagonalPreconditioner prec(toffsets);
HypreBoomerAMG P00(A00);
P00.SetPrintLevel(0);
HypreSmoother P11(A11);
prec.SetDiagonalBlock(0,&P00);
prec.SetDiagonalBlock(1,&P11);
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetPrintLevel(-1);
gmres.SetRelTol(1e-8);
gmres.SetMaxIter(20000);
gmres.SetKDim(500);
gmres.SetOperator(A);
gmres.SetPreconditioner(prec);
gmres.Mult(trhs,tx);
u_gf.SetFromTrueDofs(tx.GetBlock(0));
delta_psi_gf.SetFromTrueDofs(tx.GetBlock(1));
u_tmp -= u_gf;
real_t Newton_update_size = u_tmp.ComputeL2Error(zero);
u_tmp = u_gf;
real_t gamma = 1.0;
delta_psi_gf *= gamma;
psi_gf += delta_psi_gf;
if (visualization)
{
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock << "solution\n" << pmesh << u_gf << "window_title 'Discrete solution'"
<< flush;
}
if (myid == 0)
{
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
}
delete A01;
if (Newton_update_size < increment_u)
{
break;
}
}
u_tmp = u_gf;
u_tmp -= u_old_gf;
increment_u = u_tmp.ComputeL2Error(zero);
if (myid == 0)
{
mfem::out << "Number of Newton iterations = " << j+1 << endl;
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
}
u_old_gf = u_gf;
psi_old_gf = psi_gf;
if (increment_u < tol || k == max_it-1)
{
break;
}
real_t H1_error = u_gf.ComputeH1Error(&exact_coef,&exact_grad_coef);
if (myid == 0)
{
mfem::out << "H1-error (|| u - uₕᵏ||) = " << H1_error << endl;
}
}
if (myid == 0)
{
mfem::out << "\n Outer iterations: " << k+1
<< "\n Total iterations: " << total_iterations
<< "\n Total dofs: " << num_dofs_H1 + num_dofs_L2
<< endl;
}
// 11. Exact solution.
if (visualization)
{
socketstream err_sock(vishost, visport);
err_sock.precision(8);
ParGridFunction error_gf(&H1fes);
error_gf.ProjectCoefficient(exact_coef);
error_gf -= u_gf;
err_sock << "parallel " << num_procs << " " << myid << "\n";
err_sock << "solution\n" << pmesh << error_gf << "window_title 'Error'" <<
flush;
}
{
real_t L2_error = u_gf.ComputeL2Error(exact_coef);
real_t H1_error = u_gf.ComputeH1Error(&exact_coef,&exact_grad_coef);
ExponentialGridFunctionCoefficient u_alt_cf(psi_gf,obstacle);
ParGridFunction u_alt_gf(&L2fes);
u_alt_gf.ProjectCoefficient(u_alt_cf);
real_t L2_error_alt = u_alt_gf.ComputeL2Error(exact_coef);
if (myid == 0)
{
mfem::out << "\n Final L2-error (|| u - uₕ||) = " << L2_error <<
endl;
mfem::out << " Final H1-error (|| u - uₕ||) = " << H1_error << endl;
mfem::out << " Final L2-error (|| u - ϕ - exp(ψₕ)||) = " << L2_error_alt <<
endl;
}
}
return 0;
}
real_t LogarithmGridFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(u != NULL, "grid function is not set");
real_t val = u->GetValue(T, ip) - obstacle->Eval(T, ip);
return max(min_val, log(val));
}
real_t ExponentialGridFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(u != NULL, "grid function is not set");
real_t val = u->GetValue(T, ip);
return min(max_val, max(min_val, exp(val) + obstacle->Eval(T, ip)));
}
real_t spherical_obstacle(const Vector &pt)
{
real_t x = pt(0), y = pt(1);
real_t r = sqrt(x*x + y*y);
real_t r0 = 0.5;
real_t beta = 0.9;
real_t b = r0*beta;
real_t tmp = sqrt(r0*r0 - b*b);
real_t B = tmp + b*b/tmp;
real_t C = -b/tmp;
if (r > b)
{
return B + r * C;
}
else
{
return sqrt(r0*r0 - r*r);
}
}
real_t exact_solution_obstacle(const Vector &pt)
{
real_t x = pt(0), y = pt(1);
real_t r = sqrt(x*x + y*y);
real_t r0 = 0.5;
real_t a = 0.348982574111686;
real_t A = -0.340129705945858;
if (r > a)
{
return A * log(r);
}
else
{
return sqrt(r0*r0-r*r);
}
}
void exact_solution_gradient_obstacle(const Vector &pt, Vector &grad)
{
real_t x = pt(0), y = pt(1);
real_t r = sqrt(x*x + y*y);
real_t r0 = 0.5;
real_t a = 0.348982574111686;
real_t A = -0.340129705945858;
if (r > a)
{
grad(0) = A * x / (r*r);
grad(1) = A * y / (r*r);
}
else
{
grad(0) = - x / sqrt( r0*r0 - r*r );
grad(1) = - y / sqrt( r0*r0 - r*r );
}
}
-466
View File
@@ -1,466 +0,0 @@
// MFEM Example 37
//
// Compile with: make ex37
//
// Sample runs:
// ex37 -alpha 10
// ex37 -alpha 10 -pv
// ex37 -lambda 0.1 -mu 0.1
// ex37 -o 2 -alpha 5.0 -mi 50 -vf 0.4 -ntol 1e-5
// ex37 -r 6 -o 1 -alpha 25.0 -epsilon 0.02 -mi 50 -ntol 1e-5
//
// Description: This example code demonstrates the use of MFEM to solve a
// density-filtered [3] topology optimization problem. The
// objective is to minimize the compliance
//
// minimize ∫_Ω f⋅u dx over u ∈ [H¹(Ω)]² and ρ ∈ L¹(Ω)
//
// subject to
//
// -Div(r(ρ̃)Cε(u)) = f in Ω + BCs
// -ϵ²Δρ̃ + ρ̃ = ρ in Ω + Neumann BCs
// 0 ≤ ρ ≤ 1 in Ω
// ∫_Ω ρ dx = θ vol(Ω)
//
// Here, r(ρ̃) = ρ₀ + ρ̃³ (1-ρ₀) is the solid isotropic material
// penalization (SIMP) law, C is the elasticity tensor for an
// isotropic linearly elastic material, ϵ > 0 is the design
// length scale, and 0 < θ < 1 is the volume fraction.
//
// The problem is discretized and gradients are computing using
// finite elements [1]. The design is optimized using an entropic
// mirror descent algorithm introduced by Keith and Surowiec [2]
// that is tailored to the bound constraint 0 ≤ ρ ≤ 1.
//
// This example highlights the ability of MFEM to deliver high-
// order solutions to inverse design problems and showcases how
// to set up and solve PDE-constrained optimization problems
// using the so-called reduced space approach.
//
// [1] Andreassen, E., Clausen, A., Schevenels, M., Lazarov, B. S., & Sigmund, O.
// (2011). Efficient topology optimization in MATLAB using 88 lines of
// code. Structural and Multidisciplinary Optimization, 43(1), 1-16.
// [2] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
// [3] Lazarov, B. S., & Sigmund, O. (2011). Filters in topology optimization
// based on Helmholtztype differential equations. International Journal
// for Numerical Methods in Engineering, 86(6), 765-781.
#include "mfem.hpp"
#include <iostream>
#include <fstream>
#include "ex37.hpp"
using namespace std;
using namespace mfem;
/**
* @brief Bregman projection of ρ = sigmoid(ψ) onto the subspace
* ρ dx = θ vol(Ω) as follows:
*
* 1. Compute the root of the R R function
* f(c) = sigmoid(ψ + c) dx - θ vol(Ω)
* 2. Set ψ ψ + c.
*
* @param psi a GridFunction to be updated
* @param target_volume θ vol(Ω)
* @param tol Newton iteration tolerance
* @param max_its Newton maximum iteration number
* @return real_t Final volume, sigmoid(ψ)
*/
real_t proj(GridFunction &psi, real_t target_volume, real_t tol=1e-12,
int max_its=10)
{
MappedGridFunctionCoefficient sigmoid_psi(&psi, sigmoid);
MappedGridFunctionCoefficient der_sigmoid_psi(&psi, der_sigmoid);
LinearForm int_sigmoid_psi(psi.FESpace());
int_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(sigmoid_psi));
LinearForm int_der_sigmoid_psi(psi.FESpace());
int_der_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(
der_sigmoid_psi));
bool done = false;
for (int k=0; k<max_its; k++) // Newton iteration
{
int_sigmoid_psi.Assemble(); // Recompute f(c) with updated ψ
const real_t f = int_sigmoid_psi.Sum() - target_volume;
int_der_sigmoid_psi.Assemble(); // Recompute df(c) with updated ψ
const real_t df = int_der_sigmoid_psi.Sum();
const real_t dc = -f/df;
psi += dc;
if (abs(dc) < tol) { done = true; break; }
}
if (!done)
{
mfem_warning("Projection reached maximum iteration without converging. "
"Result may not be accurate.");
}
int_sigmoid_psi.Assemble();
return int_sigmoid_psi.Sum();
}
/**
* ---------------------------------------------------------------
* ALGORITHM PREAMBLE
* ---------------------------------------------------------------
*
* The Lagrangian for this problem is
*
* L(u,ρ,ρ̃,w,) = (f,u) - (r(ρ̃) C ε(u),ε(w)) + (f,w)
* - (ϵ² ρ̃,) - (ρ̃,) + (ρ,)
*
* where
*
* r(ρ̃) = ρ + ρ̃³ (1 - ρ) (SIMP rule)
*
* ε(u) = (u + uᵀ)/2 (symmetric gradient)
*
* C e = λtr(e)I + 2μe (isotropic material)
*
* NOTE: The Lame parameters can be computed from Young's modulus E
* and Poisson's ratio ν as follows:
*
* λ = E ν/((1+ν)(1-2ν)), μ = E/(2(1+ν))
*
* ---------------------------------------------------------------
*
* Discretization choices:
*
* u V (H¹) (order p)
* ψ L² (order p - 1), ρ = sigmoid(ψ)
* ρ̃ H¹ (order p)
* w V (order p)
* H¹ (order p)
*
* ---------------------------------------------------------------
* ALGORITHM
* ---------------------------------------------------------------
*
* Update ρ with projected mirror descent via the following algorithm.
*
* 1. Initialize ψ = inv_sigmoid(vol_fraction) so that sigmoid(ψ) = θ vol(Ω)
*
* While not converged:
*
* 2. Solve filter equation _w̃ L = 0; i.e.,
*
* (ϵ² ρ̃, v ) + (ρ̃,v) = (ρ,v) v H¹.
*
* 3. Solve primal problem _w L = 0; i.e.,
*
* (λ r(ρ̃) u, v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v) v V.
*
* NB. The dual problem _u L = 0 is the negative of the primal problem due to symmetry.
*
* 4. Solve for filtered gradient _ρ̃ L = 0; i.e.,
*
* (ϵ² , v ) + ( ,v) = (-r'(ρ̃) ( λ |u|² + 2 μ |ε(u)|²),v) v H¹.
*
* 5. Project the gradient onto the discrete latent space; i.e., solve
*
* (G,v) = (,v) v L².
*
* 6. Bregman proximal gradient update; i.e.,
*
* ψ ψ - αG + c,
*
* where α > 0 is a step size parameter and c R is a constant ensuring
*
* sigmoid(ψ - αG + c) dx = θ vol(Ω).
*
* end
*/
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
int ref_levels = 5;
int order = 2;
real_t alpha = 1.0;
real_t epsilon = 0.01;
real_t vol_fraction = 0.5;
int max_it = 1e3;
real_t itol = 1e-1;
real_t ntol = 1e-4;
real_t rho_min = 1e-6;
real_t lambda = 1.0;
real_t mu = 1.0;
bool glvis_visualization = true;
bool paraview_output = false;
OptionsParser args(argc, argv);
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&alpha, "-alpha", "--alpha-step-length",
"Step length for gradient descent.");
args.AddOption(&epsilon, "-epsilon", "--epsilon-thickness",
"Length scale for ρ.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of gradient descent iterations.");
args.AddOption(&ntol, "-ntol", "--rel-tol",
"Normalized exit tolerance.");
args.AddOption(&itol, "-itol", "--abs-tol",
"Increment exit tolerance.");
args.AddOption(&vol_fraction, "-vf", "--volume-fraction",
"Volume fraction for the material density.");
args.AddOption(&lambda, "-lambda", "--lambda",
"Lamé constant λ.");
args.AddOption(&mu, "-mu", "--mu",
"Lamé constant μ.");
args.AddOption(&rho_min, "-rmin", "--psi-min",
"Minimum of density coefficient.");
args.AddOption(&glvis_visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&paraview_output, "-pv", "--paraview", "-no-pv",
"--no-paraview",
"Enable or disable ParaView output.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(mfem::out);
return 1;
}
args.PrintOptions(mfem::out);
Mesh mesh = Mesh::MakeCartesian2D(3, 1, mfem::Element::Type::QUADRILATERAL,
true, 3.0, 1.0);
int dim = mesh.Dimension();
// 2. Set BCs.
for (int i = 0; i<mesh.GetNBE(); i++)
{
Element * be = mesh.GetBdrElement(i);
Array<int> vertices;
be->GetVertices(vertices);
real_t * coords1 = mesh.GetVertex(vertices[0]);
real_t * coords2 = mesh.GetVertex(vertices[1]);
Vector center(2);
center(0) = 0.5*(coords1[0] + coords2[0]);
center(1) = 0.5*(coords1[1] + coords2[1]);
if (abs(center(0) - 0.0) < 1e-10)
{
// the left edge
be->SetAttribute(1);
}
else
{
// all other boundaries
be->SetAttribute(2);
}
}
mesh.SetAttributes();
// 3. Refine the mesh.
for (int lev = 0; lev < ref_levels; lev++)
{
mesh.UniformRefinement();
}
// 4. Define the necessary finite element spaces on the mesh.
H1_FECollection state_fec(order, dim); // space for u
H1_FECollection filter_fec(order, dim); // space for ρ̃
L2_FECollection control_fec(order-1, dim,
BasisType::GaussLobatto); // space for ψ
FiniteElementSpace state_fes(&mesh, &state_fec,dim);
FiniteElementSpace filter_fes(&mesh, &filter_fec);
FiniteElementSpace control_fes(&mesh, &control_fec);
int state_size = state_fes.GetTrueVSize();
int control_size = control_fes.GetTrueVSize();
int filter_size = filter_fes.GetTrueVSize();
mfem::out << "Number of state unknowns: " << state_size << std::endl;
mfem::out << "Number of filter unknowns: " << filter_size << std::endl;
mfem::out << "Number of control unknowns: " << control_size << std::endl;
// 5. Set the initial guess for ρ.
GridFunction u(&state_fes);
GridFunction psi(&control_fes);
GridFunction psi_old(&control_fes);
GridFunction rho_filter(&filter_fes);
u = 0.0;
rho_filter = vol_fraction;
psi = inv_sigmoid(vol_fraction);
psi_old = inv_sigmoid(vol_fraction);
// ρ = sigmoid(ψ)
MappedGridFunctionCoefficient rho(&psi, sigmoid);
// Interpolation of ρ = sigmoid(ψ) in control fes (for ParaView output)
GridFunction rho_gf(&control_fes);
// ρ - ρ_old = sigmoid(ψ) - sigmoid(ψ_old)
DiffMappedGridFunctionCoefficient succ_diff_rho(&psi, &psi_old, sigmoid);
// 6. Set-up the physics solver.
int maxat = mesh.bdr_attributes.Max();
Array<int> ess_bdr(maxat);
ess_bdr = 0;
ess_bdr[0] = 1;
ConstantCoefficient one(1.0);
ConstantCoefficient lambda_cf(lambda);
ConstantCoefficient mu_cf(mu);
LinearElasticitySolver * ElasticitySolver = new LinearElasticitySolver();
ElasticitySolver->SetMesh(&mesh);
ElasticitySolver->SetOrder(state_fec.GetOrder());
ElasticitySolver->SetupFEM();
Vector center(2); center(0) = 2.9; center(1) = 0.5;
Vector force(2); force(0) = 0.0; force(1) = -1.0;
real_t r = 0.05;
VolumeForceCoefficient vforce_cf(r,center,force);
ElasticitySolver->SetRHSCoefficient(&vforce_cf);
ElasticitySolver->SetEssentialBoundary(ess_bdr);
// 7. Set-up the filter solver.
ConstantCoefficient eps2_cf(epsilon*epsilon);
DiffusionSolver * FilterSolver = new DiffusionSolver();
FilterSolver->SetMesh(&mesh);
FilterSolver->SetOrder(filter_fec.GetOrder());
FilterSolver->SetDiffusionCoefficient(&eps2_cf);
FilterSolver->SetMassCoefficient(&one);
Array<int> ess_bdr_filter;
if (mesh.bdr_attributes.Size())
{
ess_bdr_filter.SetSize(mesh.bdr_attributes.Max());
ess_bdr_filter = 0;
}
FilterSolver->SetEssentialBoundary(ess_bdr_filter);
FilterSolver->SetupFEM();
BilinearForm mass(&control_fes);
mass.AddDomainIntegrator(new InverseIntegrator(new MassIntegrator(one)));
mass.Assemble();
SparseMatrix M;
Array<int> empty;
mass.FormSystemMatrix(empty,M);
// 8. Define the Lagrange multiplier and gradient functions.
GridFunction grad(&control_fes);
GridFunction w_filter(&filter_fes);
// 9. Define some tools for later.
ConstantCoefficient zero(0.0);
GridFunction onegf(&control_fes);
onegf = 1.0;
GridFunction zerogf(&control_fes);
zerogf = 0.0;
LinearForm vol_form(&control_fes);
vol_form.AddDomainIntegrator(new DomainLFIntegrator(one));
vol_form.Assemble();
real_t domain_volume = vol_form(onegf);
const real_t target_volume = domain_volume * vol_fraction;
// 10. Connect to GLVis. Prepare for VisIt output.
char vishost[] = "localhost";
int visport = 19916;
socketstream sout_r;
if (glvis_visualization)
{
sout_r.open(vishost, visport);
sout_r.precision(8);
}
mfem::ParaViewDataCollection paraview_dc("ex37", &mesh);
if (paraview_output)
{
rho_gf.ProjectCoefficient(rho);
paraview_dc.SetPrefixPath("ParaView");
paraview_dc.SetLevelsOfDetail(order);
paraview_dc.SetDataFormat(VTKFormat::BINARY);
paraview_dc.SetHighOrderOutput(true);
paraview_dc.SetCycle(0);
paraview_dc.SetTime(0.0);
paraview_dc.RegisterField("displacement",&u);
paraview_dc.RegisterField("density",&rho_gf);
paraview_dc.RegisterField("filtered_density",&rho_filter);
paraview_dc.Save();
}
// 11. Iterate:
for (int k = 1; k <= max_it; k++)
{
if (k > 1) { alpha *= ((real_t) k) / ((real_t) k-1); }
mfem::out << "\nStep = " << k << std::endl;
// Step 1 - Filter solve
// Solve (ϵ^2 ∇ ρ̃, ∇ v ) + (ρ̃,v) = (ρ,v)
FilterSolver->SetRHSCoefficient(&rho);
FilterSolver->Solve();
rho_filter = *FilterSolver->GetFEMSolution();
// Step 2 - State solve
// Solve (λ r(ρ̃) ∇⋅u, ∇⋅v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v)
SIMPInterpolationCoefficient SIMP_cf(&rho_filter,rho_min, 1.0);
ProductCoefficient lambda_SIMP_cf(lambda_cf,SIMP_cf);
ProductCoefficient mu_SIMP_cf(mu_cf,SIMP_cf);
ElasticitySolver->SetLameCoefficients(&lambda_SIMP_cf,&mu_SIMP_cf);
ElasticitySolver->Solve();
u = *ElasticitySolver->GetFEMSolution();
// Step 3 - Adjoint filter solve
// Solve (ϵ² ∇ w̃, ∇ v) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v)
StrainEnergyDensityCoefficient rhs_cf(&lambda_cf,&mu_cf,&u, &rho_filter,
rho_min);
FilterSolver->SetRHSCoefficient(&rhs_cf);
FilterSolver->Solve();
w_filter = *FilterSolver->GetFEMSolution();
// Step 4 - Compute gradient
// Solve G = M⁻¹w̃
GridFunctionCoefficient w_cf(&w_filter);
LinearForm w_rhs(&control_fes);
w_rhs.AddDomainIntegrator(new DomainLFIntegrator(w_cf));
w_rhs.Assemble();
M.Mult(w_rhs,grad);
// Step 5 - Update design variable ψ ← proj(ψ - αG)
psi.Add(-alpha, grad);
const real_t material_volume = proj(psi, target_volume);
// Compute ||ρ - ρ_old|| in control fes.
real_t norm_increment = zerogf.ComputeL1Error(succ_diff_rho);
real_t norm_reduced_gradient = norm_increment/alpha;
psi_old = psi;
real_t compliance = (*(ElasticitySolver->GetLinearForm()))(u);
mfem::out << "norm of the reduced gradient = " << norm_reduced_gradient <<
std::endl;
mfem::out << "norm of the increment = " << norm_increment << endl;
mfem::out << "compliance = " << compliance << std::endl;
mfem::out << "volume fraction = " << material_volume / domain_volume <<
std::endl;
if (glvis_visualization)
{
GridFunction r_gf(&filter_fes);
r_gf.ProjectCoefficient(SIMP_cf);
sout_r << "solution\n" << mesh << r_gf
<< "window_title 'Design density r(ρ̃)'" << flush;
}
if (paraview_output)
{
rho_gf.ProjectCoefficient(rho);
paraview_dc.SetCycle(k);
paraview_dc.SetTime((real_t)k);
paraview_dc.Save();
}
if (norm_reduced_gradient < ntol && norm_increment < itol)
{
break;
}
}
delete ElasticitySolver;
delete FilterSolver;
return 0;
}
-748
View File
@@ -1,748 +0,0 @@
// MFEM Example 37 - Serial/Parallel Shared Code
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <functional>
namespace mfem
{
/// @brief Inverse sigmoid function
real_t inv_sigmoid(real_t x)
{
real_t tol = 1e-12;
x = std::min(std::max(tol,x), real_t(1.0)-tol);
return std::log(x/(1.0-x));
}
/// @brief Sigmoid function
real_t sigmoid(real_t x)
{
if (x >= 0)
{
return 1.0/(1.0+std::exp(-x));
}
else
{
return std::exp(x)/(1.0+std::exp(x));
}
}
/// @brief Derivative of sigmoid function
real_t der_sigmoid(real_t x)
{
real_t tmp = sigmoid(-x);
return tmp - std::pow(tmp,2);
}
/// @brief Returns f(u(x)) where u is a scalar GridFunction and f:R → R
class MappedGridFunctionCoefficient : public GridFunctionCoefficient
{
protected:
std::function<real_t(const real_t)> fun; // f:R → R
public:
MappedGridFunctionCoefficient()
:GridFunctionCoefficient(),
fun([](real_t x) {return x;}) {}
MappedGridFunctionCoefficient(const GridFunction *gf,
std::function<real_t(const real_t)> fun_,
int comp=1)
:GridFunctionCoefficient(gf, comp),
fun(fun_) {}
virtual real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
return fun(GridFunctionCoefficient::Eval(T, ip));
}
void SetFunction(std::function<real_t(const real_t)> fun_) { fun = fun_; }
};
/// @brief Returns f(u(x)) - f(v(x)) where u, v are scalar GridFunctions and f:R → R
class DiffMappedGridFunctionCoefficient : public GridFunctionCoefficient
{
protected:
const GridFunction *OtherGridF;
GridFunctionCoefficient OtherGridF_cf;
std::function<real_t(const real_t)> fun; // f:R → R
public:
DiffMappedGridFunctionCoefficient()
:GridFunctionCoefficient(),
OtherGridF(nullptr),
OtherGridF_cf(),
fun([](real_t x) {return x;}) {}
DiffMappedGridFunctionCoefficient(const GridFunction *gf,
const GridFunction *other_gf,
std::function<real_t(const real_t)> fun_,
int comp=1)
:GridFunctionCoefficient(gf, comp),
OtherGridF(other_gf),
OtherGridF_cf(OtherGridF),
fun(fun_) {}
virtual real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
const real_t value1 = fun(GridFunctionCoefficient::Eval(T, ip));
const real_t value2 = fun(OtherGridF_cf.Eval(T, ip));
return value1 - value2;
}
void SetFunction(std::function<real_t(const real_t)> fun_) { fun = fun_; }
};
/// @brief Solid isotropic material penalization (SIMP) coefficient
class SIMPInterpolationCoefficient : public Coefficient
{
protected:
GridFunction *rho_filter;
real_t min_val;
real_t max_val;
real_t exponent;
public:
SIMPInterpolationCoefficient(GridFunction *rho_filter_, real_t min_val_= 1e-6,
real_t max_val_ = 1.0, real_t exponent_ = 3)
: rho_filter(rho_filter_), min_val(min_val_), max_val(max_val_),
exponent(exponent_) { }
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip)
{
real_t val = rho_filter->GetValue(T, ip);
real_t coeff = min_val + pow(val,exponent)*(max_val-min_val);
return coeff;
}
};
/// @brief Strain energy density coefficient
class StrainEnergyDensityCoefficient : public Coefficient
{
protected:
Coefficient * lambda=nullptr;
Coefficient * mu=nullptr;
GridFunction *u = nullptr; // displacement
GridFunction *rho_filter = nullptr; // filter density
DenseMatrix grad; // auxiliary matrix, used in Eval
real_t exponent;
real_t rho_min;
public:
StrainEnergyDensityCoefficient(Coefficient *lambda_, Coefficient *mu_,
GridFunction * u_, GridFunction * rho_filter_, real_t rho_min_=1e-6,
real_t exponent_ = 3.0)
: lambda(lambda_), mu(mu_), u(u_), rho_filter(rho_filter_),
exponent(exponent_), rho_min(rho_min_)
{
MFEM_ASSERT(rho_min_ >= 0.0, "rho_min must be >= 0");
MFEM_ASSERT(rho_min_ < 1.0, "rho_min must be > 1");
MFEM_ASSERT(u, "displacement field is not set");
MFEM_ASSERT(rho_filter, "density field is not set");
}
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip)
{
real_t L = lambda->Eval(T, ip);
real_t M = mu->Eval(T, ip);
u->GetVectorGradient(T, grad);
real_t div_u = grad.Trace();
real_t density = L*div_u*div_u;
int dim = T.GetSpaceDim();
for (int i=0; i<dim; i++)
{
for (int j=0; j<dim; j++)
{
density += M*grad(i,j)*(grad(i,j)+grad(j,i));
}
}
real_t val = rho_filter->GetValue(T,ip);
return -exponent * pow(val, exponent-1.0) * (1-rho_min) * density;
}
};
/// @brief Volumetric force for linear elasticity
class VolumeForceCoefficient : public VectorCoefficient
{
private:
real_t r;
Vector center;
Vector force;
public:
VolumeForceCoefficient(real_t r_,Vector & center_, Vector & force_) :
VectorCoefficient(center_.Size()), r(r_), center(center_), force(force_) { }
using VectorCoefficient::Eval;
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
Vector xx; xx.SetSize(T.GetDimension());
T.Transform(ip,xx);
for (int i=0; i<xx.Size(); i++)
{
xx[i]=xx[i]-center[i];
}
real_t cr=xx.Norml2();
V.SetSize(T.GetDimension());
if (cr <= r)
{
V = force;
}
else
{
V = 0.0;
}
}
void Set(real_t r_,Vector & center_, Vector & force_)
{
r=r_;
center = center_;
force = force_;
}
};
/**
* @brief Class for solving Poisson's equation:
*
* - (κ u) = f in Ω
*
*/
class DiffusionSolver
{
private:
Mesh * mesh = nullptr;
int order = 1;
// diffusion coefficient
Coefficient * diffcf = nullptr;
// mass coefficient
Coefficient * masscf = nullptr;
Coefficient * rhscf = nullptr;
Coefficient * essbdr_cf = nullptr;
Coefficient * neumann_cf = nullptr;
VectorCoefficient * gradient_cf = nullptr;
// FEM solver
int dim;
FiniteElementCollection * fec = nullptr;
FiniteElementSpace * fes = nullptr;
Array<int> ess_bdr;
Array<int> neumann_bdr;
GridFunction * u = nullptr;
LinearForm * b = nullptr;
bool parallel;
#ifdef MFEM_USE_MPI
ParMesh * pmesh = nullptr;
ParFiniteElementSpace * pfes = nullptr;
#endif
public:
DiffusionSolver() { }
DiffusionSolver(Mesh * mesh_, int order_, Coefficient * diffcf_,
Coefficient * cf_);
void SetMesh(Mesh * mesh_)
{
mesh = mesh_;
parallel = false;
#ifdef MFEM_USE_MPI
pmesh = dynamic_cast<ParMesh *>(mesh);
if (pmesh) { parallel = true; }
#endif
}
void SetOrder(int order_) { order = order_ ; }
void SetDiffusionCoefficient(Coefficient * diffcf_) { diffcf = diffcf_; }
void SetMassCoefficient(Coefficient * masscf_) { masscf = masscf_; }
void SetRHSCoefficient(Coefficient * rhscf_) { rhscf = rhscf_; }
void SetEssentialBoundary(const Array<int> & ess_bdr_) { ess_bdr = ess_bdr_;};
void SetNeumannBoundary(const Array<int> & neumann_bdr_) { neumann_bdr = neumann_bdr_;};
void SetNeumannData(Coefficient * neumann_cf_) {neumann_cf = neumann_cf_;}
void SetEssBdrData(Coefficient * essbdr_cf_) {essbdr_cf = essbdr_cf_;}
void SetGradientData(VectorCoefficient * gradient_cf_) {gradient_cf = gradient_cf_;}
void ResetFEM();
void SetupFEM();
void Solve();
GridFunction * GetFEMSolution();
LinearForm * GetLinearForm() {return b;}
#ifdef MFEM_USE_MPI
ParGridFunction * GetParFEMSolution();
ParLinearForm * GetParLinearForm()
{
if (parallel)
{
return dynamic_cast<ParLinearForm *>(b);
}
else
{
MFEM_ABORT("Wrong code path. Call GetLinearForm");
return nullptr;
}
}
#endif
~DiffusionSolver();
};
/**
* @brief Class for solving linear elasticity:
*
* - σ(u) = f in Ω + BCs
*
* where
*
* σ(u) = λ u I + μ ( u + uᵀ)
*
*/
class LinearElasticitySolver
{
private:
Mesh * mesh = nullptr;
int order = 1;
Coefficient * lambda_cf = nullptr;
Coefficient * mu_cf = nullptr;
VectorCoefficient * essbdr_cf = nullptr;
VectorCoefficient * rhs_cf = nullptr;
// FEM solver
int dim;
FiniteElementCollection * fec = nullptr;
FiniteElementSpace * fes = nullptr;
Array<int> ess_bdr;
Array<int> neumann_bdr;
GridFunction * u = nullptr;
LinearForm * b = nullptr;
bool parallel;
#ifdef MFEM_USE_MPI
ParMesh * pmesh = nullptr;
ParFiniteElementSpace * pfes = nullptr;
#endif
public:
LinearElasticitySolver() { }
LinearElasticitySolver(Mesh * mesh_, int order_,
Coefficient * lambda_cf_, Coefficient * mu_cf_);
void SetMesh(Mesh * mesh_)
{
mesh = mesh_;
parallel = false;
#ifdef MFEM_USE_MPI
pmesh = dynamic_cast<ParMesh *>(mesh);
if (pmesh) { parallel = true; }
#endif
}
void SetOrder(int order_) { order = order_ ; }
void SetLameCoefficients(Coefficient * lambda_cf_, Coefficient * mu_cf_) { lambda_cf = lambda_cf_; mu_cf = mu_cf_; }
void SetRHSCoefficient(VectorCoefficient * rhs_cf_) { rhs_cf = rhs_cf_; }
void SetEssentialBoundary(const Array<int> & ess_bdr_) { ess_bdr = ess_bdr_;};
void SetNeumannBoundary(const Array<int> & neumann_bdr_) { neumann_bdr = neumann_bdr_;};
void SetEssBdrData(VectorCoefficient * essbdr_cf_) {essbdr_cf = essbdr_cf_;}
void ResetFEM();
void SetupFEM();
void Solve();
GridFunction * GetFEMSolution();
LinearForm * GetLinearForm() {return b;}
#ifdef MFEM_USE_MPI
ParGridFunction * GetParFEMSolution();
ParLinearForm * GetParLinearForm()
{
if (parallel)
{
return dynamic_cast<ParLinearForm *>(b);
}
else
{
MFEM_ABORT("Wrong code path. Call GetLinearForm");
return nullptr;
}
}
#endif
~LinearElasticitySolver();
};
// Poisson solver
DiffusionSolver::DiffusionSolver(Mesh * mesh_, int order_,
Coefficient * diffcf_, Coefficient * rhscf_)
: mesh(mesh_), order(order_), diffcf(diffcf_), rhscf(rhscf_)
{
#ifdef MFEM_USE_MPI
pmesh = dynamic_cast<ParMesh *>(mesh);
if (pmesh) { parallel = true; }
#endif
SetupFEM();
}
void DiffusionSolver::SetupFEM()
{
dim = mesh->Dimension();
fec = new H1_FECollection(order, dim);
#ifdef MFEM_USE_MPI
if (parallel)
{
pfes = new ParFiniteElementSpace(pmesh, fec);
u = new ParGridFunction(pfes);
b = new ParLinearForm(pfes);
}
else
{
fes = new FiniteElementSpace(mesh, fec);
u = new GridFunction(fes);
b = new LinearForm(fes);
}
#else
fes = new FiniteElementSpace(mesh, fec);
u = new GridFunction(fes);
b = new LinearForm(fes);
#endif
*u=0.0;
if (!ess_bdr.Size())
{
if (mesh->bdr_attributes.Size())
{
ess_bdr.SetSize(mesh->bdr_attributes.Max());
ess_bdr = 1;
}
}
}
void DiffusionSolver::Solve()
{
OperatorPtr A;
Vector B, X;
Array<int> ess_tdof_list;
#ifdef MFEM_USE_MPI
if (parallel)
{
pfes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
}
else
{
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
}
#else
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
#endif
*u=0.0;
if (b)
{
delete b;
#ifdef MFEM_USE_MPI
if (parallel)
{
b = new ParLinearForm(pfes);
}
else
{
b = new LinearForm(fes);
}
#else
b = new LinearForm(fes);
#endif
}
if (rhscf)
{
b->AddDomainIntegrator(new DomainLFIntegrator(*rhscf));
}
if (neumann_cf)
{
MFEM_VERIFY(neumann_bdr.Size(), "neumann_bdr attributes not provided");
b->AddBoundaryIntegrator(new BoundaryLFIntegrator(*neumann_cf),neumann_bdr);
}
else if (gradient_cf)
{
MFEM_VERIFY(neumann_bdr.Size(), "neumann_bdr attributes not provided");
b->AddBoundaryIntegrator(new BoundaryNormalLFIntegrator(*gradient_cf),
neumann_bdr);
}
b->Assemble();
BilinearForm * a = nullptr;
#ifdef MFEM_USE_MPI
if (parallel)
{
a = new ParBilinearForm(pfes);
}
else
{
a = new BilinearForm(fes);
}
#else
a = new BilinearForm(fes);
#endif
a->AddDomainIntegrator(new DiffusionIntegrator(*diffcf));
if (masscf)
{
a->AddDomainIntegrator(new MassIntegrator(*masscf));
}
a->Assemble();
if (essbdr_cf)
{
u->ProjectBdrCoefficient(*essbdr_cf,ess_bdr);
}
a->FormLinearSystem(ess_tdof_list, *u, *b, A, X, B);
CGSolver * cg = nullptr;
Solver * M = nullptr;
#ifdef MFEM_USE_MPI
if (parallel)
{
M = new HypreBoomerAMG;
dynamic_cast<HypreBoomerAMG*>(M)->SetPrintLevel(0);
cg = new CGSolver(pmesh->GetComm());
}
else
{
M = new GSSmoother((SparseMatrix&)(*A));
cg = new CGSolver;
}
#else
M = new GSSmoother((SparseMatrix&)(*A));
cg = new CGSolver;
#endif
cg->SetRelTol(1e-12);
cg->SetMaxIter(10000);
cg->SetPrintLevel(0);
cg->SetPreconditioner(*M);
cg->SetOperator(*A);
cg->Mult(B, X);
delete M;
delete cg;
a->RecoverFEMSolution(X, *b, *u);
delete a;
}
GridFunction * DiffusionSolver::GetFEMSolution()
{
return u;
}
#ifdef MFEM_USE_MPI
ParGridFunction * DiffusionSolver::GetParFEMSolution()
{
if (parallel)
{
return dynamic_cast<ParGridFunction*>(u);
}
else
{
MFEM_ABORT("Wrong code path. Call GetFEMSolution");
return nullptr;
}
}
#endif
DiffusionSolver::~DiffusionSolver()
{
delete u; u = nullptr;
delete fes; fes = nullptr;
#ifdef MFEM_USE_MPI
delete pfes; pfes=nullptr;
#endif
delete fec; fec = nullptr;
delete b;
}
// Elasticity solver
LinearElasticitySolver::LinearElasticitySolver(Mesh * mesh_, int order_,
Coefficient * lambda_cf_, Coefficient * mu_cf_)
: mesh(mesh_), order(order_), lambda_cf(lambda_cf_), mu_cf(mu_cf_)
{
#ifdef MFEM_USE_MPI
pmesh = dynamic_cast<ParMesh *>(mesh);
if (pmesh) { parallel = true; }
#endif
SetupFEM();
}
void LinearElasticitySolver::SetupFEM()
{
dim = mesh->Dimension();
fec = new H1_FECollection(order, dim,BasisType::Positive);
#ifdef MFEM_USE_MPI
if (parallel)
{
pfes = new ParFiniteElementSpace(pmesh, fec, dim);
u = new ParGridFunction(pfes);
b = new ParLinearForm(pfes);
}
else
{
fes = new FiniteElementSpace(mesh, fec,dim);
u = new GridFunction(fes);
b = new LinearForm(fes);
}
#else
fes = new FiniteElementSpace(mesh, fec, dim);
u = new GridFunction(fes);
b = new LinearForm(fes);
#endif
*u=0.0;
if (!ess_bdr.Size())
{
if (mesh->bdr_attributes.Size())
{
ess_bdr.SetSize(mesh->bdr_attributes.Max());
ess_bdr = 1;
}
}
}
void LinearElasticitySolver::Solve()
{
GridFunction * x = nullptr;
OperatorPtr A;
Vector B, X;
Array<int> ess_tdof_list;
#ifdef MFEM_USE_MPI
if (parallel)
{
x = new ParGridFunction(pfes);
pfes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
}
else
{
x = new GridFunction(fes);
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
}
#else
x = new GridFunction(fes);
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
#endif
*u=0.0;
if (b)
{
delete b;
#ifdef MFEM_USE_MPI
if (parallel)
{
b = new ParLinearForm(pfes);
}
else
{
b = new LinearForm(fes);
}
#else
b = new LinearForm(fes);
#endif
}
if (rhs_cf)
{
b->AddDomainIntegrator(new VectorDomainLFIntegrator(*rhs_cf));
}
b->Assemble();
*x = 0.0;
BilinearForm * a = nullptr;
#ifdef MFEM_USE_MPI
if (parallel)
{
a = new ParBilinearForm(pfes);
}
else
{
a = new BilinearForm(fes);
}
#else
a = new BilinearForm(fes);
#endif
a->AddDomainIntegrator(new ElasticityIntegrator(*lambda_cf, *mu_cf));
a->Assemble();
if (essbdr_cf)
{
u->ProjectBdrCoefficient(*essbdr_cf,ess_bdr);
}
a->FormLinearSystem(ess_tdof_list, *x, *b, A, X, B);
CGSolver * cg = nullptr;
Solver * M = nullptr;
#ifdef MFEM_USE_MPI
if (parallel)
{
M = new HypreBoomerAMG;
dynamic_cast<HypreBoomerAMG*>(M)->SetPrintLevel(0);
cg = new CGSolver(pmesh->GetComm());
}
else
{
M = new GSSmoother((SparseMatrix&)(*A));
cg = new CGSolver;
}
#else
M = new GSSmoother((SparseMatrix&)(*A));
cg = new CGSolver;
#endif
cg->SetRelTol(1e-10);
cg->SetMaxIter(10000);
cg->SetPrintLevel(0);
cg->SetPreconditioner(*M);
cg->SetOperator(*A);
cg->Mult(B, X);
delete M;
delete cg;
a->RecoverFEMSolution(X, *b, *x);
*u+=*x;
delete a;
delete x;
}
GridFunction * LinearElasticitySolver::GetFEMSolution()
{
return u;
}
#ifdef MFEM_USE_MPI
ParGridFunction * LinearElasticitySolver::GetParFEMSolution()
{
if (parallel)
{
return dynamic_cast<ParGridFunction*>(u);
}
else
{
MFEM_ABORT("Wrong code path. Call GetFEMSolution");
return nullptr;
}
}
#endif
LinearElasticitySolver::~LinearElasticitySolver()
{
delete u; u = nullptr;
delete fes; fes = nullptr;
#ifdef MFEM_USE_MPI
delete pfes; pfes=nullptr;
#endif
delete fec; fec = nullptr;
delete b;
}
} // namespace mfem
-500
View File
@@ -1,500 +0,0 @@
// MFEM Example 37 - Parallel Version
//
// Compile with: make ex37p
//
// Sample runs:
// mpirun -np 4 ex37p -alpha 10 -pv
// mpirun -np 4 ex37p -lambda 0.1 -mu 0.1
// mpirun -np 4 ex37p -o 2 -alpha 5.0 -mi 50 -vf 0.4 -ntol 1e-5
// mpirun -np 4 ex37p -r 6 -o 2 -alpha 10.0 -epsilon 0.02 -mi 50 -ntol 1e-5
//
// Description: This example code demonstrates the use of MFEM to solve a
// density-filtered [3] topology optimization problem. The
// objective is to minimize the compliance
//
// minimize ∫_Ω f⋅u dx over u ∈ [H¹(Ω)]² and ρ ∈ L¹(Ω)
//
// subject to
//
// -Div(r(ρ̃)Cε(u)) = f in Ω + BCs
// -ϵ²Δρ̃ + ρ̃ = ρ in Ω + Neumann BCs
// 0 ≤ ρ ≤ 1 in Ω
// ∫_Ω ρ dx = θ vol(Ω)
//
// Here, r(ρ̃) = ρ₀ + ρ̃³ (1-ρ₀) is the solid isotropic material
// penalization (SIMP) law, C is the elasticity tensor for an
// isotropic linearly elastic material, ϵ > 0 is the design
// length scale, and 0 < θ < 1 is the volume fraction.
//
// The problem is discretized and gradients are computing using
// finite elements [1]. The design is optimized using an entropic
// mirror descent algorithm introduced by Keith and Surowiec [2]
// that is tailored to the bound constraint 0 ≤ ρ ≤ 1.
//
// This example highlights the ability of MFEM to deliver high-
// order solutions to inverse design problems and showcases how
// to set up and solve PDE-constrained optimization problems
// using the so-called reduced space approach.
//
// [1] Andreassen, E., Clausen, A., Schevenels, M., Lazarov, B. S., & Sigmund, O.
// (2011). Efficient topology optimization in MATLAB using 88 lines of
// code. Structural and Multidisciplinary Optimization, 43(1), 1-16.
// [2] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
// [3] Lazarov, B. S., & Sigmund, O. (2011). Filters in topology optimization
// based on Helmholtztype differential equations. International Journal
// for Numerical Methods in Engineering, 86(6), 765-781.
#include "mfem.hpp"
#include <iostream>
#include <fstream>
#include "ex37.hpp"
using namespace std;
using namespace mfem;
/**
* @brief Bregman projection of ρ = sigmoid(ψ) onto the subspace
* ρ dx = θ vol(Ω) as follows:
*
* 1. Compute the root of the R R function
* f(c) = sigmoid(ψ + c) dx - θ vol(Ω)
* 2. Set ψ ψ + c.
*
* @param psi a GridFunction to be updated
* @param target_volume θ vol(Ω)
* @param tol Newton iteration tolerance
* @param max_its Newton maximum iteration number
* @return real_t Final volume, sigmoid(ψ)
*/
real_t proj(ParGridFunction &psi, real_t target_volume, real_t tol=1e-12,
int max_its=10)
{
MappedGridFunctionCoefficient sigmoid_psi(&psi, sigmoid);
MappedGridFunctionCoefficient der_sigmoid_psi(&psi, der_sigmoid);
ParLinearForm int_sigmoid_psi(psi.ParFESpace());
int_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(sigmoid_psi));
ParLinearForm int_der_sigmoid_psi(psi.ParFESpace());
int_der_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(
der_sigmoid_psi));
bool done = false;
for (int k=0; k<max_its; k++) // Newton iteration
{
int_sigmoid_psi.Assemble(); // Recompute f(c) with updated ψ
real_t f = int_sigmoid_psi.Sum();
MPI_Allreduce(MPI_IN_PLACE, &f, 1, MPITypeMap<real_t>::mpi_type,
MPI_SUM, MPI_COMM_WORLD);
f -= target_volume;
int_der_sigmoid_psi.Assemble(); // Recompute df(c) with updated ψ
real_t df = int_der_sigmoid_psi.Sum();
MPI_Allreduce(MPI_IN_PLACE, &df, 1, MPITypeMap<real_t>::mpi_type,
MPI_SUM, MPI_COMM_WORLD);
const real_t dc = -f/df;
psi += dc;
if (abs(dc) < tol) { done = true; break; }
}
if (!done)
{
mfem_warning("Projection reached maximum iteration without converging. "
"Result may not be accurate.");
}
int_sigmoid_psi.Assemble();
real_t material_volume = int_sigmoid_psi.Sum();
MPI_Allreduce(MPI_IN_PLACE, &material_volume, 1,
MPITypeMap<real_t>::mpi_type, MPI_SUM, MPI_COMM_WORLD);
return material_volume;
}
/**
* ---------------------------------------------------------------
* ALGORITHM PREAMBLE
* ---------------------------------------------------------------
*
* The Lagrangian for this problem is
*
* L(u,ρ,ρ̃,w,) = (f,u) - (r(ρ̃) C ε(u),ε(w)) + (f,w)
* - (ϵ² ρ̃,) - (ρ̃,) + (ρ,)
*
* where
*
* r(ρ̃) = ρ + ρ̃³ (1 - ρ) (SIMP rule)
*
* ε(u) = (u + uᵀ)/2 (symmetric gradient)
*
* C e = λtr(e)I + 2μe (isotropic material)
*
* NOTE: The Lame parameters can be computed from Young's modulus E
* and Poisson's ratio ν as follows:
*
* λ = E ν/((1+ν)(1-2ν)), μ = E/(2(1+ν))
*
* ---------------------------------------------------------------
*
* Discretization choices:
*
* u V (H¹) (order p)
* ψ L² (order p - 1), ρ = sigmoid(ψ)
* ρ̃ H¹ (order p)
* w V (order p)
* H¹ (order p)
*
* ---------------------------------------------------------------
* ALGORITHM
* ---------------------------------------------------------------
*
* Update ρ with projected mirror descent via the following algorithm.
*
* 1. Initialize ψ = inv_sigmoid(vol_fraction) so that sigmoid(ψ) = θ vol(Ω)
*
* While not converged:
*
* 2. Solve filter equation _w̃ L = 0; i.e.,
*
* (ϵ² ρ̃, v ) + (ρ̃,v) = (ρ,v) v H¹.
*
* 3. Solve primal problem _w L = 0; i.e.,
*
* (λ r(ρ̃) u, v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v) v V.
*
* NB. The dual problem _u L = 0 is the negative of the primal problem due to symmetry.
*
* 4. Solve for filtered gradient _ρ̃ L = 0; i.e.,
*
* (ϵ² , v ) + ( ,v) = (-r'(ρ̃) ( λ |u|² + 2 μ |ε(u)|²),v) v H¹.
*
* 5. Project the gradient onto the discrete latent space; i.e., solve
*
* (G,v) = (,v) v L².
*
* 6. Bregman proximal gradient update; i.e.,
*
* ψ ψ - αG + c,
*
* where α > 0 is a step size parameter and c R is a constant ensuring
*
* sigmoid(ψ - αG + c) dx = θ vol(Ω).
*
* end
*/
int main(int argc, char *argv[])
{
// 0. Initialize MPI and HYPRE.
Mpi::Init();
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
// 1. Parse command-line options.
int ref_levels = 5;
int order = 2;
real_t alpha = 1.0;
real_t epsilon = 0.01;
real_t vol_fraction = 0.5;
int max_it = 1e3;
real_t itol = 1e-1;
real_t ntol = 1e-4;
real_t rho_min = 1e-6;
real_t lambda = 1.0;
real_t mu = 1.0;
bool glvis_visualization = true;
bool paraview_output = false;
OptionsParser args(argc, argv);
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&alpha, "-alpha", "--alpha-step-length",
"Step length for gradient descent.");
args.AddOption(&epsilon, "-epsilon", "--epsilon-thickness",
"Length scale for ρ.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of gradient descent iterations.");
args.AddOption(&ntol, "-ntol", "--rel-tol",
"Normalized exit tolerance.");
args.AddOption(&itol, "-itol", "--abs-tol",
"Increment exit tolerance.");
args.AddOption(&vol_fraction, "-vf", "--volume-fraction",
"Volume fraction for the material density.");
args.AddOption(&lambda, "-lambda", "--lambda",
"Lamé constant λ.");
args.AddOption(&mu, "-mu", "--mu",
"Lamé constant μ.");
args.AddOption(&rho_min, "-rmin", "--psi-min",
"Minimum of density coefficient.");
args.AddOption(&glvis_visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&paraview_output, "-pv", "--paraview", "-no-pv",
"--no-paraview",
"Enable or disable ParaView output.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
mfem::out << num_procs << " number of process created.\n";
args.PrintOptions(cout);
}
Mesh mesh = Mesh::MakeCartesian2D(3, 1, mfem::Element::Type::QUADRILATERAL,
true, 3.0, 1.0);
int dim = mesh.Dimension();
// 2. Set BCs.
for (int i = 0; i<mesh.GetNBE(); i++)
{
Element * be = mesh.GetBdrElement(i);
Array<int> vertices;
be->GetVertices(vertices);
real_t * coords1 = mesh.GetVertex(vertices[0]);
real_t * coords2 = mesh.GetVertex(vertices[1]);
Vector center(2);
center(0) = 0.5*(coords1[0] + coords2[0]);
center(1) = 0.5*(coords1[1] + coords2[1]);
if (abs(center(0) - 0.0) < 1e-10)
{
// the left edge
be->SetAttribute(1);
}
else
{
// all other boundaries
be->SetAttribute(2);
}
}
mesh.SetAttributes();
// 3. Refine the mesh.
for (int lev = 0; lev < ref_levels; lev++)
{
mesh.UniformRefinement();
}
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
// 4. Define the necessary finite element spaces on the mesh.
H1_FECollection state_fec(order, dim); // space for u
H1_FECollection filter_fec(order, dim); // space for ρ̃
L2_FECollection control_fec(order-1, dim,
BasisType::GaussLobatto); // space for ψ
ParFiniteElementSpace state_fes(&pmesh, &state_fec,dim);
ParFiniteElementSpace filter_fes(&pmesh, &filter_fec);
ParFiniteElementSpace control_fes(&pmesh, &control_fec);
HYPRE_BigInt state_size = state_fes.GlobalTrueVSize();
HYPRE_BigInt control_size = control_fes.GlobalTrueVSize();
HYPRE_BigInt filter_size = filter_fes.GlobalTrueVSize();
if (myid==0)
{
cout << "Number of state unknowns: " << state_size << endl;
cout << "Number of filter unknowns: " << filter_size << endl;
cout << "Number of control unknowns: " << control_size << endl;
}
// 5. Set the initial guess for ρ.
ParGridFunction u(&state_fes);
ParGridFunction psi(&control_fes);
ParGridFunction psi_old(&control_fes);
ParGridFunction rho_filter(&filter_fes);
u = 0.0;
rho_filter = vol_fraction;
psi = inv_sigmoid(vol_fraction);
psi_old = inv_sigmoid(vol_fraction);
// ρ = sigmoid(ψ)
MappedGridFunctionCoefficient rho(&psi, sigmoid);
// Interpolation of ρ = sigmoid(ψ) in control fes (for ParaView output)
ParGridFunction rho_gf(&control_fes);
// ρ - ρ_old = sigmoid(ψ) - sigmoid(ψ_old)
DiffMappedGridFunctionCoefficient succ_diff_rho(&psi, &psi_old, sigmoid);
// 6. Set-up the physics solver.
int maxat = pmesh.bdr_attributes.Max();
Array<int> ess_bdr(maxat);
ess_bdr = 0;
ess_bdr[0] = 1;
ConstantCoefficient one(1.0);
ConstantCoefficient lambda_cf(lambda);
ConstantCoefficient mu_cf(mu);
LinearElasticitySolver * ElasticitySolver = new LinearElasticitySolver();
ElasticitySolver->SetMesh(&pmesh);
ElasticitySolver->SetOrder(state_fec.GetOrder());
ElasticitySolver->SetupFEM();
Vector center(2); center(0) = 2.9; center(1) = 0.5;
Vector force(2); force(0) = 0.0; force(1) = -1.0;
real_t r = 0.05;
VolumeForceCoefficient vforce_cf(r,center,force);
ElasticitySolver->SetRHSCoefficient(&vforce_cf);
ElasticitySolver->SetEssentialBoundary(ess_bdr);
// 7. Set-up the filter solver.
ConstantCoefficient eps2_cf(epsilon*epsilon);
DiffusionSolver * FilterSolver = new DiffusionSolver();
FilterSolver->SetMesh(&pmesh);
FilterSolver->SetOrder(filter_fec.GetOrder());
FilterSolver->SetDiffusionCoefficient(&eps2_cf);
FilterSolver->SetMassCoefficient(&one);
Array<int> ess_bdr_filter;
if (pmesh.bdr_attributes.Size())
{
ess_bdr_filter.SetSize(pmesh.bdr_attributes.Max());
ess_bdr_filter = 0;
}
FilterSolver->SetEssentialBoundary(ess_bdr_filter);
FilterSolver->SetupFEM();
ParBilinearForm mass(&control_fes);
mass.AddDomainIntegrator(new InverseIntegrator(new MassIntegrator(one)));
mass.Assemble();
HypreParMatrix M;
Array<int> empty;
mass.FormSystemMatrix(empty,M);
// 8. Define the Lagrange multiplier and gradient functions.
ParGridFunction grad(&control_fes);
ParGridFunction w_filter(&filter_fes);
// 9. Define some tools for later.
ConstantCoefficient zero(0.0);
ParGridFunction onegf(&control_fes);
onegf = 1.0;
ParGridFunction zerogf(&control_fes);
zerogf = 0.0;
ParLinearForm vol_form(&control_fes);
vol_form.AddDomainIntegrator(new DomainLFIntegrator(one));
vol_form.Assemble();
real_t domain_volume = vol_form(onegf);
const real_t target_volume = domain_volume * vol_fraction;
// 10. Connect to GLVis. Prepare for VisIt output.
char vishost[] = "localhost";
int visport = 19916;
socketstream sout_r;
if (glvis_visualization)
{
sout_r.open(vishost, visport);
sout_r.precision(8);
}
mfem::ParaViewDataCollection paraview_dc("ex37p", &pmesh);
if (paraview_output)
{
rho_gf.ProjectCoefficient(rho);
paraview_dc.SetPrefixPath("ParaView");
paraview_dc.SetLevelsOfDetail(order);
paraview_dc.SetDataFormat(VTKFormat::BINARY);
paraview_dc.SetHighOrderOutput(true);
paraview_dc.SetCycle(0);
paraview_dc.SetTime(0.0);
paraview_dc.RegisterField("displacement",&u);
paraview_dc.RegisterField("density",&rho_gf);
paraview_dc.RegisterField("filtered_density",&rho_filter);
paraview_dc.Save();
}
// 11. Iterate:
for (int k = 1; k <= max_it; k++)
{
if (k > 1) { alpha *= ((real_t) k) / ((real_t) k-1); }
if (myid == 0)
{
cout << "\nStep = " << k << endl;
}
// Step 1 - Filter solve
// Solve (ϵ^2 ∇ ρ̃, ∇ v ) + (ρ̃,v) = (ρ,v)
FilterSolver->SetRHSCoefficient(&rho);
FilterSolver->Solve();
rho_filter = *FilterSolver->GetFEMSolution();
// Step 2 - State solve
// Solve (λ r(ρ̃) ∇⋅u, ∇⋅v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v)
SIMPInterpolationCoefficient SIMP_cf(&rho_filter,rho_min, 1.0);
ProductCoefficient lambda_SIMP_cf(lambda_cf,SIMP_cf);
ProductCoefficient mu_SIMP_cf(mu_cf,SIMP_cf);
ElasticitySolver->SetLameCoefficients(&lambda_SIMP_cf,&mu_SIMP_cf);
ElasticitySolver->Solve();
u = *ElasticitySolver->GetFEMSolution();
// Step 3 - Adjoint filter solve
// Solve (ϵ² ∇ w̃, ∇ v) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v)
StrainEnergyDensityCoefficient rhs_cf(&lambda_cf,&mu_cf,&u, &rho_filter,
rho_min);
FilterSolver->SetRHSCoefficient(&rhs_cf);
FilterSolver->Solve();
w_filter = *FilterSolver->GetFEMSolution();
// Step 4 - Compute gradient
// Solve G = M⁻¹w̃
GridFunctionCoefficient w_cf(&w_filter);
ParLinearForm w_rhs(&control_fes);
w_rhs.AddDomainIntegrator(new DomainLFIntegrator(w_cf));
w_rhs.Assemble();
M.Mult(w_rhs,grad);
// Step 5 - Update design variable ψ ← proj(ψ - αG)
psi.Add(-alpha, grad);
const real_t material_volume = proj(psi, target_volume);
// Compute ||ρ - ρ_old|| in control fes.
real_t norm_increment = zerogf.ComputeL1Error(succ_diff_rho);
real_t norm_reduced_gradient = norm_increment/alpha;
psi_old = psi;
real_t compliance = (*(ElasticitySolver->GetLinearForm()))(u);
MPI_Allreduce(MPI_IN_PLACE, &compliance, 1, MPITypeMap<real_t>::mpi_type,
MPI_SUM, MPI_COMM_WORLD);
if (myid == 0)
{
mfem::out << "norm of the reduced gradient = " << norm_reduced_gradient << endl;
mfem::out << "norm of the increment = " << norm_increment << endl;
mfem::out << "compliance = " << compliance << endl;
mfem::out << "volume fraction = " << material_volume / domain_volume << endl;
}
if (glvis_visualization)
{
ParGridFunction r_gf(&filter_fes);
r_gf.ProjectCoefficient(SIMP_cf);
sout_r << "parallel " << num_procs << " " << myid << "\n";
sout_r << "solution\n" << pmesh << r_gf
<< "window_title 'Design density r(ρ̃)'" << flush;
}
if (paraview_output)
{
rho_gf.ProjectCoefficient(rho);
paraview_dc.SetCycle(k);
paraview_dc.SetTime((real_t)k);
paraview_dc.Save();
}
if (norm_reduced_gradient < ntol && norm_increment < itol)
{
break;
}
}
delete ElasticitySolver;
delete FilterSolver;
return 0;
}
-696
View File
@@ -1,696 +0,0 @@
// MFEM Example 38
//
// Compile with: make ex38
//
// Sample runs:
// (since all sample runs require LAPACK, the * symbol is used to exclude them
// from the automatically generated internal MFEM tests).
// * ex38
// * ex38 -i volumetric1d
// * ex38 -i surface2d
// * ex38 -i surface2d -o 4 -r 5
// * ex38 -i volumetric2d
// * ex38 -i volumetric2d -o 4 -r 5
// * ex38 -i surface3d
// * ex38 -i surface3d -o 4 -r 5
// * ex38 -i volumetric3d
// * ex38 -i volumetric3d -o 4 -r 5
//
// Description: This example code demonstrates the use of MFEM to integrate
// functions over implicit interfaces and subdomains bounded by
// implicit interfaces.
//
// The quadrature rules are constructed by means of moment-fitting.
// The interface is given by the zero isoline of a level-set
// function ϕ and the subdomain is given as the domain where ϕ>0
// holds. The algorithm for construction of the quadrature rules
// was introduced by Mueller, Kummer and Oberlack [1].
//
// This example also showcases how to set up integrators using the
// integration rules on implicit surfaces and subdomains.
//
// [1] Mueller, B., Kummer, F. and Oberlack, M. (2013) Highly accurate surface
// and volume integration on implicit domains by means of moment-fitting.
// Int. J. Numer. Meth. Engr. (96) 512-528. DOI:10.1002/nme.4569
#include "mfem.hpp"
#include <iostream>
using namespace std;
using namespace mfem;
/// @brief Integration rule the example should demonstrate
enum class IntegrationType { Volumetric1D, Surface2D, Volumetric2D,
Surface3D, Volumetric3D
};
IntegrationType itype;
/// @brief Level-set function defining the implicit interface
real_t lvlset(const Vector& X)
{
switch (itype)
{
case IntegrationType::Volumetric1D:
return .55 - X(0);
case IntegrationType::Surface2D:
return 1. - (pow(X(0), 2.) + pow(X(1), 2.));
case IntegrationType::Volumetric2D:
return 1. - (pow(X(0) / 1.5, 2.) + pow(X(1) / .75, 2.));
case IntegrationType::Surface3D:
return 1. - (pow(X(0), 2.) + pow(X(1), 2.) + pow(X(2), 2.));
case IntegrationType::Volumetric3D:
return 1. - (pow(X(0) / 1.5, 2.) + pow(X(1) / .75, 2.) + pow(X(2) / .5, 2.));
default:
return 1.;
}
}
/// @brief Function that should be integrated
real_t integrand(const Vector& X)
{
switch (itype)
{
case IntegrationType::Volumetric1D:
return 1.;
case IntegrationType::Surface2D:
return 3. * pow(X(0), 2.) - pow(X(1), 2.);
case IntegrationType::Volumetric2D:
return 1.;
case IntegrationType::Surface3D:
return 4. - 3. * pow(X(0), 2.) + 2. * pow(X(1), 2.) - pow(X(2), 2.);
case IntegrationType::Volumetric3D:
return 1.;
default:
return 0.;
}
}
/// @brief Analytic surface integral
real_t Surface()
{
switch (itype)
{
case IntegrationType::Volumetric1D:
return 1.;
case IntegrationType::Surface2D:
return 2. * M_PI;
case IntegrationType::Volumetric2D:
return 7.26633616541076;
case IntegrationType::Surface3D:
return 40. / 3. * M_PI;
case IntegrationType::Volumetric3D:
return 9.90182151329315;
default:
return 0.;
}
}
/// @brief Analytic volume integral over subdomain with positive level-set
real_t Volume()
{
switch (itype)
{
case IntegrationType::Volumetric1D:
return .55;
case IntegrationType::Surface2D:
return NAN;
case IntegrationType::Volumetric2D:
return 9. / 8. * M_PI;
case IntegrationType::Surface3D:
return NAN;
case IntegrationType::Volumetric3D:
return 3. / 4. * M_PI;
default:
return 0.;
}
}
#ifdef MFEM_USE_LAPACK
/**
@brief Class for surface IntegrationRule
This class demonstrates how IntegrationRules computed as CutIntegrationRules
can be saved to reduce the impact by computing them from scratch each time.
*/
class SIntegrationRule : public IntegrationRule
{
protected:
/// @brief Space Dimension of the IntegrationRule
int dim;
/// @brief Column-wise matrix of the quadtrature weights
DenseMatrix Weights;
/// @brief Column-wise matrix of the transformation weights of the normal
DenseMatrix SurfaceWeights;
public:
/**
@brief Constructor of SIntegrationRule
The surface integrationRules are computed and saved in the constructor.
@param [in] Order Order of the IntegrationRule
@param [in] LvlSet Level-set defining the implicit interface
@param [in] lsOrder Polynomial degree for approx of level-set function
@param [in] mesh Pointer to the mesh that is used
*/
SIntegrationRule(int Order, Coefficient& LvlSet, int lsOrder, Mesh* mesh)
{
dim = mesh->Dimension();
IsoparametricTransformation Tr;
MomentFittingIntRules MFIRs(Order, LvlSet, lsOrder);
mesh->GetElementTransformation(0, &Tr);
IntegrationRule ir;
MFIRs.GetSurfaceIntegrationRule(Tr, ir);
if (dim >1)
{
Weights.SetSize(ir.GetNPoints(), mesh->GetNE());
}
else
{
Weights.SetSize(2, mesh->GetNE());
}
SurfaceWeights.SetSize(ir.GetNPoints(), mesh->GetNE());
Vector w;
MFIRs.GetSurfaceWeights(Tr, ir, w);
SurfaceWeights.SetCol(0, w);
SetSize(ir.GetNPoints());
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntPoint(ip).index = ip;
IntegrationPoint &intp = IntPoint(ip);
intp.x = ir.IntPoint(ip).x;
intp.y = ir.IntPoint(ip).y;
intp.z = ir.IntPoint(ip).z;
if (dim > 1)
{
Weights(ip, 0) = ir.IntPoint(ip).weight;
}
else
{
Weights(0, 0) = ir.IntPoint(ip).x;
Weights(1, 0) = ir.IntPoint(ip).weight;
}
}
for (int elem = 1; elem < mesh->GetNE(); elem++)
{
mesh->GetElementTransformation(elem, &Tr);
MFIRs.GetSurfaceIntegrationRule(Tr, ir);
Vector w;
MFIRs.GetSurfaceWeights(Tr, ir, w);
SurfaceWeights.SetCol(elem, w);
for (int ip = 0; ip < GetNPoints(); ip++)
{
if (dim > 1)
{
Weights(ip, elem) = ir.IntPoint(ip).weight;
}
else
{
Weights(0, elem) = ir.IntPoint(ip).x;
Weights(1, elem) = ir.IntPoint(ip).weight;
}
}
}
}
/**
@brief Set the weights for the given element and multiply them with the
transformation of the interface
*/
void SetElementinclSurfaceWeight(int Element)
{
if (dim == 1)
{
IntegrationPoint &intp = IntPoint(0);
intp.x = Weights(0, Element);
intp.weight = Weights(1, Element);
cout << intp.x << " " << Element << endl;
}
else
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
intp.weight = Weights(ip, Element) * SurfaceWeights(ip, Element);
}
}
/// @brief Set the weights for the given element
void SetElement(int Element)
{
if (dim == 1)
{
IntegrationPoint &intp = IntPoint(0);
intp.x = Weights(0, Element);
intp.weight = Weights(1, Element);
}
else
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
intp.weight = Weights(ip, Element);
}
}
/// @brief Destructor of SIntegrationRule
~SIntegrationRule() {}
};
/**
@brief Class for volume IntegrationRule
This class demonstrates how IntegrationRules computed as CutIntegrationRules
can be saved to reduce the impact by computing them from scratch each time.
*/
class CIntegrationRule : public IntegrationRule
{
protected:
/// @brief Space Dimension of the IntegrationRule
int dim;
/// @brief Column-wise matrix of the quadtrature weights
DenseMatrix Weights;
public:
/**
@brief Constructor of CIntegrationRule
The volume integrationRules are computed and saved in the constructor.
@param [in] Order Order of the IntegrationRule
@param [in] LvlSet Level-set defining the implicit interface
@param [in] lsOrder Polynomial degree for approx of level-set function
@param [in] mesh Pointer to the mesh that is used
*/
CIntegrationRule(int Order, Coefficient& LvlSet, int lsOrder, Mesh* mesh)
{
dim = mesh->Dimension();
IsoparametricTransformation Tr;
MomentFittingIntRules MFIRs(Order, LvlSet, lsOrder);
mesh->GetElementTransformation(0, &Tr);
IntegrationRule ir;
MFIRs.GetVolumeIntegrationRule(Tr, ir);
if (dim > 1)
{
Weights.SetSize(ir.GetNPoints(), mesh->GetNE());
}
else
{
Weights.SetSize(2 * ir.GetNPoints(), mesh->GetNE());
}
SetSize(ir.GetNPoints());
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntPoint(ip).index = ip;
IntegrationPoint &intp = IntPoint(ip);
intp.x = ir.IntPoint(ip).x;
intp.y = ir.IntPoint(ip).y;
intp.z = ir.IntPoint(ip).z;
if (dim > 1)
{
Weights(ip, 0) = ir.IntPoint(ip).weight;
}
else
{
Weights(2 * ip, 0) = ir.IntPoint(ip).x;
Weights(2 * ip + 1, 0) = ir.IntPoint(ip).weight;
}
}
for (int elem = 1; elem < mesh->GetNE(); elem++)
{
mesh->GetElementTransformation(elem, &Tr);
MFIRs.GetVolumeIntegrationRule(Tr, ir);
for (int ip = 0; ip < GetNPoints(); ip++)
{
if (dim > 1)
{
Weights(ip, elem) = ir.IntPoint(ip).weight;
}
else
{
Weights(2 * ip, elem) = ir.IntPoint(ip).x;
Weights(2 * ip + 1, elem) = ir.IntPoint(ip).weight;
}
}
}
}
/// @brief Set the weights for the given element
void SetElement(int Element)
{
if (dim == 1)
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
intp.x = Weights(2 * ip, Element);
intp.weight = Weights(2 * ip + 1, Element);
}
else
for (int ip = 0; ip < GetNPoints(); ip++)
{
IntegrationPoint &intp = IntPoint(ip);
intp.weight = Weights(ip, Element);
}
}
/// @brief Destructor of CIntegrationRule
~CIntegrationRule() {}
};
/**
@brief Class for surface linearform integrator
Integrator to demonstrate the use of the surface integration rule on an
implicit surface defined by a level-set.
*/
class SurfaceLFIntegrator : public LinearFormIntegrator
{
protected:
/// @brief vector to evaluate the basis functions
Vector shape;
/// @brief surface integration rule
SIntegrationRule* SIntRule;
/// @brief coefficient representing the level-set defining the interface
Coefficient &LevelSet;
/// @brief coefficient representing the integrand
Coefficient &Q;
public:
/**
@brief Constructor for the surface linear form integrator
Constructor for the surface linear form integrator to demonstrate the use
of the surface integration rule by means of moment-fitting.
@param [in] q coefficient representing the inegrand
@param [in] levelset level-set defining the implicit interfac
@param [in] ir surface integrtion rule to be used
*/
SurfaceLFIntegrator(Coefficient &q, Coefficient &levelset,
SIntegrationRule* ir)
: LinearFormIntegrator(), SIntRule(ir), LevelSet(levelset), Q(q) { }
/**
@brief Assembly of the element vector
Assemble the element vector of for the right hand side on the element given
by the FiniteElement and ElementTransformation.
@param [in] el finite Element the vector belongs to
@param [in] Tr transformation of finite element
@param [out] elvect vector containing the
*/
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect) override
{
int dof = el.GetDof();
shape.SetSize(dof);
elvect.SetSize(dof);
elvect = 0.;
// Update the surface integration rule for the current element
SIntRule->SetElementinclSurfaceWeight(Tr.ElementNo);
for (int ip = 0; ip < SIntRule->GetNPoints(); ip++)
{
Tr.SetIntPoint((&(SIntRule->IntPoint(ip))));
real_t val = Tr.Weight() * Q.Eval(Tr, SIntRule->IntPoint(ip));
el.CalcShape(SIntRule->IntPoint(ip), shape);
add(elvect, SIntRule->IntPoint(ip).weight * val, shape, elvect);
}
}
};
/**
@brief Class for subdomain linearform integrator
Integrator to demonstrate the use of the subdomain integration rule within
an area defined by an implicit surface defined by a level-set.
*/
class SubdomainLFIntegrator : public LinearFormIntegrator
{
protected:
/// @brief vector to evaluate the basis functions
Vector shape;
/// @brief surface integration rule
CIntegrationRule* CIntRule;
/// @brief coefficient representing the level-set defining the interface
Coefficient &LevelSet;
/// @brief coefficient representing the integrand
Coefficient &Q;
public:
/**
@brief Constructor for the volumetric subdomain linear form integrator
Constructor for the subdomain linear form integrator to demonstrate the use
of the volumetric subdomain integration rule by means of moment-fitting.
@param [in] q coefficient representing the inegrand
@param [in] levelset level-set defining the implicit interfac
@param [in] ir subdomain integrtion rule to be used
*/
SubdomainLFIntegrator(Coefficient &q, Coefficient &levelset,
CIntegrationRule* ir)
: LinearFormIntegrator(), CIntRule(ir), LevelSet(levelset), Q(q) { }
/**
@brief Assembly of the element vector
Assemble the element vector of for the right hand side on the element given
by the FiniteElement and ElementTransformation.
@param [in] el finite Element the vector belongs to
@param [in] Tr transformation of finite element
@param [out] elvect vector containing the
*/
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect) override
{
int dof = el.GetDof();
shape.SetSize(dof);
elvect.SetSize(dof);
elvect = 0.;
// Update the subdomain integration rule
CIntRule->SetElement(Tr.ElementNo);
for (int ip = 0; ip < CIntRule->GetNPoints(); ip++)
{
Tr.SetIntPoint((&(CIntRule->IntPoint(ip))));
real_t val = Tr.Weight()
* Q.Eval(Tr, CIntRule->IntPoint(ip));
el.CalcPhysShape(Tr, shape);
add(elvect, CIntRule->IntPoint(ip).weight * val, shape, elvect);
}
}
};
#endif // MFEM_USE_LAPACK
int main(int argc, char *argv[])
{
#ifndef MFEM_USE_LAPACK
cout << "MFEM must be built with LAPACK for this example." << endl;
return EXIT_FAILURE;
#else
// 1. Parse he command-line options.
int ref_levels = 3;
int order = 2;
const char *inttype = "surface2d";
bool visualization = true;
itype = IntegrationType::Surface2D;
OptionsParser args(argc, argv);
args.AddOption(&order, "-o", "--order", "Order of quadrature rule");
args.AddOption(&ref_levels, "-r", "--refine", "Number of meh refinements");
args.AddOption(&inttype, "-i", "--integrationtype",
"IntegrationType to demonstrate");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.ParseCheck();
if (strcmp(inttype, "volumetric1d") == 0
|| strcmp(inttype, "Volumetric1D") == 0)
{
itype = IntegrationType::Volumetric1D;
}
else if (strcmp(inttype, "surface2d") == 0
|| strcmp(inttype, "Surface2D") == 0)
{
itype = IntegrationType::Surface2D;
}
else if (strcmp(inttype, "volumetric2d") == 0
|| strcmp(inttype, "Volumetric2D") == 0)
{
itype = IntegrationType::Volumetric2D;
}
else if (strcmp(inttype, "surface3d") == 0
|| strcmp(inttype, "Surface3d") == 0)
{
itype = IntegrationType::Surface3D;
}
else if (strcmp(inttype, "volumetric3d") == 0
|| strcmp(inttype, "Volumetric3d") == 0)
{
itype = IntegrationType::Volumetric3D;
}
// 2. Construct and refine the mesh.
Mesh *mesh;
if (itype == IntegrationType::Volumetric1D)
{
mesh = new Mesh("../data/inline-segment.mesh");
}
if (itype == IntegrationType::Surface2D
|| itype == IntegrationType::Volumetric2D)
{
mesh = new Mesh(2, 4, 1, 0, 2);
mesh->AddVertex(-1.6,-1.6);
mesh->AddVertex(1.6,-1.6);
mesh->AddVertex(1.6,1.6);
mesh->AddVertex(-1.6,1.6);
mesh->AddQuad(0,1,2,3);
mesh->FinalizeQuadMesh(1, 0, 1);
}
else if (itype == IntegrationType::Surface3D
|| itype == IntegrationType::Volumetric3D)
{
mesh = new Mesh(3, 8, 1, 0, 3);
mesh->AddVertex(-1.6,-1.6,-1.6);
mesh->AddVertex(1.6,-1.6,-1.6);
mesh->AddVertex(1.6,1.6,-1.6);
mesh->AddVertex(-1.6,1.6,-1.6);
mesh->AddVertex(-1.6,-1.6,1.6);
mesh->AddVertex(1.6,-1.6,1.6);
mesh->AddVertex(1.6,1.6,1.6);
mesh->AddVertex(-1.6,1.6,1.6);
mesh->AddHex(0,1,2,3,4,5,6,7);
mesh->FinalizeHexMesh(1, 0, 1);
}
for (int lev = 0; lev < ref_levels; lev++)
{
mesh->UniformRefinement();
}
// 3. Define the necessary finite element space on the mesh.
H1_FECollection fe_coll(1, mesh->Dimension());
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, &fe_coll);
// 4. Construction Coefficients for the level set and the integrand.
FunctionCoefficient levelset(lvlset);
FunctionCoefficient u(integrand);
// 5. Define the necessary Integration rules on element 0.
IsoparametricTransformation Tr;
mesh->GetElementTransformation(0, &Tr);
SIntegrationRule* sir = new SIntegrationRule(order, levelset, 2, mesh);
CIntegrationRule* cir = NULL;
if (itype == IntegrationType::Volumetric1D
|| itype == IntegrationType::Volumetric2D
|| itype == IntegrationType::Volumetric3D)
{
cir = new CIntegrationRule(order, levelset, 2, mesh);
}
// 6. Define and assemble the linear forms on the finite element space.
LinearForm surface(fespace);
LinearForm volume(fespace);
surface.AddDomainIntegrator(new SurfaceLFIntegrator(u, levelset, sir));
surface.Assemble();
if (itype == IntegrationType::Volumetric1D
|| itype == IntegrationType::Volumetric2D
|| itype == IntegrationType::Volumetric3D)
{
volume.AddDomainIntegrator(new SubdomainLFIntegrator(u, levelset, cir));
volume.Assemble();
}
// 7. Print information, computed values and errors to the console.
int qorder = 0;
int nbasis = 2 * (order + 1) + (int)(order * (order + 1) / 2);
IntegrationRules irs(0, Quadrature1D::GaussLegendre);
IntegrationRule ir = irs.Get(Geometry::SQUARE, qorder);
for (; ir.GetNPoints() <= nbasis; qorder++)
{
ir = irs.Get(Geometry::SQUARE, qorder);
}
cout << "============================================" << endl;
cout << "Mesh size dx: ";
if (itype != IntegrationType::Volumetric1D)
{
cout << 3.2 / pow(2., (real_t)ref_levels) << endl;
}
else
{
cout << .25 / pow(2., (real_t)ref_levels) << endl;
}
if (itype == IntegrationType::Surface2D
|| itype == IntegrationType::Volumetric2D)
{
cout << "Number of div free basis functions: " << nbasis << endl;
cout << "Number of quadrature points: " << ir.GetNPoints() << endl;
}
cout << scientific << setprecision(2);
cout << "============================================" << endl;
cout << "Computed value of surface integral: " << surface.Sum() << endl;
cout << "True value of surface integral: " << Surface() << endl;
cout << "Absolute Error (Surface): ";
cout << abs(surface.Sum() - Surface()) << endl;
cout << "Relative Error (Surface): ";
cout << abs(surface.Sum() - Surface()) / Surface() << endl;
if (itype == IntegrationType::Volumetric1D
|| itype == IntegrationType::Volumetric2D
|| itype == IntegrationType::Volumetric3D)
{
cout << "--------------------------------------------" << endl;
cout << "Computed value of volume integral: " << volume.Sum() << endl;
cout << "True value of volume integral: " << Volume() << endl;
cout << "Absolute Error (Volume): ";
cout << abs(volume.Sum() - Volume()) << endl;
cout << "Relative Error (Volume): ";
cout << abs(volume.Sum() - Volume()) / Volume() << endl;
}
cout << "============================================" << endl;
// 8. Plot the level-set function on a high order finite element space.
if (visualization)
{
H1_FECollection fe_coll2(5, mesh->Dimension());
FiniteElementSpace fespace2(mesh, &fe_coll2);
FunctionCoefficient levelset_coeff(levelset);
GridFunction lgf(&fespace2);
lgf.ProjectCoefficient(levelset_coeff);
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << lgf << flush;
sol_sock << "keys pppppppppppppppppppppppppppcmmlRj\n";
sol_sock << "levellines " << 0. << " " << 0. << " " << 1 << "\n" << flush;
}
delete sir;
delete cir;
delete fespace;
delete mesh;
return EXIT_SUCCESS;
#endif //MFEM_USE_LAPACK
}
+2 -12
View File
@@ -5,7 +5,6 @@
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh -nc -o 2
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh -o 2 -pa
// mpirun -np 4 ex3p -m ../data/escher.mesh
@@ -55,7 +54,7 @@ using namespace mfem;
// Exact solution, E, and r.h.s., f. See below for implementation.
void E_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
real_t freq = 1.0, kappa;
double freq = 1.0, kappa;
int dim;
int main(int argc, char *argv[])
@@ -71,7 +70,6 @@ int main(int argc, char *argv[])
int order = 1;
bool static_cond = false;
bool pa = false;
bool nc = false;
const char *device_config = "cpu";
bool visualization = true;
#ifdef MFEM_USE_AMGX
@@ -89,9 +87,6 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&nc, "-nc", "--non-conforming", "-c",
"--conforming",
"Mark the mesh as nonconforming before partitioning.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
@@ -129,11 +124,6 @@ int main(int argc, char *argv[])
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
if (nc)
{
// Can set to false to use conformal refinement for simplices.
mesh->EnsureNCMesh(true);
}
// 5. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
@@ -263,7 +253,7 @@ int main(int argc, char *argv[])
// 15. Compute and print the L^2 norm of the error.
{
real_t error = x.ComputeL2Error(E);
double error = x.ComputeL2Error(E);
if (myid == 0)
{
cout << "\n|| E_h - E ||_{L^2} = " << error << '\n' << endl;
+8 -8
View File
@@ -54,7 +54,7 @@ using namespace mfem;
// Exact solution, F, and r.h.s., f. See below for implementation.
void F_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
real_t freq = 1.0, kappa;
double freq = 1.0, kappa;
int main(int argc, char *argv[])
{
@@ -269,9 +269,9 @@ void F_exact(const Vector &p, Vector &F)
{
int dim = p.Size();
real_t x = p(0);
real_t y = p(1);
// real_t z = (dim == 3) ? p(2) : 0.0; // Uncomment if F is changed to depend on z
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if F is changed to depend on z
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
@@ -286,11 +286,11 @@ void f_exact(const Vector &p, Vector &f)
{
int dim = p.Size();
real_t x = p(0);
real_t y = p(1);
// real_t z = (dim == 3) ? p(2) : 0.0; // Uncomment if f is changed to depend on z
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if f is changed to depend on z
real_t temp = 1 + 2*kappa*kappa;
double temp = 1 + 2*kappa*kappa;
f(0) = temp*cos(kappa*x)*sin(kappa*y);
f(1) = temp*cos(kappa*y)*sin(kappa*x);
+9 -9
View File
@@ -54,7 +54,7 @@ using namespace mfem;
// Exact solution, F, and r.h.s., f. See below for implementation.
void F_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
real_t freq = 1.0, kappa;
double freq = 1.0, kappa;
int main(int argc, char *argv[])
{
@@ -255,7 +255,7 @@ int main(int argc, char *argv[])
// 15. Compute and print the L^2 norm of the error.
{
real_t error = x.ComputeL2Error(F);
double error = x.ComputeL2Error(F);
if (myid == 0)
{
cout << "\n|| F_h - F ||_{L^2} = " << error << '\n' << endl;
@@ -311,9 +311,9 @@ void F_exact(const Vector &p, Vector &F)
{
int dim = p.Size();
real_t x = p(0);
real_t y = p(1);
// real_t z = (dim == 3) ? p(2) : 0.0; // Uncomment if F is changed to depend on z
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if F is changed to depend on z
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
@@ -328,11 +328,11 @@ void f_exact(const Vector &p, Vector &f)
{
int dim = p.Size();
real_t x = p(0);
real_t y = p(1);
// real_t z = (dim == 3) ? p(2) : 0.0; // Uncomment if f is changed to depend on z
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if f is changed to depend on z
real_t temp = 1 + 2*kappa*kappa;
double temp = 1 + 2*kappa*kappa;
f(0) = temp*cos(kappa*x)*sin(kappa*y);
f(1) = temp*cos(kappa*y)*sin(kappa*x);
+18 -18
View File
@@ -45,10 +45,10 @@ using namespace mfem;
// Define the analytical solution and forcing terms / boundary conditions
void uFun_ex(const Vector & x, Vector & u);
real_t pFun_ex(const Vector & x);
double pFun_ex(const Vector & x);
void fFun(const Vector & x, Vector & f);
real_t gFun(const Vector & x);
real_t f_natural(const Vector & x);
double gFun(const Vector & x);
double f_natural(const Vector & x);
int main(int argc, char *argv[])
{
@@ -270,8 +270,8 @@ int main(int argc, char *argv[])
// 11. Solve the linear system with MINRES.
// Check the norm of the unpreconditioned residual.
int maxIter(1000);
real_t rtol(1.e-6);
real_t atol(1.e-10);
double rtol(1.e-6);
double atol(1.e-10);
chrono.Clear();
chrono.Start();
@@ -313,10 +313,10 @@ int main(int argc, char *argv[])
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t err_u = u.ComputeL2Error(ucoeff, irs);
real_t norm_u = ComputeLpNorm(2., ucoeff, *mesh, irs);
real_t err_p = p.ComputeL2Error(pcoeff, irs);
real_t norm_p = ComputeLpNorm(2., pcoeff, *mesh, irs);
double err_u = u.ComputeL2Error(ucoeff, irs);
double norm_u = ComputeLpNorm(2., ucoeff, *mesh, irs);
double err_p = p.ComputeL2Error(pcoeff, irs);
double norm_p = ComputeLpNorm(2., pcoeff, *mesh, irs);
std::cout << "|| u_h - u_ex || / || u_ex || = " << err_u / norm_u << "\n";
std::cout << "|| p_h - p_ex || / || p_ex || = " << err_p / norm_p << "\n";
@@ -391,9 +391,9 @@ int main(int argc, char *argv[])
void uFun_ex(const Vector & x, Vector & u)
{
real_t xi(x(0));
real_t yi(x(1));
real_t zi(0.0);
double xi(x(0));
double yi(x(1));
double zi(0.0);
if (x.Size() == 3)
{
zi = x(2);
@@ -409,11 +409,11 @@ void uFun_ex(const Vector & x, Vector & u)
}
// Change if needed
real_t pFun_ex(const Vector & x)
double pFun_ex(const Vector & x)
{
real_t xi(x(0));
real_t yi(x(1));
real_t zi(0.0);
double xi(x(0));
double yi(x(1));
double zi(0.0);
if (x.Size() == 3)
{
@@ -428,7 +428,7 @@ void fFun(const Vector & x, Vector & f)
f = 0.0;
}
real_t gFun(const Vector & x)
double gFun(const Vector & x)
{
if (x.Size() == 3)
{
@@ -440,7 +440,7 @@ real_t gFun(const Vector & x)
}
}
real_t f_natural(const Vector & x)
double f_natural(const Vector & x)
{
return (-pFun_ex(x));
}
+18 -18
View File
@@ -46,10 +46,10 @@ using namespace mfem;
// Define the analytical solution and forcing terms / boundary conditions
void uFun_ex(const Vector & x, Vector & u);
real_t pFun_ex(const Vector & x);
double pFun_ex(const Vector & x);
void fFun(const Vector & x, Vector & f);
real_t gFun(const Vector & x);
real_t f_natural(const Vector & x);
double gFun(const Vector & x);
double f_natural(const Vector & x);
int main(int argc, char *argv[])
{
@@ -326,8 +326,8 @@ int main(int argc, char *argv[])
// 13. Solve the linear system with MINRES.
// Check the norm of the unpreconditioned residual.
int maxIter(pa ? 1000 : 500);
real_t rtol(1.e-6);
real_t atol(1.e-10);
double rtol(1.e-6);
double atol(1.e-10);
chrono.Clear();
chrono.Start();
@@ -371,10 +371,10 @@ int main(int argc, char *argv[])
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t err_u = u->ComputeL2Error(ucoeff, irs);
real_t norm_u = ComputeGlobalLpNorm(2, ucoeff, *pmesh, irs);
real_t err_p = p->ComputeL2Error(pcoeff, irs);
real_t norm_p = ComputeGlobalLpNorm(2, pcoeff, *pmesh, irs);
double err_u = u->ComputeL2Error(ucoeff, irs);
double norm_u = ComputeGlobalLpNorm(2, ucoeff, *pmesh, irs);
double err_p = p->ComputeL2Error(pcoeff, irs);
double norm_p = ComputeGlobalLpNorm(2, pcoeff, *pmesh, irs);
if (verbose)
{
@@ -493,9 +493,9 @@ int main(int argc, char *argv[])
void uFun_ex(const Vector & x, Vector & u)
{
real_t xi(x(0));
real_t yi(x(1));
real_t zi(0.0);
double xi(x(0));
double yi(x(1));
double zi(0.0);
if (x.Size() == 3)
{
zi = x(2);
@@ -511,11 +511,11 @@ void uFun_ex(const Vector & x, Vector & u)
}
// Change if needed
real_t pFun_ex(const Vector & x)
double pFun_ex(const Vector & x)
{
real_t xi(x(0));
real_t yi(x(1));
real_t zi(0.0);
double xi(x(0));
double yi(x(1));
double zi(0.0);
if (x.Size() == 3)
{
@@ -530,7 +530,7 @@ void fFun(const Vector & x, Vector & f)
f = 0.0;
}
real_t gFun(const Vector & x)
double gFun(const Vector & x)
{
if (x.Size() == 3)
{
@@ -542,7 +542,7 @@ real_t gFun(const Vector & x)
}
}
real_t f_natural(const Vector & x)
double f_natural(const Vector & x)
{
return (-pFun_ex(x));
}
+8 -8
View File
@@ -28,8 +28,8 @@ using namespace std;
using namespace mfem;
// Exact solution and r.h.s., see below for implementation.
real_t analytic_solution(const Vector &x);
real_t analytic_rhs(const Vector &x);
double analytic_solution(const Vector &x);
double analytic_rhs(const Vector &x);
void SnapNodes(Mesh &mesh);
int main(int argc, char *argv[])
@@ -81,7 +81,7 @@ int main(int argc, char *argv[])
if (elem_type == 0) // inscribed octahedron
{
const real_t tri_v[6][3] =
const double tri_v[6][3] =
{
{ 1, 0, 0}, { 0, 1, 0}, {-1, 0, 0},
{ 0, -1, 0}, { 0, 0, 1}, { 0, 0, -1}
@@ -105,7 +105,7 @@ int main(int argc, char *argv[])
}
else // inscribed cube
{
const real_t quad_v[8][3] =
const double quad_v[8][3] =
{
{-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1},
{-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1}
@@ -249,15 +249,15 @@ int main(int argc, char *argv[])
return 0;
}
real_t analytic_solution(const Vector &x)
double analytic_solution(const Vector &x)
{
real_t l2 = x(0)*x(0) + x(1)*x(1) + x(2)*x(2);
double l2 = x(0)*x(0) + x(1)*x(1) + x(2)*x(2);
return x(0)*x(1)/l2;
}
real_t analytic_rhs(const Vector &x)
double analytic_rhs(const Vector &x)
{
real_t l2 = x(0)*x(0) + x(1)*x(1) + x(2)*x(2);
double l2 = x(0)*x(0) + x(1)*x(1) + x(2)*x(2);
return 7*x(0)*x(1)/l2;
}
+9 -9
View File
@@ -28,8 +28,8 @@ using namespace std;
using namespace mfem;
// Exact solution and r.h.s., see below for implementation.
real_t analytic_solution(const Vector &x);
real_t analytic_rhs(const Vector &x);
double analytic_solution(const Vector &x);
double analytic_rhs(const Vector &x);
void SnapNodes(Mesh &mesh);
int main(int argc, char *argv[])
@@ -101,7 +101,7 @@ int main(int argc, char *argv[])
if (elem_type == 0) // inscribed octahedron
{
const real_t tri_v[6][3] =
const double tri_v[6][3] =
{
{ 1, 0, 0}, { 0, 1, 0}, {-1, 0, 0},
{ 0, -1, 0}, { 0, 0, 1}, { 0, 0, -1}
@@ -125,7 +125,7 @@ int main(int argc, char *argv[])
}
else // inscribed cube
{
const real_t quad_v[8][3] =
const double quad_v[8][3] =
{
{-1, -1, -1}, {+1, -1, -1}, {+1, +1, -1}, {-1, +1, -1},
{-1, -1, +1}, {+1, -1, +1}, {+1, +1, +1}, {-1, +1, +1}
@@ -281,7 +281,7 @@ int main(int argc, char *argv[])
delete b;
// 12. Compute and print the L^2 norm of the error.
real_t error = x.ComputeL2Error(sol_coef);
double error = x.ComputeL2Error(sol_coef);
if (myid == 0)
{
cout << "\nL2 norm of error: " << error << endl;
@@ -323,15 +323,15 @@ int main(int argc, char *argv[])
return 0;
}
real_t analytic_solution(const Vector &x)
double analytic_solution(const Vector &x)
{
real_t l2 = x(0)*x(0) + x(1)*x(1) + x(2)*x(2);
double l2 = x(0)*x(0) + x(1)*x(1) + x(2)*x(2);
return x(0)*x(1)/l2;
}
real_t analytic_rhs(const Vector &x)
double analytic_rhs(const Vector &x)
{
real_t l2 = x(0)*x(0) + x(1)*x(1) + x(2)*x(2);
double l2 = x(0)*x(0) + x(1)*x(1) + x(2)*x(2);
return 7*x(0)*x(1)/l2;
}

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