Compare commits

..
170 changed files with 61894 additions and 8816 deletions
-11
View File
@@ -272,27 +272,16 @@ miniapps/navier/*_output
miniapps/nurbs/nurbs_ex1
miniapps/nurbs/nurbs_ex1p
miniapps/nurbs/nurbs_ex3
miniapps/nurbs/nurbs_ex5
miniapps/nurbs/nurbs_ex11p
miniapps/nurbs/nurbs_ex24
miniapps/nurbs/nurbs_solenoidal
miniapps/nurbs/nurbs_printfunc
miniapps/nurbs/nurbs_patch_ex1
miniapps/nurbs/nurbs_curveint
miniapps/nurbs/refined.mesh
miniapps/nurbs/mesh.*
miniapps/nurbs/sol_?.gf
miniapps/nurbs/sol.*
miniapps/nurbs/mode_*
miniapps/nurbs/Example1*
miniapps/nurbs/Example3*
miniapps/nurbs/Example5*
miniapps/nurbs/Solenoidal*
miniapps/nurbs/ParaView
miniapps/nurbs/sin-fit.mesh
miniapps/nurbs/ex5.mesh
miniapps/nurbs/exsol.mesh
miniapps/nurbs/CurveInt
miniapps/nurbs/nurbs_naca_cmesh
miniapps/nurbs/naca-cmesh.mesh
+5 -5
View File
@@ -22,7 +22,7 @@ include:
# the "needs" keyword and express the DAG of jobs for more efficiency.
# - We use setup and setup_baseline phases to download content outside of mfem
# directory.
# - Allocate/Release is where ruby resource are allocated/released once for all.
# - Allocate/Release is where quartz resource are allocated/released once for all.
# - Build and Test is where we build and MFEM for multiple toolchains.
# - Baseline_checks gathers baseline-type test suites execution
# - Baseline_publish, only available on master, allows to update baseline
@@ -53,7 +53,7 @@ variables:
AUTOTEST_COMMIT: "YES"
# Trigger subpipelines:
ruby-build-and-test:
quartz-build-and-test:
stage: sub-pipelines
variables:
# Explicitly pass down values that we want to be able to set when triggering
@@ -61,10 +61,10 @@ ruby-build-and-test:
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
trigger:
include: .gitlab/ruby-build-and-test.yml
include: .gitlab/quartz-build-and-test.yml
strategy: depend
ruby-baseline:
quartz-baseline:
stage: sub-pipelines
variables:
# Explicitly pass down values that we want to be able to set when triggering
@@ -73,7 +73,7 @@ ruby-baseline:
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
trigger:
include: .gitlab/ruby-baseline.yml
include: .gitlab/quartz-baseline.yml
strategy: depend
lassen-build-and-test:
+3 -3
View File
@@ -24,7 +24,7 @@ and `test type`.
Machines typically include:
* Ruby: 2nd Gen Intel Xeon (Cascade Lake)
* Quartz: Intel bi-socket x86
* Lassen: Power9 + Nvidia GPU
* Corona: AMD GPU
@@ -76,13 +76,13 @@ with a spack spec of MFEM, within the limits permitted by the MFEM spack
package.
In any build-and-test sub-pipeline a job basically consists in defining the
spack spec to use. Adding a job on ruby for example resumes to:
spack spec to use. Adding a job on quartz for example resumes to:
```yaml
<job_name>:
variables:
SPEC: "<spack_spec>"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_quartz
```
The remaining and non trivial work is to make sure this spec is working. To
+1 -1
View File
@@ -24,7 +24,7 @@ variables:
# TODO: add a clean-up mechanism
BUILD_ROOT: ${USER_CI_TOP_DIR}/${CI_PROJECT_NAME}-${MACHINE_NAME}-pipeline-${CI_PIPELINE_ID}
# On LLNL's ruby, there is only one allocation shared among jobs in order to
# 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}
@@ -9,17 +9,17 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# GitLab pipelines configurations for the Ruby machine at LLNL
# GitLab pipelines configurations for the Quartz machine at LLNL
variables:
MACHINE_NAME: ruby
MACHINE_NAME: quartz
.on_ruby:
.on_quartz:
tags:
- shell
- ruby
- quartz
rules:
# Don't run ruby jobs if...
- if: '$CI_COMMIT_BRANCH =~ /_qnone/ || $ON_RUBY == "OFF"'
# Don't run quartz jobs if...
- if: '$CI_COMMIT_BRANCH =~ /_qnone/ || $ON_QUARTZ == "OFF"'
when: never
# Don't run autotest update if...
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
@@ -40,13 +40,13 @@ variables:
- when: on_success
# Spack helped builds
# Generic ruby build job, extending build script
.build_and_test_on_ruby:
extends: [.on_ruby]
# Generic quartz build job, extending build script
.build_and_test_on_quartz:
extends: [.on_quartz]
stage: build_and_test
script:
# THREADS is used by 'tests/gitlab/build_and_test', run below
- export THREADS=16
- export THREADS=12
- echo ${ALLOC_NAME}
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
- echo ${JOBID}
+1 -1
View File
@@ -18,7 +18,7 @@
setup_baseline:
tags:
- shell
- ruby
- quartz
stage: setup
variables:
GIT_STRATEGY: none
+1 -1
View File
@@ -16,7 +16,7 @@
setup:
tags:
- shell
- ruby
- quartz
stage: setup
variables:
GIT_STRATEGY: none
@@ -19,8 +19,8 @@ stages:
- cleanup
- baseline_publish
baselinecheck_mfem_intel_ruby:
extends: [.on_ruby]
baselinecheck_mfem_intel_quartz:
extends: [.on_quartz]
stage: baseline_check
variables:
# TPLS_DIR is used in .gitlab/scripts/baseline to provide the tpls location
@@ -32,7 +32,7 @@ baselinecheck_mfem_intel_ruby:
- echo ${BUILD_ROOT}
- echo ${TPLS_DIR}
# Used by the tests in MFEM/tests:
- export MFEM_TEST_NP=48
- 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
@@ -44,16 +44,18 @@ baselinecheck_mfem_intel_ruby:
allow_failure: true
cleanup:
extends: .on_ruby
extends: .on_quartz
stage: cleanup
variables:
GIT_STRATEGY: none
script:
- echo "BUILD_ROOT=${BUILD_ROOT}"
- rm -rf "${BUILD_ROOT}" || true
- echo "CI_PROJECT_DIR=${CI_PROJECT_DIR}"
- make -C "${CI_PROJECT_DIR}" distclean
report_baseline:
extends: [.on_ruby]
extends: [.on_quartz]
stage: baseline_report
script:
- echo ${MACHINE_NAME}
@@ -113,8 +115,8 @@ report_baseline:
exit $err
) 9> autotest.lock
baselinepublish_mfem_ruby:
extends: [.on_ruby]
baselinepublish_mfem_quartz:
extends: [.on_quartz]
stage: baseline_publish
rules:
# - if: '$CI_COMMIT_BRANCH == "master" || $REBASELINE == "YES"'
@@ -129,5 +131,5 @@ baselinepublish_mfem_ruby:
include:
- local: .gitlab/configs/common.yml
- local: .gitlab/configs/ruby-config.yml
- local: .gitlab/configs/quartz-config.yml
- local: .gitlab/configs/setup-baseline.yml
@@ -19,54 +19,54 @@ stages:
allocate_resource:
variables:
GIT_STRATEGY: none
extends: .on_ruby
extends: .on_quartz
stage: allocate_resource
script:
- echo ${ALLOC_NAME}
- salloc --exclusive --nodes=1 --reservation=ci --time=60 --no-shell --job-name=${ALLOC_NAME}
timeout: 6h
# GitLab jobs for the Ruby machine at LLNL
# GitLab jobs for the Quartz machine at LLNL
debug_ser_gcc_10:
variables:
SPEC: "%gcc@10.3.1 +debug~mpi"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_quartz
debug_par_gcc_10:
variables:
SPEC: "%gcc@10.3.1 +debug+mpi"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_quartz
opt_ser_gcc_10:
variables:
SPEC: "%gcc@10.3.1 ~mpi"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_quartz
opt_par_gcc_10:
variables:
SPEC: "%gcc@10.3.1"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_quartz
opt_par_gcc_10_sundials:
variables:
SPEC: "%gcc@10.3.1 +sundials"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_quartz
opt_par_gcc_10_petsc:
variables:
SPEC: "%gcc@10.3.1 +petsc ^petsc+mumps~superlu-dist"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_quartz
opt_par_gcc_10_pumi:
variables:
SPEC: "%gcc@10.3.1 +pumi"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_quartz
# Release
release_resource:
variables:
GIT_STRATEGY: none
extends: .on_ruby
extends: .on_quartz
stage: release_resource_and_report
script:
- echo ${ALLOC_NAME}
@@ -78,17 +78,17 @@ release_resource:
report_job_success:
stage: release_resource_and_report
extends:
- .on_ruby
- .on_quartz
- .report_job_success
report_job_failure:
stage: release_resource_and_report
extends:
- .on_ruby
- .on_quartz
- .report_job_failure
include:
- local: .gitlab/configs/common.yml
- local: .gitlab/configs/ruby-config.yml
- local: .gitlab/configs/quartz-config.yml
- local: .gitlab/configs/setup-build-and-test.yml
- local: .gitlab/configs/report-build-and-test.yml
+4 -4
View File
@@ -14,7 +14,7 @@
# locals
glob_err=${BASELINE_TEST}.err
base=${BASELINE_TEST}-${SYS_TYPE}
if [[ "${MACHINE_NAME}" == "ruby" ]]; then
if [[ "${MACHINE_NAME}" == "quartz" ]]; then
base="${BASELINE_TEST}-${MACHINE_NAME}"
fi
base_diff=${base}.diff
@@ -31,8 +31,8 @@ cd tests
mkdir _${BASELINE_TEST} && cd _${BASELINE_TEST}
# run
if [[ "${MACHINE_NAME}" == "ruby" ]]; then
salloc --nodes=1 --exclusive --reservation=ci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
if [[ "${MACHINE_NAME}" == "quartz" || "${MACHINE_NAME}" == "ruby" ]]; then
salloc --nodes=1 --reservation=ci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
elif [[ ${MACHINE_NAME} == "corona" ]]; then
salloc --nodes=1 -t 60 -p pbatch ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
elif [[ ${MACHINE_NAME} == "lassen" ]]; then
@@ -41,11 +41,11 @@ else
echo "Unknown machine: MACHINE_NAME=$MACHINE_NAME"
exit 1
fi
status="$?"
# post
mkdir ${artifacts_path}
status=0
if [[ -f ${BASELINE_TEST}.out ]]; then
cp ${BASELINE_TEST}.out ${artifacts_path}
fi
+2 -2
View File
@@ -11,7 +11,7 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# There will be collision between corona and ruby baselines.
# There will be collision between corona and quartz baselines.
# Once the corresponding files have been generated, we can switch to machine
# specific ref.
ARTIFACT_PATH=${CI_PROJECT_DIR}/${ARTIFACTS_DIR}/baseline-${SYS_TYPE}
@@ -21,7 +21,7 @@ PATCH_FILE=${ARTIFACT_PATH}.patch
FULL_FILE=${ARTIFACT_PATH}.out
DIFF_FILE=${ARTIFACT_PATH}.diff
# There will be collision between corona and ruby baselines.
# There will be collision between corona and quartz baselines.
# Once the corresponding files have been generated, we can switch to machine
# specific ref.
SAVED_NAME=baseline-${SYS_TYPE}.saved
-22
View File
@@ -11,28 +11,9 @@
Version 4.7.1 (development)
===========================
- Refactored the `ARKStepSolver` class (ARKODE interface) to use
`TimeDependentOperator::Mult` only when the associated ODE operator is
expressed in explicit form (i.e., `TimeDependentOperator::isExplicit()`),
otherwise `TimeDependentOperator::ExplicitMult` is used. A check has been
added to `ARKStepSolver` to verify that the associated ODE operator is not in
explicit form when a mass matrix solver is enabled via a call to either the
`UseMFEMMassLinearSolver` or `UseSundialsMassLinearSolver` methods. This is
because enabling a mass matrix solver assumes that F(u,k,t) = M k in the
associated ODE operator.
- Added support for custom interpolation procedure in FindPointsGSLIB.
- Added NURBS-based H(div) and H(curl) elements in 2D and 3D. Only on single
patch meshes. Only implemented for serial computations.
- Added miniapps to demonstrate the H(div) and H(curl) NURBS elements.
- Added an MFEM example for the eikonal equation. This new solver is based on
the proximal Galerkin method introduced by Keith and Surowiec.
- API change: in class GridFunction, 'fec' was renamed to 'fec_owned'.
Version 4.7, released on May 7, 2024
====================================
@@ -57,9 +38,6 @@ Meshing improvements
- Added support for internal boundary elements in nonconforming meshes.
- Added ExodusII output capability. The writer can handle first-order (Pyramid5,
Wedge6, Hex8, Tet4) and second-order FE types (Pyramid14, Wedge18, Hex27, Tet10).
- The ReadCubit Genesis mesh importer has been rewritten to improve readability.
Discretization improvements
+1 -7
View File
@@ -273,13 +273,7 @@ Installation options:
PREFIX - Specify the installation directory. The library (libmfem.a) will be
installed in $(PREFIX)/lib, the headers in $(PREFIX)/include, and
the configuration makefile (config.mk) in $(PREFIX)/share/mfem.
INSTALL - Specify the install program, default = /usr/bin/install
INSTALL_DEF_PERM - Specify the default install permissions. This affects
headers and configuration makefiles, default = 644
INSTALL_BIN_PERM - Specify the install permissions for binaries. This only
affects the shared version of the library, default = 755
INSTALL_DIR_PERM - Specify the install permissions for directories and,
on macOS/BSD, for symlinks as well, default = 755
INSTALL - Specify the install program, e.g /usr/bin/install
MFEM library features/options (GNU make)
----------------------------------------
-4
View File
@@ -95,10 +95,6 @@ else
# Silence unused command line argument warnings when generating dependencies
# with mpicxx and clang
DEP_FLAGS := -Wno-unused-command-line-argument $(DEP_FLAGS)
# Silence "ignoring duplicate libraries" warnings on new (Xcode 15) linker
ifneq (,$(findstring PROJECT:dyld,$(shell ld -v 2>&1)))
LDFLAGS_INTERNAL = -Xlinker -no_warn_duplicate_libraries
endif
endif
# Set CXXFLAGS to overwrite the default selection of DEBUG_FLAGS/OPTIM_FLAGS
+13 -83
View File
@@ -32,7 +32,7 @@ groups_serial=(
'"examples"
"Examples:"
"examples"
"ex{,[1-9]}[0-9].cpp"'
"ex{,1,2,3}[0-9].cpp"'
# "ex1.cpp"'
'"sundials"
"SUNDIALS examples:"
@@ -58,10 +58,6 @@ groups_serial=(
"HiOp examples:"
"examples/hiop"
"ex9.cpp"'
'"moonolith"
"Moonolith examples:"
"examples/moonolith"
"ex1.cpp"'
'"pumi"
"PUMI examples:"
"examples/pumi"
@@ -70,38 +66,25 @@ groups_serial=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp mesh-quality.cpp
polar-nc.cpp reflector.cpp shaper.cpp trimmer.cpp twist.cpp
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
mesh-optimizer.cpp minimal-surface.cpp"'
'"adjoint"
"Adjoint miniapps:"
"miniapps/adjoint"
"cvsRoberts_ASAi_dns.cpp"'
'"autodiff"
"Autodiff miniapps:"
"miniapps/autodiff"
"seq_example.cpp seq_test.cpp"' # 'seq_test.cpp' has no sample runs
'"dpg"
"DPG miniapps:"
"miniapps/dpg"
"{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
'"gslib"
"GSLIB miniapps:"
"miniapps/gslib"
"field-diff.cpp field-interp.cpp findpts.cpp schwarz_ex1.cpp "'
# todo: miniapps/mtop
'"nurbs"
"NURBS miniapps:"
"miniapps/nurbs"
"nurbs_ex1.cpp"'
# todo: add other nurbs miniapps
# todo: miniapps/solvers (serial)
'"tools"
"Tools miniapps:"
"miniapps/tools"
"convert-dc.cpp display-basis.cpp get-values.cpp load-dc.cpp
lor-transfer.cpp"'
# todo: add other tools miniapps
'"toys"
"Toys miniapps:"
"miniapps/toys"
@@ -117,7 +100,7 @@ groups_parallel=(
'"examples"
"Examples:"
"examples"
"ex{,[1-9]}[0-9]p.cpp"'
"ex{,1,2,3}[0-9]p.cpp"'
# "ex1p.cpp"'
'"sundials"
"SUNDIALS examples:"
@@ -143,10 +126,6 @@ groups_parallel=(
"HiOp examples:"
"examples/hiop"
"ex9p.cpp"'
'"moonolith"
"Moonolith examples:"
"examples/moonolith"
"ex{1,2}p.cpp"'
'"pumi"
"PUMI examples:"
"examples/pumi"
@@ -159,41 +138,24 @@ groups_parallel=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"pmesh-optimizer.cpp pmesh-fitting.cpp pminimal-surface.cpp
fit-node-position.cpp"'
"pmesh-optimizer.cpp pmesh-fitting.cpp pminimal-surface.cpp"'
'"electromagnetics"
"Electromagnetics miniapps:"
"miniapps/electromagnetics"
"joule.cpp"'
# "{joule,maxwell,tesla,volta}.cpp"' # todo: multiline sample runs
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
'"adjoint"
"Adjoint miniapps:"
"miniapps/adjoint"
"adjoint_advection_diffusion.cpp"'
'"autodiff"
"Autodiff miniapps:"
"miniapps/autodiff"
"par_example.cpp"'
'"dpg"
"DPG miniapps:"
"miniapps/dpg"
"p{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
'"gslib"
"GSLIB miniapps:"
"miniapps/gslib"
"pfindpts.cpp schwarz_ex1p.cpp"'
'"hdiv-linear-solver"
"H(div) linear solver miniapps:"
"miniapps/hdiv-linear-solver"
"grad_div.cpp darcy.cpp"'
# 'miniapps/hooke/hooke.cpp' has no sample runs
# todo: miniapps/mtop
# todo: miniapps/multidomain
'"navier"
"Navier miniapps:"
"miniapps/navier"
"navier_cht.cpp"'
# todo: add other navier miniapps
'"nurbs"
"NURBS miniapps:"
"miniapps/nurbs"
@@ -202,18 +164,14 @@ groups_parallel=(
"Shifted miniapps:"
"miniapps/shifted"
"distance.cpp"'
# todo: add other shifted miniapps
'"solvers"
"Solvers miniapps:"
"miniapps/solvers"
"block-solvers.cpp"'
# todo: add other solvers miniapps
# todo: miniapps/spde
'"tools"
"Tools miniapps:"
"miniapps/tools"
"convert-dc.cpp get-values.cpp load-dc.cpp"'
# todo: add other tools miniapps
"convert-cd.cpp get-values.cpp load-dc.cpp"'
'"convergence"
"Convergence tests:"
"tests/convergence"
@@ -228,7 +186,7 @@ groups_all=(
'"examples"
"Examples:"
"examples"
"ex\"{,[1-9]}[0-9]\"{,p}.cpp"'
"ex\"{,1,2,3}[0-9]\"{,p}.cpp"'
'"sundials"
"SUNDIALS examples:"
"examples/sundials"
@@ -257,14 +215,10 @@ groups_all=(
"HiOp examples:"
"examples/hiop"
"ex9.cpp ex9p.cpp"'
'"moonolith"
"Moonolith examples:"
"examples/moonolith"
"ex1.cpp ex{1,2}p.cpp"'
'"pumi"
"PUMI examples:"
"examples/pumi"
"ex1.cpp ex2.cpp ex1p.cpp ex6p.cpp"'
"ex1.cpp ex1p.cpp ex2.cpp ex6p.cpp"'
'"superlu"
"Superlu examples:"
"examples/superlu"
@@ -272,67 +226,43 @@ groups_all=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp mesh-quality.cpp
polar-nc.cpp reflector.cpp shaper.cpp trimmer.cpp twist.cpp
{,p}mesh-optimizer.cpp pmesh-fitting.cpp {,p}minimal-surface.cpp
fit-node-position.cpp"'
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
{,p}mesh-optimizer.cpp pmesh-fitting.cpp {,p}minimal-surface.cpp"'
'"electromagnetics"
"Electromagnetics miniapps:"
"miniapps/electromagnetics"
"joule.cpp"'
# "{joule,maxwell,tesla,volta}.cpp"' # todo: multiline sample runs
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
'"adjoint"
"Adjoint miniapps:"
"miniapps/adjoint"
"cvsRoberts_ASAi_dns.cpp adjoint_advection_diffusion.cpp"'
'"autodiff"
"Autodiff miniapps:"
"miniapps/autodiff"
"seq_example.cpp seq_test.cpp par_example.cpp"'
# 'seq_test.cpp' has no sample runs
'"dpg"
"DPG miniapps:"
"miniapps/dpg"
"{,p}{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
"adjoint_advection_diffusion.cpp cvsRoberts_ASAi_dns.cpp"'
'"gslib"
"GSLIB miniapps:"
"miniapps/gslib"
"field-diff.cpp field-interp.cpp findpts.cpp schwarz_ex1.cpp pfindpts.cpp
schwarz_ex1p.cpp"'
'"hdiv-linear-solver"
"H(div) linear solver miniapps:"
"miniapps/hdiv-linear-solver"
"grad_div.cpp darcy.cpp"'
# 'miniapps/hooke/hooke.cpp' has no sample runs
# todo: miniapps/mtop
# todo: miniapps/multidomain
'"navier"
"Navier miniapps:"
"miniapps/navier"
"navier_cht.cpp"'
# todo: add other navier miniapps
'"nurbs"
"NURBS miniapps:"
"miniapps/nurbs"
"nurbs_ex1.cpp nurbs_ex1p.cpp nurbs_ex11p.cpp"'
# todo: add other nurbs miniapps
'"shifted"
"Shifted miniapps:"
"miniapps/shifted"
"distance.cpp"'
# todo: add other shifted miniapps
'"solvers"
"Solvers miniapps:"
"miniapps/solvers"
"block-solvers.cpp"'
# todo: add other solvers miniapps
# todo: miniapps/spde
'"tools"
"Tools miniapps:"
"miniapps/tools"
"convert-dc.cpp display-basis.cpp get-values.cpp load-dc.cpp
lor-transfer.cpp"'
# todo: add other tools miniapps
'"toys"
"Toys miniapps:"
"miniapps/toys"
@@ -456,7 +386,7 @@ function help_message()
mfem_config [${mfem_config}]
Set MFEM configuration options
make [${make}], mpiexec [${mpiexec}], mpiexec_np [${mpiexec_np}]
Their values can also be set using the respective uppercase environment
Their values can also set using the respective uppercase environment
variable
mfem_build_dir [${mfem_build_dir}]
Same as '-d': set this variable to something different from <mfem_dir>
+3 -3
View File
@@ -18,9 +18,9 @@ elements
boundary
4
1 1 0 1
2 1 2 3
3 1 3 0
4 1 1 2
1 1 2 3
1 1 3 0
1 1 1 2
edges
4
+1 -2
View File
@@ -1049,8 +1049,7 @@ RECURSIVE = NO
EXCLUDE = @MFEM_SOURCE_DIR@/config/_config.hpp \
@MFEM_SOURCE_DIR@/config/get_hypre_version.cpp \
@MFEM_SOURCE_DIR@/general/tinyxml2.h \
@MFEM_SOURCE_DIR@/general/tinyxml2.cpp \
@MFEM_SOURCE_DIR@/linalg/lapack.hpp
@MFEM_SOURCE_DIR@/general/tinyxml2.cpp
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
-15
View File
@@ -182,21 +182,6 @@ namespace mfem {
* <a class="el" href="examples_2superlu_2ex1p_8cpp_source.html">1p</a>,
* demonstrating the use of MFEM's \link superlu.hpp SuperLU integration\endlink.
*
* <H4>NURBS Examples</H4>
* - Variants of Examples
* <a class="el" href="nurbs__ex1_8cpp_source.html">1</a>,
* <a class="el" href="nurbs__ex1p_8cpp_source.html">1p</a>,
* <a class="el" href="nurbs__ex3_8cpp_source.html">3</a>,
* <a class="el" href="nurbs__ex5_8cpp_source.html">5</a>,
* <a class="el" href="nurbs__ex11p_8cpp_source.html">11p</a>, and
* <a class="el" href="nurbs__ex24_8cpp_source.html">24</a>,
* demonstrating howto perform NURBS-based Isogeometric Analysis.
* - Variant of Example <a class="el" href="nurbs__patch__ex1_8cpp_source.html">1</a>: demonstrates the use of patch integration
* - <a class="el" href="nurbs__solenoidal_8cpp_source.html">NURBS Divergence-free</a>: solve a solenoidal vector projection with NURBS-based H(div) elements
* - <a class="el" href="nurbs__curveint_8cpp_source.html">NURBS Interpolation</a>: NURBS interpolation of given geometry
* - <a class="el" href="nurbs__naca__cmesh_8cpp_source.html">NURBS NACA Mesher</a>: generate NURBS based mesh around a NACA foil
* - <a class="el" href="nurbs__printfunc_8cpp_source.html">NURBS Printer</a>: print the NURBS-basis
*
* <H3>Miniapps</H3>
* - <a class="el" href="volta_8cpp_source.html">Volta</a>: simple electrostatics simulation code
* - <a class="el" href="tesla_8cpp_source.html">Tesla</a>: simple magnetostatics simulation code
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/amgx/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/caliper,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
+20 -16
View File
@@ -44,7 +44,7 @@ protected:
BilinearForm *M;
BilinearForm *K;
SparseMatrix Mmat, Kmat;
SparseMatrix Mmat, Kmat, Kmat0;
SparseMatrix *T; // T = M + dt K
real_t current_dt;
@@ -83,24 +83,25 @@ WaveOperator::WaveOperator(FiniteElementSpace &f,
: SecondOrderTimeDependentOperator(f.GetTrueVSize(), (real_t) 0.0),
fespace(f), M(NULL), K(NULL), T(NULL), current_dt(0.0), z(height)
{
// Assemble Laplace matrix
const real_t rel_tol = 1e-8;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
c2 = new ConstantCoefficient(speed*speed);
K = new BilinearForm(&fespace);
K->AddDomainIntegrator(new DiffusionIntegrator(*c2));
K->Assemble();
// Assemble Mass matrix
Array<int> dummy;
K->FormSystemMatrix(dummy, Kmat0);
K->FormSystemMatrix(ess_tdof_list, Kmat);
M = new BilinearForm(&fespace);
M->AddDomainIntegrator(new MassIntegrator());
M->Assemble();
// Apply Bcs
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
K->FormSystemMatrix(ess_tdof_list, Kmat);
M->FormSystemMatrix(ess_tdof_list, Mmat);
// Configure preconditioner
const real_t rel_tol = 1e-8;
M_solver.iterative_mode = false;
M_solver.SetRelTol(rel_tol);
M_solver.SetAbsTol(0.0);
@@ -109,13 +110,14 @@ WaveOperator::WaveOperator(FiniteElementSpace &f,
M_solver.SetPreconditioner(M_prec);
M_solver.SetOperator(Mmat);
// Configure solver
T_solver.iterative_mode = false;
T_solver.SetRelTol(rel_tol);
T_solver.SetAbsTol(0.0);
T_solver.SetMaxIter(100);
T_solver.SetPrintLevel(0);
T_solver.SetPreconditioner(T_prec);
T = NULL;
}
void WaveOperator::Mult(const Vector &u, const Vector &du_dt,
@@ -124,11 +126,9 @@ void WaveOperator::Mult(const Vector &u, const Vector &du_dt,
// Compute:
// d2udt2 = M^{-1}*-K(u)
// for d2udt2
K->FullMult(u, z);
Kmat.Mult(u, z);
z.Neg(); // z = -z
z.SetSubVector(ess_tdof_list, 0.0);
M_solver.Mult(z, d2udt2);
d2udt2.SetSubVector(ess_tdof_list, 0.0);
}
void WaveOperator::ImplicitSolve(const real_t fac0, const real_t fac1,
@@ -142,11 +142,14 @@ void WaveOperator::ImplicitSolve(const real_t fac0, const real_t fac1,
T = Add(1.0, Mmat, fac0, Kmat);
T_solver.SetOperator(*T);
}
K->FullMult(u, z);
Kmat0.Mult(u, z);
z.Neg();
z.SetSubVector(ess_tdof_list, 0.0);
for (int i = 0; i < ess_tdof_list.Size(); i++)
{
z[ess_tdof_list[i]] = 0.0;
}
T_solver.Mult(z, d2udt2);
d2udt2.SetSubVector(ess_tdof_list, 0.0);
}
void WaveOperator::SetParameters(const Vector &u)
@@ -311,6 +314,7 @@ int main(int argc, char *argv[])
ess_bdr = 0;
}
}
WaveOperator oper(fespace, ess_bdr, speed);
u_gf.SetFromTrueDofs(u);
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/ginkgo/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
-1
View File
@@ -96,7 +96,6 @@ public:
{
Vector w_glob(width);
pfes.Dof_TrueDof_Matrix()->MultTranspose(w, w_glob);
w_glob.HostReadWrite(); // read+write -> can use w_glob(i) (non-const)
for (int i = 0; i < width; i++) { grad(0, i) = w_glob(i); }
}
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/hiop/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ..
MFEM_BUILD_DIR ?= ..
MFEM_INSTALL_DIR ?= ../mfem
SRC = $(if $(MFEM_DIR:..=),$(MFEM_DIR)/examples/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/moonolith/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/petsc/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
+1
View File
@@ -66,6 +66,7 @@ int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI) and HYPRE.
Mpi::Init(argc, argv);
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
+2
View File
@@ -80,6 +80,8 @@ int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI) and HYPRE.
Mpi::Init(argc, argv);
int num_proc = Mpi::WorldSize();
int myId = Mpi::WorldRank();
Hypre::Init();
// 2. Parse command-line options.
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/pumi/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
+3 -16
View File
@@ -31,21 +31,11 @@ include_directories(BEFORE ${PROJECT_BINARY_DIR})
add_custom_target(test_sundials
${CMAKE_CTEST_COMMAND} -R sundials USES_TERMINAL)
# Add one executable per cpp file, adding "sundials_" as prefix so the CMake
# target is unique from those in the non-SUNDIALS examples. Also sets
# "test_sundials" as a target that depends on the given SUNDIALS examples.
# Add one executable per cpp file, adding "sundials_" as prefix. Sets
# "test_sundials" as a target that depends on the given examples.
set(PFX sundials_)
add_mfem_examples(SUNDIALS_EXAMPLES_SRCS ${PFX} "" test_sundials)
# Remove "sundials_" prefix from exectuable name for consistency with GNU build
# system.
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TARGET_NAME "${PFX}${SRC_FILENAME}")
string(REPLACE ${PFX} "" EXE_NAME ${TARGET_NAME})
set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${EXE_NAME})
endforeach()
# Testing.
# The SUNDIALS tests can be run separately using the target "test_sundials"
# which builds the examples and runs:
@@ -61,10 +51,7 @@ if (MFEM_ENABLE_TESTING)
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: test ARKODE with implicit time stepping using mass form
set(EX16_COMMON_OPTS -s 15)
set(EX16_TEST_OPTS ${EX16_COMMON_OPTS})
set(EX16P_TEST_OPTS ${EX16_COMMON_OPTS})
# Example 16: use the default options
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
+1 -3
View File
@@ -1,9 +1,7 @@
// MFEM Example 10
// SUNDIALS Modification
//
// Compile with:
// make ex10 (GNU make)
// make sundials_ex10 (CMake)
// Compile with: make ex10
//
// Sample runs:
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 12 -dt 0.15 -vs 10
+1 -3
View File
@@ -1,9 +1,7 @@
// MFEM Example 10 - Parallel Version
// SUNDIALS Modification
//
// Compile with:
// make ex10p (GNU make)
// make sundials_ex10p (CMake)
// Compile with: make ex10p
//
// Sample runs:
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 12 -dt 0.15 -vs 10
+164 -257
View File
@@ -1,21 +1,15 @@
// MFEM Example 16
// SUNDIALS Modification
//
// Compile with:
// make ex16 (GNU make)
// make sundials_ex16 (CMake)
// Compile with: make ex16
//
// Sample runs: ex16
// ex16 -m ../../data/inline-tri.mesh
// ex16 -m ../../data/disc-nurbs.mesh -tf 2
// ex16 -s 12 -a 0.0 -k 1.0
// ex16 -s 15 -a 0.0 -k 1.0
// ex16 -s 8 -a 1.0 -k 0.0 -dt 1e-4 -tf 5e-2 -vs 25
// ex16 -s 11 -a 1.0 -k 0.0 -dt 1e-4 -tf 5e-2 -vs 25
// ex16 -s 9 -a 0.5 -k 0.5 -o 4 -dt 1e-4 -tf 2e-2 -vs 25
// ex16 -s 12 -a 0.5 -k 0.5 -o 4 -dt 1e-4 -tf 2e-2 -vs 25
// ex16 -s 10 -dt 1.0e-4 -tf 4.0e-2 -vs 40
// ex16 -s 13 -dt 1.0e-4 -tf 4.0e-2 -vs 40
// ex16 -m ../../data/fichera-q2.mesh
// ex16 -m ../../data/escher.mesh
// ex16 -m ../../data/beam-tet.mesh -tf 10 -dt 0.1
@@ -43,102 +37,75 @@
using namespace std;
using namespace mfem;
/** After spatial discretization, the conduction model is expressed as
/** After spatial discretization, the conduction model can be written as:
*
* M du/dt = - K(u) u
* du/dt = M^{-1}(-Ku)
*
* where u is the vector representing the temperature, M is the mass matrix,
* and K(u) is the diffusion operator with diffusivity depending on u:
* and K is the diffusion operator with diffusivity depending on u:
* (\kappa + \alpha u).
*
* Class ConductionOperatorOperator represents the above ODE operator in the
* general form F(u, k, t) = G(u, t) where
*
* 1. F(u, du/dt, t) = du/dt (ODE is expressed in EXPLICIT form)
* G(u, t) = - inv(M) K(u) u
* 2. F(u, du/dt, t) = M du/dt (ODE is expressed in IMPLICIT form)
* G(u, t) = - K(u) u
* Class ConductionOperator represents the right-hand side of the above ODE.
*/
class ConductionOperator : public TimeDependentOperator
{
protected:
FiniteElementSpace &fespace;
Array<int> ess_tdof_list; // this list remains empty for pure Neumann b.c.
BilinearForm M;
SparseMatrix Mmat;
BilinearForm *M;
BilinearForm *K;
const real_t alpha, kappa;
std::unique_ptr<BilinearForm> K;
SparseMatrix Kmat;
std::unique_ptr<SparseMatrix> T; // T = M + gam K(u)
SparseMatrix Mmat, Kmat;
SparseMatrix *T; // T = M + dt K
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
DSmoother M_prec; // Preconditioner for the mass matrix M
CGSolver T_solver; // Implicit solver for T = M + gam K(u)
CGSolver T_solver; // Implicit solver for T = M + dt K
DSmoother T_prec; // Preconditioner for the implicit solver
double alpha, kappa;
mutable Vector z; // auxiliary vector
public:
ConductionOperator(FiniteElementSpace &f, double alpha, double kappa,
const Vector &u);
ConductionOperator(FiniteElementSpace &f, const real_t alpha,
const real_t kappa, const Vector &u,
const Type &ode_expression_type);
virtual void Mult(const Vector &u, Vector &du_dt) const;
// Compute K(u_n) for use as an approximation in - K(u) u
void SetConductionTensor(const Vector &u);
/** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
This is the only requirement for high-order SDIRK implicit integration.*/
virtual void ImplicitSolve(const double dt, const Vector &u, Vector &k);
/** Compute G(u, t) as defined in the IMPLICIT expression form of the ODE
operator, i.e., @a v = - K(u_n) @a u. Note that K(u_n) is an
approximation to K(u). */
void ExplicitMult(const Vector &u, Vector &v) const override;
/// Custom Jacobian system solver for the SUNDIALS time integrators.
/** For the ODE system represented by ConductionOperator
/** Solve for k in F(u, k, t) = G(u, t) for either EXPLICIT or IMPLICIT
expression forms of the ODE operator, i.e., @a k = - inv(M) K(u_n) @a u.
Note that K(u_n) is an approximation to K(u). */
void Mult(const Vector &u, Vector &k) const override;
M du/dt = -K(u),
/** Solve for k in F(u + gam*k, k, t) = G(u + gam*k, t) for either EXPLICIT
or IMPLICIT expression forms of the ODE operator, i.e.,
[ M + @a gam K(u_n) ] @a k = - K(u_n) @a u . Note that K(u_n) is an
approximation to K(u). */
void ImplicitSolve(const real_t gam, const Vector &u, Vector &k) override;
this class facilitates the solution of linear systems of the form
/** Setup to solve for dk in [dF/dk + gam*dF/du - gam*dG/du] dk = G - F for
either EXPLICIT or IMPLICIT expression forms of the ODE operator, i.e.,
[M - @a gam Jf(u)] dk = G - F, where Jf(u) is an approximation of the
Jacobian of -K(u) u. The approximation chosen here is Jf(u) = -K(u_n). */
int SUNImplicitSetup(const Vector &u, const Vector &fu, int jok, int *jcur,
real_t gam) override;
(M + γK) y = M b,
/** Solve for @a dk in the system in SUNImplicitSetup to the given tolerance,
with the residual @a r providing either
1. @a r = G - F = inv(M) f(u) - k (EXPLICIT expression form)
1. @a r = G - F = f(u) - M k (IMPLICIT expression form)
*/
int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol) override;
for given b, u (not used), and γ = GetTimeStep(). */
int SUNMassSetup() override;
/** Setup the system (M + dt K) x = M b. This method is used by the implicit
SUNDIALS solvers. */
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
int jok, int *jcur, double gamma);
int SUNMassSolve(const Vector &b, Vector &x, real_t tol) override;
/** Solve the system (M + dt K) x = M b. This method is used by the implicit
SUNDIALS solvers. */
virtual int SUNImplicitSolve(const Vector &b, Vector &x, double tol);
int SUNMassMult(const Vector &x, Vector &v) override;
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
void SetParameters(const Vector &u);
virtual ~ConductionOperator();
};
real_t InitialTemperature(const Vector &x)
{
if (x.Norml2() < 0.5)
{
return 2.0;
}
else
{
return 1.0;
}
}
double InitialTemperature(const Vector &x);
int main(int argc, char *argv[])
{
@@ -150,16 +117,16 @@ int main(int argc, char *argv[])
int ref_levels = 2;
int order = 2;
int ode_solver_type = 9; // CVODE implicit BDF
real_t t_final = 0.5;
real_t dt = 1.0e-2;
real_t alpha = 1.0e-2;
real_t kappa = 0.5;
double t_final = 0.5;
double dt = 1.0e-2;
double alpha = 1.0e-2;
double kappa = 0.5;
bool visualization = true;
bool visit = false;
int vis_steps = 5;
// Relative and absolute tolerances for CVODE and ARKODE.
const real_t reltol = 1e-4, abstol = 1e-4;
const double reltol = 1e-4, abstol = 1e-4;
int precision = 8;
cout.precision(precision);
@@ -184,10 +151,7 @@ int main(int argc, char *argv[])
"9 - CVODE (implicit BDF),\n\t"
"10 - ARKODE (default explicit),\n\t"
"11 - ARKODE (explicit Fehlberg-6-4-5),\n\t"
"12 - ARKODE (default implicit),\n\t"
"13 - ARKODE (default explicit with MFEM mass solve),\n\t"
"14 - ARKODE (explicit Fehlberg-6-4-5 with MFEM mass solve),\n\t"
"15 - ARKODE (default implicit with MFEM mass solve).");
"12 - ARKODE (default impicit).");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -210,13 +174,16 @@ int main(int argc, char *argv[])
args.PrintUsage(cout);
return 1;
}
if (ode_solver_type < 1 || ode_solver_type > 12)
{
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
return 3;
}
args.PrintOptions(cout);
bool use_mass_solver = ode_solver_type >= 13;
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral and hexahedral meshes with the same code.
std::unique_ptr<Mesh> mesh(new Mesh(mesh_file, 1, 1));
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
@@ -230,7 +197,7 @@ int main(int argc, char *argv[])
// 4. Define the vector finite element space representing the current and the
// initial temperature, u_ref.
H1_FECollection fe_coll(order, dim);
FiniteElementSpace fespace(mesh.get(), &fe_coll);
FiniteElementSpace fespace(mesh, &fe_coll);
int fe_size = fespace.GetTrueVSize();
cout << "Number of temperature unknowns: " << fe_size << endl;
@@ -244,17 +211,8 @@ int main(int argc, char *argv[])
Vector u;
u_gf.GetTrueDofs(u);
// 6. Initialize the conduction ODE operator and the visualization.
ConductionOperator::Type ode_expression_type;
if (use_mass_solver)
{
ode_expression_type = ConductionOperator::Type::IMPLICIT;
}
else
{
ode_expression_type = ConductionOperator::Type::EXPLICIT;
}
ConductionOperator oper(fespace, alpha, kappa, u, ode_expression_type);
// 6. Initialize the conduction operator and the visualization.
ConductionOperator oper(fespace, alpha, kappa, u);
u_gf.SetFromTrueDofs(u);
{
@@ -266,7 +224,7 @@ int main(int argc, char *argv[])
u_gf.Save(osol);
}
VisItDataCollection visit_dc("Example16", mesh.get());
VisItDataCollection visit_dc("Example16", mesh);
visit_dc.RegisterField("temperature", &u_gf);
if (visit)
{
@@ -300,75 +258,52 @@ int main(int argc, char *argv[])
}
// 7. Define the ODE solver used for time integration.
real_t t = 0.0;
std::unique_ptr<ODESolver> ode_solver;
double t = 0.0;
ODESolver *ode_solver = NULL;
CVODESolver *cvode = NULL;
ARKStepSolver *arkode = NULL;
switch (ode_solver_type)
{
// MFEM explicit methods
case 1: ode_solver = std::make_unique<ForwardEulerSolver>(); break;
case 2: ode_solver = std::make_unique<RK2Solver>(0.5); break; // midpoint method
case 3: ode_solver = std::make_unique<RK3SSPSolver>(); break;
case 4: ode_solver = std::make_unique<RK4Solver>(); break;
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(0.5); break; // midpoint method
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
// MFEM implicit L-stable methods
case 5: ode_solver = std::make_unique<BackwardEulerSolver>(); break;
case 6: ode_solver = std::make_unique<SDIRK23Solver>(2); break;
case 7: ode_solver = std::make_unique<SDIRK33Solver>(); break;
case 5: ode_solver = new BackwardEulerSolver; break;
case 6: ode_solver = new SDIRK23Solver(2); break;
case 7: ode_solver = new SDIRK33Solver; break;
// CVODE
case 8:
case 9:
{
int cvode_solver_type;
if (ode_solver_type == 8)
{
cvode_solver_type = CV_ADAMS;
}
else
{
cvode_solver_type = CV_BDF;
}
std::unique_ptr<CVODESolver> cvode(new CVODESolver(cvode_solver_type));
cvode = new CVODESolver(CV_ADAMS);
cvode->Init(oper);
cvode->SetSStolerances(reltol, abstol);
cvode->SetMaxStep(dt);
ode_solver = std::move(cvode);
break;
}
ode_solver = cvode; break;
case 9:
cvode = new CVODESolver(CV_BDF);
cvode->Init(oper);
cvode->SetSStolerances(reltol, abstol);
cvode->SetMaxStep(dt);
ode_solver = cvode; break;
// ARKODE
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
{
ARKStepSolver::Type arkode_solver_type;
if (ode_solver_type == 12 || ode_solver_type == 15)
{
arkode_solver_type = ARKStepSolver::IMPLICIT;
}
else
{
arkode_solver_type = ARKStepSolver::EXPLICIT;
}
std::unique_ptr<ARKStepSolver> arkode(
new ARKStepSolver(arkode_solver_type));
arkode = new ARKStepSolver(ARKStepSolver::EXPLICIT);
arkode->Init(oper);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
if (ode_solver_type == 11 || ode_solver_type == 14)
if (ode_solver_type == 11)
{
arkode->SetERKTableNum(ARKODE_FEHLBERG_13_7_8);
}
if (use_mass_solver)
{
arkode->UseMFEMMassLinearSolver(SUNFALSE);
}
ode_solver = std::move(arkode);
break;
}
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
return 3;
ode_solver = arkode; break;
case 12:
arkode = new ARKStepSolver(ARKStepSolver::IMPLICIT);
arkode->Init(oper);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
ode_solver = arkode; break;
}
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
@@ -376,14 +311,8 @@ int main(int argc, char *argv[])
// Since we want to update the diffusion coefficient after every time step,
// we need to use the "one-step" mode of the SUNDIALS solvers.
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
{
cvode->SetStepMode(CV_ONE_STEP);
}
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
{
arkode->SetStepMode(ARK_ONE_STEP);
}
if (cvode) { cvode->SetStepMode(CV_ONE_STEP); }
if (arkode) { arkode->SetStepMode(ARK_ONE_STEP); }
// 8. Perform time-integration (looping over the time iterations, ti, with a
// time-step dt).
@@ -394,7 +323,7 @@ int main(int argc, char *argv[])
bool last_step = false;
for (int ti = 1; !last_step; ti++)
{
real_t dt_real = min(dt, t_final - t);
double dt_real = min(dt, t_final - t);
// Note that since we are using the "one-step" mode of the SUNDIALS
// solvers, they will, generally, step over the final time and will not
@@ -408,14 +337,8 @@ int main(int argc, char *argv[])
if (last_step || (ti % vis_steps) == 0)
{
cout << "step " << ti << ", t = " << t << endl;
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
{
cvode->PrintInfo();
}
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
{
arkode->PrintInfo();
}
if (cvode) { cvode->PrintInfo(); }
if (arkode) { arkode->PrintInfo(); }
u_gf.SetFromTrueDofs(u);
if (visualization)
@@ -430,153 +353,137 @@ int main(int argc, char *argv[])
visit_dc.Save();
}
}
oper.SetConductionTensor(u);
oper.SetParameters(u);
}
tic_toc.Stop();
cout << "Done, " << tic_toc.RealTime() << "s." << endl;
// 9. Save the final solution. This output can be viewed later using GLVis:
// "glvis -m ex16.mesh -g ex16-final.gf".
u_gf.Save("ex16-final.gf", precision);
{
ofstream osol("ex16-final.gf");
osol.precision(precision);
u_gf.Save(osol);
}
// 10. Free the used memory.
delete ode_solver;
delete mesh;
return 0;
}
ConductionOperator::ConductionOperator(FiniteElementSpace &fes,
const real_t alpha, const real_t kappa,
const Vector &u,
const Type &ode_expression_type)
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace), z(height)
ConductionOperator::ConductionOperator(FiniteElementSpace &f, double al,
double kap, const Vector &u)
: TimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL), K(NULL),
T(NULL), z(height)
{
// specify a relative tolerance for all solves with MFEM integrators
const real_t rel_tol = 1e-8;
const double rel_tol = 1e-8;
M.AddDomainIntegrator(new MassIntegrator());
M.Assemble();
M.FormSystemMatrix(ess_tdof_list, Mmat);
M = new BilinearForm(&fespace);
M->AddDomainIntegrator(new MassIntegrator());
M->Assemble();
M->FormSystemMatrix(ess_tdof_list, Mmat);
M_solver.iterative_mode = false;
M_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
M_solver.SetRelTol(rel_tol);
M_solver.SetAbsTol(0.0);
M_solver.SetMaxIter(50);
M_solver.SetPrintLevel(0);
M_solver.SetPreconditioner(M_prec);
M_solver.SetOperator(Mmat);
alpha = al;
kappa = kap;
T_solver.iterative_mode = false;
T_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
T_solver.SetRelTol(rel_tol);
T_solver.SetAbsTol(0.0);
T_solver.SetMaxIter(100);
T_solver.SetPrintLevel(0);
T_solver.SetPreconditioner(T_prec);
SetConductionTensor(u);
SetParameters(u);
}
void ConductionOperator::SetConductionTensor(const Vector &u)
void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
{
// Compute:
// du_dt = M^{-1}*-K(u)
// for du_dt
Kmat.Mult(u, z);
z.Neg(); // z = -z
M_solver.Mult(z, du_dt);
}
void ConductionOperator::ImplicitSolve(const double dt,
const Vector &u, Vector &du_dt)
{
// Solve the equation:
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
// for du_dt
if (T) { delete T; }
T = Add(1.0, Mmat, dt, Kmat);
T_solver.SetOperator(*T);
Kmat.Mult(u, z);
z.Neg();
T_solver.Mult(z, du_dt);
}
void ConductionOperator::SetParameters(const Vector &u)
{
// Compute K(u_n).
GridFunction u_alpha_gf(&fespace);
u_alpha_gf.SetFromTrueDofs(u);
for (int i = 0; i < u_alpha_gf.Size(); i++)
{
u_alpha_gf(i) = kappa + alpha*u_alpha_gf(i);
}
delete K;
K = new BilinearForm(&fespace);
GridFunctionCoefficient u_coeff(&u_alpha_gf);
K = std::make_unique<BilinearForm>(&fespace);
K->AddDomainIntegrator(new DiffusionIntegrator(u_coeff));
K->Assemble();
K->FormSystemMatrix(ess_tdof_list, Kmat);
}
void ConductionOperator::ExplicitMult(const Vector &u, Vector &v) const
int ConductionOperator::SUNImplicitSetup(const Vector &x,
const Vector &fx, int jok, int *jcur,
double gamma)
{
// Compute - K(u_n) u.
Kmat.Mult(u, v);
v.Neg();
}
void ConductionOperator::Mult(const Vector &u, Vector &k) const
{
// Compute - inv(M) K(u_n) u.
ExplicitMult(u, z);
M_solver.Mult(z, k);
}
void ConductionOperator::ImplicitSolve(const real_t gam, const Vector &u,
Vector &k)
{
// Solve for k in M k = - K(u_n) [u + gam*k].
ExplicitMult(u, z);
T = std::unique_ptr<SparseMatrix>(Add(1.0, Mmat, gam, Kmat));
// Setup the ODE Jacobian T = M + gamma K.
if (T) { delete T; }
T = Add(1.0, Mmat, gamma, Kmat);
T_solver.SetOperator(*T);
T_solver.Mult(z, k);
*jcur = 1;
return (0);
}
int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
int jok, int *jcur, real_t gam)
int ConductionOperator::SUNImplicitSolve(const Vector &b, Vector &x, double tol)
{
// Compute T = M + gamma K(u_n).
T = std::unique_ptr<SparseMatrix>(Add(1.0, Mmat, gam, Kmat));
T_solver.SetOperator(*T);
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
return SUNLS_SUCCESS;
// Solve the system A x = z => (M - gamma K) x = M b.
Mmat.Mult(b, z);
T_solver.Mult(z, x);
return (0);
}
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
real_t tol)
ConductionOperator::~ConductionOperator()
{
// Solve the system [M + gamma K(u_n)] dk = - K(u_n) u - M k.
// What value r is providing depends on the ODE expression form:
// EXPLICIT form: r = -inv(M) K(u_n) u - k
// IMPLICIT form: r = -K(u_n) u - M k
T_solver.SetRelTol(tol);
if (isExplicit())
delete T;
delete M;
delete K;
}
double InitialTemperature(const Vector &x)
{
if (x.Norml2() < 0.5)
{
Mmat.Mult(r, z);
T_solver.Mult(z, dk);
return 2.0;
}
else
{
T_solver.Mult(r, dk);
}
if (T_solver.GetConverged())
{
return SUNLS_SUCCESS;
}
else
{
return SUNLS_CONV_FAIL;
return 1.0;
}
}
int ConductionOperator::SUNMassSetup()
{
// Do nothing b/c mass solver was setup in constructor.
return SUNLS_SUCCESS;
}
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
{
// Solve the system M x = b.
M_solver.SetRelTol(tol);
M_solver.Mult(b, x);
if (M_solver.GetConverged())
{
return SUNLS_SUCCESS;
}
else
{
return SUNLS_CONV_FAIL;
}
}
int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
{
// Compute M x.
Mmat.Mult(x, v);
return SUNLS_SUCCESS;
}
+189 -286
View File
@@ -1,22 +1,16 @@
// MFEM Example 16 - Parallel Version
// SUNDIALS Modification
//
// Compile with:
// make ex16p (GNU make)
// make sundials_ex16p (CMake)
// Compile with: make ex16p
//
// Sample runs:
// mpirun -np 4 ex16p
// mpirun -np 4 ex16p -m ../../data/inline-tri.mesh
// mpirun -np 4 ex16p -m ../../data/disc-nurbs.mesh -tf 2
// mpirun -np 4 ex16p -s 12 -a 0.0 -k 1.0
// mpirun -np 4 ex16p -s 15 -a 0.0 -k 1.0
// mpirun -np 4 ex16p -s 8 -a 1.0 -k 0.0 -dt 4e-6 -tf 2e-2 -vs 50
// mpirun -np 4 ex16p -s 11 -a 1.0 -k 0.0 -dt 4e-6 -tf 2e-2 -vs 50
// mpirun -np 8 ex16p -s 9 -a 0.5 -k 0.5 -o 4 -dt 8e-6 -tf 2e-2 -vs 50
// mpirun -np 8 ex16p -s 12 -a 0.5 -k 0.5 -o 4 -dt 8e-6 -tf 2e-2 -vs 50
// mpirun -np 4 ex16p -s 10 -dt 2.0e-4 -tf 4.0e-2
// mpirun -np 4 ex16p -s 13 -dt 2.0e-4 -tf 4.0e-2
// mpirun -np 16 ex16p -m ../../data/fichera-q2.mesh
// mpirun -np 16 ex16p -m ../../data/escher-p2.mesh
// mpirun -np 8 ex16p -m ../../data/beam-tet.mesh -tf 10 -dt 0.1
@@ -44,102 +38,66 @@
using namespace std;
using namespace mfem;
/** After spatial discretization, the conduction model is expressed as
/** After spatial discretization, the conduction model can be written as:
*
* M du/dt = - K(u) u
* du/dt = M^{-1}(-Ku)
*
* where u is the vector representing the temperature, M is the mass matrix,
* and K(u) is the diffusion operator with diffusivity depending on u:
* and K is the diffusion operator with diffusivity depending on u:
* (\kappa + \alpha u).
*
* Class ConductionOperatorOperator represents the above ODE operator in the
* general form F(u, k, t) = G(u, t) where either
*
* 1. F(u, du/dt, t) = du/dt (ODE is expressed in EXPLICIT form)
* G(u, t) = - inv(M) K(u) u
* 2. F(u, du/dt, t) = M du/dt (ODE is expressed in IMPLICIT form)
* G(u, t) = - K(u) u
* Class ConductionOperator represents the right-hand side of the above ODE.
*/
class ConductionOperator : public TimeDependentOperator
{
protected:
ParFiniteElementSpace &fespace;
Array<int> ess_tdof_list; // this list remains empty for pure Neumann b.c.
ParBilinearForm M;
ParBilinearForm *M;
ParBilinearForm *K;
HypreParMatrix Mmat;
const real_t alpha, kappa;
std::unique_ptr<BilinearForm> K;
HypreParMatrix Kmat;
HypreParMatrix *T; // T = M + dt K
double current_dt;
std::unique_ptr<HypreParMatrix> T; // T = M + gam K(u)
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
HypreSmoother M_prec; // Preconditioner for the mass matrix M
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
HypreSmoother M_prec; // Preconditioner for the mass matrix M
CGSolver T_solver; // Implicit solver for T = M + dt K
HypreSmoother T_prec; // Preconditioner for the implicit solver
CGSolver T_solver; // Implicit solver for T = M + gam K(u)
HypreSmoother T_prec; // Preconditioner for the implicit solver
double alpha, kappa;
mutable Vector z; // auxiliary vector
public:
ConductionOperator(ParFiniteElementSpace &f, double alpha, double kappa,
const Vector &u);
ConductionOperator(ParFiniteElementSpace &f, const real_t alpha,
const real_t kappa, const Vector &u,
const Type &ode_expression_type);
virtual void Mult(const Vector &u, Vector &du_dt) const;
// Compute K(u_n) for use as an approximation in - K(u) u
void SetConductionTensor(const Vector &u);
/** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
This is the only requirement for high-order SDIRK implicit integration.*/
virtual void ImplicitSolve(const double dt, const Vector &u, Vector &k);
/** Compute G(u, t) as defined in the IMPLICIT expression form of the ODE
operator, i.e., @a v = - K(u_n) @a u. Note that K(u_n) is an
approximation to K(u). */
void ExplicitMult(const Vector &u, Vector &v) const override;
/** Setup the system (M + dt K) x = M b. This method is used by the implicit
SUNDIALS solvers. */
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
int jok, int *jcur, double gamma);
/** Solve for k in F(u, k, t) = G(u, t) for either EXPLICIT or IMPLICIT
expression forms of the ODE operator, i.e., @a k = - inv(M) K(u_n) @a u.
Note that K(u_n) is an approximation to K(u). */
void Mult(const Vector &u, Vector &k) const override;
/** Solve the system (M + dt K) x = M b. This method is used by the implicit
SUNDIALS solvers. */
virtual int SUNImplicitSolve(const Vector &b, Vector &x, double tol);
/** Solve for k in F(u + gam*k, k, t) = G(u + gam*k, t) for either EXPLICIT
or IMPLICIT expression forms of the ODE operator, i.e.,
[ M + @a gam K(u_n) ] @a k = - K(u_n) @a u . Note that K(u_n) is an
approximation to K(u). */
void ImplicitSolve(const real_t gam, const Vector &u, Vector &k) override;
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
void SetParameters(const Vector &u);
/** Setup to solve for dk in [dF/dk + gam*dF/du - gam*dG/du] dk = G - F for
either EXPLICIT or IMPLICIT expression forms of the ODE operator, i.e.,
[M - @a gam Jf(u)] dk = G - F, where Jf(u) is an approximation of the
Jacobian of -K(u) u. The approximation chosen here is Jf(u) = -K(u_n). */
int SUNImplicitSetup(const Vector &u, const Vector &fu, int jok, int *jcur,
real_t gam) override;
/** Solve for @a dk in the system in SUNImplicitSetup to the given tolerance,
with the residual @a r providing either
1. @a r = G - F = inv(M) f(u) - k (EXPLICIT expression form)
1. @a r = G - F = f(u) - M k (IMPLICIT expression form)
*/
int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol) override;
int SUNMassSetup() override;
int SUNMassSolve(const Vector &b, Vector &x, real_t tol) override;
int SUNMassMult(const Vector &x, Vector &v) override;
virtual ~ConductionOperator();
};
real_t InitialTemperature(const Vector &x)
{
if (x.Norml2() < 0.5)
{
return 2.0;
}
else
{
return 1.0;
}
}
double InitialTemperature(const Vector &x);
int main(int argc, char *argv[])
{
@@ -156,16 +114,16 @@ int main(int argc, char *argv[])
int par_ref_levels = 1;
int order = 2;
int ode_solver_type = 9; // CVODE implicit BDF
real_t t_final = 0.5;
real_t dt = 1.0e-2;
real_t alpha = 1.0e-2;
real_t kappa = 0.5;
double t_final = 0.5;
double dt = 1.0e-2;
double alpha = 1.0e-2;
double kappa = 0.5;
bool visualization = true;
bool visit = false;
int vis_steps = 5;
// Relative and absolute tolerances for CVODE and ARKODE.
const real_t reltol = 1e-4, abstol = 1e-4;
const double reltol = 1e-4, abstol = 1e-4;
int precision = 8;
cout.precision(precision);
@@ -192,10 +150,7 @@ int main(int argc, char *argv[])
"9 - CVODE (implicit BDF),\n\t"
"10 - ARKODE (default explicit),\n\t"
"11 - ARKODE (explicit Fehlberg-6-4-5),\n\t"
"12 - ARKODE (default implicit),\n\t"
"13 - ARKODE (default explicit with MFEM mass solve),\n\t"
"14 - ARKODE (explicit Fehlberg-6-4-5 with MFEM mass solve),\n\t"
"15 - ARKODE (default implicit with MFEM mass solve).");
"12 - ARKODE (default impicit).");
args.AddOption(&t_final, "-tf", "--t-final",
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
@@ -219,33 +174,40 @@ int main(int argc, char *argv[])
return 1;
}
if (Mpi::Root())
if (myid == 0)
{
args.PrintOptions(cout);
}
bool use_mass_solver = ode_solver_type >= 13;
// check for valid ODE solver option
if (ode_solver_type < 1 || ode_solver_type > 12)
{
if (myid == 0)
{
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
}
return 1;
}
// 3. Define a parallel mesh by a partitioning of a serial mesh. Read the
// serial mesh from the given mesh file on all processors. We can
// 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.
std::unique_ptr<ParMesh> pmesh;
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++)
{
std::unique_ptr<Mesh> mesh(new Mesh(mesh_file, 1, 1));
// 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. Refine this mesh further in parallel to increase the resolution.
// Once the parallel mesh is defined, the serial mesh can be deleted.
pmesh = std::make_unique<ParMesh>(MPI_COMM_WORLD, *mesh);
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();
@@ -253,9 +215,8 @@ int main(int argc, char *argv[])
// 6. Define the vector finite element space representing the current and the
// initial temperature, u_ref.
int dim = pmesh->Dimension();
H1_FECollection fe_coll(order, dim);
ParFiniteElementSpace fespace(pmesh.get(), &fe_coll);
ParFiniteElementSpace fespace(pmesh, &fe_coll);
int fe_size = fespace.GlobalTrueVSize();
if (myid == 0)
@@ -272,17 +233,8 @@ int main(int argc, char *argv[])
Vector u;
u_gf.GetTrueDofs(u);
// 8. Initialize the conduction ODE operator and the visualization.
ConductionOperator::Type ode_expression_type;
if (use_mass_solver)
{
ode_expression_type = ConductionOperator::Type::IMPLICIT;
}
else
{
ode_expression_type = ConductionOperator::Type::EXPLICIT;
}
ConductionOperator oper(fespace, alpha, kappa, u, ode_expression_type);
// 8. Initialize the conduction operator and the VisIt visualization.
ConductionOperator oper(fespace, alpha, kappa, u);
u_gf.SetFromTrueDofs(u);
{
@@ -297,7 +249,7 @@ int main(int argc, char *argv[])
u_gf.Save(osol);
}
VisItDataCollection visit_dc("Example16-Parallel", pmesh.get());
VisItDataCollection visit_dc("Example16-Parallel", pmesh);
visit_dc.RegisterField("temperature", &u_gf);
if (visit)
{
@@ -341,76 +293,52 @@ int main(int argc, char *argv[])
}
// 9. Define the ODE solver used for time integration.
real_t t = 0.0;
std::unique_ptr<ODESolver> ode_solver;
double t = 0.0;
ODESolver *ode_solver = NULL;
CVODESolver *cvode = NULL;
ARKStepSolver *arkode = NULL;
switch (ode_solver_type)
{
// MFEM explicit methods
case 1: ode_solver = std::make_unique<ForwardEulerSolver>(); break;
case 2: ode_solver = std::make_unique<RK2Solver>(0.5); break; // midpoint method
case 3: ode_solver = std::make_unique<RK3SSPSolver>(); break;
case 4: ode_solver = std::make_unique<RK4Solver>(); break;
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(0.5); break; // midpoint method
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
// MFEM implicit L-stable methods
case 5: ode_solver = std::make_unique<BackwardEulerSolver>(); break;
case 6: ode_solver = std::make_unique<SDIRK23Solver>(2); break;
case 7: ode_solver = std::make_unique<SDIRK33Solver>(); break;
case 5: ode_solver = new BackwardEulerSolver; break;
case 6: ode_solver = new SDIRK23Solver(2); break;
case 7: ode_solver = new SDIRK33Solver; break;
// CVODE
case 8:
case 9:
{
int cvode_solver_type;
if (ode_solver_type == 8)
{
cvode_solver_type = CV_ADAMS;
}
else
{
cvode_solver_type = CV_BDF;
}
std::unique_ptr<CVODESolver> cvode(
new CVODESolver(MPI_COMM_WORLD, cvode_solver_type));
cvode = new CVODESolver(MPI_COMM_WORLD, CV_ADAMS);
cvode->Init(oper);
cvode->SetSStolerances(reltol, abstol);
cvode->SetMaxStep(dt);
ode_solver = std::move(cvode);
break;
}
ode_solver = cvode; break;
case 9:
cvode = new CVODESolver(MPI_COMM_WORLD, CV_BDF);
cvode->Init(oper);
cvode->SetSStolerances(reltol, abstol);
cvode->SetMaxStep(dt);
ode_solver = cvode; break;
// ARKODE
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
{
ARKStepSolver::Type arkode_solver_type;
if (ode_solver_type == 12 || ode_solver_type == 15)
{
arkode_solver_type = ARKStepSolver::IMPLICIT;
}
else
{
arkode_solver_type = ARKStepSolver::EXPLICIT;
}
std::unique_ptr<ARKStepSolver> arkode(
new ARKStepSolver(MPI_COMM_WORLD, arkode_solver_type));
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::EXPLICIT);
arkode->Init(oper);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
if (ode_solver_type == 11 || ode_solver_type == 14)
if (ode_solver_type == 11)
{
arkode->SetERKTableNum(ARKODE_FEHLBERG_13_7_8);
}
if (use_mass_solver)
{
arkode->UseMFEMMassLinearSolver(SUNFALSE);
}
ode_solver = std::move(arkode);
break;
}
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
return 3;
ode_solver = arkode; break;
case 12:
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::IMPLICIT);
arkode->Init(oper);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
ode_solver = arkode; break;
}
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
@@ -418,18 +346,12 @@ int main(int argc, char *argv[])
// Since we want to update the diffusion coefficient after every time step,
// we need to use the "one-step" mode of the SUNDIALS solvers.
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
{
cvode->SetStepMode(CV_ONE_STEP);
}
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
{
arkode->SetStepMode(ARK_ONE_STEP);
}
if (cvode) { cvode->SetStepMode(CV_ONE_STEP); }
if (arkode) { arkode->SetStepMode(ARK_ONE_STEP); }
// 10. Perform time-integration (looping over the time iterations, ti, with a
// time-step dt).
if (Mpi::Root())
if (myid == 0)
{
cout << "Integrating the ODE ..." << endl;
}
@@ -439,7 +361,7 @@ int main(int argc, char *argv[])
bool last_step = false;
for (int ti = 1; !last_step; ti++)
{
real_t dt_real = min(dt, t_final - t);
double dt_real = min(dt, t_final - t);
// Note that since we are using the "one-step" mode of the SUNDIALS
// solvers, they will, generally, step over the final time and will not
@@ -455,14 +377,8 @@ int main(int argc, char *argv[])
if (myid == 0)
{
cout << "step " << ti << ", t = " << t << endl;
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
{
cvode->PrintInfo();
}
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
{
arkode->PrintInfo();
}
if (cvode) { cvode->PrintInfo(); }
if (arkode) { arkode->PrintInfo(); }
}
u_gf.SetFromTrueDofs(u);
@@ -479,38 +395,46 @@ int main(int argc, char *argv[])
visit_dc.Save();
}
}
oper.SetConductionTensor(u);
oper.SetParameters(u);
}
tic_toc.Stop();
if (Mpi::Root())
if (myid == 0)
{
cout << "Done, " << tic_toc.RealTime() << "s." << endl;
}
// 11. Save the final solution in parallel. This output can be viewed later
// using GLVis: "glvis -np <np> -m ex16-mesh -g ex16-final".
u_gf.Save("ex16-final", precision);
{
ostringstream sol_name;
sol_name << "ex16-final." << setfill('0') << setw(6) << myid;
ofstream osol(sol_name.str().c_str());
osol.precision(precision);
u_gf.Save(osol);
}
// 12. Free the used memory.
delete ode_solver;
delete pmesh;
return 0;
}
ConductionOperator::ConductionOperator(ParFiniteElementSpace &fes,
const real_t alpha, const real_t kappa,
const Vector &u,
const Type &ode_expression_type)
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace),
M_solver(fes.GetComm()), T_solver(fes.GetComm()), z(height)
ConductionOperator::ConductionOperator(ParFiniteElementSpace &f, double al,
double kap, const Vector &u)
: TimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL), K(NULL),
T(NULL),
M_solver(f.GetComm()), T_solver(f.GetComm()), z(height)
{
// specify a relative tolerance for all solves with MFEM integrators
const real_t rel_tol = 1e-8;
const double rel_tol = 1e-8;
M.AddDomainIntegrator(new MassIntegrator());
M.Assemble(0); // keep zeros to keep sparsity pattern of M and K the same
M.FormSystemMatrix(ess_tdof_list, Mmat);
M = new ParBilinearForm(&fespace);
M->AddDomainIntegrator(new MassIntegrator());
M->Assemble(0); // keep sparsity pattern of M and K the same
M->FormSystemMatrix(ess_tdof_list, Mmat);
M_solver.iterative_mode = false;
M_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
M_solver.SetRelTol(rel_tol);
M_solver.SetAbsTol(0.0);
M_solver.SetMaxIter(100);
M_solver.SetPrintLevel(0);
@@ -518,118 +442,97 @@ ConductionOperator::ConductionOperator(ParFiniteElementSpace &fes,
M_solver.SetPreconditioner(M_prec);
M_solver.SetOperator(Mmat);
alpha = al;
kappa = kap;
T_solver.iterative_mode = false;
T_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
T_solver.SetRelTol(rel_tol);
T_solver.SetAbsTol(0.0);
T_solver.SetMaxIter(100);
T_solver.SetPrintLevel(0);
T_solver.SetPreconditioner(T_prec);
SetConductionTensor(u);
SetParameters(u);
}
void ConductionOperator::SetConductionTensor(const Vector &u)
void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
{
// Compute:
// du_dt = M^{-1}*-K(u)
// for du_dt
Kmat.Mult(u, z);
z.Neg(); // z = -z
M_solver.Mult(z, du_dt);
}
void ConductionOperator::ImplicitSolve(const double dt,
const Vector &u, Vector &du_dt)
{
// Solve the equation:
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
// for du_dt
if (T) { delete T; }
T = Add(1.0, Mmat, dt, Kmat);
T_solver.SetOperator(*T);
Kmat.Mult(u, z);
z.Neg();
T_solver.Mult(z, du_dt);
}
int ConductionOperator::SUNImplicitSetup(const Vector &x,
const Vector &fx, int jok, int *jcur,
double gamma)
{
// Setup the ODE Jacobian T = M + gamma K.
if (T) { delete T; }
T = Add(1.0, Mmat, gamma, Kmat);
T_solver.SetOperator(*T);
*jcur = 1;
return (0);
}
int ConductionOperator::SUNImplicitSolve(const Vector &b, Vector &x, double tol)
{
// Solve the system A x = z => (M - gamma K) x = M b.
Mmat.Mult(b, z);
T_solver.Mult(z, x);
return (0);
}
void ConductionOperator::SetParameters(const Vector &u)
{
// Compute K(u_n).
ParGridFunction u_alpha_gf(&fespace);
u_alpha_gf.SetFromTrueDofs(u);
for (int i = 0; i < u_alpha_gf.Size(); i++)
{
u_alpha_gf(i) = kappa + alpha*u_alpha_gf(i);
}
delete K;
K = new ParBilinearForm(&fespace);
GridFunctionCoefficient u_coeff(&u_alpha_gf);
K = std::make_unique<ParBilinearForm>(&fespace);
K->AddDomainIntegrator(new DiffusionIntegrator(u_coeff));
K->Assemble(0); // keep zeros to keep sparsity pattern of M and K the same
K->Assemble(0); // keep sparsity pattern of M and K the same
K->FormSystemMatrix(ess_tdof_list, Kmat);
}
void ConductionOperator::ExplicitMult(const Vector &u, Vector &v) const
ConductionOperator::~ConductionOperator()
{
// Compute - K(u_n) u.
Kmat.Mult(u, v);
v.Neg();
delete T;
delete M;
delete K;
}
void ConductionOperator::Mult(const Vector &u, Vector &k) const
double InitialTemperature(const Vector &x)
{
// Compute - inv(M) K(u_n) u.
ExplicitMult(u, z);
M_solver.Mult(z, k);
}
void ConductionOperator::ImplicitSolve(const real_t gam, const Vector &u,
Vector &k)
{
// Solve for k in M k = - K(u_n) [u + gam*k].
ExplicitMult(u, z);
T = std::unique_ptr<HypreParMatrix>(Add(1.0, Mmat, gam, Kmat));
T_solver.SetOperator(*T);
T_solver.Mult(z, k);
}
int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
int jok, int *jcur, real_t gam)
{
// Compute T = M + gamma K(u_n).
T = std::unique_ptr<HypreParMatrix>(Add(1.0, Mmat, gam, Kmat));
T_solver.SetOperator(*T);
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
return SUNLS_SUCCESS;
}
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
real_t tol)
{
// Solve the system [M + gamma K(u_n)] dk = - K(u_n) u - M k.
// What value r is providing depends on the ODE expression form:
// EXPLICIT form: r = -inv(M) K(u_n) u - k
// IMPLICIT form: r = -K(u_n) u - M k
T_solver.SetRelTol(tol);
if (isExplicit())
if (x.Norml2() < 0.5)
{
Mmat.Mult(r, z);
T_solver.Mult(z, dk);
return 2.0;
}
else
{
T_solver.Mult(r, dk);
}
if (T_solver.GetConverged())
{
return SUNLS_SUCCESS;
}
else
{
return SUNLS_CONV_FAIL;
return 1.0;
}
}
int ConductionOperator::SUNMassSetup()
{
// Do nothing b/c mass solver was setup in constructor.
return SUNLS_SUCCESS;
}
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
{
// Solve the system M x = b.
M_solver.SetRelTol(tol);
M_solver.Mult(b, x);
if (M_solver.GetConverged())
{
return SUNLS_SUCCESS;
}
else
{
return SUNLS_CONV_FAIL;
}
}
int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
{
// Compute M x.
Mmat.Mult(x, v);
return SUNLS_SUCCESS;
}
+1 -3
View File
@@ -1,9 +1,7 @@
// MFEM Example 9
// SUNDIALS Modification
//
// Compile with:
// make ex9 (GNU make)
// make sundials_ex9 (CMake)
// Compile with: make ex9
//
// Sample runs:
// ex9 -m ../../data/periodic-segment.mesh -p 0 -r 2 -s 7 -dt 0.005
+1 -3
View File
@@ -1,9 +1,7 @@
// MFEM Example 9 - Parallel Version
// SUNDIALS Modification
//
// Compile with:
// make ex9p (GNU make)
// make sundials_ex9p (CMake)
// Compile with: make ex9p
//
// Sample runs:
// mpirun -np 4 ex9p -m ../../data/periodic-segment.mesh -p 1 -rp 1 -s 7 -dt 0.0025
+4 -9
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/sundials/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
@@ -99,12 +100,6 @@ ex10-test-seq: ex10
@$(call mfem-test,$<,, $(SERIAL_NAME),$(EX10_ARGS))
ex10p-test-par: ex10p
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME),$(EX10P_ARGS))
# Example 16: test ARKODE with implicit time stepping using mass form
EX16_COMMON_ARGS := -s 15
ex16-test-seq: ex16
@$(call mfem-test,$<,, $(SERIAL_NAME),$(EX16_COMMON_ARGS))
ex16p-test-par: ex16p
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME),$(EX16_COMMON_ARGS))
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/superlu/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
+2 -17
View File
@@ -52,15 +52,6 @@ protected:
const DenseMatrix &EvalTransAdjugateJ();
const DenseMatrix &EvalInverseJ();
/// @name Tolerance used for point comparisons
///@{
#ifdef MFEM_USE_DOUBLE
static constexpr real_t tol_0 = 1e-15;
#elif defined(MFEM_USE_SINGLE)
static constexpr real_t tol_0 = 1e-7;
#endif
///@}
public:
/** This enumeration declares the values stored in
@@ -185,7 +176,7 @@ public:
returned. This method is not 100 percent reliable for non-linear
transformations. */
virtual int TransformBack(const Vector &pt, IntegrationPoint &ip,
const real_t phys_tol = tol_0) = 0;
const real_t phys_tol = 1e-15) = 0;
virtual ~ElementTransformation() { }
};
@@ -290,15 +281,9 @@ public:
rel_qpts_order(-1),
solver_type(NewtonElementProject),
max_iter(16),
#ifdef MFEM_USE_DOUBLE
ref_tol(1e-15),
phys_rtol(1e-15),
ip_tol(1e-8),
#elif defined(MFEM_USE_SINGLE)
ref_tol(1e-7),
phys_rtol(1e-7),
ip_tol(1e-4),
#endif
print_level(-1)
{ }
@@ -464,7 +449,7 @@ public:
returned. This method is not 100 percent reliable for non-linear
transformations. */
virtual int TransformBack(const Vector & v, IntegrationPoint & ip,
const real_t phys_rel_tol = tol_0)
const real_t phys_rel_tol = 1e-15)
{
InverseElementTransformation inv_tr(this);
inv_tr.SetPhysicalRelTol(phys_rel_tol);
+25 -26
View File
@@ -394,32 +394,7 @@ public:
/// Get a const reference to the nodes of the element
const IntegrationRule & GetNodes() const { return Nodes; }
/** @brief Evaluate the Hessians of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
part of the Hessian of one shape function.
The order in 2D is {u_xx, u_xy, u_yy}.
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
element in physical space at the given point @a ip. */
/** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
void CalcPhysHessian(ElementTransformation &Trans,
DenseMatrix& Hessian) const;
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
element in physical space at the given point @a ip. */
/** The size (#dof) of @a Laplacian must be set in advance. */
void CalcPhysLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
element in physical space at the given point @a ip. */
/** The size (#dof) of @a Laplacian must be set in advance. */
void CalcPhysLinLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
// virtual functions for finite elements on vector spaces
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in reference space at the given point @a ip. */
@@ -479,6 +454,30 @@ public:
*/
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
/** @brief Evaluate the Hessians of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
part of the Hessian of one shape function.
The order in 2D is {u_xx, u_xy, u_yy}.
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
virtual void CalcPhysHessian(ElementTransformation &Trans,
DenseMatrix& Hessian) const;
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** The size (#dof) of @a Laplacian must be set in advance. */
virtual void CalcPhysLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
virtual void CalcPhysLinLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
/** @brief Return the local interpolation matrix @a I (Dof x Dof) where the
fine element is the image of the base geometry under the given
transformation. */
+1 -614
View File
@@ -398,621 +398,8 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip,
hessian(o,5) = hessian(o,5)*sum
- 2*du(o,1)*sum*dsum[1]
+ u[o]*sum*(2*dsum[1]*dsum[1] - d2sum[5]);
}
}
void NURBS_HDiv2DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
order = max(orders[0]+1, orders[1]+1);
dof = (orders[0] + 2)*(orders[1] + 1)
+ (orders[1] + 1)*(orders[1] + 2);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HDiv2DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,0) = shape1_x(i)*sy;
shape(o,1) = 0.0;
}
}
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1 = shape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,0) = 0.0;
shape(o,1) = shape_x(i)*sy1;
}
}
}
void NURBS_HDiv2DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & J = Trans.Jacobian();
MFEM_ASSERT(J.Width() == 2 && J.Height() == 2,
"NURBS_HDiv2DFiniteElement cannot be embedded in "
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
shape(i, 0) = sx * J(0, 0) + sy * J(0, 1);
shape(i, 1) = sx * J(1, 0) + sy * J(1, 1);
}
shape *= (1.0 / Trans.Weight());
}
void NURBS_HDiv2DFiniteElement::CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
divshape(o) = dshape1_x(i)*sy;
}
}
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t dsy1 = dshape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
divshape(o) = shape_x(i)*dsy1;
}
}
}
NURBS_HDiv2DFiniteElement::~NURBS_HDiv2DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
}
void NURBS_HDiv3DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
orders[2] = kv[2]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
kv1[2] = kv[2]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
shape_z.SetSize(orders[2]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
dshape_z.SetSize(orders[2]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
d2shape_z.SetSize(orders[2]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
shape1_z.SetSize(orders[2]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
dshape1_z.SetSize(orders[2]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
d2shape1_z.SetSize(orders[2]+2);
order = max(orders[0]+1, max( orders[1]+1, orders[2]+1));
dof = (orders[0] + 2)*(orders[1] + 1)*(orders[2] + 1) +
(orders[0] + 1)*(orders[1] + 2)*(orders[2] + 1) +
(orders[0] + 1)*(orders[1] + 1)*(orders[2] + 2);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HDiv3DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv[2]->CalcShape(shape_z, ijk[2], ip.z);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
shape = 0.0;
int o = 0;
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz = shape_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,0) = shape1_x(i)*sy_sz;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz = shape1_y(j)*sz;
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,1) = shape_x(i)*sy1_sz;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz1 = shape_y(j)*sz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,2) = shape_x(i)*sy_sz1;
}
}
}
}
void NURBS_HDiv3DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & J = Trans.Jacobian();
MFEM_ASSERT(J.Width() == 3 && J.Height() == 3,
"RT_R2D_FiniteElement cannot be embedded in "
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
real_t sz = shape(i, 2);
shape(i, 0) = sx * J(0, 0) + sy * J(0, 1) + sz * J(0, 2);
shape(i, 1) = sx * J(1, 0) + sy * J(1, 1) + sz * J(1, 2);
shape(i, 2) = sx * J(2, 0) + sy * J(2, 1) + sz * J(2, 2);
}
shape *= (1.0 / Trans.Weight());
}
void NURBS_HDiv3DFiniteElement::CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv[2]->CalcShape ( shape_z, ijk[2], ip.z);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
kv1[2]->CalcDShape(dshape1_z, ijk[2], ip.z);
int o = 0;
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz = shape_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
divshape(o) = dshape1_x(i)*sy_sz;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t dy1_sz = dshape1_y(j)*sz;
for (int i = 0; i <= orders[0]; i++, o++)
{
divshape(o) = shape_x(i)*dy1_sz;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t dz1 = dshape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_dz1 = shape_y(j)*dz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
divshape(o) = shape_x(i)*sy_dz1;
}
}
}
}
NURBS_HDiv3DFiniteElement::~NURBS_HDiv3DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
}
void NURBS_HCurl2DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
order = max(orders[0]+1, orders[1]+1);
dof = (orders[0] + 1)*(orders[1] + 2)
+ (orders[1] + 2)*(orders[1] + 1);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HCurl2DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1 = shape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,0) = shape_x(i)*sy1;
shape(o,1) = 0.0;
}
}
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,0) = 0.0;
shape(o,1) = shape1_x(i)*sy;
}
}
}
void NURBS_HCurl2DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & JI = Trans.InverseJacobian();
MFEM_ASSERT(JI.Width() == 2 && JI.Height() == 2,
"NURBS_HCurl2DFiniteElement cannot be embedded in "
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
shape(i, 0) = sx * JI(0, 0) + sy * JI(1, 0);
shape(i, 1) = sx * JI(0, 1) + sy * JI(1, 1);
}
}
void NURBS_HCurl2DFiniteElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t dsy1 = dshape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
curl_shape(o,0) = -shape_x(i)*dsy1;
}
}
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
curl_shape(o,0) = dshape1_x(i)*sy;
}
}
}
NURBS_HCurl2DFiniteElement::~NURBS_HCurl2DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
}
void NURBS_HCurl3DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
orders[2] = kv[2]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
kv1[2] = kv[2]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
shape_z.SetSize(orders[2]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
dshape_z.SetSize(orders[2]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
d2shape_z.SetSize(orders[2]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
shape1_z.SetSize(orders[2]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
dshape1_z.SetSize(orders[2]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
d2shape1_z.SetSize(orders[2]+2);
order = max(orders[0]+1, max( orders[1]+1, orders[2]+1));
dof = (orders[0] + 1)*(orders[1] + 2)*(orders[2] + 2) +
(orders[0] + 2)*(orders[1] + 1)*(orders[2] + 2) +
(orders[0] + 2)*(orders[1] + 2)*(orders[2] + 1);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HCurl3DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv[2]->CalcShape(shape_z, ijk[2], ip.z);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
shape = 0.0;
int o = 0;
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz1 = shape1_y(j)*sz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,0) = shape_x(i)*sy1_sz1;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz1 = shape_y(j)*sz1;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,1) = shape1_x(i)*sy_sz1;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz = shape1_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,2) = shape1_x(i)*sy1_sz;
}
}
}
}
void NURBS_HCurl3DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & JI = Trans.InverseJacobian();
MFEM_ASSERT(JI.Width() == 3 && JI.Height() == 3,
"NURBS_HCurl3DFiniteElement must be in a"
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
real_t sz = shape(i, 2);
shape(i, 0) = sx * JI(0, 0) + sy * JI(1, 0) + sz * JI(2, 0);
shape(i, 1) = sx * JI(0, 1) + sy * JI(1, 1) + sz * JI(2, 1);
shape(i, 2) = sx * JI(0, 2) + sy * JI(1, 2) + sz * JI(2, 2);
}
}
void NURBS_HCurl3DFiniteElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv[2]->CalcShape ( shape_z, ijk[2], ip.z);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
kv1[2]->CalcDShape(dshape1_z, ijk[2], ip.z);
int o = 0;
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k), dsz1 = dshape1_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_dsz1 = shape1_y(j)*dsz1,
dsy1_sz1 = dshape1_y(j)*sz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
curl_shape(o,0) = 0.0;
curl_shape(o,1) = shape_x(i)*sy1_dsz1;
curl_shape(o,2) = -shape_x(i)*dsy1_sz1;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k), dsz1 = dshape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_dsz1 = shape_y(j)*dsz1,
sy_sz1 = shape_y(j)*sz1;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
curl_shape(o,0) = -shape1_x(i)*sy_dsz1;
curl_shape(o,1) = 0.0;
curl_shape(o,2) = dshape1_x(i)*sy_sz1;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz = shape1_y(j)*sz,
dsy1_sz = dshape1_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
curl_shape(o,0) = shape1_x(i)*dsy1_sz;
curl_shape(o,1) = -dshape1_x(i)*sy1_sz;
curl_shape(o,2) = 0.0;
}
}
}
}
NURBS_HCurl3DFiniteElement::~NURBS_HCurl3DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
}
}
+23 -380
View File
@@ -20,7 +20,7 @@ namespace mfem
class KnotVector;
/// An arbitrary order and dimension NURBS element
class NURBSFiniteElement
class NURBSFiniteElement : public ScalarFiniteElement
{
protected:
mutable Array <const KnotVector*> kv;
@@ -30,34 +30,31 @@ protected:
public:
/** @brief Construct NURBSFiniteElement with given
@param dim Reference space dimension
@param D Reference space dimension
@param G Geometry type (of type Geometry::Type)
@param Do Number of degrees of freedom in the FiniteElement
@param O Order/degree of the FiniteElement
@param F FunctionSpace type of the FiniteElement
*/
NURBSFiniteElement(int dim)
NURBSFiniteElement(int D, Geometry::Type G, int Do, int O, int F)
: ScalarFiniteElement(D, G, Do, O, F)
{
ijk = NULL;
patch = elem = -1;
kv.SetSize(dim);
weights.SetSize(dof);
weights = 1.0;
}
/// Resets the patch and element data stored in the element
void Reset () const { patch = elem = -1; }
/// Set which IJK in patch should be evaluated
void SetIJK (const int *IJK) const { ijk = IJK; }
/// Get which patch is currently considered
int GetPatch () const { return patch; }
/// Set which patch should be evaluated
void SetPatch (int p) const { patch = p; }
/// Set which elemenet should be evaluated
int GetElement () const { return elem; }
/// Get which element is currently considered
void SetElement (int e) const { elem = e; }
/// Get the KnotVectors
Array <const KnotVector*> &KnotVectors() const { return kv; }
/// Get the Weights
Vector &Weights () const { return weights; }
/// Update the polynomial order according to the currently set knotvectors
/// Resizes all internal data members to have the correct size
/// related to the polynomial order
/// Update the NURBSFiniteElement according to the currently set knot vectors
virtual void SetOrder () const { }
/// Returns the indices (i,j) in 2D or (i,j,k) in 3D of this element in the
@@ -67,8 +64,7 @@ public:
/// An arbitrary order 1D NURBS element on a segment
class NURBS1DFiniteElement : public ScalarFiniteElement,
public NURBSFiniteElement
class NURBS1DFiniteElement : public NURBSFiniteElement
{
protected:
mutable Vector shape_x;
@@ -76,8 +72,7 @@ protected:
public:
/// Construct the NURBS1DFiniteElement of order @a p
NURBS1DFiniteElement(int p)
: ScalarFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk),
NURBSFiniteElement(1),
: NURBSFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk),
shape_x(p + 1) { }
virtual void SetOrder() const;
@@ -89,8 +84,7 @@ public:
};
/// An arbitrary order 2D NURBS element on a square
class NURBS2DFiniteElement : public ScalarFiniteElement,
public NURBSFiniteElement
class NURBS2DFiniteElement : public NURBSFiniteElement
{
protected:
mutable Vector u, shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
@@ -99,18 +93,16 @@ protected:
public:
/// Construct the NURBS2DFiniteElement of order @a p
NURBS2DFiniteElement(int p)
: ScalarFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p,
FunctionSpace::Qk),
NURBSFiniteElement(2),
: NURBSFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p,
FunctionSpace::Qk),
u(dof), shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1), du(dof,2)
{ orders[0] = orders[1] = p; }
/// Construct the NURBS2DFiniteElement with x-order @a px and y-order @a py
NURBS2DFiniteElement(int px, int py)
: ScalarFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1),
std::max(px, py), FunctionSpace::Qk),
NURBSFiniteElement(2),
: NURBSFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1),
std::max(px, py), FunctionSpace::Qk),
u(dof), shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1), du(dof,2)
{ orders[0] = px; orders[1] = py; }
@@ -124,8 +116,7 @@ public:
};
/// An arbitrary order 3D NURBS element on a cube
class NURBS3DFiniteElement : public ScalarFiniteElement,
public NURBSFiniteElement
class NURBS3DFiniteElement : public NURBSFiniteElement
{
protected:
mutable Vector u, shape_x, shape_y, shape_z;
@@ -136,9 +127,8 @@ protected:
public:
/// Construct the NURBS3DFiniteElement of order @a p
NURBS3DFiniteElement(int p)
: ScalarFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p,
FunctionSpace::Qk),
NURBSFiniteElement(3),
: NURBSFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p,
FunctionSpace::Qk),
u(dof), shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1), du(dof,3)
@@ -147,9 +137,8 @@ public:
/// Construct the NURBS3DFiniteElement with x-order @a px and y-order @a py
/// and z-order @a pz
NURBS3DFiniteElement(int px, int py, int pz)
: ScalarFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1),
std::max(std::max(px,py),pz), FunctionSpace::Qk),
NURBSFiniteElement(2),
: NURBSFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1),
std::max(std::max(px,py),pz), FunctionSpace::Qk),
u(dof), shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1), du(dof,3)
@@ -163,352 +152,6 @@ public:
DenseMatrix &hessian) const;
};
/** An arbitrary order H(div)-conforming 2D NURBS element on a square.
More details in the following papers:
[1] Annalisa Buffa, Carlo De Falco, Giancarlo Sangalli
"Isogeometric analysis: stable elements for the 2D Stokes equation."
International Journal for Numerical Methods in Fluids 65 (1112) 1407-1422
[2] John A Evans, Thomas JR Hughes
"Isogeometric divergence-conforming B-splines for the unsteady NavierStokes equations."
Journal of Computational Physics (241) 141-167
*/
class NURBS_HDiv2DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
mutable Vector shape1_x, shape1_y, dshape1_x, dshape1_y, d2shape1_x, d2shape1_y;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HDiv2DFiniteElement of order @a p
NURBS_HDiv2DFiniteElement(int p)
: VectorFiniteElement(2, Geometry::SQUARE, 2*(p + 1)*(p + 2), p,
H_DIV,FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1),
shape1_x(p + 2), shape1_y(p + 2), dshape1_x(p + 2),
dshape1_y(p + 2), d2shape1_x(p + 2), d2shape1_y(p + 2),
u(dof), du(dof,2)
{
orders[0] = orders[1] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
/// Construct the NURBS_HDiv2DFiniteElement with x-order @a px and y-order @a py
NURBS_HDiv2DFiniteElement(int px, int py)
: VectorFiniteElement(2, Geometry::SQUARE,
(px + 2)*(py + 1)+(px + 1)*(py + 2),
std::max(px, py), H_DIV, FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1),
shape1_x(px + 2), shape1_y(py + 2), dshape1_x(px + 2),
dshape1_y(py + 2), d2shape1_x(px + 2), d2shape1_y(py + 2),
u(dof), du(dof,2)
{
orders[0] = px; orders[1] = py;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the divergence of all shape functions of a *vector*
finite element in reference space at the given point @a ip. */
/** The size (#dof) of the result Vector @a divshape must be set in advance.
*/
virtual void CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const;
~NURBS_HDiv2DFiniteElement();
};
/** An arbitrary order H(div)-conforming 3D NURBS element on a cube
More details in the following papers:
[1] Annalisa Buffa, Carlo De Falco, Giancarlo Sangalli
"Isogeometric analysis: stable elements for the 2D Stokes equation."
International Journal for Numerical Methods in Fluids 65 (1112) 1407-1422
[2] John A Evans, Thomas JR Hughes
"Isogeometric divergence-conforming B-splines for the unsteady
NavierStokes equations."
Journal of Computational Physics (241) 141-167 */
class NURBS_HDiv3DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, shape_z;
mutable Vector dshape_x, dshape_y, dshape_z;
mutable Vector d2shape_x, d2shape_y, d2shape_z;
mutable Vector shape1_x, shape1_y, shape1_z;
mutable Vector dshape1_x, dshape1_y, dshape1_z;
mutable Vector d2shape1_x, d2shape1_y, d2shape1_z;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HDiv3DFiniteElement of order @a p
NURBS_HDiv3DFiniteElement(int p)
: VectorFiniteElement(3, Geometry::CUBE, 3*(p + 1)*(p + 1)*(p + 2),
p, H_DIV,FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1),
shape1_x(p + 2), shape1_y(p + 2), shape1_z(p + 2),
dshape1_x(p + 2), dshape1_y(p + 2),dshape1_z(p + 2),
d2shape1_x(p + 2), d2shape1_y(p + 2), d2shape1_z(p + 2),
u(dof), du(dof,3)
{
orders[0] = orders[1] = orders[2] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
/// Construct the NURBS_HDiv3DFiniteElement with x-order @a px, y-order @a py and z-order @a pz
NURBS_HDiv3DFiniteElement(int px, int py, int pz)
: VectorFiniteElement(3, Geometry::CUBE,
(px + 2)*(py + 1)*(pz + 1) +
(px + 1)*(py + 2)*(pz + 1) +
(px + 1)*(py + 1)*(pz + 2),
std::max(px, py), H_DIV, FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1),
shape1_x(px + 2), shape1_y(py + 2), shape1_z(pz + 2),
dshape1_x(px + 2), dshape1_y(py + 2),dshape1_z(pz + 2),
d2shape1_x(px + 2), d2shape1_y(py + 2), d2shape1_z(pz + 2),
u(dof), du(dof,3)
{
orders[0] = px; orders[1] = py; orders[2] = pz;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the divergence of all shape functions of a *vector*
finite element in reference space at the given point @a ip. */
/** The size (#dof) of the result Vector @a divshape must be set in advance.
*/
virtual void CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const;
~NURBS_HDiv3DFiniteElement();
};
/** An arbitrary order H(curl)-conforming 2D NURBS element on a square
More details in the following paper:
[1] Annalisa Buffa, Giancarlo Sangalli, Rafael Vázquez
"Isogeometric analysis in electromagnetics: B-splines approximation."
Computer Methods in Applied Mechanics and Engineering (199) 1143-1152 */
class NURBS_HCurl2DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
mutable Vector shape1_x, shape1_y, dshape1_x, dshape1_y, d2shape1_x, d2shape1_y;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HCurl2DFiniteElement of order @a p
NURBS_HCurl2DFiniteElement(int p)
: VectorFiniteElement(2, Geometry::SQUARE, 2*(p + 1)*(p + 2), p,
H_CURL,FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1),
shape1_x(p + 2), shape1_y(p + 2), dshape1_x(p + 2),
dshape1_y(p + 2), d2shape1_x(p + 2), d2shape1_y(p + 2),
u(dof), du(dof,2)
{
orders[0] = orders[1] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
/// Construct the NURBS_HCurl2DFiniteElement with x-order @a px and y-order @a py
NURBS_HCurl2DFiniteElement(int px, int py)
: VectorFiniteElement(2, Geometry::SQUARE,
(px + 1)*(py + 2)+(px + 2)*(py + 1),
std::max(px, py), H_CURL, FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1),
shape1_x(px + 2), shape1_y(py + 2), dshape1_x(px + 2),
dshape1_y(py + 2), d2shape1_x(px + 2), d2shape1_y(py + 2),
u(dof), du(dof,2)
{
orders[0] = px; orders[1] = py;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the curl of all shape functions of a *vector* finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a curl_shape contains the components
of the curl of one vector shape function. The size (#dof x CDim) of
@a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
CDim = 1 for #dim = 2. */
virtual void CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const;
~NURBS_HCurl2DFiniteElement();
};
/** An arbitrary order H(curl)-conforming 3D NURBS element on a cube
More details in the following paper:
[1] Annalisa Buffa, Giancarlo Sangalli, Rafael Vázquez
"Isogeometric analysis in electromagnetics: B-splines approximation."
Computer Methods in Applied Mechanics and Engineering (199) 1143-1152 */
class NURBS_HCurl3DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, shape_z;
mutable Vector dshape_x, dshape_y, dshape_z;
mutable Vector d2shape_x, d2shape_y, d2shape_z;
mutable Vector shape1_x, shape1_y, shape1_z;
mutable Vector dshape1_x, dshape1_y, dshape1_z;
mutable Vector d2shape1_x, d2shape1_y, d2shape1_z;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HCurl3DFiniteElement of order @a p
NURBS_HCurl3DFiniteElement(int p)
: VectorFiniteElement(3, Geometry::CUBE, 3*(p + 1)*(p + 2)*(p + 2), p,
H_CURL,FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1),
shape1_x(p + 2), shape1_y(p + 2), shape1_z(p + 2),
dshape1_x(p + 2), dshape1_y(p + 2),dshape1_z(p + 2),
d2shape1_x(p + 2), d2shape1_y(p + 2), d2shape1_z(p + 2),
u(dof), du(dof,3)
{
orders[0] = orders[1] = orders[2] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
/// Construct the NURBS_HCurl3DFiniteElement with x-order @a px, y-order @a py and z-order @a pz
NURBS_HCurl3DFiniteElement(int px, int py, int pz)
: VectorFiniteElement(3, Geometry::CUBE,
(px + 1)*(py + 2)*(pz + 2) +
(px + 2)*(py + 1)*(pz + 2) +
(px + 2)*(py + 2)*(pz + 1),
std::max(std::max(px, py), pz), H_CURL, FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1),
shape1_x(px + 2), shape1_y(py + 2), shape1_z(pz + 2),
dshape1_x(px + 2), dshape1_y(py + 2),dshape1_z(pz + 2),
d2shape1_x(px + 2), d2shape1_y(py + 2), d2shape1_z(pz + 2),
u(dof), du(dof,3)
{
orders[0] = px; orders[1] = py; orders[2] = pz;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the curl of all shape functions of a *vector* finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a curl_shape contains the components
of the curl of one vector shape function. The size (#dof x CDim) of
@a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
CDim = 1 for #dim = 2. */
virtual void CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const;
~NURBS_HCurl3DFiniteElement();
};
} // namespace mfem
#endif
-214
View File
@@ -344,32 +344,6 @@ FiniteElementCollection *FiniteElementCollection::New(const char *name)
{
fec = new Local_FECollection(name + 6);
}
else if (!strncmp(name, "NURBS_HDiv", 10))
{
if (name[10] != '\0')
{
// "NURBS" + "number" --> fixed order nurbs collection
fec = new NURBS_HDivFECollection(atoi(name + 10));
}
else
{
// "NURBS" --> variable order nurbs collection
fec = new NURBS_HDivFECollection();
}
}
else if (!strncmp(name, "NURBS_HCurl", 11))
{
if (name[11] != '\0')
{
// "NURBS" + "number" --> fixed order nurbs collection
fec = new NURBS_HCurlFECollection(atoi(name + 11));
}
else
{
// "NURBS" --> variable order nurbs collection
fec = new NURBS_HCurlFECollection();
}
}
else if (!strncmp(name, "NURBS", 5))
{
if (name[5] != '\0')
@@ -3559,192 +3533,4 @@ FiniteElementCollection *NURBSFECollection::GetTraceCollection() const
return NULL;
}
NURBS_HDivFECollection::NURBS_HDivFECollection(int Order, const int dim)
: NURBSFECollection((Order == VariableOrder) ? 1 : Order)
{
const int order = (Order == VariableOrder) ? 1 : Order;
SegmentFE = new NURBS1DFiniteElement(order);
QuadrilateralFE = new NURBS2DFiniteElement(order);
QuadrilateralVFE = new NURBS_HDiv2DFiniteElement(order);
ParallelepipedVFE = new NURBS_HDiv3DFiniteElement(order);
if (dim != -1) { SetDim(dim); }
SetOrder(Order);
}
void NURBS_HDivFECollection::SetDim(int dim)
{
if (dim == 2)
{
sFE = SegmentFE;
qFE = QuadrilateralVFE;
hFE = nullptr;
}
else if (dim == 3)
{
sFE = nullptr;
qFE = QuadrilateralFE;
hFE = ParallelepipedVFE;
}
else
{
mfem::err<<"Dimension = "<<dim<<endl;
mfem_error ("NURBS_HDivFECollection: wrong dimension!");
}
}
NURBS_HDivFECollection::~NURBS_HDivFECollection()
{
delete SegmentFE;
delete QuadrilateralFE;
delete QuadrilateralVFE;
delete ParallelepipedVFE;
}
const FiniteElement *
NURBS_HDivFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
switch (GeomType)
{
case Geometry::SEGMENT: return sFE;
case Geometry::SQUARE: return qFE;
case Geometry::CUBE: return hFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("NURBS_HDivFECollection: unknown geometry type.");
}
return QuadrilateralFE; // Make some compilers happy
}
void NURBS_HDivFECollection::SetOrder(int Order) const
{
mOrder = Order;
if (Order != VariableOrder)
{
snprintf(name, 16, "NURBS_HDiv%i", Order);
}
else
{
snprintf(name, 16, "NURBS_HDiv");
}
}
int NURBS_HDivFECollection::DofForGeometry(Geometry::Type GeomType) const
{
mfem_error("NURBS_HDivFECollection::DofForGeometry");
return 0; // Make some compilers happy
}
const int *NURBS_HDivFECollection::DofOrderForOrientation(
Geometry::Type GeomType,
int Or) const
{
mfem_error("NURBS_HDivFECollection::DofOrderForOrientation");
return NULL;
}
FiniteElementCollection *NURBS_HDivFECollection::GetTraceCollection() const
{
MFEM_ABORT("NURBS finite elements can not be statically condensed!");
return NULL;
}
NURBS_HCurlFECollection::NURBS_HCurlFECollection(int Order, const int dim)
: NURBSFECollection((Order == VariableOrder) ? 1 : Order)
{
const int order = (Order == VariableOrder) ? 1 : Order;
SegmentFE = new NURBS1DFiniteElement(order+1);
QuadrilateralFE = new NURBS2DFiniteElement(order+1);
QuadrilateralVFE = new NURBS_HCurl2DFiniteElement(order);
ParallelepipedVFE = new NURBS_HCurl3DFiniteElement(order);
if (dim != -1) { SetDim(dim); }
SetOrder(Order);
}
void NURBS_HCurlFECollection::SetDim(int dim)
{
if (dim == 2)
{
sFE = SegmentFE;
qFE = QuadrilateralVFE;
hFE = nullptr;
}
else if (dim == 3)
{
sFE = nullptr;
qFE = QuadrilateralFE;
hFE = ParallelepipedVFE;
}
else
{
mfem::err<<"Dimension = "<<dim<<endl;
mfem_error ("NURBS_HCurlFECollection: wrong dimension!");
}
}
NURBS_HCurlFECollection::~NURBS_HCurlFECollection()
{
delete SegmentFE;
delete QuadrilateralFE;
delete QuadrilateralVFE;
delete ParallelepipedVFE;
}
const FiniteElement *
NURBS_HCurlFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
switch (GeomType)
{
case Geometry::SEGMENT: return sFE;
case Geometry::SQUARE: return qFE;
case Geometry::CUBE: return hFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("NURBS_HCurlFECollection: unknown geometry type.");
}
return QuadrilateralFE; // Make some compilers happy
}
void NURBS_HCurlFECollection::SetOrder(int Order) const
{
mOrder = Order;
if (Order != VariableOrder)
{
snprintf(name, 16, "NURBS_HCurl%i", Order);
}
else
{
snprintf(name, 16, "NURBS_HCurl");
}
}
int NURBS_HCurlFECollection::DofForGeometry(Geometry::Type GeomType) const
{
mfem_error("NURBS_HCurlFECollection::DofForGeometry");
return 0; // Make some compilers happy
}
const int *NURBS_HCurlFECollection::DofOrderForOrientation(
Geometry::Type GeomType,
int Or) const
{
mfem_error("NURBS_HCurlFECollection::DofOrderForOrientation");
return NULL;
}
FiniteElementCollection *NURBS_HCurlFECollection::GetTraceCollection() const
{
MFEM_ABORT("NURBS finite elements can not be statically condensed!");
return NULL;
}
}
+4 -109
View File
@@ -680,8 +680,8 @@ public:
/// Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
class NURBSFECollection : public FiniteElementCollection
{
protected:
PointFiniteElement *PointFE;
private:
PointFiniteElement *PointFE;
NURBS1DFiniteElement *SegmentFE;
NURBS2DFiniteElement *QuadrilateralFE;
NURBS3DFiniteElement *ParallelepipedFE;
@@ -701,15 +701,13 @@ public:
order, or VariableOrder (default). */
explicit NURBSFECollection(int Order = VariableOrder);
virtual void Reset() const
void Reset() const
{
SegmentFE->Reset();
QuadrilateralFE->Reset();
ParallelepipedFE->Reset();
}
virtual void SetDim(const int dim) {};
/** @brief Get the order of the NURBS collection: either a positive number,
when using fixed order, or VariableOrder. */
/** @note Not to be confused with FiniteElementCollection::GetOrder(). */
@@ -717,7 +715,7 @@ public:
/** @brief Set the order and the name, based on the given @a Order: either a
positive number for fixed order, or VariableOrder. */
virtual void SetOrder(int Order) const;
void SetOrder(int Order) const;
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
@@ -736,109 +734,6 @@ public:
virtual ~NURBSFECollection();
};
/// Arbitrary order H(div) NURBS finite elements.
class NURBS_HDivFECollection : public NURBSFECollection
{
private:
NURBS1DFiniteElement *SegmentFE;
NURBS2DFiniteElement *QuadrilateralFE;
NURBS_HDiv2DFiniteElement *QuadrilateralVFE;
NURBS_HDiv3DFiniteElement *ParallelepipedVFE;
FiniteElement *sFE;
FiniteElement *qFE;
FiniteElement *hFE;
public:
/** @brief The parameter @a Order must be either a positive number, for fixed
order, or VariableOrder (default). */
explicit NURBS_HDivFECollection(int Order = VariableOrder, const int vdim = -1);
virtual void Reset() const override
{
SegmentFE->Reset();
QuadrilateralFE->Reset();
QuadrilateralVFE->Reset();
ParallelepipedVFE->Reset();
}
virtual void SetDim(const int dim) override;
/** @brief Set the order and the name, based on the given @a Order: either a
positive number for fixed order, or VariableOrder. */
virtual void SetOrder(int Order) const override;
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
int DofForGeometry(Geometry::Type GeomType) const override;
const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const override;
const char *Name() const override { return name; }
int GetContType() const override { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const override;
virtual ~NURBS_HDivFECollection();
};
/// Arbitrary order H(curl) NURBS finite elements.
class NURBS_HCurlFECollection : public NURBSFECollection
{
private:
NURBS1DFiniteElement *SegmentFE;
NURBS2DFiniteElement *QuadrilateralFE;
NURBS_HCurl2DFiniteElement *QuadrilateralVFE;
NURBS_HCurl3DFiniteElement *ParallelepipedVFE;
FiniteElement *sFE;
FiniteElement *qFE;
FiniteElement *hFE;
public:
/** @brief The parameter @a Order must be either a positive number, for fixed
order, or VariableOrder (default). */
explicit NURBS_HCurlFECollection(int Order = VariableOrder,
const int vdim = -1);
virtual void Reset() const override
{
SegmentFE->Reset();
QuadrilateralFE->Reset();
QuadrilateralVFE->Reset();
ParallelepipedVFE->Reset();
}
virtual void SetDim(const int dim) override;
/** @brief Set the order and the name, based on the given @a Order: either a
positive number for fixed order, or VariableOrder. */
virtual void SetOrder(int Order) const override;
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
int DofForGeometry(Geometry::Type GeomType) const override;
const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const override;
const char *Name() const override { return name; }
int GetContType() const override { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const override;
virtual ~NURBS_HCurlFECollection();
};
/// Piecewise-(bi/tri)linear continuous finite elements.
class LinearFECollection : public FiniteElementCollection
{
+37 -262
View File
@@ -1525,67 +1525,6 @@ SparseMatrix *FiniteElementSpace::RefinementMatrix_main(
return P;
}
SparseMatrix *FiniteElementSpace::VariableOrderRefinementMatrix(
const int coarse_ndofs, const Table &coarse_elem_dof) const
{
MFEM_VERIFY(mesh->GetLastOperation() == Mesh::REFINE, "");
Array<int> dofs, coarse_dofs, coarse_vdofs;
Vector row;
Mesh::GeometryList elem_geoms(*mesh);
SparseMatrix *P = new SparseMatrix(GetVSize(), coarse_ndofs*vdim);
Array<int> mark(P->Height());
mark = 0;
const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
DenseMatrix lP;
IsoparametricTransformation isotr;
for (int k = 0; k < mesh->GetNE(); k++)
{
const Embedding &emb = rtrans.embeddings[k];
const Geometry::Type geom = mesh->GetElementBaseGeometry(k);
const FiniteElement *fe = GetFE(k);
isotr.SetIdentityTransformation(geom);
const int ldof = fe->GetDof();
lP.SetSize(ldof, ldof);
const DenseTensor &pmats = rtrans.point_matrices[geom];
isotr.SetPointMat(pmats(emb.matrix));
fe->GetLocalInterpolation(isotr, lP);
const int fine_ldof = lP.Height();
elem_dof->GetRow(k, dofs);
coarse_elem_dof.GetRow(emb.parent, coarse_dofs);
for (int vd = 0; vd < vdim; vd++)
{
coarse_dofs.Copy(coarse_vdofs);
DofsToVDofs(vd, coarse_vdofs, coarse_ndofs);
for (int i = 0; i < fine_ldof; i++)
{
const int r = DofToVDof(dofs[i], vd);
int m = (r >= 0) ? r : (-1 - r);
if (!mark[m])
{
lP.GetRow(i, row);
P->SetRow(r, coarse_vdofs, row);
mark[m] = 1;
}
}
}
}
MFEM_VERIFY(mark.Sum() == P->Height(), "Not all rows of P set.");
P->Finalize();
return P;
}
void FiniteElementSpace::GetLocalRefinementMatrices(
Geometry::Type geom, DenseTensor &localP) const
{
@@ -1617,20 +1556,15 @@ SparseMatrix* FiniteElementSpace::RefinementMatrix(int old_ndofs,
"Previous mesh is not coarser.");
Mesh::GeometryList elem_geoms(*mesh);
if (!IsVariableOrder())
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
{
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
{
GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
localP);
}
else
{
return VariableOrderRefinementMatrix(old_ndofs, *old_elem_dof);
GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
localP);
}
FiniteElementSpace::RefinementOperator::RefinementOperator(
@@ -1648,12 +1582,9 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
if (!fespace->IsVariableOrder())
for (int i = 0; i < elem_geoms.Size(); i++)
{
for (int i = 0; i < elem_geoms.Size(); i++)
{
fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
ConstructDoFTransArray();
@@ -1666,13 +1597,10 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
{
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
if (!fespace->IsVariableOrder())
for (int i = 0; i < elem_geoms.Size(); i++)
{
for (int i = 0; i < elem_geoms.Size(); i++)
{
fespace->GetLocalRefinementMatrices(*coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
}
fespace->GetLocalRefinementMatrices(*coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
}
// Make a copy of the coarse elem_dof Table.
@@ -1748,25 +1676,11 @@ void FiniteElementSpace::RefinementOperator::Mult(const Vector &x,
Vector subY, subX;
DenseMatrix eP;
IsoparametricTransformation isotr;
for (int k = 0; k < mesh_ref->GetNE(); k++)
{
const Embedding &emb = trans_ref.embeddings[k];
const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
if (fespace->IsVariableOrder())
{
const FiniteElement *fe = fespace->GetFE(k);
isotr.SetIdentityTransformation(geom);
const int ldof = fe->GetDof();
eP.SetSize(ldof, ldof);
const DenseTensor &pmats = trans_ref.point_matrices[geom];
isotr.SetPointMat(pmats(emb.matrix));
fe->GetLocalInterpolation(isotr, eP);
}
const DenseMatrix &lP = (fespace->IsVariableOrder()) ? eP : localP[geom](
emb.matrix);
const DenseMatrix &lP = localP[geom](emb.matrix);
subY.SetSize(lP.Height());
@@ -1831,28 +1745,11 @@ void FiniteElementSpace::RefinementOperator::MultTranspose(const Vector &x,
Vector subY, subX, subYt;
DenseMatrix eP;
IsoparametricTransformation isotr;
const FiniteElement *fe = nullptr;
for (int k = 0; k < mesh_ref->GetNE(); k++)
{
const Embedding &emb = trans_ref.embeddings[k];
const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
if (fespace->IsVariableOrder())
{
fe = fespace->GetFE(k);
isotr.SetIdentityTransformation(geom);
const int ldof = fe->GetDof();
eP.SetSize(ldof);
const DenseTensor &pmats = trans_ref.point_matrices[geom];
isotr.SetPointMat(pmats(emb.matrix));
fe->GetLocalInterpolation(isotr, eP);
}
const DenseMatrix &lP = (fespace->IsVariableOrder()) ? eP : localP[geom](
emb.matrix);
const DenseMatrix &lP = localP[geom](emb.matrix);
DofTransformation *doftrans = fespace->GetElementDofs(k, f_dofs);
old_elem_dof->GetRow(emb.parent, c_dofs);
@@ -2211,12 +2108,9 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
Mesh::GeometryList elem_geoms(*mesh);
DenseTensor localR[Geometry::NumGeom];
if (!IsVariableOrder())
for (int i = 0; i < elem_geoms.Size(); i++)
{
for (int i = 0; i < elem_geoms.Size(); i++)
{
GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
}
GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
}
SparseMatrix *R = new SparseMatrix(ndofs*vdim, old_ndofs*vdim);
@@ -2231,34 +2125,14 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
bool is_dg = FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS;
int num_marked = 0;
const FiniteElement *fe = nullptr;
DenseMatrix localRVO; //for variable order only
for (int k = 0; k < dtrans.embeddings.Size(); k++)
{
const Embedding &emb = dtrans.embeddings[k];
Geometry::Type geom = mesh->GetElementBaseGeometry(emb.parent);
if (IsVariableOrder())
{
fe = GetFE(emb.parent);
const DenseTensor &pmats = dtrans.point_matrices[geom];
const int ldof = fe->GetDof();
IsoparametricTransformation isotr;
isotr.SetIdentityTransformation(geom);
localRVO.SetSize(ldof, ldof);
isotr.SetPointMat(pmats(emb.matrix));
// Local restriction is size ldofxldof assuming that the parent and
// child are of same polynomial order.
fe->GetLocalRestriction(isotr, localRVO);
}
DenseMatrix &lR = IsVariableOrder() ? localRVO : localR[geom](emb.matrix);
DenseMatrix &lR = localR[geom](emb.matrix);
elem_dof->GetRow(emb.parent, dofs);
old_elem_dof->GetRow(k, old_dofs);
MFEM_VERIFY(old_dofs.Size() == dofs.Size(),
"Parent and child must have same #dofs.");
for (int vd = 0; vd < vdim; vd++)
{
@@ -2284,7 +2158,7 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
}
}
if (!is_dg && !IsVariableOrder())
if (!is_dg)
{
MFEM_VERIFY(num_marked == R->Height(),
"internal error: not all rows of R were set.");
@@ -2342,7 +2216,6 @@ void FiniteElementSpace::Constructor(Mesh *mesh_, NURBSExtension *NURBSext_,
const NURBSFECollection *nurbs_fec =
dynamic_cast<const NURBSFECollection *>(fec_);
if (nurbs_fec)
{
MFEM_VERIFY(mesh_->NURBSext, "NURBS FE space requires a NURBS mesh.");
@@ -2439,63 +2312,12 @@ void FiniteElementSpace::UpdateNURBS()
face_dof = NULL;
face_to_be.DeleteAll();
// Depending on the element type create the appropriate extensions
// for the individual components.
dynamic_cast<const NURBSFECollection *>(fec)->Reset();
if (dynamic_cast<const NURBS_HDivFECollection *>(fec))
{
VNURBSext.SetSize(mesh->Dimension());
for (int d = 0; d < mesh->Dimension(); d++)
{
VNURBSext[d] = NURBSext->GetDivExtension(d);
}
}
ndofs = NURBSext->GetNDof();
elem_dof = NURBSext->GetElementDofTable();
bdr_elem_dof = NURBSext->GetBdrElementDofTable();
if (dynamic_cast<const NURBS_HCurlFECollection *>(fec))
{
VNURBSext.SetSize(mesh->Dimension());
for (int d = 0; d < mesh->Dimension(); d++)
{
VNURBSext[d] = NURBSext->GetCurlExtension(d);
}
}
// If required: concatenate the dof tables of the individual components into
// one dof table for the vector fespace.
if (VNURBSext.Size() == 2)
{
int offset1 = VNURBSext[0]->GetNDof();
ndofs = VNURBSext[0]->GetNDof() + VNURBSext[1]->GetNDof();
// Merge Tables
elem_dof = new Table(*VNURBSext[0]->GetElementDofTable(),
*VNURBSext[1]->GetElementDofTable(),offset1 );
bdr_elem_dof = new Table(*VNURBSext[0]->GetBdrElementDofTable(),
*VNURBSext[1]->GetBdrElementDofTable(),offset1);
}
else if (VNURBSext.Size() == 3)
{
int offset1 = VNURBSext[0]->GetNDof();
int offset2 = offset1 + VNURBSext[1]->GetNDof();
ndofs = offset2 + VNURBSext[2]->GetNDof();
// Merge Tables
elem_dof = new Table(*VNURBSext[0]->GetElementDofTable(),
*VNURBSext[1]->GetElementDofTable(),offset1,
*VNURBSext[2]->GetElementDofTable(),offset2);
bdr_elem_dof = new Table(*VNURBSext[0]->GetBdrElementDofTable(),
*VNURBSext[1]->GetBdrElementDofTable(),offset1,
*VNURBSext[2]->GetBdrElementDofTable(),offset2);
}
else
{
ndofs = NURBSext->GetNDof();
elem_dof = NURBSext->GetElementDofTable();
bdr_elem_dof = NURBSext->GetBdrElementDofTable();
}
mesh_sequence = mesh->GetSequence();
sequence++;
}
@@ -3497,21 +3319,11 @@ void FiniteElementSpace::Destroy()
dof_elem_array.DeleteAll();
dof_ldof_array.DeleteAll();
for (int i = 0; i < VNURBSext.Size(); i++)
{
delete VNURBSext[i];
}
if (NURBSext)
{
if (own_ext) { delete NURBSext; }
delete face_dof;
face_to_be.DeleteAll();
if (VNURBSext.Size() > 0 )
{
delete elem_dof;
delete bdr_elem_dof;
}
}
else
{
@@ -3523,8 +3335,6 @@ void FiniteElementSpace::Destroy()
delete [] bdofs;
}
ceed::RemoveBasisAndRestriction(this);
}
void FiniteElementSpace::DestroyDoFTransArray()
@@ -3543,27 +3353,19 @@ void FiniteElementSpace::GetTransferOperator(
if (T.Type() == Operator::MFEM_SPARSEMAT)
{
if (!IsVariableOrder())
{
Mesh::GeometryList elem_geoms(*mesh);
Mesh::GeometryList elem_geoms(*mesh);
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
{
GetLocalRefinementMatrices(coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
}
T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
coarse_fes.GetElementToDofTable(),
coarse_fes.
GetElementToFaceOrientationTable(),
localP));
}
else
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
{
T.Reset(VariableOrderRefinementMatrix(coarse_fes.GetNDofs(),
coarse_fes.GetElementToDofTable()));
GetLocalRefinementMatrices(coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
}
T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
coarse_fes.GetElementToDofTable(),
coarse_fes.
GetElementToFaceOrientationTable(),
localP));
}
else
{
@@ -3614,33 +3416,19 @@ void FiniteElementSpace::GetTrueTransferOperator(
void FiniteElementSpace::UpdateElementOrders()
{
const CoarseFineTransformations &cf_tr = mesh->GetRefinementTransforms();
Array<char> new_order(mesh->GetNE());
switch (mesh->GetLastOperation())
{
case Mesh::REFINE:
{
const CoarseFineTransformations &cf_tr = mesh->GetRefinementTransforms();
for (int i = 0; i < mesh->GetNE(); i++)
{
new_order[i] = elem_order[cf_tr.embeddings[i].parent];
}
break;
}
case Mesh::DEREFINE:
{
const CoarseFineTransformations &cf_tr =
mesh->ncmesh->GetDerefinementTransforms();
Table coarse_to_fine;
cf_tr.MakeCoarseToFineTable(coarse_to_fine);
Array<int> tabrow;
for (int i = 0; i < coarse_to_fine.Size(); i++)
{
coarse_to_fine.GetRow(i, tabrow);
//For now we require that all children are of same polynomial order.
new_order[i] = elem_order[tabrow[0]];
}
break;
}
default:
MFEM_ABORT("not implemented yet");
}
@@ -3735,23 +3523,11 @@ void FiniteElementSpace::Update(bool want_transform)
{
BuildConformingInterpolation();
Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
if (IsVariableOrder())
if (cP && cR)
{
if (cP && cR_hp)
{
Th.SetOperatorOwner(false);
Th.Reset(new TripleProductOperator(cP.get(), cR_hp.get(), Th.Ptr(),
false, false, true));
}
}
else
{
if (cP && cR)
{
Th.SetOperatorOwner(false);
Th.Reset(new TripleProductOperator(cP.get(), cR.get(), Th.Ptr(),
false, false, true));
}
Th.SetOperatorOwner(false);
Th.Reset(new TripleProductOperator(cP.get(), cR.get(), Th.Ptr(),
false, false, true));
}
break;
}
@@ -3864,7 +3640,6 @@ FiniteElementCollection *FiniteElementSpace::Load(Mesh *m, std::istream &input)
input >> ord;
NURBSFECollection *nurbs_fec = dynamic_cast<NURBSFECollection*>(r_fec);
if (nurbs_fec) { nurbs_fec->SetDim(m->Dimension()); }
NURBSExtension *nurbs_ext = NULL;
if (fes_format == 90) // original format, v0.9
{
+1 -15
View File
@@ -268,10 +268,6 @@ protected:
Array<int> dof_elem_array, dof_ldof_array;
NURBSExtension *NURBSext;
/** array of NURBS extension for H(div) and H(curl) vector elements.
For each direction an extension is created from the base NURBSext,
with an increase in order in the appropriate direction. */
Array<NURBSExtension*> VNURBSext;
int own_ext;
mutable Array<int> face_to_be; // NURBS FE space only
@@ -473,11 +469,6 @@ protected:
const Table *coarse_elem_fos,
const DenseTensor localP[]) const;
/* This method returns the Refinement matrix (i.e., the embedding)
from a coarse variable-order fes to a fine fes (after a geometric refinement) */
SparseMatrix *VariableOrderRefinementMatrix(const int coarse_ndofs,
const Table &coarse_elem_dof) const;
void GetLocalRefinementMatrices(Geometry::Type geom,
DenseTensor &localP) const;
void GetLocalDerefinementMatrices(Geometry::Type geom,
@@ -526,8 +517,6 @@ protected:
const Array<int> *perm);
public:
/** @brief Default constructor: the object is invalid until initialized using
the method Load(). */
FiniteElementSpace();
@@ -655,10 +644,7 @@ public:
const ElementRestrictionOperator *GetElementRestriction(
ElementDofOrdering e_ordering) const;
/** @brief Return an Operator that converts L-vectors to E-vectors on each
face. */
/** @warning only meshes with tensor-product elements are currently
supported. */
/// Return an Operator that converts L-vectors to E-vectors on each face.
virtual const FaceRestriction *GetFaceRestriction(
ElementDofOrdering f_ordering, FaceType,
L2FaceValues mul = L2FaceValues::DoubleValued) const;
+33 -96
View File
@@ -12,8 +12,6 @@
// Implementation of GridFunction
#include "gridfunc.hpp"
#include "linearform.hpp"
#include "bilinearform.hpp"
#include "quadinterpolator.hpp"
#include "../mesh/nurbs.hpp"
#include "../general/text.hpp"
@@ -41,7 +39,7 @@ GridFunction::GridFunction(Mesh *m, std::istream &input)
UseDevice(true);
fes = new FiniteElementSpace;
fec_owned = fes->Load(m, input);
fec = fes->Load(m, input);
skip_comment_lines(input, '#');
istream::int_type next_char = input.peek();
@@ -83,10 +81,10 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
int vdim, ordering;
fes = gf_array[0]->FESpace();
fec_owned = FiniteElementCollection::New(fes->FEColl()->Name());
fec = FiniteElementCollection::New(fes->FEColl()->Name());
vdim = fes->GetVDim();
ordering = fes->GetOrdering();
fes = new FiniteElementSpace(m, fec_owned, vdim, ordering);
fes = new FiniteElementSpace(m, fec, vdim, ordering);
SetSize(fes->GetVSize());
if (m->NURBSext)
@@ -155,11 +153,11 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
void GridFunction::Destroy()
{
if (fec_owned)
if (fec)
{
delete fes;
delete fec_owned;
fec_owned = NULL;
delete fec;
fec = NULL;
}
}
@@ -327,9 +325,10 @@ int GridFunction::VectorDim() const
const FiniteElement *fe;
if (!fes->GetNE())
{
const FiniteElementCollection *fe_coll = fes->FEColl();
static const Geometry::Type geoms[3] =
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
fe = fes->FEColl()->
fe = fe_coll->
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
}
else
@@ -351,8 +350,7 @@ int GridFunction::CurlDim() const
{
static const Geometry::Type geoms[3] =
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
fe = fes->FEColl()->
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
fe = fec->FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
}
else
{
@@ -2374,48 +2372,19 @@ void GridFunction::ProjectCoefficient(Coefficient &coeff)
if (delta_c == NULL)
{
if (fes->GetNURBSext() == NULL)
{
Array<int> vdofs;
Vector vals;
Array<int> vdofs;
Vector vals;
for (int i = 0; i < fes->GetNE(); i++)
for (int i = 0; i < fes->GetNE(); i++)
{
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
{
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
{
doftrans->TransformPrimal(vals);
}
SetSubVector(vdofs, vals);
doftrans->TransformPrimal(vals);
}
}
else
{
// Define and assemble linear form
LinearForm b(fes);
b.AddDomainIntegrator(new DomainLFIntegrator(coeff));
b.Assemble();
// Define and assemble bilinear form
BilinearForm a(fes);
a.AddDomainIntegrator(new MassIntegrator());
a.Assemble();
// Set solver and preconditioner
SparseMatrix A(a.SpMat());
GSSmoother prec(A);
CGSolver cg;
cg.SetOperator(A);
cg.SetPreconditioner(prec);
cg.SetRelTol(1e-12);
cg.SetMaxIter(1000);
cg.SetPrintLevel(0);
// Solve and get solution
*this = 0.0;
cg.Mult(b,*this);
SetSubVector(vdofs, vals);
}
}
else
@@ -2456,54 +2425,22 @@ void GridFunction::ProjectCoefficient(
void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff)
{
if (fes->GetNURBSext() == NULL)
int i;
Array<int> vdofs;
Vector vals;
DofTransformation * doftrans = NULL;
for (i = 0; i < fes->GetNE(); i++)
{
int i;
Array<int> vdofs;
Vector vals;
DofTransformation * doftrans = NULL;
for (i = 0; i < fes->GetNE(); i++)
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
{
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
{
doftrans->TransformPrimal(vals);
}
SetSubVector(vdofs, vals);
doftrans->TransformPrimal(vals);
}
}
else
{
// Define and assemble linear form
LinearForm b(fes);
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(vcoeff));
b.Assemble();
// Define and assemble bilinear form
BilinearForm a(fes);
a.AddDomainIntegrator(new VectorFEMassIntegrator());
a.Assemble();
// Set solver and preconditioner
SparseMatrix A(a.SpMat());
GSSmoother prec(A);
CGSolver cg;
cg.SetOperator(A);
cg.SetPreconditioner(prec);
cg.SetRelTol(1e-12);
cg.SetMaxIter(1000);
cg.SetPrintLevel(0);
// Solve and get solution
*this = 0.0;
cg.Mult(b,*this);
SetSubVector(vdofs, vals);
}
}
@@ -3989,7 +3926,7 @@ void GridFunction::LegacyNCReorder()
mesh->GetEdgeVertices(i, ev);
if (old_vertex[ev[0]] > old_vertex[ev[1]])
{
const int *ind = fes->FEColl()->DofOrderForOrientation(Geometry::SEGMENT, -1);
const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, -1);
fes->GetEdgeInteriorDofs(i, dofs);
for (int k = 0; k < dofs.Size(); k++)
+13 -15
View File
@@ -30,14 +30,14 @@ namespace mfem
class GridFunction : public Vector
{
protected:
/// FE space on which the grid function lives. Owned if #fec_owned is not NULL.
/// FE space on which the grid function lives. Owned if #fec is not NULL.
FiniteElementSpace *fes;
/** @brief Used when the grid function is read from a file. It can also be
set explicitly, see MakeOwner().
If not NULL, this pointer is owned by the GridFunction. */
FiniteElementCollection *fec_owned;
FiniteElementCollection *fec;
long fes_sequence; // see FiniteElementSpace::sequence, Mesh::sequence
@@ -72,16 +72,16 @@ protected:
public:
GridFunction() { fes = NULL; fec_owned = NULL; fes_sequence = 0; UseDevice(true); }
GridFunction() { fes = NULL; fec = NULL; fes_sequence = 0; UseDevice(true); }
/// Copy constructor. The internal true-dof vector #t_vec is not copied.
GridFunction(const GridFunction &orig)
: Vector(orig), fes(orig.fes), fec_owned(NULL), fes_sequence(orig.fes_sequence)
: Vector(orig), fes(orig.fes), fec(NULL), fes_sequence(orig.fes_sequence)
{ UseDevice(true); }
/// Construct a GridFunction associated with the FiniteElementSpace @a *f.
GridFunction(FiniteElementSpace *f) : Vector(f->GetVSize())
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/// Construct a GridFunction using previously allocated array @a data.
/** The GridFunction does not assume ownership of @a data which is assumed to
@@ -91,13 +91,13 @@ public:
*/
GridFunction(FiniteElementSpace *f, real_t *data)
: Vector(data, f->GetVSize())
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/** @brief Construct a GridFunction using previously allocated Vector @a base
starting at the given offset, @a base_offset. */
GridFunction(FiniteElementSpace *f, Vector &base, int base_offset = 0)
: Vector(base, base_offset, f->GetVSize())
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/// Construct a GridFunction on the given Mesh, using the data from @a input.
/** The content of @a input should be in the format created by the method
@@ -116,12 +116,12 @@ public:
GridFunction &operator=(const GridFunction &rhs)
{ return operator=((const Vector &)rhs); }
/// Make the GridFunction the owner of #fec_owned and #fes.
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec_owned
/// Make the GridFunction the owner of #fec and #fes.
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec
and #fes is taken away. */
void MakeOwner(FiniteElementCollection *fec_) { fec_owned = fec_; }
void MakeOwner(FiniteElementCollection *fec_) { fec = fec_; }
FiniteElementCollection *OwnFEC() { return fec_owned; }
FiniteElementCollection *OwnFEC() { return fec; }
int VectorDim() const;
int CurlDim() const;
@@ -387,8 +387,7 @@ public:
/** @brief Project @a coeff Coefficient to @a this GridFunction. The
projection computation depends on the choice of the FiniteElementSpace
#fes. Note that this is usually interpolation at the degrees of freedom
in each element (not L2 projection). For NURBS spaces these degrees of
freedom are not available and L2 projection is resorted to as fallback. */
in each element (not L2 projection). */
virtual void ProjectCoefficient(Coefficient &coeff);
/** @brief Project @a coeff Coefficient to @a this GridFunction, using one
@@ -399,8 +398,7 @@ public:
/** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction. The
projection computation depends on the choice of the FiniteElementSpace
#fes. Note that this is usually interpolation at the degrees of freedom
in each element (not L2 projection). For NURBS spaces these degrees of
freedom are not available and L2 projection is resorted to as fallback. */
in each element (not L2 projection).*/
void ProjectCoefficient(VectorCoefficient &vcoeff);
/** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction, using
-114
View File
@@ -1168,120 +1168,6 @@ void FindPointsGSLIB::InterpolateGeneral(const GridFunction &field_in,
} // parallel
}
void FindPointsGSLIB::DistributePointInfoToOwningMPIRanks(
Array<unsigned int> &recv_elem, Vector &recv_ref,
Array<unsigned int> &recv_code)
{
MFEM_VERIFY(points_cnt,
"Invalid size. Please make sure to call FindPoints method "
"before calling this function.");
// Pack data to send via crystal router
struct gslib::array *outpt = new gslib::array;
struct out_pt { double rst[3]; uint index, elem, proc, code; };
struct out_pt *pt;
array_init(struct out_pt, outpt, points_cnt);
outpt->n=points_cnt;
pt = (struct out_pt *)outpt->ptr;
for (int index = 0; index < points_cnt; index++)
{
pt->index = index;
pt->elem = gsl_mfem_elem[index];
pt->proc = gsl_proc[index];
pt->code = gsl_code[index];
for (int d = 0; d < dim; ++d)
{
pt->rst[d]= gsl_mfem_ref(index*dim + d);
}
++pt;
}
// Transfer data to target MPI ranks
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
// Store received data
const int points_recv = outpt->n;
recv_proc.SetSize(points_recv);
recv_elem.SetSize(points_recv);
recv_index.SetSize(points_recv);
recv_code.SetSize(points_recv);
recv_ref.SetSize(points_recv*dim);
pt = (struct out_pt *)outpt->ptr;
for (int index = 0; index < points_recv; index++)
{
recv_index[index] = pt->index;
recv_elem[index] = pt->elem;
recv_proc[index] = pt->proc;
recv_code[index] = pt->code;
for (int d = 0; d < dim; ++d)
{
recv_ref(index*dim + d)= pt->rst[d];
}
++pt;
}
array_free(outpt);
delete outpt;
}
void FindPointsGSLIB::DistributeInterpolatedValues(const Vector &int_vals,
const int vdim,
const int ordering,
Vector &field_out) const
{
const int points_recv = recv_index.Size();;
MFEM_VERIFY(points_recv == 0 ||
int_vals.Size() % points_recv == 0,
"Incompatible size. Please return interpolated values"
"corresponding to points received using"
"SendCoordinatesToOwningProcessors.");
field_out.SetSize(points_cnt*vdim);
for (int v = 0; v < vdim; v++)
{
// Pack data to send via crystal router
struct gslib::array *outpt = new gslib::array;
struct out_pt { double val; uint index, proc; };
struct out_pt *pt;
array_init(struct out_pt, outpt, points_recv);
outpt->n=points_recv;
pt = (struct out_pt *)outpt->ptr;
for (int index = 0; index < points_recv; index++)
{
pt->index = recv_index[index];
pt->proc = recv_proc[index];
pt->val = ordering == Ordering::byNODES ?
int_vals(index + v*points_recv) :
int_vals(index*vdim + v);
++pt;
}
// Transfer data to target MPI ranks
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
// Store received data
MFEM_VERIFY(outpt->n == points_cnt, "Incompatible size. Number of points "
"received does not match the number of points originally "
"found using FindPoints.");
pt = (struct out_pt *)outpt->ptr;
for (int index = 0; index < points_cnt; index++)
{
int idx = ordering == Ordering::byNODES ?
pt->index + v*points_cnt :
pt->index*vdim + v;
field_out(idx) = pt->val;
++pt;
}
array_free(outpt);
delete outpt;
}
}
void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
GridFunction *gfmax,
const double bb_t, const double newt_tol,
+19 -66
View File
@@ -34,7 +34,7 @@ namespace mfem
*
* There are three key functions in FindPointsGSLIB:
*
* 1. Setup - constructs the internal data structures of gslib. See \ref Setup.
* 1. Setup - constructs the internal data structures of gslib.
*
* 2. FindPoints - for any given arbitrary set of points in physical space,
* gslib finds the element number, MPI rank, and the reference space
@@ -45,23 +45,12 @@ namespace mfem
* on an element edge/face or near the domain boundary, and gslib also
* returns a distance to the border. Points near (but outside) the domain
* boundary must then be marked as not found using the distance returned
* by gslib. See \ref FindPoints.
* by gslib.
*
* 3. Interpolate - Interpolates any grid function at the points found using 2.
* For functions in L2 finite element space, use \ref SetL2AvgType to
* specify how to interpolate values at points located at element boundaries
* where the function might be multi-valued. See \ref Interpolate.
*
* FindPointsGSLIB also provides interface to use these functions through a
* single call.
*
* For custom interpolation (e.g., evaluating strain rate tensor), we provide
* functions that use gslib to send element index and corresponding
* reference-space coordinates for each point to the mpi rank that the element
* is located on. Then, custom interpolation can be defined locally by the user
* before sending the values back to mpi ranks where the query originated from.
* See \ref DistributePointInfoToOwningMPIRanks and
* \ref DistributeInterpolatedValues.
* FindPointsGSLIB provides interface to use these functions individually or
* using a single call.
*/
class FindPointsGSLIB
{
@@ -85,8 +74,7 @@ protected:
int dim, points_cnt;
Array<unsigned int> gsl_code, gsl_proc, gsl_elem, gsl_mfem_elem;
Vector gsl_mesh, gsl_ref, gsl_dist, gsl_mfem_ref;
Array<unsigned int> recv_proc, recv_index; // data for custom interpolation
bool setupflag; // flag to indicate if gslib data has been setup
bool setupflag; // flag to indicate whether gslib data has been setup
double default_interp_value; // used for points that are not found in the mesh
AvgType avgtype; // average type used for L2 functions
Array<int> split_element_map;
@@ -130,9 +118,9 @@ public:
virtual ~FindPointsGSLIB();
/** Initializes the internal mesh in gslib, by sending the positions of the
Gauss-Lobatto nodes of the input Mesh object \p m.
Gauss-Lobatto nodes of the input Mesh object @a m.
Note: not tested with periodic (L2).
Note: the input mesh \p m must have Nodes set.
Note: the input mesh @a m must have Nodes set.
@param[in] m Input mesh.
@param[in] bb_t (Optional) Relative size of bounding box around
@@ -145,9 +133,9 @@ public:
void Setup(Mesh &m, const double bb_t = 0.1,
const double newt_tol = 1.0e-12,
const int npt_max = 256);
/** Searches positions given in physical space by \p point_pos.
/** Searches positions given in physical space by @a point_pos.
These positions can be ordered byNodes: (XXX...,YYY...,ZZZ) or
byVDim: (XYZ,XYZ,....XYZ) specified by \p point_pos_ordering.
byVDim: (XYZ,XYZ,....XYZ) specified by @a point_pos_ordering.
This function populates the following member variables:
#gsl_code Return codes for each point: inside element (0),
element boundary (1), not found (2).
@@ -176,20 +164,20 @@ public:
/** Interpolation of field values at prescribed reference space positions.
@param[in] field_in Function values that will be interpolated on the
reference positions. Note: it is assumed that
\p field_in is in H1 and in the same space as the
@a field_in is in H1 and in the same space as the
mesh that was given to Setup().
@param[out] field_out Interpolated values. For points that are not found
the value is set to #default_interp_value. */
virtual void Interpolate(const GridFunction &field_in, Vector &field_out);
/** Search positions and interpolate. The ordering (byNODES or byVDIM) of
the output values in \p field_out corresponds to the ordering used
in the input GridFunction \p field_in. */
the output values in @a field_out corresponds to the ordering used
in the input GridFunction @a field_in. */
void Interpolate(const Vector &point_pos, const GridFunction &field_in,
Vector &field_out,
int point_pos_ordering = Ordering::byNODES);
/** Setup FindPoints, search positions and interpolate. The ordering (byNODES
or byVDIM) of the output values in \p field_out corresponds to the
ordering used in the input GridFunction \p field_in. */
or byVDIM) of the output values in @a field_out corresponds to the
ordering used in the input GridFunction @a field_in. */
void Interpolate(Mesh &m, const Vector &point_pos,
const GridFunction &field_in, Vector &field_out,
int point_pos_ordering = Ordering::byNODES);
@@ -237,41 +225,6 @@ public:
/// Return reference coordinates in [-1,1] (internal range in GSLIB) for each
/// point found by FindPoints.
virtual const Vector &GetGSLIBReferencePosition() const { return gsl_ref; }
/** @name Methods to support a custom interpolation procedure.
\brief The physical-space point that the user seeks to interpolate at
could be located inside an element on another mpi rank.
To enable a custom interpolation procedure (e.g., strain tensor computation)
we need a mechanism to first send element indices and reference-space
coordinates to the mpi-ranks where each point is found. Then the custom
interpolation can be done locally by the user before sending the
interpolated values back to the mpi-ranks that the query originated from.
Example usage looks something like this:
FindPoints() -> DistributePointInfoToOwningMPIRanks() -> Computation by
user -> DistributeInterpolatedValues().
*/
///@{
/// Distribute element indices in #gsl_mfem_elem, the reference coordinates
/// #gsl_mfem_ref, and the code #gsl_code to the corresponding mpi-rank
/// #gsl_proc for each point. The received information is provided locally
/// in \p recv_elem, \p recv_ref (ordered by vdim), and \p recv_code.
/// Note: The user can send empty Array/Vectors to the method as they are
/// appropriately sized and filled internally.
virtual void DistributePointInfoToOwningMPIRanks(
Array<unsigned int> &recv_elem, Vector &recv_ref,
Array<unsigned int> &recv_code);
/// Return interpolated values back to the mpi-ranks #recv_proc that had
/// sent the element indices and corresponding reference-space coordinates.
/// Specify \p vdim and \p ordering (by nodes or by vdim) based on how the
/// \p int_vals are structured. The received values are filled in
/// \p field_out consistent with the original ordering of the points that
/// were used in \ref FindPoints.
virtual void DistributeInterpolatedValues(const Vector &int_vals,
const int vdim,
const int ordering,
Vector &field_out) const;
///@}
};
/** \brief OversetFindPointsGSLIB enables use of findpts for arbitrary number of
@@ -296,9 +249,9 @@ public:
#endif
/** Initializes the internal mesh in gslib, by sending the positions of the
Gauss-Lobatto nodes of the input Mesh object \p m.
Gauss-Lobatto nodes of the input Mesh object @a m.
Note: not tested with periodic meshes (L2).
Note: the input mesh \p m must have Nodes set.
Note: the input mesh @a m must have Nodes set.
@param[in] m Input mesh.
@param[in] meshid A unique # for each overlapping mesh. This id is
@@ -321,12 +274,12 @@ public:
const double bb_t = 0.1, const double newt_tol = 1.0e-12,
const int npt_max = 256);
/** Searches positions given in physical space by \p point_pos. All output
/** Searches positions given in physical space by @a point_pos. All output
Arrays and Vectors are expected to have the correct size.
@param[in] point_pos Positions to be found.
@param[in] point_id Index of the mesh that the point belongs
to (corresponding to \p meshid in Setup).
to (corresponding to @a meshid in Setup).
@param[in] point_pos_ordering Ordering of the points:
byNodes: (XXX...,YYY...,ZZZ) or
byVDim: (XYZ,XYZ,....XYZ) */
@@ -389,7 +342,7 @@ public:
enum GSOp {ADD, MUL, MIN, MAX};
/// Update the identifiers used for the gather-scatter operator.
/// Same \p ids get grouped together and id == 0 does not participate.
/// Same @a ids get grouped together and id == 0 does not participate.
/// See class description.
void UpdateIdentifiers(const Array<long long> &ids);
+44 -44
View File
@@ -220,8 +220,8 @@ void MomentFittingIntRules::ComputeSurfaceWeights1D(ElementTransformation& Tr)
{
IntegrationPoint ip2;
ip2.x = .5;
while (LvlSet->Eval(Tr, ip2) > tol_1
|| LvlSet->Eval(Tr, ip2) < -tol_1)
while (LvlSet->Eval(Tr, ip2) > 1e-12
|| LvlSet->Eval(Tr, ip2) < -1e-12)
{
if (LvlSet->Eval(Tr, ip0) * LvlSet->Eval(Tr, ip2) < 0.)
{
@@ -237,12 +237,12 @@ void MomentFittingIntRules::ComputeSurfaceWeights1D(ElementTransformation& Tr)
intp.x = ip2.x;
intp.weight = 1. / Tr.Weight();
}
else if (LvlSet->Eval(Tr, ip0) > 0. && LvlSet->Eval(Tr, ip1) <= tol_1)
else if (LvlSet->Eval(Tr, ip0) > 0. && LvlSet->Eval(Tr, ip1) <= 1e-12)
{
intp.x = 1.;
intp.weight = 1. / Tr.Weight();
}
else if (LvlSet->Eval(Tr, ip1) > 0. && LvlSet->Eval(Tr, ip0) <= tol_1)
else if (LvlSet->Eval(Tr, ip1) > 0. && LvlSet->Eval(Tr, ip0) <= 1e-12)
{
intp.x = 0.;
intp.weight = 1. / Tr.Weight();
@@ -290,8 +290,8 @@ void MomentFittingIntRules::ComputeVolumeWeights1D(ElementTransformation& Tr,
}
}
}
else if (LvlSet->Eval(Tr, ip0) <= -tol_1
|| LvlSet->Eval(Tr, ip1) <= -tol_1)
else if (LvlSet->Eval(Tr, ip0) <= -1e-12
|| LvlSet->Eval(Tr, ip1) <= -1e-12)
{
for (int ip = 0; ip < ir.GetNPoints(); ip++)
{
@@ -356,24 +356,24 @@ void MomentFittingIntRules::ComputeSurfaceWeights2D(ElementTransformation& Tr)
IntegrationPoint ipB;
Trafo.TransformBack(pointB, ipB);
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1)
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -tol_1
&& LvlSet->Eval(Trafo, ipB) > -tol_1)
if (LvlSet->Eval(Trafo, ipA) > -1e-12
&& LvlSet->Eval(Trafo, ipB) > -1e-12)
{
layout = Layout::inside;
}
else if (LvlSet->Eval(Trafo, ipA) > tol_2
else if (LvlSet->Eval(Trafo, ipA) > 1e-15
&& LvlSet->Eval(Trafo, ipB) <= 0.)
{
layout = Layout::intersected;
}
else if (LvlSet->Eval(Trafo, ipA) <= 0.
&& LvlSet->Eval(Trafo, ipB) > tol_2)
&& LvlSet->Eval(Trafo, ipB) > 1e-15)
{
layout = Layout::intersected;
Vector temp(pointA.Size());
@@ -399,10 +399,10 @@ void MomentFittingIntRules::ComputeSurfaceWeights2D(ElementTransformation& Tr)
IntegrationPoint ip;
Trafo.TransformBack(mid, ip);
while (LvlSet->Eval(Trafo, ip) > tol_1
|| LvlSet->Eval(Trafo, ip) < -tol_1)
while (LvlSet->Eval(Trafo, ip) > 1e-12
|| LvlSet->Eval(Trafo, ip) < -1e-12)
{
if (LvlSet->Eval(Trafo, ip) > tol_1)
if (LvlSet->Eval(Trafo, ip) > 1e-12)
{
pointC = mid;
}
@@ -539,7 +539,7 @@ void MomentFittingIntRules::ComputeSurfaceWeights2D(ElementTransformation& Tr)
temp2 = 0.;
for (int i = 0; i < nBasis; i++)
{
if (SVD.Singularvalue(i) > tol_1)
if (SVD.Singularvalue(i) > 1e-12)
{
temp2(i) = temp(i) / SVD.Singularvalue(i);
}
@@ -606,24 +606,24 @@ void MomentFittingIntRules::ComputeVolumeWeights2D(ElementTransformation& Tr,
IntegrationPoint ipB;
Trafo.TransformBack(pointB, ipB);
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1)
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -tol_1
&& LvlSet->Eval(Trafo, ipB) > -tol_1)
if (LvlSet->Eval(Trafo, ipA) > -1e-12
&& LvlSet->Eval(Trafo, ipB) > -1e-12)
{
layout = Layout::inside;
}
else if (LvlSet->Eval(Trafo, ipA) > tol_2
else if (LvlSet->Eval(Trafo, ipA) > 1e-15
&& LvlSet->Eval(Trafo, ipB) <= 0.)
{
layout = Layout::intersected;
}
else if (LvlSet->Eval(Trafo, ipA) <= 0.
&& LvlSet->Eval(Trafo, ipB) > tol_2)
&& LvlSet->Eval(Trafo, ipB) > 1e-15)
{
layout = Layout::intersected;
Vector temp(pointA.Size());
@@ -648,10 +648,10 @@ void MomentFittingIntRules::ComputeVolumeWeights2D(ElementTransformation& Tr,
IntegrationPoint ip;
Trafo.TransformBack(mid, ip);
while (LvlSet->Eval(Trafo, ip) > tol_1
|| LvlSet->Eval(Trafo, ip) < -tol_1)
while (LvlSet->Eval(Trafo, ip) > 1e-12
|| LvlSet->Eval(Trafo, ip) < -1e-12)
{
if (LvlSet->Eval(Trafo, ip) > tol_1)
if (LvlSet->Eval(Trafo, ip) > 1e-12)
{
pointC = mid;
}
@@ -786,7 +786,7 @@ void MomentFittingIntRules::ComputeVolumeWeights2D(ElementTransformation& Tr,
VolumeSVD->LeftSingularvectors().MultTranspose(RHS, temp);
for (int i = 0; i < nBasisVolume; i++)
{
if (VolumeSVD->Singularvalue(i) > tol_1)
if (VolumeSVD->Singularvalue(i) > 1e-12)
{
temp2(i) = temp(i) / VolumeSVD->Singularvalue(i);
}
@@ -865,18 +865,18 @@ void MomentFittingIntRules::ComputeSurfaceWeights3D(ElementTransformation& Tr)
IntegrationPoint ipD;
Trafo.TransformBack(pointD, ipD);
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1
|| LvlSet->Eval(Trafo, ipC) < -tol_1
|| LvlSet->Eval(Trafo, ipD) < -tol_1)
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12
|| LvlSet->Eval(Trafo, ipC) < -1e-12
|| LvlSet->Eval(Trafo, ipD) < -1e-12)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -tol_1
|| LvlSet->Eval(Trafo, ipB) > -tol_1
|| LvlSet->Eval(Trafo, ipC) > -tol_1
|| LvlSet->Eval(Trafo, ipD) > -tol_1)
if (LvlSet->Eval(Trafo, ipA) > -1e-12
|| LvlSet->Eval(Trafo, ipB) > -1e-12
|| LvlSet->Eval(Trafo, ipC) > -1e-12
|| LvlSet->Eval(Trafo, ipD) > -1e-12)
{
element_int = true;
}
@@ -978,7 +978,7 @@ void MomentFittingIntRules::ComputeSurfaceWeights3D(ElementTransformation& Tr)
temp2 = 0.;
for (int i = 0; i < nBasis; i++)
{
if (SVD.Singularvalue(i) > tol_1)
if (SVD.Singularvalue(i) > 1e-12)
{
temp2(i) = temp(i) / SVD.Singularvalue(i);
}
@@ -1047,18 +1047,18 @@ void MomentFittingIntRules::ComputeVolumeWeights3D(ElementTransformation& Tr,
IntegrationPoint ipD;
Trafo.TransformBack(pointD, ipD);
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1
|| LvlSet->Eval(Trafo, ipC) < -tol_1
|| LvlSet->Eval(Trafo, ipD) < -tol_1)
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12
|| LvlSet->Eval(Trafo, ipC) < -1e-12
|| LvlSet->Eval(Trafo, ipD) < -1e-12)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -tol_1
|| LvlSet->Eval(Trafo, ipB) > -tol_1
|| LvlSet->Eval(Trafo, ipC) > -tol_1
|| LvlSet->Eval(Trafo, ipD) > -tol_1)
if (LvlSet->Eval(Trafo, ipA) > -1e-12
|| LvlSet->Eval(Trafo, ipB) > -1e-12
|| LvlSet->Eval(Trafo, ipC) > -1e-12
|| LvlSet->Eval(Trafo, ipD) > -1e-12)
{
element_int = true;
}
@@ -1159,7 +1159,7 @@ void MomentFittingIntRules::ComputeVolumeWeights3D(ElementTransformation& Tr,
VolumeSVD->LeftSingularvectors().MultTranspose(RHS, temp);
temp2 = 0.;
for (int i = 0; i < nBasisVolume; i++)
if (VolumeSVD->Singularvalue(i) > tol_1)
if (VolumeSVD->Singularvalue(i) > 1e-12)
{
temp2(i) = temp(i) / VolumeSVD->Singularvalue(i);
}
-11
View File
@@ -36,17 +36,6 @@ protected:
/// Space order for the LS projection.
int lsOrder;
/// @name Tolerances used for point comparisons
///@{
#ifdef MFEM_USE_DOUBLE
static constexpr real_t tol_1 = 1e-12;
static constexpr real_t tol_2 = 1e-15;
#elif defined(MFEM_USE_SINGLE)
static constexpr real_t tol_1 = 1e-5;
static constexpr real_t tol_2 = 1e-7;
#endif
///@}
/** @brief Constructor to set up the generated cut IntegrationRules.
@param [in] order Order of the constructed IntegrationRule.
+3 -4
View File
@@ -39,10 +39,9 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, const GridFunction *gf,
{
const FiniteElementSpace *glob_fes = gf->FESpace();
// duplicate the FiniteElementCollection from 'gf'
fec_owned = FiniteElementCollection::New(glob_fes->FEColl()->Name());
fec = FiniteElementCollection::New(glob_fes->FEColl()->Name());
// create a local ParFiniteElementSpace from the global one:
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning,
fec_owned);
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning, fec);
SetSize(pfes->GetVSize());
if (partitioning)
@@ -82,7 +81,7 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, std::istream &input)
: GridFunction(pmesh, input)
{
// Convert the FiniteElementSpace, fes, to a ParFiniteElementSpace:
pfes = new ParFiniteElementSpace(pmesh, fec_owned, fes->GetVDim(),
pfes = new ParFiniteElementSpace(pmesh, fec, fes->GetVDim(),
fes->GetOrdering());
delete fes;
fes = pfes;
+7 -9
View File
@@ -751,11 +751,11 @@ void ConformingFaceRestriction::CheckFESpace(const ElementDofOrdering
#ifdef MFEM_DEBUG
const FiniteElement *fe0 = fes.GetFE(0);
const TensorBasisElement *tfe = dynamic_cast<const TensorBasisElement*>(fe0);
MFEM_VERIFY(tfe != NULL,
"ConformingFaceRestriction only supports TensorBasisElements");
MFEM_VERIFY(tfe->GetBasisType()==BasisType::GaussLobatto ||
tfe->GetBasisType()==BasisType::Positive,
"ConformingFaceRestriction only supports Gauss-Lobatto and Bernstein bases");
MFEM_VERIFY(tfe != NULL &&
(tfe->GetBasisType()==BasisType::GaussLobatto ||
tfe->GetBasisType()==BasisType::Positive),
"Only Gauss-Lobatto and Bernstein basis are supported in "
"ConformingFaceRestriction.");
// Assuming all finite elements are using Gauss-Lobatto.
const bool dof_reorder = (f_ordering == ElementDofOrdering::LEXICOGRAPHIC);
@@ -855,8 +855,7 @@ void ConformingFaceRestriction::SetFaceDofsScatterIndices(
"This method should not be used on nonconforming coarse faces.");
MFEM_ASSERT(face.element[0].orientation==0,
"FaceRestriction used on degenerated mesh.");
MFEM_VERIFY(f_ordering == ElementDofOrdering::LEXICOGRAPHIC,
"NATIVE ordering is not supported yet");
MFEM_CONTRACT_VAR(f_ordering); // not supported yet
fes.GetFE(0)->GetFaceMap(face.element[0].local_face_id, face_map);
@@ -884,8 +883,7 @@ void ConformingFaceRestriction::SetFaceDofsGatherIndices(
{
MFEM_ASSERT(!(face.IsNonconformingCoarse()),
"This method should not be used on nonconforming coarse faces.");
MFEM_VERIFY(f_ordering == ElementDofOrdering::LEXICOGRAPHIC,
"NATIVE ordering is not supported yet");
MFEM_CONTRACT_VAR(f_ordering); // not supported yet
fes.GetFE(0)->GetFaceMap(face.element[0].local_face_id, face_map);
+4 -4
View File
@@ -3390,12 +3390,11 @@ real_t TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
const IntegrationPoint &ip_s = ir_s->IntPoint(s);
Tpr->SetIntPoint(&ip_s);
double w = surf_fit_coeff->Eval(*Tpr, ip_s) * surf_fit_normal *
1.0 / surf_fit_dof_count[scalar_dof_id];
if (surf_fit_gf)
{
energy += w * sigma_e(s) * sigma_e(s);
energy += surf_fit_coeff->Eval(*Tpr, ip_s) * surf_fit_normal *
sigma_e(s) * sigma_e(s);
}
if (surf_fit_pos)
{
@@ -3406,7 +3405,8 @@ real_t TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
pos(d) = PMatI(s, d);
pos_target(d) = (*surf_fit_pos)(vdofs[d*dof + s]);
}
energy += w * surf_fit_limiter->Eval(pos, pos_target, 1.0);
energy += surf_fit_coeff->Eval(*Tpr, ip_s) * surf_fit_normal *
surf_fit_limiter->Eval(pos, pos_target, 1.0);
}
}
}
-15
View File
@@ -217,21 +217,6 @@ public:
virtual WorstCaseType GetWorstCaseType() { return wctype; }
};
/// 0 metric
class TMOP_Metric_000 : public TMOP_QualityMetric
{
public:
// W = 0.
virtual real_t EvalW(const DenseMatrix &Jpt) const {return 0.0;}
virtual void EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const {P = 0.0;}
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
const double weight, DenseMatrix &A) const {A = 0.0;}
virtual int Id() const { return 0; }
};
/// 2D non-barrier metric without a type.
class TMOP_Metric_001 : public TMOP_QualityMetric
{
-2
View File
@@ -1233,8 +1233,6 @@ void PRefinementTransferOperator::Mult(const Vector& x, Vector& y) const
int vdim = lFESpace.GetVDim();
y = 0.0;
for (int i = 0; i < mesh->GetNE(); i++)
{
DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
+2 -2
View File
@@ -63,9 +63,9 @@
#define MFEM_FOREACH_THREAD(i,k,N) for(int i=0; i<N; i++)
#endif
// 'double' and 'float' atomicAdd implementation for previous versions of CUDA
// 'double' atomicAdd implementation for previous versions of CUDA
#if defined(MFEM_USE_CUDA) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600
MFEM_DEVICE inline mfem::real_t atomicAdd(mfem::real_t *add, mfem::real_t val)
MFEM_DEVICE inline real_t atomicAdd(real_t *add, real_t val)
{
unsigned long long int *ptr = (unsigned long long int *) add;
unsigned long long int old = *ptr, reg;
+1 -1
View File
@@ -51,7 +51,7 @@ int isockstream::establish()
{
// char myname[129];
char myname[] = "localhost";
int sfd = -1;
int sfd;
struct addrinfo hints, *res, *rp;
memset(&hints, 0, sizeof(hints));
-72
View File
@@ -37,78 +37,6 @@ Table::Table(const Table &table)
}
}
Table::Table(const Table &table1,
const Table &table2, int offset)
{
MFEM_ASSERT(table1.size == table2.size,
"Tables have different sizes can not merge.");
size = table1.size;
const int nnz = table1.I[size] + table2.I[size];
I.New(size+1, table1.I.GetMemoryType());
J.New(nnz, table1.J.GetMemoryType());
I[0] = 0;
Array<int> row;
for (int i = 0; i < size; i++)
{
I[i+1] = I[i];
table1.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = row[r];
}
table2.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset : row[r] + offset;
}
}
}
Table::Table(const Table &table1,
const Table &table2, int offset2,
const Table &table3, int offset3)
{
MFEM_ASSERT(table1.size == table2.size,
"Tables have different sizes can not merge.");
MFEM_ASSERT(table1.size == table3.size,
"Tables have different sizes can not merge.");
size = table1.size;
const int nnz = table1.I[size] + table2.I[size] + table3.I[size];
I.New(size+1, table1.I.GetMemoryType());
J.New(nnz, table1.J.GetMemoryType());
I[0] = 0;
Array<int> row;
for (int i = 0; i < size; i++)
{
I[i+1] = I[i];
table1.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = row[r];
}
table2.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset2 : row[r] + offset2;
}
table3.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset3 : row[r] + offset3;
}
}
}
Table& Table::operator=(const Table &rhs)
{
Clear();
-8
View File
@@ -58,14 +58,6 @@ public:
/// Copy constructor
Table(const Table &);
/** Merge constructors
This is used to combine two or three tables into one table.*/
Table(const Table &table1,
const Table &table2, int offset2);
Table(const Table &table1,
const Table &table2, int offset2,
const Table &table3, int offset3);
/// Assignment operator: deep copy
Table& operator=(const Table &rhs);
-2
View File
@@ -1,2 +0,0 @@
linadv
output
-1168
View File
File diff suppressed because it is too large Load Diff
-204
View File
@@ -1,204 +0,0 @@
# Copyright (c) 2010-2024, 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 ?= ..
MFEM_INSTALL_DIR ?= ../mfem
SRC = $(if $(MFEM_DIR:..=),$(MFEM_DIR)/linadvmcl/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_EXAMPLES = ex0 ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 \
ex17 ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex28 ex29 ex30 \
ex31 ex33 ex34 ex36 ex37 ex38 ex39 ex40
PAR_EXAMPLES = ex0p ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p \
ex12p ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p \
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p ex34p ex35p ex36p \
ex37p ex39p ex40p
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex14 ex22 ex24 ex25 ex26 ex34
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex14p \
ex22p ex24p ex25p ex26p ex34p ex35p
ifeq ($(MFEM_USE_LAPACK),YES)
SEQ_EXAMPLES += ex38
endif
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
else
EXAMPLES = $(PAR_EXAMPLES) $(SEQ_EXAMPLES)
endif
SUBDIRS =
ifeq ($(MFEM_USE_AMGX),YES)
SUBDIRS += amgx
endif
ifeq ($(MFEM_USE_GINKGO),YES)
SUBDIRS += ginkgo
endif
ifeq ($(MFEM_USE_HIOP),YES)
SUBDIRS += hiop
endif
ifeq ($(MFEM_USE_PETSC),YES)
SUBDIRS += petsc
endif
ifeq ($(MFEM_USE_PUMI),YES)
SUBDIRS += pumi
endif
ifeq ($(MFEM_USE_SUNDIALS),YES)
SUBDIRS += sundials
endif
ifeq ($(MFEM_USE_SUPERLU),YES)
SUBDIRS += superlu
endif
ifeq ($(MFEM_USE_MOONOLITH),YES)
SUBDIRS += moonolith
endif
ifeq ($(MFEM_USE_CALIPER),YES)
SUBDIRS += caliper
endif
SUBDIRS_ALL = $(addsuffix /all,$(SUBDIRS))
SUBDIRS_TEST = $(addsuffix /test,$(SUBDIRS))
SUBDIRS_CLEAN = $(addsuffix /clean,$(SUBDIRS))
SUBDIRS_TPRINT = $(addsuffix /test-print,$(SUBDIRS))
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all clean clean-build clean-exec
# Remove built-in rule
%: %.cpp
# Replace the default implicit rule for *.cpp files
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
all: $(EXAMPLES) $(SUBDIRS_ALL)
.PHONY: $(SUBDIRS_ALL) $(SUBDIRS_TEST) $(SUBDIRS_CLEAN) $(SUBDIRS_TPRINT)
$(SUBDIRS_ALL) $(SUBDIRS_TEST) $(SUBDIRS_CLEAN):
$(MAKE) -C $(@D) $(@F)
$(SUBDIRS_TPRINT):
@$(MAKE) -C $(@D) $(@F)
# Additional dependencies
ex18: $(SRC)ex18.hpp
ex33: $(SRC)ex33.hpp
ex37: $(SRC)ex37.hpp
ifeq ($(MFEM_USE_MPI),YES)
ex18p: $(SRC)ex18.hpp
ex33p: $(SRC)ex33.hpp
ex37p: $(SRC)ex37.hpp
endif
MFEM_TESTS = EXAMPLES
include $(MFEM_TEST_MK)
test: $(SUBDIRS_TEST)
test-print: $(SUBDIRS_TPRINT)
# Testing: Parallel vs. serial runs
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
%-test-par: %
@$(call mfem-test,$<, $(RUN_MPI), Parallel example)
%-test-seq: %
@$(call mfem-test,$<,, Serial example)
%-test-par-cuda: %
@$(call mfem-test,$<, $(RUN_MPI), Parallel CUDA example,-d cuda)
%-test-seq-cuda: %
@$(call mfem-test,$<,, Serial CUDA example,-d cuda)
%-test-par-hip: %
@$(call mfem-test,$<, $(RUN_MPI), Parallel HIP example,-d hip)
%-test-seq-hip: %
@$(call mfem-test,$<,, Serial HIP example,-d hip)
# Testing: Specific execution options
ex0-test-seq: ex0
@$(call mfem-test,$<,, Serial example,,1)
ex0p-test-par: ex0p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,,1)
ex1-test-seq: ex1
@$(call mfem-test,$<,, Serial example)
ex1p-test-par: ex1p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example)
ex10-test-seq: ex10
@$(call mfem-test,$<,, Serial example,-tf 5)
ex10p-test-par: ex10p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-tf 5)
ex14-test-seq-cuda: ex14
@$(call mfem-test,$<,, Serial CUDA example,-r 2 -pa -d cuda)
ex14p-test-par-cuda: ex14p
@$(call mfem-test,$<, $(RUN_MPI), Parallel CUDA example,-rs 2 -rp 0 -pa -d cuda)
ex14-test-seq-hip: ex14
@$(call mfem-test,$<,, Serial HIP example,-r 2 -pa -d hip)
ex14p-test-par-hip: ex14p
@$(call mfem-test,$<, $(RUN_MPI), Parallel HIP example,-rs 2 -rp 0 -pa -d hip)
ex15-test-seq: ex15
@$(call mfem-test,$<,, Serial example,-e 1)
ex15p-test-par: ex15p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-e 1)
ex27-test-seq: ex27
@$(call mfem-test,$<,, Serial example,-dg)
ex27p-test-par: ex27p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-dg)
ex37-test-seq: ex37
@$(call mfem-test,$<,, Serial example,-mi 3)
ex37p-test-par: ex37p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-mi 3)
# Testing: optional tests
ifeq ($(MFEM_USE_STRUMPACK),YES)
ex11p-test-strumpack: ex11p
@$(call mfem-test,$<, $(RUN_MPI), STRUMPACK example,--strumpack)
test-par-YES: ex11p-test-strumpack
endif
ifeq ($(MFEM_USE_SUPERLU),YES)
ex11p-test-superlu: ex11p
@$(call mfem-test,$<, $(RUN_MPI), SuperLU_DIST example,--superlu)
test-par-YES: ex11p-test-superlu
endif
ifeq ($(MFEM_USE_MKL_CPARDISO),YES)
ex11p-test-cpardiso: ex11p
@$(call mfem-test,$<, $(RUN_MPI), MKL_CPARDISO example,--cpardiso)
test-par-YES: ex11p-test-cpardiso
endif
# 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 $(SUBDIRS_CLEAN)
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -f refined.mesh displaced.mesh mesh.* ex5.mesh ex6p-checkpoint.*
@rm -rf Example5* Example9* Example15* Example16* Example23* ParaView
@rm -f sphere_refined.* sol.* sol_u.* sol_p.* sol_r.* sol_i.*
@rm -f ex9.mesh ex9-mesh.* ex9-init.* ex9-final.*
@rm -f deformed.* velocity.* elastic_energy.* mode_* mode_deriv_* flux.*
@rm -f ex5-p-*.bp ex9-p-*.bp ex12-p-*.bp ex16-p-*.bp
@rm -f ex16.mesh ex16-mesh.* ex16-init.* ex16-final.*
@rm -f deformation.* pressure.*
@rm -f ex20.dat ex20p_?????.dat gnuplot_ex20.inp gnuplot_ex20p.inp
@rm -f ex21*.mesh ex21*.sol ex21p_*.*
@rm -f ex23.mesh ex23-*.gf
@rm -f ex25.mesh ex25-*.gf ex25p-*.*
@rm -f euler-?-final.* euler-?-init.* euler-mesh-final.* euler-mesh.*
@rm -rf ex28_* ex28p_*
@rm -rf cond.* cond_mesh.* cond_j.* dsol.* port_mesh.* port_mode.*
-1
View File
@@ -44,7 +44,6 @@ list(APPEND HDRS
handle.hpp
invariants.hpp
kernels.hpp
lapack.hpp
linalg.hpp
matrix.hpp
ode.hpp
+138 -20
View File
@@ -10,9 +10,60 @@
// CONTRIBUTING.md for details.
#include "complex_densemat.hpp"
#include "lapack.hpp"
#include <complex>
#ifdef MFEM_USE_LAPACK
#ifdef MFEM_USE_SINGLE
extern "C" void
cgetrf_(int *, int *, std::complex<float> *, int *, int *, int *);
extern "C" void
cgetrs_(char *, int *, int *, std::complex<float> *, int *, int *,
std::complex<float> *, int *, int *);
extern "C" void
cgetri_(int *, std::complex<float> *, int *, int *,
std::complex<float> *, int *, int *);
extern "C" void
ctrsm_(char *, char *, char *, char *, int *, int *, std::complex<float> *,
std::complex<float> *, int *, std::complex<float> *, int *);
extern "C" void
cpotrf_(char *, int *, std::complex<float> *, int *, int *);
extern "C" void
ctrtrs_(char *, char*, char *, int *, int *, std::complex<float> *, int *,
std::complex<float> *, int *, int *);
extern "C" void
cpotri_(char *, int *, std::complex<float> *, int*, int *);
extern "C" void
cpotrs_(char *, int *, int *, std::complex<float> *, int *,
std::complex<float> *, int *, int *);
#elif defined MFEM_USE_DOUBLE
extern "C" void
zgetrf_(int *, int *, std::complex<double> *, int *, int *, int *);
extern "C" void
zgetrs_(char *, int *, int *, std::complex<double> *, int *, int *,
std::complex<double> *, int *, int *);
extern "C" void
zgetri_(int *, std::complex<double> *, int *, int *,
std::complex<double> *, int *, int *);
extern "C" void
ztrsm_(char *, char *, char *, char *, int *, int *, std::complex<double> *,
std::complex<double> *, int *, std::complex<double> *, int *);
extern "C" void
zpotrf_(char *, int *, std::complex<double> *, int *, int *);
extern "C" void
ztrtrs_(char *, char*, char *, int *, int *, std::complex<double> *, int *,
std::complex<double> *, int *, int *);
extern "C" void
zpotri_(char *, int *, std::complex<double> *, int*, int *);
extern "C" void
zpotrs_(char *, int *, int *, std::complex<double> *, int *,
std::complex<double> *, int *, int *);
#endif
#endif
namespace mfem
{
@@ -124,17 +175,35 @@ ComplexDenseMatrix * ComplexDenseMatrix::ComputeInverse()
std::complex<real_t> qwork, *work;
int info;
MFEM_LAPACK_COMPLEX(getrf_)(&w, &w, data, &w, ipiv, &info);
#ifdef MFEM_USE_SINGLE
cgetrf_(&w, &w, data, &w, ipiv, &info);
#elif defined MFEM_USE_DOUBLE
zgetrf_(&w, &w, data, &w, ipiv, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (info)
{
mfem_error("DenseMatrix::Invert() : Error in ZGETRF");
}
MFEM_LAPACK_COMPLEX(getri_)(&w, data, &w, ipiv, &qwork, &lwork, &info);
#ifdef MFEM_USE_SINGLE
cgetri_(&w, data, &w, ipiv, &qwork, &lwork, &info);
#elif defined MFEM_USE_DOUBLE
zgetri_(&w, data, &w, ipiv, &qwork, &lwork, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
lwork = (int) qwork.real();
work = new std::complex<real_t>[lwork];
MFEM_LAPACK_COMPLEX(getri_)(&w, data, &w, ipiv, work, &lwork, &info);
#ifdef MFEM_USE_SINGLE
cgetri_(&w, data, &w, ipiv, work, &lwork, &info);
#elif defined MFEM_USE_DOUBLE
zgetri_(&w, data, &w, ipiv, work, &lwork, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (info)
{
mfem_error("DenseMatrix::Invert() : Error in ZGETRI");
@@ -424,7 +493,11 @@ bool ComplexLUFactors::Factor(int m, real_t TOL)
#ifdef MFEM_USE_LAPACK
int info = 0;
MFEM_VERIFY(data, "Matrix data not set");
if (m) { MFEM_LAPACK_COMPLEX(getrf_)(&m, &m, data, &m, ipiv, &info); }
#ifdef MFEM_USE_SINGLE
if (m) { cgetrf_(&m, &m, data, &m, ipiv, &info); }
#elif defined MFEM_USE_DOUBLE
if (m) { zgetrf_(&m, &m, data, &m, ipiv, &info); }
#endif
return info == 0;
#else
// compiling without LAPACK
@@ -586,10 +659,13 @@ void ComplexLUFactors::Solve(int m, int n, real_t *X_r, real_t * X_i) const
std::complex<real_t> * x = ComplexFactors::RealToComplex(m*n,X_r,X_i);
char trans = 'N';
int info = 0;
if (m > 0 && n > 0)
{
MFEM_LAPACK_COMPLEX(getrs_)(&trans, &m, &n, data, &m, ipiv, x, &m, &info);
}
#ifdef MFEM_USE_SINGLE
if (m > 0 && n > 0) { cgetrs_(&trans, &m, &n, data, &m, ipiv, x, &m, &info); }
#elif defined MFEM_USE_DOUBLE
if (m > 0 && n > 0) { zgetrs_(&trans, &m, &n, data, &m, ipiv, x, &m, &info); }
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "LAPACK: error in ZGETRS");
ComplexFactors::ComplexToReal(m*n,x,X_r,X_i);
delete [] x;
@@ -609,8 +685,15 @@ void ComplexLUFactors::RightSolve(int m, int n, real_t *X_r, real_t * X_i) const
if (m > 0 && n > 0)
{
std::complex<real_t> alpha(1.0,0.0);
MFEM_LAPACK_COMPLEX(trsm_)(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
MFEM_LAPACK_COMPLEX(trsm_)(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#ifdef MFEM_USE_SINGLE
ctrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
ctrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#elif defined MFEM_USE_DOUBLE
ztrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
ztrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#else
MFEM_ABORT("Floating point type undefined");
#endif
}
#else
// compiling without LAPACK
@@ -732,7 +815,13 @@ bool ComplexCholeskyFactors::Factor(int m, real_t TOL)
int info = 0;
char uplo = 'L';
MFEM_VERIFY(data, "Matrix data not set");
if (m) { MFEM_LAPACK_COMPLEX(potrf_)(&uplo, &m, data, &m, &info); }
#ifdef MFEM_USE_SINGLE
if (m) {cpotrf_(&uplo, &m, data, &m, &info);}
#elif defined MFEM_USE_DOUBLE
if (m) {zpotrf_(&uplo, &m, data, &m, &info);}
#else
MFEM_ABORT("Floating point type undefined");
#endif
return info == 0;
#else
// CholeskyCrout algorithm
@@ -832,8 +921,13 @@ void ComplexCholeskyFactors::LSolve(int m, int n, real_t * X_r,
char diag = 'N';
int info = 0;
MFEM_LAPACK_COMPLEX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, x, &m,
&info);
#ifdef MFEM_USE_SINGLE
ctrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#elif defined MFEM_USE_DOUBLE
ztrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "ComplexCholeskyFactors:LSolve:: info");
#else
for (int k = 0; k < n; k++)
@@ -866,8 +960,13 @@ void ComplexCholeskyFactors::USolve(int m, int n, real_t * X_r,
char diag = 'N';
int info = 0;
MFEM_LAPACK_COMPLEX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, x, &m,
&info);
#ifdef MFEM_USE_SINGLE
ctrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#elif defined MFEM_USE_DOUBLE
ztrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "ComplexCholeskyFactors:USolve:: info");
#else
// X <- L^{-t} X
@@ -895,7 +994,13 @@ void ComplexCholeskyFactors::Solve(int m, int n, real_t * X_r,
char uplo = 'L';
int info = 0;
std::complex<real_t> *x = ComplexFactors::RealToComplex(m*n,X_r,X_i);
MFEM_LAPACK_COMPLEX(potrs_)(&uplo, &m, &n, data, &m, x, &m, &info);
#ifdef MFEM_USE_SINGLE
cpotrs_(&uplo, &m, &n, data, &m, x, &m, &info);
#elif defined MFEM_USE_DOUBLE
zpotrs_(&uplo, &m, &n, data, &m, x, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "ComplexCholeskyFactors:Solve:: info");
ComplexFactors::ComplexToReal(m*n,x,X_r,X_i);
delete x;
@@ -921,8 +1026,15 @@ void ComplexCholeskyFactors::RightSolve(int m, int n, real_t * X_r,
std::complex<real_t> alpha(1.0,0.0);
if (m > 0 && n > 0)
{
MFEM_LAPACK_COMPLEX(trsm_)(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
MFEM_LAPACK_COMPLEX(trsm_)(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
#ifdef MFEM_USE_SINGLE
ctrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
ctrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
#elif defined MFEM_USE_DOUBLE
ztrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
ztrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
#else
MFEM_ABORT("Floating point type undefined");
#endif
}
#else
// X <- X L^{-H}
@@ -973,7 +1085,13 @@ void ComplexCholeskyFactors::GetInverseMatrix(int m, real_t * X_r,
}
char uplo = 'L';
int info = 0;
MFEM_LAPACK_COMPLEX(potri_)(&uplo, &m, X, &m, &info);
#ifdef MFEM_USE_SINGLE
cpotri_(&uplo, &m, X, &m, &info);
#elif defined MFEM_USE_DOUBLE
zpotri_(&uplo, &m, X, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "ComplexCholeskyFactors:GetInverseMatrix:: info");
// fill in the upper triangular part
for (int i = 0; i<m; i++)
+355 -69
View File
@@ -17,7 +17,6 @@
#include "vector.hpp"
#include "matrix.hpp"
#include "densemat.hpp"
#include "lapack.hpp"
#include "../general/forall.hpp"
#include "../general/table.hpp"
#include "../general/globals.hpp"
@@ -33,6 +32,103 @@
#endif
#ifdef MFEM_USE_LAPACK
#ifdef MFEM_USE_SINGLE
extern "C" void
sgemm_(char *, char *, int *, int *, int *, float *, float *,
int *, float *, int *, float *, float *, int *);
extern "C" void
sgetrf_(int *, int *, float *, int *, int *, int *);
extern "C" void
sgetrs_(char *, int *, int *, float *, int *, int *, float *, int *, int *);
extern "C" void
sgetri_(int *N, float *A, int *LDA, int *IPIV, float *WORK,
int *LWORK, int *INFO);
extern "C" void
ssyevr_(char *JOBZ, char *RANGE, char *UPLO, int *N, float *A, int *LDA,
float *VL, float *VU, int *IL, int *IU, float *ABSTOL, int *M,
float *W, float *Z, int *LDZ, int *ISUPPZ, float *WORK, int *LWORK,
int *IWORK, int *LIWORK, int *INFO);
extern "C" void
ssyev_(char *JOBZ, char *UPLO, int *N, float *A, int *LDA, float *W,
float *WORK, int *LWORK, int *INFO);
extern "C" void
ssygv_ (int *ITYPE, char *JOBZ, char *UPLO, int * N, float *A, int *LDA,
float *B, int *LDB, float *W, float *WORK, int *LWORK, int *INFO);
extern "C" void
sgesvd_(char *JOBU, char *JOBVT, int *M, int *N, float *A, int *LDA,
float *S, float *U, int *LDU, float *VT, int *LDVT, float *WORK,
int *LWORK, int *INFO);
extern "C" void
strsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n,
float *alpha, float *a, int *lda, float *b, int *ldb);
extern "C" void
sggev_(char *jobvl, char *jobvr, int *n, float *a, int *lda, float *B,
int *ldb, float *alphar, float *alphai, float *beta, float *vl,
int * ldvl, float * vr, int * ldvr, float * work, int * lwork, int* info);
// Cholesky factorizations/solves
extern "C" void
spotrf_(char *, int *, float *, int *, int *);
// Solve
extern "C" void
spotrs_(char *, int *, int *, float *, int *, float *, int *, int *);
// Triangular Solves
extern "C" void
strtrs_(char *, char*, char *, int *, int *, float *, int *, float *, int *,
int *);
extern "C" void
spotri_(char *, int *, float *, int*, int *);
#elif defined MFEM_USE_DOUBLE
extern "C" void
dgemm_(char *, char *, int *, int *, int *, double *, double *,
int *, double *, int *, double *, double *, int *);
extern "C" void
dgetrf_(int *, int *, double *, int *, int *, int *);
extern "C" void
dgetrs_(char *, int *, int *, double *, int *, int *, double *, int *, int *);
extern "C" void
dgetri_(int *N, double *A, int *LDA, int *IPIV, double *WORK,
int *LWORK, int *INFO);
extern "C" void
dsyevr_(char *JOBZ, char *RANGE, char *UPLO, int *N, double *A, int *LDA,
double *VL, double *VU, int *IL, int *IU, double *ABSTOL, int *M,
double *W, double *Z, int *LDZ, int *ISUPPZ, double *WORK, int *LWORK,
int *IWORK, int *LIWORK, int *INFO);
extern "C" void
dsyev_(char *JOBZ, char *UPLO, int *N, double *A, int *LDA, double *W,
double *WORK, int *LWORK, int *INFO);
extern "C" void
dsygv_ (int *ITYPE, char *JOBZ, char *UPLO, int * N, double *A, int *LDA,
double *B, int *LDB, double *W, double *WORK, int *LWORK, int *INFO);
extern "C" void
dgesvd_(char *JOBU, char *JOBVT, int *M, int *N, double *A, int *LDA,
double *S, double *U, int *LDU, double *VT, int *LDVT, double *WORK,
int *LWORK, int *INFO);
extern "C" void
dtrsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n,
double *alpha, double *a, int *lda, double *b, int *ldb);
extern "C" void
dggev_(char *jobvl, char *jobvr, int *n, double *a, int *lda, double *B,
int *ldb, double *alphar, double *alphai, double *beta, double *vl,
int * ldvl, double * vr, int * ldvr, double * work, int * lwork, int* info);
// Cholesky factorizations/solves
extern "C" void
dpotrf_(char *, int *, double *, int *, int *);
// Solve
extern "C" void
dpotrs_(char *, int *, int *, double *, int *, double *, int *, int *);
// Triangular Solves
extern "C" void
dtrtrs_(char *, char*, char *, int *, int *, double *, int *, double *, int *,
int *);
extern "C" void
dpotri_(char *, int *, double *, int*, int *);
#endif
#endif
namespace mfem
{
@@ -705,19 +801,36 @@ void DenseMatrix::Invert()
real_t qwork, *work;
int info;
MFEM_LAPACK_PREFIX(getrf_)(&width, &width, data, &width, ipiv, &info);
#ifdef MFEM_USE_SINGLE
sgetrf_(&width, &width, data, &width, ipiv, &info);
#elif defined MFEM_USE_DOUBLE
dgetrf_(&width, &width, data, &width, ipiv, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (info)
{
mfem_error("DenseMatrix::Invert() : Error in DGETRF");
}
MFEM_LAPACK_PREFIX(getri_)(&width, data, &width, ipiv, &qwork, &lwork, &info);
#ifdef MFEM_USE_SINGLE
sgetri_(&width, data, &width, ipiv, &qwork, &lwork, &info);
lwork = (int) qwork;
work = new real_t[lwork];
work = new float[lwork];
MFEM_LAPACK_PREFIX(getri_)(&width, data, &width, ipiv, work, &lwork, &info);
sgetri_(&width, data, &width, ipiv, work, &lwork, &info);
#elif defined MFEM_USE_DOUBLE
dgetri_(&width, data, &width, ipiv, &qwork, &lwork, &info);
lwork = (int) qwork;
work = new double[lwork];
dgetri_(&width, data, &width, ipiv, work, &lwork, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (info)
{
@@ -953,9 +1066,15 @@ void dsyevr_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect)
A[i] = data[i];
}
MFEM_LAPACK_PREFIX(syevr_)(&JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL,
&IU, &ABSTOL, &M, W, Z, &LDZ, ISUPPZ, &QWORK,
&LWORK, &QIWORK, &LIWORK, &INFO);
#ifdef MFEM_USE_SINGLE
ssyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
#elif defined MFEM_USE_DOUBLE
dsyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
#else
MFEM_ABORT("Floating point type undefined");
#endif
&ABSTOL, &M, W, Z, &LDZ, ISUPPZ, &QWORK, &LWORK,
&QIWORK, &LIWORK, &INFO );
LWORK = (int) QWORK;
LIWORK = QIWORK;
@@ -963,9 +1082,15 @@ void dsyevr_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect)
WORK = new real_t[LWORK];
IWORK = new int[LIWORK];
MFEM_LAPACK_PREFIX(syevr_)(&JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL,
&IU, &ABSTOL, &M, W, Z, &LDZ, ISUPPZ, WORK,
&LWORK, IWORK, &LIWORK, &INFO);
#ifdef MFEM_USE_SINGLE
ssyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
#elif defined MFEM_USE_DOUBLE
dsyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
#else
MFEM_ABORT("Floating point type undefined");
#endif
&ABSTOL, &M, W, Z, &LDZ, ISUPPZ, WORK, &LWORK,
IWORK, &LIWORK, &INFO );
if (INFO != 0)
{
@@ -1105,12 +1230,24 @@ void dsyev_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect)
A[i] = data[i];
}
MFEM_LAPACK_PREFIX(syev_)(&JOBZ, &UPLO, &N, A, &LDA, W, &QWORK, &LWORK, &INFO);
#ifdef MFEM_USE_SINGLE
ssyev_(&JOBZ, &UPLO, &N, A, &LDA, W, &QWORK, &LWORK, &INFO);
#elif defined MFEM_USE_DOUBLE
dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, &QWORK, &LWORK, &INFO);
#else
MFEM_ABORT("Floating point type undefined");
#endif
LWORK = (int) QWORK;
WORK = new real_t[LWORK];
MFEM_LAPACK_PREFIX(syev_)(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO);
#ifdef MFEM_USE_SINGLE
ssyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO);
#elif defined MFEM_USE_DOUBLE
dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO);
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (INFO != 0)
{
@@ -1185,14 +1322,24 @@ void dsygv_Eigensystem(DenseMatrix &a, DenseMatrix &b, Vector &ev,
B[i] = b_data[i];
}
MFEM_LAPACK_PREFIX(sygv_)(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W,
&QWORK, &LWORK, &INFO);
#ifdef MFEM_USE_SINGLE
ssygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, &QWORK, &LWORK, &INFO);
#elif defined MFEM_USE_DOUBLE
dsygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, &QWORK, &LWORK, &INFO);
#else
MFEM_ABORT("Floating point type undefined");
#endif
LWORK = (int) QWORK;
WORK = new real_t[LWORK];
MFEM_LAPACK_PREFIX(sygv_)(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, WORK,
&LWORK, &INFO);
#ifdef MFEM_USE_SINGLE
ssygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, WORK, &LWORK, &INFO);
#elif defined MFEM_USE_DOUBLE
dsygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, WORK, &LWORK, &INFO);
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (INFO != 0)
{
@@ -1244,14 +1391,26 @@ void DenseMatrix::SingularValues(Vector &sv) const
int info;
real_t qwork;
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, a, &m, s, u, &m, vt, &n,
&qwork, &lwork, &info);
#ifdef MFEM_USE_SINGLE
sgesvd_(&jobu, &jobvt, &m, &n, a, &m,
#elif defined MFEM_USE_DOUBLE
dgesvd_(&jobu, &jobvt, &m, &n, a, &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
s, u, &m, vt, &n, &qwork, &lwork, &info);
lwork = (int) qwork;
work = new real_t[lwork];
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, a, &m, s, u, &m, vt, &n,
work, &lwork, &info);
#ifdef MFEM_USE_SINGLE
sgesvd_(&jobu, &jobvt, &m, &n, a, &m,
#elif defined MFEM_USE_DOUBLE
dgesvd_(&jobu, &jobvt, &m, &n, a, &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
s, u, &m, vt, &n, work, &lwork, &info);
delete [] work;
if (info)
@@ -2414,8 +2573,14 @@ void Mult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
static real_t alpha = 1.0, beta = 0.0;
int m = b.Height(), n = c.Width(), k = b.Width();
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
c.Data(), &k, &beta, a.Data(), &m);
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
c.Data(), &k, &beta, a.Data(), &m);
#else
const int ah = a.Height();
const int aw = a.Width();
@@ -2438,8 +2603,14 @@ void AddMult_a(real_t alpha, const DenseMatrix &b, const DenseMatrix &c,
static real_t beta = 1.0;
int m = b.Height(), n = c.Width(), k = b.Width();
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
c.Data(), &k, &beta, a.Data(), &m);
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
c.Data(), &k, &beta, a.Data(), &m);
#else
const int ah = a.Height();
const int aw = a.Width();
@@ -2470,8 +2641,12 @@ void AddMult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
static real_t alpha = 1.0, beta = 1.0;
int m = b.Height(), n = c.Width(), k = b.Width();
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
c.Data(), &k, &beta, a.Data(), &m);
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#endif
c.Data(), &k, &beta, a.Data(), &m);
#else
const int ah = a.Height();
const int aw = a.Width();
@@ -2790,8 +2965,12 @@ void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
static real_t alpha = 1.0, beta = 0.0;
int m = A.Height(), n = B.Height(), k = A.Width();
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
B.Data(), &n, &beta, ABt.Data(), &m);
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#endif
B.Data(), &n, &beta, ABt.Data(), &m);
#elif 1
const int ah = A.Height();
const int bh = B.Height();
@@ -2895,8 +3074,12 @@ void AddMultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
static real_t alpha = 1.0, beta = 1.0;
int m = A.Height(), n = B.Height(), k = A.Width();
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
B.Data(), &n, &beta, ABt.Data(), &m);
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#endif
B.Data(), &n, &beta, ABt.Data(), &m);
#elif 1
const int ah = A.Height();
const int bh = B.Height();
@@ -2990,8 +3173,12 @@ void AddMult_a_ABt(real_t a, const DenseMatrix &A, const DenseMatrix &B,
static real_t beta = 1.0;
int m = A.Height(), n = B.Height(), k = A.Width();
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
B.Data(), &n, &beta, ABt.Data(), &m);
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#endif
B.Data(), &n, &beta, ABt.Data(), &m);
#elif 1
const int ah = A.Height();
const int bh = B.Height();
@@ -3047,8 +3234,12 @@ void MultAtB(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &AtB)
static real_t alpha = 1.0, beta = 0.0;
int m = A.Width(), n = B.Width(), k = A.Height();
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
B.Data(), &k, &beta, AtB.Data(), &m);
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#endif
B.Data(), &k, &beta, AtB.Data(), &m);
#elif 1
const int ah = A.Height();
const int aw = A.Width();
@@ -3100,8 +3291,12 @@ void AddMultAtB(const DenseMatrix &A, const DenseMatrix &B,
static real_t alpha = 1.0, beta = 1.0;
int m = A.Width(), n = B.Width(), k = A.Height();
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
B.Data(), &k, &beta, AtB.Data(), &m);
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#endif
B.Data(), &k, &beta, AtB.Data(), &m);
#else
const int ah = A.Height();
const int aw = A.Width();
@@ -3140,8 +3335,12 @@ void AddMult_a_AtB(real_t a, const DenseMatrix &A, const DenseMatrix &B,
static real_t beta = 1.0;
int m = A.Width(), n = B.Width(), k = A.Height();
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
B.Data(), &k, &beta, AtB.Data(), &m);
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#endif
B.Data(), &k, &beta, AtB.Data(), &m);
#else
const int ah = A.Height();
const int aw = A.Width();
@@ -3346,7 +3545,13 @@ bool LUFactors::Factor(int m, real_t TOL)
{
#ifdef MFEM_USE_LAPACK
int info = 0;
if (m) { MFEM_LAPACK_PREFIX(getrf_)(&m, &m, data, &m, ipiv, &info); }
#ifdef MFEM_USE_SINGLE
if (m) { sgetrf_(&m, &m, data, &m, ipiv, &info); }
#elif defined MFEM_USE_DOUBLE
if (m) { dgetrf_(&m, &m, data, &m, ipiv, &info); }
#else
MFEM_ABORT("Floating point type undefined");
#endif
return info == 0;
#else
// compiling without LAPACK
@@ -3498,10 +3703,13 @@ void LUFactors::Solve(int m, int n, real_t *X) const
#ifdef MFEM_USE_LAPACK
char trans = 'N';
int info = 0;
if (m > 0 && n > 0)
{
MFEM_LAPACK_PREFIX(getrs_)(&trans, &m, &n, data, &m, ipiv, X, &m, &info);
}
#ifdef MFEM_USE_SINGLE
if (m > 0 && n > 0) { sgetrs_(&trans, &m, &n, data, &m, ipiv, X, &m, &info); }
#elif defined MFEM_USE_DOUBLE
if (m > 0 && n > 0) { dgetrs_(&trans, &m, &n, data, &m, ipiv, X, &m, &info); }
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "LAPACK: error in DGETRS");
#else
// compiling without LAPACK
@@ -3518,8 +3726,15 @@ void LUFactors::RightSolve(int m, int n, real_t *X) const
real_t alpha = 1.0;
if (m > 0 && n > 0)
{
MFEM_LAPACK_PREFIX(trsm_)(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
MFEM_LAPACK_PREFIX(trsm_)(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#ifdef MFEM_USE_SINGLE
strsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
strsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#elif defined MFEM_USE_DOUBLE
dtrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
dtrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#else
MFEM_ABORT("Floating point type undefined");
#endif
}
#else
// compiling without LAPACK
@@ -3696,7 +3911,13 @@ bool CholeskyFactors::Factor(int m, real_t TOL)
int info = 0;
char uplo = 'L';
MFEM_VERIFY(data, "Matrix data not set");
if (m) { MFEM_LAPACK_PREFIX(potrf_)(&uplo, &m, data, &m, &info); }
#ifdef MFEM_USE_SINGLE
if (m) {spotrf_(&uplo, &m, data, &m, &info);}
#elif defined MFEM_USE_DOUBLE
if (m) {dpotrf_(&uplo, &m, data, &m, &info);}
#else
MFEM_ABORT("Floating point type undefined");
#endif
return info == 0;
#else
// CholeskyCrout algorithm
@@ -3788,8 +4009,13 @@ void CholeskyFactors::LSolve(int m, int n, real_t * X) const
char diag = 'N';
int info = 0;
MFEM_LAPACK_PREFIX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, X, &m,
&info);
#ifdef MFEM_USE_SINGLE
strtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
#elif defined MFEM_USE_DOUBLE
dtrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "CholeskyFactors:LSolve:: info");
#else
@@ -3819,8 +4045,13 @@ void CholeskyFactors::USolve(int m, int n, real_t * X) const
char diag = 'N';
int info = 0;
MFEM_LAPACK_PREFIX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, X, &m,
&info);
#ifdef MFEM_USE_SINGLE
strtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
#elif defined MFEM_USE_DOUBLE
dtrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "CholeskyFactors:USolve:: info");
#else
@@ -3846,7 +4077,13 @@ void CholeskyFactors::Solve(int m, int n, real_t * X) const
#ifdef MFEM_USE_LAPACK
char uplo = 'L';
int info = 0;
MFEM_LAPACK_PREFIX(potrs_)(&uplo, &m, &n, data, &m, X, &m, &info);
#ifdef MFEM_USE_SINGLE
spotrs_(&uplo, &m, &n, data, &m, X, &m, &info);
#elif defined MFEM_USE_DOUBLE
dpotrs_(&uplo, &m, &n, data, &m, X, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "CholeskyFactors:Solve:: info");
#else
@@ -3867,8 +4104,15 @@ void CholeskyFactors::RightSolve(int m, int n, real_t * X) const
real_t alpha = 1.0;
if (m > 0 && n > 0)
{
MFEM_LAPACK_PREFIX(trsm_)(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,X,&n);
MFEM_LAPACK_PREFIX(trsm_)(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,X,&n);
#ifdef MFEM_USE_SINGLE
strsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,X,&n);
strsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,X,&n);
#elif defined MFEM_USE_DOUBLE
dtrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,X,&n);
dtrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,X,&n);
#else
MFEM_ABORT("Floating point type undefined");
#endif
}
#else
// X <- X L^{-t}
@@ -3916,7 +4160,13 @@ void CholeskyFactors::GetInverseMatrix(int m, real_t * X) const
}
char uplo = 'L';
int info = 0;
MFEM_LAPACK_PREFIX(potri_)(&uplo, &m, X, &m, &info);
#ifdef MFEM_USE_SINGLE
spotri_(&uplo, &m, X, &m, &info);
#elif defined MFEM_USE_DOUBLE
dpotri_(&uplo, &m, X, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "CholeskyFactors:GetInverseMatrix:: info");
// fill in the upper triangular part
for (int i = 0; i<m; i++)
@@ -4100,8 +4350,14 @@ DenseMatrixEigensystem::DenseMatrixEigensystem(DenseMatrix &m)
uplo = 'U';
lwork = -1;
real_t qwork;
MFEM_LAPACK_PREFIX(syev_)(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
&qwork, &lwork, &info);
#ifdef MFEM_USE_SINGLE
ssyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
#elif defined MFEM_USE_DOUBLE
dsyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
#else
MFEM_ABORT("Floating point type undefined");
#endif
&qwork, &lwork, &info);
lwork = (int) qwork;
work = new real_t[lwork];
@@ -4129,8 +4385,14 @@ void DenseMatrixEigensystem::Eval()
#endif
EVect = mat;
MFEM_LAPACK_PREFIX(syev_)(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
work, &lwork, &info);
#ifdef MFEM_USE_SINGLE
ssyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
#elif defined MFEM_USE_DOUBLE
dsyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
#else
MFEM_ABORT("Floating point type undefined");
#endif
work, &lwork, &info);
if (info != 0)
{
@@ -4182,9 +4444,15 @@ DenseMatrixGeneralizedEigensystem::DenseMatrixGeneralizedEigensystem(
int nl = max(1,Vl.Height());
int nr = max(1,Vr.Height());
MFEM_LAPACK_PREFIX(ggev_)(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,
alphar, alphai, beta, Vl.Data(), &nl, Vr.Data(),
&nr, &qwork, &lwork, &info);
#ifdef MFEM_USE_SINGLE
sggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
#elif defined MFEM_USE_DOUBLE
dggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
#else
MFEM_ABORT("Floating point type undefined");
#endif
alphai, beta, Vl.Data(), &nl, Vr.Data(), &nr,
&qwork, &lwork, &info);
lwork = (int) qwork;
work = new real_t[lwork];
@@ -4197,9 +4465,15 @@ void DenseMatrixGeneralizedEigensystem::Eval()
A_copy = A;
B_copy = B;
MFEM_LAPACK_PREFIX(ggev_)(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,
alphar, alphai, beta, Vl.Data(), &nl, Vr.Data(),
&nr, work, &lwork, &info);
#ifdef MFEM_USE_SINGLE
sggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
#elif defined MFEM_USE_DOUBLE
dggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
#else
MFEM_ABORT("Floating point type undefined");
#endif
alphai, beta, Vl.Data(), &nl, Vr.Data(), &nr,
work, &lwork, &info);
if (info != 0)
{
mfem::err << "DenseMatrixGeneralizedEigensystem::Eval(): DGGEV error code: "
@@ -4280,8 +4554,14 @@ void DenseMatrixSVD::Init()
sv.SetSize(min(m, n));
real_t qwork;
lwork = -1;
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(),
NULL, &m, NULL, &n, &qwork, &lwork, &info);
#ifdef MFEM_USE_SINGLE
sgesvd_(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(), NULL, &m,
#elif defined MFEM_USE_DOUBLE
dgesvd_(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(), NULL, &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
NULL, &n, &qwork, &lwork, &info);
lwork = (int) qwork;
work = new real_t[lwork];
}
@@ -4317,8 +4597,14 @@ void DenseMatrixSVD::Eval(DenseMatrix &M)
datavt = Vt.Data();
}
Mc = M;
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, Mc.Data(), &m, sv.GetData(),
datau, &m, datavt, &n, work, &lwork, &info);
#ifdef MFEM_USE_SINGLE
sgesvd_(&jobu, &jobvt, &m, &n, Mc.Data(), &m, sv.GetData(), datau, &m,
#elif defined MFEM_USE_DOUBLE
dgesvd_(&jobu, &jobvt, &m, &n, Mc.Data(), &m, sv.GetData(), datau, &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
datavt, &n, work, &lwork, &info);
if (info)
{
-134
View File
@@ -1,134 +0,0 @@
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_LAPACK_HPP
#define MFEM_LAPACK_HPP
#include "../config/config.hpp"
#ifdef MFEM_USE_LAPACK
#ifdef MFEM_USE_SINGLE
#define MFEM_LAPACK_PREFIX(stub) s##stub
#define MFEM_LAPACK_COMPLEX(stub) c##stub
#elif defined(MFEM_USE_DOUBLE)
#define MFEM_LAPACK_PREFIX(stub) d##stub
#define MFEM_LAPACK_COMPLEX(stub) z##stub
#endif
namespace mfem
{
extern "C" void
MFEM_LAPACK_PREFIX(gemm_)(char *, char *, int *, int *, int *, real_t *,
real_t *, int *, real_t *, int *, real_t *, real_t *,
int *);
extern "C" void
MFEM_LAPACK_PREFIX(getrf_)(int *, int *, real_t *, int *, int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(getrs_)(char *, int *, int *, real_t *, int *, int *,
real_t *, int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(getri_)(int *N, real_t *A, int *LDA, int *IPIV, real_t *WORK,
int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(syevr_)(char *JOBZ, char *RANGE, char *UPLO, int *N,
real_t *A, int *LDA, real_t *VL, real_t *VU, int *IL,
int *IU, real_t *ABSTOL, int *M, real_t *W,
real_t *Z, int *LDZ, int *ISUPPZ, real_t *WORK,
int *LWORK, int *IWORK, int *LIWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(syev_)(char *JOBZ, char *UPLO, int *N, real_t *A, int *LDA,
real_t *W, real_t *WORK, int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(sygv_) (int *ITYPE, char *JOBZ, char *UPLO, int * N,
real_t *A, int *LDA, real_t *B, int *LDB, real_t *W,
real_t *WORK, int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(gesvd_)(char *JOBU, char *JOBVT, int *M, int *N, real_t *A,
int *LDA, real_t *S, real_t *U, int *LDU, real_t *VT,
int *LDVT, real_t *WORK, int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(trsm_)(char *side, char *uplo, char *transa, char *diag,
int *m, int *n, real_t *alpha, real_t *a, int *lda,
real_t *b, int *ldb);
extern "C" void
MFEM_LAPACK_PREFIX(ggev_)(char *jobvl, char *jobvr, int *n, real_t *a, int *lda,
real_t *B, int *ldb, real_t *alphar, real_t *alphai,
real_t *beta, real_t *vl, int * ldvl, real_t * vr,
int * ldvr, real_t * work, int * lwork, int* info);
// Cholesky factorizations/solves
extern "C" void
MFEM_LAPACK_PREFIX(potrf_)(char *, int *, real_t *, int *, int *);
// Solve
extern "C" void
MFEM_LAPACK_PREFIX(potrs_)(char *, int *, int *, real_t *, int *, real_t *,
int *, int *);
// Triangular Solves
extern "C" void
MFEM_LAPACK_PREFIX(trtrs_)(char *, char*, char *, int *, int *, real_t *, int *,
real_t *, int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(potri_)(char *, int *, real_t *, int*, int *);
// LAPACK routines for NNLSSolver
extern "C" void
MFEM_LAPACK_PREFIX(ormqr_)(char *, char *, int *, int *, int *, real_t *, int*,
real_t *, real_t *, int *, real_t *, int*, int*);
extern "C" void
MFEM_LAPACK_PREFIX(geqrf_)(int *, int *, real_t *, int *, real_t *, real_t *,
int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(gemv_)(char *, int *, int *, real_t *, real_t *, int *,
real_t *, int *, real_t *, real_t *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(trsm_)(char *side, char *uplo, char *transa, char *diag,
int *m, int *n, real_t *alpha, real_t *a, int *lda,
real_t *b, int *ldb);
// Complex
extern "C" void
MFEM_LAPACK_COMPLEX(getrf_)(int *, int *, std::complex<real_t> *, int *, int *,
int *);
extern "C" void
MFEM_LAPACK_COMPLEX(getrs_)(char *, int *, int *, std::complex<real_t> *, int *,
int *, std::complex<real_t> *, int *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(getri_)(int *, std::complex<real_t> *, int *, int *,
std::complex<real_t> *, int *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(trsm_)(char *, char *, char *, char *, int *, int *,
std::complex<real_t> *, std::complex<real_t> *,
int *, std::complex<real_t> *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(potrf_)(char *, int *, std::complex<real_t> *, int *,
int *);
extern "C" void
MFEM_LAPACK_COMPLEX(trtrs_)(char *, char*, char *, int *, int *,
std::complex<real_t> *, int *,
std::complex<real_t> *, int *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(potri_)(char *, int *, std::complex<real_t> *, int*, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(potrs_)(char *, int *, int *, std::complex<real_t> *, int *,
std::complex<real_t> *, int *, int *);
}
#endif
#endif
+10 -29
View File
@@ -420,9 +420,8 @@ public:
/** @brief Perform the action of the explicit part of the operator, G:
@a v = G(@a u, t) where t is the current time.
Presently, this method is used by some PETSc ODE solvers and the
SUNDIALS ARKStep integrator, for more details, see either the PETSc
Manual or the ARKode User Guide, respectively. */
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual. */
virtual void ExplicitMult(const Vector &u, Vector &v) const;
/** @brief Perform the action of the implicit part of the operator, F:
@@ -446,7 +445,7 @@ public:
Regardless of the choice of F and G, this function should always compute
@a k = inv(M) g(@a u, t). */
virtual void Mult(const Vector &u, Vector &k) const override;
virtual void Mult(const Vector &u, Vector &v) const override;
/** @brief Solve for the unknown @a k, at the current time t, the following
equation:
@@ -497,17 +496,7 @@ public:
details, see the PETSc Manual. */
virtual Operator& GetExplicitGradient(const Vector &u) const;
/** @brief Setup a linear system as needed by some SUNDIALS ODE solvers to
perform a similar action to ImplicitSolve, i.e., solve for k, at the
current time t, in F(u + gamma k, k, t) = G(u + gamma k, t).
The SUNDIALS ODE solvers iteratively solve for k, as knew = kold + dk.
The linear system here is for dk, obtained by linearizing the nonlinear
system F(u + gamma knew, knew, t) = G(u + gamma knew, t) about dk = 0:
F(u + gamma (kold + dk), kold + dk, t) = G(u + gamma (kold + dk), t)
=> [dF/dk + gamma (dF/du - dG/du)] dk = G - F + O(dk^2)
In other words, the linear system to be setup here is A dk = r, where
A = [dF/dk + gamma (dF/du - dG/du)] and r = G - F.
/** @brief Setup a linear system as needed by some SUNDIALS ODE solvers.
For solving an ordinary differential equation of the form
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined as one
@@ -517,7 +506,7 @@ public:
2. F(u,k,t) = M k and G(u,t) = g(u,t)
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
This function performs setup to solve $ A dk = r $ where A is either
This function performs setup to solve $ A x = b $ where A is either
1. A(@a y,t) = I - @a gamma inv(M) J(@a y,t)
2. A(@a y,t) = M - @a gamma J(@a y,t)
@@ -538,26 +527,18 @@ public:
virtual int SUNImplicitSetup(const Vector &y, const Vector &v,
int jok, int *jcur, real_t gamma);
/** @brief Solve the ODE linear system A @a dk = @a r , where A and r are
defined by the method SUNImplicitSetup().
/** @brief Solve the ODE linear system A @a x = @a b, where A is defined by
the method SUNImplicitSetup().
For solving an ordinary differential equation of the form
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined as one
of the following:
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
2. F(u,k,t) = M k and G(u,t) = g(u,t)
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
@param[in] r inv(M) g(y,t) - k for 1 or g(y,t) - M k for 2 & 3.
@param[in,out] dk On input, the initial guess. On output, the solution.
@param[in] b The linear system right-hand side.
@param[in,out] x On input, the initial guess. On output, the solution.
@param[in] tol Linear solve tolerance.
If not re-implemented, this method simply generates an error.
Presently, this method is used by SUNDIALS ODE solvers, for more
details, see the SUNDIALS User Guides. */
virtual int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol);
virtual int SUNImplicitSolve(const Vector &b, Vector &x, real_t tol);
/** @brief Setup the mass matrix in the ODE system
$ M \frac{dy}{dt} = g(y,t) $ .
+177 -92
View File
@@ -10,7 +10,6 @@
// CONTRIBUTING.md for details.
#include "linalg.hpp"
#include "lapack.hpp"
#include "../general/annotation.hpp"
#include "../general/forall.hpp"
#include "../general/globals.hpp"
@@ -264,7 +263,7 @@ void OperatorJacobiSmoother::SetOperator(const Operator &op)
oper = &op;
height = op.Height();
width = op.Width();
MFEM_VERIFY(height == width, "not a square matrix!");
MFEM_ASSERT(height == width, "not a square matrix!");
// ess_tdof_list is only used with BilinearForm
ess_tdof_list = nullptr;
}
@@ -305,8 +304,8 @@ void OperatorJacobiSmoother::Mult(const Vector &x, Vector &y) const
{
// For empty MPI ranks, height may be 0:
// MFEM_VERIFY(Height() > 0, "The diagonal hasn't been computed.");
MFEM_VERIFY(x.Size() == Width(), "invalid input vector");
MFEM_VERIFY(y.Size() == Height(), "invalid output vector");
MFEM_ASSERT(x.Size() == Width(), "invalid input vector");
MFEM_ASSERT(y.Size() == Height(), "invalid output vector");
if (iterative_mode)
{
@@ -592,7 +591,7 @@ void SLISolver::Mult(const Vector &b, Vector &x) const
}
initial_norm = nom0;
if (print_options.iterations || print_options.first_and_last)
if (print_options.iterations | print_options.first_and_last)
{
mfem::out << " Iteration : " << setw(3) << right << 0 << " ||Br|| = "
<< nom << (print_options.first_and_last ? " ..." : "") << '\n';
@@ -744,7 +743,7 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
}
nom0 = nom = Dot(d, r);
if (nom0 >= 0.0) { initial_norm = sqrt(nom0); }
MFEM_VERIFY(IsFinite(nom), "nom = " << nom);
MFEM_ASSERT(IsFinite(nom), "nom = " << nom);
if (print_options.iterations || print_options.first_and_last)
{
mfem::out << " Iteration : " << setw(3) << 0 << " (B r, r) = "
@@ -776,7 +775,7 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
oper->Mult(d, z); // z = A d
den = Dot(z, d);
MFEM_VERIFY(IsFinite(den), "den = " << den);
MFEM_ASSERT(IsFinite(den), "den = " << den);
if (den <= 0.0)
{
if (Dot(d, d) > 0.0 && print_options.warnings)
@@ -811,7 +810,7 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
{
betanom = Dot(r, r);
}
MFEM_VERIFY(IsFinite(betanom), "betanom = " << betanom);
MFEM_ASSERT(IsFinite(betanom), "betanom = " << betanom);
if (betanom < 0.0)
{
if (print_options.warnings)
@@ -855,7 +854,7 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
}
oper->Mult(d, z); // z = A d
den = Dot(d, z);
MFEM_VERIFY(IsFinite(den), "den = " << den);
MFEM_ASSERT(IsFinite(den), "den = " << den);
if (den <= 0.0)
{
if (Dot(d, d) > 0.0 && print_options.warnings)
@@ -1025,7 +1024,7 @@ void GMRESSolver::Mult(const Vector &b, Vector &x) const
}
}
real_t beta = initial_norm = Norm(r); // beta = ||r||
MFEM_VERIFY(IsFinite(beta), "beta = " << beta);
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
final_norm = std::max(rel_tol*beta, abs_tol);
@@ -1075,7 +1074,7 @@ void GMRESSolver::Mult(const Vector &b, Vector &x) const
}
H(i+1,i) = Norm(w); // H(i+1,i) = ||w||
MFEM_VERIFY(IsFinite(H(i+1,i)), "Norm(w) = " << H(i+1,i));
MFEM_ASSERT(IsFinite(H(i+1,i)), "Norm(w) = " << H(i+1,i));
if (v[i+1] == NULL) { v[i+1] = new Vector(n); }
v[i+1]->Set(1.0/H(i+1,i), w); // v[i+1] = w / H(i+1,i)
@@ -1089,7 +1088,7 @@ void GMRESSolver::Mult(const Vector &b, Vector &x) const
ApplyPlaneRotation(s(i), s(i+1), cs(i), sn(i));
const real_t resid = fabs(s(i+1));
MFEM_VERIFY(IsFinite(resid), "resid = " << resid);
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
if (resid <= final_norm)
{
@@ -1128,7 +1127,7 @@ void GMRESSolver::Mult(const Vector &b, Vector &x) const
subtract(b, r, r);
}
beta = Norm(r); // beta = ||r||
MFEM_VERIFY(IsFinite(beta), "beta = " << beta);
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
if (beta <= final_norm)
{
final_norm = beta;
@@ -1185,7 +1184,7 @@ void FGMRESSolver::Mult(const Vector &b, Vector &x) const
r = b;
}
real_t beta = initial_norm = Norm(r); // beta = ||r||
MFEM_VERIFY(IsFinite(beta), "beta = " << beta);
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
final_norm = std::max(rel_tol*beta, abs_tol);
@@ -1262,7 +1261,7 @@ void FGMRESSolver::Mult(const Vector &b, Vector &x) const
ApplyPlaneRotation(s(i), s(i+1), cs(i), sn(i));
const real_t resid = fabs(s(i+1));
MFEM_VERIFY(IsFinite(resid), "resid = " << resid);
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
if (print_options.iterations || (print_options.first_and_last &&
resid <= final_norm))
{
@@ -1303,7 +1302,7 @@ void FGMRESSolver::Mult(const Vector &b, Vector &x) const
oper->Mult(x, r);
subtract(b,r,r);
beta = Norm(r);
MFEM_VERIFY(IsFinite(beta), "beta = " << beta);
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
if (beta <= final_norm)
{
converged = true;
@@ -1400,7 +1399,7 @@ void BiCGSTABSolver::Mult(const Vector &b, Vector &x) const
rtilde = r;
resid = initial_norm = Norm(r);
MFEM_VERIFY(IsFinite(resid), "resid = " << resid);
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
if (print_options.iterations || print_options.first_and_last)
{
mfem::out << " Iteration : " << setw(3) << 0
@@ -1467,7 +1466,7 @@ void BiCGSTABSolver::Mult(const Vector &b, Vector &x) const
alpha = rho_1 / Dot(rtilde, v);
add(r, -alpha, v, s); // s = r - alpha * v
resid = Norm(s);
MFEM_VERIFY(IsFinite(resid), "resid = " << resid);
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
if (resid < tol_goal)
{
x.Add(alpha, phat); // x = x + alpha * phat
@@ -1507,7 +1506,7 @@ void BiCGSTABSolver::Mult(const Vector &b, Vector &x) const
rho_2 = rho_1;
resid = Norm(r);
MFEM_VERIFY(IsFinite(resid), "resid = " << resid);
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
if (print_options.iterations)
{
mfem::out << " ||r|| = " << resid << '\n';
@@ -1647,7 +1646,7 @@ void MINRESSolver::Mult(const Vector &b, Vector &x) const
prec->Mult(v1, u1);
}
eta = beta = initial_norm = sqrt(Dot(*z, v1));
MFEM_VERIFY(IsFinite(eta), "eta = " << eta);
MFEM_ASSERT(IsFinite(eta), "eta = " << eta);
gamma0 = gamma1 = 1.;
sigma0 = sigma1 = 0.;
@@ -1675,7 +1674,7 @@ void MINRESSolver::Mult(const Vector &b, Vector &x) const
}
oper->Mult(*z, q);
alpha = Dot(*z, q);
MFEM_VERIFY(IsFinite(alpha), "alpha = " << alpha);
MFEM_ASSERT(IsFinite(alpha), "alpha = " << alpha);
if (it > 1) // (v0 == 0) for (it == 1)
{
q.Add(-beta, v0);
@@ -1694,7 +1693,7 @@ void MINRESSolver::Mult(const Vector &b, Vector &x) const
prec->Mult(v0, q);
beta = sqrt(Dot(v0, q));
}
MFEM_VERIFY(IsFinite(beta), "beta = " << beta);
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
rho1 = std::hypot(delta, beta);
if (it == 1)
@@ -1720,7 +1719,7 @@ void MINRESSolver::Mult(const Vector &b, Vector &x) const
sigma1 = beta/rho1;
eta = -sigma1*eta;
MFEM_VERIFY(IsFinite(eta), "eta = " << eta);
MFEM_ASSERT(IsFinite(eta), "eta = " << eta);
if (fabs(eta) <= norm_goal)
{
@@ -1813,7 +1812,7 @@ void NewtonSolver::SetOperator(const Operator &op)
oper = &op;
height = op.Height();
width = op.Width();
MFEM_VERIFY(height == width, "square Operator is required.");
MFEM_ASSERT(height == width, "square Operator is required.");
r.SetSize(width);
c.SetSize(width);
@@ -1821,8 +1820,8 @@ void NewtonSolver::SetOperator(const Operator &op)
void NewtonSolver::Mult(const Vector &b, Vector &x) const
{
MFEM_VERIFY(oper != NULL, "the Operator is not set (use SetOperator).");
MFEM_VERIFY(prec != NULL, "the Solver is not set (use SetSolver).");
MFEM_ASSERT(oper != NULL, "the Operator is not set (use SetOperator).");
MFEM_ASSERT(prec != NULL, "the Solver is not set (use SetSolver).");
int it;
real_t norm0, norm, norm_goal;
@@ -1854,7 +1853,7 @@ void NewtonSolver::Mult(const Vector &b, Vector &x) const
// x_{i+1} = x_i - [DF(x_i)]^{-1} [F(x_i)-b]
for (it = 0; true; it++)
{
MFEM_VERIFY(IsFinite(norm), "norm = " << norm);
MFEM_ASSERT(IsFinite(norm), "norm = " << norm);
if (print_options.iterations)
{
mfem::out << "Newton iteration " << setw(2) << it
@@ -2048,7 +2047,7 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const
norm_goal = std::max(rel_tol*norm, abs_tol);
for (it = 0; true; it++)
{
MFEM_VERIFY(IsFinite(norm), "norm = " << norm);
MFEM_ASSERT(IsFinite(norm), "norm = " << norm);
if (print_options.iterations)
{
mfem::out << "LBFGS iteration " << it
@@ -2310,14 +2309,14 @@ OptimizationProblem::OptimizationProblem(const int insize,
: C(C_), D(D_), c_e(NULL), d_lo(NULL), d_hi(NULL), x_lo(NULL), x_hi(NULL),
input_size(insize)
{
if (C) { MFEM_VERIFY(C->Width() == input_size, "Wrong width of C."); }
if (D) { MFEM_VERIFY(D->Width() == input_size, "Wrong width of D."); }
if (C) { MFEM_ASSERT(C->Width() == input_size, "Wrong width of C."); }
if (D) { MFEM_ASSERT(D->Width() == input_size, "Wrong width of D."); }
}
void OptimizationProblem::SetEqualityConstraint(const Vector &c)
{
MFEM_VERIFY(C, "The C operator is unspecified -- can't set constraints.");
MFEM_VERIFY(c.Size() == C->Height(), "Wrong size of the constraint.");
MFEM_ASSERT(C, "The C operator is unspecified -- can't set constraints.");
MFEM_ASSERT(c.Size() == C->Height(), "Wrong size of the constraint.");
c_e = &c;
}
@@ -2325,8 +2324,8 @@ void OptimizationProblem::SetEqualityConstraint(const Vector &c)
void OptimizationProblem::SetInequalityConstraint(const Vector &dl,
const Vector &dh)
{
MFEM_VERIFY(D, "The D operator is unspecified -- can't set constraints.");
MFEM_VERIFY(dl.Size() == D->Height() && dh.Size() == D->Height(),
MFEM_ASSERT(D, "The D operator is unspecified -- can't set constraints.");
MFEM_ASSERT(dl.Size() == D->Height() && dh.Size() == D->Height(),
"Wrong size of the constraint.");
d_lo = &dl; d_hi = &dh;
@@ -2334,7 +2333,7 @@ void OptimizationProblem::SetInequalityConstraint(const Vector &dl,
void OptimizationProblem::SetSolutionBounds(const Vector &xl, const Vector &xh)
{
MFEM_VERIFY(xl.Size() == input_size && xh.Size() == input_size,
MFEM_ASSERT(xl.Size() == input_size && xh.Size() == input_size,
"Wrong size of the constraint.");
x_lo = &xl; x_hi = &xh;
@@ -2355,8 +2354,8 @@ void SLBQPOptimizer::SetOptimizationProblem(const OptimizationProblem &prob)
MFEM_WARNING("Objective functional is ignored as SLBQP always minimizes"
"the l2 norm of (x - x_target).");
}
MFEM_VERIFY(prob.GetC(), "Linear constraint is not set.");
MFEM_VERIFY(prob.GetC()->Height() == 1, "Solver expects scalar constraint.");
MFEM_ASSERT(prob.GetC(), "Linear constraint is not set.");
MFEM_ASSERT(prob.GetC()->Height() == 1, "Solver expects scalar constraint.");
problem = &prob;
}
@@ -2787,7 +2786,7 @@ void BlockILU::SetOperator(const Operator &op)
}
height = op.Height();
width = op.Width();
MFEM_VERIFY(A->Finalized(), "Matrix must be finalized.");
MFEM_ASSERT(A->Finalized(), "Matrix must be finalized.");
CreateBlockPattern(*A);
Factorize();
}
@@ -2998,7 +2997,7 @@ void BlockILU::Factorize()
void BlockILU::Mult(const Vector &b, Vector &x) const
{
MFEM_VERIFY(height > 0, "BlockILU(0) preconditioner is not constructed");
MFEM_ASSERT(height > 0, "BlockILU(0) preconditioner is not constructed");
int nblockrows = Height()/block_size;
y.SetSize(Height());
@@ -3293,7 +3292,7 @@ void KLUSolver::SetOperator(const Operator &op)
{
if (Numeric)
{
MFEM_VERIFY(Symbolic != 0,
MFEM_ASSERT(Symbolic != 0,
"Had Numeric pointer in KLU, but not Symbolic");
klu_free_symbolic(&Symbolic, &Common);
Symbolic = 0;
@@ -3544,6 +3543,38 @@ void AuxSpaceSmoother::Mult(const Vector &x, Vector &y, bool transpose) const
#endif // MFEM_USE_MPI
#ifdef MFEM_USE_LAPACK
// LAPACK routines for NNLSSolver
#ifdef MFEM_USE_SINGLE
extern "C" void
sormqr_(char *, char *, int *, int *, int *, float *, int*, float *,
float *, int *, float *, int*, int*);
extern "C" void
sgeqrf_(int *, int *, float *, int *, float *, float *, int *, int *);
extern "C" void
sgemv_(char *, int *, int *, float *, float *, int *, float *, int *,
float *, float *, int *);
extern "C" void
strsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n,
float *alpha, float *a, int *lda, float *b, int *ldb);
#elif defined MFEM_USE_DOUBLE
extern "C" void
dormqr_(char *, char *, int *, int *, int *, double *, int*, double *,
double *, int *, double *, int*, int*);
extern "C" void
dgeqrf_(int *, int *, double *, int *, double *, double *, int *, int *);
extern "C" void
dgemv_(char *, int *, int *, double *, double *, int *, double *, int *,
double *, double *, int *);
extern "C" void
dtrsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n,
double *alpha, double *a, int *lda, double *b, int *ldb);
#endif
NNLSSolver::NNLSSolver()
: Solver(0), mat(nullptr), const_tol_(1.0e-14), min_nnz_(0),
@@ -3907,19 +3938,25 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
lwork = -1;
work.resize(10);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &n_update,
&i_qr_start, mat_qr_data.GetData(), &m,
tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m),
&m, work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T A update work calculation failed
lwork = static_cast<int>(work[0]);
work.resize(lwork);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &n_update,
&i_qr_start, mat_qr_data.GetData(), &m,
tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m),
&m, work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T A update failed
// Compute QR factorization of the submatrix
lwork = -1;
@@ -3940,16 +3977,24 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
sub_tau[j] = tau[i_qr_start + j];
}
MFEM_LAPACK_PREFIX(geqrf_)(&m_update, &n_update, submat_data.GetData(),
&m_update, sub_tau.GetData(), work.data(),
&lwork, &info);
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m_update, &n_update,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m_update, &n_update,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR update factorization work calc
lwork = static_cast<int>(work[0]);
if (lwork == 0) { lwork = 1; }
work.resize(lwork);
MFEM_LAPACK_PREFIX(geqrf_)(&m_update, &n_update, submat_data.GetData(),
&m_update, sub_tau.GetData(), work.data(),
&lwork, &info);
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m_update, &n_update,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m_update, &n_update,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR update factorization failed
// Copy result back
@@ -3978,13 +4023,23 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
// perform qr)
lwork = -1;
work.resize(10);
MFEM_LAPACK_PREFIX(geqrf_)(&m, &n_glob, mat_qr_data.GetData(), &m,
tau.GetData(), work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m, &n_glob,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR factorization work calculation
lwork = static_cast<int>(work[0]);
work.resize(lwork);
MFEM_LAPACK_PREFIX(geqrf_)(&m, &n_glob, mat_qr_data.GetData(), &m,
tau.GetData(), work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m, &n_glob,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR factorization failed
}
@@ -4012,17 +4067,25 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
sub_tau[0] = tau[i_qr_start];
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m_update, &ione, &ione,
submat_data.GetData(), &m_update,
sub_tau.GetData(), sub_qt.GetData(),
&m_update, work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m_update, &ione, &ione,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m_update, &ione, &ione,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
sub_qt.GetData(), &m_update,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // H_last y work calculation failed
lwork = static_cast<int>(work[0]);
work.resize(lwork);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m_update, &ione, &ione,
submat_data.GetData(), &m_update,
sub_tau.GetData(), sub_qt.GetData(),
&m_update, work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m_update, &ione, &ione,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m_update, &ione, &ione,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
sub_qt.GetData(), &m_update,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // H_last y failed
// Copy result back
for (int i=0; i<m_update; ++i)
@@ -4036,17 +4099,25 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
qt_rhs_glob = rhs_avg_glob;
lwork = -1;
work.resize(10);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &ione, &n_glob,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &ione, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T b work calculation failed
lwork = static_cast<int>(work[0]);
work.resize(lwork);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &ione, &n_glob,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &ione, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T b failed
}
@@ -4059,10 +4130,14 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
char upper = 'U';
char nounit = 'N';
vec1 = qt_rhs_glob;
MFEM_LAPACK_PREFIX(trsm_)(&lside, &upper, &notrans, &nounit,
&n_glob, &ione, &fone,
mat_qr_data.GetData(), &m,
vec1.GetData(), &n_glob);
#ifdef MFEM_USE_SINGLE
strsm_(&lside, &upper, &notrans, &nounit,
#elif defined MFEM_USE_DOUBLE
dtrsm_(&lside, &upper, &notrans, &nounit,
#endif
&n_glob, &ione, &fone,
mat_qr_data.GetData(), &m,
vec1.GetData(), &n_glob);
if (verbosity_ > 2)
{
@@ -4285,10 +4360,14 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
{
res_glob = rhs_avg_glob;
real_t fmone = -1.0;
MFEM_LAPACK_PREFIX(gemv_)(&notrans, &m, &n_glob, &fmone,
mat_0_data.GetData(), &m,
soln_nz_glob.GetData(), &ione, &fone,
res_glob.GetData(), &ione);
#ifdef MFEM_USE_SINGLE
sgemv_(&notrans, &m, &n_glob, &fmone,
#elif defined MFEM_USE_DOUBLE
dgemv_(&notrans, &m, &n_glob, &fmone,
#endif
mat_0_data.GetData(), &m,
soln_nz_glob.GetData(), &ione, &fone,
res_glob.GetData(), &ione);
}
else
{
@@ -4302,18 +4381,24 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
qqt_rhs_glob(i) = qt_rhs_glob(i);
}
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &notrans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m,
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#endif
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q Q^T b work calculation failed.
lwork = static_cast<int>(work[0]);
work.resize(lwork);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &notrans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m,
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#endif
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q Q^T b calculation failed.
res_glob = rhs_avg_glob;
res_glob -= qqt_rhs_glob;
+11 -74
View File
@@ -1267,32 +1267,24 @@ real_t SparseMatrix::InnerProduct(const Vector &x, const Vector &y) const
void SparseMatrix::GetRowSums(Vector &x) const
{
if (Finalized())
for (int i = 0; i < height; i++)
{
auto d_I = ReadI();
auto d_A = ReadData();
auto d_x = x.Write();
mfem::forall(height, [=] MFEM_HOST_DEVICE (int i)
real_t a = 0.0;
if (A)
{
real_t sum = 0.0;
for (int j = d_I[i], end = d_I[i+1]; j < end; j++)
for (int j = I[i], end = I[i+1]; j < end; j++)
{
sum += d_A[j];
a += A[j];
}
d_x[i] = sum;
});
}
else
{
for (int i = 0; i < height; i++)
}
else
{
real_t a = 0.0;
for (RowNode *np = Rows[i]; np != NULL; np = np->Prev)
{
a += np->Value;
}
x(i) = a;
}
x(i) = a;
}
}
@@ -3308,7 +3300,7 @@ void SparseMatrix::Print(std::ostream & os, int width_) const
{
int i, j;
if (A.Empty())
if (A == NULL)
{
RowNode *nd;
for (i = 0; i < height; i++)
@@ -3362,7 +3354,7 @@ void SparseMatrix::PrintMatlab(std::ostream & os) const
os.setf(ios::scientific);
std::streamsize old_prec = os.precision(14);
if (A.Empty())
if (A == NULL)
{
RowNode *nd;
for (i = 0; i < height; i++)
@@ -3393,61 +3385,6 @@ void SparseMatrix::PrintMatlab(std::ostream & os) const
os.flags(old_fmt);
}
void SparseMatrix::PrintMathematica(std::ostream & os) const
{
int i, j;
ios::fmtflags old_fmt = os.flags();
os.setf(ios::scientific);
std::streamsize old_prec = os.precision(14);
os << "(* Read file into Mathematica using: "
<< "my_mat = Get[\"this_file_name\"] *)\n";
os << "SparseArray[";
if (A == NULL)
{
RowNode *nd;
int c = 0;
os << "{\n";
for (i = 0; i < height; i++)
{
for (nd = Rows[i], j = 0; nd != NULL; nd = nd->Prev, j++, c++)
{
os << "{"<< i+1 << ", " << nd->Column+1
<< "} -> Internal`StringToMReal[\"" << nd->Value << "\"]";
if (c < NumNonZeroElems() - 1) { os << ","; }
os << '\n';
}
}
os << "}\n";
}
else
{
// HostRead forces synchronization
HostReadI();
HostReadJ();
HostReadData();
int c = 0;
os << "{\n";
for (i = 0; i < height; i++)
{
for (j = I[i]; j < I[i+1]; j++, c++)
{
os << "{" << i+1 << ", " << J[j]+1
<< "} -> Internal`StringToMReal[\"" << A[j] << "\"]";
if (c < NumNonZeroElems() - 1) { os << ","; }
os << '\n';
}
}
os << "}";
}
os << ",{" << height << "," << width << "}]\n";
os.precision(old_prec);
os.flags(old_fmt);
}
void SparseMatrix::PrintMM(std::ostream & os) const
{
int i, j;
@@ -3460,7 +3397,7 @@ void SparseMatrix::PrintMM(std::ostream & os) const
os << height << " " << width << " " << NumNonZeroElems() << '\n';
if (A.Empty())
if (A == NULL)
{
RowNode *nd;
for (i = 0; i < height; i++)
+1 -14
View File
@@ -216,7 +216,7 @@ public:
void ClearCuSparse() { ClearGPUSparse(); }
/// Check if the SparseMatrix is empty.
bool Empty() const { return A.Empty() && (Rows == NULL); }
bool Empty() const { return (A == NULL) && (Rows == NULL); }
/// Return the array #I.
inline int *GetI() { return I; }
@@ -657,19 +657,6 @@ public:
/** @note The host in synchronized when the finalized matrix is on the device. */
virtual void PrintMatlab(std::ostream &out = mfem::out) const;
/// Prints matrix as a SparseArray for importing into Mathematica.
/** The resulting file can be read into Mathematica using an expression such
as: my_mat = Get["output_file_name"]
The Mathematica variable "my_mat" will then be assigned to a new
SparseArray object containing the data from this MFEM SparseMatrix.
@note Mathematica uses 1-based indexing so the MFEM row and column
indices will be sifted up by one in the Mathematica output.
@note The host in synchronized when the finalized matrix is on the
device. */
virtual void PrintMathematica(std::ostream &out = mfem::out) const;
/// Prints matrix in Matrix Market sparse format.
/** @note The host in synchronized when the finalized matrix is on the device. */
void PrintMM(std::ostream &out = mfem::out) const;
+10 -37
View File
@@ -1341,59 +1341,38 @@ CVODESSolver::~CVODESSolver()
// ARKStep interface
// ---------------------------------------------------------------------------
int ARKStepSolver::RHS1(realtype t, const N_Vector y, N_Vector result,
int ARKStepSolver::RHS1(realtype t, const N_Vector y, N_Vector ydot,
void *user_data)
{
// Get data from N_Vectors
const SundialsNVector mfem_y(y);
SundialsNVector mfem_result(result);
SundialsNVector mfem_ydot(ydot);
ARKStepSolver *self = static_cast<ARKStepSolver*>(user_data);
// Compute either f(t, y) in one of
// 1. y' = f(t, y)
// 2. M y' = f(t, y)
// or fe(t, y) in one of
// 1. y' = fe(t, y) + fi(t, y)
// 2. M y' = fe(t, y) + fi(t, y)
// Compute f(t, y) in y' = f(t, y) or fe(t, y) in y' = fe(t, y) + fi(t, y)
self->f->SetTime(t);
if (self->rk_type == IMEX)
{
self->f->SetEvalMode(TimeDependentOperator::ADDITIVE_TERM_1);
}
if (self->f->isExplicit()) // ODE is in form 1
{
self->f->Mult(mfem_y, mfem_result);
}
else // ODE is in form 2
{
self->f->ExplicitMult(mfem_y, mfem_result);
}
self->f->Mult(mfem_y, mfem_ydot);
// Return success
return (0);
}
int ARKStepSolver::RHS2(realtype t, const N_Vector y, N_Vector result,
int ARKStepSolver::RHS2(realtype t, const N_Vector y, N_Vector ydot,
void *user_data)
{
// Get data from N_Vectors
const SundialsNVector mfem_y(y);
SundialsNVector mfem_result(result);
SundialsNVector mfem_ydot(ydot);
ARKStepSolver *self = static_cast<ARKStepSolver*>(user_data);
// Compute fi(t, y) in one of
// 1. y' = fe(t, y) + fi(t, y) (ODE is expressed in EXPLICIT form)
// 2. M y' = fe(t, y) + fi(y, t) (ODE is expressed in IMPLICIT form)
// Compute fi(t, y) in y' = fe(t, y) + fi(t, y)
self->f->SetTime(t);
self->f->SetEvalMode(TimeDependentOperator::ADDITIVE_TERM_2);
if (self->f->isExplicit())
{
self->f->Mult(mfem_y, mfem_result);
}
else
{
self->f->ExplicitMult(mfem_y, mfem_result);
}
self->f->Mult(mfem_y, mfem_ydot);
// Return success
return (0);
@@ -1588,7 +1567,7 @@ void ARKStepSolver::Init(TimeDependentOperator &f_)
reinit = true;
}
void ARKStepSolver::Step(Vector &x, real_t &t, real_t &dt)
void ARKStepSolver::Step(Vector &x, double &t, double &dt)
{
Y->MakeRef(x, 0, x.Size());
MFEM_VERIFY(Y->Size() == x.Size(), "size mismatch");
@@ -1687,7 +1666,7 @@ void ARKStepSolver::UseMFEMMassLinearSolver(int tdep)
LSM->content = this;
LSM->ops->gettype = LSGetType;
LSM->ops->solve = ARKStepSolver::MassSysSolve;
LSM->ops->free = LSFree;
LSA->ops->free = LSFree;
M = SUNMatNewEmpty(Sundials::GetContext());
MFEM_VERIFY(M, "error in SUNMatNewEmpty()");
@@ -1704,9 +1683,6 @@ void ARKStepSolver::UseMFEMMassLinearSolver(int tdep)
// Set the linear system function
flag = ARKStepSetMassFn(sundials_mem, ARKStepSolver::MassSysSetup);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassFn()");
// Check that the ODE is not expressed in EXPLICIT form
MFEM_VERIFY(!f->isExplicit(), "ODE operator is expressed in EXPLICIT form")
}
void ARKStepSolver::UseSundialsMassLinearSolver(int tdep)
@@ -1727,9 +1703,6 @@ void ARKStepSolver::UseSundialsMassLinearSolver(int tdep)
flag = ARKStepSetMassTimes(sundials_mem, NULL, ARKStepSolver::MassMult2,
this);
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassTimes()");
// Check that the ODE is not expressed in EXPLICIT form
MFEM_VERIFY(!f->isExplicit(), "ODE operator is expressed in EXPLICIT form")
}
void ARKStepSolver::SetStepMode(int itask)
+1 -1
View File
@@ -763,7 +763,7 @@ public:
@note On input, the values of @a t and @a dt are used to compute desired
output time for the integration, tout = @a t + @a dt.
*/
virtual void Step(Vector &x, real_t &t, real_t &dt) override;
virtual void Step(Vector &x, double &t, double &dt);
/** @brief Attach the linear system setup and solve methods from the
TimeDependentOperator i.e., SUNImplicitSetup() and SUNImplicitSolve() to
+27 -52
View File
@@ -193,8 +193,7 @@ endif
# Compile flags used by MFEM: CPPFLAGS, CXXFLAGS, plus library flags
INCFLAGS =
# Link flags used by MFEM: library link flags plus LDFLAGS and LDFLAGS_INTERNAL
# (added at the end)
# Link flags used by MFEM: library link flags plus LDFLAGS (added last)
ALL_LIBS =
# Building static and/or shared libraries:
@@ -373,7 +372,7 @@ MFEM_TPLFLAGS ?= $(INCFLAGS)
MFEM_INCFLAGS ?= -I@MFEM_INC_DIR@ @MFEM_TPLFLAGS@
MFEM_PICFLAG ?= $(if $(shared),$(PICFLAG))
MFEM_FLAGS ?= @MFEM_CPPFLAGS@ @MFEM_CXXFLAGS@ @MFEM_INCFLAGS@
MFEM_EXT_LIBS ?= $(ALL_LIBS) $(LDFLAGS) $(LDFLAGS_INTERNAL)
MFEM_EXT_LIBS ?= $(ALL_LIBS) $(LDFLAGS)
MFEM_LIBS ?= $(if $(shared),$(BUILD_RPATH)) -L@MFEM_LIB_DIR@ -lmfem\
@MFEM_EXT_LIBS@
MFEM_LIB_FILE ?= @MFEM_LIB_DIR@/libmfem.$(if $(shared),$(SO_VER),a)
@@ -582,77 +581,53 @@ clean: $(addsuffix /clean,$(EM_DIRS) $(TEST_DIRS))
distclean: clean config/clean doc/clean
rm -rf mfem/
# User-definable install permissions.
# Install permissions for everything except directories and binaries:
INSTALL_DEF_PERM ?= 644
# Install permissions for binaries:
INSTALL_BIN_PERM ?= 755
# Install permissions for directories (and symlinks on macOS/BSD):
INSTALL_DIR_PERM ?= 755
# Shortcuts, not to be modified by the user on the command line.
# We use 'umask' because 'mkdir -p' (and 'install -d') do not use the mode
# specified with the '-m' flag when creating non-existent parent directories.
# WARNING: $(MKINSTALLDIR) changes the umask for commands following it as part
# of the same shell expression unless it is placed inside '()' to be
# executed in a sub-shell.
override INSTALLDEF = $(INSTALL) -m $(INSTALL_DEF_PERM)
override INSTALLMASK = $(shell printf "%o" $$((~0$(INSTALL_DIR_PERM) & 0777)))
override MKINSTALLDIR = umask $(INSTALLMASK) && mkdir -p
INSTALL_SHARED_LIB = $(MFEM_CXX) $(MFEM_LINK_FLAGS) $(INSTALL_SOFLAGS)\
$(OBJECT_FILES) $(EXT_LIBS) -o $(PREFIX_LIB)/libmfem.$(SO_VER) && \
cd $(PREFIX_LIB) && chmod $(INSTALL_BIN_PERM) libmfem.$(SO_VER) && \
( umask $(INSTALLMASK) && ln -sf libmfem.$(SO_VER) libmfem.$(SO_EXT) )
cd $(PREFIX_LIB) && ln -sf libmfem.$(SO_VER) libmfem.$(SO_EXT)
install: $(if $(static),$(BLD)libmfem.a) $(if $(shared),$(BLD)libmfem.$(SO_EXT))
$(MKINSTALLDIR) $(PREFIX_LIB)
mkdir -p $(PREFIX_LIB)
# install static and/or shared library
$(if $(static),$(INSTALLDEF) $(BLD)libmfem.a $(PREFIX_LIB))
$(if $(static),$(INSTALL) -m 640 $(BLD)libmfem.a $(PREFIX_LIB))
$(if $(shared),$(INSTALL_SHARED_LIB))
# install top level includes
$(MKINSTALLDIR) $(PREFIX_INC)/mfem
$(INSTALLDEF) $(SRC)mfem.hpp $(SRC)mfem-performance.hpp \
mkdir -p $(PREFIX_INC)/mfem
$(INSTALL) -m 640 $(SRC)mfem.hpp $(SRC)mfem-performance.hpp \
$(PREFIX_INC)/mfem
for hdr in mfem.hpp mfem-performance.hpp; do \
printf '// Auto-generated file.\n#include "mfem/'$$hdr'"\n' \
> $(PREFIX_INC)/$$hdr && \
chmod $(INSTALL_DEF_PERM) $(PREFIX_INC)/$$hdr; done
> $(PREFIX_INC)/$$hdr && chmod 640 $(PREFIX_INC)/$$hdr; done
# install config include
$(MKINSTALLDIR) $(PREFIX_INC)/mfem/config
$(INSTALLDEF) $(BLD)config/_config.hpp $(PREFIX_INC)/mfem/config
$(INSTALLDEF) $(SRC)config/config.hpp $(PREFIX_INC)/mfem/config
$(INSTALLDEF) $(SRC)config/tconfig.hpp $(PREFIX_INC)/mfem/config
mkdir -p $(PREFIX_INC)/mfem/config
$(INSTALL) -m 640 $(BLD)config/_config.hpp $(PREFIX_INC)/mfem/config/_config.hpp
$(INSTALL) -m 640 $(SRC)config/config.hpp $(PREFIX_INC)/mfem/config/config.hpp
$(INSTALL) -m 640 $(SRC)config/tconfig.hpp $(PREFIX_INC)/mfem/config
# install remaining includes in each subdirectory
for dir in $(DIRS); do \
( $(MKINSTALLDIR) $(PREFIX_INC)/mfem/$$dir ) && \
$(INSTALLDEF) $(SRC)$$dir/*.hpp $(PREFIX_INC)/mfem/$$dir; \
mkdir -p $(PREFIX_INC)/mfem/$$dir && \
$(INSTALL) -m 640 $(SRC)$$dir/*.hpp $(PREFIX_INC)/mfem/$$dir; \
done
# install *.okl files
for dir in $(OKL_DIRS); do \
( $(MKINSTALLDIR) $(PREFIX_INC)/mfem/$$dir ) && \
$(INSTALLDEF) $(SRC)$$dir/*.okl $(PREFIX_INC)/mfem/$$dir; \
mkdir -p $(PREFIX_INC)/mfem/$$dir && \
$(INSTALL) -m 640 $(SRC)$$dir/*.okl $(PREFIX_INC)/mfem/$$dir; \
done
# install libCEED q-function headers
$(MKINSTALLDIR) $(PREFIX_INC)/mfem/fem/ceed/integrators/mass
$(INSTALLDEF) $(SRC)fem/ceed/integrators/mass/*.h \
$(PREFIX_INC)/mfem/fem/ceed/integrators/mass
$(MKINSTALLDIR) $(PREFIX_INC)/mfem/fem/ceed/integrators/convection
$(INSTALLDEF) $(SRC)fem/ceed/integrators/convection/*.h \
$(PREFIX_INC)/mfem/fem/ceed/integrators/convection
$(MKINSTALLDIR) $(PREFIX_INC)/mfem/fem/ceed/integrators/diffusion
$(INSTALLDEF) $(SRC)fem/ceed/integrators/diffusion/*.h \
$(PREFIX_INC)/mfem/fem/ceed/integrators/diffusion
$(MKINSTALLDIR) $(PREFIX_INC)/mfem/fem/ceed/integrators/nlconvection
$(INSTALLDEF) $(SRC)fem/ceed/integrators/nlconvection/*.h \
$(PREFIX_INC)/mfem/fem/ceed/integrators/nlconvection
mkdir -p $(PREFIX_INC)/mfem/fem/ceed/integrators/mass
$(INSTALL) -m 640 $(SRC)fem/ceed/integrators/mass/*.h $(PREFIX_INC)/mfem/fem/ceed/integrators/mass
mkdir -p $(PREFIX_INC)/mfem/fem/ceed/integrators/convection
$(INSTALL) -m 640 $(SRC)fem/ceed/integrators/convection/*.h $(PREFIX_INC)/mfem/fem/ceed/integrators/convection
mkdir -p $(PREFIX_INC)/mfem/fem/ceed/integrators/diffusion
$(INSTALL) -m 640 $(SRC)fem/ceed/integrators/diffusion/*.h $(PREFIX_INC)/mfem/fem/ceed/integrators/diffusion
mkdir -p $(PREFIX_INC)/mfem/fem/ceed/integrators/nlconvection
$(INSTALL) -m 640 $(SRC)fem/ceed/integrators/nlconvection/*.h $(PREFIX_INC)/mfem/fem/ceed/integrators/nlconvection
# install config.mk in $(PREFIX_SHARE)
$(MKINSTALLDIR) $(PREFIX_SHARE)
mkdir -p $(PREFIX_SHARE)
$(MAKE) -C $(BLD)config config-mk CONFIG_MK=config-install.mk
$(INSTALLDEF) $(BLD)config/config-install.mk $(PREFIX_SHARE)/config.mk
$(INSTALL) -m 640 $(BLD)config/config-install.mk $(PREFIX_SHARE)/config.mk
rm -f $(BLD)config/config-install.mk
# install test.mk in $(PREFIX_SHARE)
$(INSTALLDEF) $(SRC)config/test.mk $(PREFIX_SHARE)
$(INSTALL) -m 640 $(SRC)config/test.mk $(PREFIX_SHARE)/test.mk
$(CONFIG_MK):
# Skip the error message when '-B' make flag is used (unconditionally
-1
View File
@@ -12,7 +12,6 @@
set(SRCS
attribute_sets.cpp
element.cpp
exodus_writer.cpp
face_nbr_geom.cpp
gmsh.cpp
hexahedron.cpp
File diff suppressed because it is too large Load Diff
+16 -49
View File
@@ -466,8 +466,7 @@ void Mesh::GetBdrElementTransformation(int i,
{
for (int j = 0; j < n; j++)
{
int idx = vdofs[n*k+j];
pm(k,j) = nodes((idx<0)? -1-idx:idx);
pm(k,j) = nodes(vdofs[n*k+j]);
}
}
ElTr->SetFE(bdr_el);
@@ -7132,15 +7131,17 @@ Table *Mesh::GetEdgeVertexTable() const
Table *Mesh::GetVertexToElementTable()
{
int i, j, nv, *v;
Table *vert_elem = new Table;
vert_elem->MakeI(NumOfVertices);
for (int i = 0; i < NumOfElements; i++)
for (i = 0; i < NumOfElements; i++)
{
const int nv = elements[i]->GetNVertices();
const int *v = elements[i]->GetVertices();
for (int j = 0; j < nv; j++)
nv = elements[i]->GetNVertices();
v = elements[i]->GetVertices();
for (j = 0; j < nv; j++)
{
vert_elem->AddAColumnInRow(v[j]);
}
@@ -7148,11 +7149,11 @@ Table *Mesh::GetVertexToElementTable()
vert_elem->MakeJ();
for (int i = 0; i < NumOfElements; i++)
for (i = 0; i < NumOfElements; i++)
{
const int nv = elements[i]->GetNVertices();
const int *v = elements[i]->GetVertices();
for (int j = 0; j < nv; j++)
nv = elements[i]->GetNVertices();
v = elements[i]->GetVertices();
for (j = 0; j < nv; j++)
{
vert_elem->AddConnection(v[j], i);
}
@@ -7163,39 +7164,6 @@ Table *Mesh::GetVertexToElementTable()
return vert_elem;
}
Table *Mesh::GetVertexToBdrElementTable()
{
Table *vert_bdr_elem = new Table;
vert_bdr_elem->MakeI(NumOfVertices);
for (int i = 0; i < NumOfBdrElements; i++)
{
const int nv = boundary[i]->GetNVertices();
const int *v = boundary[i]->GetVertices();
for (int j = 0; j < nv; j++)
{
vert_bdr_elem->AddAColumnInRow(v[j]);
}
}
vert_bdr_elem->MakeJ();
for (int i = 0; i < NumOfBdrElements; i++)
{
const int nv = boundary[i]->GetNVertices();
const int *v = boundary[i]->GetVertices();
for (int j = 0; j < nv; j++)
{
vert_bdr_elem->AddConnection(v[j], i);
}
}
vert_bdr_elem->ShiftUpI();
return vert_bdr_elem;
}
Table *Mesh::GetFaceToElementTable() const
{
Table *face_elem = new Table;
@@ -13632,23 +13600,22 @@ Mesh &MeshPart::GetMesh()
MeshPartitioner::MeshPartitioner(Mesh &mesh_,
int num_parts_,
const int *partitioning_,
int *partitioning_,
int part_method)
: mesh(mesh_)
{
if (partitioning_)
{
partitioning.MakeRef(const_cast<int *>(partitioning_), mesh.GetNE(),
false);
partitioning.MakeRef(partitioning_, mesh.GetNE(), false);
}
else
{
partitioning_ = mesh.GeneratePartitioning(num_parts_, part_method);
// Mesh::GeneratePartitioning always uses new[] to allocate the,
// partitioning, so we need to tell the memory manager to free it with
// delete[] (even if a different host memory type has been selected).
constexpr MemoryType mt = MemoryType::HOST;
partitioning.MakeRef(mesh.GeneratePartitioning(num_parts_, part_method),
mesh.GetNE(), mt, true);
const MemoryType mt = MemoryType::HOST;
partitioning.MakeRef(partitioning_, mesh.GetNE(), mt, true);
}
Transpose(partitioning, part_to_element, num_parts_);
+2 -10
View File
@@ -1537,9 +1537,6 @@ public:
/// @note The returned Table should be deleted by the caller
Table *GetVertexToElementTable();
/// @note The returned Table should be deleted by the caller
Table *GetVertexToBdrElementTable();
/// Return the "face"-element Table. Here "face" refers to face (3D),
/// edge (2D), or vertex (1D).
///
@@ -2334,11 +2331,6 @@ public:
bool high_order_output=false,
int compression_level=0);
#ifdef MFEM_USE_NETCDF
/// @brief Export a mesh to an Exodus II file.
void PrintExodusII(const std::string fpath);
#endif
/** @brief Prints the mesh with boundary elements given by the boundary of
the subdomains, so that the boundary of subdomain i has boundary
attribute i+1. */
@@ -2736,8 +2728,8 @@ public:
Mesh::GeneratePartitioning() when the provided
input partitioning is NULL.
*/
MeshPartitioner(Mesh &mesh_, int num_parts_,
const int *partitioning_ = nullptr, int part_method = 1);
MeshPartitioner(Mesh &mesh_, int num_parts_, int *partitioning_ = NULL,
int part_method = 1);
/** @brief Construct a MeshPart corresponding to the given @a part_id.
+30 -109
View File
@@ -1857,7 +1857,7 @@ NURBSPatch *Revolve3D(NURBSPatch &patch, real_t n[], real_t ang, int times)
{
if (patch.Dim != 4)
{
mfem_error("Revolve3D(NURBSPatch &, real_t [], real_t)");
mfem_error("Revolve3D(NURBSPatch &, double [], double)");
}
int size = 1, ns;
@@ -2008,23 +2008,23 @@ NURBSExtension::NURBSExtension(std::istream &input, bool spacing)
input >> numSpacing;
for (int j = 0; j < numSpacing; j++)
{
int ki, spacingType, numIntParam, numRealParam;
input >> ki >> spacingType >> numIntParam >> numRealParam;
int ki, spacingType, numIntParam, numDoubleParam;
input >> ki >> spacingType >> numIntParam >> numDoubleParam;
MFEM_VERIFY(0 <= ki && ki < NumOfKnotVectors,
"Invalid knotvector index");
MFEM_VERIFY(numIntParam >= 0 && numRealParam >= 0,
MFEM_VERIFY(numIntParam >= 0 && numDoubleParam >= 0,
"Invalid number of parameters in KnotVector");
Array<int> ipar(numIntParam);
Vector dpar(numRealParam);
Vector dpar(numDoubleParam);
for (int i=0; i<numIntParam; ++i)
{
input >> ipar[i];
}
for (int i=0; i<numRealParam; ++i)
for (int i=0; i<numDoubleParam; ++i)
{
input >> dpar[i];
}
@@ -2064,7 +2064,7 @@ NURBSExtension::NURBSExtension(std::istream &input, bool spacing)
new KnotVector(*patches[p]->GetKV(0));
}
}
else if (Dimension() == 2)
if (Dimension() == 2)
{
patchTopo->GetElementEdges(p, edges, oedge);
if (knotVectors[KnotInd(edges[0])] == NULL)
@@ -2230,8 +2230,7 @@ NURBSExtension::NURBSExtension(NURBSExtension *parent, int newOrder)
}
NURBSExtension::NURBSExtension(NURBSExtension *parent,
const Array<int> &newOrders, Mode mode)
: mode(mode)
const Array<int> &newOrders)
{
newOrders.Copy(mOrders);
SetOrderFromOrders();
@@ -3892,16 +3891,7 @@ void NURBSExtension::GenerateBdrElementDofTable()
int ndof = bel_dof->Size_of_connections();
for (int i = 0; i < ndof; i++)
{
int idx = dof[i];
if (idx < 0)
{
dof[i] = -1 - (activeDof[-1-idx] - 1);
dof[i] = -activeDof[-1-idx];
}
else
{
dof[i] = activeDof[idx] - 1;
}
dof[i] = activeDof[dof[i]] - 1;
}
}
@@ -3953,22 +3943,6 @@ void NURBSExtension::Generate2DBdrElementDofTable()
// Load dofs
const int nks0 = kv[0]->GetNKS();
const int ord0 = kv[0]->GetOrder();
bool add_dofs = true;
int s = 1;
if (mode == Mode::H_DIV)
{
int fn = patchTopo->GetBdrElementFaceIndex(b);
if (ord0 == mOrders.Max()) { add_dofs = false; }
if (fn == 0) { s = -1; }
if (fn == 2) { s = -1; }
}
else if (mode == Mode::H_CURL)
{
if (ord0 == mOrders.Max()) { add_dofs = false; }
}
for (int i = 0; i < nks0; i++)
{
if (kv[0]->isElement(i))
@@ -3976,14 +3950,10 @@ void NURBSExtension::Generate2DBdrElementDofTable()
if (activeBdrElem[gbe])
{
Connection conn(lbe,0);
if (add_dofs)
for (int ii = 0; ii <= ord0; ii++)
{
for (int ii = 0; ii <= ord0; ii++)
{
conn.to = DofMap(p2g[(okv[0] >= 0) ? (i+ii) : (nx-i-ii)]);
if (s == -1) { conn.to = -1 -conn.to; }
bel_dof_list.Append(conn);
}
conn.to = DofMap(p2g[(okv[0] >= 0) ? (i+ii) : (nx-i-ii)]);
bel_dof_list.Append(conn);
}
bel_to_patch[lbe] = b;
bel_to_IJK(lbe,0) = (okv[0] >= 0) ? i : (-1-i);
@@ -4020,25 +3990,6 @@ void NURBSExtension::Generate3DBdrElementDofTable()
const int ord0 = kv[0]->GetOrder();
const int nks1 = kv[1]->GetNKS();
const int ord1 = kv[1]->GetOrder();
// Check if dofs are actually defined on boundary
bool add_dofs = true;
int s = 1;
if (mode == Mode::H_DIV)
{
int fn = patchTopo->GetBdrElementFaceIndex(b);
if (ord0 != ord1) { add_dofs = false; }
if (fn == 4) { s = -1; }
if (fn == 1) { s = -1; }
if (fn == 0) { s = -1; }
}
else if (mode == Mode::H_CURL)
{
if (ord0 == ord1) { add_dofs = false; }
}
for (int j = 0; j < nks1; j++)
{
if (kv[1]->isElement(j))
@@ -4050,18 +4001,14 @@ void NURBSExtension::Generate3DBdrElementDofTable()
if (activeBdrElem[gbe])
{
Connection conn(lbe,0);
if (add_dofs)
for (int jj = 0; jj <= ord1; jj++)
{
for (int jj = 0; jj <= ord1; jj++)
const int jj_ = (okv[1] >= 0) ? (j+jj) : (ny-j-jj);
for (int ii = 0; ii <= ord0; ii++)
{
const int jj_ = (okv[1] >= 0) ? (j+jj) : (ny-j-jj);
for (int ii = 0; ii <= ord0; ii++)
{
const int ii_ = (okv[0] >= 0) ? (i+ii) : (nx-i-ii);
conn.to = DofMap(p2g(ii_, jj_));
if (s == -1) { conn.to = -1 -conn.to; }
bel_dof_list.Append(conn);
}
const int ii_ = (okv[0] >= 0) ? (i+ii) : (nx-i-ii);
conn.to = DofMap(p2g(ii_, jj_));
bel_dof_list.Append(conn);
}
}
bel_to_patch[lbe] = b;
@@ -4294,38 +4241,6 @@ void NURBSExtension::DegreeElevate(int rel_degree, int degree)
}
}
NURBSExtension* NURBSExtension::GetDivExtension(int component)
{
// Smarter routine
if (GetNP() > 1)
{
mfem_error("NURBSExtension::GetDivExtension currently "
"only works for single patch NURBS meshes ");
}
Array<int> newOrders = GetOrders();
newOrders[component] += 1;
return new NURBSExtension(this, newOrders, Mode::H_DIV);
}
NURBSExtension* NURBSExtension::GetCurlExtension(int component)
{
// Smarter routine
if (GetNP() > 1)
{
mfem_error("NURBSExtension::GetCurlExtension currently "
"only works for single patch NURBS meshes ");
}
Array<int> newOrders = GetOrders();
for (int c = 0; c < newOrders.Size(); c++) { newOrders[c]++; }
newOrders[component] -= 1;
return new NURBSExtension(this, newOrders, Mode::H_CURL);
}
void NURBSExtension::UniformRefinement(Array<int> const& rf)
{
for (int p = 0; p < patches.Size(); p++)
@@ -4807,15 +4722,19 @@ const Array<int>& NURBSExtension::GetPatchBdrElements(int patch)
#ifdef MFEM_USE_MPI
ParNURBSExtension::ParNURBSExtension(const ParNURBSExtension &orig)
: NURBSExtension(orig),
partitioning(orig.partitioning),
partitioning(orig.partitioning ? new int[orig.GetGNE()] : NULL),
gtopo(orig.gtopo),
ldof_group(orig.ldof_group)
{
// Copy the partitioning, if not NULL
if (partitioning)
{
std::memcpy(partitioning, orig.partitioning, orig.GetGNE()*sizeof(int));
}
}
ParNURBSExtension::ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent,
const int *partitioning_,
const Array<bool> &active_bel)
int *part, const Array<bool> &active_bel)
: gtopo(comm)
{
if (parent->NumOfActiveElems < parent->NumOfElements)
@@ -4853,11 +4772,11 @@ ParNURBSExtension::ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent,
CountElements();
CountBdrElements();
// copy 'partitioning_' to 'partitioning'
partitioning.SetSize(GetGNE());
// copy 'part' to 'partitioning'
partitioning = new int[GetGNE()];
for (int i = 0; i < GetGNE(); i++)
{
partitioning[i] = partitioning_[i];
partitioning[i] = part[i];
}
SetActive(partitioning, active_bel);
@@ -4948,6 +4867,8 @@ ParNURBSExtension::ParNURBSExtension(NURBSExtension *parent,
delete parent;
partitioning = NULL;
MFEM_VERIFY(par_parent->partitioning,
"parent ParNURBSExtension has no partitioning!");
+11 -34
View File
@@ -426,16 +426,6 @@ class NURBSExtension
friend class NURBSPatchMap;
protected:
/// Flag for indicating what type of NURBS fespace this extension is used for.
enum class Mode
{
H_1, ///> Extension for a standard scalar-valued space
H_DIV, ///> Extension for a divergence conforming vector-valued space
H_CURL, ///> Extension for a curl conforming vector-valued space
};
Mode mode = Mode::H_1;
/// Order of KnotVectors, see GetOrder() for description.
int mOrder;
@@ -665,10 +655,8 @@ public:
/** @a note If a KnotVector in @a parent already has order greater than or
equal to the corresponding entry in @a newOrder, it will be used
unmodified. */
NURBSExtension(NURBSExtension *parent, const Array<int> &newOrders,
Mode mode = Mode::H_1);
NURBSExtension(NURBSExtension *parent, const Array<int> &newOrders);
/// Construct a NURBSExtension by merging a partitioned NURBS mesh.
NURBSExtension(Mesh *mesh_array[], int num_pieces);
/// Copy assignment not supported.
@@ -853,16 +841,6 @@ public:
void KnotInsert(Array<KnotVector *> &kv);
void KnotInsert(Array<Vector *> &kv);
/** Returns the NURBSExtension to be used for @a component of
an H(div) conforming NURBS space. Caller gets ownership of
the returned object, and is responsible for deletion.*/
NURBSExtension* GetDivExtension(int component);
/** Returns the NURBSExtension to be used for @a component of
an H(curl) conforming NURBS space. Caller gets ownership of
the returned object, and is responsible for deletion.*/
NURBSExtension* GetCurlExtension(int component);
void KnotRemove(Array<Vector *> &kv, real_t tol = 1.0e-12);
/** Calls GetCoarseningFactors for each patch and finds the minimum factor
@@ -870,7 +848,6 @@ public:
non-nested spacing functions. */
void GetCoarseningFactors(Array<int> & f) const;
/// Returns the index of the patch containing element @a elem.
int GetElementPatch(int elem) const { return el_to_patch[elem]; }
@@ -895,7 +872,7 @@ class ParNURBSExtension : public NURBSExtension
{
private:
/// Partitioning of the global elements by MPI rank
mfem::Array<int> partitioning;
int *partitioning;
/// Construct and return a table of DOFs for each global element.
Table *GetGlobalElementDofTable();
@@ -905,10 +882,9 @@ private:
/** @brief Set active global elements and boundary elements based on MPI
ranks in @a partition and the array @a active_bel. */
void SetActive(const int *partitioning_, const Array<bool> &active_bel);
void SetActive(const int *partition, const Array<bool> &active_bel);
/// Set up GroupTopology @a gtopo for MPI communication.
void BuildGroups(const int *partitioning_, const Table &elem_dof);
void BuildGroups(const int *partition, const Table &elem_dof);
public:
GroupTopology gtopo;
@@ -919,12 +895,11 @@ public:
ParNURBSExtension(const ParNURBSExtension &orig);
/** @brief Constructor for an MPI communicator @a comm, a global
NURBSExtension @a parent, a partitioning @a partitioning_ of the global
elements by MPI rank, and a marker @a active_bel of active global
boundary elements on this rank. The partitioning is deep-copied and will
not be deleted by this object. */
ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent,
const int *partitioning_,
NURBSExtension @a parent, a partitioning @a part of the global elements
by MPI rank, and a marker @a active_bel of active global boundary
elements on this rank. The partitioning is deep-copied and will not be
deleted by this object. */
ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent, int *part,
const Array<bool> &active_bel);
/** @brief Create a parallel version of @a parent with partitioning as in
@@ -932,6 +907,8 @@ public:
The @a parent can be either a local NURBSExtension or a global one. */
ParNURBSExtension(NURBSExtension *parent,
const ParNURBSExtension *par_parent);
virtual ~ParNURBSExtension() { delete [] partitioning; }
};
#endif
+23 -22
View File
@@ -103,32 +103,29 @@ ParMesh& ParMesh::operator=(ParMesh &&mesh)
return *this;
}
ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, const int *partitioning_,
ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
int part_method)
: glob_elem_offset(-1)
, glob_offset_sequence(-1)
, gtopo(comm)
{
int *partitioning = NULL;
Array<bool> activeBdrElem;
MyComm = comm;
MPI_Comm_size(MyComm, &NRanks);
MPI_Comm_rank(MyComm, &MyRank);
Array<int> partitioning;
Array<bool> activeBdrElem;
if (partitioning_)
{
partitioning.MakeRef(const_cast<int *>(partitioning_), mesh.GetNE(),
false);
}
if (mesh.Nonconforming())
{
ncmesh = pncmesh = new ParNCMesh(comm, *mesh.ncmesh, partitioning_);
if (!partitioning_)
if (partitioning_)
{
partitioning.SetSize(mesh.GetNE());
partitioning = partitioning_;
}
ncmesh = pncmesh = new ParNCMesh(comm, *mesh.ncmesh, partitioning);
if (!partitioning)
{
partitioning = new int[mesh.GetNE()];
for (int i = 0; i < mesh.GetNE(); i++)
{
partitioning[i] = pncmesh->InitialPartition(i);
@@ -161,14 +158,13 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, const int *partitioning_,
ncmesh = pncmesh = NULL;
if (!partitioning_)
if (partitioning_)
{
// Mesh::GeneratePartitioning always uses new[] to allocate the,
// partitioning, so we need to tell the memory manager to free it with
// delete[] (even if a different host memory type has been selected).
constexpr MemoryType mt = MemoryType::HOST;
partitioning.MakeRef(mesh.GeneratePartitioning(NRanks, part_method),
mesh.GetNE(), mt, true);
partitioning = partitioning_;
}
else
{
partitioning = mesh.GeneratePartitioning(NRanks, part_method);
}
// re-enumerate the partitions to better map to actual processor
@@ -310,6 +306,11 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, const int *partitioning_,
SetVerticesFromNodes(Nodes);
}
if (partitioning != partitioning_)
{
delete [] partitioning;
}
have_face_nbr_data = false;
}
@@ -729,7 +730,7 @@ void ParMesh::BuildVertexGroup(int ngroups, const Table &vert_element)
}
void ParMesh::BuildSharedFaceElems(int ntri_faces, int nquad_faces,
const Mesh& mesh, const int *partitioning,
const Mesh& mesh, int *partitioning,
const STable3D *faces_tbl,
const Array<int> &face_group,
const Array<int> &vert_global_local)
+4 -2
View File
@@ -241,7 +241,7 @@ protected:
void BuildVertexGroup(int ngroups, const Table& vert_element);
void BuildSharedFaceElems(int ntri_faces, int nquad_faces,
const Mesh &mesh, const int *partitioning,
const Mesh &mesh, int *partitioning,
const STable3D *faces_tbl,
const Array<int> &face_group,
const Array<int> &vert_global_local);
@@ -343,7 +343,7 @@ public:
meshes and quick space-filling curve equipartitioning for nonconforming
meshes (elements of nonconforming meshes should ideally be ordered as a
sequence of face-neighbors). */
ParMesh(MPI_Comm comm, Mesh &mesh, const int *partitioning_ = nullptr,
ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_ = NULL,
int part_method = 1);
/** Copy constructor. Performs a deep copy of (almost) all data, so that the
@@ -438,6 +438,8 @@ public:
ParNCMesh* pncmesh;
int *partitioning_cache = nullptr;
int GetNGroups() const { return gtopo.NGroups(); }
///@{ @name These methods require group > 0
+2 -4
View File
@@ -28,8 +28,7 @@ namespace mfem
using namespace bin_io;
ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh,
const int *partitioning)
ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh, int *part)
: NCMesh(ncmesh)
{
MyComm = comm;
@@ -40,8 +39,7 @@ ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh,
// sequence of leaf elements into 'NRanks' parts
for (int i = 0; i < leaf_elements.Size(); i++)
{
elements[leaf_elements[i]].rank =
partitioning ? partitioning[i] : InitialPartition(i);
elements[leaf_elements[i]].rank = part ? part[i] : InitialPartition(i);
}
Update();
+8 -12
View File
@@ -67,8 +67,7 @@ public:
/// Construct by partitioning a serial NCMesh.
/** SFC partitioning is used by default. A user-specified partition can be
passed in 'part', where part[i] is the desired MPI rank for element i. */
ParNCMesh(MPI_Comm comm, const NCMesh& ncmesh,
const int *partitioning = nullptr);
ParNCMesh(MPI_Comm comm, const NCMesh& ncmesh, int* part = NULL);
/** Load from a stream, parallel version. See the serial NCMesh::NCMesh
counterpart for a description of the parameters. */
@@ -82,8 +81,7 @@ public:
/** An override of NCMesh::Refine, which is called eventually, after making
sure that refinements that occur on the processor boundary are sent to
the neighbor processors so they can keep their ghost layers up to
date. */
the neighbor processors so they can keep their ghost layers up to date.*/
void Refine(const Array<Refinement> &refinements) override;
/// Parallel version of NCMesh::LimitNCLevel.
@@ -231,8 +229,8 @@ public:
const Table &deref_table);
/** Extension of NCMesh::GetBoundaryClosure. Filters out ghost vertices and
ghost edges from 'bdr_vertices' and 'bdr_edges', and uncovers hidden
internal boundary faces. */
ghost edges from 'bdr_vertices' and 'bdr_edges', and uncovers hidden internal
boundary faces. */
void GetBoundaryClosure(const Array<int> &bdr_attr_is_ess,
Array<int> &bdr_vertices,
Array<int> &bdr_edges, Array<int> &bdr_faces) override;
@@ -254,9 +252,8 @@ protected: // interface for ParMesh
friend class ParMesh;
/** For compatibility with conforming code in ParMesh and ParFESpace.
Initializes shared structures in ParMesh: gtopo, shared_*, group_s*,
s*_l*. The ParMesh then acts as a parallel mesh cut along the NC
interfaces. */
Initializes shared structures in ParMesh: gtopo, shared_*, group_s*, s*_l*.
The ParMesh then acts as a parallel mesh cut along the NC interfaces. */
void GetConformingSharedStructures(class ParMesh &pmesh);
/** Populate face neighbor members of ParMesh from the ghost layer, without
@@ -522,9 +519,8 @@ protected: // implementation
owners, keeping the ghost layer up to date. Used by Rebalance() and
Derefine(). 'target_elements' is the number of elements this rank
is supposed to own after the exchange. If this number is not known
a priori, the parameter can be set to -1, but more expensive
communication (synchronous sends and a barrier) will be used in that
case. */
a priori, the parameter can be set to -1, but more expensive communication
(synchronous sends and a barrier) will be used in that case. */
void RedistributeElements(Array<int> &new_ranks, int target_elements,
bool record_comm);
+3 -3
View File
@@ -819,7 +819,7 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh,
apf::Downward verts;
apf_mesh->getDownward(ent,0,verts);
int *v = nullptr, nv = 0;
int *v, nv = 0;
apf::Mesh::Type ftype = apf_mesh->getType(ent);
if (ftype == apf::Mesh::TRIANGLE)
{
@@ -890,9 +890,9 @@ GridFunctionPumi::GridFunctionPumi(Mesh* m, apf::Mesh2* PumiM,
{
int spDim = m->SpaceDimension();
// Note: default BasisType for 'fec' is GaussLobatto.
fec_owned = new H1_FECollection(mesh_order, m->Dimension());
fec = new H1_FECollection(mesh_order, m->Dimension());
int ordering = Ordering::byVDIM; // x1y1z1/x2y2z2/...
fes = new FiniteElementSpace(m, fec_owned, spDim, ordering);
fes = new FiniteElementSpace(m, fec, spDim, ordering);
int data_size = fes->GetVSize();
// Read PUMI mesh data
+3 -1
View File
@@ -31,7 +31,7 @@ SubMesh SubMesh::CreateFromBoundary(const Mesh &parent,
SubMesh::SubMesh(const Mesh &parent, From from,
Array<int> attributes) : parent_(parent), from_(from), attributes_(attributes)
{
if (parent.Nonconforming())
if (Nonconforming())
{
MFEM_ABORT("SubMesh does not support non-conforming meshes");
}
@@ -193,6 +193,8 @@ SubMesh::SubMesh(const Mesh &parent, From from,
Finalize();
}
SubMesh::~SubMesh() {}
void SubMesh::Transfer(const GridFunction &src, GridFunction &dst)
{
TransferMap map(src, dst);
+2
View File
@@ -174,6 +174,8 @@ public:
return dynamic_cast<const SubMesh *>(m) != nullptr;
}
~SubMesh();
private:
/// Private constructor
SubMesh(const Mesh &parent, From from, Array<int> attributes);
+1 -2
View File
@@ -174,8 +174,7 @@ void BuildVdofToVdofMap(const FiniteElementSpace& subfes,
Array<int> sub_vdofs;
subfes.GetElementVDofs(i, sub_vdofs);
MFEM_ASSERT(parent_vdofs.Size() == sub_vdofs.Size(),
"elem " << i << ' ' << parent_vdofs.Size() << ' ' << sub_vdofs.Size());
MFEM_ASSERT(parent_vdofs.Size() == sub_vdofs.Size(), "internal error");
for (int j = 0; j < parent_vdofs.Size(); j++)
{
real_t sub_sign = 1.0;
+2 -5
View File
@@ -92,13 +92,10 @@ TransferMap::TransferMap(const GridFunction &src,
if (!root_fes_reset)
{
const FiniteElementCollection *src_fec = src.FESpace()->FEColl();
const FiniteElementCollection *dst_fec = dst.FESpace()->FEColl();
auto *root_fec = src_sm_dim == parent_dim ? src_fec : dst_fec;
root_fes_.reset(new FiniteElementSpace(
*src.FESpace(),
const_cast<Mesh *>(
SubMeshUtils::GetRootParent(*src_sm)), root_fec));
SubMeshUtils::GetRootParent(*src_sm))));
}
}
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/adjoint/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/autodiff/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
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
+4 -3
View File
@@ -12,10 +12,11 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
MFEM_INSTALL_DIR ?= ../../mfem
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/common/,)
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
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
# Default target
all: lib-common
+637
View File
@@ -0,0 +1,637 @@
// Parallel contact example
// mpirun -np 4 ./contact -ls 2 -sr 1 -testno 4
// CG iteration numbers = 105 114 116 115 113 109 113 108 107 114 206 236 268 435 987
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 5
// CG iteration numbers = 106 116 116 116 115 113 107 107 128 131 531 1437 1318
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 6
// CG iteration numbers = 18 18 18 18 18 17 17 21 22 46 52 53
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include "ipsolver/ParIPsolver.hpp"
using namespace std;
using namespace mfem;
double GetBdrElementVolume(int i, Mesh & mesh)
{
ElementTransformation *et = mesh.GetBdrElementTransformation(i);
const IntegrationRule &ir = IntRules.Get(mesh.GetBdrElementGeometry(i),
et->OrderJ());
double volume = 0.0;
for (int j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
et->SetIntPoint(&ip);
volume += ip.weight * et->Weight();
}
return volume;
}
double GetBdrArea(int bdrattr, Mesh&mesh)
{
double area = 0.0;
for (int i = 0; i<mesh.GetNBE(); i++)
{
if (mesh.GetBdrAttribute(i) == bdrattr)
{
area += GetBdrElementVolume(i,mesh);
}
}
MPI_Allreduce(MPI_IN_PLACE,&area,1, MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
return area;
}
void OutputData(ostringstream & file_name, double E0, double Ef, int dofs, int constr, int optit, const Array<int> & iters)
{
file_name << ".csv";
std::ofstream outputfile(file_name.str().c_str());
//if (!outputfile.is_open())
//{
// MFEM_ABORT("Failed to open file for writing.\n");
//}
outputfile << "Initial Energy objective = " << E0 << endl;
outputfile << "Final Energy objective = " << Ef << endl;
outputfile << "Global number of dofs = " << dofs << endl;
outputfile << "Global number of constraints = " << constr << endl;
outputfile << "Optimizer number of iterations = " << optit << endl;
outputfile << "CG iteration numbers = "; iters.Print(outputfile, iters.Size());
outputfile << "OptimizerIteration,CGIterations" << endl;
for (int i = 0; i< iters.Size(); i++)
{
outputfile << i+1 <<","<< iters[i] << endl;
}
outputfile.close();
std::cout << " Data has been written to " << file_name.str().c_str() << endl;
}
int main(int argc, char *argv[])
{
Mpi::Init();
int myid = Mpi::WorldRank();
int num_procs = Mpi::WorldSize();
Hypre::Init();
int order = 1;
int sref = 1;
int pref = 0;
Array<int> attr;
Array<int> m_attr;
bool visualization = true;
bool paraview = false;
int paraview_plot_every = 1;
int SQPrepeat = 1;
double linsolverrtol = 1e-10;
double linsolveratol = 1e-12;
int relax_type = 8;
double optimizer_tol = 1e-6;
int optimizer_maxit = 20;
int linsolver = 2; // PCG - AMG
bool elast = false;
bool nocontact = false;
int testNo = -1; // 0-6
int nsteps = 1;
bool outputfiles = false;
bool doublepass = false;
// 1. Parse command-line options.
OptionsParser args(argc, argv);
args.AddOption(&testNo, "-testno", "--test-number",
"Choice of test problem:"
"-1: default (original 2 block problem)"
"0: not implemented yet"
"1: not implemented yet"
"2: not implemented yet"
"3: not implemented yet"
"4: two block problem - diablo"
"41: two block problem - twisted"
"5: ironing problem"
"51: ironing problem extended"
"6: nested spheres problem");
args.AddOption(&attr, "-at", "--attributes-surf",
"Attributes of boundary faces on contact surface for mesh 2.");
args.AddOption(&sref, "-sr", "--serial-refinements",
"Number of uniform refinements.");
args.AddOption(&nsteps, "-nsteps", "--nsteps",
"Number of steps.");
args.AddOption(&pref, "-pr", "--parallel-refinements",
"Number of uniform refinements.");
args.AddOption(&linsolverrtol, "-srtol", "--solver-rel-tol",
"Linear Solver Relative Tolerance.");
args.AddOption(&linsolveratol, "-satol", "--solver-abs-tol",
"Linear Solver Abs Tolerance.");
args.AddOption(&elast, "-elast", "--elast", "-no-elast",
"--no-elast",
"Enable or disable AMG Elasticity options.");
args.AddOption(&nocontact, "-nocontact", "--nocontact", "-no-nocontact",
"--no-nocontact",
"Enable or disable AMG solve with no contact for testing.");
args.AddOption(&doublepass, "-doublepass", "--double-pass", "-singlepass",
"--single-pass",
"Enable or disable double pass for contact constraints.");
args.AddOption(&optimizer_tol, "-otol", "--optimizer-tol",
"Interior Point Solver Tolerance.");
args.AddOption(&optimizer_maxit, "-omaxit", "--optimizer-maxit",
"Interior Point Solver maximum number of iterations.");
args.AddOption(&relax_type, "-rt", "--relax-type",
"Selection of Smoother for AMG");
args.AddOption(&linsolver, "-ls", "--linear-solver",
"Selection of inner linear solver:"
"0: mumps,"
"1: mumps-reduced,"
"2: PCG-AMG-reduced,"
"3: PCG- with block-diag(AMG,direct solver)"
"4: with static cond of contact dofs");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&paraview, "-paraview", "--paraview", "-no-paraview",
"--no-paraview",
"Enable or disable ParaView visualization.");
args.AddOption(&paraview_plot_every, "-plot_every", "--plot-every",
"Output every plot_every pseudotimesteps as a paraview file");
args.AddOption(&SQPrepeat, "-nSQPrepeat", "--nSQP-repeats", "Number of times to relinearize and resolve the SQP before incremenetally updating forcing and boundary terms");
args.AddOption(&outputfiles, "-out", "--output", "-no-out",
"--no-ouput",
"Enable or disable ouput to files.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
if (Mpi::Root())
{
mfem::out << "Solving test problem number: " << testNo << endl;
}
const char *mesh_file = nullptr;
switch (testNo)
{
case -1:
mesh_file = "meshes/two-block.mesh";
break;
case 0:
case 1:
case 2:
case 3:
{
MFEM_ABORT("Problem not implemented yet");
break;
}
case 4:
mesh_file = "meshes/Test4.mesh";
break;
case 40:
mesh_file = "meshes/Test40.mesh";
break;
case 41:
mesh_file = "meshes/Test41.mesh";
break;
case 42:
mesh_file = "meshes/Test42.mesh";
break;
case 5:
mesh_file = "meshes/Test5.mesh";
break;
case 51:
mesh_file = "meshes/Test51.mesh";
break;
case 6:
mesh_file = "meshes/Test6.mesh";
break;
case 61:
// Something wrong with this mesh
mesh_file = "meshes/Test61.mesh";
break;
case 62:
mesh_file = "meshes/Test62.mesh";
break;
default:
MFEM_ABORT("Should be unreachable");
break;
}
Mesh * mesh = new Mesh(mesh_file,1);
for (int i = 0; i<sref; i++)
{
mesh->UniformRefinement();
}
ParMesh * pmesh = new ParMesh(MPI_COMM_WORLD,*mesh);
for (int i = 0; i<pref; i++)
{
pmesh->UniformRefinement();
}
Array<int> ess_bdr_attr;
Array<int> ess_bdr_attr_comp;
if (testNo == 6 || testNo == 61)
{
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(1);
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(2);
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
}
else if (testNo == 62)
{
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
}
else if (testNo == 40)
{
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(-1);
ess_bdr_attr.Append(10); ess_bdr_attr_comp.Append(-1);
}
else
{
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(-1);
ess_bdr_attr.Append(6); ess_bdr_attr_comp.Append(-1);
}
ParElasticityProblem * prob = new ParElasticityProblem(pmesh,
ess_bdr_attr,ess_bdr_attr_comp,
order);
Vector lambda(prob->GetMesh()->attributes.Max());
Vector mu(prob->GetMesh()->attributes.Max());
if (testNo == -1 )
{
lambda = 57.6923076923;
mu = 38.4615384615;
}
else if (testNo == 6 || testNo == 61 || testNo == 62)
{
lambda = (1000*0.3)/(1.3*0.4);
mu = 500/(1.3);
}
else
{
//lambda = 57.6923076923;
//mu = 38.4615384615;
//lambda = 0.499 / (1.499 * 0.002);
//mu = 1. / (2. * 1.499);
lambda[0] = 0.499/(1.499*0.002);
lambda[1] = 0.0;
mu[0] = 1. / (2. * 1.499);
mu[1] = 500.;
}
prob->SetLambda(lambda); prob->SetMu(mu);
int dim = pmesh->Dimension();
Vector ess_values(dim);
int essbdr_attr;
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_values = 0.0;
double area = GetBdrArea(3,*mesh);
// ConstantCoefficient one(-area);
ConstantCoefficient one(-1.0);
std::set<int> mortar_attr;
std::set<int> nonmortar_attr;
if (testNo == 6 || testNo == 61)
{
ess_values = 0.0;
ess_bdr = 0;
ess_bdr[0] = 1;
ess_bdr[1] = 1;
ess_bdr[3] = 1;
ess_bdr[4] = 1;
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
ess_bdr = 0;
ess_bdr[2] = 1;
// prob->SetNeumanPressureData(one,ess_bdr);
mortar_attr.insert(6);
mortar_attr.insert(9);
nonmortar_attr.insert(7);
nonmortar_attr.insert(8);
}
else if(testNo == 62)
{
ess_values = 0.0;
ess_bdr = 0;
ess_bdr[3] = 1;
ess_bdr[4] = 1;
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
ess_bdr = 0;
ess_bdr[2] = 1;
// prob->SetNeumanPressureData(one,ess_bdr);
prob->SetNeumanData(0,3,-2.0);
mortar_attr.insert(6);
mortar_attr.insert(9);
nonmortar_attr.insert(7);
nonmortar_attr.insert(8);
}
else
{
if (testNo == -1 || testNo == 41)
{
ess_values[0] = 0.1/nsteps;
}
else
{
ess_values[2] = 1.0 / 1.4 / nsteps;
//ess_values[2] = 0.25 / nsteps;//1.0/1.4/nsteps;
// ess_values[0] = -2.0/nsteps;
}
essbdr_attr = (testNo == 40) ? 1 : 2;
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
essbdr_attr = (testNo == 40) ? 10 : 6;
ess_values = 0.0; ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
if (testNo == 40)
{
mortar_attr.insert(4);
nonmortar_attr.insert(7);
}
else
{
mortar_attr.insert(3);
nonmortar_attr.insert(4);
}
}
ParFiniteElementSpace * fes = prob->GetFESpace();
ParGridFunction x_gf(fes); x_gf = 0.0;
ParGridFunction xnew(fes); xnew = 0.0;
ParaViewDataCollection * paraview_dc = nullptr;
ParMesh pmesh_copy(*pmesh);
ParFiniteElementSpace fes_copy(*fes,pmesh_copy);
ParGridFunction xcopy_gf(&fes_copy); xcopy_gf = 0.0;
if (paraview)
{
std::ostringstream paraview_file_name;
paraview_file_name << "QPContact-Test_" << testNo
<< "_par_ref_" << pref
<< "_ser_ref_" << sref;
paraview_dc = new ParaViewDataCollection(paraview_file_name.str(), &pmesh_copy);
paraview_dc->SetPrefixPath("ParaView");
paraview_dc->SetLevelsOfDetail(1);
paraview_dc->SetDataFormat(VTKFormat::BINARY);
paraview_dc->SetHighOrderOutput(true);
// paraview_dc->RegisterField("u", &x_gf);
paraview_dc->RegisterField("u", &xcopy_gf);
paraview_dc->SetCycle(0);
paraview_dc->SetTime(double(0));
paraview_dc->Save();
}
socketstream sol_sock;
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
sol_sock.open(vishost, visport);
sol_sock.precision(8);
}
// ParGridFunction coords(prob->GetFESpace());
ParGridFunction ref_coords(prob->GetFESpace());
ParGridFunction new_coords(prob->GetFESpace());
pmesh->GetNodes(new_coords);
pmesh->GetNodes(ref_coords);
Vector xref(x_gf.GetTrueVector().Size());
HypreParMatrix *dgdu;
double p = 1;
ConstantCoefficient f(p);
// SQPrepeat solves on same problem (forcing/boundary conditions)
int Nsteps = nsteps * SQPrepeat;
double pseudotime = 0.0;
double pseudotimestep = 1.0 / ((double) nsteps);
double paraview_time = 0.0;
double paraview_subtimestep = pseudotimestep / ((double) SQPrepeat);
int paraview_cycle = 1;
bool QPConverged;
std::ofstream numConstraintsStream;
std::ostringstream numConstraints_file_name;
numConstraints_file_name << "data/numConstraints_ref" << sref << ".dat";
if (Mpi::Root)
{
numConstraintsStream.open(numConstraints_file_name.str(), ios::out | ios::trunc);
}
for (int i = 0; i < nsteps; i++)
{
pseudotime = ((double) (i + 1)) / ((double) nsteps);
for (int j = 0; j < SQPrepeat; j++)
{
paraview_time = pseudotime + j * paraview_subtimestep;
if (testNo == 6)
{
ess_bdr = 0;
ess_bdr[2] = 1;
f.constant = -p * pseudotime;
prob->SetNeumanPressureData(f,ess_bdr);
// prob->SetNeumanData(0,3,-p*(i+1)/nsteps);
}
else if (testNo == 4 || testNo == 40 || testNo == 5 || testNo == 51)
{
ess_bdr = 0;
essbdr_attr = (testNo == 40) ? 1 : 2;
ess_bdr[essbdr_attr-1] = 1;
ess_values = 0.0;
//ess_values[2] = 4.0 / 7.0 * pseudotime;
//ess_values[2] = 0.25 * pseudotime; //1.0/1.4 * pseudotime;
ess_values[2] = 1.0 / 1.4 * pseudotime;
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
}
else if (testNo == 41)
{
ess_values = 0.0;
ess_values[0] = 0.5 * pseudotime; //0.5/nsteps*(i+1);
// ess_values[0] = 0.0;
essbdr_attr = 2;
ess_bdr[essbdr_attr-1] = 1;
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
essbdr_attr = 6;
ess_values = 0.0;
// ess_values[0] = -0.5/nsteps*(i+1);
if (myid == 0)
{
mfem::out << "ess_values[0] = " << ess_values[0] << endl;
}
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
}
//xref.Set(1.0, x_gf.GetTrueVector());
xref = 0.0;
ParContactProblem contact(prob, mortar_attr, nonmortar_attr, &new_coords, doublepass);
QPOptParContactProblem qpopt(&contact, xref);
int numconstr = contact.GetGlobalNumConstraints();
ParInteriorPointSolver optimizer(&qpopt);
optimizer.SetTol(optimizer_tol);
optimizer.SetMaxIter(optimizer_maxit);
optimizer.SetLinearSolver(linsolver);
optimizer.SetLinearSolveRelTol(linsolverrtol);
optimizer.SetLinearSolveAbsTol(linsolveratol);
optimizer.SetLinearSolveRelaxType(relax_type);
if (nocontact)
{
optimizer.EnableNoContactSolve();
}
if (elast)
{
optimizer.SetElasticityOptions(prob->GetFESpace());
}
// ParGridFunction x = prob->GetDisplacementGridFunction();
// x.SetTrueVector();
// Vector x0 = x.GetTrueVector();
x_gf.SetTrueVector();
Vector x0 = x_gf.GetTrueVector();
int ndofs = x0.Size();
Vector xf(ndofs); xf = 0.0;
optimizer.Mult(x0, xf);
QPConverged = optimizer.GetConverged();
/* exit if not converged */
MFEM_VERIFY(QPConverged, "IPM not converged on QP contact problem");
double Einitial = contact.E(x0);
double Efinal = contact.E(xf);
Array<int> & CGiterations = optimizer.GetCGIterNumbers();
int gndofs = prob->GetGlobalNumDofs();
int gnconstraints = contact.GetGlobalNumConstraints();
//std::ofstream xfStream;
//std::ostringstream xf_file_name;
//xf_file_name << "data/xf_" << i << ".dat";
//if (Mpi::Root())
//{
// xfStream.open(xf_file_name.str(), ios::out | ios::trunc);
// for (int ii = 0; ii < xf.Size(); ii++)
// {
// xfStream << xf(ii) << "\n";
// }
// xfStream.close();
//}
//if (Mpi::Root)
//{
// numConstraintsStream.open(numConstraints_file_name.str(), ios::out | ios::trunc);
//}
if (Mpi::Root())
{
mfem::out << endl;
mfem::out << " Initial Energy objective = " << Einitial << endl;
mfem::out << " Final Energy objective = " << Efinal << endl;
mfem::out << " Global number of dofs = " << gndofs << endl;
mfem::out << " Global number of constraints = " << numconstr << endl;
mfem::out << " Optimizer number of iterations = " <<
optimizer.GetNumIterations() << endl;
if (linsolver == 2 || linsolver == 3 || linsolver == 4)
{
mfem::out << " CG iteration numbers = " ;
CGiterations.Print(mfem::out, CGiterations.Size());
}
if (nocontact)
{
Array<int> & CGNoContactIterations = optimizer.GetCGNoContactIterNumbers();
mfem::out << " CG no Contact iteration numbers = " ;
CGNoContactIterations.Print(mfem::out, CGNoContactIterations.Size());
}
if (outputfiles)
{
ostringstream file_name;
file_name << "output/Testno-"<<testNo<<"-ref-"<<sref+pref << "-step-" << i;
OutputData(file_name, Einitial, Efinal, gndofs,numconstr, optimizer.GetNumIterations(), CGiterations);
}
numConstraintsStream << gnconstraints << endl;
}
// Vector X_new(xf.GetData(),fes->GetTrueVSize());
// xnew.SetFromTrueDofs(X_new);
// x_gf = xnew;
x_gf.SetFromTrueDofs(xf);
// mfem::out << "x_gf norm = " << x_gf.Norml2() << endl;
// cin.get();
// pmesh->MoveNodes(xnew);
// pmesh_copy.MoveNodes(xnew);
// pmesh_copy.MoveNodes(xnew);
add(ref_coords,x_gf,new_coords);
// mfem::out << " ref_coords norm " << ref_coords.Norml2() << endl;
// mfem::out << " x_gf norm " << x_gf.Norml2() << endl;
// mfem::out << " new_coords norm " << new_coords.Norml2() << endl;
// pmesh_copy.SetNodes(new_coords);
pmesh_copy.SetNodes(new_coords);
xcopy_gf = x_gf;
// pmesh_copy.MoveNodes(x_gf);
// pmesh_copy.SetNodes(x_gf);
if (paraview && ((i+1) % paraview_plot_every == 0 ))
{
paraview_cycle += 1;
paraview_dc->SetCycle(paraview_cycle) ;
paraview_dc->SetTime(paraview_time);
paraview_dc->Save();
}
if (visualization)
{
sol_sock << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << pmesh_copy << x_gf << flush;
if (i == nsteps - 1 && j == SQPrepeat - 1)
{
pmesh->MoveNodes(x_gf);
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock1(vishost, visport);
sol_sock1 << "parallel " << num_procs << " " << myid << "\n";
sol_sock1.precision(8);
sol_sock1 << "solution\n" << *pmesh << x_gf << flush;
}
}
if (i == nsteps - 1 && j == SQPrepeat) break;
prob->UpdateStep();
if (testNo == 6 )
{
double area_new = GetBdrArea(3,*pmesh);
if (myid == 0)
{
mfem::out << "New area = " << area_new << endl;
}
}
}
}
if (Mpi::Root)
{
numConstraintsStream.close();
}
delete prob;
delete pmesh;
delete mesh;
return 0;
}
File diff suppressed because it is too large Load Diff
+114
View File
@@ -0,0 +1,114 @@
#include "mfem.hpp"
#include "../problems/parproblems.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
#ifndef PARIPSOLVER
#define PARIPSOLVER
class ParInteriorPointSolver
{
protected:
QPOptParContactProblem* problem = nullptr;
double OptTol;
int max_iter;
int iter=0;
double mu_k; // \mu_k
Vector lk, zlk;
double sMax, kSig, tauMin, eta, thetaMin, delta, sTheta, sPhi, kMu, thetaMu;
double thetaMax, kSoc, gTheta, gPhi, kEps;
// filter
Array<double> F1, F2;
// quantities computed in lineSearch
double alpha, alphaz;
double thx0, thxtrial;
double phx0, phxtrial;
bool descentDirection, switchCondition, sufficientDecrease, lineSearchSuccess, inFilterRegion;
double Dxphi0_xhat;
int dimU, dimM, dimC;
int gdimU, gdimM, gdimC;
Array<int> block_offsetsumlz, block_offsetsuml, block_offsetsx;
Vector ml;
Vector ckSoc;
HypreParMatrix * Huu = nullptr;
HypreParMatrix * Hum = nullptr;
HypreParMatrix * Hmu = nullptr;
HypreParMatrix * Hmm = nullptr;
HypreParMatrix * Wmm = nullptr;
HypreParMatrix * Ju = nullptr;
HypreParMatrix * Jm = nullptr;
HypreParMatrix * JuT = nullptr;
HypreParMatrix * JmT = nullptr;
Array<int> cgnum_iterations;
Array<int> cgnum_iterations_nocontact;
ParFiniteElementSpace *pfes = nullptr;
int jOpt;
bool converged;
int MyRank;
bool iAmRoot;
bool saveLogBarrierIterates = false;
int linSolver=0;
double linSolveAbsTol = 1e-12;
double linSolveRelTol = 1e-6;
int relax_type = 8;
bool nocontact = false;
public:
ParInteriorPointSolver(QPOptParContactProblem*);
double MaxStepSize(Vector& , Vector& , Vector& , double);
double MaxStepSize(Vector& , Vector& , double);
void Mult(const BlockVector& , BlockVector&);
void Mult(const Vector&, Vector &);
void FormIPNewtonMat(BlockVector& , Vector& , Vector& , BlockOperator &);
void IPNewtonSolve(BlockVector& , Vector& , Vector& , Vector&, BlockVector& , double, bool);
void lineSearch(BlockVector& , BlockVector& , double);
void projectZ(const Vector & , Vector &, double);
void filterCheck(double, double);
double E(const BlockVector &, const Vector &, const Vector &, double, bool);
double E(const BlockVector &, const Vector &, const Vector &, bool);
bool GetConverged() const;
Array<int> & GetCGIterNumbers() {return cgnum_iterations;}
Array<int> & GetCGNoContactIterNumbers() {return cgnum_iterations_nocontact;}
int GetNumIterations() {return iter;}
// TO DO: include Hessian of Lagrangian
double theta(const BlockVector &);
double phi(const BlockVector &, double);
void Dxphi(const BlockVector &, double, BlockVector &);
double L(const BlockVector &, const Vector &, const Vector &);
void DxL(const BlockVector &, const Vector &, const Vector &, BlockVector &);
void SetTol(double);
void SetMaxIter(int);
void SetBarrierParameter(double);
void SaveLogBarrierHessianIterates(bool);
void SaveLambda(int);
void SaveZl(int);
void SetLinearSolver(int);
void SetLinearSolveAbsTol(double);
void SetLinearSolveRelTol(double);
void SetLinearSolveRelaxType(int);
void SetElasticityOptions(ParFiniteElementSpace * pfes_)
{
pfes = pfes_;
}
void EnableNoContactSolve()
{
nocontact = true;
}
virtual ~ParInteriorPointSolver();
};
#endif
+109
View File
@@ -0,0 +1,109 @@
# Copyright (c) 2010-2023, 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/contact/,)
CONFIG_MK = $(MFEM_BUILD_DIR)/config/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)
FRAMEWORK_SRC = ipsolver/ParIPsolver.cpp problems/parproblems.cpp problems/parproblems_util.cpp
CONTACT_SRC = contact.cpp $(FRAMEWORK_SRC)
CONTACT_OBJ = $(CONTACT_SRC:.cpp=.o)
CONTACT_FDCHECK_SRC = contactFDcheck.cpp $(FRAMEWORK_SRC)
CONTACT_FDCHECK_OBJ = $(CONTACT_FDCHECK_SRC:.cpp=.o)
SCRATCH_SRC = scratch.cpp $(FRAMEWORK_SRC)
SCRATCH_OBJ = $(SCRATCH_SRC:.cpp=.o)
SEQ_MINIAPPS =
PAR_MINIAPPS = scratch contact contactFDcheck
ifeq ($(MFEM_USE_MPI),NO)
MINIAPPS = $(SEQ_MINIAPPS)
else
MINIAPPS = $(PAR_MINIAPPS) $(SEQ_MINIAPPS)
endif
COMMON_LIB = -L$(MFEM_BUILD_DIR)/miniapps/common -lmfem-common
# If MFEM_SHARED is set, add the ../common rpath
COMMON_LIB += $(if $(MFEM_SHARED:YES=),,\
$(if $(MFEM_USE_CUDA:YES=),$(CXX_XLINKER),$(CUDA_XLINKER))-rpath,$(abspath\
$(MFEM_BUILD_DIR)/miniapps/common))
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all lib-common clean clean-build clean-exec
# Remove built-in rule
%: %.cpp
%.o: %.cpp
%.o: $(SRC)%.cpp $(wildcard $(SRC)%.hpp) $(MFEM_LIB_FILE)\
$(CONFIG_MK) | lib-common
$(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@
problems/%.o: $(SRC)problems/%.cpp $(wildcard $(SRC)problems/%.hpp) $(MFEM_LIB_FILE)\
$(CONFIG_MK) | lib-common
mkdir -p $(@D)
$(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@
all: $(MINIAPPS)
contact: $(CONTACT_OBJ)
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(CONTACT_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
contactFDcheck: $(CONTACT_FDCHECK_OBJ)
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(CONTACT_FDCHECK_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
scratch: $(SCRATCH_OBJ)
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(SCRATCH_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
# Rule for building lib-common
lib-common:
$(MAKE) -C $(MFEM_BUILD_DIR)/miniapps/common
MFEM_TESTS = MINIAPPS
include $(MFEM_TEST_MK)
# Testing: Specific execution options
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
contact-test-par: contact
@$(call mfem-test,$<, $(RUN_MPI), pcontact miniapp,)
# 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 *~ $(PAR_MINIAPPS) $(SEQ_MINIAPPS)
rm -f $(CONTACT_OBJ)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -rf ParaView
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

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