Compare commits

..
125 changed files with 1755 additions and 13140 deletions
+2 -2
View File
@@ -82,9 +82,9 @@ jobs:
uses: mfem/github-actions/build-mfem@v2.0
with:
os: ${{ runner.os }}
target: opt
target: optim
codecov: NO
mpi: par
mpi: parallel
build-system: make
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
-8
View File
@@ -225,14 +225,6 @@ miniapps/mtop/ParHeat*
miniapps/mtop/seqheat
miniapps/mtop/SeqHeat*
miniapps/autodiff/paradiff
miniapps/autodiff/seqadiff
miniapps/autodiff/seqtest
miniapps/autodiff/par_example
miniapps/autodiff/seq_example
miniapps/autodiff/seq_test
miniapps/autodiff/Exampl*
miniapps/navier/navier_mms
miniapps/navier/navier_kovasznay
miniapps/navier/navier_kovasznay_vs
+4 -36
View File
@@ -29,34 +29,12 @@ stages:
variables:
CUSTOM_CI_BUILDS_DIR: "/usr/workspace/mfem/gitlab-runner"
USER_CI_TOP_DIR: "${CUSTOM_CI_BUILDS_DIR}/${GITLAB_USER_LOGIN}"
SHARED_REPOS_DIR: "${USER_CI_TOP_DIR}/repos"
AUTOTEST_ROOT: "${SHARED_REPOS_DIR}"
# MFEM_DATA_DIR is setup in '.gitlab/configs/setup-build-and-test.yml' and
# used in '.gitlab/configs/<machine>-config.yml':
MFEM_DATA_DIR: "${SHARED_REPOS_DIR}/mfem-data"
# Defines the default choice for updating the saved baseline results. By default
# the baseline can only be updated from the master branch. This variable offers
# the option to manually ask for rebaselining from another branch if necessary.
REBASELINE: "NO"
AUTOTEST: "NO"
# AUTOTEST_COMMIT: used only when AUTOTEST is set to YES.
# * If AUTOTEST_COMMIT is NOT set to NO, reporting jobs will commit their
# files to the MFEM/autotest repo.
# * If AUTOTEST_COMMIT is set to NO, reporting jobs will NOT commit their
# files to the MFEM/autotest repo. Instead they will just show the contents
# of the report files and remove them.
AUTOTEST_COMMIT: "YES"
# Trigger subpipelines:
quartz-build-and-test:
stage: sub-pipelines
variables:
# Explicitly pass down values that we want to be able to set when triggering
# pipelines manually or using scheduling
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
_AUTOTEST: $AUTOTEST
trigger:
include: .gitlab/quartz-build-and-test.yml
strategy: depend
@@ -64,11 +42,7 @@ quartz-build-and-test:
quartz-baseline:
stage: sub-pipelines
variables:
# Explicitly pass down values that we want to be able to set when triggering
# pipelines manually or using scheduling
REBASELINE: "${REBASELINE}"
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
_AUTOTEST: $AUTOTEST
trigger:
include: .gitlab/quartz-baseline.yml
strategy: depend
@@ -76,10 +50,7 @@ quartz-baseline:
lassen-build-and-test:
stage: sub-pipelines
variables:
# Explicitly pass down values that we want to be able to set when triggering
# pipelines manually or using scheduling
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
_AUTOTEST: $AUTOTEST
trigger:
include: .gitlab/lassen-build-and-test.yml
strategy: depend
@@ -87,10 +58,7 @@ lassen-build-and-test:
corona-build-and-test:
stage: sub-pipelines
variables:
# Explicitly pass down values that we want to be able to set when triggering
# pipelines manually or using scheduling
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
_AUTOTEST: $AUTOTEST
trigger:
include: .gitlab/corona-build-and-test.yml
strategy: depend
+9 -1
View File
@@ -18,13 +18,19 @@ variables:
# the pipeline, preventing any form of concurrency with other pipelines. This
# also means that the BUILD_ROOT directory will never be cleaned.
# TODO: add a clean-up mechanism
BUILD_ROOT: ${USER_CI_TOP_DIR}/${CI_PROJECT_NAME}-${MACHINE_NAME}-pipeline-${CI_PIPELINE_ID}
BUILD_ROOT: ${CI_BUILDS_DIR}/MFEM_${MACHINE_NAME}/${CI_PROJECT_NAME}_${CI_COMMIT_REF_SLUG}_${CI_PIPELINE_ID}
# On LLNL's quartz, there is only one allocation shared among jobs in order to
# save time and resource. This allocation has to be uniquely named so that we
# are sure to retrieve it.
ALLOC_NAME: ${CI_PROJECT_NAME}_ci_${CI_PIPELINE_ID}
# Defines the default choice for updating the saved baseline results. By default
# the baseline can only be updated from the master branch. This variable offers
# the option to manually ask for rebaselining from another branch if necessary.
_REBASELINE: "NO"
_AUTOTEST: "NO"
# Git repositories used in the pipeline
TPLS_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/tpls.git
TESTS_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/tests.git
@@ -34,3 +40,5 @@ variables:
# Directory used to place artifacts.
ARTIFACTS_DIR: artifacts
SLURM_OVERLAP: 1
+5 -10
View File
@@ -26,20 +26,17 @@ variables:
- if: '$CI_COMMIT_BRANCH =~ /_cnone/ || $ON_CORONA != "ON"'
when: never
# Dont run autotest update if...
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
- if: '$CI_JOB_NAME =~ /report/ && $_AUTOTEST != "YES"'
when: never
# Report success on success status
- if: '$CI_JOB_NAME =~ /report_job_success/ && $AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_success/ && $_AUTOTEST == "YES"'
when: on_success
# Report failure on failure status
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $_AUTOTEST == "YES"'
when: on_failure
# Always release resource
- if: '$CI_JOB_NAME =~ /release_resource/'
when: always
# Always cleanup
- if: '$CI_JOB_NAME =~ /cleanup/'
when: always
# Default is to run if previous stage succeeded
- when: on_success
@@ -49,11 +46,9 @@ variables:
extends: [.on_corona]
stage: build_and_test
script:
# THREADS is used by 'tests/gitlab/build_and_test', run below
- export THREADS=12
- echo ${ALLOC_NAME}
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
- echo ${JOBID}
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 15 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 15 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --build-root "${BUILD_ROOT}" --data
+4 -10
View File
@@ -21,17 +21,14 @@ variables:
- if: '$CI_COMMIT_BRANCH =~ /_lnone/ || $ON_LASSEN == "OFF"' #run except if ...
when: never
# Don't run autotest update if...
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
- if: '$CI_JOB_NAME =~ /report/ && $_AUTOTEST != "YES"'
when: never
# Report success on success status
- if: '$CI_JOB_NAME =~ /report_job_success/ && $AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_success/ && $_AUTOTEST == "YES"'
when: on_success
# Report failure on failure status
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $_AUTOTEST == "YES"'
when: on_failure
# Always cleanup
- if: '$CI_JOB_NAME =~ /cleanup/'
when: always
- when: on_success
# Lassen uses a different job scheduler (spectrum lsf) that does not allow
@@ -42,8 +39,5 @@ variables:
extends: [.on_lassen]
stage: build_and_test
script:
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
# Next script uses 'THREADS': leaving it empty --> it uses 'make all -j'
- lalloc 1 -W 30 -q pdebug tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
- lalloc 1 -W 30 -q pdebug tests/gitlab/build_and_test --spec "${SPEC}" --build-root "${BUILD_ROOT}" --data
needs: [setup]
+5 -10
View File
@@ -22,20 +22,17 @@ variables:
- if: '$CI_COMMIT_BRANCH =~ /_qnone/ || $ON_QUARTZ == "OFF"'
when: never
# Don't run autotest update if...
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
- if: '$CI_JOB_NAME =~ /report/ && $_AUTOTEST != "YES"'
when: never
# Report success on success status
- if: '$CI_JOB_NAME =~ /report_job_success/ && $AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_success/ && $_AUTOTEST == "YES"'
when: on_success
# Report failure on failure status
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $_AUTOTEST == "YES"'
when: on_failure
# Always release resource
- if: '$CI_JOB_NAME =~ /release_resource/'
when: always
# Always cleanup
- if: '$CI_JOB_NAME =~ /cleanup/'
when: always
# Default is to run if previous stage succeeded
- when: on_success
@@ -45,11 +42,9 @@ variables:
extends: [.on_quartz]
stage: build_and_test
script:
# THREADS is used by 'tests/gitlab/build_and_test', run below
- export THREADS=12
- echo ${ALLOC_NAME}
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
- echo ${JOBID}
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 30 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 30 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --build-root "${BUILD_ROOT}" --data
-81
View File
@@ -1,81 +0,0 @@
# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Jobs report
.report_job_success:
script:
- echo ${MACHINE_NAME}
- echo ${AUTOTEST}
- echo ${AUTOTEST_COMMIT}
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
- cd ${AUTOTEST_ROOT}
- |
(
date
echo "Waiting to aquire lock on '$PWD/autotest.lock' ..."
# try to get an excusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/autotest.lock'"
date
# Report SUCCESS while holding the file lock on 'autotest.lock'.
# The next script uses the following environment variables:
# - MACHINE_NAME, AUTOTEST_ROOT, AUTOTEST_COMMIT
# - CI_COMMIT_REF_SLUG, CI_PROJECT_DIR, CI_PIPELINE_URL
# It also calls the script '.gitlab/scripts/safe_create_rundir'.
${CI_PROJECT_DIR}/.gitlab/scripts/report_build_and_test_success
err=$?
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> autotest.lock
.report_job_failure:
script:
- echo ${MACHINE_NAME}
- echo ${AUTOTEST}
- echo ${AUTOTEST_COMMIT}
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
- cd ${AUTOTEST_ROOT}
- |
(
date
echo "Waiting to aquire lock on '$PWD/autotest.lock' ..."
# try to get an excusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/autotest.lock'"
date
# Report FAILURE while holding the file lock on 'autotest.lock'.
# The next script uses the following environment variables:
# - MACHINE_NAME, AUTOTEST_ROOT, AUTOTEST_COMMIT
# - CI_COMMIT_REF_SLUG, CI_PROJECT_DIR, CI_PIPELINE_URL
# It also calls the script '.gitlab/scripts/safe_create_rundir'.
${CI_PROJECT_DIR}/.gitlab/scripts/report_build_and_test_failure
err=$?
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> autotest.lock
+9 -39
View File
@@ -9,6 +9,13 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# TPLS_DIR is used in .gitlab/scripts/baseline to provide the tpls location
# when call the runtest script in MFEM test repo.
# Note: the value must be consistent with what setup_baseline does.
variables:
TPLS_DIR: ${BUILD_ROOT}/tpls
AUTOTEST_ROOT: ${CI_BUILDS_DIR}/MFEM_${MACHINE_NAME}_baseline
# The setup_baseline job doesn't rely on MFEM git repo. It prepares a
# pipeline-wide working directory downloading/updating external repos.
# TODO:
@@ -23,50 +30,13 @@ setup_baseline:
variables:
GIT_STRATEGY: none
script:
#
# Setup ${BUILD_ROOT}/tpls and ${BUILD_ROOT}/tests:
#
- echo "MACHINE_NAME = ${MACHINE_NAME}"
- echo "REBASELINE = ${REBASELINE}"
- echo "AUTOTEST = ${AUTOTEST}"
- echo "AUTOTEST_COMMIT = ${AUTOTEST_COMMIT}"
- echo "BUILD_ROOT ${BUILD_ROOT}"
- mkdir -p ${BUILD_ROOT} && cd ${BUILD_ROOT}
- if [ ! -d "tpls" ]; then git clone ${TPLS_REPO}; fi
- if [ ! -d "tests" ]; then git clone ${TESTS_REPO}; fi
- cd tpls && git pull && cd ..
- cd tests && git pull origin && cd ..
#
# Setup ${AUTOTEST_ROOT}/autotest:
#
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
- mkdir -p ${AUTOTEST_ROOT} && cd ${AUTOTEST_ROOT}
- command -v flock || echo "Required command 'flock' not found"
- |
(
date
echo "Waiting to aquire lock on '$PWD/autotest.lock' ..."
# try to get an excusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/autotest.lock'"
date
# clone/update the autotest repo while holding the file lock on
# 'autotest.lock'
err=0
if [[ ! -d "autotest" ]]; then
git clone ${AUTOTEST_REPO}
else
cd autotest && git pull && cd ..
fi || err=1
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> autotest.lock
- if [ ! -d "autotest" ]; then git clone ${AUTOTEST_REPO}; fi
- cd autotest && git pull && cd ..
+13 -73
View File
@@ -9,10 +9,13 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Setup clones the mfem/data repo in ${SHARED_REPOS_DIR}. The build_and_test
# script then symlinks the repo to the parent directory of the MFEM source
# directory. Unit tests that depend on the mfem/data repo will then detect that
# this directory is present and be enabled.
variables:
AUTOTEST_ROOT: ${CI_BUILDS_DIR}/MFEM_${MACHINE_NAME}_build_and_test
# setup clones the mfem/data repo in ${BUILD_ROOT}. The build_and_test script
# then symlinks the repo to the parent directory of the MFEM source directory.
# Unit tests that depend on the mfem/data repo will then detect that this
# directory is present and be enabled.
setup:
tags:
- shell
@@ -21,74 +24,11 @@ setup:
variables:
GIT_STRATEGY: none
script:
#
# Setup MFEM_DATA_DIR=${SHARED_REPOS_DIR}/mfem-data, see '.gitlab-ci.yml'
# and '.gitlab/configs/<machine>-config.yml'
#
- echo "MACHINE_NAME = ${MACHINE_NAME}"
- echo "AUTOTEST = ${AUTOTEST}"
- echo "AUTOTEST_COMMIT = ${AUTOTEST_COMMIT}"
- echo "SHARED_REPOS_DIR ${SHARED_REPOS_DIR}"
- mkdir -p ${SHARED_REPOS_DIR} && cd ${SHARED_REPOS_DIR}
- command -v flock || echo "Required command 'flock' not found"
- |
(
date
echo "Waiting to aquire lock on '$PWD/mfem-data.lock' ..."
# try to get an excusive lock on fd 9 (mfem-data.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/mfem-data.lock'"
date
# clone/update the mfem/data repo while holding the file lock on
# 'mfem-data.lock'
err=0
if [[ ! -d "mfem-data" ]]; then
git clone ${MFEM_DATA_REPO} "mfem-data"
else
cd "mfem-data" && git pull && cd ..
fi || err=1
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> mfem-data.lock
#
# Setup ${AUTOTEST_ROOT}/autotest:
#
- echo "BUILD_ROOT ${BUILD_ROOT}"
- mkdir -p ${BUILD_ROOT} && cd ${BUILD_ROOT}
- if [ ! -d data ]; then git clone ${MFEM_DATA_REPO}; fi
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
- mkdir -p ${AUTOTEST_ROOT} && cd ${AUTOTEST_ROOT}
- |
(
date
echo "Waiting to aquire lock on '$PWD/autotest.lock' ..."
# try to get an excusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/autotest.lock'"
date
# clone/update the autotest repo while holding the file lock on
# 'autotest.lock'
err=0
if [[ ! -d "autotest" ]]; then
git clone ${AUTOTEST_REPO}
else
cd autotest && git pull && cd ..
fi || err=1
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> autotest.lock
- if [ ! -d "autotest" ]; then git clone ${AUTOTEST_REPO}; fi
- cd autotest && git pull && cd ..
+6 -10
View File
@@ -22,7 +22,6 @@ allocate_resource:
extends: .on_corona
stage: allocate_resource
script:
- echo ${ALLOC_NAME}
- salloc --exclusive --nodes=1 --partition=mi60 --time=30 --no-shell --job-name=${ALLOC_NAME}
timeout: 6h
needs: [setup]
@@ -41,27 +40,24 @@ release_resource:
extends: .on_corona
stage: release_resource_and_report
script:
- echo ${ALLOC_NAME}
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
- echo ${JOBID}
- ([[ -n "${JOBID}" ]] && scancel ${JOBID})
needs: [rocm_gcc_8.3.1]
# Jobs report
report_job_success:
extends: .on_corona
stage: release_resource_and_report
extends:
- .on_corona
- .report_job_success
script:
- .gitlab/scripts/report_build_and_test_success
report_job_failure:
extends: .on_corona
stage: release_resource_and_report
extends:
- .on_corona
- .report_job_failure
script:
- .gitlab/scripts/report_build_and_test_failure
include:
- local: .gitlab/configs/common.yml
- local: .gitlab/configs/corona-config.yml
- local: .gitlab/configs/setup-build-and-test.yml
- local: .gitlab/configs/report-build-and-test.yml
+6 -7
View File
@@ -21,19 +21,18 @@ opt_mpi_cuda_xl_16_1_1_8:
# Jobs report
report_job_success:
extends: .on_lassen
stage: report
extends:
- .on_lassen
- .report_job_success
script:
- .gitlab/scripts/report_build_and_test_success
report_job_failure:
extends: .on_lassen
stage: report
extends:
- .on_lassen
- .report_job_failure
script:
- .gitlab/scripts/report_build_and_test_failure
include:
- local: .gitlab/configs/common.yml
- local: .gitlab/configs/lassen-config.yml
- local: .gitlab/configs/setup-build-and-test.yml
- local: .gitlab/configs/report-build-and-test.yml
+15 -84
View File
@@ -16,26 +16,12 @@ stages:
- setup
- baseline_check
- baseline_report
- cleanup
- baseline_publish
baselinecheck_mfem_intel_quartz:
extends: [.on_quartz]
stage: baseline_check
variables:
# TPLS_DIR is used in .gitlab/scripts/baseline to provide the tpls location
# when call the runtest script in MFEM test repo.
# Note: the value must be consistent with the setup performed in
# .gitlab/configs/setup-baseline.yml.
TPLS_DIR: ${BUILD_ROOT}/tpls
script:
- echo ${BUILD_ROOT}
- echo ${TPLS_DIR}
# Used by the tests in MFEM/tests:
- export MFEM_TEST_NP=32
# The next script uses the following environment variables:
# * BASELINE_TEST, SYS_TYPE, CI_PROJECT_DIR, ARTIFACTS_DIR,
# * BUILD_ROOT, TPLS_DIR, MACHINE_NAME
- .gitlab/scripts/baseline
artifacts:
when: always
@@ -43,88 +29,33 @@ baselinecheck_mfem_intel_quartz:
- ${ARTIFACTS_DIR}
allow_failure: true
cleanup:
extends: .on_quartz
stage: cleanup
variables:
GIT_STRATEGY: none
script:
- echo "BUILD_ROOT=${BUILD_ROOT}"
- rm -rf "${BUILD_ROOT}" || true
report_baseline:
extends: [.on_quartz]
stage: baseline_report
script:
- echo ${MACHINE_NAME}
- echo ${AUTOTEST}
- echo ${AUTOTEST_COMMIT}
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
- cd ${AUTOTEST_ROOT}
- cd ${AUTOTEST_ROOT}/autotest && git pull
- mkdir -p ${MACHINE_NAME}
- rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-${BASELINE_TEST}-${CI_COMMIT_REF_SLUG}"
- rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir ${rundir})
- cp ${CI_PROJECT_DIR}/${ARTIFACTS_DIR}/* ${rundir}
# We create an autotest-email.html file, because that's how we signal that there was a diff (temporary).
- |
(
date
echo "Waiting to aquire lock on '$PWD/autotest.lock' ..."
# try to get an excusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/autotest.lock'"
date
# ----------------------
cd ${AUTOTEST_ROOT}/autotest || \
{ echo "Invalid 'autotest' dir: ${AUTOTEST_ROOT}/autotest"; exit 1; }
mkdir -p ${MACHINE_NAME}
rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-${BASELINE_TEST}-${CI_COMMIT_REF_SLUG}"
rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir ${rundir})
cp ${CI_PROJECT_DIR}/${ARTIFACTS_DIR}/* ${rundir}
# We create an autotest-email.html file, because that's how we signal that there was a diff (temporary).
if [[ -f ${rundir}/${BASELINE_TEST}.err ]]; then
cp ${rundir}/${BASELINE_TEST}.err ${rundir}/autotest-email.html
fi
printf "%s\n" "" "Pipeline URL:" "$CI_PIPELINE_URL" \
>> ${rundir}/pipeline.txt
msg="GitLab CI log for ${BASELINE_TEST} on ${MACHINE_NAME} ($(date +%Y-%m-%d))"
if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
echo "Content of '$file'"
echo "******************************"
cat $file
echo "******************************"
done
rm -rf ${rundir} || true
fi
err=$?
# ----------------------
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> autotest.lock
if [[ -f ${rundir}/*.err ]]
then
echo "See the pipeline here -> $CI_PIPELINE_URL" >> ${rundir}/*.err
cp ${rundir}/*.err ${rundir}/autotest-email.html
fi
- git add ${rundir}
- git commit -am "GitLab CI log for ${BASELINE_TEST} on ${MACHINE_NAME} with intel ($(date +%Y-%m-%d))"
- git push origin master
baselinepublish_mfem_quartz:
extends: [.on_quartz]
stage: baseline_publish
rules:
# - if: '$CI_COMMIT_BRANCH == "master" || $REBASELINE == "YES"'
- if: '$REBASELINE == "YES"'
- if: '$CI_COMMIT_BRANCH == "master" || $REBASELINE == "YES"'
when: manual
script:
- echo ${BUILD_ROOT}
- echo ${PWD}
- echo ${ARTIFACTS_DIR}
- ls -lA ${ARTIFACTS_DIR}
- .gitlab/scripts/rebaseline
include:
+6 -10
View File
@@ -22,7 +22,6 @@ allocate_resource:
extends: .on_quartz
stage: allocate_resource
script:
- echo ${ALLOC_NAME}
- salloc --exclusive --nodes=1 --partition=pdebug --time=30 --no-shell --job-name=${ALLOC_NAME}
timeout: 6h
@@ -74,26 +73,23 @@ release_resource:
extends: .on_quartz
stage: release_resource_and_report
script:
- echo ${ALLOC_NAME}
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
- echo ${JOBID}
- ([[ -n "${JOBID}" ]] && scancel ${JOBID})
# Jobs report
report_job_success:
extends: .on_quartz
stage: release_resource_and_report
extends:
- .on_quartz
- .report_job_success
script:
- .gitlab/scripts/report_build_and_test_success
report_job_failure:
extends: .on_quartz
stage: release_resource_and_report
extends:
- .on_quartz
- .report_job_failure
script:
- .gitlab/scripts/report_build_and_test_failure
include:
- local: .gitlab/configs/common.yml
- local: .gitlab/configs/quartz-config.yml
- local: .gitlab/configs/setup-build-and-test.yml
- local: .gitlab/configs/report-build-and-test.yml
+1 -9
View File
@@ -20,8 +20,7 @@ base_out=${base}.out
artifacts_path=${CI_PROJECT_DIR}/${ARTIFACTS_DIR}
# prepare
cd ${BUILD_ROOT} || \
{ echo "Invalid BUILD_ROOT=$BUILD_ROOT"; exit 1; }
cd ${BUILD_ROOT}
ln -snf ${CI_PROJECT_DIR} mfem
cd tests
[[ -d _${BASELINE_TEST} ]] && rm -rf _${BASELINE_TEST}
@@ -34,9 +33,6 @@ elif [[ ${MACHINE_NAME} == "corona" ]]; then
srun --nodes=1 -t 60 -p mi60 ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
elif [[ ${MACHINE_NAME} == "lassen" ]]; then
lalloc 1 -q pdebug ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
else
echo "Unknown machine: MACHINE_NAME=$MACHINE_NAME"
exit 1
fi
# post
@@ -64,10 +60,6 @@ then
cp ${base_out} ${artifacts_path}/${base_out}
fi
if [[ -f ${BASELINE_TEST}.out ]]; then
cp ${BASELINE_TEST}.out ${artifacts_path}
fi
# base_diff won't even exist if there is no difference.
if [[ -f ${base_diff} ]]
then
+7 -20
View File
@@ -13,33 +13,20 @@
echo "Runs if there was at least one failure on ${MACHINE_NAME}"
cd ${AUTOTEST_ROOT}/autotest || \
{ echo "Invalid 'autotest' dir: ${AUTOTEST_ROOT}/autotest"; exit 1; }
cd ${AUTOTEST_ROOT}/autotest && git pull
mkdir -p ${MACHINE_NAME}
rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-ci-${CI_COMMIT_REF_SLUG}"
rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir $rundir)
printf "%s\n" "Some 'build-and-test' jobs on ${MACHINE_NAME} FAILED." \
"Pipeline URL:" "$CI_PIPELINE_URL" > ${rundir}/gitlab.err
echo "There was an error while running CI on ${MACHINE_NAME}" > ${rundir}/gitlab.err
echo "See the pipeline here -> $CI_PIPELINE_URL" >> ${rundir}/gitlab.err
msg="GitLab CI log for build-and-test on ${MACHINE_NAME} ($(date +%Y-%m-%d))"
# Create 'autotest-email.html' to indicate failure:
cp ${rundir}/gitlab.err ${rundir}/autotest-email.html
if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
echo "Content of '$file'"
echo "******************************"
cat $file
echo "******************************"
done
rm -rf ${rundir} || true
fi
git pull
git add ${rundir}
git commit -am "${msg}"
git push origin master
+7 -19
View File
@@ -13,30 +13,18 @@
echo "Can only run if all the ${MACHINE_NAME} jobs passed"
cd ${AUTOTEST_ROOT}/autotest || \
{ echo "Invalid 'autotest' dir: ${AUTOTEST_ROOT}/autotest"; exit 1; }
cd ${AUTOTEST_ROOT}/autotest && git pull
mkdir -p ${MACHINE_NAME}
rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-ci-${CI_COMMIT_REF_SLUG}"
rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir $rundir)
printf "%s\n" "The 'build-and-test' jobs on ${MACHINE_NAME} were SUCCESSFUL." \
"Pipeline URL:" "$CI_PIPELINE_URL" > ${rundir}/gitlab.out
echo "The ${MACHINE_NAME} jobs were successful" > ${rundir}/gitlab.out
echo "See the pipeline here -> $CI_PIPELINE_URL" >> ${rundir}/gitlab.err
msg="GitLab CI log for build-and-test on ${MACHINE_NAME} ($(date +%Y-%m-%d))"
if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
echo "Content of '$file'"
echo "******************************"
cat $file
echo "******************************"
done
rm -rf ${rundir} || true
fi
git pull
git add ${rundir}
git commit -am "${msg}"
git push origin master
-11
View File
@@ -10,11 +10,6 @@
Version 4.3.1 (development)
===========================
- Added support for automatic differentiation. Users can select between
native implementation and external library implementation at the
configuration phase. A parallel and two serial examples are implemented
in the autodiff miniapp directory.
- Added support for mesh preprocessing to resolve fine scale problem data
before simulation. This feature uses adaptive mesh refinement to control the
associated data oscillation error. See the new Example 30/30p.
@@ -71,12 +66,6 @@ Version 4.3.1 (development)
- Added initial TMOP-based capabilities for surface fitting and tangential
relaxation in the mesh-optimizer and pmesh-optimizer miniapps.
- Added ParMesh Adjaceny Set (adjset) creation support to the Conduit Mesh
Blueprint MFEM wrapper functions in ConduitDataCollection.
- `HypreParVector` and `Vector` now support move semantics, and the copy
constructor for `HypreParVector` now copies the local vector data.
Version 4.3, released on July 29, 2021
+1 -12
View File
@@ -252,11 +252,6 @@ if (MFEM_USE_OPENMP OR MFEM_USE_LEGACY_OPENMP)
endif()
find_package(OpenMP REQUIRED)
set(OPENMP_LIBRARIES ${OpenMP_CXX_LIBRARIES})
if(APPLE)
# On macOS, the compiler needs additional help to find the <omp.h> header.
# See issue #2642 for more information.
include_directories(${OpenMP_CXX_INCLUDE_DIRS})
endif(APPLE)
endif()
# SuiteSparse (before SUNDIALS which may depend on KLU)
@@ -372,12 +367,6 @@ if (MFEM_USE_HIOP)
# find_package updates HIOP_FOUND, HIOP_INCLUDE_DIRS, HIOP_LIBRARIES
endif()
# CoDiPack package
if (MFEM_USE_CODIPACK)
find_package(CODIPACK REQUIRED)
# find_package updates CODIPACK_FOUND, CODIPACK_INCLUDE_DIRS, CODIPACK_LIBRARIES
endif()
# OCCA
if (MFEM_USE_OCCA)
find_package(OCCA REQUIRED)
@@ -457,7 +446,7 @@ endif()
set(MFEM_TPLS OPENMP HYPRE BLAS LAPACK SuperLUDist METIS SuiteSparse SUNDIALS PETSC
SLEPC MESQUITE MUMPS STRUMPACK AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB NETCDF
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2
CUSPARSE MKL_CPARDISO AMGX CALIPER CODIPACK BENCHMARK PARELAG MPI_CXX)
CUSPARSE MKL_CPARDISO AMGX CALIPER BENCHMARK PARELAG MPI_CXX)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
-1
View File
@@ -123,7 +123,6 @@ The MFEM source code has the following structure:
├── mesh
├── miniapps
│ ├── adjoint
│ ├── autodiff
│ ├── common
│ ├── electromagnetics
│ ├── gslib
-16
View File
@@ -467,14 +467,6 @@ MFEM_USE_HIOP = YES/NO
Enable the usage of HiOp (https://github.com/LLNL/hiop) in MFEM. HiOp is an
HPC solver for nonlinear optimization problems.
MFEM_USE_CODIPACK = YES/NO
Enable automatic differentiation using the CoDiPack library.
www.scicomp.uni-kl.de/codi/
MFEM_USE_ADFORWARD = YES/NO
Enable forward mode for AD packages. This option is valid
only if the AD package supports two modes (backward/forward).
MFEM_USE_CUDA = YES/NO
Enables support for CUDA devices in MFEM. CUDA is a parallel computing
platform and programming model for general computing on graphical processing
@@ -711,11 +703,6 @@ The specific libraries and their options are:
Options: HIOP_OPT, HIOP_LIB.
Versions: HIOP >= 0.4.6.
- CoDiPack (optiobal), used with MFEM_USE_CODIPACK = YES
URL: https://www.scicomp.uni-kl.de/codi/
Options: CODIPACK_OPT
Versions: 1.9.3
- GSLIB (optional), used when MFEM_USE_GSLIB = YES. The gslib library must be
built prior to the MFEM build, as follows: download gslib-1.0.7, untar it at
the same level as MFEM and create a symbolic link: "ln -s gslib-1.0.7 gslib".
@@ -921,8 +908,6 @@ MFEM_USE_MPFR
MFEM_USE_ZLIB
MFEM_USE_PUMI
MFEM_USE_HIOP
MFEM_USE_CODIPACK
MFEM_USE_ADFORWARD
MFEM_USE_CUDA
MFEM_USE_OCCA
MFEM_USE_CEED
@@ -982,7 +967,6 @@ The CMake build system adds auto-detection for the following packages/libraries:
- POSIXCLOCKS
- PUMI
- HIOP
- CoDiPack
- OCCA
- RAJA
- UMPIRE
-2
View File
@@ -54,8 +54,6 @@ set(MFEM_USE_CEED @MFEM_USE_CEED@)
set(MFEM_USE_UMPIRE @MFEM_USE_UMPIRE@)
set(MFEM_USE_SIMD @MFEM_USE_SIMD@)
set(MFEM_USE_ADIOS2 @MFEM_USE_ADIOS2@)
set(MFEM_USE_CODIPACK @MFEM_USE_CODIPACK@)
set(MFEM_USE_ADFORWARD @MFEM_USE_ADFORWARD@)
set(MFEM_USE_CALIPER @MFEM_USE_CALIPER@)
set(MFEM_USE_BENCHMARK @MFEM_USE_BENCHMARK@)
set(MFEM_USE_PARELAG @MFEM_USE_PARELAG@)
-6
View File
@@ -175,12 +175,6 @@
// Enable interface to the MKL CPardiso library.
#cmakedefine MFEM_USE_MKL_CPARDISO
// Use forward mode for automatic differentiation
#cmakedefine MFEM_USE_ADFORWARD
// Enable the use of the CoDiPack library for AD
#cmakedefine MFEM_USE_CODIPACK
// Enable MFEM functionality based on the Google Benchmark library.
#cmakedefine MFEM_USE_BENCHMARK
-24
View File
@@ -1,24 +0,0 @@
# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Automatic differentiation using the CoDiPack library.
# www.scicomp.uni-kl.de/codi/
# Sets the following variables:
# - CODIPACK_FOUND
# - CODIPACK_INCLUDE_DIRS
# - CODIPACK_LIBRARIES
include(MfemCmakeUtilities)
mfem_find_package(CODIPACK CODIPACK CODIPACK_DIR
"include" "codi.h"
"lib" ""
"Paths to headers required by CODIPACK."
"Libraries required by CODIPACK.")
-6
View File
@@ -180,12 +180,6 @@
// Enable interface to the MKL CPardiso library.
// #define MFEM_USE_MKL_CPARDISO
// Use forward mode for automatic differentiation
// #define MFEM_USE_ADFORWARD
// Enable the use of the CoDiPack library for AD
// #define MFEM_USE_CODIPACK
// Enable functionality based on the Google Benchmark library.
// #define MFEM_USE_BENCHMARK
-2
View File
@@ -58,8 +58,6 @@ MFEM_USE_UMPIRE = @MFEM_USE_UMPIRE@
MFEM_USE_SIMD = @MFEM_USE_SIMD@
MFEM_USE_ADIOS2 = @MFEM_USE_ADIOS2@
MFEM_USE_MKL_CPARDISO = @MFEM_USE_MKL_CPARDISO@
MFEM_USE_ADFORWARD = @MFEM_USE_ADFORWARD@
MFEM_USE_CODIPACK = @MFEM_USE_CODIPACK@
MFEM_USE_BENCHMARK = @MFEM_USE_BENCHMARK@
MFEM_USE_PARELAG = @MFEM_USE_PARELAG@
-5
View File
@@ -58,8 +58,6 @@ option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" OFF)
option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
option(MFEM_USE_CALIPER "Enable Caliper support" OFF)
option(MFEM_USE_MKL_CPARDISO "Enable MKL CPardiso" OFF)
option(MFEM_USE_ADFORWARD "Enable forward mode for AD" OFF)
option(MFEM_USE_CODIPACK "Enable automatic differentiation (AD) using CoDiPack" OFF)
option(MFEM_USE_BENCHMARK "Enable Google Benchmark" OFF)
option(MFEM_USE_PARELAG "Enable ParELAG" OFF)
@@ -245,9 +243,6 @@ set(BLAS_LIBRARIES "" CACHE STRING "The BLAS library.")
set(LAPACK_INCLUDE_DIRS "" CACHE STRING "Path to LAPACK headers.")
set(LAPACK_LIBRARIES "" CACHE STRING "The LAPACK library.")
set(CODIPACK_INCLUDE_DIRS "${MFEM_DIR}/../CoDiPack/inlude" CACHE STRING "Path to CoDiPack headers.")
set(CODIPACK_LIBRARIES "")
# Some useful variables:
set(CMAKE_SKIP_PREPROCESSED_SOURCE_RULES ON) # Skip *.i rules
set(CMAKE_SKIP_ASSEMBLY_SOURCE_RULES ON) # Skip *.s rules
-13
View File
@@ -59,9 +59,6 @@ HIP_FLAGS = --amdgpu-target=$(HIP_ARCH)
HIP_XCOMPILER =
HIP_XLINKER = -Wl,
# Flags for generating dependencies.
DEP_FLAGS = -MM -MT
ifneq ($(NOTMAC),)
AR = ar
ARFLAGS = crv
@@ -89,9 +86,6 @@ else
BUILD_RPATH = $(XLINKER)-undefined,dynamic_lookup
INSTALL_SOFLAGS = $(subst $1 ,,$(call MAKE_SOFLAGS,$(MFEM_LIB_DIR)))
INSTALL_RPATH = $(XLINKER)-undefined,dynamic_lookup
# Silence unused command line argument warnings when generating dependencies
# with mpicxx and clang
DEP_FLAGS := -Wno-unused-command-line-argument $(DEP_FLAGS)
endif
# Set CXXFLAGS to overwrite the default selection of DEBUG_FLAGS/OPTIM_FLAGS
@@ -157,8 +151,6 @@ MFEM_USE_UMPIRE = NO
MFEM_USE_SIMD = NO
MFEM_USE_ADIOS2 = NO
MFEM_USE_MKL_CPARDISO = NO
MFEM_USE_ADFORWARD = NO
MFEM_USE_CODIPACK = NO
MFEM_USE_BENCHMARK = NO
MFEM_USE_PARELAG = NO
@@ -416,11 +408,6 @@ HIOP_DIR = @MFEM_DIR@/../hiop/install
HIOP_OPT = -I$(HIOP_DIR)/include
HIOP_LIB = -L$(HIOP_DIR)/lib -lhiop $(LAPACK_LIB)
# CoDiPack
CODIPACK_DIR = @MFEM_DIR@/../CoDiPack
CODIPACK_OPT = -I$(CODIPACK_DIR)
CODIPACK_LIB =
# GSLIB library
GSLIB_DIR = @MFEM_DIR@/../gslib/build
GSLIB_OPT = -I$(GSLIB_DIR)/include
-1
View File
@@ -781,7 +781,6 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/miniapps/gslib \
@MFEM_SOURCE_DIR@/miniapps/meshing \
@MFEM_SOURCE_DIR@/miniapps/mtop \
@MFEM_SOURCE_DIR@/miniapps/autodiff \
@MFEM_SOURCE_DIR@/miniapps/navier \
@MFEM_SOURCE_DIR@/miniapps/nurbs \
@MFEM_SOURCE_DIR@/miniapps/performance \
-2
View File
@@ -194,8 +194,6 @@ namespace mfem {
* - <a class="el" href="parheat_8cpp_source.html">Optimization gradients</a>: Gradients of PDE-constrained function
* - <a class="el" href="miniapps_2performance_2ex1_8cpp_source.html">HPC Example 1</a>: high-performance nodal H1 FEM for the Laplace problem
* - <a class="el" href="miniapps_2performance_2ex1p_8cpp_source.html">HPC Example 1p</a>: high-performance parallel nodal H1 FEM for the Laplace problem
* - <a class="el" href="par__example_8cpp_source.html">Parallel pLaplacian example using AD</a>: Parallel pLaplacian example
* - <a class="el" href="seq__example_8cpp_source.html">Serial pLaplacian example using AD</a>: Serial pLaplacian example
*
* See also the <a class="el" href="https://mfem.org/examples/">examples documentation</a> online.
*/
+60 -62
View File
@@ -82,80 +82,78 @@ include_directories(BEFORE ${PROJECT_BINARY_DIR})
add_mfem_examples(ALL_EXE_SRCS)
# Add a test for each example
if (MFEM_ENABLE_TESTING)
foreach(SRC_FILE ${ALL_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
foreach(SRC_FILE ${ALL_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
set(THIS_TEST_OPTIONS "-no-vis")
if (${TEST_NAME} MATCHES "ex0p?")
set(THIS_TEST_OPTIONS)
endif()
if (${TEST_NAME} MATCHES "ex10p*")
list(APPEND THIS_TEST_OPTIONS "-tf" "5")
elseif(${TEST_NAME} MATCHES "ex15p*")
list(APPEND THIS_TEST_OPTIONS "-e" "1")
elseif(${TEST_NAME} MATCHES "ex27p*")
list(APPEND THIS_TEST_OPTIONS "-dg")
endif()
set(THIS_TEST_OPTIONS "-no-vis")
if (${TEST_NAME} MATCHES "ex0p?")
set(THIS_TEST_OPTIONS)
endif()
if (${TEST_NAME} MATCHES "ex10p*")
list(APPEND THIS_TEST_OPTIONS "-tf" "5")
elseif(${TEST_NAME} MATCHES "ex15p*")
list(APPEND THIS_TEST_OPTIONS "-e" "1")
elseif(${TEST_NAME} MATCHES "ex27p*")
list(APPEND THIS_TEST_OPTIONS "-dg")
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
# Add CUDA/HIP tests.
set(DEVICE_EXAMPLES
# serial examples with device support:
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)
set(MFEM_TEST_DEVICE)
if (MFEM_USE_CUDA)
set(MFEM_TEST_DEVICE "cuda")
elseif (MFEM_USE_HIP)
set(MFEM_TEST_DEVICE "hip")
endif()
if (MFEM_TEST_DEVICE)
foreach(TEST_NAME ${DEVICE_EXAMPLES})
set(THIS_TEST_OPTIONS "-no-vis" "-d" "${MFEM_TEST_DEVICE}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
elseif (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
# Add CUDA/HIP tests.
set(DEVICE_EXAMPLES
# serial examples with device support:
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)
set(MFEM_TEST_DEVICE)
if (MFEM_USE_CUDA)
set(MFEM_TEST_DEVICE "cuda")
elseif (MFEM_USE_HIP)
set(MFEM_TEST_DEVICE "hip")
endif()
if (MFEM_TEST_DEVICE)
foreach(TEST_NAME ${DEVICE_EXAMPLES})
set(THIS_TEST_OPTIONS "-no-vis" "-d" "${MFEM_TEST_DEVICE}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
elseif (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
# If STRUMPACK is enabled, add a test run that uses it.
if (MFEM_USE_STRUMPACK)
add_test(NAME ex11p_strumpack_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--strumpack"
${MPIEXEC_POSTFLAGS})
endif()
# If STRUMPACK is enabled, add a test run that uses it.
if (MFEM_USE_STRUMPACK)
add_test(NAME ex11p_strumpack_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--strumpack"
${MPIEXEC_POSTFLAGS})
endif()
# If SuperLU_DIST is enabled, add a test run that uses it.
if (MFEM_USE_SUPERLU)
add_test(NAME ex11p_superlu_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--superlu"
${MPIEXEC_POSTFLAGS})
endif()
# If SuperLU_DIST is enabled, add a test run that uses it.
if (MFEM_USE_SUPERLU)
add_test(NAME ex11p_superlu_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--superlu"
${MPIEXEC_POSTFLAGS})
endif()
# Include the examples/amgx directory if AmgX is enabled
+24 -26
View File
@@ -50,32 +50,30 @@ add_mfem_examples(AMGX_EXAMPLES_SRCS ${PFX} copy_amgx_json_files test_amgx)
# which builds the examples and runs:
# ctest -R amgx
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 1/1p:
set(EX1_TEST_OPTS)
set(EX1P_TEST_OPTS)
# Command line options for the tests.
# Example 1/1p:
set(EX1_TEST_OPTS)
set(EX1P_TEST_OPTS)
# Add the tests: one test per source file.
foreach(SRC_FILE ${AMGX_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${AMGX_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
+17 -17
View File
@@ -30,22 +30,22 @@ set(PREFIX caliper_)
add_mfem_examples(CALIPER_EXE_SRCS ${PREFIX})
# Add a test for each example
if (MFEM_ENABLE_TESTING)
foreach(SRC_FILE ${CALIPER_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
foreach(SRC_FILE ${CALIPER_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
set(THIS_TEST_OPTIONS "-no-vis")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
set(THIS_TEST_OPTIONS "-no-vis")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
-266
View File
@@ -1,266 +0,0 @@
// MFEM Example 1
//
// Compile with: make ex1
//
// Sample runs: ex1 -m ../data/square-disc.mesh
// ex1 -m ../data/star.mesh
// ex1 -m ../data/escher.mesh
// ex1 -m ../data/fichera.mesh
// ex1 -m ../data/square-disc-p2.vtk -o 2
// ex1 -m ../data/square-disc-p3.mesh -o 3
// ex1 -m ../data/square-disc-nurbs.mesh -o -1
// ex1 -m ../data/disc-nurbs.mesh -o -1
// ex1 -m ../data/pipe-nurbs.mesh -o -1
// ex1 -m ../data/star-surf.mesh
// ex1 -m ../data/square-disc-surf.mesh
// ex1 -m ../data/inline-segment.mesh
// ex1 -m ../data/amr-quad.mesh
// ex1 -m ../data/amr-hex.mesh
// ex1 -m ../data/fichera-amr.mesh
// ex1 -m ../data/mobius-strip.mesh
// ex1 -m ../data/mobius-strip.mesh -o -1 -sc
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int rs = -1;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 50,000
// elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
cout << "Calling RandomRefinement " << ra << " times." << endl;
for (int l = 0; l < ra; l++)
{
mesh->RandomRefinement(0.2);
}
cout << "Done with refinement" << endl;
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
if ( mesh->ncmesh )
{
mesh->ncmesh->PrintStats(cout);
ofstream ofsV("vp.out");
ofstream ofsE("ce.out");
mesh->ncmesh->PrintVertexParents(ofsV);
mesh->ncmesh->PrintCoarseElements(ofsE);
}
// 4. Define a finite element space on the mesh. Here we use continuous
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
cout << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
LinearForm *b = new LinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 7. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
GridFunction x(fespace);
x = 0.0;
// 8. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 9. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A.Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 10. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
PCG(A, M, B, X, 1, 200, 1e-12, 0.0);
#else
// 10. 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
// 11. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 12. 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);
// 13. 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;
}
// 14. Free the used memory.
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete mesh;
return 0;
}
-388
View File
@@ -1,388 +0,0 @@
// MFEM Example 1 - Parallel Version
//
// Compile with: make ex1p
//
// Sample runs: mpirun -np 4 ex1p -m ../data/square-disc.mesh
// mpirun -np 4 ex1p -m ../data/star.mesh
// mpirun -np 4 ex1p -m ../data/escher.mesh
// mpirun -np 4 ex1p -m ../data/fichera.mesh
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3
// mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/pipe-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/ball-nurbs.mesh -o 2
// mpirun -np 4 ex1p -m ../data/star-surf.mesh
// mpirun -np 4 ex1p -m ../data/square-disc-surf.mesh
// mpirun -np 4 ex1p -m ../data/inline-segment.mesh
// mpirun -np 4 ex1p -m ../data/amr-quad.mesh
// mpirun -np 4 ex1p -m ../data/amr-hex.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh -o -1 -sc
//
// The following are examples of using EntitySets to define
// homogeneous Dirichlet boundary condition. These examples
// require a modified mesh file and a specialized version of
// example 1 called "ex1p_es".
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 0 -bs Origin
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 1 -bs Axes
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 1 -bs "Negative Axes"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 2 -bs "Interior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 2 -bs "Exterior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 3 -bs "Interior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 3 -bs "Exterior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 3 -bs "Steps"
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 10,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
cout << "creating ParMesh from serial mesh" << endl;
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
cout << "done creating ParMesh from serial mesh" << endl;
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
/*
We now have a ParEntitySets object which marshals the data stored
in EntitySets objects. The data has now been pruned so that each
rank only contains indices of local entities.
The NCEntitySets object remains unchanged...
If we have an NC mesh a different path is taken and the
EntitySets are ignored.
1) ParNCMesh is created from NCMesh
a) Creates a ParNCEntitySets object from ncmesh (every rank contains
information to find every entity)
2) ParNCMesh is pruned which involves renumbering elements and vertices
3) ParMesh is initialized from ParNCMesh
4) ParNCMesh::OnMeshUpdated is called
5) Mesh::GenerateNCFaceInfo is called
*/
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
/*
RandomRefinement will end up calling
ParMesh::NonconformingRefinement which will create a new ParMesh
object using the ParNCMesh object and then call
ParMesh::OnMeshUpdated on this new mesh.
*/
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (pmesh->GetNodes())
{
fec = pmesh->GetNodes()->OwnFEC();
if (myid == 0)
{
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
for (int i=0; i<num_procs; i++)
{
if (myid == i)
{
cout << "Number of Dirichlet dofs on proc " << i << ": "
<< ess_tdof_list.Size() << endl;
}
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (1,phi_i) where phi_i are the basis functions in fespace.
ParLinearForm *b = new ParLinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(fespace);
x = 0.0;
// 10. Set up the parallel bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
// 12. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
HypreSolver *amg = new HypreBoomerAMG(A);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(200);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*amg);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// 14. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 15. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 16. Free the used memory.
delete pcg;
delete amg;
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete pmesh;
MPI_Finalize();
return 0;
}
-411
View File
@@ -1,411 +0,0 @@
// MFEM Example 3 - Parallel Version
//
// Compile with: make ex3p
//
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
// mpirun -np 4 ex3p -m ../data/escher.mesh
// mpirun -np 4 ex3p -m ../data/fichera.mesh
// mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
// mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
// mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
//
// Description: This example code solves a simple electromagnetic diffusion
// problem corresponding to the second order definite Maxwell
// equation curl curl E + E = f with boundary condition
// E x n = <given tangential field>. Here, we use a given exact
// solution E and compute the corresponding r.h.s. f.
// We discretize with Nedelec finite elements in 2D or 3D.
//
// The example demonstrates the use of H(curl) finite element
// spaces with the curl-curl and the (vector finite element) mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Static condensation is
// also illustrated.
//
// We recommend viewing examples 1-2 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Exact solution, E, and r.h.s., f. See below for implementation.
//void E_exact(const Vector &, Vector &);
//void f_exact(const Vector &, Vector &);
//double freq = 1.0, kappa;
void f_const(const Vector &, Vector &);
int dim;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../data/beam-tet.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
/*
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
" solution.");
*/
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// kappa = freq * M_PI;
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
pmesh->ReorientTetMesh();
pmesh->ent_sets->PrintSetInfo(cout);
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
if (myid == 0)
{
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
VectorFunctionCoefficient f(sdim, f_const);
ParLinearForm *b = new ParLinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
// VectorFunctionCoefficient E(sdim, E_exact);
// x.ProjectCoefficient(E);
x = 0.0;
// 10. Set up the parallel bilinear form corresponding to the EM diffusion
// operator curl muinv curl + sigma I, by adding the curl-curl and the
// mass domain integrators.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
// 12. Define and apply a parallel PCG solver for AX=B with the AMS
// preconditioner from hypre.
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
HypreSolver *ams = new HypreAMS(A, prec_fespace);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*ams);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
/*
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(E);
if (myid == 0)
{
cout << "\n|| E_h - E ||_{L^2} = " << err << '\n' << endl;
}
}
*/
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
delete pcg;
delete ams;
delete a;
delete sigma;
delete muinv;
delete b;
delete fespace;
delete fec;
delete pmesh;
MPI_Finalize();
return 0;
}
/*
void E_exact(const Vector &x, Vector &E)
{
if (dim == 3)
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(2));
E(2) = sin(kappa * x(0));
}
else
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(0));
if (x.Size() == 3) { E(2) = 0.0; }
}
}
void f_exact(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
}
else
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
if (x.Size() == 3) { f(2) = 0.0; }
}
}
*/
void f_const(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = 1.0;
f(1) = 1.0;
f(2) = 1.0;
}
else
{
f(0) = 1.0;
f(1) = 1.0;
if (x.Size() == 3) { f(2) = 0.0; }
}
}
-438
View File
@@ -1,438 +0,0 @@
// MFEM Example 4 - Parallel Version
//
// Compile with: make ex4p
//
// Sample runs: mpirun -np 4 ex4p -m ../data/square-disc.mesh
// mpirun -np 4 ex4p -m ../data/star.mesh
// mpirun -np 4 ex4p -m ../data/beam-tet.mesh
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh
// mpirun -np 4 ex4p -m ../data/escher.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/fichera.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/fichera-q2.vtk
// mpirun -np 4 ex4p -m ../data/fichera-q3.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/square-disc-nurbs.mesh -o 3
// mpirun -np 4 ex4p -m ../data/beam-hex-nurbs.mesh -o 3
// mpirun -np 4 ex4p -m ../data/periodic-square.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/periodic-cube.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/amr-quad.mesh
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
//
// Description: This example code solves a simple 2D/3D H(div) diffusion
// problem corresponding to the second order definite equation
// -grad(alpha div F) + beta F = f with boundary condition F dot n
// = <given normal field>. Here, we use a given exact solution F
// and compute the corresponding r.h.s. f. We discretize with
// Raviart-Thomas finite elements.
//
// The example demonstrates the use of H(div) finite element
// spaces with the grad-div and H(div) vector finite element mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Bilinear form
// hybridization and static condensation are also illustrated.
//
// We recommend viewing examples 1-3 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
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 &);
//double freq = 1.0, kappa;
void f_const(const Vector &, Vector &);
int dim;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool set_bc = true;
bool static_cond = false;
bool hybridization = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
"Impose or not essential boundary conditions.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
// args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
// " solution.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
"--no-hybridization", "Enable hybridization.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// kappa = freq * M_PI;
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume, as well as periodic meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them (this is needed in the ADS solver below).
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
}
pmesh->ReorientTetMesh();
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *fec = new RT_FECollection(order-1, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = set_bc ? 1 : 0;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
if (myid == 0)
{
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
VectorFunctionCoefficient f(sdim, f_const);
ParLinearForm *b = new ParLinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary faces will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
// VectorFunctionCoefficient F(sdim, F_exact);
// x.ProjectCoefficient(F);
x = 0.0;
// 10. Set up the parallel bilinear form corresponding to the H(div)
// diffusion operator grad alpha div + beta I, by adding the div-div and
// the mass domain integrators.
Coefficient *alpha = new ConstantCoefficient(1.0);
Coefficient *beta = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation,
// hybridization, etc.
FiniteElementCollection *hfec = NULL;
ParFiniteElementSpace *hfes = NULL;
if (static_cond)
{
a->EnableStaticCondensation();
}
else if (hybridization)
{
hfec = new DG_Interface_FECollection(order-1, dim);
hfes = new ParFiniteElementSpace(pmesh, hfec);
a->EnableHybridization(hfes, new NormalTraceJumpIntegrator(),
ess_tdof_list);
}
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
HYPRE_Int glob_size = A.GetGlobalNumRows();
if (myid == 0)
{
cout << "Size of linear system: " << glob_size << endl;
}
// 12. Define and apply a parallel PCG solver for A X = B with the 2D AMS or
// the 3D ADS preconditioners from hypre. If using hybridization, the
// system is preconditioned with hypre's BoomerAMG.
HypreSolver *prec = NULL;
CGSolver *pcg = new CGSolver(A.GetComm());
pcg->SetOperator(A);
pcg->SetRelTol(1e-12);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(1);
if (hybridization) { prec = new HypreBoomerAMG(A); }
else
{
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
if (dim == 2) { prec = new HypreAMS(A, prec_fespace); }
else { prec = new HypreADS(A, prec_fespace); }
}
pcg->SetPreconditioner(*prec);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
/*
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(F);
if (myid == 0)
{
cout << "\n|| F_h - F ||_{L^2} = " << err << '\n' << endl;
}
}
*/
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
delete pcg;
delete prec;
delete hfes;
delete hfec;
delete a;
delete alpha;
delete beta;
delete b;
delete fespace;
delete fec;
delete pmesh;
MPI_Finalize();
return 0;
}
/*
// The exact solution (for non-surface meshes)
void F_exact(const Vector &p, Vector &F)
{
int dim = p.Size();
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
if (dim == 3)
{
F(2) = 0.0;
}
}
// The right hand side
void f_exact(const Vector &p, Vector &f)
{
int dim = p.Size();
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
double temp = 1 + 2*kappa*kappa;
f(0) = temp*cos(kappa*x)*sin(kappa*y);
f(1) = temp*cos(kappa*y)*sin(kappa*x);
if (dim == 3)
{
f(2) = 0;
}
}
*/
void f_const(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = 1.0;
f(1) = 1.0;
f(2) = 1.0;
}
else
{
f(0) = 1.0;
f(1) = 1.0;
if (x.Size() == 3) { f(2) = 0.0; }
}
}
-325
View File
@@ -1,325 +0,0 @@
// MFEM Example 6 - Parallel Version
//
// Compile with: make ex6p
//
// Sample runs: mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 1
// mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex6p -m ../data/square-disc-nurbs.mesh -o 2
// mpirun -np 4 ex6p -m ../data/star.mesh -o 3
// mpirun -np 4 ex6p -m ../data/escher.mesh -o 2
// mpirun -np 4 ex6p -m ../data/fichera.mesh -o 2
// mpirun -np 4 ex6p -m ../data/disc-nurbs.mesh -o 2
// mpirun -np 4 ex6p -m ../data/ball-nurbs.mesh
// mpirun -np 4 ex6p -m ../data/pipe-nurbs.mesh
// mpirun -np 4 ex6p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex6p -m ../data/square-disc-surf.mesh -o 2
// mpirun -np 4 ex6p -m ../data/amr-quad.mesh
//
// Description: This is a version of Example 1 with a simple adaptive mesh
// refinement loop. The problem being solved is again the Laplace
// equation -Delta u = 1 with homogeneous Dirichlet boundary
// conditions. The problem is solved on a sequence of meshes which
// are locally refined in a conforming (triangles, tetrahedrons)
// or non-conforming (quadrilaterals, hexahedra) manner according
// to a simple ZZ error estimator.
//
// The example demonstrates MFEM's capability to work with both
// conforming and nonconforming refinements, in 2D and 3D, on
// linear, curved and surface meshes. Interpolation of functions
// from coarse to fine meshes, as well as persistent GLVis
// visualization are also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
static int max_dofs = 100000;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int bt = EntitySets::INVALID;
const char *bs = "";
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&max_dofs, "-md", "--max-dofs",
"Maximum number of degrees of freedom.");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution.
// Also project a NURBS mesh to a piecewise-quadratic curved mesh. Make
// sure that the mesh is non-conforming.
if (mesh->NURBSext)
{
mesh->UniformRefinement();
mesh->SetCurvature(2);
}
mesh->EnsureNCMesh();
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
// 5. Define a parallel mesh by partitioning the serial mesh.
// Once the parallel mesh is defined, the serial mesh can be deleted.
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh.pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh.pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
// 6. Define a finite element space on the mesh. The polynomial order is
// one (linear) by default, but this can be changed on the command line.
H1_FECollection fec(order, dim);
ParFiniteElementSpace fespace(&pmesh, &fec);
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace.GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
// 7. As in Example 1p, we set up bilinear and linear forms corresponding to
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
// problem yet, this will be done in the main loop.
ParBilinearForm a(&fespace);
ParLinearForm b(&fespace);
ConstantCoefficient one(1.0);
BilinearFormIntegrator *integ = new DiffusionIntegrator(one);
a.AddDomainIntegrator(integ);
b.AddDomainIntegrator(new DomainLFIntegrator(one));
// 8. The solution vector x and the associated finite element grid function
// will be maintained over the AMR iterations. We initialize it to zero.
ParGridFunction x(&fespace);
x = 0;
// 9. Connect to GLVis.
char vishost[] = "localhost";
int visport = 19916;
socketstream sout;
if (visualization)
{
sout.open(vishost, visport);
if (!sout)
{
if (myid == 0)
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
cout << "GLVis visualization disabled.\n";
}
visualization = false;
}
sout.precision(8);
}
// 10. Set up an error estimator. Here we use the Zienkiewicz-Zhu estimator
// with L2 projection in the smoothing step to better handle hanging
// nodes and parallel partitioning. We need to supply a space for the
// discontinuous flux (L2) and a space for the smoothed flux (H(div) is
// used here).
L2_FECollection flux_fec(order, dim);
ParFiniteElementSpace flux_fes(&pmesh, &flux_fec, sdim);
RT_FECollection smooth_flux_fec(order-1, dim);
ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec);
// Another possible option for the smoothed flux space:
// H1_FECollection smooth_flux_fec(order, dim);
// ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec, dim);
L2ZienkiewiczZhuEstimator estimator(*integ, x, flux_fes, smooth_flux_fes);
// 11. A refiner selects and refines elements based on a refinement strategy.
// The strategy here is to refine elements with errors larger than a
// fraction of the maximum element error. Other strategies are possible.
// The refiner will call the given error estimator.
ThresholdRefiner refiner(estimator);
refiner.SetTotalErrorFraction(0.7);
// 12. The main AMR loop. In each iteration we solve the problem on the
// current mesh, visualize the solution, and refine the mesh.
// const int max_dofs = 100000;
for (int it = 0; ; it++)
{
HYPRE_Int global_dofs = fespace.GlobalTrueVSize();
if (myid == 0)
{
cout << "\nAMR iteration " << it << endl;
cout << "Number of unknowns: " << global_dofs << endl;
}
// 13. Assemble the stiffness matrix and the right-hand side. Note that
// MFEM doesn't care at this point that the mesh is nonconforming
// and parallel. The FE space is considered 'cut' along hanging
// edges/faces, and also across processor boundaries.
a.Assemble();
b.Assemble();
// 14. Create the parallel linear system: eliminate boundary conditions,
// constrain hanging nodes and nodes across processor boundaries.
// The system will be solved for true (unconstrained/unique) DOFs only.
// Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace.GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
HypreParMatrix A;
Vector B, X;
const int copy_interior = 1;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
// 15. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
HypreBoomerAMG amg;
amg.SetPrintLevel(0);
CGSolver pcg(A.GetComm());
pcg.SetPreconditioner(amg);
pcg.SetOperator(A);
pcg.SetRelTol(1e-6);
pcg.SetMaxIter(200);
pcg.SetPrintLevel(3); // print the first and the last iterations only
pcg.Mult(B, X);
// 16. Extract the parallel grid function corresponding to the finite element
// approximation X. This is the local solution on each processor.
a.RecoverFEMSolution(X, b, x);
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
sout << "parallel " << num_procs << " " << myid << "\n";
sout << "solution\n" << pmesh << x << flush;
}
if (global_dofs > max_dofs)
{
if (myid == 0)
{
cout << "Reached the maximum number of dofs. Stop." << endl;
}
break;
}
// 18. Call the refiner to modify the mesh. The refiner calls the error
// estimator to obtain element errors, then it selects elements to be
// refined and finally it modifies the mesh. The Stop() method can be
// used to determine if a stopping criterion was met.
refiner.Apply(pmesh);
if (refiner.Stop())
{
if (myid == 0)
{
cout << "Stopping criterion satisfied. Stop." << endl;
}
break;
}
// 19. Update the finite element space (recalculate the number of DOFs,
// etc.) and create a grid function update matrix. Apply the matrix
// to any GridFunctions over the space. In this case, the update
// matrix is an interpolation matrix so the updated GridFunction will
// still represent the same function as before refinement.
fespace.Update();
x.Update();
// 20. Load balance the mesh, and update the space and solution. Currently
// available only for nonconforming meshes.
if (pmesh.Nonconforming())
{
pmesh.Rebalance();
// Update the space and the GridFunction. This time the update matrix
// redistributes the GridFunction among the processors.
fespace.Update();
x.Update();
}
// 21. Inform also the bilinear and linear forms that the space has
// changed.
a.Update();
b.Update();
}
MPI_Finalize();
return 0;
}
-162
View File
@@ -1,162 +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
3
elements
14
1 4 13 15 21 25
1 4 12 13 15 21
1 4 13 21 22 25
1 4 15 24 21 25
1 4 13 15 25 16
1 5 0 1 4 3 9 10 13 12
1 5 8 9 12 11 17 18 21 20
1 5 2 3 6 5 11 12 15 14
1 6 3 4 6 12 13 15
1 6 4 7 6 13 16 15
1 6 12 13 21 9 10 18
1 6 13 22 21 10 19 18
1 6 11 14 20 12 15 21
1 6 15 21 24 14 20 23
boundary
30
1 3 5 6 3 2
2 2 3 6 4
2 2 4 6 7
3 3 3 4 1 0
4 3 11 12 9 8
5 3 2 3 12 11
6 3 0 1 10 9
7 2 9 10 18
7 2 10 19 18
8 3 8 9 18 17
9 3 1 4 13 10
10 3 4 7 16 13
11 2 13 16 25
11 2 13 25 22
12 3 10 13 22 19
13 3 7 6 15 16
14 3 6 5 14 15
15 3 15 14 23 24
16 2 16 15 25
16 2 15 24 25
17 3 5 2 11 14
18 3 3 0 9 12
19 3 11 8 17 20
20 2 11 20 14
20 2 14 20 23
21 3 17 18 21 20
22 3 18 19 22 21
23 2 21 22 25
23 2 21 25 24
24 3 20 21 24 23
vertices
26
3
0 -1 -1
1 -1 -1
-1 0 -1
0 0 -1
1 0 -1
-1 1 -1
0 1 -1
1 1 -1
-1 -1 0
0 -1 0
1 -1 0
-1 0 0
0 0 0
1 0 0
-1 1 0
0 1 0
1 1 0
-1 -1 1
0 -1 1
1 -1 1
-1 0 1
0 0 1
1 0 1
-1 1 1
0 1 1
1 1 1
MFEM sets v1.0
vertex_sets
1
Origin
1
12
edge_sets
2
Axes
3
12 13
12 15
12 21
Negative Axes
3
12 9
12 11
12 3
face_sets
2
Interior Corner
3
3 11 12 9 8
3 2 3 12 11
3 3 0 9 12
Exterior Corner
15
2 13 16 25
2 13 25 22
2 16 15 25
2 15 24 25
2 21 22 25
2 21 25 24
3 10 13 22 19
3 4 7 16 13
3 1 4 13 10
3 7 6 15 16
3 6 5 14 15
3 15 14 23 24
3 20 21 24 23
3 18 19 22 21
3 17 18 21 20
element_sets
3
Interior Corner
3
5 6 7
Exterior Corner
5
0 1 2 3 4
Steps
3
6 8 9
-145
View File
@@ -1,145 +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
#
dimension
3
elements
7
1 5 0 1 4 3 9 10 13 12
1 5 3 4 7 6 12 13 16 15
1 5 2 3 6 5 11 12 15 14
1 5 8 9 12 11 17 18 21 20
1 5 9 10 13 12 18 19 22 21
1 5 12 13 16 15 21 22 25 24
1 5 11 12 15 14 20 21 24 23
boundary
24
1 3 5 6 3 2
2 3 6 7 4 3
3 3 3 4 1 0
4 3 11 12 9 8
5 3 2 3 12 11
6 3 0 1 10 9
7 3 9 10 19 18
8 3 8 9 18 17
9 3 1 4 13 10
10 3 4 7 16 13
11 3 13 16 25 22
12 3 10 13 22 19
13 3 7 6 15 16
14 3 6 5 14 15
15 3 15 14 23 24
16 3 16 15 24 25
17 3 5 2 11 14
18 3 3 0 9 12
19 3 11 8 17 20
20 3 14 11 20 23
21 3 17 18 21 20
22 3 18 19 22 21
23 3 21 22 25 24
24 3 20 21 24 23
vertices
26
3
0 -1 -1
1 -1 -1
-1 0 -1
0 0 -1
1 0 -1
-1 1 -1
0 1 -1
1 1 -1
-1 -1 0
0 -1 0
1 -1 0
-1 0 0
0 0 0
1 0 0
-1 1 0
0 1 0
1 1 0
-1 -1 1
0 -1 1
1 -1 1
-1 0 1
0 0 1
1 0 1
-1 1 1
0 1 1
1 1 1
MFEM sets v1.0
vertex_sets
1
Origin
1
12
edge_sets
2
Axes
3
12 13
12 15
12 21
Negative Axes
3
12 9
12 11
12 3
face_sets
2
Interior Corner
3
3 11 12 9 8
3 2 3 12 11
3 3 0 9 12
Exterior Corner
12
3 13 16 25 22
3 16 15 24 25
3 21 22 25 24
3 10 13 22 19
3 4 7 16 13
3 1 4 13 10
3 7 6 15 16
3 6 5 14 15
3 15 14 23 24
3 20 21 24 23
3 18 19 22 21
3 17 18 21 20
element_sets
3
Interior Corner
3
0 2 3
Exterior Corner
1
5
Steps
2
1 3
+23 -25
View File
@@ -31,31 +31,29 @@ add_mfem_examples(GINKGO_EXAMPLES_SRCS ${PFX} "" test_ginkgo)
# which builds the examples and runs:
# ctest -R ginkgo
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
set(EX1_COMMON_OPTS ex1 -m ../data/star.mesh --use_gko_solver)
set(EX1_TEST_OPTS ${EX9_COMMON_OPTS})
# Command line options for the tests.
set(EX1_COMMON_OPTS ex1 -m ../data/star.mesh --use_gko_solver)
set(EX1_TEST_OPTS ${EX9_COMMON_OPTS})
# Add the tests: one test per source file.
foreach(SRC_FILE ${GINKGO_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${GINKGO_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
+25 -27
View File
@@ -33,33 +33,31 @@ add_mfem_examples(HIOP_EXAMPLES_SRCS ${PFX} "" test_hiop)
# which builds the examples and runs:
# ctest -R hiop
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 9:
set(EX9_COMMON_OPTS -m ../../data/periodic-segment.mesh -p 0 -dt 0.005)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 )
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS})
# Command line options for the tests.
# Example 9:
set(EX9_COMMON_OPTS -m ../../data/periodic-segment.mesh -p 0 -dt 0.005)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 )
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS})
# Add the tests: one test per source file.
foreach(SRC_FILE ${HIOP_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${HIOP_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
+26 -28
View File
@@ -94,32 +94,30 @@ if (MFEM_USE_SLEPC)
endif()
# Add the tests: one test per command-line-variable.
if (MFEM_ENABLE_TESTING)
set(TEST_OPTIONS_VARS
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
if (MFEM_USE_SLEPC)
list(APPEND TEST_OPTIONS_VARS EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
endif()
foreach(TEST_OPTIONS_VAR ${TEST_OPTIONS_VARS})
string(REGEX REPLACE "^(.+)_ARGS" "\\1" TEST_NAME_UC ${TEST_OPTIONS_VAR})
string(REGEX REPLACE "^([^_]+)" "\\1P" TEST_NAME_UC ${TEST_NAME_UC})
string(TOLOWER ${TEST_NAME_UC} TEST_NAME_FULL)
string(REGEX REPLACE "^([^_]+).*" "\\1" TEST_NAME ${TEST_NAME_FULL})
set(TEST_NAME_FULL ${PFX}${TEST_NAME_FULL})
set(TEST_NAME ${PFX}${TEST_NAME})
set(TEST_OPTIONS "-no-vis" ${${TEST_OPTIONS_VAR}})
# message(STATUS "${TEST_NAME_FULL} --> ${TEST_NAME} ${TEST_OPTIONS}")
# All PETSC tests are parallel.
if (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME_FULL}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
set(TEST_OPTIONS_VARS
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
if (MFEM_USE_SLEPC)
list(APPEND TEST_OPTIONS_VARS EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
endif()
foreach(TEST_OPTIONS_VAR ${TEST_OPTIONS_VARS})
string(REGEX REPLACE "^(.+)_ARGS" "\\1" TEST_NAME_UC ${TEST_OPTIONS_VAR})
string(REGEX REPLACE "^([^_]+)" "\\1P" TEST_NAME_UC ${TEST_NAME_UC})
string(TOLOWER ${TEST_NAME_UC} TEST_NAME_FULL)
string(REGEX REPLACE "^([^_]+).*" "\\1" TEST_NAME ${TEST_NAME_FULL})
set(TEST_NAME_FULL ${PFX}${TEST_NAME_FULL})
set(TEST_NAME ${PFX}${TEST_NAME})
set(TEST_OPTIONS "-no-vis" ${${TEST_OPTIONS_VAR}})
# message(STATUS "${TEST_NAME_FULL} --> ${TEST_NAME} ${TEST_OPTIONS}")
# All PETSC tests are parallel.
if (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME_FULL}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
+30 -32
View File
@@ -37,39 +37,37 @@ add_mfem_examples(PUMI_EXAMPLES_SRCS ${PFX} "" test_pumi)
# which builds the examples and runs:
# ctest -R pumi
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# TODO...
# Command line options for the tests.
# TODO...
# Set the number of processors for the parallel examples. The value of
# MFEM_MPI_NP is ignored.
set(EX1_TEST_NP 1)
set(EX1P_TEST_NP 8)
set(EX2_TEST_NP 1)
set(EX6P_TEST_NP 8)
# Set the number of processors for the parallel examples. The value of
# MFEM_MPI_NP is ignored.
set(EX1_TEST_NP 1)
set(EX1P_TEST_NP 8)
set(EX2_TEST_NP 1)
set(EX6P_TEST_NP 8)
# Add the tests: one test per source file.
foreach(SRC_FILE ${PUMI_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${PUMI_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
# All PUMI examples require MPI
if (FALSE)
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
set(TEST_NP ${${UP_TEST_NAME}_TEST_NP})
add_test(NAME ${TEST_NAME}_np=${TEST_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${TEST_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
# All PUMI examples require MPI
if (FALSE)
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
set(TEST_NP ${${UP_TEST_NAME}_TEST_NP})
add_test(NAME ${TEST_NAME}_np=${TEST_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${TEST_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
-158
View File
@@ -1,158 +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
30
1 3 0 11 26 14
1 3 0 14 27 17
1 3 0 17 28 20
1 3 0 20 29 23
1 3 0 23 30 11
1 2 11 1 26
1 2 1 12 26
1 3 26 12 3 13
1 2 26 13 2
1 2 14 26 2
1 2 14 2 27
1 2 2 15 27
1 3 27 15 5 16
1 2 27 16 4
1 2 17 27 4
1 2 17 4 28
1 2 4 18 28
1 3 28 18 7 19
1 2 28 19 6
1 2 20 28 6
1 2 20 6 29
1 2 6 21 29
1 3 29 21 9 22
1 2 29 22 8
1 2 23 29 8
1 2 23 8 30
1 2 8 24 30
1 3 30 24 10 25
1 2 30 25 1
1 2 11 30 1
boundary
20
1 1 13 2
1 1 12 3
1 1 16 4
1 1 15 5
1 1 19 6
1 1 18 7
1 1 22 8
1 1 21 9
1 1 25 1
1 1 24 10
1 1 3 13
1 1 1 12
1 1 5 16
1 1 2 15
1 1 7 19
1 1 4 18
1 1 9 22
1 1 6 21
1 1 10 25
1 1 8 24
vertices
31
2
0 0
1 0
0.309017 0.951057
1.30902 0.951057
-0.809017 0.587785
-0.5 1.53884
-0.809017 -0.587785
-1.61803 0
0.309017 -0.951057
-0.5 -1.53884
1.30902 -0.951057
0.5 0
1.15451 0.475529
0.809019 0.951057
0.154508 0.475529
-0.0954915 1.24495
-0.654508 1.06331
-0.404508 0.293893
-1.21352 0.293893
-1.21352 -0.293892
-0.404508 -0.293893
-0.654508 -1.06331
-0.0954915 -1.24495
0.154508 -0.475529
0.809019 -0.951057
1.15451 -0.475529
0.654509 0.475529
-0.25 0.769421
-0.809016 0
-0.25 -0.76942
0.654509 -0.475529
MFEM sets v1.0
vertex_sets
3
Origin
1
0
Tent
5
1 2 4 6 8
Gazebo
5
3 5 7 9 10
edge_sets
2
Columbine
5
1 11
2 14
4 17
6 20
8 23
Lily
5
0 11
0 14
0 17
0 20
0 23
element_sets
3
Flying Squirrel
3
7 17 27
Sea Lion
4
12 17 22 27
Pinwheel
5
8 13 18 23 28
-143
View File
@@ -1,143 +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
#
dimension
2
elements
20
1 3 0 11 26 14
1 3 0 14 27 17
1 3 0 17 28 20
1 3 0 20 29 23
1 3 0 23 30 11
1 3 11 1 12 26
1 3 26 12 3 13
1 3 14 26 13 2
1 3 14 2 15 27
1 3 27 15 5 16
1 3 17 27 16 4
1 3 17 4 18 28
1 3 28 18 7 19
1 3 20 28 19 6
1 3 20 6 21 29
1 3 29 21 9 22
1 3 23 29 22 8
1 3 23 8 24 30
1 3 30 24 10 25
1 3 11 30 25 1
boundary
20
1 1 13 2
1 1 12 3
1 1 16 4
1 1 15 5
1 1 19 6
1 1 18 7
1 1 22 8
1 1 21 9
1 1 25 1
1 1 24 10
1 1 3 13
1 1 1 12
1 1 5 16
1 1 2 15
1 1 7 19
1 1 4 18
1 1 9 22
1 1 6 21
1 1 10 25
1 1 8 24
vertices
31
2
0 0
1 0
0.309017 0.951057
1.30902 0.951057
-0.809017 0.587785
-0.5 1.53884
-0.809017 -0.587785
-1.61803 0
0.309017 -0.951057
-0.5 -1.53884
1.30902 -0.951057
0.5 0
1.15451 0.475529
0.809019 0.951057
0.154508 0.475529
-0.0954915 1.24495
-0.654508 1.06331
-0.404508 0.293893
-1.21352 0.293893
-1.21352 -0.293892
-0.404508 -0.293893
-0.654508 -1.06331
-0.0954915 -1.24495
0.154508 -0.475529
0.809019 -0.951057
1.15451 -0.475529
0.654509 0.475529
-0.25 0.769421
-0.809016 0
-0.25 -0.76942
0.654509 -0.475529
MFEM sets v1.0
vertex_sets
3
Origin
1
0
Tent
5
1 2 4 6 8
Gazebo
5
3 5 7 9 10
edge_sets
2
Columbine
5
1 11
2 14
4 17
6 20
8 23
Lily
5
0 11
0 14
0 17
0 20
0 23
element_sets
2
Flying Squirrel
3
6 12 18
Sea Lion
4
9 12 15 18
+30 -32
View File
@@ -41,38 +41,36 @@ add_mfem_examples(SUNDIALS_EXAMPLES_SRCS ${PFX} "" test_sundials)
# which builds the examples and runs:
# ctest -R sundials
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 9: test CVODE with CV_ADAMS (non-stiff implicit) time stepping
set(EX9_COMMON_OPTS -m ../../data/periodic-hexagon.mesh -p 0 -s 7)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 -dt 0.0018 -vs 25)
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS} -rp 1 -dt 0.0009 -vs 50)
# Example 10: test CVODE with CV_BDF (stiff implicit) time stepping
set(EX10_COMMON_OPTS -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -tf 6 -vs 10)
set(EX10_TEST_OPTS ${EX10_COMMON_OPTS} -r 2)
set(EX10P_TEST_OPTS ${EX10_COMMON_OPTS} -rp 1)
# Example 16: use the default options
# Command line options for the tests.
# Example 9: test CVODE with CV_ADAMS (non-stiff implicit) time stepping
set(EX9_COMMON_OPTS -m ../../data/periodic-hexagon.mesh -p 0 -s 7)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 -dt 0.0018 -vs 25)
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS} -rp 1 -dt 0.0009 -vs 50)
# Example 10: test CVODE with CV_BDF (stiff implicit) time stepping
set(EX10_COMMON_OPTS -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -tf 6 -vs 10)
set(EX10_TEST_OPTS ${EX10_COMMON_OPTS} -r 2)
set(EX10P_TEST_OPTS ${EX10_COMMON_OPTS} -rp 1)
# Example 16: use the default options
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
+25 -26
View File
@@ -32,32 +32,31 @@ add_mfem_examples(SUPERLU_EXAMPLES_SRCS ${PFX} "" test_superlu)
# The SuperLU tests can be run separately using the target "test_superlu"
# which builds the examples and runs:
# ctest -R superlu
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 1: Test SuperLU on the simple Poisson problem
set(EX1_COMMON_OPTS -m ../../data/star.mesh -p 2)
set(EX1P_TEST_OPTS ${EX1_COMMON_OPTS})
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUPERLU_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Command line options for the tests.
# Example 1: Test SuperLU on the simple Poisson problem
set(EX1_COMMON_OPTS -m ../../data/star.mesh -p 2)
set(EX1P_TEST_OPTS ${EX1_COMMON_OPTS})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUPERLU_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
+183 -149
View File
@@ -1556,7 +1556,7 @@ static void SmemPADiffusionApply3D(const int NE,
auto d = Reshape(d_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
MFEM_FORALL_3D(e, NE, Q1D, Q1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -1585,102 +1585,118 @@ static void SmemPADiffusionApply3D(const int NE,
double (*QDD0)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+0);
double (*QDD1)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+1);
double (*QDD2)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+2);
MFEM_FOREACH_THREAD(dz,z,D1D)
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
MFEM_FOREACH_THREAD(dx,x,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
X[dz][dy][dx] = x(dx,dy,dz,e);
}
}
}
if (MFEM_THREAD_ID(z) == 0)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const int i = qi(qx,dy,Q1D);
const int j = dj(qx,dy,D1D);
const int k = qk(qx,dy,Q1D);
const int l = dl(qx,dy,D1D);
B[i][j] = b(qx,dy);
G[k][l] = g(qx,dy) * sign(qx,dy);
}
const int i = qi(qx,dy,Q1D);
const int j = dj(qx,dy,D1D);
const int k = qk(qx,dy,Q1D);
const int l = dl(qx,dy,D1D);
B[i][j] = b(qx,dy);
G[k][l] = g(qx,dy) * sign(qx,dy);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1D)
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
double u[D1D], v[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++) { u[dz] = v[dz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dx = 0; dx < D1D; ++dx)
{
double u = 0.0, v = 0.0;
MFEM_UNROLL(MD1)
for (int dx = 0; dx < D1D; ++dx)
{
const int i = qi(qx,dx,Q1D);
const int j = dj(qx,dx,D1D);
const int k = qk(qx,dx,Q1D);
const int l = dl(qx,dx,D1D);
const double s = sign(qx,dx);
const double coords = X[dz][dy][dx];
u += coords * B[i][j];
v += coords * G[k][l] * s;
}
DDQ0[dz][dy][qx] = u;
DDQ1[dz][dy][qx] = v;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u = 0.0, v = 0.0, w = 0.0;
MFEM_UNROLL(MD1)
for (int dy = 0; dy < D1D; ++dy)
{
const int i = qi(qy,dy,Q1D);
const int j = dj(qy,dy,D1D);
const int k = qk(qy,dy,Q1D);
const int l = dl(qy,dy,D1D);
const double s = sign(qy,dy);
u += DDQ1[dz][dy][qx] * B[i][j];
v += DDQ0[dz][dy][qx] * G[k][l] * s;
w += DDQ0[dz][dy][qx] * B[i][j];
}
DQQ0[dz][qy][qx] = u;
DQQ1[dz][qy][qx] = v;
DQQ2[dz][qy][qx] = w;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u = 0.0, v = 0.0, w = 0.0;
const int i = qi(qx,dx,Q1D);
const int j = dj(qx,dx,D1D);
const int k = qk(qx,dx,Q1D);
const int l = dl(qx,dx,D1D);
const double s = sign(qx,dx);
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
const double coords = X[dz][dy][dx];
u[dz] += coords * B[i][j];
v[dz] += coords * G[k][l] * s;
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
DDQ0[dz][dy][qx] = u[dz];
DDQ1[dz][dy][qx] = v[dz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[D1D], v[D1D], w[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++) { u[dz] = v[dz] = w[dz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dy = 0; dy < D1D; ++dy)
{
const int i = qi(qy,dy,Q1D);
const int j = dj(qy,dy,D1D);
const int k = qk(qy,dy,Q1D);
const int l = dl(qy,dy,D1D);
const double s = sign(qy,dy);
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++)
{
u[dz] += DDQ1[dz][dy][qx] * B[i][j];
v[dz] += DDQ0[dz][dy][qx] * G[k][l] * s;
w[dz] += DDQ0[dz][dy][qx] * B[i][j];
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++)
{
DQQ0[dz][qy][qx] = u[dz];
DQQ1[dz][qy][qx] = v[dz];
DQQ2[dz][qy][qx] = w[dz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[Q1D], v[Q1D], w[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++) { u[qz] = v[qz] = w[qz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++)
{
const int i = qi(qz,dz,Q1D);
const int j = dj(qz,dz,D1D);
const int k = qk(qz,dz,Q1D);
const int l = dl(qz,dz,D1D);
const double s = sign(qz,dz);
u += DQQ0[dz][qy][qx] * B[i][j];
v += DQQ1[dz][qy][qx] * B[i][j];
w += DQQ2[dz][qy][qx] * G[k][l] * s;
u[qz] += DQQ0[dz][qy][qx] * B[i][j];
v[qz] += DQQ1[dz][qy][qx] * B[i][j];
w[qz] += DQQ2[dz][qy][qx] * G[k][l] * s;
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++)
{
const double O11 = d(qx,qy,qz,0,e);
const double O12 = d(qx,qy,qz,1,e);
const double O13 = d(qx,qy,qz,2,e);
@@ -1690,9 +1706,9 @@ static void SmemPADiffusionApply3D(const int NE,
const double O31 = symmetric ? O13 : d(qx,qy,qz,6,e);
const double O32 = symmetric ? O23 : d(qx,qy,qz,7,e);
const double O33 = symmetric ? d(qx,qy,qz,5,e) : d(qx,qy,qz,8,e);
const double gX = u;
const double gY = v;
const double gZ = w;
const double gX = u[qz];
const double gY = v[qz];
const double gZ = w[qz];
QQQ0[qz][qy][qx] = (O11*gX) + (O12*gY) + (O13*gZ);
QQQ1[qz][qy][qx] = (O21*gX) + (O22*gY) + (O23*gZ);
QQQ2[qz][qy][qx] = (O31*gX) + (O32*gY) + (O33*gZ);
@@ -1700,94 +1716,112 @@ static void SmemPADiffusionApply3D(const int NE,
}
}
MFEM_SYNC_THREAD;
if (MFEM_THREAD_ID(z) == 0)
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(d,y,D1D)
MFEM_FOREACH_THREAD(q,x,Q1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
const int i = qi(q,d,Q1D);
const int j = dj(q,d,D1D);
const int k = qk(q,d,Q1D);
const int l = dl(q,d,D1D);
Bt[j][i] = b(q,d);
Gt[l][k] = g(q,d) * sign(q,d);
}
const int i = qi(q,d,Q1D);
const int j = dj(q,d,D1D);
const int k = qk(q,d,Q1D);
const int l = dl(q,d,D1D);
Bt[j][i] = b(q,d);
Gt[l][k] = g(q,d) * sign(q,d);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz,z,Q1D)
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
MFEM_FOREACH_THREAD(dx,x,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
double u[Q1D], v[Q1D], w[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = v[qz] = w[qz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qx = 0; qx < Q1D; ++qx)
{
double u = 0.0, v = 0.0, w = 0.0;
MFEM_UNROLL(MQ1)
for (int qx = 0; qx < Q1D; ++qx)
{
const int i = qi(qx,dx,Q1D);
const int j = dj(qx,dx,D1D);
const int k = qk(qx,dx,Q1D);
const int l = dl(qx,dx,D1D);
const double s = sign(qx,dx);
u += QQQ0[qz][qy][qx] * Gt[l][k] * s;
v += QQQ1[qz][qy][qx] * Bt[j][i];
w += QQQ2[qz][qy][qx] * Bt[j][i];
}
QQD0[qz][qy][dx] = u;
QQD1[qz][qy][dx] = v;
QQD2[qz][qy][dx] = w;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u = 0.0, v = 0.0, w = 0.0;
MFEM_UNROLL(Q1D)
for (int qy = 0; qy < Q1D; ++qy)
{
const int i = qi(qy,dy,Q1D);
const int j = dj(qy,dy,D1D);
const int k = qk(qy,dy,Q1D);
const int l = dl(qy,dy,D1D);
const double s = sign(qy,dy);
u += QQD0[qz][qy][dx] * Bt[j][i];
v += QQD1[qz][qy][dx] * Gt[l][k] * s;
w += QQD2[qz][qy][dx] * Bt[j][i];
}
QDD0[qz][dy][dx] = u;
QDD1[qz][dy][dx] = v;
QDD2[qz][dy][dx] = w;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u = 0.0, v = 0.0, w = 0.0;
const int i = qi(qx,dx,Q1D);
const int j = dj(qx,dx,D1D);
const int k = qk(qx,dx,Q1D);
const int l = dl(qx,dx,D1D);
const double s = sign(qx,dx);
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += QQQ0[qz][qy][qx] * Gt[l][k] * s;
v[qz] += QQQ1[qz][qy][qx] * Bt[j][i];
w[qz] += QQQ2[qz][qy][qx] * Bt[j][i];
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
QQD0[qz][qy][dx] = u[qz];
QQD1[qz][qy][dx] = v[qz];
QQD2[qz][qy][dx] = w[qz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[Q1D], v[Q1D], w[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = v[qz] = w[qz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qy = 0; qy < Q1D; ++qy)
{
const int i = qi(qy,dy,Q1D);
const int j = dj(qy,dy,D1D);
const int k = qk(qy,dy,Q1D);
const int l = dl(qy,dy,D1D);
const double s = sign(qy,dy);
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += QQD0[qz][qy][dx] * Bt[j][i];
v[qz] += QQD1[qz][qy][dx] * Gt[l][k] * s;
w[qz] += QQD2[qz][qy][dx] * Bt[j][i];
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
QDD0[qz][dy][dx] = u[qz];
QDD1[qz][dy][dx] = v[qz];
QDD2[qz][dy][dx] = w[qz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[D1D], v[D1D], w[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz) { u[dz] = v[dz] = w[dz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
const int i = qi(qz,dz,Q1D);
const int j = dj(qz,dz,D1D);
const int k = qk(qz,dz,Q1D);
const int l = dl(qz,dz,D1D);
const double s = sign(qz,dz);
u += QDD0[qz][dy][dx] * Bt[j][i];
v += QDD1[qz][dy][dx] * Bt[j][i];
w += QDD2[qz][dy][dx] * Gt[l][k] * s;
u[dz] += QDD0[qz][dy][dx] * Bt[j][i];
v[dz] += QDD1[qz][dy][dx] * Bt[j][i];
w[dz] += QDD2[qz][dy][dx] * Gt[l][k] * s;
}
y(dx,dy,dz,e) += (u + v + w);
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
y(dx,dy,dz,e) += (u[dz] + v[dz] + w[dz]);
}
}
}
-169
View File
@@ -28,52 +28,6 @@ double PWConstCoefficient::Eval(ElementTransformation & T,
return (constants(att-1));
}
void PWCoefficient::InitMap(const Array<int> & attr,
const Array<Coefficient*> & coefs)
{
MFEM_VERIFY(attr.Size() == coefs.Size(),
"PWCoefficient: "
"Attribute and coefficient arrays have incompatible "
"dimensions.");
for (int i=0; i<attr.Size(); i++)
{
if (coefs[i] != NULL)
{
UpdateCoefficient(attr[i], *coefs[i]);
}
}
}
void PWCoefficient::SetTime(double t)
{
Coefficient::SetTime(t);
std::map<int, Coefficient*>::iterator p = pieces.begin();
for (; p != pieces.end(); p++)
{
if (p->second != NULL)
{
p->second->SetTime(t);
}
}
}
double PWCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
const int att = T.Attribute;
std::map<int, Coefficient*>::const_iterator p = pieces.find(att);
if (p != pieces.end())
{
if ( p->second != NULL)
{
return p->second->Eval(T, ip);
}
}
return 0.0;
}
double FunctionCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
@@ -166,63 +120,6 @@ void VectorCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
}
}
void PWVectorCoefficient::InitMap(const Array<int> & attr,
const Array<VectorCoefficient*> & coefs)
{
MFEM_VERIFY(attr.Size() == coefs.Size(),
"PWVectorCoefficient: "
"Attribute and coefficient arrays have incompatible "
"dimensions.");
for (int i=0; i<attr.Size(); i++)
{
if (coefs[i] != NULL)
{
UpdateCoefficient(attr[i], *coefs[i]);
}
}
}
void PWVectorCoefficient::UpdateCoefficient(int attr, VectorCoefficient & coef)
{
MFEM_VERIFY(coef.GetVDim() == vdim,
"PWVectorCoefficient::UpdateCoefficient: "
"VectorCoefficient has incompatible dimension.");
pieces[attr] = &coef;
}
void PWVectorCoefficient::SetTime(double t)
{
VectorCoefficient::SetTime(t);
std::map<int, VectorCoefficient*>::iterator p = pieces.begin();
for (; p != pieces.end(); p++)
{
if (p->second != NULL)
{
p->second->SetTime(t);
}
}
}
void PWVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
const int att = T.Attribute;
std::map<int, VectorCoefficient*>::const_iterator p = pieces.find(att);
if (p != pieces.end())
{
if ( p->second != NULL)
{
p->second->Eval(V, T, ip);
return;
}
}
V.SetSize(vdim);
V = 0.0;
}
void VectorFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
@@ -434,72 +331,6 @@ void VectorRestrictedCoefficient::Eval(
}
}
void PWMatrixCoefficient::InitMap(const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs)
{
MFEM_VERIFY(attr.Size() == coefs.Size(),
"PWMatrixCoefficient: "
"Attribute and coefficient arrays have incompatible "
"dimensions.");
for (int i=0; i<attr.Size(); i++)
{
if (coefs[i] != NULL)
{
UpdateCoefficient(attr[i], *coefs[i]);
}
}
}
void PWMatrixCoefficient::UpdateCoefficient(int attr, MatrixCoefficient & coef)
{
MFEM_VERIFY(coef.GetHeight() == height,
"PWMatrixCoefficient::UpdateCoefficient: "
"MatrixCoefficient has incompatible height.");
MFEM_VERIFY(coef.GetWidth() == width,
"PWMatrixCoefficient::UpdateCoefficient: "
"MatrixCoefficient has incompatible width.");
if (symmetric)
{
MFEM_VERIFY(coef.IsSymmetric(),
"PWMatrixCoefficient::UpdateCoefficient: "
"MatrixCoefficient has incompatible symmetry.");
}
pieces[attr] = &coef;
}
void PWMatrixCoefficient::SetTime(double t)
{
MatrixCoefficient::SetTime(t);
std::map<int, MatrixCoefficient*>::iterator p = pieces.begin();
for (; p != pieces.end(); p++)
{
if (p->second != NULL)
{
p->second->SetTime(t);
}
}
}
void PWMatrixCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
const int att = T.Attribute;
std::map<int, MatrixCoefficient*>::const_iterator p = pieces.find(att);
if (p != pieces.end())
{
if ( p->second != NULL)
{
p->second->Eval(K, T, ip);
return;
}
}
K.SetSize(height, width);
K = 0.0;
}
void MatrixFunctionCoefficient::SetTime(double t)
{
if (Q) { Q->SetTime(t); }
-269
View File
@@ -125,87 +125,6 @@ public:
const IntegrationPoint &ip);
};
/** @brief A piecewise coefficient with the pieces keyed off the element
attribute numbers.
A value of zero will be returned for any missing attribute numbers.
This object will not assume ownership of any Coefficient objects
passed to it. Consequently, the caller must ensure that the
individual Coefficient objects are not deleted while this
PWCoefficient is still in use.
\note The keys may either be domain attribute numbers or boundary
attribute numbers. If the PWCoefficient is used with a domain
integrator the keys are assumed to be domain attribute
numbers. Similarly, if the PWCoefficient is used with a boundary
integrator the keys are assumed to be boundary attribute numbers.
*/
class PWCoefficient : public Coefficient
{
private:
/** Internal data structure to store pointers to the appropriate
coefficients for different regions of the mesh. The keys used
in the map are the mesh attribute numbers (either element
attribute or boundary element attribute depending upon
context). The values returned for any missing attributes will
be zero. The coefficient pointers may be NULL in which case a
value of zero is returned.
The Coefficient objects contained in this map are NOT owned by
this PWCoefficient object. This means that they will not be
deleted when this object is deleted also the caller must ensure
that the various Coefficient objects are not deleted while this
PWCoefficient is still needed.
*/
std::map<int, Coefficient*> pieces;
/** Convenience function to check for compatible array lengths,
loop over the arrays, and add their attribute/Coefficient pairs
to the internal data structure.
*/
void InitMap(const Array<int> & attr,
const Array<Coefficient*> & coefs);
public:
/// Constructs a piecewise coefficient
explicit PWCoefficient() {}
/// Construct the coefficient using arrays describing the pieces
/** \param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of Coefficient pointers
Any missing attributes or NULL coefficient pointers will result in a
value of zero being returned for that attribute.
\note Ownership of the Coefficient objects will NOT be
transferred to this object.
*/
PWCoefficient(const Array<int> & attr,
const Array<Coefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Set the time for time dependent coefficients
virtual void SetTime(double t);
/// Replace a set of coefficients
void UpdateCoefficients(const Array<int> & attr,
const Array<Coefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Replace a single Coefficient for a particular attribute
void UpdateCoefficient(int attr, Coefficient & coef)
{ pieces[attr] = &coef; }
/// Remove a single Coefficient for a particular attribute
void ZeroCoefficient(int attr)
{ pieces.erase(attr); }
/// Evaluate the coefficient.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
/// A general function coefficient
class FunctionCoefficient : public Coefficient
{
@@ -494,88 +413,6 @@ public:
const Vector& GetVec() { return vec; }
};
/** @brief A piecewise vector-valued coefficient with the pieces keyed off the
element attribute numbers.
A value of zero will be returned for any missing attribute numbers.
This object will not assume ownership of any VectorCoefficient
objects passed to it. Consequently, the caller must ensure that
the individual VectorCoefficient objects are not deleted while
this PWVectorCoefficient is still in use.
\note The keys may either be domain attribute numbers or boundary
attribute numbers. If the PWVectorCoefficient is used with a
domain integrator the keys are assumed to be domain attribute
numbers. Similarly, if the PWVectorCoefficient is used with a
boundary integrator the keys are assumed to be boundary attribute
numbers.
*/
class PWVectorCoefficient : public VectorCoefficient
{
private:
/** Internal data structure to store pointers to the appropriate
coefficients for different regions of the mesh. The keys used
in the map are the mesh attribute numbers (either element
attribute or boundary element attribute depending upon
context). The values returned for any missing attributes will
be zero. The coefficient pointers may be NULL in which case a
value of zero is returned.
The VectorCoefficient objects contained in this map are NOT
owned by this PWVectorCoefficient object. This means that they
will not be deleted when this object is deleted also the caller
must ensure that the various VectorCoefficient objects are not
deleted while this PWVectorCoefficient is still needed.
*/
std::map<int, VectorCoefficient*> pieces;
/** Convenience function to check for compatible array lengths,
loop over the arrays, and add their attribute/VectorCoefficient
pairs to the internal data structure.
*/
void InitMap(const Array<int> & attr,
const Array<VectorCoefficient*> & coefs);
public:
/// Constructs a piecewise vector coefficient of dimension vd
explicit PWVectorCoefficient(int vd): VectorCoefficient(vd) {}
/// Construct the coefficient using arrays describing the pieces
/** \param vd - dimension of the vector-valued result
\param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of VectorCoefficient pointers
Any missing attributes or NULL coefficient pointers will result in a
zero vector being returned for that attribute.
\note Ownership of the VectorCoefficient objects will NOT be
transferred to this object.
*/
PWVectorCoefficient(int vd, const Array<int> & attr,
const Array<VectorCoefficient*> & coefs)
: VectorCoefficient(vd) { InitMap(attr, coefs); }
/// Set the time for time dependent coefficients
virtual void SetTime(double t);
/// Replace a set of coefficients
void UpdateCoefficients(const Array<int> & attr,
const Array<VectorCoefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Replace a single Coefficient for a particular attribute
void UpdateCoefficient(int attr, VectorCoefficient & coef);
/// Remove a single VectorCoefficient for a particular attribute
void ZeroCoefficient(int attr)
{ pieces.erase(attr); }
/// Evaluate the coefficient.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
};
/// A general vector function coefficient
class VectorFunctionCoefficient : public VectorCoefficient
{
@@ -945,112 +782,6 @@ public:
};
/** @brief A piecewise matrix-valued coefficient with the pieces keyed off the
element attribute numbers.
A value of zero will be returned for any missing attribute numbers.
This object will not assume ownership of any MatrixCoefficient
objects passed to it. Consequently, the caller must ensure that
the individual MatrixCoefficient objects are not deleted while
this PWMatrixCoefficient is still in use.
\note The keys may either be domain attribute numbers or boundary
attribute numbers. If the PWMatrixCoefficient is used with a
domain integrator the keys are assumed to be domain attribute
numbers. Similarly, if the PWMatrixCoefficient is used with a
boundary integrator the keys are assumed to be boundary attribute
numbers.
*/
class PWMatrixCoefficient : public MatrixCoefficient
{
private:
/** Internal data structure to store pointers to the appropriate
coefficients for different regions of the mesh. The keys used
in the map are the mesh attribute numbers (either element
attribute or boundary element attribute depending upon
context). The values returned for any missing attributes will
be zero. The coefficient pointers may be NULL in which case a
value of zero is returned.
The MatrixCoefficient objects contained in this map are NOT
owned by this PWMatrixCoefficient object. This means that they
will not be deleted when this object is deleted also the caller
must ensure that the various MatrixCoefficient objects are not
deleted while this PWMatrixCoefficient is still needed.
*/
std::map<int, MatrixCoefficient*> pieces;
/** Convenience function to check for compatible array lengths,
loop over the arrays, and add their attribute/MatrixCoefficient
pairs to the internal data structure.
*/
void InitMap(const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs);
public:
/// Constructs a piecewise matrix coefficient of dimension dim by dim
explicit PWMatrixCoefficient(int dim, bool symm = false)
: MatrixCoefficient(dim, symm) {}
/// Constructs a piecewise matrix coefficient of dimension h by w
explicit PWMatrixCoefficient(int h, int w, bool symm = false)
: MatrixCoefficient(h, w, symm) {}
/// Construct the coefficient using arrays describing the pieces
/** \param dim - size of the square matrix-valued result
\param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of MatrixCoefficient pointers
\param symm - true if the result will be symmetric, false otherwise
Any missing attributes or NULL coefficient pointers will result in a
zero matrix being returned.
\note Ownership of the MatrixCoefficient objects will NOT be
transferred to this object.
*/
PWMatrixCoefficient(int dim, const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs,
bool symm=false)
: MatrixCoefficient(dim, symm) { InitMap(attr, coefs); }
/// Construct the coefficient using arrays describing the pieces
/** \param h - height of the matrix-valued result
\param w - width of the matrix-valued result
\param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of MatrixCoefficient pointers
\param symm - true if the result will be symmetric, false otherwise
Any missing attributes or NULL coefficient pointers will result in a
zero matrix being returned for that attribute.
\note Ownership of the MatrixCoefficient objects will NOT be
transferred to this object.
*/
PWMatrixCoefficient(int h, int w, const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs,
bool symm=false)
: MatrixCoefficient(h, w, symm) { InitMap(attr, coefs); }
/// Set the time for time dependent coefficients
virtual void SetTime(double t);
/// Replace a set of coefficients
void UpdateCoefficients(const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Replace a single coefficient for a particular attribute
void UpdateCoefficient(int attr, MatrixCoefficient & coef);
/// Remove a single MatrixCoefficient for a particular attribute
void ZeroCoefficient(int attr)
{ pieces.erase(attr); }
/// Evaluate the coefficient.
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
};
/** @brief A matrix coefficient with an optional scalar coefficient multiplier
\a q. The matrix function can either be represented by a std function or
a constant matrix provided when constructing this object. */
-34
View File
@@ -195,15 +195,6 @@ ComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
if ( lfi_imag ) { lfi->AddDomainIntegrator(lfi_imag); }
}
void
ComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &elem_attr_marker)
{
if ( lfi_real ) { lfr->AddDomainIntegrator(lfi_real, elem_attr_marker); }
if ( lfi_imag ) { lfi->AddDomainIntegrator(lfi_imag, elem_attr_marker); }
}
void
ComplexLinearForm::AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag)
@@ -326,14 +317,6 @@ void SesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
if (bfi_imag) { blfi->AddDomainIntegrator(bfi_imag); }
}
void SesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> & elem_marker)
{
if (bfi_real) { blfr->AddDomainIntegrator(bfi_real, elem_marker); }
if (bfi_imag) { blfi->AddDomainIntegrator(bfi_imag, elem_marker); }
}
void
SesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
@@ -896,15 +879,6 @@ ParComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
if ( lfi_imag ) { plfi->AddDomainIntegrator(lfi_imag); }
}
void
ParComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &elem_attr_marker)
{
if ( lfi_real ) { plfr->AddDomainIntegrator(lfi_real, elem_attr_marker); }
if ( lfi_imag ) { plfi->AddDomainIntegrator(lfi_imag, elem_attr_marker); }
}
void
ParComplexLinearForm::AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag)
@@ -1066,14 +1040,6 @@ void ParSesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
if (bfi_imag) { pblfi->AddDomainIntegrator(bfi_imag); }
}
void ParSesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> & elem_marker)
{
if (bfi_real) { pblfr->AddDomainIntegrator(bfi_real, elem_marker); }
if (bfi_imag) { pblfi->AddDomainIntegrator(bfi_imag, elem_marker); }
}
void
ParSesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
-20
View File
@@ -128,11 +128,6 @@ public:
void AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag);
/// Adds new Domain Integrator, restricted to the given attributes.
void AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &elem_attr_marker);
/// Adds new Boundary Integrator.
void AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag);
@@ -265,11 +260,6 @@ public:
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag);
/// Adds new Domain Integrator, restricted to the given attributes.
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> &elem_marker);
/// Adds new Boundary Integrator.
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag);
@@ -474,11 +464,6 @@ public:
void AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag);
/// Adds new Domain Integrator, restricted to specific attributes.
void AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &elem_attr_marker);
/// Adds new Boundary Integrator.
void AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag);
@@ -613,11 +598,6 @@ public:
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag);
/// Adds new Domain Integrator, restricted to specific attributes.
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> &elem_marker);
/// Adds new Boundary Integrator.
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag);
+1 -79
View File
@@ -645,8 +645,7 @@ ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
Node &n_mesh,
const std::string &coordset_name,
const std::string &main_topology_name,
const std::string &boundary_topology_name,
const std::string &main_adjset_name)
const std::string &boundary_topology_name)
{
int dim = mesh->SpaceDimension();
@@ -816,83 +815,6 @@ ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
bndry_att_vals[i] = mesh->GetBdrAttribute(i);
}
}
////////////////////////////////////////////
// Setup adjsets
////////////////////////////////////////////
#ifdef MFEM_USE_MPI
ParMesh *pmesh = dynamic_cast<ParMesh*>(mesh);
if (pmesh)
{
////////////////////////////////////////////
// Setup main adjset
////////////////////////////////////////////
Node &n_adjset = n_mesh["adjsets"][main_adjset_name];
n_adjset["association"] = "vertex";
n_adjset["topology"] = main_topology_name;
n_adjset["groups"].set(DataType::object());
const GroupTopology &pmesh_gtopo = pmesh->gtopo;
const int local_rank = pmesh->GetMyRank();
const int num_groups = pmesh_gtopo.NGroups();
// NOTE: skip the first group since its the local-only group
for (int i = 1; i < num_groups; i++)
{
const int num_group_nbrs = pmesh_gtopo.GetGroupSize(i);
const int *group_nbrs = pmesh_gtopo.GetGroup(i);
const int num_group_verts = pmesh->GroupNVertices(i);
// NOTE: 'neighbor' values are local to this processor, but Blueprint
// expects global domain identifiers, so we collapse this layer of
// indirection
Array<int> group_ranks(num_group_nbrs);
std::string group_name = "group";
{
for (int j = 0; j < num_group_nbrs; j++)
{
group_ranks[j] = pmesh_gtopo.GetNeighborRank(group_nbrs[j]);
}
group_ranks.Sort();
for (int j = 0; j < num_group_nbrs; j++)
{
group_name += "_" + std::to_string(group_ranks[j]);
}
// NOTE: Blueprint only wants remote ranks in its neighbor list,
// so we remove the local rank after the canonicalized Blueprint
// group name is formed
group_ranks.DeleteFirst(local_rank);
}
Node &n_group = n_adjset["groups"][group_name];
n_group["neighbors"].set(group_ranks.GetData(), group_ranks.Size());
n_group["values"].set(DataType::c_int(num_group_verts));
int_array group_vals = n_group["values"].value();
for (int j = 0; j < num_group_verts; j++)
{
group_vals[j] = pmesh->GroupVertex(i, j);
}
}
// NOTE: We don't create an adjset for face neighbor data because
// these faces aren't listed in the 'boundary_topology_name' topology
// (this topology only covers the faces between 'main_topology_name'
// elements and void). To include a face neighbor data adjset, this
// function would need to export a topology with either (1) all faces
// in the mesh topology or (2) all boundary faces, including neighbors.
////////////////////////////////////////////
// Setup distributed state
////////////////////////////////////////////
Node &n_domid = n_mesh["state/domain_id"];
n_domid.set(local_rank);
}
#endif
}
//---------------------------------------------------------------------------//
+1 -2
View File
@@ -166,8 +166,7 @@ public:
conduit::Node &out,
const std::string &coordset_name = "coords",
const std::string &main_topology_name = "main",
const std::string &boundary_topology_name = "boundary",
const std::string &main_adjset_name = "main_adjset");
const std::string &boundary_topology_name = "boundary");
/// Describes a MFEM grid function using the mesh blueprint
/** Sets up passed conduit::Node out to describe the given grid function
-74
View File
@@ -85,11 +85,6 @@ void TransformPrimal(const DofTransformation *ran_dof_trans,
}
}
void DofTransformation::InvTransformDual(Vector &v) const
{
InvTransformDual(v.GetData());
}
void TransformDual(const DofTransformation *ran_dof_trans,
const DofTransformation *dom_dof_trans,
DenseMatrix &elmat)
@@ -200,35 +195,6 @@ void VDofTransformation::TransformDual(double *v) const
}
}
void VDofTransformation::InvTransformDual(double *v) const
{
int size = doftrans_->Size();
if ((Ordering::Type)ordering_ == Ordering::byNODES)
{
for (int i=0; i<vdim_; i++)
{
doftrans_->InvTransformDual(&v[i*size]);
}
}
else
{
Vector vec(size);
for (int i=0; i<vdim_; i++)
{
for (int j=0; j<size; j++)
{
vec(j) = v[j*vdim_+i];
}
doftrans_->InvTransformDual(vec);
for (int j=0; j<size; j++)
{
v[j*vdim_+i] = vec(j);
}
}
}
}
const double ND_DofTransformation::T_data[24] =
{
1.0, 0.0, 0.0, 1.0,
@@ -325,26 +291,6 @@ ND_TriDofTransformation::TransformDual(double *v) const
}
}
void
ND_TriDofTransformation::InvTransformDual(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<1; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[3*nedofs + f*nfdofs + 2*i];
T(Fo[f]).MultTranspose(v2, &v[3*nedofs + f*nfdofs + 2*i]);
}
}
}
ND_TetDofTransformation::ND_TetDofTransformation(int p)
: ND_DofTransformation(p*(p + 2)*(p + 3)/2, p)
{
@@ -409,24 +355,4 @@ ND_TetDofTransformation::TransformDual(double *v) const
}
}
void
ND_TetDofTransformation::InvTransformDual(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<4; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[6*nedofs + f*nfdofs + 2*i];
T(Fo[f]).MultTranspose(v2, &v[6*nedofs + f*nfdofs + 2*i]);
}
}
}
} // namespace mfem
-15
View File
@@ -102,10 +102,6 @@ public:
virtual void TransformDual(double *v) const = 0;
virtual void TransformDual(Vector &v) const;
/** Inverse Transform dual DoFs */
virtual void InvTransformDual(double *v) const = 0;
virtual void InvTransformDual(Vector &v) const;
/** Transform a matrix of dual DoFs entries as computed by a
BilinearFormIntegrator before summing into a BilinearForm object. */
virtual void TransformDual(DenseMatrix &V) const;
@@ -187,12 +183,10 @@ public:
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
/** Abstract base class for high-order Nedelec spaces on elements with
@@ -241,8 +235,6 @@ public:
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
/// DoF transformation implementation for the Nedelec basis on tetrahedra
@@ -254,15 +246,12 @@ public:
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
/// DoF transformation implementation for the Nedelec basis on wedge elements
@@ -275,16 +264,12 @@ public:
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
} // namespace mfem
+5 -183
View File
@@ -561,155 +561,6 @@ void FiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
}
}
void FiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_vdofs,
int component) const
{
Array<int> vdofs, dofs;
ess_vdofs.SetSize(GetVSize());
ess_vdofs = 0;
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
if (!mesh->ent_sets->SetExists(type, set_index))
{
ostringstream oss; oss << "Entity set of type \""
<< EntitySets::GetTypeName(type)
<< "\" and index " << set_index
<< " was not found.";
MFEM_VERIFY(false, oss.str().c_str());
}
set<int>::iterator it;
for (it=(*mesh->ent_sets)(type, set_index).begin();
it!=(*mesh->ent_sets)(type, set_index).end(); it++)
{
int ent_index = *it;
cout << "collecting vdofs for entity " << ent_index << "->";
if (component < 0)
{
switch (type)
{
case EntitySets::VERTEX:
GetVertexVDofs(ent_index, vdofs);
break;
case EntitySets::EDGE:
GetEdgeVDofs(ent_index, vdofs);
break;
case EntitySets::FACE:
GetFaceVDofs(ent_index, vdofs);
break;
case EntitySets::ELEMENT:
GetElementVDofs(ent_index, vdofs);
break;
default:
mfem_error("GetEssentialVDofs: Invalid entity type");
}
vdofs.Print(cout);
mark_dofs(vdofs, ess_vdofs);
}
else
{
switch (type)
{
case EntitySets::VERTEX:
GetVertexDofs(ent_index, dofs);
break;
case EntitySets::EDGE:
GetEdgeDofs(ent_index, dofs);
break;
case EntitySets::FACE:
GetFaceDofs(ent_index, dofs);
break;
case EntitySets::ELEMENT:
GetElementDofs(ent_index, dofs);
break;
default:
mfem_error("GetEssentialDofs: Invalid entity type");
}
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
if (mesh->ncmesh)
{
Array<int> es_verts, es_edges, es_faces;
mesh->ncmesh->GetEntitySetClosure(type, set_index,
es_verts, es_edges, es_faces);
cout << "returned from get closure" << endl;
for (int i = 0; i < es_verts.Size(); i++)
{
if (es_verts[i] < GetNV())
{
if (component < 0)
{
GetVertexVDofs(es_verts[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetVertexDofs(es_verts[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
for (int i = 0; i < es_edges.Size(); i++)
{
if (es_edges[i] < GetMesh()->GetNEdges())
{
if (component < 0)
{
GetEdgeVDofs(es_edges[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetEdgeDofs(es_edges[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
for (int i = 0; i < es_faces.Size(); i++)
{
if (es_faces[i] < GetMesh()->GetNFaces())
{
if (component < 0)
{
GetFaceVDofs(es_faces[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetFaceDofs(es_faces[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
}
}
void FiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_vdofs,
int component) const
{
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
GetEssentialVDofs(type, mesh->ent_sets->GetSetIndex(type, set_name),
ess_vdofs, component);
}
void FiniteElementSpace::GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
Array<int> &ess_tdof_list,
int component)
@@ -728,36 +579,6 @@ void FiniteElementSpace::GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
MarkerToList(ess_tdofs, ess_tdof_list);
}
void FiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_tdof_list,
int component)
{
Array<int> ess_vdofs, ess_tdofs;
GetEssentialVDofs(type, set_index, ess_vdofs, component);
const SparseMatrix *R = GetConformingRestriction();
if (!R)
{
ess_tdofs.MakeRef(ess_vdofs);
}
else
{
R->BooleanMult(ess_vdofs, ess_tdofs);
}
MarkerToList(ess_tdofs, ess_tdof_list);
}
void FiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_tdof_list,
int component)
{
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
GetEssentialTrueDofs(type, mesh->ent_sets->GetSetIndex(type, set_name),
ess_tdof_list, component);
}
void FiniteElementSpace::GetBoundaryTrueDofs(Array<int> &boundary_dofs,
int component)
{
@@ -1888,7 +1709,8 @@ void FiniteElementSpace::RefinementOperator
fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
x.GetSubVector(f_vdofs, subX);
doftrans->InvTransformDual(subX);
old_DoFTrans[geom]->InvTransformPrimal(subX);
for (int p = 0; p < f_dofs.Size(); ++p)
{
if (processed[DecodeDof(f_dofs[p])])
@@ -1897,9 +1719,9 @@ void FiniteElementSpace::RefinementOperator
}
}
lP.MultTranspose(subX, subYt);
old_DoFTrans[geom]->TransformDual(subYt);
y.AddElementVector(c_vdofs, subYt);
lP.MultTranspose(subX, subY);
doftrans->TransformPrimal(subY);
y.AddElementVector(c_vdofs, subY);
}
if (vdoftrans)
-26
View File
@@ -778,19 +778,6 @@ public:
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_vdofs,
int component = -1) const;
/** @brief Get a list of essential true dofs, ess_tdof_list, corresponding to the
boundary attributes marked in the array bdr_attr_is_ess.
For spaces with 'vdim' > 1, the 'component' parameter can be used
@@ -799,19 +786,6 @@ public:
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set index. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set name. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_tdof_list,
int component = -1);
/** @brief Get a list of all boundary true dofs, @a boundary_dofs. For spaces
with 'vdim' > 1, the 'component' parameter can be used to restricts the
marked tDOFs to the specified component. Equivalent to
-47
View File
@@ -23,8 +23,6 @@
#include <limits>
#include <list>
using namespace std;
namespace mfem
{
@@ -1020,30 +1018,6 @@ void ParFiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
}
}
void ParFiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_dofs,
int component) const
{
FiniteElementSpace::GetEssentialVDofs(type, set_index, ess_dofs, component);
if (Conforming())
{
// Make sure that processors without boundary elements mark
// their boundary dofs (if they have any).
Synchronize(ess_dofs);
}
}
void ParFiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_vdofs,
int component) const
{
GetEssentialVDofs(type, pmesh->ent_sets->GetSetIndex(type, set_name),
ess_vdofs, component);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(const Array<int>
&bdr_attr_is_ess,
Array<int> &ess_tdof_list,
@@ -1073,27 +1047,6 @@ void ParFiniteElementSpace::GetEssentialTrueDofs(const Array<int>
MarkerToList(true_ess_dofs, ess_tdof_list);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_tdof_list,
int component)
{
Array<int> ess_dofs, true_ess_dofs;
GetEssentialVDofs(type, set_index, ess_dofs, component);
GetRestrictionMatrix()->BooleanMult(ess_dofs, true_ess_dofs);
MarkerToList(true_ess_dofs, ess_tdof_list);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_tdof_list,
int component)
{
GetEssentialTrueDofs(type, pmesh->ent_sets->GetSetIndex(type, set_name),
ess_tdof_list, component);
}
int ParFiniteElementSpace::GetLocalTDofNumber(int ldof) const
{
if (Nonconforming())
-26
View File
@@ -355,38 +355,12 @@ public:
Array<int> &ess_dofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_vdofs,
int component = -1) const;
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
boundary attributes marked in the array bdr_attr_is_ess. */
virtual void GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set index. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set name. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_tdof_list,
int component = -1);
/** If the given ldof is owned by the current processor, return its local
tdof number, otherwise return -1 */
int GetLocalTDofNumber(int ldof) const;
+2
View File
@@ -40,6 +40,8 @@ StaticCondensation::StaticCondensation(FiniteElementSpace *fespace)
#endif
S = S_e = NULL;
symm = false;
A_data.Reset();
A_ipiv.Reset();
Array<int> vdofs;
const int NE = fes->GetNE();
+6 -27
View File
@@ -913,11 +913,7 @@ TransferOperator::TransferOperator(const FiniteElementSpace& lFESpace_,
else if (lFESpace_.GetMesh()->GetNE() > 0
&& hFESpace_.GetMesh()->GetNE() > 0
&& dynamic_cast<const TensorBasisElement*>(lFESpace_.GetFE(0))
&& dynamic_cast<const TensorBasisElement*>(hFESpace_.GetFE(0))
&& (hFESpace_.FEColl()->GetContType() ==
mfem::FiniteElementCollection::CONTINUOUS ||
hFESpace_.FEColl()->GetContType() ==
mfem::FiniteElementCollection::DISCONTINUOUS))
&& dynamic_cast<const TensorBasisElement*>(hFESpace_.GetFE(0)))
{
opr = new TensorProductPRefinementTransferOperator(lFESpace_, hFESpace_);
}
@@ -965,8 +961,8 @@ void PRefinementTransferOperator::Mult(const Vector& x, Vector& y) const
for (int i = 0; i < mesh->GetNE(); i++)
{
DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
DofTransformation * doftrans_l = lFESpace.GetElementDofs(i, l_dofs);
hFESpace.GetElementDofs(i, h_dofs);
lFESpace.GetElementDofs(i, l_dofs);
const Geometry::Type geom = mesh->GetElementBaseGeometry(i);
if (geom != cached_geom)
@@ -986,15 +982,7 @@ void PRefinementTransferOperator::Mult(const Vector& x, Vector& y) const
h_dofs.Copy(h_vdofs);
hFESpace.DofsToVDofs(vd, h_vdofs);
x.GetSubVector(l_vdofs, subX);
if (doftrans_l)
{
doftrans_l->InvTransformPrimal(subX);
}
loc_prol.Mult(subX, subY);
if (doftrans_h)
{
doftrans_h->TransformPrimal(subY);
}
y.SetSubVector(h_vdofs, subY);
}
}
@@ -1022,8 +1010,8 @@ void PRefinementTransferOperator::MultTranspose(const Vector& x,
for (int i = 0; i < mesh->GetNE(); i++)
{
DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
DofTransformation * doftrans_l = lFESpace.GetElementDofs(i, l_dofs);
hFESpace.GetElementDofs(i, h_dofs);
lFESpace.GetElementDofs(i, l_dofs);
const Geometry::Type geom = mesh->GetElementBaseGeometry(i);
if (geom != cached_geom)
@@ -1045,10 +1033,6 @@ void PRefinementTransferOperator::MultTranspose(const Vector& x,
hFESpace.DofsToVDofs(vd, h_vdofs);
x.GetSubVector(h_vdofs, subX);
if (doftrans_h)
{
doftrans_h->InvTransformDual(subX);
}
for (int p = 0; p < h_dofs.Size(); ++p)
{
if (processed[lFESpace.DecodeDof(h_dofs[p])])
@@ -1058,10 +1042,6 @@ void PRefinementTransferOperator::MultTranspose(const Vector& x,
}
loc_prol.Mult(subX, subY);
if (doftrans_l)
{
doftrans_l->TransformDual(subY);
}
y.AddElementVector(l_vdofs, subY);
}
@@ -1105,8 +1085,7 @@ TensorProductPRefinementTransferOperator(
// must be sorted in lexicographical order
for (int i = 0; i < ir.GetNPoints(); ++i)
{
int j = hdofmap[i] >=0 ? hdofmap[i] : -1 - hdofmap[i];
irLex.IntPoint(i) = ir.IntPoint(j);
irLex.IntPoint(i) = ir.IntPoint(hdofmap[i]);
}
NE = lFESpace.GetNE();
+2 -3
View File
@@ -175,9 +175,8 @@ protected:
// Copy{From,To}, {ReadWrite,Read,Write}.
public:
/** Default constructor, sets the host pointer to nullptr and the metadata to
meaningful default values. */
Memory() { Reset(); }
/// Default constructor: no initialization.
Memory() { }
/// Copy constructor: default.
Memory(const Memory &orig) = default;
-1
View File
@@ -69,7 +69,6 @@ void IntegerSet::Recreate(const int n, const int *p)
me.Sort();
// Remove duplicate entries
for (j = 0, i = 1; i < n; i++)
if (me[i] != me[j])
{
+2 -7
View File
@@ -36,7 +36,7 @@ public:
IntegerSet(const int n, const int *p) { Recreate(n, p); }
/// Return the size of the set.
int Size() const { return me.Size(); }
int Size() { return me.Size(); }
/// Return a reference to the sorted array of all the set entries.
operator Array<int>& () { return me; }
@@ -50,8 +50,6 @@ public:
/// Return 1 if the sets are equal and 0 otherwise.
int operator==(IntegerSet &s);
inline const int & operator[](int i) const { return me[i]; }
/** @brief Create an integer set from C-array 'p' of 'n' integers.
Overwrites any existing set data. */
void Recreate(const int n, const int *p);
@@ -66,7 +64,7 @@ private:
public:
/// Return the number of integer sets in the list.
int Size() const { return TheList.Size(); }
int Size() { return TheList.Size(); }
/// Return the value of the first element of the ith set.
int PickElementInSet(int i) { return TheList[i]->PickElement(); }
@@ -86,9 +84,6 @@ public:
/// Write the list of sets into table 't'.
void AsTable(Table &t);
inline const IntegerSet & operator[](int i) const { return *TheList[i]; }
inline IntegerSet & operator[](int i) { return *TheList[i]; }
~ListOfIntegerSets();
};
+7 -9
View File
@@ -61,7 +61,7 @@ inline void Sort3 (int &r, int &c, int &f)
}
}
int STable3D::Push (int r, int c, int f, int t)
int STable3D::Push (int r, int c, int f)
{
STable3DNode *node;
@@ -86,7 +86,6 @@ int STable3D::Push (int r, int c, int f, int t)
#endif
node->Column = c;
node->Floor = f;
node->Tier = t;
node->Number = NElem;
node->Prev = Rows[r];
Rows[r] = node;
@@ -110,9 +109,9 @@ int STable3D::operator() (int r, int c, int f) const
}
}
// MFEM_ABORT("(r,c,f) = (" << r << "," << c << "," << f << ")");
MFEM_ABORT("(r,c,f) = (" << r << "," << c << "," << f << ")");
return -1;
return 0;
}
int STable3D::Index (int r, int c, int f) const
@@ -153,13 +152,13 @@ int STable3D::Push4 (int r, int c, int f, int t)
switch (i)
{
case 0:
return Push (c,f,t,r);
return Push (c,f,t);
case 1:
return Push (r,f,t,c);
return Push (r,f,t);
case 2:
return Push (r,c,t,f);
return Push (r,c,t);
case 3:
return Push (r,c,f,t);
return Push (r,c,f);
}
return -1;
@@ -219,7 +218,6 @@ void STable3D::Print(std::ostream & out) const
out << row
<< ' ' << node_p->Column
<< ' ' << node_p->Floor
<< ' ' << node_p->Tier
<< ' ' << node_p->Number
<< endl;
node_p = node_p->Prev;
+3 -22
View File
@@ -15,8 +15,6 @@
#include "mem_alloc.hpp"
#include "../general/globals.hpp"
#include <iostream>
namespace mfem
{
@@ -24,7 +22,7 @@ class STable3DNode
{
public:
STable3DNode *Prev;
int Column, Floor, Tier, Number;
int Column, Floor, Number;
};
/** @brief Symmetric 3D Table stored as an array of rows each of which has a
@@ -49,7 +47,7 @@ public:
/** @brief Check to see if this entry is in the table and add it to the table
if it is not there. Returns the number assigned to the table entry. */
int Push (int r, int c, int f, int t = -1);
int Push (int r, int c, int f);
/// Return the number assigned to the table entry. Abort if it's not there.
int operator() (int r, int c, int f) const;
@@ -68,30 +66,13 @@ public:
not there. */
int operator() (int r, int c, int f, int t) const;
/// Return the number of rows added to the table.
int NumberOfRows() const { return Size; }
/// Return the number of elements added to the table.
int NumberOfElements() const { return NElem; }
int NumberOfElements() { return NElem; }
/// Print out all of the table elements.
void Print(std::ostream &out = mfem::out) const;
~STable3D ();
class RowIterator
{
private:
STable3DNode *n;
public:
RowIterator (const STable3D &t, int r) { n = t.Rows[r]; }
int operator!() { return (n != NULL); }
void operator++() { n = n->Prev; }
int Column() { return (n->Column); }
int Floor() { return (n->Floor); }
int Tier() { return (n->Tier); }
int Index() { return (n->Number); }
};
};
}
+4
View File
@@ -35,6 +35,10 @@ Table::Table(const Table &table)
I.CopyFrom(table.I, size+1);
J.CopyFrom(table.J, nnz);
}
else
{
I.Reset(); J.Reset();
}
}
Table& Table::operator=(const Table &rhs)
+2 -2
View File
@@ -53,7 +53,7 @@ protected:
public:
/// Creates an empty table
Table() { size = -1; }
Table() { size = -1; I.Reset(); J.Reset(); }
/// Copy constructor
Table(const Table &);
@@ -66,7 +66,7 @@ public:
/** Create a table from a list of connections, see MakeFromList(). */
Table(int nrows, Array<Connection> &list) : size(-1)
{ MakeFromList(nrows, list); }
{ I.Reset(); J.Reset(); MakeFromList(nrows, list); }
/** Create a table with one entry per row with column indices given
by 'partitioning'. */
+20 -1
View File
@@ -70,7 +70,10 @@ namespace mfem
using namespace std;
DenseMatrix::DenseMatrix() : Matrix(0) { }
DenseMatrix::DenseMatrix() : Matrix(0)
{
data.Reset();
}
DenseMatrix::DenseMatrix(const DenseMatrix &m) : Matrix(m.height, m.width)
{
@@ -81,6 +84,10 @@ DenseMatrix::DenseMatrix(const DenseMatrix &m) : Matrix(m.height, m.width)
data.New(hw);
std::memcpy(data, m.data, sizeof(double)*hw);
}
else
{
data.Reset();
}
}
DenseMatrix::DenseMatrix(int s) : Matrix(s)
@@ -91,6 +98,10 @@ DenseMatrix::DenseMatrix(int s) : Matrix(s)
data.New(s*s);
*this = 0.0; // init with zeroes
}
else
{
data.Reset();
}
}
DenseMatrix::DenseMatrix(int m, int n) : Matrix(m, n)
@@ -103,6 +114,10 @@ DenseMatrix::DenseMatrix(int m, int n) : Matrix(m, n)
data.New(capacity);
*this = 0.0; // init with zeroes
}
else
{
data.Reset();
}
}
DenseMatrix::DenseMatrix(const DenseMatrix &mat, char ch)
@@ -122,6 +137,10 @@ DenseMatrix::DenseMatrix(const DenseMatrix &mat, char ch)
}
}
}
else
{
data.Reset();
}
}
void DenseMatrix::SetSize(int h, int w)
+5
View File
@@ -753,6 +753,7 @@ public:
DenseTensor()
{
nk = 0;
tdata.Reset();
}
DenseTensor(int i, int j, int k)
@@ -786,6 +787,10 @@ public:
tdata.New(size, other.tdata.GetMemoryType());
tdata.CopyFrom(other.tdata, size);
}
else
{
tdata.Reset();
}
}
int SizeI() const { return Mk.Height(); }
+11 -50
View File
@@ -127,19 +127,18 @@ HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size,
own_ParVector = 1;
}
// Call the move constructor on the "compatible" temp vector
HypreParVector::HypreParVector(const HypreParVector &y) : HypreParVector(
y.CreateCompatibleVector())
HypreParVector::HypreParVector(const HypreParVector &y) : Vector()
{
// Deep copy the local data
hypre_SeqVectorCopy(hypre_ParVectorLocalVector(y.x),
hypre_ParVectorLocalVector(x));
}
HypreParVector::HypreParVector(HypreParVector &&y)
{
own_ParVector = 0;
*this = std::move(y);
x = hypre_ParVectorCreate(y.x -> comm, y.x -> global_size,
y.x -> partitioning);
hypre_ParVectorInitialize(x);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParVectorSetPartitioningOwner(x,0);
#endif
hypre_ParVectorSetDataOwner(x,1);
hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
_SetDataAndSize_();
own_ParVector = 1;
}
HypreParVector::HypreParVector(const HypreParMatrix &A,
@@ -179,23 +178,6 @@ HypreParVector::HypreParVector(ParFiniteElementSpace *pfes)
own_ParVector = 1;
}
HypreParVector HypreParVector::CreateCompatibleVector() const
{
HypreParVector result;
result.x = hypre_ParVectorCreate(x -> comm, x -> global_size,
x -> partitioning);
hypre_ParVectorInitialize(result.x);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParVectorSetPartitioningOwner(result.x,0);
#endif
hypre_ParVectorSetDataOwner(result.x,1);
hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(result.x),1);
result._SetDataAndSize_();
result.own_ParVector = 1;
return result;
}
void HypreParVector::WrapHypreParVector(hypre_ParVector *y, bool owner)
{
if (own_ParVector) { hypre_ParVectorDestroy(x); }
@@ -234,18 +216,6 @@ HypreParVector& HypreParVector::operator=(const HypreParVector &y)
return *this;
}
HypreParVector& HypreParVector::operator=(HypreParVector &&y)
{
// If the argument vector owns its data, then the calling vector will as well
WrapHypreParVector(static_cast<hypre_ParVector*>(y), y.own_ParVector);
// Either way the argument vector will no longer own its data
y.own_ParVector = 0;
y.x = nullptr;
y.data.Reset();
y.size = 0;
return *this;
}
void HypreParVector::SetData(double *data_)
{
hypre_VectorData(hypre_ParVectorLocalVector(x)) = data_;
@@ -1603,16 +1573,9 @@ HypreParMatrix *HypreParMatrix::ExtractSubmatrix(const Array<int> &indices,
}
// Construct cpts_global array on hypre matrix structure
#if (MFEM_HYPRE_VERSION > 22300) || (MFEM_HYPRE_VERSION == 22300 && HYPRE_DEVELOP_NUMBER >=8)
HYPRE_BigInt cpts_global[2];
hypre_BoomerAMGCoarseParms(MPI_COMM_WORLD, local_num_vars, 1, NULL,
CF_marker, NULL, cpts_global);
#else
HYPRE_BigInt *cpts_global;
hypre_BoomerAMGCoarseParms(MPI_COMM_WORLD, local_num_vars, 1, NULL,
CF_marker, NULL, &cpts_global);
#endif
// Extract submatrix into *submat
#ifdef hypre_IntArrayData
@@ -1624,9 +1587,7 @@ HypreParMatrix *HypreParMatrix::ExtractSubmatrix(const Array<int> &indices,
"FF", &submat, threshold);
#endif
#if (MFEM_HYPRE_VERSION <= 22300) && !(MFEM_HYPRE_VERSION == 22300 && HYPRE_DEVELOP_NUMBER >=8)
mfem_hypre_TFree(cpts_global);
#endif
#ifdef hypre_IntArrayData
hypre_IntArrayDestroy(CF_marker);
#endif
+1 -9
View File
@@ -141,10 +141,8 @@ public:
allocated in the memory location HYPRE_MEMORY_DEVICE. */
HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size, double *data_,
HYPRE_BigInt *col, bool is_device_ptr = false);
/// Creates a deep copy of @a y
/// Creates vector compatible with y
HypreParVector(const HypreParVector &y);
/// Move constructor for HypreParVector. "Steals" data from its argument.
HypreParVector(HypreParVector&& other);
/// Creates vector compatible with (i.e. in the domain of) A or A^T
explicit HypreParVector(const HypreParMatrix &A, int transpose = 0);
/// Creates vector wrapping y
@@ -152,10 +150,6 @@ public:
/// Create a true dof parallel vector on a given ParFiniteElementSpace
explicit HypreParVector(ParFiniteElementSpace *pfes);
/// \brief Constructs a @p HypreParVector *compatible* with the calling vector
/// - meaning that it will be the same size and have the same partitioning.
HypreParVector CreateCompatibleVector() const;
/// MPI communicator
MPI_Comm GetComm() const { return x->comm; }
@@ -198,8 +192,6 @@ public:
HypreParVector& operator= (double d);
/// Define '=' for hypre vectors.
HypreParVector& operator= (const HypreParVector &y);
/// Move assignment
HypreParVector& operator= (HypreParVector &&y);
using Vector::Read;
+4
View File
@@ -558,6 +558,8 @@ PetscParVector::PetscParVector(MPI_Comm comm, const Operator &op,
else /* Vector intended to be used with Place/ResetMemory calls */
{
size = loc;
pdata.Reset();
data.Reset();
}
}
@@ -579,6 +581,8 @@ PetscParVector::PetscParVector(const PetscParMatrix &A,
PetscInt n;
ierr = VecGetLocalSize(x,&n); PCHKERRQ(x,ierr);
size = n;
pdata.Reset();
data.Reset();
}
else
{
+6 -6
View File
@@ -84,9 +84,9 @@ SparseMatrix::SparseMatrix(int nrows, int ncols)
isSorted(false)
{
// We probably do not need to set the ownership flags here.
I.SetHostPtrOwner(true);
J.SetHostPtrOwner(true);
A.SetHostPtrOwner(true);
I.Reset(); I.SetHostPtrOwner(true);
J.Reset(); J.SetHostPtrOwner(true);
A.Reset(); A.SetHostPtrOwner(true);
for (int i = 0; i < nrows; i++)
{
@@ -229,9 +229,9 @@ SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph,
}
// We probably do not need to set the ownership flags here.
I.SetHostPtrOwner(true);
J.SetHostPtrOwner(true);
A.SetHostPtrOwner(true);
I.Reset(); I.SetHostPtrOwner(true);
J.Reset(); J.SetHostPtrOwner(true);
A.Reset(); A.SetHostPtrOwner(true);
}
current_row = -1;
+8 -1
View File
@@ -17,7 +17,10 @@
namespace mfem
{
DenseSymmetricMatrix::DenseSymmetricMatrix() : Matrix(0) { }
DenseSymmetricMatrix::DenseSymmetricMatrix() : Matrix(0)
{
data.Reset();
}
DenseSymmetricMatrix::DenseSymmetricMatrix(int s) : Matrix(s)
{
@@ -27,6 +30,10 @@ DenseSymmetricMatrix::DenseSymmetricMatrix(int s) : Matrix(s)
data.New((s*(s+1))/2);
*this = 0.0; // init with zeroes
}
else
{
data.Reset();
}
}
void DenseSymmetricMatrix::SetSize(int s)
+6 -15
View File
@@ -39,21 +39,21 @@ namespace mfem
Vector::Vector(const Vector &v)
{
const int s = v.Size();
size = s;
if (s > 0)
{
MFEM_ASSERT(!v.data.Empty(), "invalid source vector");
size = s;
data.New(s, v.data.GetMemoryType());
data.CopyFrom(v.data, s);
}
else
{
size = 0;
data.Reset();
}
UseDevice(v.UseDevice());
}
Vector::Vector(Vector &&v)
{
*this = std::move(v);
}
void Vector::Load(std::istream **in, int np, int *dim)
{
int i, j, s;
@@ -146,15 +146,6 @@ Vector &Vector::operator=(const Vector &v)
return *this;
}
Vector &Vector::operator=(Vector &&v)
{
data = std::move(v.data);
size = v.size;
v.data.Reset();
v.size = 0;
return *this;
}
Vector &Vector::operator=(double value)
{
const bool use_dev = UseDevice();
+8 -11
View File
@@ -66,16 +66,12 @@ protected:
public:
/** Default constructor for Vector. Sets size = 0, and calls Memory::Reset on
data through Memory<double>'s default constructor. */
Vector(): size(0) { }
/// Default constructor for Vector. Sets size = 0 and data = NULL.
Vector() { data.Reset(); size = 0; }
/// Copy constructor. Allocates a new data array and copies the data.
Vector(const Vector &);
/// Move constructor. "Steals" data from its argument.
Vector(Vector&& v);
/// @brief Creates vector of size s.
/// @warning Entries are not initialized to zero!
explicit Vector(int s);
@@ -282,9 +278,6 @@ public:
assignment operator. */
Vector &operator=(const Vector &v);
/// Move assignment
Vector &operator=(Vector&& v);
/// Redefine '=' for vector = constant.
Vector &operator=(double value);
@@ -510,12 +503,16 @@ inline int CheckFinite(const double *v, const int n)
inline Vector::Vector(int s)
{
MFEM_ASSERT(s>=0,"Unexpected negative size.");
size = s;
if (s > 0)
{
size = s;
data.New(s);
}
else
{
size = 0;
data.Reset();
}
}
inline void Vector::SetSize(int s)
+5 -7
View File
@@ -123,7 +123,7 @@ EXAMPLE_SUBDIRS = amgx caliper ginkgo hiop petsc pumi sundials superlu
EXAMPLE_DIRS := examples $(addprefix examples/,$(EXAMPLE_SUBDIRS))
EXAMPLE_TEST_DIRS := examples
MINIAPP_SUBDIRS = common electromagnetics meshing navier performance tools toys nurbs gslib adjoint solvers shifted mtop parelag autodiff
MINIAPP_SUBDIRS = common electromagnetics meshing navier performance tools toys nurbs gslib adjoint solvers shifted mtop parelag
MINIAPP_DIRS := $(addprefix miniapps/,$(MINIAPP_SUBDIRS))
MINIAPP_TEST_DIRS := $(filter-out %/common,$(MINIAPP_DIRS))
MINIAPP_USE_COMMON := $(addprefix miniapps/,electromagnetics meshing tools toys shifted)
@@ -274,7 +274,7 @@ endif
# List of MFEM dependencies, that require the *_LIB variable to be non-empty
MFEM_REQ_LIB_DEPS = SUPERLU MUMPS METIS FMS CONDUIT SIDRE LAPACK SUNDIALS MESQUITE\
SUITESPARSE STRUMPACK GINKGO GNUTLS NETCDF PETSC SLEPC MPFR PUMI HIOP GSLIB\
OCCA CEED RAJA UMPIRE MKL_CPARDISO AMGX CALIPER PARELAG BENCHMARK
OCCA CEED RAJA UMPIRE MKL_CPARDISO AMGX CALIPER PARELAG BENCHMARK
PETSC_ERROR_MSG = $(if $(PETSC_FOUND),,. PETSC config not found: $(PETSC_VARS))
SLEPC_ERROR_MSG = $(if $(SLEPC_FOUND),,. SLEPC config not found: $(SLEPC_VARS))
@@ -340,8 +340,8 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\
MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\
MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE MFEM_USE_SIMD\
MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO MFEM_USE_AMGX MFEM_USE_MUMPS\
MFEM_USE_ADFORWARD MFEM_USE_CODIPACK MFEM_USE_CALIPER MFEM_USE_BENCHMARK\
MFEM_USE_PARELAG MFEM_SOURCE_DIR MFEM_INSTALL_DIR
MFEM_USE_CALIPER MFEM_USE_BENCHMARK MFEM_USE_PARELAG\
MFEM_SOURCE_DIR MFEM_INSTALL_DIR
# List of makefile variables that will be written to config.mk:
MFEM_CONFIG_VARS = MFEM_CXX MFEM_HOST_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS\
@@ -500,7 +500,7 @@ hpc:
deps:
rm -f $(BLD)deps.mk
for i in $(RELSRC_FILES:.cpp=); do \
$(DEP_CXX) $(MFEM_BUILD_FLAGS) $(DEP_FLAGS) $(BLD)$${i}.o $(SRC)$${i}.cpp\
$(DEP_CXX) $(MFEM_BUILD_FLAGS) -MM -MT $(BLD)$${i}.o $(SRC)$${i}.cpp\
>> $(BLD)deps.mk; done
check: lib
@@ -679,8 +679,6 @@ status info:
$(info MFEM_USE_SIMD = $(MFEM_USE_SIMD))
$(info MFEM_USE_ADIOS2 = $(MFEM_USE_ADIOS2))
$(info MFEM_USE_MKL_CPARDISO = $(MFEM_USE_MKL_CPARDISO))
$(info MFEM_USE_ADFORWARD = $(MFEM_USE_ADFORWARD))
$(info MFEM_USE_CODIPACK = $(MFEM_USE_CODIPACK))
$(info MFEM_USE_BENCHMARK = $(MFEM_USE_BENCHMARK))
$(info MFEM_USE_PARELAG = $(MFEM_USE_PARELAG))
$(info MFEM_CXX = $(value MFEM_CXX))
-1295
View File
File diff suppressed because it is too large Load Diff
-219
View File
@@ -1,219 +0,0 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_ENTITY_SETS
#define MFEM_ENTITY_SETS
#include "../config/config.hpp"
#include "../general/table.hpp"
#include "../general/stable3d.hpp"
#include <limits>
#include <map>
#include <set>
#include <string>
#include <vector>
namespace mfem
{
class Mesh;
class NCMesh;
class NCEntitySets;
class EntitySets
{
friend class Mesh;
friend class NCMesh;
friend class NCEntitySets;
public:
enum EntityType {INVALID = -1, VERTEX = 0, EDGE = 1, FACE = 2, ELEMENT = 3};
static std::map<EntityType,std::string> EntityTypeNames;
EntitySets(Mesh & mesh);
EntitySets(const EntitySets & ent_sets);
EntitySets(Mesh & mesh, NCMesh &ncmesh);
virtual ~EntitySets();
static const std::string & GetTypeName(EntityType t);
bool SetExists(EntityType t, unsigned int s) const;
bool SetExists(EntityType t, const std::string & s) const;
void Load(std::istream &input);
void Print(std::ostream &output) const;
virtual void PrintSetInfo(std::ostream &output) const;
inline Mesh *GetMesh() const { return mesh_; }
unsigned int GetNumSets(EntityType t) const;
const std::string & GetSetName(EntityType t, unsigned int s) const;
unsigned int GetNumEntities(EntityType t, unsigned int s) const;
int GetSetIndex(EntityType t, const std::string & s) const;
unsigned int GetNumEntities(EntityType t, const std::string & s) const;
inline std::set<int> & operator()(EntityType t, unsigned int s)
{ return sets_[t][s]; }
inline const std::set<int> & operator()(EntityType t, unsigned int s) const
{ return sets_[t][s]; }
const Table * GetEdgeVertexTable() const { return edge_vertex_; }
const Table * GetFaceVertexTable() const { return face_vertex_; }
const Table * GetFaceEdgeTable() const { return face_edge_; }
// void Prune(int nelems);
protected:
void SetNumSets(EntityType t, unsigned int n)
{ sets_[t].resize(n); set_names_[t].resize(n); }
void SetSetName(EntityType t, int s, const std::string & name)
{ set_names_[t][s] = name; set_index_by_name_[t][name] = s; }
/// Make local copies of edge_vertex, face_vertex, and face_edge tables.
void CopyMeshTables();
/// Refine quadrilateral mesh.
virtual void QuadUniformRefinement();
/// Refine hexahedral mesh.
virtual void HexUniformRefinement();
/// Refine 2D mesh.
virtual void UniformRefinement2D();
/// Refine 3D mesh.
virtual void UniformRefinement3D();
private:
static void skip_comment_lines(std::istream &is, const char comment_char)
{
while (1)
{
is >> std::ws;
if (is.peek() != comment_char) { break; }
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
// Check for, and remove, a trailing '\r'.
static void filter_dos(std::string &line)
{
if (!line.empty() && *line.rbegin() == '\r')
{ line.resize(line.size()-1); }
}
static std::map<EntityType,std::string> init_type_names();
void LoadEntitySets(std::istream &input, EntityType t,
const std::string & header);
void PrintEntitySets(std::ostream &output, EntityType t,
const std::string & header) const;
void PrintEdgeSets(std::ostream &output) const;
void PrintFaceSets(std::ostream &output) const;
void PrintEntitySetInfo(std::ostream & output, EntityType t,
const std::string & ent_name) const;
void CopyEntitySets(const EntitySets & ent_sets, EntityType t);
void BuildEntitySets(NCMesh &ncmesh, EntityType t);
protected:
Mesh * mesh_;
Table * edge_vertex_;
Table * face_vertex_;
Table * face_edge_;
int NumOfVertices_;
int NumOfEdges_;
int NumOfElements_;
/** The node/edge/face/element indices needed by the finite element
space to look up DoFs. */
std::vector<std::vector<std::set<int> > > sets_;
/// Names of each entity set
std::vector<std::vector<std::string> > set_names_;
/// Indices of each entity set indexed by set name
std::vector<std::map<std::string, int> > set_index_by_name_;
};
class NCEntitySets
{
friend class EntitySets;
public:
NCEntitySets(const EntitySets & ent_sets, NCMesh &ncmesh);
NCEntitySets(const NCEntitySets & ncent_sets);
bool SetExists(EntitySets::EntityType t, unsigned int s) const;
bool SetExists(EntitySets::EntityType t, const std::string & s) const;
unsigned int GetNumSets(EntitySets::EntityType t) const;
static int GetEntitySize(EntitySets::EntityType t);
const std::string & GetSetName(EntitySets::EntityType t, int s) const;
unsigned int GetNumEntities(EntitySets::EntityType t, int s) const;
void GetEntityIndex(EntitySets::EntityType t, int s,
int i, Array<int> & inds) const;
int GetSetIndex(EntitySets::EntityType t,
const std::string & s) const;
unsigned int GetNumEntities(EntitySets::EntityType t,
const std::string & s) const;
void GetEntityIndex(EntitySets::EntityType t,
const std::string & s, int i,
Array<int> & inds) const;
inline std::vector<int> & operator()(EntitySets::EntityType t, int s)
{ return sets_[t][s]; }
inline const std::vector<int> & operator()(EntitySets::EntityType t,
int s) const
{ return sets_[t][s]; }
inline int & operator()(EntitySets::EntityType t, int s, int i)
{ return sets_[t][s][i]; }
inline int operator()(EntitySets::EntityType t, int s, int i) const
{ return sets_[t][s][i]; }
private:
void CopyNCEntitySets(const NCEntitySets & ncent_sets,
EntitySets::EntityType t);
protected:
NCMesh * ncmesh_;
/// The nodes defining the node/edge/face/element sets
std::vector<std::vector<std::vector<int> > > sets_;
/// Names of each entity set
std::vector<std::vector<std::string> > set_names_;
/// Indices of each entity set indexed by set name
std::vector<std::map<std::string, int> > set_index_by_name_;
/// Number of indices per entity
static const int entity_size_[4];
};
} // namespace mfem
#endif // MFEM_ENTITY_SETS
+5 -71
View File
@@ -1090,7 +1090,8 @@ FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo)
int fn = GetBdrFace(BdrElemNo);
// Check if the face is interior, shared, or non-conforming.
if (FaceIsTrueInterior(fn) || faces_info[fn].NCFace >= 0)
// if (FaceIsTrueInterior(fn) || faces_info[fn].NCFace >= 0)
if (faces_info[fn].NCFace >= 0)
{
return NULL;
}
@@ -1177,15 +1178,13 @@ void Mesh::Init()
own_nodes = 1;
NURBSext = NULL;
ncmesh = NULL;
ent_sets = NULL;
last_operation = Mesh::NONE;
}
void Mesh::InitTables()
{
el_to_edge =
el_to_face = el_to_el = bel_to_edge = face_edge =
face_vertex = edge_vertex = NULL;
el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
}
void Mesh::SetEmpty()
@@ -1207,7 +1206,6 @@ void Mesh::DestroyTables()
}
delete face_edge;
delete face_vertex;
delete edge_vertex;
}
@@ -1215,8 +1213,6 @@ void Mesh::DestroyPointers()
{
if (own_nodes) { delete Nodes; }
delete ent_sets;
delete ncmesh;
delete NURBSext;
@@ -3351,12 +3347,6 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
// Copy the edge-to-vertex Table, edge_vertex
edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
// Copy the face-to-vertex Table, edge_vertex
face_vertex = (mesh.face_vertex) ? new Table(*mesh.face_vertex) : NULL;
// Do not copy any of the coarse (c_*), fine (f_*) or fine/coarse (fc_*)
// data members.
// Copy the attributes and bdr_attributes
mesh.attributes.Copy(attributes);
mesh.bdr_attributes.Copy(bdr_attributes);
@@ -3407,9 +3397,6 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
Nodes = mesh.Nodes;
own_nodes = 0;
}
// Copy entity sets if present in the input mesh
ent_sets = (mesh.ent_sets) ? new EntitySets(*mesh.ent_sets) : NULL;
}
Mesh::Mesh(Mesh &&mesh) : Mesh()
@@ -5782,38 +5769,6 @@ Table *Mesh::GetEdgeVertexTable() const
return edge_vertex;
}
Table *Mesh::GetFaceVertexTable() const
{
if (face_vertex)
{
return face_vertex;
}
STable3D * faces_tbl = GetFacesTable();
int nfaces = faces_tbl->NumberOfElements();
face_vertex = new Table(nfaces, 4);
for (int i = 0; i < NumOfVertices; i++)
{
for (STable3D::RowIterator it(*faces_tbl, i); !it; ++it)
{
int j = it.Index();
face_vertex->Push(j, i);
face_vertex->Push(j, it.Column());
face_vertex->Push(j, it.Floor());
if ( it.Tier() > 0 )
{
face_vertex->Push(j, it.Tier());
}
}
}
face_vertex->Finalize();
delete faces_tbl;
return face_vertex;
}
Table *Mesh::GetVertexToElementTable()
{
int i, j, nv, *v;
@@ -6448,7 +6403,7 @@ void Mesh::GenerateNCFaceInfo()
}
}
STable3D *Mesh::GetFacesTable() const
STable3D *Mesh::GetFacesTable()
{
STable3D *faces_tbl = new STable3D(NumOfVertices);
for (int i = 0; i < NumOfElements; i++)
@@ -7703,11 +7658,6 @@ void Mesh::UniformRefinement2D_base(bool update_nodes)
NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
}
if ( ent_sets )
{
ent_sets->CopyMeshTables();
}
int quad_counter = 0;
for (int i = 0; i < NumOfElements; i++)
{
@@ -7843,11 +7793,6 @@ void Mesh::UniformRefinement2D_base(bool update_nodes)
if (update_nodes) { UpdateNodes(); }
if ( ent_sets )
{
ent_sets->UniformRefinement2D();
}
#ifdef MFEM_DEBUG
if (!Nodes || update_nodes)
{
@@ -7878,11 +7823,6 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
GetElementToFaceTable();
}
if ( ent_sets )
{
ent_sets->CopyMeshTables();
}
Array<int> f2qf_loc;
Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
f2qf.SetSize(0);
@@ -8209,6 +8149,7 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
}
AverageVertices(vv, 4, oface + f2qf[f[fi]]);
}
for (int ei = 0; ei < 9; ei++)
{
for (int k = 0; k < 2; k++)
@@ -8552,11 +8493,6 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
sequence++;
if (update_nodes) { UpdateNodes(); }
if (ent_sets)
{
ent_sets->UniformRefinement3D();
}
}
void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
@@ -9026,8 +8962,6 @@ void Mesh::Swap(Mesh& other, bool non_geometry)
mfem::Swap(geom_factors, other.geom_factors);
mfem::Swap(ent_sets, other.ent_sets);
#ifdef MFEM_USE_MEMALLOC
TetMemory.Swap(other.TetMemory);
#endif
+2 -11
View File
@@ -20,7 +20,6 @@
#include "vertex.hpp"
#include "vtk.hpp"
#include "ncmesh.hpp"
#include "entsets.hpp"
#include "../fem/eltrans.hpp"
#include "../fem/coefficient.hpp"
#include "../general/zstr.hpp"
@@ -55,11 +54,9 @@ class Mesh
#ifdef MFEM_USE_MPI
friend class ParMesh;
friend class ParNCMesh;
friend class ParEntitySets;
#endif
friend class NCMesh;
friend class NURBSExtension;
friend class EntitySets;
#ifdef MFEM_USE_ADIOS2
friend class adios2stream;
@@ -169,7 +166,6 @@ protected:
Array<int> be_to_face;
mutable Table *face_edge;
mutable Table *edge_vertex;
mutable Table *face_vertex;
IsoparametricTransformation Transformation, Transformation2;
IsoparametricTransformation BdrTransformation;
@@ -220,8 +216,6 @@ public:
Array<FaceGeometricFactors*>
face_geom_factors; ///< Optional face geometric factors.
EntitySets *ent_sets;
// Global parameter that can be used to control the removal of unused
// vertices performed when reading a mesh in MFEM format. The default value
// (true) is set in mesh_readers.cpp.
@@ -293,7 +287,7 @@ protected:
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert);
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert);
STable3D *GetFacesTable() const;
STable3D *GetFacesTable();
STable3D *GetElementToFaceTable(int ret_ftbl = 0);
/** Red refinement. Element with index i is refined. The default
@@ -1073,12 +1067,9 @@ public:
/// Returns the face-to-edge Table (3D)
Table *GetFaceEdgeTable() const;
/// Returns the edge-to-vertex Table (2D or 3D)
/// Returns the edge-to-vertex Table (3D)
Table *GetEdgeVertexTable() const;
/// Returns the face-to-vertex Table (2d or 3D)
Table *GetFaceVertexTable() const;
/// Return the indices and the orientations of all faces of element i.
void GetElementFaces(int i, Array<int> &faces, Array<int> &ori) const;
-8
View File
@@ -100,14 +100,6 @@ void Mesh::ReadMFEMMesh(std::istream &input, int version, int &curved)
curved = 1;
}
ent_sets = new EntitySets(*this);
ent_sets->Load(input);
if ( ent_sets->GetNumSets(EntitySets::FACE) > 0 && faces.Size() == 0 )
{
GetElementToFaceTable();
GenerateFaces();
}
// When visualizing solutions on non-conforming grids, PETSc
// may dump additional vertices
if (remove_unused_vertices) { RemoveUnusedVertices(); }
+4 -404
View File
@@ -185,10 +185,6 @@ NCMesh::NCMesh(const Mesh *mesh)
face->attribute = be->GetAttribute();
}
// Store entity set information if present in the Mesh
ncent_sets = (mesh->ent_sets) ?
new NCEntitySets(*mesh->ent_sets, *this) : NULL;
// copy top-level vertex coordinates (leave empty if the mesh is curved)
if (!mesh->Nodes)
{
@@ -220,10 +216,6 @@ NCMesh::NCMesh(const NCMesh &other)
other.free_element_ids.Copy(free_element_ids);
other.root_state.Copy(root_state);
other.coordinates.Copy(coordinates);
// Copy the entity set information
ncent_sets = (other.ncent_sets) ? new NCEntitySets(*other.ncent_sets) : NULL;
Update();
}
@@ -262,11 +254,8 @@ NCMesh::~NCMesh()
DeleteUnusedFaces(elemFaces);
}
}
// NOTE: in release mode, we just throw away all faces and nodes at once
#endif
delete ncent_sets;
}
NCMesh::Node::~Node()
@@ -2515,42 +2504,6 @@ void NCMesh::OnMeshUpdated(Mesh *mesh)
if (face->index < 0) { face->index = NFaces + (nghosts++); }
}
MFEM_ASSERT(nghosts == NGhostFaces, "");
if (ncent_sets)
{
std::cout << "NCMesh::OnMeshUpdated ncent_sets is non NULL" << std::endl;
if (!mesh->ent_sets)
{
std::cout << "NCMesh::OnMeshUpdated creating ent_sets from NCMesh" << std::endl;
mesh->ent_sets = new EntitySets(*mesh, *this);
std::cout << "NCMesh::OnMeshUpdated done creating ent_sets from NCMesh" <<
std::endl;
}
}
std::ostringstream ossN;
ossN << "node_on_mesh_updated.out";
std::ofstream ofsN(ossN.str().c_str());
ofsN << nodes.Size() << std::endl;
for (int i=0; i<nodes.Size(); i++)
{
ofsN << i
// << " " << nodes[i].vert_refc
// << " " << nodes[i].edge_refc
<< " " << nodes[i].HasVertex()
<< " " << nodes[i].HasEdge()
<< " " << nodes[i].vert_index
<< " " << nodes[i].edge_index
<< " " << nodes[i].p1
<< " " << nodes[i].p2
<< " " << nodes[i].next << std::endl;
}
ofsN.close();
NEdges = mesh->GetNEdges();
NFaces = mesh->GetNumFaces();
std::cout << "Leaving NCMesh::OnMeshUpdated" << std::endl;
}
@@ -3353,15 +3306,12 @@ const NCMesh::MeshId& NCMesh::NCList::LookUp(int index, int *type) const
void NCMesh::CollectEdgeVertices(int v0, int v1, Array<int> &indices)
{
int mid = nodes.FindId(v0, v1);
if (mid >= 0)
if (mid >= 0 && nodes[mid].HasVertex())
{
if (nodes[mid].HasVertex())
{
indices.Append(mid);
indices.Append(mid);
CollectEdgeVertices(v0, mid, indices);
CollectEdgeVertices(mid, v1, indices);
}
CollectEdgeVertices(v0, mid, indices);
CollectEdgeVertices(mid, v1, indices);
}
}
@@ -3423,78 +3373,6 @@ void NCMesh::CollectQuadFaceVertices(int v0, int v1, int v2, int v3,
}
}
void NCMesh::CollectElementVertices(int elem_id, Array<int> &indices)
{
Element &el = elements[elem_id];
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size())
{
CollectElementVertices(el.child[i], indices);
}
}
}
else
{
// This element has not been refined so add its vertices
for (int i=0; i<8; i++)
{
if (el.node[i] >= 0 && el.node[i] < nodes.Size())
{
indices.Append(el.node[i]);
}
}
}
}
void NCMesh::CollectElementEdges(int elem_id, Array<int> &indices)
{
Element &el = elements[elem_id];
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size())
{
CollectElementEdges(el.child[i], indices);
}
}
}
else
{
int* node = el.node;
GeomInfo& gi = GI[(int) el.geom];
for (int i = 0; i < gi.nv; i++)
{
if (nodes[node[i]].HasEdge())
{
indices.Append(node[i]);
}
}
for (int i = 0; i < gi.ne; i++)
{
const int* ev = gi.edges[i];
int index = nodes.FindId(node[ev[0]], node[ev[1]]);
if (index >= 0)
{
if (nodes[index].HasEdge())
{
indices.Append(index);
}
}
}
}
}
void NCMesh::BuildElementToVertexTable()
{
int nrows = leaf_elements.Size();
@@ -4996,107 +4874,6 @@ int NCMesh::GetElementDepth(int i) const
return depth;
}
void NCMesh::GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edges)
{
std::cout << "entering NCMesh::GetRefinedEdges "
<<"searching for edge with vertices: " << vn0 << " and " << vn1
<< std::endl;
int mid = nodes.FindId(vn0, vn1);
if (mid < 0) { return; }
Node &nd = nodes[mid];
// if ( nd.edge_index < 0 ) { return; }
// edges.Append(nd.edge_index);
if ( nd.HasEdge() )
{
std::cout << " found node " << mid << std::endl;
edges.Append(mid);
}
GetRefinedEdges(vn0, mid, edges);
GetRefinedEdges(mid, vn1, edges);
}
void NCMesh::GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids)
{
// Face* fa = faces.Find(vn0, vn1, vn2, vn3);
int face = faces.FindId(vn0, vn1, vn2, vn3);
/*
if (fa)
{
if ( fa->index >= 0 )
{
face_ids.Append(fa->index);
}
return;
}
*/
if (face>=0)
{
if ( faces[face].index >= 0 )
{
face_ids.Append(face);
}
return;
}
// we need to recurse deeper
int mid[4];
int split = QuadFaceSplitType(vn0, vn1, vn2, vn3, mid);
if (split == 1) // "X" split face
{
GetRefinedFaces(vn0, mid[0], mid[2], vn3, face_ids);
GetRefinedFaces(mid[0], vn1, vn2, mid[2], face_ids);
}
else if (split == 2) // "Y" split face
{
GetRefinedFaces(vn0, vn1, mid[1], mid[3], face_ids);
GetRefinedFaces(mid[3], mid[1], vn2, vn3, face_ids);
}
}
void NCMesh::GetRefinedElements(int elem_id, BlockArray<int> & elem_ids)
{
// std::cout << "entering NCMesh::GetRefinedElements searching for element id: "
// << elem_id << std::endl;
Element &el = elements[elem_id];
/*
if (el.index >= 0 && el.rank >= 0)
{
elem_ids.Append(el.index);
return;
}
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size() )
{
GetRefinedElements(el.child[i], elem_ids);
}
}
*/
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size() )
{
GetRefinedElements(el.child[i], elem_ids);
}
}
}
else
{
// This element has not been refined so add it
elem_ids.Append(elem_id);
}
}
int NCMesh::GetElementSizeReduction(int i) const
{
int elem = leaf_elements[i];
@@ -5216,183 +4993,6 @@ void NCMesh::GetBoundaryClosure(const Array<int> &bdr_attr_is_ess,
bdr_edges.Unique();
}
void NCMesh::GetEntitySetClosure(EntitySets::EntityType type,
int set_index,
Array<int> &es_vertices,
Array<int> &es_edges,
Array<int> &es_faces)
{
es_vertices.SetSize(0);
es_edges.SetSize(0);
es_faces.SetSize(0);
MFEM_VERIFY(ncent_sets != NULL, "NCMesh object contains no "
"entity set information");
if (!ncent_sets->SetExists(type, set_index))
{
std::ostringstream oss; oss << "Entity set of type \""
<< EntitySets::GetTypeName(type)
<< "\" and index " << set_index
<< " was not found.";
MFEM_VERIFY(false, oss.str().c_str());
}
int ni = ncent_sets->GetNumEntities(type ,set_index);
Array<int> inds;
Array<int> coll_inds;
switch (type)
{
case EntitySets::VERTEX:
{
/// Do nothing because vertices cannot hide
}
break;
case EntitySets::EDGE:
{
for (int i=0; i<ni; i++)
{
ncent_sets->GetEntityIndex(type, set_index, i, inds);
// collect vertices
inds.Copy(coll_inds);
this->CollectEdgeVertices(inds[0], inds[1], coll_inds);
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].vert_index;
if (index >= 0)
{
es_vertices.Append(index);
}
}
}
}
break;
case EntitySets::FACE:
{
for (int i=0; i<ni; i++)
{
ncent_sets->GetEntityIndex(type, set_index, i, inds);
// collect vertices
inds.Copy(coll_inds);
if (inds.Size() == 4)
{
this->CollectQuadFaceVertices(inds[0], inds[1], inds[2], inds[3],
coll_inds);
}
else
{
this->CollectTriFaceVertices(inds[0], inds[1], inds[2],
coll_inds);
}
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].vert_index;
if (index >= 0)
{
es_vertices.Append(index);
}
}
}
}
break;
case EntitySets::ELEMENT:
{
for (int i=0; i<ni; i++)
{
int elem_id = (*ncent_sets)(type, set_index, i);
std::cout << "examining element " << elem_id << std::endl;
// collect vertices
coll_inds.SetSize(0);
this->CollectElementVertices(elem_id, coll_inds);
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].vert_index;
if (index >= 0)
{
es_vertices.Append(index);
}
}
// collect edges
coll_inds.SetSize(0);
this->CollectElementEdges(elem_id, coll_inds);
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].edge_index;
if (index >= 0)
{
es_edges.Append(index);
}
}
}
}
break;
default:
MFEM_ABORT("GetEnitySetClosure - Unknown entity set type: \""
<< EntitySets::GetTypeName(type) << "\"");
}
/*
if (Dim == 3)
{
GetFaceList(); // make sure 'boundary_faces' is up to date
for (int i = 0; i < boundary_faces.Size(); i++)
{
int face = boundary_faces[i];
if (bdr_attr_is_ess[faces[face].attribute - 1])
{
int node[4];
FindFaceNodes(face, node);
for (int j = 0; j < 4; j++)
{
bdr_vertices.Append(nodes[node[j]].vert_index);
int enode = nodes.FindId(node[j], node[(j+1) % 4]);
MFEM_ASSERT(enode >= 0 && nodes[enode].HasEdge(), "Edge not found.");
bdr_edges.Append(nodes[enode].edge_index);
while ((enode = GetEdgeMaster(enode)) >= 0)
{
// append master edges that may not be accessible from any
// boundary element, this happens in 3D in re-entrant corners
bdr_edges.Append(nodes[enode].edge_index);
}
}
}
}
}
else if (Dim == 2)
{
GetEdgeList(); // make sure 'boundary_faces' is up to date
for (int i = 0; i < boundary_faces.Size(); i++)
{
int face = boundary_faces[i];
Face &fc = faces[face];
if (bdr_attr_is_ess[fc.attribute - 1])
{
bdr_vertices.Append(nodes[fc.p1].vert_index);
bdr_vertices.Append(nodes[fc.p3].vert_index);
}
}
}
*/
es_vertices.Sort();
es_vertices.Unique();
es_edges.Sort();
es_edges.Unique();
es_faces.Sort();
es_faces.Unique();
}
static int max4(int a, int b, int c, int d)
{
return std::max(std::max(a, b), std::max(c, d));
-35
View File
@@ -19,7 +19,6 @@
#include "../linalg/densemat.hpp"
#include "element.hpp"
#include "vertex.hpp"
#include "entsets.hpp"
#include "../fem/geom.hpp"
#include <vector>
@@ -118,9 +117,6 @@ struct MatrixMap; // for internal use
*/
class NCMesh
{
friend class EntitySets;
friend class NCEntitySets;
public:
//// Initialize with elements from an existing 'mesh'.
explicit NCMesh(const Mesh *mesh);
@@ -347,16 +343,6 @@ public:
Array<int> &bdr_vertices,
Array<int> &bdr_edges);
/** Get a list of vertices (2D/3D), edges (2D/3D), and faces (3D) that
coincide with members of the specified entity set. In 3D this function
also reveals "hidden" edges or faces. In parallel it helps identifying
vertices/edges/faces affected by non-local entities. */
virtual void GetEntitySetClosure(EntitySets::EntityType t,
int set_index,
Array<int> &es_vertices,
Array<int> &es_edges,
Array<int> &es_faces);
/// Return element geometry type. @a index is the Mesh element number.
Geometry::Type GetElementGeometry(int index) const
{ return elements[leaf_elements[index]].Geom(); }
@@ -371,19 +357,6 @@ public:
/// Return the distance of leaf 'i' from the root.
int GetElementDepth(int i) const;
/** Collect edge indices of all refined edges which are children of
the coarse edge defined by the given vertices. */
void GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edge_ids);
/** Collect face indices of all refined faces which are children of
the coarse face defined by the given vertices. */
void GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids);
/** Collect element indices of all refined elements which are children of
the coarse element defined by the given element index. */
void GetRefinedElements(int elem_id, BlockArray<int> & elem_ids);
/** Return the size reduction compared to the root element (ignoring local
stretching and curvature). */
int GetElementSizeReduction(int i) const;
@@ -528,7 +501,6 @@ protected: // implementation
Array<double> coordinates;
// secondary data
/** Apart from the primary data structure, which is the element/node/face
@@ -558,8 +530,6 @@ protected: // implementation
Table element_vertex; ///< leaf-element to vertex table, see FindSetNeighbors
// Node/edge/Face/Element sets defined on the coarse mesh
NCEntitySets * ncent_sets;
void UpdateLeafElements();
void UpdateVertices(); ///< update Vertex::index and vertex_nodeId
@@ -741,10 +711,6 @@ protected: // implementation
void CollectTriFaceVertices(int v0, int v1, int v2, Array<int> &indices);
void CollectQuadFaceVertices(int v0, int v1, int v2, int v3,
Array<int> &indices);
void CollectElementVertices(int elem_id, Array<int> &indices);
void CollectElementEdges(int elem_id, Array<int> &indices);
void BuildElementToVertexTable();
void UpdateElementToVertexTable()
@@ -960,7 +926,6 @@ public:
#endif
friend class ParNCMesh; // for ParNCMesh::ElementSet
friend class ParNCEntitySets;
friend struct MatrixMap;
friend struct PointMatrixHash;
};
-392
View File
@@ -1,392 +0,0 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../config/config.hpp"
#ifdef MFEM_USE_MPI
#include "pentsets.hpp"
#include "pmesh.hpp"
using namespace std;
namespace mfem
{
ParEntitySets::ParEntitySets(const ParEntitySets & ent_sets)
: EntitySets(ent_sets),
pmesh_(ent_sets.GetParMesh())
{
MPI_Comm_size(pmesh_->GetComm(), &NRanks_);
MPI_Comm_rank(pmesh_->GetComm(), &MyRank_);
cout << MyRank_ << ": Entering ParEntitySets copy c'tor" << endl;
cout << MyRank_ << ": Leaving ParEntitySets copy c'tor" << endl;
}
ParEntitySets::ParEntitySets(ParMesh & pmesh, const EntitySets & ent_sets,
int * partitioning,
const Array<int> & vert_global_local)
: EntitySets(ent_sets),
pmesh_(&pmesh)
{
// The copy constructor for EntitySets will initialize this object's
// data with the correct set names, and numbers of sets. However,
// the set entries themselves will need to be recomputed based on
// local numberings and the paritioning.
//
// The EntitySets object will be a copy of the serial object. This
// constructor will have to prune and renumber the data. Once this
// is done the mesh pointer stored in the EntitySets object can be
// replaced with the local portion of the parallel mesh.
MPI_Comm MyComm = pmesh_->GetComm();
MPI_Comm_size(MyComm, &NRanks_);
MPI_Comm_rank(MyComm, &MyRank_);
cout << MyRank_ << ": Entering ParEntitySets(ParMesh, EntitySets, ...) c'tor" <<
endl;
int nelem = mesh_->GetNE();
DSTable v_to_v(vert_global_local.Size());
pmesh_->GetVertexToVertexTable(v_to_v);
STable3D * faces_tbl = NULL;
const Table * serial_edge_vertex = NULL;
const Table * serial_face_vertex = NULL;
if ( ent_sets.GetNumSets(EDGE) > 0 )
{
serial_edge_vertex = ent_sets.GetEdgeVertexTable();
}
if ( ent_sets.GetNumSets(FACE) > 0 )
{
serial_face_vertex = ent_sets.GetFaceVertexTable();
faces_tbl = pmesh_->GetFacesTable();
}
Array<int> elem_global_local(nelem);
elem_global_local = -1;
int elem_counter = 0;
for (int i=0; i<nelem; i++)
{
if ( partitioning[i] == MyRank_ )
{
elem_global_local[i] = elem_counter;
elem_counter++;
}
}
EntityType t;
unsigned int ns;
t = VERTEX;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
int v0 = vert_global_local[*it];
if ( v0 >= 0 )
{
sets_[t][s].insert(v0);
}
}
}
if ( pmesh_->Dimension() > 1 )
{
t = EDGE;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
int old_edge = *it;
const int *v = serial_edge_vertex->GetRow(old_edge);
int v0 = vert_global_local[v[0]];
int v1 = vert_global_local[v[1]];
if ( v0 >= 0 && v1 >= 0 )
{
int new_edge = v_to_v(v0,v1);
if ( new_edge >= 0 )
{
sets_[t][s].insert(new_edge);
}
}
}
}
}
if ( pmesh_->Dimension() > 2 )
{
Array<int> v;
t = FACE;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
int old_face = *it;
int numv = serial_face_vertex->RowSize(old_face);
const int *v = serial_face_vertex->GetRow(old_face);
if ( vert_global_local[v[0]] >= 0 &&
vert_global_local[v[1]] >= 0 &&
vert_global_local[v[2]] >= 0 )
{
int new_face = -1;
if ( numv == 3 )
{
new_face = (*faces_tbl)(vert_global_local[v[0]],
vert_global_local[v[1]],
vert_global_local[v[2]]);
}
else
{
new_face = (*faces_tbl)(vert_global_local[v[0]],
vert_global_local[v[1]],
vert_global_local[v[2]],
vert_global_local[v[3]]);
}
if ( new_face >= 0 )
{
sets_[t][s].insert(new_face);
}
}
}
}
delete faces_tbl;
}
t = ELEMENT;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
if ( partitioning[*it] == MyRank_ )
{
sets_[t][s].insert(elem_global_local[*it]);
}
}
}
this->mesh_ = (Mesh*)this->pmesh_;
this->CopyMeshTables();
cout << MyRank_ << ": Leaving ParEntitySets(ParMesh, EntitySets, ...) c'tor" <<
endl;
}
ParEntitySets::ParEntitySets(ParMesh & pmesh, ParNCMesh &pncmesh)
: EntitySets(pmesh),
pmesh_(&pmesh)
{
MPI_Comm MyComm = pmesh_->GetComm();
MPI_Comm_size(MyComm, &NRanks_);
MPI_Comm_rank(MyComm, &MyRank_);
cout << MyRank_ << ": Entering ParEntitySets(ParMesh, ParNCMesh) c'tor" << endl;
this->BuildEntitySets(pncmesh, VERTEX);
this->BuildEntitySets(pncmesh, EDGE);
this->BuildEntitySets(pncmesh, FACE);
this->BuildEntitySets(pncmesh, ELEMENT);
cout << MyRank_ << ": Leaving ParEntitySets(ParMesh, ParNCMesh) c'tor" << endl;
}
ParEntitySets::~ParEntitySets()
{
cout << MyRank_ << ": Entering ParEntitySets d'tor" << endl;
cout << MyRank_ << ": Leaving ParEntitySets d'tor" << endl;
}
void
ParEntitySets::PrintSetInfo(std::ostream & output) const
{
if ( MyRank_ == 0 &&
( GetNumSets(VERTEX) > 0 || GetNumSets(EDGE) > 0 ||
GetNumSets(FACE) > 0 || GetNumSets(ELEMENT) > 0 ) )
{
output << "\nMFEM Parallel Entity Sets:\n";
}
this->PrintEntitySetInfo(output, VERTEX, "Vertex");
this->PrintEntitySetInfo(output, EDGE, "Edge");
this->PrintEntitySetInfo(output, FACE, "Face");
this->PrintEntitySetInfo(output, ELEMENT, "Element");
}
void
ParEntitySets::PrintEntitySetInfo(std::ostream & output, EntityType t,
const string & ent_name) const
{
if ( sets_[t].size() > 0 )
{
if ( MyRank_ == 0 )
{
output << " " << ent_name
<< " Sets (Index, Set Name, Global Size):\n";
}
for (unsigned int s=0; s<sets_[t].size(); s++)
{
int loc_size = sets_[t][s].size();
int glb_size = -1;
MPI_Reduce(&loc_size, &glb_size, 1, MPI_INT, MPI_SUM, 0,
pmesh_->GetComm());
if ( MyRank_ == 0 )
{
output << '\t' << s
<< '\t' << set_names_[t][s]
<< '\t' << glb_size
<< '\n';
}
}
if ( MyRank_ == 0 )
{
output << '\n';
}
}
}
void
ParEntitySets::BuildEntitySets(ParNCMesh &pncmesh, EntityType t)
{
cout << MyRank_ << ": BuildEntitySets for type " << GetTypeName(t) << endl;
int es = pncmesh.pncent_sets->GetEntitySize(t);
unsigned int ns = pncmesh.pncent_sets->GetNumSets(t);
cout << MyRank_ << ": num sets " << ns << endl;
Array<int> inds(es);
sets_[t].resize(ns);
set_names_[t].resize(ns);
for (unsigned int s=0; s<ns; s++)
{
int ni = pncmesh.pncent_sets->GetNumEntities(t, s);
set_names_[t][s] = pncmesh.pncent_sets->GetSetName(t, s);
set_index_by_name_[t][set_names_[t][s]] = s;
switch (t)
{
case VERTEX:
for (int i=0; i<ni; i++)
{
int node = (*pncmesh.pncent_sets)(t, s, i);
int index = pncmesh.nodes[node].vert_index;
if (!pncmesh.IsGhost(0,index))
{
sets_[t][s].insert(index);
}
}
break;
case EDGE:
for (int i=0; i<ni; i++)
{
pncmesh.pncent_sets->GetEntityIndex(t, s, i, inds);
BlockArray<int> ind_coll;
pncmesh.GetRefinedEdges(inds[0], inds[1],
ind_coll);
for (int j=0; j<ind_coll.Size(); j++)
{
int edge = ind_coll[j];
int index = pncmesh.nodes[edge].edge_index;
if (index >= 0 && !pncmesh.IsGhost(1, index))
{
sets_[t][s].insert(index);
}
}
}
break;
case FACE:
for (int i=0; i<ni; i++)
{
pncmesh.pncent_sets->GetEntityIndex(t, s, i, inds);
BlockArray<int> ind_coll;
pncmesh.GetRefinedFaces(inds[0], inds[1], inds[2], inds[3],
ind_coll);
for (int j=0; j<ind_coll.Size(); j++)
{
int face = ind_coll[j];
int index = pncmesh.faces[face].index;
if (index >= 0 && !pncmesh.IsGhost(2, index))
{
sets_[t][s].insert(index);
}
}
}
break;
case ELEMENT:
for (int i=0; i<ni; i++)
{
int elem = (*pncmesh.pncent_sets)(t, s, i);
BlockArray<int> ind_coll;
pncmesh.GetRefinedElements(elem, ind_coll);
for (int j=0; j<ind_coll.Size(); j++)
{
sets_[t][s].insert(pncmesh.elements[ind_coll[j]].index);
}
}
break;
default:
MFEM_ABORT("Unknown entity set type: \"" << GetTypeName(t) << "\"");
}
cout << MyRank_ << ": " << set_names_[t][s] << " " << s << " set size " <<
sets_[t][s].size() << "{";
for (set<int>::iterator it=sets_[t][s].begin(); it!=sets_[t][s].end(); it++)
{
cout << " " << *it;
}
cout << "}" << endl;
}
map<string,int>::iterator it;
cout << MyRank_ << ": set index by name ";
for (it=set_index_by_name_[t].begin(); it != set_index_by_name_[t].end(); it++)
{
cout << " " << it->first << "->" << it->second;
}
cout << endl;
cout << MyRank_ << ": done BuildEntitySets for type " << GetTypeName(t) << endl;
}
ParNCEntitySets::ParNCEntitySets(MPI_Comm comm, const NCMesh &ncmesh)
: NCEntitySets(*ncmesh.ncent_sets)
{
MyComm_ = comm;
MPI_Comm_size(MyComm_, &NRanks_);
MPI_Comm_rank(MyComm_, &MyRank_);
if ( MyRank_ == 0 )
{
cout << "Entering ParNCEntitySets(NCMesh) c'tor" << endl;
}
if ( MyRank_ == 0 )
{
cout << "Leaving ParNCEntitySets(NCMesh) c'tor" << endl;
}
}
} // namespace mfem
#endif // MFEM_USE_MPI
-74
View File
@@ -1,74 +0,0 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_PAR_ENTITY_SETS
#define MFEM_PAR_ENTITY_SETS
#include "../config/config.hpp"
#ifdef MFEM_USE_MPI
#include "entsets.hpp"
#include "../general/communication.hpp"
namespace mfem
{
class ParMesh;
class ParNCMesh;
class ParEntitySets : public EntitySets
{
friend class ParMesh;
public:
ParEntitySets(const ParEntitySets & ent_sets);
ParEntitySets(ParMesh & _mesh, const EntitySets & ent_sets, int * part,
const Array<int> & vert_global_local);
ParEntitySets(ParMesh & mesh, ParNCMesh &ncmesh);
virtual ~ParEntitySets();
virtual void PrintSetInfo(std::ostream &output) const;
inline ParMesh *GetParMesh() const { return pmesh_; }
private:
void PrintEntitySetInfo(std::ostream & output, EntityType t,
const std::string & ent_name) const;
void BuildEntitySets(ParNCMesh &pncmesh, EntityType t);
ParMesh * pmesh_;
int NRanks_;
int MyRank_;
};
class ParNCEntitySets : public NCEntitySets
{
public:
// ParNCEntitySets(MPI_Comm comm, EntitySets &ent_sets, NCMesh &ncmesh);
ParNCEntitySets(MPI_Comm comm, const NCMesh &ncmesh);
// ParNCEntitySets(const ParMesh & pmesh, const ParNCMesh &pncmesh);
// ParNCEntitySets(const ParNCEntitySets & pncent_sets);
private:
MPI_Comm MyComm_;
int NRanks_;
int MyRank_;
};
} // namespace mfem
#endif // MFEM_USE_MPI
#endif // MFEM_PAR_ENTITY_SETS
+3 -37
View File
@@ -91,10 +91,6 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes)
*Nodes = *pmesh.Nodes;
own_nodes = 1;
}
// Copy entity sets if present in the input mesh
ent_sets = pent_sets =
(pmesh.pent_sets) ? new ParEntitySets(*pmesh.pent_sets) : NULL;
}
ParMesh::ParMesh(ParMesh &&mesh) : ParMesh()
@@ -114,7 +110,6 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
, glob_elem_offset(-1)
, glob_offset_sequence(-1)
, gtopo(comm)
, pent_sets(NULL)
{
int *partitioning = NULL;
Array<bool> activeBdrElem;
@@ -123,8 +118,6 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
MPI_Comm_size(MyComm, &NRanks);
MPI_Comm_rank(MyComm, &MyRank);
Array<int> vert_global_local;
if (mesh.Nonconforming())
{
if (partitioning_)
@@ -155,10 +148,6 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
mesh.bdr_attributes.Copy(bdr_attributes);
GenerateNCFaceInfo();
// if (mesh.ent_sets)
// NumOfVertices = BuildLocalVertices(mesh, partitioning,
// vert_global_local);
}
else // mesh.Conforming()
{
@@ -179,6 +168,7 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
// re-enumerate the partitions to better map to actual processor
// interconnect topology !?
Array<int> vert_global_local;
NumOfVertices = BuildLocalVertices(mesh, partitioning, vert_global_local);
NumOfElements = BuildLocalElements(mesh, partitioning, vert_global_local);
@@ -250,12 +240,6 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
SetMeshGen();
meshgen = mesh.meshgen; // copy the global 'meshgen'
ent_sets = pent_sets =
(mesh.ent_sets) ? new ParEntitySets(*this, *mesh.ent_sets,
partitioning,
vert_global_local)
: NULL;
}
if (mesh.NURBSext)
@@ -305,12 +289,7 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
// for compatibility (e.g., Mesh::GetVertex())
SetVerticesFromNodes(Nodes);
}
/*
ent_sets = pent_sets =
(mesh.ent_sets) ? new ParEntitySets(*this, *mesh.ent_sets,
partitioning,
vert_global_local) : NULL;
*/
if (partitioning != partitioning_)
{
delete [] partitioning;
@@ -880,7 +859,6 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh)
, glob_offset_sequence(-1)
, gtopo(MyComm)
, pncmesh(NULL)
, pent_sets(NULL)
{
Mesh::InitFromNCMesh(pncmesh);
ReduceMeshGen();
@@ -947,7 +925,6 @@ ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine)
, glob_elem_offset(-1)
, glob_offset_sequence(-1)
, gtopo(comm)
, pent_sets(NULL)
{
MyComm = comm;
MPI_Comm_size(MyComm, &NRanks);
@@ -1162,8 +1139,7 @@ void ParMesh::MakeRefined_(ParMesh &orig_mesh, int ref_factor, int ref_type)
gtopo = orig_mesh.gtopo;
have_face_nbr_data = false;
pncmesh = NULL;
pent_sets = NULL;
Array<int> ref_factors(orig_mesh.GetNE());
ref_factors = ref_factor;
Mesh::MakeRefined_(orig_mesh, ref_factors, ref_type);
@@ -3792,13 +3768,6 @@ void ParMesh::NonconformingRefinement(const Array<Refinement> &refinements,
// and this mesh will be the new fine mesh
Mesh::Swap(*pmesh2, false);
// swap entity set information if present
mfem::Swap(pmesh2->pent_sets, this->pent_sets);
if (this->pent_sets)
{
this->pent_sets->pmesh_ = this;
}
delete pmesh2; // NOTE: old face neighbors destroyed here
pncmesh->GetConformingSharedStructures(*this);
@@ -6202,9 +6171,6 @@ void ParMesh::Destroy()
delete pncmesh;
ncmesh = pncmesh = NULL;
delete pent_sets;
ent_sets = pent_sets = NULL;
DeleteFaceNbrData();
for (int i = 0; i < shared_edges.Size(); i++)
-2
View File
@@ -20,7 +20,6 @@
#include "../general/globals.hpp"
#include "mesh.hpp"
#include "pncmesh.hpp"
#include "pentsets.hpp"
#include <iostream>
namespace mfem
@@ -321,7 +320,6 @@ public:
Table send_face_nbr_vertices;
ParNCMesh* pncmesh;
ParEntitySets* pent_sets;
int GetNGroups() const { return gtopo.NGroups(); }
-508
View File
@@ -20,8 +20,6 @@
#include <map>
#include <climits> // INT_MIN, INT_MAX
#include <fstream> // MLS Debugging
namespace mfem
{
@@ -29,7 +27,6 @@ using namespace bin_io;
ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh, int *part)
: NCMesh(ncmesh)
, pncent_sets(NULL)
{
MyComm = comm;
MPI_Comm_size(MyComm, &NRanks);
@@ -44,40 +41,6 @@ ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh, int *part)
Update();
std::ostringstream oss; oss << "elements_" << MyRank << ".out";
std::ofstream ofs(oss.str().c_str());
for (int i=0; i<elements.Size(); i++)
{
ofs << i
<< '\t' << elements[i].index
<< '\t' << elements[i].rank
<< '\t' << elements[i].attribute
<< '\t' << elements[i].parent;
if ( elements[i].ref_type == 0 )
{
ofs << " nodes {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].node[j];
}
ofs << "}";
}
else
{
ofs << " children {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].child[j];
}
ofs << "}";
}
ofs << std::endl;
}
ncent_sets = pncent_sets =
(ncmesh.ncent_sets) ? new ParNCEntitySets(comm, ncmesh) : NULL;
// note that at this point all processors still have all the leaf elements;
// we however may now start pruning the refinement tree to get rid of
// branches that only contain someone else's leaves (see Prune())
@@ -122,9 +85,6 @@ ParNCMesh::ParNCMesh(const ParNCMesh &other)
ParNCMesh::~ParNCMesh()
{
ClearAuxPM();
delete pncent_sets;
ncent_sets = pncent_sets = NULL;
}
void ParNCMesh::Update()
@@ -155,386 +115,6 @@ void ParNCMesh::Update()
boundary_layer.SetSize(0);
}
/*
void ParNCMesh::AssignLeafIndices()
{
// This is an override of NCMesh::AssignLeafIndices(). The difference is
// that we shift all elements we own to the beginning of the array
// 'leaf_elements' and assign all ghost elements indices >= NElements.
// Also note that the ordering of ghosts and non-ghosts is preserved here,
// which is important for ParNCMesh::GetFaceNeighbors.
// We store the original leaf ordering in 'leaf_glob_order'. This is later
// used (and deleted) in GetConformingSharedStructures
NCMesh::AssignLeafIndices(); // original numbering, for 'leaf_glob_order'
int nleafs = leaf_elements.Size();
Array<int> ghosts;
ghosts.Reserve(nleafs);
NElements = 0;
for (int i = 0; i < nleafs; i++)
{
int elem = leaf_elements[i];
if (elements[elem].rank == MyRank)
{
leaf_elements[NElements++] = elem;
}
else
{
ghosts.Append(elem);
}
}
NGhostElements = ghosts.Size();
leaf_elements.SetSize(NElements);
leaf_elements.Append(ghosts);
// store original (globally consistent) numbering in 'leaf_glob_order'
leaf_glob_order.SetSize(nleafs);
for (int i = 0; i < nleafs; i++)
{
leaf_glob_order[i] = elements[leaf_elements[i]].index;
}
// new numbering with ghost shifted to the back
NCMesh::AssignLeafIndices();
}
void ParNCMesh::UpdateVertices()
{
// This is an override of NCMesh::UpdateVertices. This version first
// assigns vert_index to vertices of elements of our rank. Only these
// vertices then make it to the Mesh in NCMesh::GetMeshComponents.
// The remaining (ghost) vertices are assigned indices greater or equal to
// Mesh::GetNV().
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasVertex()) { node->vert_index = -1; }
}
NVertices = 0;
for (int i = 0; i < leaf_elements.Size(); i++)
{
Element &el = elements[leaf_elements[i]];
if (el.rank == MyRank)
{
for (int j = 0; j < GI[el.Geom()].nv; j++)
{
int &vindex = nodes[el.node[j]].vert_index;
if (vindex < 0) { vindex = NVertices++; }
}
}
}
vertex_nodeId.SetSize(NVertices);
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasVertex() && node->vert_index >= 0)
{
vertex_nodeId[node->vert_index] = node.index();
}
}
NGhostVertices = 0;
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasVertex() && node->vert_index < 0)
{
node->vert_index = NVertices + (NGhostVertices++);
}
}
}
void ParNCMesh::OnMeshUpdated(Mesh *mesh)
{
std::cout << MyRank << ": Entering ParNCMesh::OnMeshUpdated" << std::endl;
// This is an override (or extension of) NCMesh::OnMeshUpdated().
// In addition to getting edge/face indices from 'mesh', we also
// assign indices to ghost edges/faces that don't exist in the 'mesh'.
// clear edge_index and Face::index
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasEdge()) { node->edge_index = -1; }
}
for (face_iterator face = faces.begin(); face != faces.end(); ++face)
{
face->index = -1;
}
// go assign existing edge/face indices
NCMesh::OnMeshUpdated(mesh);
std::cout << MyRank << ": NVertices = " << NVertices << std::endl;
std::ostringstream ossN;
ossN << "node_on_mesh_updated_" << MyRank << ".out";
std::ofstream ofsN(ossN.str().c_str());
ofsN << nodes.Size() << std::endl;
for (int i=0; i<nodes.Size(); i++)
{
ofsN << i
// << " " << nodes[i].vert_refc
// << " " << nodes[i].edge_refc
<< " " << nodes[i].HasVertex()
<< " " << nodes[i].HasEdge()
<< " " << nodes[i].vert_index
<< " " << nodes[i].edge_index
<< " " << nodes[i].p1
<< " " << nodes[i].p2
<< " " << nodes[i].next << std::endl;
}
ofsN.close();
// count ghost edges and assign their indices
NEdges = mesh->GetNEdges();
NGhostEdges = 0;
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasEdge() && node->edge_index < 0)
{
node->edge_index = NEdges + (NGhostEdges++);
}
}
// count ghost faces
NFaces = mesh->GetNumFaces();
NGhostFaces = 0;
for (face_iterator face = faces.begin(); face != faces.end(); ++face)
{
if (face->index < 0) { NGhostFaces++; }
}
if (Dim == 2)
{
// in 2D we have fake faces because of DG
MFEM_ASSERT(NFaces == NEdges, "");
MFEM_ASSERT(NGhostFaces == NGhostEdges, "");
}
// resize face_geom (default_geom is for slave faces beyond the ghost layer)
Geometry::Type default_geom = Geometry::SQUARE;
face_geom.SetSize(NFaces + NGhostFaces, default_geom);
// update 'face_geom' for ghost faces, assign ghost face indices
int nghosts = 0;
for (int i = 0; i < NGhostElements; i++)
{
Element &el = elements[leaf_elements[NElements + i]]; // ghost element
GeomInfo &gi = GI[el.Geom()];
for (int j = 0; j < gi.nf; j++)
{
const int *fv = gi.faces[j];
Face* face = faces.Find(el.node[fv[0]], el.node[fv[1]],
el.node[fv[2]], el.node[fv[3]]);
MFEM_ASSERT(face, "face not found!");
if (face->index < 0)
{
face->index = NFaces + (nghosts++);
// store the face geometry
static const Geometry::Type types[5] =
{
Geometry::INVALID, Geometry::INVALID,
Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::SQUARE
};
face_geom[face->index] = types[gi.nfv[j]];
}
}
}
// assign valid indices also to faces beyond the ghost layer
for (face_iterator face = faces.begin(); face != faces.end(); ++face)
{
if (face->index < 0) { face->index = NFaces + (nghosts++); }
}
MFEM_ASSERT(nghosts == NGhostFaces, "");
{
/// Debugging output
std::ostringstream oss; oss << "elements_on_mesh_updated_"
<< MyRank << ".out";
std::ofstream ofs(oss.str().c_str());
for (int i=0; i<elements.Size(); i++)
{
ofs << i
<< '\t' << elements[i].index
<< '\t' << elements[i].rank
<< '\t' << elements[i].attribute
<< '\t' << elements[i].parent;
if ( elements[i].ref_type == 0 )
{
ofs << " nodes {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].node[j];
}
ofs << "}";
}
else
{
ofs << " children {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].child[j];
}
ofs << "}";
}
ofs << std::endl;
}
if (pncent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated pncent_sets is non NULL" << std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated pncent_sets is NULL" << std::endl;
}
if (ncent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated ncent_sets is non NULL" << std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated ncent_sets is NULL" << std::endl;
}
if (mesh->ent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated mesh->ent_sets is non NULL" << std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated mesh->ent_sets is NULL" << std::endl;
}
ParMesh * pmesh = dynamic_cast<ParMesh*>(mesh);
if (pmesh)
{
std::cout << "dynamic cast succeeded: mesh is a ParMesh" << std::endl;
if (pmesh->pent_sets != NULL)
{
std::cout << "ParNCMesh::OnMeshUpdated deleting ParEntitySets object in ParMesh"
<< std::endl;
delete pmesh->pent_sets;
}
else if (pmesh->ent_sets != NULL)
{
std::cout << "ParNCMesh::OnMeshUpdated deleting EntitySets object in ParMesh" <<
std::endl;
delete pmesh->ent_sets;
}
std::cout << "ParNCMesh::OnMeshUpdated creating ParEntitySets object in ParMesh"
<< std::endl;
pmesh->ent_sets = pmesh->pent_sets =
(pncent_sets) ? new ParEntitySets(*pmesh, *this): NULL;
*/
/*
if (pmesh->ent_sets)
{
std::cout << MyRank << ": ParNCMesh::OnMeshUpdated pmesh->ent_sets is non NULL" << std::endl;
pmesh->ent_sets->PrintSetInfo(std::cout);
std::ostringstream oss; oss << "ent_sets_" << MyRank << ".out";
std::ofstream ofs(oss.str().c_str());
pmesh->ent_sets->Print(ofs);
MPI_Barrier(MyComm);
std::cout << MyRank << ": testing " << NElements << std::endl;
//pmesh->ent_sets->Prune(NElements);
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated pmesh->ent_sets is NULL" << std::endl;
}
*/
/*
if (pmesh->pent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated pmesh->pent_sets is non NULL" <<
std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated pmesh->pent_sets is NULL" << std::endl;
}
}
else
{
std::cout << "dynamic cast failed: mesh is not a ParMesh" << std::endl;
}
*/
/*
if (pncent_sets)
{
if (!pmesh->pent_sets)
{
pmesh->pent_sets = new ParEntitySets(*pmesh, *this);
}
}
*/
/*
// Prune the Entity Sets
if ( entity_sets )
{
EntitySets::EntityType t = EntitySets::INVALID;
unsigned int ns = -1;
std::cout << "Processing node sets" << std::endl;
t = EntitySets::VERTEX;
ns = entity_sets->GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
unsigned int ni = entity_sets->GetNumEntities(t, s);
int e = 0;
for (unsigned int i=0; i<ni; i++)
{
if ( (*mesh->ent_sets)(t, s, i) < NVertices )
{
(*mesh->ent_sets)(t, s, e) = (*mesh->ent_sets)(t, s, i);
e++;
}
}
(*mesh->ent_sets)(t, s).resize(e);
}
t = EntitySets::EDGE;
ns = entity_sets->GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
unsigned int ni = entity_sets->GetNumEntities(t, s);
BlockArray<int> ids;
for (unsigned int i=0; i<ni; i++)
{
if ( (*mesh->ent_sets)(t, s, i) < NEdges )
{
ids.Append((*mesh->ent_sets)(t, s, i));
}
}
(*mesh->ent_sets)(t, s).resize(ids.Size());
for (int i=0; i<ids.Size(); i++)
{
(*mesh->ent_sets)(t, s, i) = ids[i];
}
}
}
*/
/*
std::cout << MyRank << ": Leaving ParNCMesh::OnMeshUpdated" << std::endl;
}
}
*/
void ParNCMesh::ElementSharesFace(int elem, int local, int face)
{
// Analogous to ElementSharesEdge.
@@ -3152,94 +2732,6 @@ void ParNCMesh::GetDebugMesh(Mesh &debug_mesh) const
debug_mesh.ncmesh = copy;
}
void ParNCMesh::GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edges)
{
std::cout << MyRank
<< ": entering ParNCMesh::GetRefinedEdges "
<<"searching for edge with vertices: " << vn0 << " and " << vn1
<< std::endl;
return this->NCMesh::GetRefinedEdges(vn0, vn1, edges);
int mid = nodes.FindId(vn0, vn1);
if (mid < 0) { return; }
/*
Node &nd = nodes[mid];
if ( nd.edge_index < 0 ) { return; }
edges.Append(nd.edge_index);
GetRefinedEdges(vn0, mid, edges);
GetRefinedEdges(mid, vn1, edges);
*/
edges.Append(mid);
GetRefinedEdges(vn0, mid, edges);
GetRefinedEdges(mid, vn1, edges);
}
void ParNCMesh::GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids)
{
return this->NCMesh::GetRefinedFaces(vn0, vn1, vn2, vn3, face_ids);
/*
Face* fa = faces.Find(vn0, vn1, vn2, vn3);
if (fa)
{
if ( fa->index >= 0 )
{
face_ids.Append(fa->index);
}
return;
}
// we need to recurse deeper
int mid[4];
int split = FaceSplitType(vn0, vn1, vn2, vn3, mid);
if (split == 1) // "X" split face
{
GetRefinedFaces(vn0, mid[0], mid[2], vn3, face_ids);
GetRefinedFaces(mid[0], vn1, vn2, mid[2], face_ids);
}
else if (split == 2) // "Y" split face
{
GetRefinedFaces(vn0, vn1, mid[1], mid[3], face_ids);
GetRefinedFaces(mid[3], mid[1], vn2, vn3, face_ids);
}
*/
}
void ParNCMesh::GetRefinedElements(int elem_id, BlockArray<int> & elem_ids)
{
// std::cout << MyRank
// << ": entering ParNCMesh::GetRefinedElements "
// <<"searching for element id: " << elem_id << std::endl;
Element &el = elements[elem_id];
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size() )
{
GetRefinedElements(el.child[i], elem_ids);
}
}
}
else
{
// This element has not been refined so add it if it's a local element
if (el.rank == MyRank)
{
elem_ids.Append(elem_id);
}
}
}
void ParNCMesh::Trim()
{
NCMesh::Trim();
-23
View File
@@ -20,7 +20,6 @@
#include <set>
#include "ncmesh.hpp"
#include "pentsets.hpp"
#include "../general/communication.hpp"
#include "../general/sort_pairs.hpp"
@@ -249,29 +248,9 @@ public:
The debug mesh will have element attributes set to element rank + 1. */
void GetDebugMesh(Mesh &debug_mesh) const;
/** Collect edge indices of all refined edges which are children of
the coarse edge defined by the given vertices. This method
overrides a method in NCMesh and only returns locally owned
edges. */
void GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edge_ids);
/** Collect face indices of all refined faces which are children of
the coarse face defined by the given vertices. This method
overrides a method in NCMesh and only returns locally owned
faces. */
void GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids);
/** Collect element indices of all refined elements which are
children of the coarse element defined by the given element
index. This method overrides a method in NCMesh and only
returns locally owned elements. */
void GetRefinedElements(int elem_id, BlockArray<int> & elem_ids);
protected: // interface for ParMesh
friend class ParMesh;
friend class ParEntitySets;
/** For compatibility with conforming code in ParMesh and ParFESpace.
Initializes shared structures in ParMesh: gtopo, shared_*, group_s*, s*_l*.
@@ -561,8 +540,6 @@ protected: // implementation
Array<DenseMatrix*> aux_pm_store;
void ClearAuxPM();
ParNCEntitySets * pncent_sets;
long GroupsMemoryUsage() const;
friend class NeighborRowMessage;
-1
View File
@@ -29,5 +29,4 @@ add_subdirectory(gslib)
add_subdirectory(solvers)
add_subdirectory(shifted)
add_subdirectory(mtop)
add_subdirectory(autodiff)
add_subdirectory(parelag)
-57
View File
@@ -1,57 +0,0 @@
# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
list(APPEND SEQADIFF_COMMON_SOURCES)
list(APPEND SEQADIFF_COMMON_HEADERS
fdual.hpp
tadvector.hpp
taddensemat.hpp
admfem.hpp)
convert_filenames_to_full_paths(SEQADIFF_COMMON_SOURCES)
convert_filenames_to_full_paths(SEQADIFF_COMMON_HEADERS)
set(SEQADIFF_COMMON_FILES
EXTRA_SOURCES ${SEQADIFF_COMMON_SOURCES}
EXTRA_HEADERS ${SEQADIFF_COMMON_HEADERS})
add_mfem_miniapp(seqadiff
MAIN seq_example.cpp
${SEQADIFF_COMMON_FILES}
LIBRARIES mfem)
add_mfem_miniapp(seqtest
MAIN seq_test.cpp
${SEQADIFF_COMMON_FILES}
LIBRARIES mfem)
if(MFEM_USE_MPI)
list(APPEND PARADIFF_COMMON_SOURCES)
list(APPEND PARADIFF_COMMON_HEADERS)
convert_filenames_to_full_paths(PARADIFF_COMMON_SOURCES)
convert_filenames_to_full_paths(PARADIFF_COMMON_HEADERS)
set(PARADIFF_COMMON_FILES
EXTRA_SOURCES ${PARADIFF_COMMON_SOURCES} ${SEQADIFF_COMMON_SOURCES}
EXTRA_HEADERS ${PARADIFF_COMMON_HEADERS} ${SEQADIFF_COMMON_HEADERS})
message(STATUS "PARADIFF_COMMON_FILES: ${PARADIFF_COMMON_FILES}")
message(STATUS "SEQADIFF_COMMON_FILES: ${SEQADIFF_COMMON_FILES}")
add_mfem_miniapp(paradiff
MAIN par_example.cpp
${PARADIFF_COMMON_FILES}
LIBRARIES mfem)
endif ()
-712
View File
@@ -1,712 +0,0 @@
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef ADMFEM_HPP
#define ADMFEM_HPP
#include "mfem.hpp"
#include "fdual.hpp"
#include "tadvector.hpp"
#include "taddensemat.hpp"
#ifdef MFEM_USE_CODIPACK
#include <codi.hpp>
namespace mfem
{
namespace ad
{
#ifdef MFEM_USE_ADFORWARD
/// Forward AD type declaration
typedef codi::RealForward ADFloatType;
/// Vector type for AD-numbers
typedef TAutoDiffVector<ADFloatType> ADVectorType;
/// Matrix type for AD-numbers
typedef TAutoDiffDenseMatrix<ADFloatType> ADMatrixType;
#else
/// Reverse AD type declaration
typedef codi::RealReverse ADFloatType;
/// Vector type for AD-numbers
typedef TAutoDiffVector<ADFloatType> ADVectorType;
/// Matrix type for AD-numbers
typedef TAutoDiffDenseMatrix<ADFloatType> ADMatrixType;
#endif
}
/// The class provides an evaluation of the Jacobian of a templated vector
/// function provided in the constructor. The Jacobian is evaluated with the
/// help of automatic differentiation (AD). The template parameters specify the
/// size of the return vector (vector_size), the size of the input vector
/// (state_size), and the size of the parameters supplied to the function.
template<int vector_size=1, int state_size=1, int param_size=0>
class VectorFuncAutoDiff
{
public:
/// F_ is user implemented function to be differentiated by
/// VectorFuncAutoDiff. The signature of the function is: F_(mfem::Vector&
/// parameters, ad::ADVectorType& state_vector, ad::ADVectorType& result).
/// The parameters vector should have size param_size. The state_vector
/// should have size state_size, and the result vector should have size
/// vector_size. All size parameters are teplate parameters in
/// VectorFuncAutoDiff.
VectorFuncAutoDiff(
std::function<void(mfem::Vector&, ad::ADVectorType&, ad::ADVectorType&)> F_)
{
F=F_;
}
/// Evaluates the Jacobian of the vector function F_ for a set of parameters
/// (vparam) and state vector vstate. The Jacobian (jac) has dimensions
/// [vector_size x state_size].
void Jacobian(mfem::Vector &vparam, mfem::Vector &vstate,
mfem::DenseMatrix &jac)
{
#ifdef MFEM_USE_ADFORWARD
// use forward mode
jac.SetSize(vector_size, state_size);
jac = 0.0;
{
ad::ADVectorType ad_state(state_size);
ad::ADVectorType ad_result(vector_size);
for (int i=0; i<state_size; i++)
{
ad_state[i].setValue(vstate[i]);
ad_state[i].setGradient(0.0);
}
for (int ii=0; ii<state_size; ii++)
{
ad_state[ii].setGradient(1.0);
F(vparam,ad_state,ad_result);
for (int jj=0; jj<vector_size; jj++)
{
jac(jj,ii)=ad_result[jj].getGradient();
}
ad_state[ii].setGradient(0.0);
}
}
#else // use reverse mode
jac.SetSize(vector_size, state_size);
jac = 0.0;
{
ad::ADVectorType ad_state(state_size);
ad::ADVectorType ad_result(vector_size);
for (int i=0; i<state_size; i++)
{
ad_state[i]=vstate[i];
}
ad::ADFloatType::TapeType& tape =ad::ADFloatType::getGlobalTape();
typename ad::ADFloatType::TapeType::Position pos=tape.getPosition();
tape.setActive();
for (int ii=0; ii<state_size; ii++) { tape.registerInput(ad_state[ii]); }
F(vparam,ad_state,ad_result);
for (int ii=0; ii<vector_size; ii++) { tape.registerOutput(ad_result[ii]); }
tape.setPassive();
for (int jj=0; jj<vector_size; jj++)
{
ad_result[jj].setGradient(1.0);
tape.evaluate();
for (int ii=0; ii<state_size; ii++)
{
jac(jj,ii)=ad_state[ii].getGradient();
}
tape.clearAdjoints();
ad_result[jj].setGradient(0.0);
}
tape.reset(pos);
}
#endif
}
private:
std::function<void(mfem::Vector&, ad::ADVectorType&, ad::ADVectorType&)> F;
}; // VectorFuncAutoDiff
/// The class provides an evaluation of the Jacobian of a templated vector
/// function provided as a functor TFunctor. The Jacobian is evaluated with the
/// help of automatic differentiation (AD). The template parameters specify the
/// size of the return vector (vector_size), the size of the input vector
/// (state_size), and the size of the parameters supplied to the function. The
/// TFunctor functor is a template class with parameters [Float data type],
/// [Vector type for the additional parameters], [Vector type for the state
/// vector and the return residual]. The integer template parameters are the
/// same ones passed to QVectorFuncAutoDiff.
template<template<typename, typename, typename, int, int, int> class TFunctor
, int vector_size=1, int state_size=1, int param_size=0>
class QVectorFuncAutoDiff
{
public:
/// Evaluates the vector function for given set of parameters and state
/// values in vector uu. The result is returned in vector rr.
void VectorFunc(const mfem::Vector &vparam, mfem::Vector &uu, mfem::Vector& rr)
{
rf(vparam,uu,rr);
}
/// Returns the gradient of TFunctor(...) in the dense matrix jac. The
/// dimensions of jac are vector_size x state_size, where state_size is the
/// length of vector uu.
void Jacobian(mfem::Vector &vparam, mfem::Vector &uu, mfem::DenseMatrix &jac)
{
#ifdef MFEM_USE_ADFORWARD
// use forward mode
jac.SetSize(vector_size, state_size);
jac = 0.0;
{
ad::ADVectorType aduu(state_size);
ad::ADVectorType rr(vector_size);
for (int i=0; i<state_size; i++)
{
aduu[i].setValue(uu[i]);
aduu[i].setGradient(0.0);
}
for (int ii=0; ii<state_size; ii++)
{
aduu[ii].setGradient(1.0);
tf(vparam,aduu,rr);
for (int jj=0; jj<vector_size; jj++)
{
jac(jj,ii)=rr[jj].getGradient();
}
aduu[ii].setGradient(0.0);
}
}
#else // end MFEM_USE_ADFORWARD
// use reverse mode
jac.SetSize(vector_size, state_size);
jac = 0.0;
{
ad::ADVectorType aduu(state_size);
ad::ADVectorType rr(vector_size);
for (int i=0; i<state_size; i++)
{
aduu[i]=uu[i];
}
ad::ADFloatType::TapeType& tape =ad::ADFloatType::getGlobalTape();
typename ad::ADFloatType::TapeType::Position pos=tape.getPosition();
tape.setActive();
for (int ii=0; ii<state_size; ii++) { tape.registerInput(aduu[ii]); }
tf(vparam,aduu,rr);
for (int ii=0; ii<vector_size; ii++) { tape.registerOutput(rr[ii]); }
tape.setPassive();
for (int jj=0; jj<vector_size; jj++)
{
rr[jj].setGradient(1.0);
tape.evaluate();
for (int ii=0; ii<state_size; ii++)
{
jac(jj,ii)=aduu[ii].getGradient();
}
tape.clearAdjoints();
rr[jj].setGradient(0.0);
}
tape.reset(pos);
}
#endif
}
private:
TFunctor<ad::ADFloatType, const Vector, ad::ADVectorType,
vector_size, state_size, param_size> tf;
TFunctor<double,const mfem::Vector, mfem::Vector,
vector_size, state_size, param_size> rf;
};
/// The class provides an evaluation of the first derivatives and the Hessian of
/// a templated scalar function provided as a functor TFunctor. Both the first
/// and the second derivatives are evaluated with the help of automatic
/// differentiation (AD). The template parameters specify the size of the input
/// vector (state_size) and the size of the parameters supplied to the
/// function. The TFunctor functor is a template class with parameters [Float
/// data type], [Vector type for the additional parameters], [Vector type for
/// the state vector and the return residual]. The integer template parameters
/// are the same ones passed to QFunctionAutoDiff.
template<template<typename, typename, typename, int, int> class TFunctor
, int state_size=1, int param_size=0>
class QFunctionAutoDiff
{
public:
/// Evaluates a function for arguments vparam and uu. The evaluation is
/// based on the operator() in the user provided functor TFunctor.
double Eval(const mfem::Vector &vparam, mfem::Vector &uu)
{
return rf(vparam,uu);
}
/// Provides the same functionality as Grad.
void VectorFunc(const mfem::Vector &vparam, mfem::Vector &uu, mfem::Vector &rr)
{
Grad(vparam,uu,rr);
}
/// Returns the first derivative of TFunctor(...) with respect to the active
/// arguments proved in vector uu. The length of rr is the same as for uu.
void Grad(const mfem::Vector &vparam, mfem::Vector &uu, mfem::Vector &rr)
{
#ifdef MFEM_USE_ADFORWARD
// use forward mode
rr.SetSize(state_size);
{
ad::ADVectorType aduu(state_size);
for (int i=0; i<state_size; i++)
{
aduu[i].setValue(uu[i]);
aduu[i].setGradient(0.0);
}
ad::ADFloatType rez;
for (int ii=0; ii<state_size; ii++)
{
aduu[ii].setGradient(1.0);
rez=tf(vparam,aduu);
rr[ii]=rez.getGradient();
aduu[ii].setGradient(0.0);
}
}
#else
{
ad::ADVectorType aduu(state_size);
ad::ADFloatType rez;
for (int i=0; i<state_size; i++)
{
aduu[i]=uu[i];
}
ad::ADFloatType::TapeType& tape =ad::ADFloatType::getGlobalTape();
typename ad::ADFloatType::TapeType::Position pos=tape.getPosition();
tape.setActive();
for (int ii=0; ii<state_size; ii++) { tape.registerInput(aduu[ii]); }
rez=tf(vparam,aduu);
tape.registerOutput(rez);
tape.setPassive();
rez.setGradient(1.0);
tape.evaluate();
for (int i=0; i<state_size; i++)
{
rr[i]=aduu[i].getGradient();
}
tape.reset(pos);
}
#endif
}
/// Provides same functionality as Hessian.
void Jacobian(mfem::Vector &vparam, mfem::Vector &uu, mfem::DenseMatrix &jac)
{
Hessian(vparam,uu,jac);
}
#ifdef MFEM_USE_ADFORWARD
// use forward-forward mode
typedef codi::RealForwardGen<double> ADFType;
typedef TAutoDiffVector<ADFType> ADFVector;
typedef TAutoDiffDenseMatrix<ADFType> ADFDenseMatrix;
typedef codi::RealForwardGen<ADFType> ADSType;
typedef TAutoDiffVector<ADSType> ADSVector;
typedef TAutoDiffDenseMatrix<ADSType> ADSDenseMatrix;
#else
//use mixed forward and reverse mode
typedef codi::RealForwardGen<double> ADFType;
typedef TAutoDiffVector<ADFType> ADFVector;
typedef TAutoDiffDenseMatrix<ADFType> ADFDenseMatrix;
typedef codi::RealReverseGen<ADFType> ADSType;
typedef TAutoDiffVector<ADSType> ADSVector;
typedef TAutoDiffDenseMatrix<ADSType> ADSDenseMatrix;
#endif
/// Returns the Hessian of TFunctor(...) in the dense matrix jac. The
/// dimensions of jac are state_size x state_size, where state_size is the
/// length of vector uu.
void Hessian(mfem::Vector &vparam, mfem::Vector &uu, mfem::DenseMatrix &jac)
{
#ifdef MFEM_USE_ADFORWARD
// use forward-forward mode
jac.SetSize(state_size);
jac=0.0;
{
ADSVector aduu(state_size);
for (int ii = 0; ii < state_size; ii++)
{
aduu[ii].value().value()=uu[ii];
aduu[ii].value().gradient()=0.0;
aduu[ii].gradient().value()=0.0;
aduu[ii].gradient().gradient()=0.0;
}
for (int ii = 0; ii < state_size; ii++)
{
aduu[ii].value().gradient()=1.0;
for (int jj=0; jj<(ii+1); jj++)
{
aduu[jj].gradient().value()=1.0;
ADSType rez=sf(vparam,aduu);
jac(ii,jj)=rez.gradient().gradient();
jac(jj,ii)=jac(ii,jj);
aduu[jj].gradient().value()=0.0;
}
aduu[ii].value().gradient()=0.0;
}
}
#else
// use mixed forward and reverse mode
jac.SetSize(state_size);
jac=0.0;
{
ADSVector aduu(state_size);
for (int ii=0; ii < state_size ; ii++)
{
aduu[ii].value().value()=uu[ii];
}
ADSType rez;
ADSType::TapeType& tape = ADSType::getGlobalTape();
typename ADSType::TapeType::Position pos;
for (int ii = 0; ii < state_size ; ii++)
{
pos=tape.getPosition();
tape.setActive();
for (int jj=0; jj < state_size; jj++)
{
if (jj==ii) {aduu[jj].value().gradient()=1.0;}
else {aduu[jj].value().gradient()=0.0;}
tape.registerInput(aduu[jj]);
}
rez=sf(vparam,aduu);
tape.registerOutput(rez);
tape.setPassive();
rez.gradient().value()=1.0;
tape.evaluate();
for (int jj=0; jj<(ii+1); jj++)
{
jac(ii,jj)=aduu[jj].gradient().gradient();
jac(jj,ii)=jac(ii,jj);
}
tape.reset(pos);
}
}
#endif
}
private:
TFunctor<double, const mfem::Vector,
mfem::Vector, state_size, param_size> rf;
TFunctor<ad::ADFloatType, const mfem::Vector,
ad::ADVectorType, state_size, param_size> tf;
TFunctor<ADSType, const mfem::Vector, ADSVector,
state_size, param_size> sf;
};
}
#else // end MFEM_USE_CODIPACK
// USE NATIVE IMPLEMENTATION
namespace mfem
{
namespace ad
{
/// MFEM native forward AD-type
typedef FDualNumber<double> ADFloatType;
/// Vector type for AD-type numbers
typedef TAutoDiffVector<ADFloatType> ADVectorType;
/// Matrix type for AD-type numbers
typedef TAutoDiffDenseMatrix<ADFloatType> ADMatrixType;
}
/// The class provides an evaluation of the Jacobian of a templated vector
/// function provided in the constructor. The Jacobian is evaluated with the
/// help of automatic differentiation (AD). The template parameters specify the
/// size of the return vector (vector_size), the size of the input vector
/// (state_size), and the size of the parameters supplied to the function.
template<int vector_size=1, int state_size=1, int param_size=0>
class VectorFuncAutoDiff
{
public:
/// F_ is user implemented function to be differentiated by
/// VectorFuncAutoDiff. The signature of the function is: F_(mfem::Vector&
/// parameters, ad::ADVectroType& state_vector, ad::ADVectorType& result).
/// The parameters vector should have size param_size. The state_vector
/// should have size state_size, and the result vector should have size
/// vector_size. All size parameters are teplate parameters in
/// VectorFuncAutoDiff.
VectorFuncAutoDiff(
std::function<void(mfem::Vector&, ad::ADVectorType&, ad::ADVectorType&)> F_)
{
F=F_;
}
/// Evaluates the Jacobian of the vector function F_ for a set of parameters
/// (vparam) and state vector uu. The Jacobian (jac) has dimensions
/// [vector_size x state_size].
void Jacobian(mfem::Vector &vparam, mfem::Vector &uu, mfem::DenseMatrix &jac)
{
jac.SetSize(vector_size, state_size);
jac = 0.0;
{
ad::ADVectorType aduu(uu); // all dual numbers are initialized to zero
ad::ADVectorType rr(vector_size);
for (int ii = 0; ii < state_size; ii++)
{
aduu[ii].dual(1.0);
F(vparam,aduu,rr);
for (int jj = 0; jj < vector_size; jj++)
{
jac(jj, ii) = rr[jj].dual();
}
aduu[ii].dual(0.0);
}
}
}
private:
std::function<void(mfem::Vector&, ad::ADVectorType&, ad::ADVectorType&)> F;
};
/// The class provides an evaluation of the Jacobian of a templated vector
/// function provided as a functor TFunctor. The Jacobian is evaluated with the
/// help of automatic differentiation (AD). The template parameters specify the
/// size of the return vector (vector_size), the size of the input vector
/// (state_size), and the size of the parameters supplied to the function. The
/// TFunctor functor is a template class with parameters [Float data type],
/// [Vector type for the additional parameters], [Vector type for the state
/// vector and the return residual].
/// The integer template parameters are the same ones
/// passed to QVectorFuncAutoDiff. \n
/// Example: f={sin(a*x*y), cos(b*x*y*z), x*x+y*x} \n
/// The vector function has vector_size=3, and state_size=3, i.e., it has
/// three arguments [x,y,z]. The parameters [a,b] size is 2.
/// The functor class will have the following form
/// \code{.cpp}
/// template<typename TDataType, typename TParamVector, typename TStateVector,
/// int residual_size, int state_size, int param_size>
/// class MyVectorFunction{
/// public:
/// TDataType operator() (TParamVector& vparam, TStateVector& uu, TStateVector& rr)
/// {
/// auto a=vparam[0];
/// auto b=vparam[1];
/// rr[0]=sin(a*uu[0]*uu[1]);
/// rr[1]=cos(b*uu[0]*uu[1]*uu[2]);
/// rr[2]=uu[0]*uu[0]+uu[0]*uu[1];
/// }
//
/// };
/// \endcode
template<template<typename, typename, typename, int, int, int> class TFunctor
, int vector_size=1, int state_size=1, int param_size=0>
class QVectorFuncAutoDiff
{
private:
/// MFEM native forward AD-type
typedef ad::FDualNumber<double> ADFType;
/// Vector type for AD-type numbers
typedef TAutoDiffVector<ADFType> ADFVector;
/// Matrix type for AD-type numbers
typedef TAutoDiffDenseMatrix<ADFType> ADFDenseMatrix;
public:
/// Returns a vector valued function rr for supplied passive arguments
/// vparam and active arguments uu. The evaluation is based on the user
/// supplied TFunctor template class.
void VectorFunc(const Vector &vparam, Vector &uu, Vector &rr)
{
func(vparam, uu, rr);
}
/// Returns the gradient of TFunctor(...) residual in the dense matrix jac.
/// The dimensions of jac are vector_size x state_size, where state_size is
/// the length of vector uu.
void Jacobian(mfem::Vector &vparam, mfem::Vector &uu, mfem::DenseMatrix &jac)
{
// use native AD package
jac.SetSize(vector_size, state_size);
jac = 0.0;
{
ADFVector aduu(uu); // all dual numbers are initialized to zero
ADFVector rr(vector_size);
for (int ii = 0; ii < state_size; ii++)
{
aduu[ii].dual(1.0);
Eval(vparam, aduu, rr);
for (int jj = 0; jj < vector_size; jj++)
{
jac(jj, ii) = rr[jj].dual();
}
aduu[ii].dual(0.0);
}
}
}
private:
/// Evaluates the residual from TFunctor(...).
/// Intended for internal use only.
void Eval(const Vector &vparam, ADFVector &uu, ADFVector &rr)
{
tf(vparam, uu, rr);
}
TFunctor<double, const Vector, Vector,
vector_size, state_size, param_size> func;
TFunctor<ADFType, const Vector, ADFVector,
vector_size, state_size, param_size> tf;
};
/// The class provides an evaluation of the first derivatives and the Hessian of
/// a templated scalar function provided as a functor TFunctor. Both the first
/// and the second derivatives are evaluated with the help of automatic
/// differentiation (AD). The template parameters specify the size of the input
/// vector (state_size) and the size of the parameters supplied to the
/// function. The TFunctor functor is a template class with parameters [Float
/// data type], [Vector type for the additional parameters], [Vector type for
/// the state vector and the return residual]. The integer template parameters
/// are the same ones passed to QFunctionAutoDiff. The class duplicates Grad and
/// Hessian, i.e., VectorFunc calls Grad, and Jacobian calls Hessian. The main
/// reason is to provide the same interface as the QVectorFuncAutoDiff class
/// used to differentiate vector functions. Such compatibility allows users to
/// start implementation of their problem based only on some energy or a weak
/// form. The gradients, computed with Grad/VectorFunc, of the function will
/// contribute to the FE residual. Computed with Hessian/Jacobian, the Hessian
/// will contribute to the tangent matrix in Newton's iterations. Once the
/// implementation is complete and tested, the users can start improving the
/// performance by replacing Grad/VectorFunc with a hand-coded version. The
/// gradient is a vector function and can be differentiated with the
/// functionality implemented in QVectorFuncAutoDiff. Thus, the user can
/// directly employ AD for computing the contributions to the global tangent
/// matrix. The main code will not require changes as the names Grad/VectorFunc
/// and Hessian/Jacobian are mirrored.
template<template<typename, typename, typename, int, int> class TFunctor
, int state_size=1, int param_size=0>
class QFunctionAutoDiff
{
private:
/// MFEM native AD-type for first derivatives
typedef ad::FDualNumber<double> ADFType;
/// Vector type for AD-numbers(first derivatives)
typedef TAutoDiffVector<ADFType> ADFVector;
/// Matrix type for AD-numbers(first derivatives)
typedef TAutoDiffDenseMatrix<ADFType> ADFDenseMatrix;
/// MFEM native AD-type for second derivatives
typedef ad::FDualNumber<ADFType> ADSType;
/// Vector type for AD-numbers (second derivatives)
typedef TAutoDiffVector<ADSType> ADSVector;
/// Vector type for AD-numbers (second derivatives)
typedef TAutoDiffDenseMatrix<ADSType> ADSDenseMatrix;
public:
/// Evaluates a function for arguments vparam and uu. The evaluation is
/// based on the operator() in the user provided functor TFunctor.
double Eval(const Vector &vparam, Vector &uu)
{
return tf(vparam,uu);
}
/// Provides the same functionality as Grad.
void VectorFunc(const Vector &vparam, Vector &uu, Vector &rr)
{
Grad(vparam,uu,rr);
}
/// Returns the first derivative of TFunctor(...) with respect to the active
/// arguments proved in vector uu. The length of rr is the same as for uu.
void Grad(const Vector &vparam, Vector &uu, Vector &rr)
{
int n = uu.Size();
rr.SetSize(n);
ADFVector aduu(uu);
ADFType rez;
for (int ii = 0; ii < n; ii++)
{
aduu[ii].dual(1.0);
rez = ff(vparam, aduu);
rr[ii] = rez.dual();
aduu[ii].dual(0.0);
}
}
/// Provides same functionality as Hessian.
void Jacobian(mfem::Vector &vparam, mfem::Vector &uu, mfem::DenseMatrix &jac)
{
Hessian(vparam,uu,jac);
}
/// Returns the Hessian of TFunctor(...) in the dense matrix jac. The
/// dimensions of jac are state_size x state_size, where state_size is the
/// length of vector uu.
void Hessian(mfem::Vector &vparam, mfem::Vector &uu, mfem::DenseMatrix &jac)
{
int n = uu.Size();
jac.SetSize(n);
jac = 0.0;
{
ADSVector aduu(n);
for (int ii = 0; ii < n; ii++)
{
aduu[ii].real(ADFType(uu[ii], 0.0));
aduu[ii].dual(ADFType(0.0, 0.0));
}
for (int ii = 0; ii < n; ii++)
{
aduu[ii].real(ADFType(uu[ii], 1.0));
for (int jj = 0; jj < (ii + 1); jj++)
{
aduu[jj].dual(ADFType(1.0, 0.0));
ADSType rez = sf(vparam, aduu);
jac(ii, jj) = rez.dual().dual();
jac(jj, ii) = rez.dual().dual();
aduu[jj].dual(ADFType(0.0, 0.0));
}
aduu[ii].real(ADFType(uu[ii], 0.0));
}
}
}
private:
TFunctor<double, const Vector, Vector, state_size, param_size> tf;
TFunctor<ADFType, const Vector, ADFVector, state_size, param_size> ff;
TFunctor<ADSType, const Vector, ADSVector, state_size, param_size> sf;
};
} // end namespace mfem
#endif // NATIVE
#endif // ADMFEM_HPP
-876
View File
@@ -1,876 +0,0 @@
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef ADEXAMPLE_HPP
#define ADEXAMPLE_HPP
#include "mfem.hpp"
#include "admfem.hpp"
#include <memory>
#include <iostream>
#include <fstream>
namespace mfem
{
/// Example: Implementation of the residual evaluation for p-Laplacian
/// problem. The residual is evaluated at the integration points for PDE
/// parameters vparam and state fields (derivatives with respect to x,y,z and
/// primal field) stored in vector uu.
template<typename TDataType, typename TParamVector, typename TStateVector,
int residual_size, int state_size, int param_size>
class MyResidualFunctor
{
public:
/// The operator returns the first derivative of the energy with respect to
/// all state variables. These are set in vector uu and consist of the
/// derivatives with respect to x,y,z and the primal field. The derivative is
/// stored in vector rr with length equal to the length of vector uu.
void operator()(TParamVector &vparam, TStateVector &uu, TStateVector &rr)
{
MFEM_ASSERT(residual_size==4,
"PLaplacianResidual residual_size should be equal to 4!");
double pp = vparam[0];
double ee = vparam[1];
double ff = vparam[2];
// The vector rr holds the gradients of the following expression:
// (u_x^2+u_y^2+u_z^2+\varepsilon^2)^(p/2)-f.u,
// where u_x,u_y,u_z are the gradients of the scalar field u.
// The state vector is defined as uu=[u_x,u_y,u_z,u].
TDataType norm2 = uu[0] * uu[0] + uu[1] * uu[1] + uu[2] * uu[2];
TDataType tvar = pow(ee * ee + norm2, (pp - 2.0) / 2.0);
rr[0] = tvar * uu[0];
rr[1] = tvar * uu[1];
rr[2] = tvar * uu[2];
rr[3] = -ff;
}
};
/// Defines template class (functor) for evaluating the energy of the
/// p-Laplacian problem. The input parameters vparam are: vparam[0] - the
/// p-Laplacian power, vparam[1] small value ensuring exciting of an unique
/// solution, and vparam[2] - the distributed external input to the PDE. The
/// template parameter TDataType will be replaced by the compiler with the
/// appropriate AD type for automatic differentiation. The TParamVector
/// represents the vector type used for the parameter vector, and TStateVector
/// the vector type used for the state vector. The template parameters
/// state_size and param_size provide information for the size of the state and
/// the parameters vectors.
template<typename TDataType, typename TParamVector, typename TStateVector
, int state_size, int param_size>
class MyEnergyFunctor
{
public:
/// Returns the energy of a p-Laplacian for state field input provided in
/// vector uu and parameters provided in vector vparam.
TDataType operator()(TParamVector &vparam, TStateVector &uu)
{
MFEM_ASSERT(state_size==4,"MyEnergyFunctor state_size should be equal to 4!");
MFEM_ASSERT(param_size==3,"MyEnergyFunctor param_size should be equal to 3!");
double pp = vparam[0];
double ee = vparam[1];
double ff = vparam[2];
TDataType u = uu[3];
TDataType norm2 = uu[0] * uu[0] + uu[1] * uu[1] + uu[2] * uu[2];
TDataType rez = pow(ee * ee + norm2, pp / 2.0) / pp - ff * u;
return rez;
}
};
/// Implements integrator for a p-Laplacian problem. The integrator is based on
/// a class QFunction utilized for evaluating the energy, the first derivative
/// (residual) and the Hessian of the energy (the Jacobian of the residual).
/// The template parameter CQVectAutoDiff represents the automatically
/// differentiated energy or residual implemented by the user.
/// CQVectAutoDiff::VectorFunc(Vector parameters, Vector state,Vector residual)
/// evaluates the residual at an integration point.
/// CQVectAutoDiff::Jacobian(Vector parameters, Vector state, Matrix hessian)
/// evaluates the Hessian of the energy(the Jacobian of the residual).
template<class CQVectAutoDiff>
class pLaplaceAD : public NonlinearFormIntegrator
{
protected:
Coefficient *pp;
Coefficient *coeff;
Coefficient *load;
CQVectAutoDiff rdf;
public:
pLaplaceAD()
{
coeff = nullptr;
pp = nullptr;
load = nullptr;
vparam.SetSize(3);
vparam[0] = 2.0; // default power
vparam[1] = 1e-8; // default epsilon
vparam[2] = 1.0; // default load
}
pLaplaceAD(Coefficient &pp_) : pp(&pp_), coeff(nullptr), load(nullptr)
{
vparam.SetSize(3);
vparam[0] = 2.0; // default power
vparam[1] = 1e-8; // default epsilon
vparam[2] = 1.0; // default load
}
pLaplaceAD(Coefficient &pp_, Coefficient &q, Coefficient &ld_)
: pp(&pp_), coeff(&q), load(&ld_)
{
vparam.SetSize(3);
vparam[0] = 2.0; // default power
vparam[1] = 1e-8; // default epsilon
vparam[2] = 1.0; // default load
}
virtual ~pLaplaceAD() {}
virtual double GetElementEnergy(const FiniteElement &el,
ElementTransformation &trans,
const Vector &elfun)
{
double energy = 0.0;
const int ndof = el.GetDof();
const int ndim = el.GetDim();
const int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
int order = 2 * el.GetOrder() + trans.OrderGrad(&el);
const IntegrationRule &ir(IntRules.Get(el.GetGeomType(), order));
Vector shapef(ndof);
// derivatives in isoparametric coordinates
DenseMatrix dshape_iso(ndof, ndim);
// derivatives in physical space
DenseMatrix dshape_xyz(ndof, spaceDim);
Vector grad(spaceDim);
Vector uu(4); //[diff_x,diff_y,diff_z,u]
uu = 0.0;
// Calculates the functional/energy at an integration point.
MyEnergyFunctor<double,Vector,Vector,4,3> qfunc;
double w;
double detJ;
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w * w);
w = ip.weight * w;
el.CalcDShape(ip, dshape_iso);
el.CalcShape(ip, shapef);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
// dshape_xyz should be divided by detJ for obtaining the real value
// calculate the gradient
dshape_xyz.MultTranspose(elfun, grad);
// set the power
if (pp != nullptr)
{
vparam[0] = pp->Eval(trans, ip);
}
// set the coefficient ensuring positiveness of the tangent matrix
if (coeff != nullptr)
{
vparam[1] = coeff->Eval(trans, ip);
}
// add the contribution from the load
if (load != nullptr)
{
vparam[2] = load->Eval(trans, ip);
}
// fill the values of vector uu
for (int jj = 0; jj < spaceDim; jj++)
{
uu[jj] = grad[jj] / detJ;
}
uu[3] = shapef * elfun;
// the energy is taken directly from the templated function
energy = energy + w * qfunc(vparam,uu);
}
return energy;
}
virtual void AssembleElementVector(const FiniteElement &el,
ElementTransformation &trans,
const Vector &elfun,
Vector &elvect)
{
MFEM_PERF_BEGIN("AssembleElementVector");
const int ndof = el.GetDof();
const int ndim = el.GetDim();
const int spaceDim = trans.GetSpaceDim();
int order = 2 * el.GetOrder() + trans.OrderGrad(&el);
const IntegrationRule &ir(IntRules.Get(el.GetGeomType(), order));
Vector shapef(ndof);
DenseMatrix dshape_iso(ndof, ndim);
DenseMatrix dshape_xyz(ndof, spaceDim);
Vector lvec(ndof);
elvect.SetSize(ndof);
elvect = 0.0;
DenseMatrix B(ndof, 4); // [diff_x,diff_y,diff_z, shape]
Vector uu(4); // [diff_x,diff_y,diff_z,u]
Vector du(4);
B = 0.0;
uu = 0.0;
double w;
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
w = ip.weight * w;
el.CalcDShape(ip, dshape_iso);
el.CalcShape(ip, shapef);
Mult(dshape_iso, trans.InverseJacobian(), dshape_xyz);
// set the matrix B
for (int jj = 0; jj < spaceDim; jj++)
{
B.SetCol(jj, dshape_xyz.GetColumn(jj));
}
B.SetCol(3, shapef);
// set the power
if (pp != nullptr)
{
vparam[0] = pp->Eval(trans, ip);
}
// set the coefficient ensuring positiveness of the tangent matrix
if (coeff != nullptr)
{
vparam[1] = coeff->Eval(trans, ip);
}
// add the contribution from the load
if (load != nullptr)
{
vparam[2] = load->Eval(trans, ip);
}
// calculate uu
B.MultTranspose(elfun, uu);
// calculate derivative of the energy with respect to uu
rdf.VectorFunc(vparam,uu,du);
B.Mult(du, lvec);
elvect.Add(w, lvec);
} // end integration loop
MFEM_PERF_END("AssembleElementVector");
}
virtual void AssembleElementGrad(const FiniteElement &el,
ElementTransformation &trans,
const Vector &elfun,
DenseMatrix &elmat)
{
MFEM_PERF_BEGIN("AssembleElementGrad");
const int ndof = el.GetDof();
const int ndim = el.GetDim();
const int spaceDim = trans.GetSpaceDim();
int order = 2 * el.GetOrder() + trans.OrderGrad(&el);
const IntegrationRule &ir(IntRules.Get(el.GetGeomType(), order));
Vector shapef(ndof);
DenseMatrix dshape_iso(ndof, ndim);
DenseMatrix dshape_xyz(ndof, spaceDim);
elmat.SetSize(ndof, ndof);
elmat = 0.0;
DenseMatrix B(ndof, 4); // [diff_x,diff_y,diff_z, shape]
DenseMatrix A(ndof, 4);
Vector uu(4); // [diff_x,diff_y,diff_z,u]
DenseMatrix duu(4, 4);
B = 0.0;
uu = 0.0;
double w;
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
w = ip.weight * w;
el.CalcDShape(ip, dshape_iso);
el.CalcShape(ip, shapef);
Mult(dshape_iso, trans.InverseJacobian(), dshape_xyz);
// set the matrix B
for (int jj = 0; jj < spaceDim; jj++)
{
B.SetCol(jj, dshape_xyz.GetColumn(jj));
}
B.SetCol(3, shapef);
// set the power
if (pp != nullptr)
{
vparam[0] = pp->Eval(trans, ip);
}
// set the coefficient ensuring positiveness of the tangent matrix
if (coeff != nullptr)
{
vparam[1] = coeff->Eval(trans, ip);
}
// add the contribution from the load
if (load != nullptr)
{
vparam[2] = load->Eval(trans, ip);
}
// calculate uu
B.MultTranspose(elfun, uu);
// calculate derivative of the energy with respect to uu
rdf.Jacobian(vparam,uu,duu);
Mult(B, duu, A);
AddMult_a_ABt(w, A, B, elmat);
} // end integration loop
MFEM_PERF_END("AssembleElementGrad");
}
private:
Vector vparam; // [power, epsilon, load]
};
/// Implements hand-coded integrator for a p-Laplacian problem. Utilized as
/// alternative for the pLaplaceAD class based on automatic differentiation.
class pLaplace : public NonlinearFormIntegrator
{
protected:
Coefficient *pp;
Coefficient *coeff;
Coefficient *load;
public:
pLaplace()
{
coeff = nullptr;
pp = nullptr;
load = nullptr;
}
pLaplace(Coefficient &pp_) : pp(&pp_), coeff(nullptr), load(nullptr) {}
pLaplace(Coefficient &pp_, Coefficient &q, Coefficient &ld_)
: pp(&pp_), coeff(&q), load(&ld_)
{}
virtual ~pLaplace() {}
virtual double GetElementEnergy(const FiniteElement &el,
ElementTransformation &trans,
const Vector &elfun)
{
double energy = 0.0;
const int ndof = el.GetDof();
const int ndim = el.GetDim();
const int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
int order = 2 * el.GetOrder() + trans.OrderGrad(&el);
const IntegrationRule &ir(IntRules.Get(el.GetGeomType(), order));
Vector shapef(ndof);
DenseMatrix dshape_iso(ndof, ndim);
DenseMatrix dshape_xyz(ndof, spaceDim);
Vector grad(spaceDim);
double w;
double detJ;
double nrgrad2;
double ppp = 2.0;
double eee = 0.0;
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w * w);
w = ip.weight * w;
el.CalcDShape(ip, dshape_iso);
el.CalcShape(ip, shapef);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
// dshape_xyz should be divided by detJ for obtaining the real value
// calculate the gradient
dshape_xyz.MultTranspose(elfun, grad);
nrgrad2 = grad * grad / (detJ * detJ);
// set the power
if (pp != nullptr)
{
ppp = pp->Eval(trans, ip);
}
// set the coefficient ensuring positiveness of the tangent matrix
if (coeff != nullptr)
{
eee = coeff->Eval(trans, ip);
}
energy = energy + w * std::pow(nrgrad2 + eee * eee, ppp / 2.0) / ppp;
// add the contribution from the load
if (load != nullptr)
{
energy = energy - w * (shapef * elfun) * load->Eval(trans, ip);
}
}
return energy;
}
virtual void AssembleElementVector(const FiniteElement &el,
ElementTransformation &trans,
const Vector &elfun,
Vector &elvect)
{
MFEM_PERF_BEGIN("AssembleElementVector");
const int ndof = el.GetDof();
const int ndim = el.GetDim();
const int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
int order = 2 * el.GetOrder() + trans.OrderGrad(&el);
const IntegrationRule &ir(IntRules.Get(el.GetGeomType(), order));
Vector shapef(ndof);
DenseMatrix dshape_iso(ndof, ndim);
DenseMatrix dshape_xyz(ndof, spaceDim);
Vector grad(spaceDim);
Vector lvec(ndof);
elvect.SetSize(ndof);
elvect = 0.0;
double w;
double detJ;
double nrgrad;
double aa;
double ppp = 2.0;
double eee = 0.0;
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w * w);
w = ip.weight * w;
el.CalcDShape(ip, dshape_iso);
el.CalcShape(ip, shapef);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
// dshape_xyz should be divided by detJ for obtaining the real value
// calculate the gradient
dshape_xyz.MultTranspose(elfun, grad);
nrgrad = grad.Norml2() / detJ;
// grad is not scaled so far, i.e., grad=grad/detJ
// set the power
if (pp != nullptr)
{
ppp = pp->Eval(trans, ip);
}
// set the coefficient ensuring positiveness of the tangent matrix
if (coeff != nullptr)
{
eee = coeff->Eval(trans, ip);
}
// compute (norm of the gradient)^2 + epsilon^2
aa = nrgrad * nrgrad + eee * eee;
aa = std::pow(aa, (ppp - 2.0) / 2.0);
dshape_xyz.Mult(grad, lvec);
elvect.Add(w * aa / (detJ * detJ), lvec);
// add loading
if (load != nullptr)
{
elvect.Add(-w * load->Eval(trans, ip), shapef);
}
} // end integration loop
MFEM_PERF_END("AssembleElementVector");
}
virtual void AssembleElementGrad(const FiniteElement &el,
ElementTransformation &trans,
const Vector &elfun,
DenseMatrix &elmat)
{
MFEM_PERF_BEGIN("AssembleElementGrad");
const int ndof = el.GetDof();
const int ndim = el.GetDim();
const int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
int order = 2 * el.GetOrder() + trans.OrderGrad(&el);
const IntegrationRule &ir(IntRules.Get(el.GetGeomType(), order));
DenseMatrix dshape_iso(ndof, ndim);
DenseMatrix dshape_xyz(ndof, spaceDim);
Vector grad(spaceDim);
Vector lvec(ndof);
// set the size of the element matrix
elmat.SetSize(ndof, ndof);
elmat = 0.0;
double w; // integration weight
double detJ;
double nrgrad; // norm of the gradient
double aa0; // original nonlinear diffusion coefficient
double aa1; // gradient of the above
double ppp = 2.0; // power in the P-Laplacian
double eee = 0.0; // regularization parameter
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w * w);
w = ip.weight * w;
el.CalcDShape(ip, dshape_iso);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
// dshape_xyz should be divided by detJ for obtaining the real value
// grad is not scaled so far,i.e., grad=grad/detJ
// set the power
if (pp != nullptr)
{
ppp = pp->Eval(trans, ip);
}
// set the coefficient ensuring positiveness of the tangent matrix
if (coeff != nullptr)
{
eee = coeff->Eval(trans, ip);
}
// calculate the gradient
dshape_xyz.MultTranspose(elfun, grad);
nrgrad = grad.Norml2() / detJ;
// (u_x^2+u_y^2+u_z^2+\varepsilon^2)
aa0 = nrgrad * nrgrad + eee * eee;
aa1 = std::pow(aa0, (ppp - 2.0) / 2.0);
aa0 = (ppp - 2.0) * std::pow(aa0, (ppp - 4.0) / 2.0);
dshape_xyz.Mult(grad, lvec);
w = w / (detJ * detJ);
AddMult_a_VVt(w * aa0 / (detJ * detJ), lvec, elmat);
AddMult_a_AAt(w * aa1, dshape_xyz, elmat);
} // end integration loop
MFEM_PERF_END("AssembleElementGrad");
}
};
/// Implements AD enabled integrator for a p-Laplacian problem. The tangent
/// matrix is computed using the residual of the element. The template argument
/// should be equal to the size of the residual vector (element vector), i.e.,
/// the user should specify the size to match the exact vector size for the
/// considered order of the shape functions.
template<int sizeres=10>
class pLaplaceSL : public NonlinearFormIntegrator
{
protected:
Coefficient *pp;
Coefficient *coeff;
Coefficient *load;
public:
pLaplaceSL()
{
coeff = nullptr;
pp = nullptr;
load = nullptr;
}
pLaplaceSL(Coefficient &pp_) : pp(&pp_), coeff(nullptr), load(nullptr) {}
pLaplaceSL(Coefficient &pp_, Coefficient &q, Coefficient &ld_)
: pp(&pp_), coeff(&q), load(&ld_)
{}
virtual ~pLaplaceSL() {}
virtual double GetElementEnergy(const FiniteElement &el,
ElementTransformation &trans,
const Vector &elfun)
{
double energy = 0.0;
const int ndof = el.GetDof();
const int ndim = el.GetDim();
const int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
int order = 2 * el.GetOrder() + trans.OrderGrad(&el);
const IntegrationRule &ir(IntRules.Get(el.GetGeomType(), order));
Vector shapef(ndof);
DenseMatrix dshape_iso(ndof, ndim);
DenseMatrix dshape_xyz(ndof, spaceDim);
Vector grad(spaceDim);
double w;
double detJ;
double nrgrad2;
double ppp = 2.0;
double eee = 0.0;
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w * w);
w = ip.weight * w;
el.CalcDShape(ip, dshape_iso);
el.CalcShape(ip, shapef);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
// dshape_xyz should be divided by detJ for obtaining the real value
// calculate the gradient
dshape_xyz.MultTranspose(elfun, grad);
nrgrad2 = grad * grad / (detJ * detJ);
// set the power
if (pp != nullptr)
{
ppp = pp->Eval(trans, ip);
}
// set the coefficient ensuring positiveness of the tangent matrix
if (coeff != nullptr)
{
eee = coeff->Eval(trans, ip);
}
energy = energy + w * std::pow(nrgrad2 + eee * eee, ppp / 2.0) / ppp;
// add the contribution from the load
if (load != nullptr)
{
energy = energy - w * (shapef * elfun) * load->Eval(trans, ip);
}
}
return energy;
}
virtual void AssembleElementVector(const FiniteElement &el,
ElementTransformation &trans,
const Vector &elfun,
Vector &elvect)
{
MFEM_PERF_BEGIN("AssembleElementVector");
const int ndof = el.GetDof();
const int ndim = el.GetDim();
const int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
int order = 2 * el.GetOrder() + trans.OrderGrad(&el);
const IntegrationRule &ir(IntRules.Get(el.GetGeomType(), order));
Vector shapef(ndof);
DenseMatrix dshape_iso(ndof, ndim);
DenseMatrix dshape_xyz(ndof, spaceDim);
Vector grad(spaceDim);
Vector lvec(ndof);
elvect.SetSize(ndof);
elvect = 0.0;
double w;
double detJ;
double nrgrad;
double aa;
double ppp = 2.0;
double eee = 0.0;
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w * w);
w = ip.weight * w; //w;
el.CalcDShape(ip, dshape_iso);
el.CalcShape(ip, shapef);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
// dshape_xyz should be divided by detJ for obtaining the real value
// calculate the gradient
dshape_xyz.MultTranspose(elfun, grad);
nrgrad = grad.Norml2() / detJ;
// grad is not scaled so far, i.e., grad=grad/detJ
// set the power
if (pp != nullptr)
{
ppp = pp->Eval(trans, ip);
}
// set the coefficient ensuring positiveness of the tangent matrix
if (coeff != nullptr)
{
eee = coeff->Eval(trans, ip);
}
aa = nrgrad * nrgrad + eee * eee;
aa = std::pow(aa, (ppp - 2.0) / 2.0);
dshape_xyz.Mult(grad, lvec);
elvect.Add(w * aa / (detJ * detJ), lvec);
// add loading
if (load != nullptr)
{
elvect.Add(-w * load->Eval(trans, ip), shapef);
}
} // end integration loop
MFEM_PERF_END("AssembleElementVector");
}
virtual void AssembleElementGrad(const FiniteElement &el,
ElementTransformation &trans,
const Vector &elfun,
DenseMatrix &elmat)
{
MFEM_PERF_BEGIN("AssembleElementGrad");
const int ndof = el.GetDof();
const int ndim = el.GetDim();
const int spaceDim = trans.GetSpaceDim();
bool square = (ndim == spaceDim);
int order = 2 * el.GetOrder() + trans.OrderGrad(&el);
const IntegrationRule &ir(IntRules.Get(el.GetGeomType(), order));
DenseMatrix dshape_iso(ndof, ndim);
DenseMatrix dshape_xyz(ndof, spaceDim);
elmat.SetSize(ndof, ndof);
elmat = 0.0;
double w;
double detJ;
double ppp = 2.0;
double eee = 0.0;
mfem::Vector param(3); param=0.0;
// Computes the residual at an integration point. The implementation is a
// copy of the integration loop in AssembleElementVector.
auto resfun = [&](mfem::Vector& vparam, mfem::ad::ADVectorType& uu,
mfem::ad::ADVectorType& vres)
{
vres.SetSize(uu.Size()); vres=0.0;
mfem::ad::ADVectorType grad(spaceDim);
mfem::ad::ADFloatType nrgrad;
mfem::ad::ADFloatType aa;
mfem::ad::ADVectorType lvec(ndof);
for (int i = 0; i < ir.GetNPoints(); i++)
{
lvec=0.0;
const IntegrationPoint &ip = ir.IntPoint(i);
trans.SetIntPoint(&ip);
w = trans.Weight();
detJ = (square ? w : w * w);
w = ip.weight * w;
el.CalcDShape(ip, dshape_iso);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
// dshape_xyz should be divided by detJ for obtaining the real value
// grad is not scaled so far,i.e., grad=grad/detJ
// set the power
if (pp != nullptr)
{
ppp = pp->Eval(trans, ip);
}
// set the coefficient ensuring positiveness of the tangent matrix
if (coeff != nullptr)
{
eee = coeff->Eval(trans, ip);
}
grad=0.0;
// calculate the gradient
for (int i=0; i<spaceDim; i++)
{
for (int j=0; j<ndof; j++)
{
grad[i]= grad[i]+ dshape_xyz(j,i)*uu[j];
}
}
nrgrad= (grad*grad)/(detJ*detJ);
aa = nrgrad + eee * eee;
aa = pow(aa, (ppp - 2.0) / 2.0);
for (int i=0; i<spaceDim; i++)
{
for (int j=0; j<ndof; j++)
{
lvec[j] = lvec[j] + dshape_xyz(j,i) * grad[i];
}
}
for (int j=0; j<ndof; j++)
{
vres[j]=vres[j] + lvec[j] * (w*aa/(detJ*detJ));
}
}
};
mfem::Vector bla(elfun);
// calculate the gradient - only for a fixed ndof
mfem::VectorFuncAutoDiff<sizeres,sizeres,3> fdr(resfun);
fdr.Jacobian(param, bla, elmat);
MFEM_PERF_END("AssembleElementGrad");
}
};
} // namespace mfem
#endif
-650
View File
@@ -1,650 +0,0 @@
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef FDUAL_H
#define FDUAL_H
#include <cmath>
#include <type_traits>
namespace mfem
{
namespace ad
{
/** The FDualNumber template class provides forward automatic differentiation
(see https://en.wikipedia.org/wiki/Automatic_differentiation) implementation
based on dual numbers.
The derivative of an arbitrary function double f(double a) can be obtained
by replacing the double type for the return value and the argument a with
FDualNumber<double>, i.e., FDualNumber<double> f(FDualNumber<double> a). The
derivative is evaluated automatically by calling the function r=f(a). The
value of the function is stored in r.pr and the derivative in r.du. These
can be extracted by the corresponding methods real()/prim() and dual().
Internally, the function f can be composed of standard functions predefined
for FDualNumber type. These consist of a large set of functions replicating
the functionality of the standard math library, i.e., sin, cos, exp, log,
etc. New functions (non-member) can be equally added to the class. Example:
\code{.cpp}
template<typename tbase>
inline FDualNumber<tbase> cos(const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(cos(f.real()), -f.dual() * sin(f.real()));
}
\endcode
The real part of the return value consists of the standard real value of the
function, i.e., cos(f.real()).
The dual part of the return value consists of the first derivative of the
function with respect to the real part of the argument -sin(f.reaf)
multiplied with the dual part of the argument f.dual().
*/
template<typename tbase>
class FDualNumber
{
private:
/// Real value
tbase pr;
/// Dual value holding derivative information
tbase du;
public:
/// Standard constructor - both values are set to zero.
FDualNumber() : pr(0), du(0) {}
/// The constructor utilized in nested definition of dual numbers. It is
/// used for second and higher order derivatives.
template<class fltyp,
class = typename std::enable_if<std::is_arithmetic<fltyp>::value>::type>
FDualNumber(fltyp &f) : pr(f), du(0)
{}
/// The constructor utilized in nested definition of dual numbers. It is
/// used for second and higher order derivatives.
template<class fltyp,
class = typename std::enable_if<std::is_arithmetic<fltyp>::value>::type>
FDualNumber(const fltyp &f) : pr(f), du(0)
{}
/// Standard constructor with user supplied input for both parts of the dual
/// number.
FDualNumber(tbase &pr_, tbase &du_) : pr(pr_), du(du_) {}
/// Standard constructor with user supplied input for both parts of the dual
/// number.
FDualNumber(const tbase &pr_, const tbase &du_) : pr(pr_), du(du_) {}
/// Standard constructor with user supplied dual number.
FDualNumber(FDualNumber<tbase> &nm) : pr(nm.pr), du(nm.du) {}
/// Standard constructor with user supplied dual number.
FDualNumber(const FDualNumber<tbase> &nm) : pr(nm.pr), du(nm.du) {}
/// Return the real value of the dual number.
tbase prim() const { return pr; }
/// Same as prim(). Return the real value of the dual number.
tbase real() const { return pr; }
/// Return the dual value of the dual number.
tbase dual() const { return du; }
/// Set the primal and the dual values.
void set(const tbase &pr_, const tbase &du_)
{
pr = pr_;
du = du_;
}
/// Set the primal value.
void prim(const tbase &pr_) { pr = pr_; }
/// Set the primal value.
void real(const tbase &pr_) { pr = pr_; }
/// Set the dual value.
void dual(const tbase &du_) { du = du_; }
/// Set the primal value.
void setReal(const tbase &pr_) { pr = pr_; }
/// Set the dual value.
void setDual(const tbase &du_) { du = du_; }
/// operator =
FDualNumber<tbase> &operator=(tbase sc_)
{
pr = sc_;
du = tbase(0);
return *this;
}
/// operator +=
FDualNumber<tbase> &operator+=(tbase sc_)
{
pr = pr + sc_;
return *this;
}
/// operator -=
FDualNumber<tbase> &operator-=(tbase sc_)
{
pr = pr - sc_;
return *this;
}
/// operator *=
FDualNumber<tbase> &operator*=(tbase sc_)
{
pr = pr * sc_;
du = du * sc_;
return *this;
}
/// operator /=
FDualNumber<tbase> &operator/=(tbase sc_)
{
pr = pr / sc_;
du = du / sc_;
return *this;
}
/// operator =
FDualNumber<tbase> &operator=(const FDualNumber<tbase> &f)
{
pr = f.real();
du = f.dual();
return *this;
}
/// operator +=
FDualNumber<tbase> &operator+=(const FDualNumber<tbase> &f)
{
pr += f.real();
du += f.dual();
return *this;
}
/// operator -=
FDualNumber<tbase> &operator-=(const FDualNumber<tbase> &f)
{
pr -= f.real();
du -= f.dual();
return *this;
}
/// operator *=
FDualNumber<tbase> &operator*=(const FDualNumber<tbase> &f)
{
du = du * f.real();
du = du + pr * f.dual();
pr = pr * f.real();
return *this;
}
/// operator /=
FDualNumber<tbase> &operator/=(const FDualNumber<tbase> &f_)
{
pr = pr / f_.real();
du = du - pr * f_.dual();
du = du / f_.real();
return *this;
}
};
/// non-member functions
/// boolean operation ==
template<typename tbase>
inline bool operator==(const FDualNumber<tbase> &a1,
const FDualNumber<tbase> &a2)
{
return a1.real() == a2.real();
}
/// boolean operation ==
template<typename tbase>
inline bool operator==(tbase a, const FDualNumber<tbase> &f_)
{
return a == f_.real();
}
/// boolean operation ==
template<typename tbase>
inline bool operator==(const FDualNumber<tbase> &a, tbase b)
{
return a.real() == b;
}
/// boolean operation <
template<typename tbase>
inline bool operator<(const FDualNumber<tbase> &f1,
const FDualNumber<tbase> &f2)
{
return f1.real() < f2.real();
}
/// boolean operation <
template<typename tbase>
inline bool operator<(const FDualNumber<tbase> &f, tbase a)
{
return f.real() < a;
}
/// boolean operation <
template<typename tbase>
inline bool operator<(tbase a, const FDualNumber<tbase> &f)
{
return a < f.real();
}
/// boolean operation >
template<typename tbase>
inline bool operator>(const FDualNumber<tbase> &f1,
const FDualNumber<tbase> &f2)
{
return f1.real() > f2.real();
}
/// boolean operation >
template<typename tbase>
inline bool operator>(const FDualNumber<tbase> &f, tbase a)
{
return f.real() > a;
}
/// boolean operation >
template<typename tbase>
inline bool operator>(tbase a, const FDualNumber<tbase> &f)
{
return (a > f.real());
}
/// Negate the real and the dual parts.
template<typename tbase>
inline FDualNumber<tbase> operator-(const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(-f.real(), -f.dual());
}
/// [dual number] - [base number]
template<typename tbase>
inline FDualNumber<tbase> operator-(const FDualNumber<tbase> &f, tbase a)
{
return FDualNumber<tbase>(f.real() - a, f.dual());
}
/// [dual number<dual number>] - [base number]
template<typename tbase>
inline FDualNumber<FDualNumber<tbase>> operator-(const
FDualNumber<FDualNumber<tbase>> &f, tbase a)
{
return FDualNumber<FDualNumber<tbase>>(f.real() - a, f.dual());
}
/// [dual number] + [base number]
template<typename tbase>
inline FDualNumber<tbase> operator+(const FDualNumber<tbase> &f, tbase a)
{
return FDualNumber<tbase>(f.real() + a, f.dual());
}
/// [dual number<dual number>] + [base number]
template<typename tbase>
inline FDualNumber<FDualNumber<tbase>> operator+(const
FDualNumber<FDualNumber<tbase>> &f, tbase a)
{
return FDualNumber<FDualNumber<tbase>>(f.real() + a, f.dual());
}
/// [dual number] * [base number]
template<typename tbase>
inline FDualNumber<tbase> operator*(const FDualNumber<tbase> &f, tbase a)
{
return FDualNumber<tbase>(f.real() * a, f.dual() * a);
}
/// [dual number] / [base number]
template<typename tbase>
inline FDualNumber<tbase> operator/(const FDualNumber<tbase> &f, tbase a)
{
return FDualNumber<tbase>(f.real() / a, f.dual() / a);
}
/// [dual number<dual number>] / [base number]
template<typename tbase>
inline FDualNumber<FDualNumber<tbase>> operator/(const
FDualNumber<FDualNumber<tbase>> &f, tbase a)
{
return FDualNumber<FDualNumber<tbase>>(f.real() / a, f.dual() / a);
}
/// [base number] + [dual number]
template<typename tbase>
inline FDualNumber<tbase> operator+(tbase a, const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(a + f.real(), f.dual());
}
/// [base number] + [dual number<dual number>]
template<typename tbase>
inline FDualNumber<FDualNumber<tbase>> operator+(tbase a,
const FDualNumber<FDualNumber<tbase>> &f)
{
return FDualNumber<FDualNumber<tbase>>(a + f.real(), f.dual());
}
/// [base number] - [dual number]
template<typename tbase>
inline FDualNumber<tbase> operator-(tbase a, const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(a - f.real(), -f.dual());
}
/// [base number] - [dual number<dual number>]
template<typename tbase>
inline FDualNumber<FDualNumber<tbase>> operator-(tbase a,
const FDualNumber<FDualNumber<tbase>> &f)
{
return FDualNumber<FDualNumber<tbase>>(a - f.real(), -f.dual());
}
/// [base number] * [dual number]
template<typename tbase>
inline FDualNumber<tbase> operator*(tbase a, const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(f.real() * a, f.dual() * a);
}
/// [base number] * [dual number<dual number>]
template<typename tbase>
inline FDualNumber<FDualNumber<tbase>> operator*(tbase a,
const FDualNumber<FDualNumber<tbase>> &f)
{
return FDualNumber<FDualNumber<tbase>>(f.real() * a, f.dual() * a);
}
/// [base number] / [dual number]
template<typename tbase>
inline FDualNumber<tbase> operator/(tbase a, const FDualNumber<tbase> &f)
{
a = a / f.real();
return FDualNumber<tbase>(a, -a * f.dual() / f.real());
}
/// [dual number] + [dual number]
template<typename tbase>
inline FDualNumber<tbase> operator+(const FDualNumber<tbase> &f1,
const FDualNumber<tbase> &f2)
{
return FDualNumber<tbase>(f1.real() + f2.real(), f1.dual() + f2.dual());
}
/// [dual number] - [dual number]
template<typename tbase>
inline FDualNumber<tbase> operator-(const FDualNumber<tbase> &f1,
const FDualNumber<tbase> &f2)
{
return FDualNumber<tbase>(f1.real() - f2.real(), f1.dual() - f2.dual());
}
/// [dual number] * [dual number]
template<typename tbase>
inline FDualNumber<tbase> operator*(const FDualNumber<tbase> &f1,
const FDualNumber<tbase> &f2)
{
return FDualNumber<tbase>(f1.real() * f2.real(),
f1.real() * f2.dual() + f1.dual() * f2.real());
}
/// [dual number] / [dual number]
template<typename tbase>
inline FDualNumber<tbase> operator/(const FDualNumber<tbase> &f1,
const FDualNumber<tbase> &f2)
{
tbase a = tbase(1) / f2.real();
tbase b = f1.real() * a;
return FDualNumber<tbase>(b, (f1.dual() - f2.dual() * b) * a);
}
/// acos([dual number])
template<typename tbase>
inline FDualNumber<tbase> acos(const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(acos(f.real()),
-f.dual() / sqrt(tbase(1) - f.real() * f.real()));
}
/// acos([dual number<double>])
template<>
inline FDualNumber<double> acos(const FDualNumber<double> &f)
{
return FDualNumber<double>(std::acos(f.real()),
-f.dual() / std::sqrt(double(1) - f.real() * f.real()));
}
/// asin([dual number])
template<typename tbase>
inline FDualNumber<tbase> asin(const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(asin(f.real()),
f.dual() / sqrt(tbase(1) - f.real() * f.real()));
}
/// asin([dual number<double>])
template<>
inline FDualNumber<double> asin(const FDualNumber<double> &f)
{
return FDualNumber<double>(std::asin(f.real()),
f.dual() / std::sqrt(double(1) - f.real() * f.real()));
}
/// atan([dual number])
template<typename tbase>
inline FDualNumber<tbase> atan(const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(atan(f.real()),
f.dual() / (tbase(1) + f.real() * f.real()));
}
/// atan([dual number<double>])
template<>
inline FDualNumber<double> atan(const FDualNumber<double> &f)
{
return FDualNumber<double>(std::atan(f.real()),
f.dual() / (double(1) + f.real() * f.real()));
}
/// cos([dual number])
template<typename tbase>
inline FDualNumber<tbase> cos(const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(cos(f.real()), -f.dual() * sin(f.real()));
}
/// cos([dual number<double>])
template<>
inline FDualNumber<double> cos(const FDualNumber<double> &f)
{
return FDualNumber<double>(std::cos(f.real()), -f.dual() * std::sin(f.real()));
}
/// cosh([dual number])
template<typename tbase>
inline FDualNumber<tbase> cosh(const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(cosh(f.real()), f.dual() * sinh(f.real()));
}
/// cosh([dual number<double>])
template<>
inline FDualNumber<double> cosh(const FDualNumber<double> &f)
{
return FDualNumber<double>(std::cosh(f.real()), f.dual() * std::sinh(f.real()));
}
/// exp([dual number])
template<typename tbase>
inline FDualNumber<tbase> exp(const FDualNumber<tbase> &f)
{
tbase x = exp(f.real());
return FDualNumber<tbase>(x, f.dual() * x);
}
/// exp([dual number<double>])
template<>
inline FDualNumber<double> exp(const FDualNumber<double> &f)
{
double x = std::exp(f.real());
return FDualNumber<double>(x, f.dual() * x);
}
/// log([dual number])
template<typename tbase>
inline FDualNumber<tbase> log(const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(log(f.real()), f.dual() / f.real());
}
/// log([dual number<double>])
template<>
inline FDualNumber<double> log(const FDualNumber<double> &f)
{
return FDualNumber<double>(std::log(f.real()), f.dual() / f.real());
}
/// log10([dual number])
template<typename tbase>
inline FDualNumber<tbase> log10(const FDualNumber<tbase> &f)
{
return log(f) / log(tbase(10));
}
/// log10([dual number<double>])
template<>
inline FDualNumber<double> log10(const FDualNumber<double> &f)
{
return log(f) / std::log(double(10));
}
/// pow([dual number],[dual number])
template<typename tbase>
inline FDualNumber<tbase> pow(const FDualNumber<tbase> &a,
const FDualNumber<tbase> &b)
{
return exp(log(a) * b);
}
/// pow([dual number], [base number])
template<typename tbase, typename tbase1>
inline FDualNumber<tbase> pow(const FDualNumber<tbase> &a, const tbase1 &b)
{
return exp(log(a) * tbase(b));
}
/// pow([base number], [dual number])
template<typename tbase, typename tbase1>
inline FDualNumber<tbase> pow(const tbase1 &a, const FDualNumber<tbase> &b)
{
return exp(log(tbase(a)) * b);
}
/// pow([base number], [dual number<double>])
template<>
inline FDualNumber<double> pow(const double &a, const FDualNumber<double> &b)
{
return exp(std::log(a) * b);
}
/// sin([dual number])
template<typename tbase>
inline FDualNumber<tbase> sin(const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(sin(f.real()), f.dual() * cos(f.real()));
}
/// sin([dual number<double>])
template<>
inline FDualNumber<double> sin(const FDualNumber<double> &f)
{
return FDualNumber<double>(std::sin(f.real()), f.dual() * std::cos(f.real()));
}
/// sinh([dual number])
template<typename tbase>
inline FDualNumber<tbase> sinh(const FDualNumber<tbase> &f)
{
return FDualNumber<tbase>(sinh(f.real()), f.dual() * cosh(f.real()));
}
/// sinh([dual number<double>])
template<>
inline FDualNumber<double> sinh(const FDualNumber<double> &f)
{
return FDualNumber<double>(std::sinh(f.real()), f.dual() * std::cosh(f.real()));
}
/// sqrt([dual number])
template<typename tbase>
inline FDualNumber<tbase> sqrt(const FDualNumber<tbase> &f)
{
tbase a = sqrt(f.real());
return FDualNumber<tbase>(a, f.dual() / (tbase(2) * a));
}
/// sqrt([dual number<double>])
template<>
inline FDualNumber<double> sqrt(const FDualNumber<double> &f)
{
double a = std::sqrt(f.real());
return FDualNumber<double>(a, f.dual() / (double(2) * a));
}
/// tan([dual number])
template<typename tbase>
inline FDualNumber<tbase> tan(const FDualNumber<tbase> &f)
{
tbase a = tan(f.real());
return FDualNumber<tbase>(a, f.dual() * (tbase(1) + a * a));
}
/// tan([dual number<double>])
template<>
inline FDualNumber<double> tan(const FDualNumber<double> &f)
{
double a = std::tan(f.real());
return FDualNumber<double>(a, f.dual() * (double(1) + a * a));
}
/// tanh([dual number])
template<typename tbase>
inline FDualNumber<tbase> tanh(const FDualNumber<tbase> &f)
{
tbase a = tanh(f.real());
return FDualNumber<tbase>(a, f.dual() * (tbase(1) - a * a));
}
/// tanh([dual number<double>])
template<>
inline FDualNumber<double> tanh(const FDualNumber<double> &f)
{
double a = std::tanh(f.real());
return FDualNumber<double>(a, f.dual() * (double(1) - a * a));
}
} // namespace ad
} // namespace mfem
#endif
-79
View File
@@ -1,79 +0,0 @@
# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/autodiff/,)
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
# Include defaults.mk to get XLINKER
DEFAULTS_MK = $(MFEM_DIR)/config/defaults.mk
include $(DEFAULTS_MK)
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
ADIFF_COMMON_SRC =
ADIFF_COMMON_OBJ = $(ADIFF_COMMON_SRC:.cpp=.o)
SEQ_MINIAPPS = seq_example seq_test
PAR_MINIAPPS = par_example
ifeq ($(MFEM_USE_MPI),NO)
MINIAPPS = $(SEQ_MINIAPPS)
else
MINIAPPS = $(PAR_MINIAPPS) $(SEQ_MINIAPPS)
endif
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all clean clean-build clean-exec
# Remove built-in rules
%: %.cpp
%.o: %.cpp
%: %.o $(ADIFF_COMMON_OBJ)
$(MFEM_CXX) $(MFEM_LINK_FLAGS) $^ -o $@ $(MFEM_LIBS)
%.o: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@
all: $(MINIAPPS)
MFEM_TESTS = MINIAPPS
include $(MFEM_TEST_MK)
# Testing: Parallel vs. serial runs
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
TEST_NAME := ADIFF miniapp
%-test-par: %
@$(call mfem-test,$<, $(RUN_MPI), $(TEST_NAME))
%-test-seq: %
@$(call mfem-test,$<,, $(TEST_NAME))
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
# Generate an error message if the MFEM library is not built and exit
$(MFEM_LIB_FILE):
$(error The MFEM library is not built)
clean: clean-build clean-exec
clean-build:
rm -f *.o *~ $(SEQ_MINIAPPS) $(PAR_MINIAPPS)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -rf Example*
-553
View File
@@ -1,553 +0,0 @@
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
//
// MFEM AD Example - Parallel Version
//
// Compile with: make par_example
//
// Sample runs: mpirun -np 2 par_example -m ../data/beam-quad.mesh -pp 3.8
// mpirun -np 2 par_example -m ../data/beam-tri.mesh -pp 7.2
// mpirun -np 2 par_example -m ../data/beam-hex.mesh
// mpirun -np 2 par_example -m ../data/beam-tet.mesh
// mpirun -np 2 par_example -m ../data/beam-wedge.mesh
//
// Description: This examples solves a quasi-static nonlinear p-Laplacian
// problem with zero Dirichlet boundary conditions applied on all
// defined boundaries
//
// The example demonstrates the use of nonlinear operators
// combined with automatic differentiation (AD). The integrators
// are defined in example.hpp. Selecting integrator = 0 will use
// the manually implemented integrator. Selecting integrator = 1
// or 2 will utilize one of the AD integrators.
//
// We recommend viewing examples 1 and 19, before viewing this
// example.
#include "example.hpp"
using namespace mfem;
enum IntegratorType
{
HandCodedIntegrator = 0,
ADJacobianIntegrator = 1,
ADHessianIntegrator = 2
};
/// Non-linear solver for the p-Laplacian problem.
class ParNLSolverPLaplacian
{
public:
/// Constructor Input: imesh - FE mesh, finite element space, power for the
/// p-Laplacian, external load (source, input), regularization parameter
ParNLSolverPLaplacian(MPI_Comm comm, ParMesh& imesh,
ParFiniteElementSpace& ifespace,
double powerp=2,
Coefficient* load=nullptr,
double regularizationp=1e-7)
{
lcomm = comm;
// default parameters for the Newton solver
newton_rtol = 1e-4;
newton_atol = 1e-8;
newton_iter = 10;
// linear solver
linear_rtol = 1e-7;
linear_atol = 1e-15;
linear_iter = 500;
print_level = 0;
// set the mesh
mesh=&imesh;
// set the fespace
fespace=&ifespace;
// set the parameters
plap_epsilon=new ConstantCoefficient(regularizationp);
plap_power=new ConstantCoefficient(powerp);
if (load==nullptr)
{
plap_input=new ConstantCoefficient(1.0);
input_ownership=true;
}
else
{
plap_input=load;
input_ownership=false;
}
nlform=nullptr;
nsolver=nullptr;
gmres=nullptr;
prec=nullptr;
// set the default integrator
integ=IntegratorType::HandCodedIntegrator;
}
~ParNLSolverPLaplacian()
{
delete nlform;
delete nsolver;
delete prec;
delete gmres;
if (input_ownership) { delete plap_input;}
delete plap_epsilon;
delete plap_power;
}
/// Set the integrator.
/// 0 - hand coded, 1 - AD based (compute only Hessian by AD),
/// 2 - AD based (compute residual and Hessian by AD)
void SetIntegrator(IntegratorType intr)
{
integ=intr;
}
// set relative tolerance for the Newton solver
void SetNRRTol(double rtol)
{
newton_rtol=rtol;
}
// set absolute tolerance for the Newton solver
void SetNRATol(double atol)
{
newton_atol=atol;
}
// set max iterations for the NR solver
void SetMaxNRIter(int miter)
{
newton_iter=miter;
}
void SetLSRTol(double rtol)
{
linear_rtol=rtol;
}
void SetLSATol(double atol)
{
linear_atol=atol;
}
// set max iterations for the linear solver
void SetMaxLSIter(int miter)
{
linear_iter=miter;
}
// set the print level
void SetPrintLevel(int plev)
{
print_level=plev;
}
/// The state vector is used as initial condition for the NR solver. On
/// return the statev holds the solution to the problem.
void Solve(Vector& statev)
{
if (nlform==nullptr)
{
AllocSolvers();
}
Vector b; // RHS is zero
nsolver->Mult(b, statev);
}
/// Compute the energy
double GetEnergy(Vector& statev)
{
if (nlform==nullptr)
{
// allocate the solvers
AllocSolvers();
}
return nlform->GetEnergy(statev);
}
private:
void AllocSolvers()
{
if (nlform!=nullptr) { delete nlform;}
if (nsolver!=nullptr) { delete nsolver;}
if (gmres!=nullptr) { delete gmres;}
if (prec!=nullptr) { delete prec;}
// Define the essential boundary attributes
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
nlform = new ParNonlinearForm(fespace);
if (integ==IntegratorType::HandCodedIntegrator)
{
nlform->AddDomainIntegrator(new pLaplace(*plap_power,*plap_epsilon,
*plap_input));
}
else if (integ==IntegratorType::ADJacobianIntegrator)
{
// The template integrator is based on automatic differentiation. For
// ADJacobianIntegrator the residual (vector function) at an
// integration point is implemented as a functor by MyResidualFunctor.
// The vector function has a return size of four(4), four state
// arguments, and three(3) parameters. MyResidualFunctor is a template
// argument to the actual template class performing the differentiation
// - in this case, QVectorFuncAutoDiff. The derivatives are used in the
// integration loop in the integrator pLaplaceAD.
nlform->AddDomainIntegrator(new
pLaplaceAD<mfem::QVectorFuncAutoDiff<MyResidualFunctor,4,4,3>>(*plap_power,
*plap_epsilon,*plap_input));
}
else if (integ==IntegratorType::ADHessianIntegrator)
{
// The main difference from the previous case is that the user has to
// implement only a functional evaluation at an integration point. The
// implementation is in MyEnergyFunctor, which takes four state
// arguments and three parameters. The residual vector is the first
// derivative of the energy/functional with respect to the state
// variables, and the Hessian is the second derivative. Automatic
// differentiation is used for evaluating both of them.
nlform->AddDomainIntegrator(new
pLaplaceAD<mfem::QFunctionAutoDiff<MyEnergyFunctor,4,3>>(*plap_power,
*plap_epsilon,*plap_input));
}
nlform->SetEssentialBC(ess_bdr);
prec = new HypreBoomerAMG();
prec->SetPrintLevel(print_level);
gmres = new GMRESSolver(lcomm);
gmres->SetAbsTol(linear_atol);
gmres->SetRelTol(linear_rtol);
gmres->SetMaxIter(linear_iter);
gmres->SetPrintLevel(print_level);
gmres->SetPreconditioner(*prec);
nsolver = new NewtonSolver(lcomm);
nsolver->iterative_mode = true;
nsolver->SetSolver(*gmres);
nsolver->SetOperator(*nlform);
nsolver->SetPrintLevel(print_level);
nsolver->SetRelTol(newton_rtol);
nsolver->SetAbsTol(newton_atol);
nsolver->SetMaxIter(newton_iter);
}
double newton_rtol;
double newton_atol;
int newton_iter;
double linear_rtol;
double linear_atol;
int linear_iter;
int print_level;
// power of the p-laplacian
Coefficient* plap_power;
// regularization parameter
Coefficient* plap_epsilon;
// load(input) parameter
Coefficient* plap_input;
// flag indicating the ownership of plap_input
bool input_ownership;
MPI_Comm lcomm;
ParMesh *mesh;
ParFiniteElementSpace *fespace;
ParNonlinearForm *nlform;
HypreBoomerAMG *prec;
GMRESSolver *gmres;
NewtonSolver *nsolver;
IntegratorType integ;
};
int main(int argc, char *argv[])
{
// 1. Initialize MPI
int num_procs, myrank;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
// Define Caliper ConfigManager
#ifdef MFEM_USE_CALIPER
cali::ConfigManager mgr;
#endif
// Caliper instrumentation
MFEM_PERF_FUNCTION;
// 2. Parse command-line options
const char *mesh_file = "../../data/beam-tet.mesh";
int ser_ref_levels = 3;
int par_ref_levels = 1;
int order = 1;
bool visualization = true;
double newton_rel_tol = 1e-4;
double newton_abs_tol = 1e-6;
int newton_iter = 10;
int print_level = 0;
double pp = 2.0; // p-Laplacian power
IntegratorType integrator = IntegratorType::ADHessianIntegrator;
int int_integrator = integrator;
// HandCodedIntegrator = 0 - do not use AD (hand coded)
// ADJacobianIntegrator = 1 - use AD for Hessian only
// ADHessianIntegrator = 2 - use AD for Residual and Hessian
const char* cali_config = "runtime-report";
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",
"Order (degree) of the finite elements.");
args.AddOption(&visualization,
"-vis",
"--visualization",
"-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&newton_rel_tol,
"-rel",
"--relative-tolerance",
"Relative tolerance for the Newton solve.");
args.AddOption(&newton_abs_tol,
"-abs",
"--absolute-tolerance",
"Absolute tolerance for the Newton solve.");
args.AddOption(&newton_iter,
"-it",
"--newton-iterations",
"Maximum iterations for the Newton solve.");
args.AddOption(&pp,
"-pp",
"--power-parameter",
"Power parameter (>=2.0) for the p-Laplacian.");
args.AddOption((&print_level), "-prt", "--print-level", "Print level.");
args.AddOption(&int_integrator,
"-int",
"--integrator",
"Integrator 0: standard; 1: AD for Hessian; 2: AD for residual and Hessian");
args.AddOption(&cali_config, "-p", "--caliper",
"Caliper configuration string.");
args.Parse();
if (!args.Good())
{
if (myrank == 0)
{
args.PrintUsage(std::cout);
}
MPI_Finalize();
return 1;
}
if (myrank == 0)
{
args.PrintOptions(std::cout);
}
integrator = static_cast<IntegratorType>(int_integrator);
StopWatch *timer = new StopWatch();
// Caliper configuration
#ifdef MFEM_USE_CALIPER
mgr.add(cali_config);
mgr.start();
#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.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. Refine the mesh in serial to increase the resolution. In this example
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
// a command-line parameter.
for (int lev = 0; lev < ser_ref_levels; lev++)
{
mesh->UniformRefinement();
}
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
for (int lev = 0; lev < par_ref_levels; lev++)
{
pmesh->UniformRefinement();
}
// 6. Define the load for the p-Laplacian
ConstantCoefficient load(1.00);
// 7. Define the finite element spaces for the solution
H1_FECollection fec(order, dim);
ParFiniteElementSpace fespace(pmesh, &fec, 1, Ordering::byVDIM);
HYPRE_Int glob_size = fespace.GlobalTrueVSize();
if (myrank == 0)
{
std::cout << "Number of finite element unknowns: " << glob_size
<< std::endl;
}
// 8. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(&fespace);
x = 0.0;
HypreParVector *sv = x.GetTrueDofs();
// 9. Define ParaView DataCollection
ParaViewDataCollection *dacol = new ParaViewDataCollection("Example",
pmesh);
dacol->SetLevelsOfDetail(order);
dacol->RegisterField("sol", &x);
// 10. Define the NR solver
ParNLSolverPLaplacian* nr;
// 11. Start with linear diffusion - solvable for any initial guess
nr=new ParNLSolverPLaplacian(MPI_COMM_WORLD,*pmesh, fespace, 2.0, &load);
nr->SetIntegrator(integrator);
nr->SetMaxNRIter(newton_iter);
nr->SetNRATol(newton_abs_tol);
nr->SetNRRTol(newton_rel_tol);
nr->SetPrintLevel(print_level);
timer->Clear();
timer->Start();
nr->Solve(*sv);
timer->Stop();
if (myrank==0)
{
std::cout << "[pp=2] The solution time is: " << timer->RealTime()
<< std::endl;
}
// Compute the energy
double energy = nr->GetEnergy(*sv);
if (myrank==0)
{
std::cout << "[pp=2] The total energy of the system is E=" << energy
<< std::endl;
}
delete nr;
x.SetFromTrueDofs(*sv);
dacol->SetTime(2.0);
dacol->SetCycle(2);
dacol->Save();
// 12. Continue with powers higher than 2
for (int i = 3; i < pp; i++)
{
nr=new ParNLSolverPLaplacian(MPI_COMM_WORLD,*pmesh, fespace, (double)i, &load);
nr->SetIntegrator(integrator);
nr->SetMaxNRIter(newton_iter);
nr->SetNRATol(newton_abs_tol);
nr->SetNRRTol(newton_rel_tol);
nr->SetPrintLevel(print_level);
timer->Clear();
timer->Start();
nr->Solve(*sv);
timer->Stop();
if (myrank==0)
{
std::cout << "[pp="<<i<<"] The solution time is: " << timer->RealTime()
<< std::endl;
}
// Compute the energy
double energy = nr->GetEnergy(*sv);
if (myrank==0)
{
std::cout << "[pp="<<i<<"] The total energy of the system is E=" << energy
<< std::endl;
}
delete nr;
x.SetFromTrueDofs(*sv);
dacol->SetTime((double)i);
dacol->SetCycle(i);
dacol->Save();
}
// 13. Continue with the final power
if (std::abs(pp - 2.0) > std::numeric_limits<double>::epsilon())
{
nr=new ParNLSolverPLaplacian(MPI_COMM_WORLD,*pmesh, fespace, pp, &load);
nr->SetIntegrator(integrator);
nr->SetMaxNRIter(newton_iter);
nr->SetNRATol(newton_abs_tol);
nr->SetNRRTol(newton_rel_tol);
nr->SetPrintLevel(print_level);
timer->Clear();
timer->Start();
nr->Solve(*sv);
timer->Stop();
if (myrank==0)
{
std::cout << "[pp="<<pp<<"] The solution time is: " << timer->RealTime()
<< std::endl;
}
// Compute the energy
double energy = nr->GetEnergy(*sv);
if (myrank==0)
{
std::cout << "[pp="<<pp<<"] The total energy of the system is E=" << energy
<< std::endl;
}
delete nr;
x.SetFromTrueDofs(*sv);
dacol->SetTime(pp);
if (pp < 2.0)
{
dacol->SetCycle(std::floor(pp));
}
else
{
dacol->SetCycle(std::ceil(pp));
}
dacol->Save();
}
// 14. Free the used memory
delete dacol;
delete sv;
delete pmesh;
delete timer;
// Flush output before MPI_finalize
#ifdef MFEM_USE_CALIPER
mgr.flush();
#endif
MPI_Finalize();
return 0;
}

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