Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96bd70ce83 | ||
|
|
55e2c232a0 | ||
|
|
fc63b37586 | ||
|
|
e03154cf81 |
@@ -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] }}
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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.*
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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@")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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@
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
+300
-704
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
html {
|
||||
--content-maxwidth: auto;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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"> $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 -->
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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 Helmholtz‐type 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,w̃) = (f,u) - (r(ρ̃) C ε(u),ε(w)) + (f,w)
|
||||
* - (ϵ² ∇ρ̃,∇w̃) - (ρ̃,w̃) + (ρ,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)
|
||||
* w̃ ∈ 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.,
|
||||
*
|
||||
* (ϵ² ∇ w̃ , ∇ v ) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v) ∀ v ∈ H¹.
|
||||
*
|
||||
* 5. Project the gradient onto the discrete latent space; i.e., solve
|
||||
*
|
||||
* (G,v) = (w̃,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(¶view_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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 Helmholtz‐type 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,w̃) = (f,u) - (r(ρ̃) C ε(u),ε(w)) + (f,w)
|
||||
* - (ϵ² ∇ρ̃,∇w̃) - (ρ̃,w̃) + (ρ,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)
|
||||
* w̃ ∈ 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.,
|
||||
*
|
||||
* (ϵ² ∇ w̃ , ∇ v ) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v) ∀ v ∈ H¹.
|
||||
*
|
||||
* 5. Project the gradient onto the discrete latent space; i.e., solve
|
||||
*
|
||||
* (G,v) = (w̃,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(¶view_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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user