Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7e0ed79e6 | ||
|
|
7359466ce4 | ||
|
|
d5814b9d8e | ||
|
|
7dd2312ec4 | ||
|
|
aa25a12086 | ||
|
|
3341feb1d3 | ||
|
|
a6f7baeede | ||
|
|
bc2ee7f3a9 | ||
|
|
2bcae01f71 | ||
|
|
cde13ad145 | ||
|
|
f728fadcf7 | ||
|
|
3db9688894 | ||
|
|
d9dc18c32b |
@@ -33,7 +33,6 @@ env:
|
||||
HYPRE_ARCHIVE: v2.19.0.tar.gz
|
||||
HYPRE_TOP_DIR: hypre-2.19.0
|
||||
METIS_ARCHIVE: metis-4.0.3.tar.gz
|
||||
METIS_ARCHIVE_MAC: metis-4.0.3-mac.tgz
|
||||
METIS_TOP_DIR: metis-4.0.3
|
||||
MFEM_TOP_DIR: mfem
|
||||
|
||||
@@ -53,7 +52,6 @@ jobs:
|
||||
mpi: [seq, par]
|
||||
build-system: [make, cmake]
|
||||
hypre-target: [int32]
|
||||
precision: [fp64]
|
||||
exclude:
|
||||
- os: ubuntu-latest
|
||||
build-system: cmake
|
||||
@@ -77,8 +75,6 @@ jobs:
|
||||
- os: ubuntu-latest
|
||||
target: dbg
|
||||
config-opts: 'CPPFLAGS+=-Og'
|
||||
- os: macos-latest
|
||||
codecov: NO
|
||||
- os: windows-latest
|
||||
codecov: NO
|
||||
- os: windows-latest
|
||||
@@ -91,7 +87,6 @@ jobs:
|
||||
mpi: par
|
||||
build-system: cmake
|
||||
hypre-target: int32
|
||||
precision: fp64
|
||||
# This option can be set to pass additional configuration options to
|
||||
# the MFEM configuration command.
|
||||
# config-opts: '-DCMAKE_VERBOSE_MAKEFILE=ON'
|
||||
@@ -101,15 +96,7 @@ jobs:
|
||||
mpi: par
|
||||
build-system: make
|
||||
hypre-target: int64
|
||||
precision: fp64
|
||||
- os: ubuntu-latest
|
||||
target: opt
|
||||
codecov: NO
|
||||
mpi: par
|
||||
build-system: make
|
||||
hypre-target: int32
|
||||
precision: fp32
|
||||
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}-${{ matrix.precision }}
|
||||
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@@ -139,17 +126,6 @@ jobs:
|
||||
# Fetch the complete history for codecov to access commits ID
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Xcode version setup (MacOS)
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: |
|
||||
XCODE_PATH="/Applications/Xcode_15.3.app"
|
||||
echo "> sudo xcode-select -s ${XCODE_PATH}"
|
||||
sudo xcode-select -s ${XCODE_PATH}
|
||||
echo "> g++ -v"
|
||||
g++ -v
|
||||
echo "> clang++ -v"
|
||||
clang++ -v
|
||||
|
||||
# Only get MPI if defined for the job.
|
||||
# TODO: It would be nice to have only one step, e.g. with a dedicated
|
||||
# action, but I (@adrienbernede) don't see how at the moment.
|
||||
@@ -193,27 +169,25 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.HYPRE_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-${{ matrix.precision }}-v2.5
|
||||
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-v2.2
|
||||
|
||||
- name: get hypre
|
||||
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os != 'windows-latest'
|
||||
uses: mfem/github-actions/build-hypre@v2.5
|
||||
uses: mfem/github-actions/build-hypre@v2.4
|
||||
with:
|
||||
archive: ${{ env.HYPRE_ARCHIVE }}
|
||||
dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
target: ${{ matrix.hypre-target }}
|
||||
build-system: make
|
||||
precision: ${{ matrix.precision }}
|
||||
|
||||
- name: get hypre (Windows)
|
||||
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os == 'windows-latest'
|
||||
uses: mfem/github-actions/build-hypre@v2.5
|
||||
uses: mfem/github-actions/build-hypre@v2.4
|
||||
with:
|
||||
archive: ${{ env.HYPRE_ARCHIVE }}
|
||||
dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
target: ${{ matrix.hypre-target }}
|
||||
build-system: cmake
|
||||
precision: ${{ matrix.precision }}
|
||||
|
||||
# Get Metis through cache, or build it.
|
||||
# Install will only run on cache miss.
|
||||
@@ -223,13 +197,13 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.METIS_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.5
|
||||
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
|
||||
|
||||
- name: install metis
|
||||
if: matrix.mpi == 'par' && matrix.os != 'windows-latest' && steps.metis-cache.outputs.cache-hit != 'true'
|
||||
uses: mfem/github-actions/build-metis@v2.5
|
||||
uses: mfem/github-actions/build-metis@v2.4
|
||||
with:
|
||||
archive: ${{ matrix.os != 'macos-latest' && env.METIS_ARCHIVE || env.METIS_ARCHIVE_MAC }}
|
||||
archive: ${{ env.METIS_ARCHIVE }}
|
||||
dir: ${{ env.METIS_TOP_DIR }}
|
||||
|
||||
- name: cache vcpkg (Windows)
|
||||
@@ -254,7 +228,7 @@ jobs:
|
||||
|
||||
# MFEM build and test
|
||||
- name: build
|
||||
uses: mfem/github-actions/build-mfem@v2.5
|
||||
uses: mfem/github-actions/build-mfem@v2.4
|
||||
env:
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
|
||||
with:
|
||||
@@ -266,7 +240,6 @@ jobs:
|
||||
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
metis-dir: ${{ env.METIS_TOP_DIR }}
|
||||
mfem-dir: ${{ env.MFEM_TOP_DIR }}
|
||||
precision: ${{ matrix.precision }}
|
||||
config-options: ${{ matrix.config-opts }}
|
||||
library-only: ${{ matrix.target == 'dbg' && matrix.os != 'ubuntu-latest' }}
|
||||
|
||||
@@ -309,7 +282,7 @@ jobs:
|
||||
# Code coverage (process and upload reports)
|
||||
- name: codecov
|
||||
if: matrix.codecov == 'YES'
|
||||
uses: mfem/github-actions/upload-coverage@v2.5
|
||||
uses: mfem/github-actions/upload-coverage@v2.4
|
||||
with:
|
||||
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
|
||||
project_dir: ${{ env.MFEM_TOP_DIR }}
|
||||
|
||||
@@ -53,11 +53,11 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.HYPRE_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.5
|
||||
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.2
|
||||
|
||||
- name: Get Hypre
|
||||
if: steps.hypre-cache.outputs.cache-hit != 'true'
|
||||
uses: mfem/github-actions/build-hypre@v2.5
|
||||
uses: mfem/github-actions/build-hypre@v2.4
|
||||
with:
|
||||
archive: ${{ env.HYPRE_ARCHIVE }}
|
||||
dir: ${{ env.HYPRE_TOP_DIR }}
|
||||
@@ -68,18 +68,18 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.METIS_TOP_DIR }}
|
||||
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.5
|
||||
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
|
||||
|
||||
- name: Install Metis
|
||||
if: steps.metis-cache.outputs.cache-hit != 'true'
|
||||
uses: mfem/github-actions/build-metis@v2.5
|
||||
uses: mfem/github-actions/build-metis@v2.4
|
||||
with:
|
||||
archive: ${{ env.METIS_ARCHIVE }}
|
||||
dir: ${{ env.METIS_TOP_DIR }}
|
||||
|
||||
# MFEM build and test
|
||||
- name: build-mfem
|
||||
uses: mfem/github-actions/build-mfem@v2.5
|
||||
uses: mfem/github-actions/build-mfem@v2.4
|
||||
with:
|
||||
os: ${{ runner.os }}
|
||||
target: opt
|
||||
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
path: mfem
|
||||
|
||||
- name: MFEM Build
|
||||
uses: mfem/github-actions/build-mfem@v2.5
|
||||
uses: mfem/github-actions/build-mfem@v2.4
|
||||
with:
|
||||
os: ${{ runner.os }}
|
||||
target: opt
|
||||
|
||||
+1
-5
@@ -57,8 +57,6 @@ examples/ex2[0-9]
|
||||
examples/ex2[0-9]p
|
||||
examples/ex3[0-9]
|
||||
examples/ex3[0-9]p
|
||||
examples/ex4[0-9]
|
||||
examples/ex4[0-9]p
|
||||
|
||||
examples/refined.mesh
|
||||
examples/displaced.mesh
|
||||
@@ -234,7 +232,7 @@ miniapps/meshing/mobius-strip.mesh
|
||||
miniapps/meshing/klein-bottle.mesh
|
||||
miniapps/meshing/toroid-*.mesh
|
||||
miniapps/meshing/twist-*.mesh
|
||||
miniapps/meshing/mesh-explorer.mesh*
|
||||
miniapps/meshing/mesh-explorer.mesh
|
||||
miniapps/meshing/partitioning.txt
|
||||
miniapps/meshing/mesh-explorer-visit*
|
||||
miniapps/meshing/mesh-explorer-paraview/
|
||||
@@ -371,8 +369,6 @@ miniapps/dpg/ParaView
|
||||
miniapps/spde/generate_random_field
|
||||
miniapps/spde/ParaView
|
||||
|
||||
miniapps/tribol/contact-patch-test
|
||||
|
||||
# Unit test binary and outputs
|
||||
tests/unit/output_meshes
|
||||
tests/unit/unit_tests
|
||||
|
||||
@@ -13,9 +13,6 @@
|
||||
# at Lawrence Livermore National Laboratory (LLNL). This entire pipeline is
|
||||
# LLNL-specific!
|
||||
|
||||
include:
|
||||
- project: 'lc-templates/id_tokens'
|
||||
file: 'id_tokens.yml'
|
||||
|
||||
# The pipeline is divided into stages. Usually, jobs in a given stage wait for
|
||||
# the preceding stages to complete before to start. However, we sometimes use
|
||||
|
||||
@@ -9,10 +9,6 @@
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
include:
|
||||
- project: 'lc-templates/id_tokens'
|
||||
file: 'id_tokens.yml'
|
||||
|
||||
# We define the following GitLab pipeline variables:
|
||||
variables:
|
||||
|
||||
|
||||
@@ -35,8 +35,9 @@ variables:
|
||||
- when: on_success
|
||||
|
||||
# Lassen uses a different job scheduler (spectrum lsf) that does not allow
|
||||
# pre-allocation the same way slurm does. We use the pci queue on lassen
|
||||
# to speed-up the allocation.
|
||||
# pre-allocation the same way slurm does. We use pdebug queue on lassen
|
||||
# to speed-up the allocation. However this would not be scalable to
|
||||
# multiple builds.
|
||||
.build_and_test_on_lassen:
|
||||
extends: [.on_lassen]
|
||||
stage: build_and_test
|
||||
@@ -44,5 +45,5 @@ variables:
|
||||
- echo ${MFEM_DATA_DIR}
|
||||
- echo ${SPEC}
|
||||
# Next script uses 'THREADS': leaving it empty --> it uses 'make all -j'
|
||||
- lalloc 1 -W 45 -q pci --atsdisable tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
|
||||
- lalloc 1 -W 45 -q pdebug --atsdisable tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
|
||||
needs: [setup]
|
||||
|
||||
@@ -52,4 +52,4 @@ variables:
|
||||
- echo ${JOBID}
|
||||
- echo ${MFEM_DATA_DIR}
|
||||
- echo ${SPEC}
|
||||
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) --reservation=ci -t 45 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
|
||||
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 45 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
|
||||
|
||||
@@ -14,14 +14,14 @@ stages:
|
||||
- build_and_test
|
||||
- report
|
||||
|
||||
opt_mpi_cuda_gcc:
|
||||
opt_mpi_cuda_xl_16_1_1_12:
|
||||
variables:
|
||||
SPEC: "%gcc@8.3.1 +mpi +cuda cuda_arch=70"
|
||||
SPEC: "%xl@16.1.1.12 +mpi +cuda cuda_arch=70"
|
||||
extends: .build_and_test_on_lassen
|
||||
|
||||
opt_mpi_cuda_hypre_cuda_gcc:
|
||||
opt_mpi_cuda_hypre_cuda_xl:
|
||||
variables:
|
||||
SPEC: "%gcc@8.3.1 +mpi +cuda cuda_arch=70 ^hypre+cuda~shared cuda_arch=70"
|
||||
SPEC: "%xl@16.1.1.12 +mpi +cuda cuda_arch=70 ^hypre+cuda~shared cuda_arch=70"
|
||||
extends: .build_and_test_on_lassen
|
||||
|
||||
# Jobs report
|
||||
|
||||
@@ -32,11 +32,11 @@ mkdir _${BASELINE_TEST} && cd _${BASELINE_TEST}
|
||||
|
||||
# run
|
||||
if [[ "${MACHINE_NAME}" == "quartz" || "${MACHINE_NAME}" == "ruby" ]]; then
|
||||
salloc --nodes=1 --reservation=ci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
salloc --nodes=1 -p pdebug ../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
|
||||
lalloc 1 -q pci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
lalloc 1 -q pdebug ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
else
|
||||
echo "Unknown machine: MACHINE_NAME=$MACHINE_NAME"
|
||||
exit 1
|
||||
|
||||
@@ -8,112 +8,74 @@
|
||||
https://mfem.org
|
||||
|
||||
|
||||
Version 4.7.1 (development)
|
||||
Version 4.6.1 (development)
|
||||
===========================
|
||||
|
||||
- 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
|
||||
====================================
|
||||
|
||||
- Added support for single precision (with corresponding hypre build). The MFEM
|
||||
floating point type was generalized from `double` to `real_t`. For details see
|
||||
https://github.com/orgs/mfem/discussions/4207.
|
||||
|
||||
Meshing improvements
|
||||
--------------------
|
||||
- Added the capability to partition (big) serial meshes in serial code, see the
|
||||
new classes MeshPartitioner and MeshPart. This capability is also exposed as a
|
||||
menu option in the mesh-explorer miniapp in miniapps/meshing.
|
||||
|
||||
- Added named attribute sets and basic supporting methods to the Mesh class as a
|
||||
convenient means of referring to sets of domain or boundary attribute numbers.
|
||||
See the new Example 39/39p and data/compass.mesh.
|
||||
|
||||
- Introduced formulas for refinement of patches in NURBS meshes. Refinement by
|
||||
arbitrary integer factors is also enabled, e.g. in the mesh-explorer miniapp.
|
||||
NURBS coarsening and knot removal are also introduced.
|
||||
|
||||
- Added support for internal boundary elements in nonconforming meshes.
|
||||
|
||||
- The ReadCubit Genesis mesh importer has been rewritten to improve readability.
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
- Added a new nonlinear integrator, `HyperbolicFormIntegrator` that implements
|
||||
- Introduced support for higher order non conformal Nedelec elements on
|
||||
simplices in ParMesh.
|
||||
- Introduced support for internal boundary elements in nonconformal adapted
|
||||
meshes.
|
||||
|
||||
- Added functionality for construction of cut-surface and cut-volume
|
||||
IntegrationRules through a moment-fitting approach. The cut is specified by
|
||||
the zero level set of a Coefficient. See fem/intrules_cut.hpp and Example 38.
|
||||
|
||||
- Added a new nonlinear integrator, `HyperbolicFormIntegrator`. This implements
|
||||
both element-wise weak divergence and face-wise numerical flux for a general
|
||||
system of hyperbolic conservation laws. To use the integrator for a specific
|
||||
system of hyperbolic conservation laws. To use this integrator for a specific
|
||||
flux function, users can define a derived class of `FluxFunction`. Currently,
|
||||
advection, Burgers, shallow-water and Euler equations (see Example 18/18p) are
|
||||
advection, Burgers', shallow-water, Euler equations (see, Example 18) are
|
||||
available.
|
||||
|
||||
- Added a capability to construct cut-surface and cut-volume IntegrationRules
|
||||
through a moment-fitting approach. The cut is specified by the zero level set
|
||||
of a Coefficient. See fem/intrules_cut.hpp and the new Example 38.
|
||||
|
||||
- Introduced support for high-order nonconforming Nedelec elements on simplices.
|
||||
|
||||
GPU computing
|
||||
-------------
|
||||
- Added partial assembly and GPU support for the DG diffusion integrator.
|
||||
|
||||
- Efficient GPU-accelerated LOR assembly is now supported on surface meshes.
|
||||
|
||||
- Added functionality to automatically configure hypre's compute policy to match
|
||||
MFEM's compute policy when hypre is built with GPU support. Requires version
|
||||
hypre-2.31.0 or later.
|
||||
|
||||
GPU support
|
||||
----------------------------
|
||||
- Added support for full assembly on simplices.
|
||||
|
||||
- Added partial assembly for linear elasticity (no sum factorization for now).
|
||||
|
||||
- Added functionality for BilinearFormIntegrators to use kernels that work for
|
||||
both tensor and unstructured elements.
|
||||
|
||||
- The RAJA backend will use `seq_exec` for serial loop execution when RAJA
|
||||
v2023.06.00 and beyond is detected as `loop_exec` is deprecated.
|
||||
|
||||
- API change: The macro MFEM_HYPRE_FORALL (from hypre.hpp) which was intended
|
||||
for internal use, has been removed and replaced by the function template
|
||||
mfem::hypre_forall in general/forall.hpp.
|
||||
- Added functionality for BilinearFormIntegrators to use kernels that work for both
|
||||
tensor and unstructured elements.
|
||||
- Added partial assembly for linear elasticity. Does not use sum factorization for now.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- Added a new miniapp illustrating elastic contact based on the Tribol library,
|
||||
(https://github.com/LLNL/Tribol). See miniapps/tribol.
|
||||
- Added a new block solver in miniapp/solvers for the Darcy problem.
|
||||
The new solver is based on a Bramble-Pasciak preconditioning. User can
|
||||
use and implement their own preconditioner for the mass matrix.
|
||||
|
||||
- Added a miniapp to demonstrate low order refined (LOR) block preconditioning
|
||||
for linear elasticity on GPUs. See miniapps/solvers/lor_elast.
|
||||
|
||||
- Added a new block solver in miniapp/solvers for the Darcy problem. The new
|
||||
solver is based on a Bramble-Pasciak preconditioning. User can use and
|
||||
implement their own preconditioner for the mass matrix.
|
||||
|
||||
- Added a small miniapp for printing the shape functions of a KnotVector. See
|
||||
miniapps/nurbs/nurbs_printfunc.cpp.
|
||||
|
||||
- Added two new example codes: 38 and 39/39p described above. Substantially
|
||||
updated Example 18/18p.
|
||||
- Added miniapp to demonstrate new elasticity integrator and unstructured element GPU support,
|
||||
and a block diagonal preconditioner using low order refinement. Allows comparison with
|
||||
currently existing legacy mode integrator. See miniapps/solvers/lor_elast.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- Added support for single and double precision, with corresponding hypre build.
|
||||
Generalized the floating point type from `double` to `real_t`. For more
|
||||
details see https://github.com/orgs/mfem/discussions/4207.
|
||||
|
||||
- The ReadCubit Genesis mesh importer has been rewritten to improve readability.
|
||||
|
||||
- Updated the Doxygen documentation style, which now requires Doxygen version
|
||||
1.9.8 or later. See the doc/ directory.
|
||||
|
||||
- Improved thread safety for global variables in the library, e.g. for IntRules,
|
||||
RefinedIntRules, GlobGeometryRefiner, and FiniteElement::dof2quad_array.
|
||||
- Improved thread safety for global variables in the library, for example
|
||||
IntegrationRules IntRules, RefinedIntRules, GeometryRefiner
|
||||
GlobGeometryRefiner, and FiniteElement::dof2quad_array.
|
||||
|
||||
- PETSc integration now generally requires PETSc version 3.21 or later, though
|
||||
depending on the functionality older versions may still work.
|
||||
|
||||
- Various other simplifications, extensions, and bugfixes in the code.
|
||||
|
||||
- Added GSLIB-based gather-scatter operator.
|
||||
- RAJA backend will use seq_exec for serial loop execution when RAJA
|
||||
v2023.06.00 and beyond is detected as loop_exec is deprecated.
|
||||
|
||||
- Adding named attribute sets and basic supporting methods to the Mesh class as
|
||||
a convenient means of referring to sets of domain or boundary attribute
|
||||
numbers. Also adding related serial and parallel examples which illustrate.
|
||||
|
||||
Version 4.6, released on September 27, 2023
|
||||
===========================================
|
||||
@@ -134,6 +96,7 @@ Meshing improvements
|
||||
* The edge to knot map for NURBS meshes can be determined automatically. It is
|
||||
no longer needed to specify this in the NURBS mesh.
|
||||
* Added curve interpolation method for NURBS.
|
||||
* Added new small miniapp for printing of shape functions of a KnotVector
|
||||
* See miniapps/nurbs for example meshes and miniapps.
|
||||
|
||||
Discretization improvements
|
||||
@@ -180,6 +143,8 @@ Linear and nonlinear solvers
|
||||
|
||||
- Added HIP support to the PETSc and SUNDIALS interfaces.
|
||||
|
||||
- Efficient GPU-accelerated LOR assembly now supports surface meshes.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- Added a new H(div) solver miniapp demonstrating the use of a matrix-free
|
||||
|
||||
+3
-13
@@ -58,7 +58,7 @@ project(mfem NONE)
|
||||
# Current version of MFEM, see also `makefile`.
|
||||
# mfem_VERSION = (string)
|
||||
# MFEM_VERSION = (int) [automatically derived from mfem_VERSION]
|
||||
set(${PROJECT_NAME}_VERSION 4.7.1)
|
||||
set(${PROJECT_NAME}_VERSION 4.6.1)
|
||||
|
||||
# Prohibit in-source build
|
||||
if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR})
|
||||
@@ -87,11 +87,10 @@ if (MFEM_USE_STRUMPACK OR MFEM_USE_MUMPS)
|
||||
# Just needed to find the MPI_Fortran libraries to link with
|
||||
set(XSDK_ENABLE_Fortran ON)
|
||||
endif()
|
||||
# SUNDIALS, STRUMPACK, Ginkgo, Tribol, RAJA and Umpire require C++14:
|
||||
# SUNDIALS, STRUMPACK, Ginkgo, RAJA and Umpire require C++14:
|
||||
if ((MFEM_USE_SUNDIALS OR
|
||||
MFEM_USE_STRUMPACK OR
|
||||
MFEM_USE_GINKGO OR
|
||||
MFEM_USE_TRIBOL OR
|
||||
MFEM_USE_RAJA OR
|
||||
MFEM_USE_UMPIRE) AND
|
||||
("${CMAKE_CXX_STANDARD}" LESS "14"))
|
||||
@@ -504,15 +503,6 @@ if (MFEM_USE_PARELAG)
|
||||
find_package(PARELAG REQUIRED)
|
||||
endif()
|
||||
|
||||
# Tribol
|
||||
if (MFEM_USE_TRIBOL)
|
||||
if (MFEM_USE_MPI)
|
||||
find_package(Tribol REQUIRED tribol redecomp)
|
||||
else()
|
||||
message(FATAL_ERROR " *** Tribol requires that MPI be enabled.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Enzyme
|
||||
if (MFEM_USE_ENZYME)
|
||||
find_package(ENZYME REQUIRED)
|
||||
@@ -558,7 +548,7 @@ set(MFEM_TPLS OPENMP HYPRE LAPACK BLAS SuperLUDist STRUMPACK METIS SuiteSparse
|
||||
SUNDIALS PETSC SLEPC MUMPS AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB
|
||||
NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
|
||||
ADIOS2 CUSPARSE MKL_CPARDISO MKL_PARDISO AMGX CALIPER CODIPACK
|
||||
BENCHMARK PARELAG TRIBOL MPI_CXX HIP HIPSPARSE MOONOLITH BLITZ ALGOIM ENZYME)
|
||||
BENCHMARK PARELAG MPI_CXX HIP HIPSPARSE MOONOLITH BLITZ ALGOIM ENZYME)
|
||||
|
||||
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
|
||||
set(TPL_LIBRARIES "")
|
||||
|
||||
+1
-2
@@ -151,8 +151,7 @@ The MFEM source code has the following structure:
|
||||
│ ├── solvers
|
||||
│ ├── spde
|
||||
│ ├── tools
|
||||
│ ├── toys
|
||||
│ └── tribol
|
||||
│ └── toys
|
||||
└── tests
|
||||
├── benchmarks
|
||||
├── convergence
|
||||
|
||||
@@ -75,8 +75,6 @@ and miniapps. See https://glvis.org and https://mfem.org/building.
|
||||
|
||||
Quick start with GNU make
|
||||
=========================
|
||||
See also: https://mfem.org/building
|
||||
|
||||
Serial build:
|
||||
make serial -j 4
|
||||
|
||||
@@ -85,7 +83,6 @@ Parallel build:
|
||||
(build METIS 4 in ../metis-4.0 relative to mfem/)
|
||||
(build hypre in ../hypre relative to mfem/)
|
||||
make parallel -j 4
|
||||
(For METIS 5, see https://mfem.org/building/#parallel-build-using-metis-5)
|
||||
|
||||
CUDA build:
|
||||
make cuda -j 4
|
||||
@@ -119,7 +116,6 @@ Parallel build:
|
||||
mkdir <mfem-build-dir> ; cd <mfem-build-dir>
|
||||
cmake <mfem-source-dir> -DMFEM_USE_MPI=YES
|
||||
make -j 4
|
||||
(For METIS 5, see https://mfem.org/building/#parallel-build-using-metis-5)
|
||||
|
||||
CUDA build:
|
||||
(this build requires CMake 3.8 or newer)
|
||||
@@ -575,11 +571,6 @@ MFEM_USE_PARELAG = YES/NO
|
||||
use ParELAG. In fact, ParELAG is dependent on MFEM. Therefore, this option
|
||||
currently only concerns the miniapps.
|
||||
|
||||
MFEM_USE_TRIBOL = YES/NO
|
||||
Enables the miniapps that use the Tribol library. MFEM does not currently
|
||||
use Tribol. In fact, Tribol is dependent on MFEM. Therefore, this option
|
||||
currently only concerns the miniapps.
|
||||
|
||||
MFEM_USE_ENZYME = YES/NO
|
||||
Enables automatic differentiation support through the LLVM plugin Enzyme.
|
||||
This requires the compiler to be set to clang (>=14.0.0). We also advise to
|
||||
@@ -616,13 +607,9 @@ The specific libraries and their options are:
|
||||
HYPRE >= 2.20.0 (HYPRE built with '--enable-mixedint')
|
||||
HYPRE >= 2.22.1 (HYPRE built with CUDA)
|
||||
HYPRE >= 2.23.0 (HYPRE built with HIP)
|
||||
HYPRE >= 2.31.0 (runtime selectable HYPRE execution on CPU/GPU)
|
||||
|
||||
- METIS, used when MFEM_USE_METIS = YES. If using METIS 5, set
|
||||
MFEM_USE_METIS_5 = YES (default is to use METIS 4). For building instructions,
|
||||
see the following:
|
||||
- METIS 4.0.3: https://mfem.org/building/#parallel-mpi-version-of-mfem
|
||||
- METIS 5.1.0: https://mfem.org/building/#parallel-build-using-metis-5
|
||||
MFEM_USE_METIS_5 = YES (default is to use METIS 4).
|
||||
URL: https://github.com/mfem/tpls (MFEM mirror, see above)
|
||||
Options: METIS_OPT, METIS_LIB.
|
||||
Versions: METIS 4.0.3 or 5.1.0.
|
||||
@@ -870,10 +857,6 @@ The specific libraries and their options are:
|
||||
URL: https://github.com/LLNL/parelag
|
||||
Options: PARELAG_DIR, PARELAG_OPT, PARELAG_LIB.
|
||||
|
||||
- Tribol, used when MFEM_USE_TRIBOL = YES.
|
||||
URL: https://github.com/LLNL/Tribol
|
||||
Options: TRIBOL_DIR, TRIBOL_OPT, TRIBOL_LIB.
|
||||
|
||||
- Enzyme, used when MFEM_USE_ENZYME = YES. Requires LLVM/Clang >= 14.0.0.
|
||||
URL: https://github.com/EnzymeAD/Enzyme
|
||||
Options: ENZYME_DIR, ENZYME_OPT, ENZYME_LIB.
|
||||
@@ -1018,7 +1001,6 @@ MFEM_USE_CALIPER
|
||||
MFEM_USE_FMS
|
||||
MFEM_USE_BENCHMARK
|
||||
MFEM_USE_PARELAG
|
||||
MFEM_USE_TRIBOL
|
||||
MFEM_USE_ENZYME
|
||||
|
||||
The following options are CMake specific:
|
||||
|
||||
@@ -287,7 +287,3 @@ ENDIF()
|
||||
IF (DEFINED TPL_ENABLE_PARELAG)
|
||||
SET(MFEM_USE_PARELAG ${TPL_ENABLE_PARELAG} CACHE BOOL "Enable ParELAG" FORCE)
|
||||
ENDIF()
|
||||
|
||||
IF (DEFINED TPL_ENABLE_TRIBOL)
|
||||
SET(MFEM_USE_TRIBOL ${TPL_ENABLE_TRIBOL} CACHE BOOL "Enable Tribol" FORCE)
|
||||
ENDIF()
|
||||
|
||||
@@ -64,7 +64,6 @@ set(MFEM_USE_CALIPER @MFEM_USE_CALIPER@)
|
||||
set(MFEM_USE_ALGOIM @MFEM_USE_ALGOIM@)
|
||||
set(MFEM_USE_BENCHMARK @MFEM_USE_BENCHMARK@)
|
||||
set(MFEM_USE_PARELAG @MFEM_USE_PARELAG@)
|
||||
set(MFEM_USE_TRIBOL @MFEM_USE_TRIBOL@)
|
||||
set(MFEM_USE_ENZYME @MFEM_USE_ENZYME@)
|
||||
|
||||
set(MFEM_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
|
||||
|
||||
@@ -18,13 +18,4 @@ include(MfemCmakeUtilities)
|
||||
# Note: components are enabled based on the find_package() parameters.
|
||||
mfem_find_package(Axom AXOM AXOM_DIR "include" "" "lib" ""
|
||||
"Paths to headers required by Axom." "Libraries required by Axom."
|
||||
ADD_COMPONENT core "include" axom/core.hpp "lib" axom_core
|
||||
ADD_COMPONENT inlet "include" axom/inlet.hpp "lib" axom_inlet
|
||||
ADD_COMPONENT klee "include" axom/klee.hpp "lib" axom_klee
|
||||
ADD_COMPONENT lumberjack "include" axom/lumberjack.hpp "lib" axom_lumberjack
|
||||
ADD_COMPONENT mint "include" axom/mint.hpp "lib" axom_mint
|
||||
ADD_COMPONENT multimat "include" axom/multimat.hpp "lib" axom_multimat
|
||||
ADD_COMPONENT quest "include" axom/quest.hpp "lib" axom_quest
|
||||
ADD_COMPONENT sidre "include" axom/sidre.hpp "lib" axom_sidre
|
||||
ADD_COMPONENT slam "include" axom/slam.hpp "lib" axom_slam
|
||||
ADD_COMPONENT slic "include" axom/slic.hpp "lib" axom_slic)
|
||||
ADD_COMPONENT Axom "include" axom/config.hpp "lib" axom)
|
||||
|
||||
@@ -36,11 +36,7 @@ include(MfemCmakeUtilities)
|
||||
mfem_find_package(Conduit CONDUIT CONDUIT_DIR
|
||||
"include;include/conduit" conduit.hpp "lib" conduit
|
||||
"Paths to headers required by Conduit." "Libraries required by Conduit."
|
||||
ADD_COMPONENT blueprint
|
||||
"include;include/conduit" conduit_blueprint.hpp "lib" conduit_blueprint
|
||||
ADD_COMPONENT blueprint_mpi
|
||||
"include;include/conduit" conduit_blueprint_mpi.hpp "lib" conduit_blueprint_mpi
|
||||
ADD_COMPONENT relay
|
||||
"include;include/conduit" conduit_relay.hpp "lib" conduit_relay
|
||||
ADD_COMPONENT relay_mpi
|
||||
"include;include/conduit" conduit_relay_mpi.hpp "lib" conduit_relay_mpi)
|
||||
ADD_COMPONENT blueprint
|
||||
"include;include/conduit" conduit_blueprint.hpp "lib" conduit_blueprint)
|
||||
|
||||
@@ -16,22 +16,12 @@
|
||||
# - MUMPS_VERSION
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
|
||||
# Toggle which precision of MUMPS to use depending on the precision of MFEM.
|
||||
if (MFEM_USE_DOUBLE)
|
||||
set(_mumps_header dmumps_c.h)
|
||||
set(_mumps_lib dmumps)
|
||||
elseif(MFEM_USE_SINGLE)
|
||||
set(_mumps_header smumps_c.h)
|
||||
set(_mumps_lib smumps)
|
||||
endif()
|
||||
|
||||
mfem_find_package(MUMPS MUMPS MUMPS_DIR
|
||||
"include" ${_mumps_header} "lib" ${_mumps_lib}
|
||||
"include" dmumps_c.h "lib" dmumps
|
||||
"Paths to headers required by MUMPS."
|
||||
"Libraries required by MUMPS."
|
||||
ADD_COMPONENT mumps_common "include" ${_mumps_header} "lib" mumps_common
|
||||
ADD_COMPONENT pord "include" ${_mumps_header} "lib" pord)
|
||||
ADD_COMPONENT mumps_common "include" dmumps_c.h "lib" mumps_common
|
||||
ADD_COMPONENT pord "include" dmumps_c.h "lib" pord)
|
||||
|
||||
if (MUMPS_FOUND AND (NOT MUMPS_VERSION))
|
||||
try_run(MUMPS_VERSION_RUN_RESULT MUMPS_VERSION_COMPILE_RESULT
|
||||
|
||||
@@ -1,22 +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.
|
||||
|
||||
# Defines the following variables:
|
||||
# - TRIBOL_FOUND
|
||||
# - TRIBOL_LIBRARIES
|
||||
# - TRIBOL_INCLUDE_DIRS
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
# Note: components are enabled based on the find_package() parameters.
|
||||
mfem_find_package(Tribol TRIBOL TRIBOL_DIR "include" tribol/config.hpp "lib" tribol
|
||||
"Paths to headers required by Tribol." "Libraries required by Tribol."
|
||||
ADD_COMPONENT redecomp
|
||||
"include" redecomp/redecomp.hpp "lib" redecomp)
|
||||
@@ -852,8 +852,8 @@ function(mfem_export_mk_files)
|
||||
MFEM_USE_CUDA MFEM_USE_HIP MFEM_USE_RAJA MFEM_USE_OCCA MFEM_USE_CEED
|
||||
MFEM_USE_CALIPER MFEM_USE_UMPIRE MFEM_USE_SIMD MFEM_USE_ADIOS2
|
||||
MFEM_USE_MKL_CPARDISO MFEM_USE_MKL_PARDISO MFEM_USE_ADFORWARD
|
||||
MFEM_USE_CODIPACK MFEM_USE_BENCHMARK MFEM_USE_PARELAG MFEM_USE_TRIBOL
|
||||
MFEM_USE_MOONOLITH MFEM_USE_ALGOIM MFEM_USE_ENZYME)
|
||||
MFEM_USE_CODIPACK MFEM_USE_BENCHMARK MFEM_USE_PARELAG MFEM_USE_MOONOLITH
|
||||
MFEM_USE_ALGOIM MFEM_USE_ENZYME)
|
||||
foreach(var ${CONFIG_MK_BOOL_VARS})
|
||||
if (${var})
|
||||
set(${var} YES)
|
||||
|
||||
@@ -120,15 +120,6 @@ constexpr real_t operator""_r(unsigned long long v)
|
||||
|
||||
// Check dependencies:
|
||||
|
||||
// Define MFEM_MPI_REAL_T to be the appropriate MPI real type
|
||||
#ifdef MFEM_USE_MPI
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
#define MFEM_MPI_REAL_T MPI_FLOAT
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
#define MFEM_MPI_REAL_T MPI_DOUBLE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Options that require MPI
|
||||
#ifndef MFEM_USE_MPI
|
||||
#ifdef MFEM_USE_SUPERLU
|
||||
|
||||
@@ -65,7 +65,6 @@ MFEM_USE_ADFORWARD = @MFEM_USE_ADFORWARD@
|
||||
MFEM_USE_CODIPACK = @MFEM_USE_CODIPACK@
|
||||
MFEM_USE_BENCHMARK = @MFEM_USE_BENCHMARK@
|
||||
MFEM_USE_PARELAG = @MFEM_USE_PARELAG@
|
||||
MFEM_USE_TRIBOL = @MFEM_USE_TRIBOL@
|
||||
MFEM_USE_ENZYME = @MFEM_USE_ENZYME@
|
||||
|
||||
# Compiler, compile options, and link options
|
||||
|
||||
+2
-14
@@ -67,7 +67,6 @@ option(MFEM_USE_ADFORWARD "Enable forward mode for AD" OFF)
|
||||
option(MFEM_USE_CODIPACK "Enable automatic differentiation (AD) using CoDiPack" OFF)
|
||||
option(MFEM_USE_BENCHMARK "Enable Google Benchmark" OFF)
|
||||
option(MFEM_USE_PARELAG "Enable ParELAG" OFF)
|
||||
option(MFEM_USE_TRIBOL "Enable Tribol" OFF)
|
||||
option(MFEM_USE_ENZYME "Enable Enzyme" OFF)
|
||||
|
||||
# Optional overrides for autodetected MPIEXEC and MPIEXEC_NUMPROC_FLAG
|
||||
@@ -213,15 +212,8 @@ set(CONDUIT_DIR "${MFEM_DIR}/../conduit" CACHE PATH
|
||||
|
||||
set(AXOM_DIR "${MFEM_DIR}/../axom" CACHE PATH "Path to the Axom library.")
|
||||
# May need to add "Boost" as requirement.
|
||||
if (MFEM_USE_SIDRE)
|
||||
if (MFEM_USE_MPI)
|
||||
set(Axom_REQUIRED_PACKAGES "Conduit/blueprint/blueprint_mpi/relay/relay_mpi" CACHE STRING
|
||||
"Additional packages required by Axom.")
|
||||
elseif()
|
||||
set(Axom_REQUIRED_PACKAGES "Conduit/blueprint/relay" CACHE STRING
|
||||
"Additional packages required by Axom.")
|
||||
endif()
|
||||
endif()
|
||||
set(Axom_REQUIRED_PACKAGES "Conduit/relay/blueprint" CACHE STRING
|
||||
"Additional packages required by Axom.")
|
||||
|
||||
set(PUMI_DIR "${MFEM_DIR}/../pumi-2.1.0" CACHE STRING
|
||||
"Directory where PUMI is installed")
|
||||
@@ -258,10 +250,6 @@ set(PARELAG_INCLUDE_DIRS "${PARELAG_DIR}/src;${PARELAG_DIR}/build/src" CACHE
|
||||
set(PARELAG_LIBRARIES "${PARELAG_DIR}/build/src/libParELAG.a" CACHE STRING
|
||||
"The ParELAG library.")
|
||||
|
||||
set(TRIBOL_DIR "${MFEM_DIR}/../tribol" CACHE PATH "Path to Tribol")
|
||||
set(Tribol_REQUIRED_PACKAGES "Axom/core/mint/slam/slic" CACHE STRING
|
||||
"Additional packages required by Tribol")
|
||||
|
||||
set(BLAS_INCLUDE_DIRS "" CACHE STRING "Path to BLAS headers.")
|
||||
set(BLAS_LIBRARIES "" CACHE STRING "The BLAS library.")
|
||||
set(LAPACK_INCLUDE_DIRS "" CACHE STRING "Path to LAPACK headers.")
|
||||
|
||||
+3
-26
@@ -167,21 +167,8 @@ MFEM_USE_ADFORWARD = NO
|
||||
MFEM_USE_CODIPACK = NO
|
||||
MFEM_USE_BENCHMARK = NO
|
||||
MFEM_USE_PARELAG = NO
|
||||
MFEM_USE_TRIBOL = NO
|
||||
MFEM_USE_ENZYME = NO
|
||||
|
||||
# Process MFEM_PRECISION -> MFEM_USE_SINGLE, MFEM_USE_DOUBLE
|
||||
ifneq ($(filter double Double DOUBLE,$(MFEM_PRECISION)),)
|
||||
MFEM_USE_DOUBLE = YES
|
||||
MFEM_USE_SINGLE = NO
|
||||
else ifneq ($(filter single Single SINGLE,$(MFEM_PRECISION)),)
|
||||
MFEM_USE_DOUBLE = NO
|
||||
MFEM_USE_SINGLE = YES
|
||||
else ifeq ($(MAKECMDGOALS),config)
|
||||
$(error Invalid floating-point precision: \
|
||||
MFEM_PRECISION = $(MFEM_PRECISION))
|
||||
endif
|
||||
|
||||
# MPI library compile and link flags
|
||||
# These settings are used only when building MFEM with MPI + HIP
|
||||
ifeq ($(MFEM_USE_MPI)$(MFEM_USE_HIP),YESYES)
|
||||
@@ -331,13 +318,13 @@ MPI_FORTRAN_LIB = -lmpifort
|
||||
# MUMPS library configuration
|
||||
MUMPS_DIR = @MFEM_DIR@/../MUMPS_5.5.0
|
||||
MUMPS_OPT = -I$(MUMPS_DIR)/include
|
||||
MUMPS_LIB = $(XLINKER)-rpath,$(MUMPS_DIR)/lib -L$(MUMPS_DIR)/lib
|
||||
MUMPS_LIB = $(XLINKER)-rpath,$(MUMPS_DIR)/lib -L$(MUMPS_DIR)/lib \
|
||||
-lmumps_common -lpord $(SCALAPACK_LIB) $(LAPACK_LIB) $(MPI_FORTRAN_LIB)
|
||||
ifeq ($(MFEM_USE_SINGLE),YES)
|
||||
MUMPS_LIB += -lsmumps
|
||||
else
|
||||
MUMPS_LIB += -ldmumps
|
||||
endif
|
||||
MUMPS_LIB += -lmumps_common -lpord $(SCALAPACK_LIB) $(LAPACK_LIB) $(MPI_FORTRAN_LIB)
|
||||
|
||||
# STRUMPACK library configuration
|
||||
STRUMPACK_DIR = @MFEM_DIR@/../STRUMPACK-build
|
||||
@@ -388,7 +375,7 @@ GINKGO_LIB = $(XLINKER)-rpath,$(GINKGO_LINK_LIB_DIR) -L$(GINKGO_LINK_LIB_DIR)\
|
||||
# AmgX library configuration
|
||||
AMGX_DIR = @MFEM_DIR@/../amgx
|
||||
AMGX_OPT = -I$(AMGX_DIR)/include
|
||||
AMGX_LIB = -L$(AMGX_DIR)/lib -lamgx -lcusparse -lcusolver -lcublas -lnvToolsExt
|
||||
AMGX_LIB = -lcusparse -lcusolver -lcublas -lnvToolsExt -L$(AMGX_DIR)/lib -lamgx
|
||||
|
||||
# GnuTLS library configuration
|
||||
GNUTLS_OPT =
|
||||
@@ -589,16 +576,6 @@ PARELAG_DIR = @MFEM_DIR@/../parelag
|
||||
PARELAG_OPT = -I$(PARELAG_DIR)/src -I$(PARELAG_DIR)/build/src
|
||||
PARELAG_LIB = -L$(PARELAG_DIR)/build/src -lParELAG
|
||||
|
||||
# Tribol library configuration
|
||||
ifeq ($(MFEM_USE_TRIBOL),YES)
|
||||
BASE_FLAGS = -std=c++14
|
||||
endif
|
||||
AXOM_DIR = @MFEM_DIR@/../axom
|
||||
TRIBOL_DIR = @MFEM_DIR@/../tribol
|
||||
TRIBOL_OPT = -I$(TRIBOL_DIR)/include -I$(AXOM_DIR)/include
|
||||
TRIBOL_LIB = -L$(TRIBOL_DIR)/lib -ltribol -lredecomp -L$(AXOM_DIR)/lib -laxom_mint\
|
||||
-laxom_slam -laxom_slic -laxom_core
|
||||
|
||||
# Enzyme configuration
|
||||
|
||||
# If you want to enable automatic differentiation at compile time, use the
|
||||
|
||||
+1
-1
@@ -110,4 +110,4 @@ config-mk:
|
||||
|
||||
clean:
|
||||
rm -f $(CONFIG_HPP) $(CONFIG_MK) sample-runs-build.log
|
||||
rm -f $(GHV) $(GHV).out $(GMV) $(GMV).out *.dSYM
|
||||
rm -f $(GHV) $(GHV).out $(GMV) $(GMV).out
|
||||
|
||||
@@ -92,5 +92,4 @@ vertices
|
||||
-0.70710678 -0.70710678
|
||||
0 -1
|
||||
0.70710678 -0.70710678
|
||||
|
||||
mfem_mesh_end
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
dimension
|
||||
4
|
||||
|
||||
elements
|
||||
24
|
||||
1 7 4 5 8 11 13
|
||||
1 7 1 4 5 7 8
|
||||
1 7 1 4 5 8 11
|
||||
1 7 1 5 8 11 13
|
||||
1 7 1 5 7 8 13
|
||||
1 7 4 5 7 8 13
|
||||
1 7 1 3 4 8 11
|
||||
1 7 1 3 4 5 11
|
||||
1 7 1 5 10 11 13
|
||||
1 7 1 8 10 11 13
|
||||
1 7 1 3 5 10 11
|
||||
1 7 1 2 3 5 10
|
||||
1 7 0 1 3 4 8
|
||||
1 7 0 1 4 7 8
|
||||
1 7 1 5 6 7 13
|
||||
1 7 1 6 7 8 13
|
||||
1 7 6 7 8 13 15
|
||||
1 7 4 7 8 13 15
|
||||
1 7 4 8 12 13 15
|
||||
1 7 4 8 11 12 13
|
||||
1 7 6 8 13 14 15
|
||||
1 7 1 6 8 13 14
|
||||
1 7 1 8 9 10 13
|
||||
1 7 1 8 9 13 14
|
||||
|
||||
boundary
|
||||
48
|
||||
1 4 0 1 3 4
|
||||
1 4 0 1 3 8
|
||||
1 4 0 3 4 8
|
||||
1 4 0 1 4 7
|
||||
1 4 0 1 7 8
|
||||
1 4 0 4 7 8
|
||||
1 4 1 4 5 7
|
||||
1 4 1 3 8 11
|
||||
1 4 1 3 4 5
|
||||
1 4 1 5 10 13
|
||||
1 4 1 8 10 11
|
||||
1 4 1 3 10 11
|
||||
1 4 1 2 3 5
|
||||
1 4 1 2 3 10
|
||||
1 4 1 2 5 10
|
||||
1 4 1 5 6 7
|
||||
1 4 1 5 6 13
|
||||
1 4 1 6 7 8
|
||||
1 4 1 6 8 14
|
||||
1 4 1 6 13 14
|
||||
1 4 1 8 9 10
|
||||
1 4 1 9 10 13
|
||||
1 4 1 8 9 14
|
||||
1 4 1 9 13 14
|
||||
1 4 2 3 5 10
|
||||
1 4 3 4 8 11
|
||||
1 4 3 4 5 11
|
||||
1 4 3 5 10 11
|
||||
1 4 4 5 11 13
|
||||
1 4 4 5 7 13
|
||||
1 4 4 7 8 15
|
||||
1 4 4 7 13 15
|
||||
1 4 4 8 12 15
|
||||
1 4 4 12 13 15
|
||||
1 4 4 8 11 12
|
||||
1 4 4 11 12 13
|
||||
1 4 5 10 11 13
|
||||
1 4 5 6 7 13
|
||||
1 4 6 7 8 15
|
||||
1 4 6 7 13 15
|
||||
1 4 6 8 14 15
|
||||
1 4 6 13 14 15
|
||||
2 4 8 10 11 13
|
||||
2 4 8 12 13 15
|
||||
2 4 8 11 12 13
|
||||
2 4 8 13 14 15
|
||||
2 4 8 9 10 13
|
||||
2 4 8 9 13 14
|
||||
|
||||
vertices
|
||||
16
|
||||
4
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
@@ -1,102 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
dimension
|
||||
4
|
||||
|
||||
elements
|
||||
24
|
||||
17 8 4 5 8 11 13
|
||||
11 8 1 4 5 7 8
|
||||
15 8 1 4 5 8 11
|
||||
16 8 1 5 8 11 13
|
||||
12 8 1 5 7 8 13
|
||||
13 8 4 5 7 8 13
|
||||
7 8 1 3 4 8 11
|
||||
2 8 1 3 4 5 11
|
||||
4 8 1 5 10 11 13
|
||||
10 8 1 8 10 11 13
|
||||
3 8 1 3 5 10 11
|
||||
1 8 1 2 3 5 10
|
||||
6 8 0 1 3 4 8
|
||||
8 8 0 1 4 7 8
|
||||
5 8 1 5 6 7 13
|
||||
20 8 1 6 7 8 13
|
||||
19 8 6 7 8 13 15
|
||||
14 8 4 7 8 13 15
|
||||
21 8 4 8 12 13 15
|
||||
22 8 4 8 11 12 13
|
||||
23 8 6 8 13 14 15
|
||||
24 8 1 6 8 13 14
|
||||
9 8 1 8 9 10 13
|
||||
18 8 1 8 9 13 14
|
||||
|
||||
boundary
|
||||
48
|
||||
1 4 0 1 3 4
|
||||
3 4 0 1 3 8
|
||||
3 4 0 3 4 8
|
||||
1 4 0 1 4 7
|
||||
3 4 0 1 7 8
|
||||
3 4 0 4 7 8
|
||||
1 4 1 4 5 7
|
||||
3 4 1 3 8 11
|
||||
1 4 1 3 4 5
|
||||
3 4 1 5 10 13
|
||||
3 4 1 8 10 11
|
||||
3 4 1 3 10 11
|
||||
1 4 1 2 3 5
|
||||
3 4 1 2 3 10
|
||||
3 4 1 2 5 10
|
||||
1 4 1 5 6 7
|
||||
3 4 1 5 6 13
|
||||
3 4 1 6 7 8
|
||||
3 4 1 6 8 14
|
||||
3 4 1 6 13 14
|
||||
3 4 1 8 9 10
|
||||
3 4 1 9 10 13
|
||||
3 4 1 8 9 14
|
||||
3 4 1 9 13 14
|
||||
3 4 2 3 5 10
|
||||
3 4 3 4 8 11
|
||||
3 4 3 4 5 11
|
||||
3 4 3 5 10 11
|
||||
3 4 4 5 11 13
|
||||
3 4 4 5 7 13
|
||||
3 4 4 7 8 15
|
||||
3 4 4 7 13 15
|
||||
3 4 4 8 12 15
|
||||
3 4 4 12 13 15
|
||||
3 4 4 8 11 12
|
||||
3 4 4 11 12 13
|
||||
3 4 5 10 11 13
|
||||
3 4 5 6 7 13
|
||||
3 4 6 7 8 15
|
||||
3 4 6 7 13 15
|
||||
3 4 6 8 14 15
|
||||
3 4 6 13 14 15
|
||||
5 4 8 10 11 13
|
||||
5 4 8 12 13 15
|
||||
5 4 8 11 12 13
|
||||
5 4 8 13 14 15
|
||||
5 4 8 9 10 13
|
||||
5 4 8 9 13 14
|
||||
|
||||
vertices
|
||||
16
|
||||
4
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
@@ -1,231 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
dimension
|
||||
4
|
||||
|
||||
elements
|
||||
96
|
||||
1 8 0 1 7 8 9
|
||||
1 8 1 6 7 8 9
|
||||
1 8 4 5 6 8 9
|
||||
1 8 4 6 7 8 9
|
||||
1 8 0 1 3 8 9
|
||||
1 8 1 2 3 8 9
|
||||
1 8 0 4 7 8 9
|
||||
1 8 0 3 4 8 9
|
||||
1 8 1 2 6 8 9
|
||||
1 8 2 5 6 8 9
|
||||
1 8 3 4 5 8 9
|
||||
1 8 2 3 5 8 9
|
||||
1 8 9 10 11 17 18
|
||||
1 8 9 11 16 17 18
|
||||
1 8 9 14 15 16 18
|
||||
1 8 9 14 16 17 18
|
||||
1 8 9 10 11 13 18
|
||||
1 8 9 11 12 13 18
|
||||
1 8 9 10 14 17 18
|
||||
1 8 9 10 13 14 18
|
||||
1 8 9 11 12 16 18
|
||||
1 8 9 12 15 16 18
|
||||
1 8 9 13 14 15 18
|
||||
1 8 9 12 13 15 18
|
||||
1 8 9 12 15 16 19
|
||||
1 8 9 11 12 16 19
|
||||
1 8 1 6 9 11 19
|
||||
1 8 6 9 11 16 19
|
||||
1 8 1 2 6 9 19
|
||||
1 8 2 5 6 9 19
|
||||
1 8 2 5 9 15 19
|
||||
1 8 2 9 12 15 19
|
||||
1 8 5 6 9 16 19
|
||||
1 8 5 9 15 16 19
|
||||
1 8 1 9 11 12 19
|
||||
1 8 1 2 9 12 19
|
||||
1 8 9 10 13 14 20
|
||||
1 8 9 10 14 17 20
|
||||
1 8 0 9 10 17 20
|
||||
1 8 0 7 9 17 20
|
||||
1 8 0 3 4 9 20
|
||||
1 8 0 4 7 9 20
|
||||
1 8 3 4 9 13 20
|
||||
1 8 4 9 13 14 20
|
||||
1 8 4 7 9 14 20
|
||||
1 8 7 9 14 17 20
|
||||
1 8 0 3 9 10 20
|
||||
1 8 3 9 10 13 20
|
||||
1 8 2 5 9 15 21
|
||||
1 8 2 9 12 15 21
|
||||
1 8 2 3 5 9 21
|
||||
1 8 3 4 5 9 21
|
||||
1 8 9 13 14 15 21
|
||||
1 8 9 12 13 15 21
|
||||
1 8 4 5 9 14 21
|
||||
1 8 5 9 14 15 21
|
||||
1 8 2 3 9 12 21
|
||||
1 8 3 9 12 13 21
|
||||
1 8 3 4 9 13 21
|
||||
1 8 4 9 13 14 21
|
||||
1 8 1 6 9 11 22
|
||||
1 8 6 9 11 16 22
|
||||
1 8 6 7 9 16 22
|
||||
1 8 7 9 16 17 22
|
||||
1 8 0 7 9 17 22
|
||||
1 8 0 9 10 17 22
|
||||
1 8 0 1 9 10 22
|
||||
1 8 1 9 10 11 22
|
||||
1 8 0 1 7 9 22
|
||||
1 8 1 6 7 9 22
|
||||
1 8 9 10 11 17 22
|
||||
1 8 9 11 16 17 22
|
||||
1 8 5 9 15 16 23
|
||||
1 8 5 6 9 16 23
|
||||
1 8 6 7 9 16 23
|
||||
1 8 7 9 16 17 23
|
||||
1 8 7 9 14 17 23
|
||||
1 8 4 7 9 14 23
|
||||
1 8 4 5 9 14 23
|
||||
1 8 5 9 14 15 23
|
||||
1 8 4 6 7 9 23
|
||||
1 8 4 5 6 9 23
|
||||
1 8 9 14 15 16 23
|
||||
1 8 9 14 16 17 23
|
||||
1 8 1 2 9 12 24
|
||||
1 8 1 9 11 12 24
|
||||
1 8 0 1 9 10 24
|
||||
1 8 1 9 10 11 24
|
||||
1 8 0 3 9 10 24
|
||||
1 8 3 9 10 13 24
|
||||
1 8 2 3 9 12 24
|
||||
1 8 3 9 12 13 24
|
||||
1 8 1 2 3 9 24
|
||||
1 8 0 1 3 9 24
|
||||
1 8 9 10 11 13 24
|
||||
1 8 9 11 12 13 24
|
||||
|
||||
boundary
|
||||
96
|
||||
1 4 0 1 7 8
|
||||
1 4 0 1 3 8
|
||||
1 4 0 4 7 8
|
||||
1 4 0 3 4 8
|
||||
2 4 0 10 17 20
|
||||
2 4 0 7 17 20
|
||||
2 4 0 3 4 20
|
||||
2 4 0 4 7 20
|
||||
2 4 0 3 10 20
|
||||
2 4 0 7 17 22
|
||||
2 4 0 10 17 22
|
||||
2 4 0 1 10 22
|
||||
2 4 0 1 7 22
|
||||
2 4 0 1 10 24
|
||||
2 4 0 3 10 24
|
||||
2 4 0 1 3 24
|
||||
1 4 1 6 7 8
|
||||
1 4 1 2 3 8
|
||||
1 4 1 2 6 8
|
||||
2 4 1 6 11 19
|
||||
2 4 1 2 6 19
|
||||
2 4 1 11 12 19
|
||||
2 4 1 2 12 19
|
||||
2 4 1 6 11 22
|
||||
2 4 1 10 11 22
|
||||
2 4 1 6 7 22
|
||||
2 4 1 2 12 24
|
||||
2 4 1 11 12 24
|
||||
2 4 1 10 11 24
|
||||
2 4 1 2 3 24
|
||||
1 4 2 5 6 8
|
||||
1 4 2 3 5 8
|
||||
2 4 2 5 6 19
|
||||
2 4 2 5 15 19
|
||||
2 4 2 12 15 19
|
||||
2 4 2 5 15 21
|
||||
2 4 2 12 15 21
|
||||
2 4 2 3 5 21
|
||||
2 4 2 3 12 21
|
||||
2 4 2 3 12 24
|
||||
1 4 3 4 5 8
|
||||
2 4 3 4 13 20
|
||||
2 4 3 10 13 20
|
||||
2 4 3 4 5 21
|
||||
2 4 3 12 13 21
|
||||
2 4 3 4 13 21
|
||||
2 4 3 10 13 24
|
||||
2 4 3 12 13 24
|
||||
1 4 4 5 6 8
|
||||
1 4 4 6 7 8
|
||||
2 4 4 13 14 20
|
||||
2 4 4 7 14 20
|
||||
2 4 4 5 14 21
|
||||
2 4 4 13 14 21
|
||||
2 4 4 7 14 23
|
||||
2 4 4 5 14 23
|
||||
2 4 4 6 7 23
|
||||
2 4 4 5 6 23
|
||||
2 4 5 6 16 19
|
||||
2 4 5 15 16 19
|
||||
2 4 5 14 15 21
|
||||
2 4 5 15 16 23
|
||||
2 4 5 6 16 23
|
||||
2 4 5 14 15 23
|
||||
2 4 6 11 16 19
|
||||
2 4 6 11 16 22
|
||||
2 4 6 7 16 22
|
||||
2 4 6 7 16 23
|
||||
2 4 7 14 17 20
|
||||
2 4 7 16 17 22
|
||||
2 4 7 16 17 23
|
||||
2 4 7 14 17 23
|
||||
3 4 10 11 17 18
|
||||
3 4 10 11 13 18
|
||||
3 4 10 14 17 18
|
||||
3 4 10 13 14 18
|
||||
2 4 10 13 14 20
|
||||
2 4 10 14 17 20
|
||||
2 4 10 11 17 22
|
||||
2 4 10 11 13 24
|
||||
3 4 11 16 17 18
|
||||
3 4 11 12 13 18
|
||||
3 4 11 12 16 18
|
||||
2 4 11 12 16 19
|
||||
2 4 11 16 17 22
|
||||
2 4 11 12 13 24
|
||||
3 4 12 15 16 18
|
||||
3 4 12 13 15 18
|
||||
2 4 12 15 16 19
|
||||
2 4 12 13 15 21
|
||||
3 4 13 14 15 18
|
||||
2 4 13 14 15 21
|
||||
3 4 14 15 16 18
|
||||
3 4 14 16 17 18
|
||||
2 4 14 15 16 23
|
||||
2 4 14 16 17 23
|
||||
|
||||
vertices
|
||||
25
|
||||
4
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.5000000000000000 0.5000000000000000 0.5000000000000000 0.0000000000000000
|
||||
0.5000000000000000 0.5000000000000000 0.5000000000000000 0.5000000000000000
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
0.5000000000000000 0.5000000000000000 0.5000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.5000000000000000 0.5000000000000000 0.5000000000000000
|
||||
0.0000000000000000 0.5000000000000000 0.5000000000000000 0.5000000000000000
|
||||
0.5000000000000000 1.0000000000000000 0.5000000000000000 0.5000000000000000
|
||||
0.5000000000000000 0.0000000000000000 0.5000000000000000 0.5000000000000000
|
||||
0.5000000000000000 0.5000000000000000 1.0000000000000000 0.5000000000000000
|
||||
0.5000000000000000 0.5000000000000000 0.0000000000000000 0.5000000000000000
|
||||
@@ -1,36 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
#
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
elements
|
||||
2
|
||||
1 2 2 0 1
|
||||
1 2 0 2 3
|
||||
|
||||
boundary
|
||||
4
|
||||
1 1 0 1
|
||||
1 1 1 2
|
||||
2 1 2 3
|
||||
1 1 3 0
|
||||
|
||||
vertices
|
||||
4
|
||||
2
|
||||
0 0
|
||||
1 0
|
||||
1 1
|
||||
0 1
|
||||
@@ -1,52 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
6
|
||||
1 4 3 1 7 5
|
||||
1 4 1 6 7 4
|
||||
1 4 6 1 0 2
|
||||
1 4 1 6 4 2
|
||||
1 4 6 1 3 0
|
||||
1 4 1 6 3 7
|
||||
|
||||
boundary
|
||||
12
|
||||
1 2 6 0 3
|
||||
1 2 0 6 2
|
||||
1 2 1 3 0
|
||||
1 2 3 1 5
|
||||
1 2 3 7 6
|
||||
1 2 7 3 5
|
||||
1 2 4 6 7
|
||||
1 2 6 4 2
|
||||
2 2 1 7 5
|
||||
2 2 7 1 4
|
||||
1 2 1 2 4
|
||||
1 2 2 1 0
|
||||
|
||||
vertices
|
||||
8
|
||||
3
|
||||
0 0 0
|
||||
0 0 1
|
||||
1 0 0
|
||||
0 1 0
|
||||
1 0 1
|
||||
0 1 1
|
||||
1 1 0
|
||||
1 1 1
|
||||
@@ -48,7 +48,7 @@ PROJECT_NAME = MFEM
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = v4.7.1
|
||||
PROJECT_NUMBER = v4.6.1
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
@@ -987,7 +987,6 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
|
||||
@MFEM_SOURCE_DIR@/miniapps/solvers \
|
||||
@MFEM_SOURCE_DIR@/miniapps/tools \
|
||||
@MFEM_SOURCE_DIR@/miniapps/toys \
|
||||
@MFEM_SOURCE_DIR@/miniapps/tribol \
|
||||
@MFEM_SOURCE_DIR@/miniapps/spde \
|
||||
@MFEM_SOURCE_DIR@/miniapps/dpg \
|
||||
@MFEM_SOURCE_DIR@/miniapps/dpg/util
|
||||
@@ -1208,13 +1207,13 @@ STRIP_CODE_COMMENTS = NO
|
||||
# entity all documented functions referencing it will be listed.
|
||||
# The default value is: NO.
|
||||
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
|
||||
# If the REFERENCES_RELATION tag is set to YES then for each documented function
|
||||
# all documented entities called/used by that function will be listed.
|
||||
# The default value is: NO.
|
||||
|
||||
REFERENCES_RELATION = YES
|
||||
REFERENCES_RELATION = NO
|
||||
|
||||
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
|
||||
# to YES then the hyperlinks from functions in REFERENCES_RELATION and
|
||||
|
||||
@@ -110,13 +110,9 @@ namespace mfem {
|
||||
* - <a class="el" href="ex35p_8cpp_source.html">Example 35p</a>: parallel multi-domain damped harmonic oscillators
|
||||
* - <a class="el" href="ex36_8cpp_source.html">Example 36</a>: Proximal Galerkin FEM for the obstacle problem
|
||||
* - <a class="el" href="ex36p_8cpp_source.html">Example 36p</a>: parallel Proximal Galerkin FEM for the obstacle problem
|
||||
* - <a class="el" href="ex37_8cpp_source.html">Example 37</a>: topology optimization
|
||||
* - <a class="el" href="ex37_8cpp_source.html">Example 37</a>: Topology optimization
|
||||
* - <a class="el" href="ex37p_8cpp_source.html">Example 37p</a>: parallel topology optimization
|
||||
* - <a class="el" href="ex38_8cpp_source.html">Example 38</a>: cut-surface and cut-volume integration
|
||||
* - <a class="el" href="ex39_8cpp_source.html">Example 39</a>: named mesh attributes
|
||||
* - <a class="el" href="ex39p_8cpp_source.html">Example 39p</a>: parallel named mesh attributes
|
||||
* - <a class="el" href="ex40_8cpp_source.html">Example 40</a>: eikonal equation
|
||||
* - <a class="el" href="ex40p_8cpp_source.html">Example 40p</a>: parallel eikonal equation
|
||||
*
|
||||
* <H4>AmgX Examples</H4>
|
||||
* - Variants of Examples
|
||||
@@ -218,8 +214,6 @@ namespace mfem {
|
||||
* - <a class="el" href="miniapps_2performance_2ex1_8cpp_source.html">HPC Example 1</a>: high-performance nodal H1 FEM for the Laplace problem
|
||||
* - <a class="el" href="miniapps_2performance_2ex1p_8cpp_source.html">HPC Example 1p</a>: high-performance parallel nodal H1 FEM for the Laplace problem
|
||||
* - <a class="el" href="generate__random__field_8cpp_source.html">SPDE Solvers</a>: SPDE solver random field generation
|
||||
* - <a class="el" href="contact-patch-test_8cpp_source.html">Contact</a>: mortar contact patch test for elasticity
|
||||
* - <a class="el" href="multidomain_8cpp_source.html">Multidomain miniapp</a>: Multidomain and Submesh demonstration miniapp
|
||||
* - <a class="el" href="pdiffusion_8cpp_source.html">DPG Diffusion example</a>: DPG formulation for the diffusion problem
|
||||
* - <a class="el" href="pmaxwell_8cpp_source.html">DPG Maxwell example</a>: DPG formulation for the indefinite Maxwell problem
|
||||
* - <a class="el" href="lor__elast_8cpp_source.html">LOR Elasticity</a>: solve linear elasticity with LOR preconditioning on GPUs
|
||||
|
||||
@@ -46,7 +46,7 @@ class DoxygenAwesomeDarkModeToggle extends HTMLElement {
|
||||
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
|
||||
})
|
||||
// Update the color scheme when the tab is made visible again.
|
||||
// It is possible that the appearance was changed in another tab
|
||||
// It is possible that the appearance was changed in another tab
|
||||
// while this tab was in the background.
|
||||
document.addEventListener("visibilitychange", visibilityState => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
@@ -97,7 +97,7 @@ class DoxygenAwesomeDarkModeToggle extends HTMLElement {
|
||||
* @returns `true` for dark-mode, `false` for light-mode user preference
|
||||
*/
|
||||
static get userPreference() {
|
||||
return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) ||
|
||||
return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) ||
|
||||
(DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey))
|
||||
}
|
||||
|
||||
|
||||
+3
-11
@@ -73,9 +73,6 @@ if (MFEM_USE_MPI)
|
||||
ex20p.cpp
|
||||
ex21p.cpp
|
||||
ex22p.cpp
|
||||
ex1p_4d.cpp
|
||||
ex3p_4d.cpp
|
||||
ex4D_DivSkew.cpp
|
||||
ex24p.cpp
|
||||
ex25p.cpp
|
||||
ex26p.cpp
|
||||
@@ -151,10 +148,10 @@ if (MFEM_ENABLE_TESTING)
|
||||
# Add CUDA/HIP tests.
|
||||
set(DEVICE_EXAMPLES
|
||||
# serial examples with device support:
|
||||
ex1 ex3 ex4 ex5 ex6 ex9 ex14 ex22 ex24 ex25 ex26 ex34
|
||||
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
|
||||
# parallel examples with device support:
|
||||
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex14p ex22p ex24p ex25p
|
||||
ex26p ex34p ex35p)
|
||||
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p
|
||||
ex34p ex35p)
|
||||
set(MFEM_TEST_DEVICE)
|
||||
if (MFEM_USE_CUDA)
|
||||
set(MFEM_TEST_DEVICE "cuda")
|
||||
@@ -164,11 +161,6 @@ if (MFEM_ENABLE_TESTING)
|
||||
if (MFEM_TEST_DEVICE)
|
||||
foreach(TEST_NAME ${DEVICE_EXAMPLES})
|
||||
set(THIS_TEST_OPTIONS "-no-vis" "-d" "${MFEM_TEST_DEVICE}")
|
||||
if (${TEST_NAME} MATCHES "ex14p")
|
||||
list(APPEND THIS_TEST_OPTIONS "-rs" "2" "-rp" "0" "-pa")
|
||||
elseif (${TEST_NAME} MATCHES "ex14")
|
||||
list(APPEND THIS_TEST_OPTIONS "-r" "2" "-pa")
|
||||
endif()
|
||||
if (NOT (${TEST_NAME} MATCHES ".*p$"))
|
||||
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_ser
|
||||
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
|
||||
|
||||
+4
-1
@@ -646,7 +646,10 @@ real_t HyperelasticOperator::ElasticEnergy(const ParGridFunction &x) const
|
||||
|
||||
real_t HyperelasticOperator::KineticEnergy(const ParGridFunction &v) const
|
||||
{
|
||||
real_t energy = 0.5*M.ParInnerProduct(v, v);
|
||||
real_t loc_energy = 0.5*M.InnerProduct(v, v);
|
||||
real_t energy;
|
||||
MPI_Allreduce(&loc_energy, &energy, 1, MPITypeMap<real_t>::mpi_type,
|
||||
MPI_SUM, fespace.GetComm());
|
||||
return energy;
|
||||
}
|
||||
|
||||
|
||||
+46
-88
@@ -18,13 +18,6 @@
|
||||
// ex14 -m ../data/amr-quad.mesh -r 3
|
||||
// ex14 -m ../data/amr-hex.mesh
|
||||
// ex14 -m ../data/fichera-amr.mesh
|
||||
// ex14 -pa -r 1 -o 3
|
||||
// ex14 -pa -r 1 -o 3 -m ../data/fichera.mesh
|
||||
// ex14 -m ../data/inline-tet.mesh -o 0 -nt 4 -s 1
|
||||
//
|
||||
// Device sample runs:
|
||||
// ex14 -pa -r 2 -d cuda -o 3
|
||||
// ex14 -pa -r 2 -d cuda -o 3 -m ../data/fichera.mesh
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define a
|
||||
// discontinuous Galerkin (DG) finite element discretization of
|
||||
@@ -53,19 +46,11 @@ int main(int argc, char *argv[])
|
||||
real_t sigma = -1.0;
|
||||
real_t kappa = -1.0;
|
||||
real_t eta = 0.0;
|
||||
bool pa = false;
|
||||
bool visualization = 1;
|
||||
const char *device_config = "cpu";
|
||||
int nt = 0;
|
||||
double st = 1.0;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&nt, "-nt", "--number-of-timeslices",
|
||||
"Number of slices through the hyper-prism in the 4th coordinate.");
|
||||
args.AddOption(&st, "-st", "--size-time",
|
||||
"Length of hyper-prims in 4th coordinate (e.g. time).");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly, -1 for auto.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
@@ -77,13 +62,9 @@ int main(int argc, char *argv[])
|
||||
"One of the three DG penalty parameters, should be positive."
|
||||
" Negative values are replaced with (order+1)^2.");
|
||||
args.AddOption(&eta, "-e", "--eta", "BR2 penalty parameter.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
@@ -96,34 +77,20 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
// 2. Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
device.Print();
|
||||
|
||||
// 3. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// 2. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral and hexahedral meshes with the same code.
|
||||
// NURBS meshes are projected to second order meshes.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
if (dim == 3 && nt > 0)
|
||||
{
|
||||
Mesh* spat_mesh = mesh;
|
||||
mesh = new Mesh(spat_mesh, nt, Element::PENTATOPE, true, st);
|
||||
delete spat_mesh;
|
||||
|
||||
ref_levels = 0;
|
||||
dim = 4;
|
||||
}
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 3. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement. By default, or if ref_levels < 0,
|
||||
// we choose it to be the largest number that gives a final mesh with no
|
||||
// more than 50,000 elements.
|
||||
{
|
||||
if (ref_levels < 0)
|
||||
{
|
||||
ref_levels = (int)floor(log(50000./mesh->GetNE())/log(2.)/(dim < 4 ? dim : 1.));
|
||||
ref_levels = (int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
|
||||
}
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
@@ -135,83 +102,69 @@ int main(int argc, char *argv[])
|
||||
mesh->SetCurvature(max(order, 1));
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use discontinuous
|
||||
// 4. Define a finite element space on the mesh. Here we use discontinuous
|
||||
// finite elements of the specified order >= 0.
|
||||
const auto bt = pa ? BasisType::GaussLobatto : BasisType::GaussLegendre;
|
||||
DG_FECollection fec(order, dim, bt);
|
||||
FiniteElementSpace fespace(mesh, &fec);
|
||||
cout << "Number of unknowns: " << fespace.GetVSize() << endl;
|
||||
FiniteElementCollection *fec = new DG_FECollection(order, dim);
|
||||
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
|
||||
cout << "Number of unknowns: " << fespace->GetVSize() << endl;
|
||||
|
||||
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// 5. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// the FEM linear system.
|
||||
LinearForm b(&fespace);
|
||||
LinearForm *b = new LinearForm(fespace);
|
||||
ConstantCoefficient one(1.0);
|
||||
ConstantCoefficient zero(0.0);
|
||||
b.AddDomainIntegrator(new DomainLFIntegrator(one));
|
||||
b.AddBdrFaceIntegrator(
|
||||
b->AddDomainIntegrator(new DomainLFIntegrator(one));
|
||||
b->AddBdrFaceIntegrator(
|
||||
new DGDirichletLFIntegrator(zero, one, sigma, kappa));
|
||||
b.Assemble();
|
||||
b->Assemble();
|
||||
|
||||
// 7. Define the solution vector x as a finite element grid function
|
||||
// 6. Define the solution vector x as a finite element grid function
|
||||
// corresponding to fespace. Initialize x with initial guess of zero.
|
||||
GridFunction x(&fespace);
|
||||
GridFunction x(fespace);
|
||||
x = 0.0;
|
||||
|
||||
// 8. Set up the bilinear form a(.,.) on the finite element space
|
||||
// 7. Set up the bilinear form a(.,.) on the finite element space
|
||||
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
|
||||
// domain integrator and the interior and boundary DG face integrators.
|
||||
// Note that boundary conditions are imposed weakly in the form, so there
|
||||
// is no need for dof elimination. After assembly and finalizing we
|
||||
// extract the corresponding sparse matrix A.
|
||||
BilinearForm a(&fespace);
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
a.AddInteriorFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
|
||||
a.AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
|
||||
BilinearForm *a = new BilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
a->AddInteriorFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
|
||||
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
|
||||
if (eta > 0)
|
||||
{
|
||||
MFEM_VERIFY(!pa, "BR2 not yet compatible with partial assembly.");
|
||||
a.AddInteriorFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta));
|
||||
a.AddBdrFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta));
|
||||
a->AddInteriorFaceIntegrator(new DGDiffusionBR2Integrator(*fespace, eta));
|
||||
a->AddBdrFaceIntegrator(new DGDiffusionBR2Integrator(*fespace, eta));
|
||||
}
|
||||
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
a.Assemble();
|
||||
a.Finalize();
|
||||
a->Assemble();
|
||||
a->Finalize();
|
||||
const SparseMatrix &A = a->SpMat();
|
||||
|
||||
// 9. Define a simple symmetric Gauss-Seidel preconditioner and use it to
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
// 8. Define a simple symmetric Gauss-Seidel preconditioner and use it to
|
||||
// solve the system Ax=b with PCG in the symmetric case, and GMRES in the
|
||||
// non-symmetric one. (Note that tolerances are squared: 1e-12 corresponds
|
||||
// to a relative tolerance of 1e-6).
|
||||
//
|
||||
// If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
|
||||
if (pa)
|
||||
// non-symmetric one.
|
||||
GSSmoother M(A);
|
||||
if (sigma == -1.0)
|
||||
{
|
||||
MFEM_VERIFY(sigma == -1.0,
|
||||
"The case of PA with sigma != -1 is not yet supported.");
|
||||
CG(a, b, x, 1, 500, 1e-12, 0.0);
|
||||
PCG(A, M, *b, x, 1, 500, 1e-12, 0.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
const SparseMatrix &A = a.SpMat();
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
GSSmoother M(A);
|
||||
if (sigma == -1.0)
|
||||
{
|
||||
PCG(A, M, b, x, 1, 500, 1e-12, 0.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
GMRES(A, M, b, x, 1, 500, 10, 1e-12, 0.0);
|
||||
}
|
||||
#else
|
||||
UMFPackSolver umf_solver;
|
||||
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
|
||||
umf_solver.SetOperator(A);
|
||||
umf_solver.Mult(b, x);
|
||||
#endif
|
||||
GMRES(A, M, *b, x, 1, 500, 10, 1e-12, 0.0);
|
||||
}
|
||||
#else
|
||||
// 8. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
|
||||
UMFPackSolver umf_solver;
|
||||
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
|
||||
umf_solver.SetOperator(A);
|
||||
umf_solver.Mult(*b, x);
|
||||
#endif
|
||||
|
||||
// 10. Save the refined mesh and the solution. This output can be viewed
|
||||
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
|
||||
// 9. Save the refined mesh and the solution. This output can be viewed later
|
||||
// using GLVis: "glvis -m refined.mesh -g sol.gf".
|
||||
ofstream mesh_ofs("refined.mesh");
|
||||
mesh_ofs.precision(8);
|
||||
mesh->Print(mesh_ofs);
|
||||
@@ -219,7 +172,7 @@ int main(int argc, char *argv[])
|
||||
sol_ofs.precision(8);
|
||||
x.Save(sol_ofs);
|
||||
|
||||
// 11. Send the solution by socket to a GLVis server.
|
||||
// 10. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
@@ -229,6 +182,11 @@ int main(int argc, char *argv[])
|
||||
sol_sock << "solution\n" << *mesh << x << flush;
|
||||
}
|
||||
|
||||
// 11. Free the used memory.
|
||||
delete a;
|
||||
delete b;
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
|
||||
+71
-95
@@ -17,13 +17,6 @@
|
||||
// mpirun -np 4 ex14p -m ../data/inline-segment.mesh -rs 5
|
||||
// mpirun -np 4 ex14p -m ../data/amr-quad.mesh -rs 3
|
||||
// mpirun -np 4 ex14p -m ../data/amr-hex.mesh
|
||||
// mpirun -np 4 ex14p -pa -rs 1 -rp 0 -o 3
|
||||
// mpirun -np 4 ex14p -pa -rs 1 -rp 0 -m ../data/fichera.mesh -o 3
|
||||
// mpirun -np 4 ex14p -m ../data/inline-tet.mesh -o 0 -nt 4 -s 1
|
||||
//
|
||||
// Device sample runs:
|
||||
// mpirun -np 4 ex14p -pa -rs 2 -rp 0 -d cuda -o 3
|
||||
// mpirun -np 4 ex14p -pa -rs 2 -rp 0 -d cuda -m ../data/fichera.mesh -o 3
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define a
|
||||
// discontinuous Galerkin (DG) finite element discretization of
|
||||
@@ -45,14 +38,11 @@ using namespace mfem;
|
||||
|
||||
class CustomSolverMonitor : public IterativeSolverMonitor
|
||||
{
|
||||
private:
|
||||
const ParMesh &pmesh;
|
||||
ParGridFunction &pgf;
|
||||
public:
|
||||
CustomSolverMonitor(const ParMesh &pmesh_,
|
||||
ParGridFunction &pgf_) :
|
||||
pmesh(pmesh_),
|
||||
pgf(pgf_) {}
|
||||
CustomSolverMonitor(const ParMesh *m,
|
||||
ParGridFunction *f) :
|
||||
pmesh(m),
|
||||
pgf(f) {}
|
||||
|
||||
void MonitorSolution(int i, real_t norm, const Vector &x, bool final)
|
||||
{
|
||||
@@ -60,24 +50,30 @@ public:
|
||||
int visport = 19916;
|
||||
int num_procs, myid;
|
||||
|
||||
MPI_Comm_size(pmesh.GetComm(), &num_procs);
|
||||
MPI_Comm_rank(pmesh.GetComm(), &myid);
|
||||
MPI_Comm_size(pmesh->GetComm(),&num_procs);
|
||||
MPI_Comm_rank(pmesh->GetComm(),&myid);
|
||||
|
||||
pgf.SetFromTrueDofs(x);
|
||||
pgf->SetFromTrueDofs(x);
|
||||
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << pmesh << pgf
|
||||
sol_sock << "solution\n" << *pmesh << *pgf
|
||||
<< "window_title 'Iteration no " << i << "'"
|
||||
<< "keys rRjlc\n" << flush;
|
||||
}
|
||||
|
||||
private:
|
||||
const ParMesh *pmesh;
|
||||
ParGridFunction *pgf;
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI and HYPRE.
|
||||
Mpi::Init(argc, argv);
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
// 2. Parse command-line options.
|
||||
@@ -88,19 +84,11 @@ int main(int argc, char *argv[])
|
||||
real_t sigma = -1.0;
|
||||
real_t kappa = -1.0;
|
||||
real_t eta = 0.0;
|
||||
bool pa = false;
|
||||
bool visualization = 1;
|
||||
const char *device_config = "cpu";
|
||||
int nt = 0;
|
||||
double st = 1.0;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&nt, "-nt", "--number-of-timeslices",
|
||||
"Number of slices through the hyper-prism in the 4th coordinate.");
|
||||
args.AddOption(&st, "-st", "--size-time",
|
||||
"Length of hyper-prims in 4th coordinate (e.g. time).");
|
||||
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
|
||||
"Number of times to refine the mesh uniformly in serial,"
|
||||
" -1 for auto.");
|
||||
@@ -115,17 +103,13 @@ int main(int argc, char *argv[])
|
||||
"One of the three DG penalty parameters, should be positive."
|
||||
" Negative values are replaced with (order+1)^2.");
|
||||
args.AddOption(&eta, "-e", "--eta", "BR2 penalty parameter.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (Mpi::Root())
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
@@ -135,28 +119,16 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
kappa = (order+1)*(order+1);
|
||||
}
|
||||
if (Mpi::Root())
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
Device device(device_config);
|
||||
if (Mpi::Root()) { device.Print(); }
|
||||
|
||||
// 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. NURBS meshes are projected to second order meshes.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
if (dim == 3 && nt > 0)
|
||||
{
|
||||
Mesh* spat_mesh = mesh;
|
||||
mesh = new Mesh(spat_mesh, nt, Element::PENTATOPE, true, st);
|
||||
delete spat_mesh;
|
||||
dim = 4;
|
||||
}
|
||||
if (dim == 4)
|
||||
ser_ref_levels = 0;
|
||||
|
||||
// 4. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ser_ref_levels' of uniform refinement. By default,
|
||||
@@ -180,39 +152,38 @@ int main(int argc, char *argv[])
|
||||
// 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(MPI_COMM_WORLD, *mesh);
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
{
|
||||
for (int l = 0; l < par_ref_levels; l++)
|
||||
{
|
||||
pmesh.UniformRefinement();
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use discontinuous finite elements of the specified order >= 0.
|
||||
const auto bt = pa ? BasisType::GaussLobatto : BasisType::GaussLegendre;
|
||||
DG_FECollection fec(order, dim, bt);
|
||||
ParFiniteElementSpace fespace(&pmesh, &fec);
|
||||
HYPRE_BigInt size = fespace.GlobalTrueVSize();
|
||||
if (Mpi::Root())
|
||||
FiniteElementCollection *fec = new DG_FECollection(order, dim);
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
HYPRE_BigInt size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 7. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system.
|
||||
ParLinearForm b(&fespace);
|
||||
ParLinearForm *b = new ParLinearForm(fespace);
|
||||
ConstantCoefficient one(1.0);
|
||||
ConstantCoefficient zero(0.0);
|
||||
b.AddDomainIntegrator(new DomainLFIntegrator(one));
|
||||
b.AddBdrFaceIntegrator(
|
||||
b->AddDomainIntegrator(new DomainLFIntegrator(one));
|
||||
b->AddBdrFaceIntegrator(
|
||||
new DGDirichletLFIntegrator(zero, one, sigma, kappa));
|
||||
b.Assemble();
|
||||
b->Assemble();
|
||||
|
||||
// 8. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x with initial guess of zero.
|
||||
ParGridFunction x(&fespace);
|
||||
ParGridFunction x(fespace);
|
||||
x = 0.0;
|
||||
|
||||
// 9. Set up the bilinear form a(.,.) on the finite element space
|
||||
@@ -221,51 +192,42 @@ int main(int argc, char *argv[])
|
||||
// Note that boundary conditions are imposed weakly in the form, so there
|
||||
// is no need for dof elimination. After serial and parallel assembly we
|
||||
// extract the corresponding parallel matrix A.
|
||||
ParBilinearForm a(&fespace);
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
a.AddInteriorFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
|
||||
a.AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
|
||||
ParBilinearForm *a = new ParBilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
a->AddInteriorFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
|
||||
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa));
|
||||
if (eta > 0)
|
||||
{
|
||||
MFEM_VERIFY(!pa, "BR2 not yet compatible with partial assembly.");
|
||||
a.AddInteriorFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta));
|
||||
a.AddBdrFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta));
|
||||
a->AddInteriorFaceIntegrator(new DGDiffusionBR2Integrator(*fespace, eta));
|
||||
a->AddBdrFaceIntegrator(new DGDiffusionBR2Integrator(*fespace, eta));
|
||||
}
|
||||
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
a.Assemble();
|
||||
a.Finalize();
|
||||
a->Assemble();
|
||||
a->Finalize();
|
||||
|
||||
// 10. Define the parallel (hypre) matrix and vectors representing a(.,.),
|
||||
// b(.) and the finite element approximation.
|
||||
OperatorHandle A;
|
||||
HypreParMatrix *A = a->ParallelAssemble();
|
||||
HypreParVector *B = b->ParallelAssemble();
|
||||
HypreParVector *X = x.ParallelProject();
|
||||
|
||||
std::unique_ptr<HypreBoomerAMG> amg;
|
||||
if (pa)
|
||||
{
|
||||
A.Reset(&a, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
A.SetType(Operator::Hypre_ParCSR);
|
||||
a.ParallelAssemble(A);
|
||||
amg.reset(new HypreBoomerAMG(*A.As<HypreParMatrix>()));
|
||||
}
|
||||
delete a;
|
||||
delete b;
|
||||
|
||||
// 11. Depending on the symmetry of A, define and apply a parallel PCG or
|
||||
// GMRES solver for AX=B using the BoomerAMG preconditioner from hypre.
|
||||
HypreSolver *amg = new HypreBoomerAMG(*A);
|
||||
if (sigma == -1.0)
|
||||
{
|
||||
CGSolver cg(MPI_COMM_WORLD);
|
||||
cg.SetRelTol(1e-12);
|
||||
cg.SetMaxIter(500);
|
||||
cg.SetPrintLevel(1);
|
||||
cg.SetOperator(*A);
|
||||
if (amg) { cg.SetPreconditioner(*amg); }
|
||||
cg.Mult(b, x);
|
||||
HyprePCG pcg(*A);
|
||||
pcg.SetTol(1e-12);
|
||||
pcg.SetMaxIter(500);
|
||||
pcg.SetPrintLevel(2);
|
||||
pcg.SetPreconditioner(*amg);
|
||||
pcg.Mult(*B, *X);
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomSolverMonitor monitor(pmesh, x);
|
||||
CustomSolverMonitor monitor(pmesh, &x);
|
||||
GMRESSolver gmres(MPI_COMM_WORLD);
|
||||
gmres.SetAbsTol(0.0);
|
||||
gmres.SetRelTol(1e-12);
|
||||
@@ -273,37 +235,51 @@ int main(int argc, char *argv[])
|
||||
gmres.SetKDim(10);
|
||||
gmres.SetPrintLevel(1);
|
||||
gmres.SetOperator(*A);
|
||||
if (amg) { gmres.SetPreconditioner(*amg); }
|
||||
gmres.SetPreconditioner(*amg);
|
||||
gmres.SetMonitor(monitor);
|
||||
gmres.Mult(b, x);
|
||||
gmres.Mult(*B, *X);
|
||||
}
|
||||
delete amg;
|
||||
|
||||
// 12. Save the refined mesh and the solution in parallel. This output can
|
||||
// 12. Extract the parallel grid function corresponding to the finite element
|
||||
// approximation X. This is the local solution on each processor.
|
||||
x = *X;
|
||||
|
||||
// 13. Save the refined mesh and the solution in parallel. This output can
|
||||
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
{
|
||||
ostringstream mesh_name, sol_name;
|
||||
mesh_name << "mesh." << setfill('0') << setw(6) << Mpi::WorldRank();
|
||||
sol_name << "sol." << setfill('0') << setw(6) << Mpi::WorldRank();
|
||||
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
|
||||
sol_name << "sol." << setfill('0') << setw(6) << myid;
|
||||
|
||||
ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
mesh_ofs.precision(8);
|
||||
pmesh.Print(mesh_ofs);
|
||||
pmesh->Print(mesh_ofs);
|
||||
|
||||
ofstream sol_ofs(sol_name.str().c_str());
|
||||
sol_ofs.precision(8);
|
||||
x.Save(sol_ofs);
|
||||
}
|
||||
|
||||
// 13. Send the solution by socket to a GLVis server.
|
||||
// 14. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << Mpi::WorldSize() << " " << Mpi::WorldRank() << "\n";
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << pmesh << x << flush;
|
||||
sol_sock << "solution\n" << *pmesh << x << flush;
|
||||
}
|
||||
|
||||
// 15. Free the used memory.
|
||||
delete X;
|
||||
delete B;
|
||||
delete A;
|
||||
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete pmesh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+4
-4
@@ -39,8 +39,8 @@ private:
|
||||
// Base Nonlinear Form
|
||||
std::unique_ptr<NonlinearForm> nonlinearForm;
|
||||
// element-wise inverse mass matrix
|
||||
std::vector<DenseMatrix> invmass; // local scalar inverse mass
|
||||
std::vector<DenseMatrix> weakdiv; // local weak divergence (trial space ByDim)
|
||||
std::vector<DenseMatrix> invmass; // local scalar inverse mass.
|
||||
std::vector<DenseMatrix> weakdiv; // local weakdivergence. Trial space is ByDim.
|
||||
// global maximum characteristic speed. Updated by form integrators
|
||||
mutable real_t max_char_speed;
|
||||
// auxiliary variable used in Mult
|
||||
@@ -169,9 +169,9 @@ void DGHyperbolicConservationLaws::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
// 0. Reset wavespeed computation before operator application.
|
||||
formIntegrator->ResetMaxCharSpeed();
|
||||
// 1. Apply Nonlinear form to obtain an auxiliary result
|
||||
// 1. Apply Nonlinear form to obtain an axiliary result
|
||||
// z = - <F̂(u_h,n), [[v]]>_e
|
||||
// If weak-divergence is not preassembled, we also have weak-divergence
|
||||
// If weak-divergencee is not preassembled, we also have weak-divergence
|
||||
// z = - <F̂(u_h,n), [[v]]>_e + (F(u_h), ∇v)
|
||||
nonlinearForm->Mult(x, z);
|
||||
if (!weakdiv.empty()) // if weak divergence is pre-assembled
|
||||
|
||||
@@ -1,412 +0,0 @@
|
||||
// MFEM Example 1 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex1p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex1p -m ../data/square-disc.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/star.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/escher.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/fichera.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1
|
||||
// mpirun -np 4 ex1p -m ../data/disc-nurbs.mesh -o -1
|
||||
// mpirun -np 4 ex1p -m ../data/pipe-nurbs.mesh -o -1
|
||||
// mpirun -np 4 ex1p -m ../data/ball-nurbs.mesh -o 2
|
||||
// mpirun -np 4 ex1p -m ../data/star-surf.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-surf.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/inline-segment.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/amr-quad.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/amr-hex.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh -o -1 -sc
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define a
|
||||
// simple finite element discretization of the Laplace problem
|
||||
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
|
||||
// Specifically, we discretize using a FE space of the specified
|
||||
// order, or if order < 1 using an isoparametric/isogeometric
|
||||
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
|
||||
// NURBS mesh, etc.)
|
||||
//
|
||||
// The example highlights the use of mesh refinement, finite
|
||||
// element grid functions, as well as linear and bilinear forms
|
||||
// corresponding to the left-hand side and right-hand side of the
|
||||
// discrete linear system. We also cover the explicit elimination
|
||||
// of essential boundary conditions, static condensation, and the
|
||||
// optional connection to the GLVis tool for visualization.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "./spe10_coeff.cpp"
|
||||
|
||||
|
||||
int* LoadIterations(int NRows, int NCol)
|
||||
{
|
||||
ifstream in("iter_grad.txt");
|
||||
|
||||
//initialize
|
||||
int *iters = new int[NCol*NRows];
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
iters[row*NCol+col] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
return iters;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
if (in.eof())
|
||||
{
|
||||
in.close();
|
||||
return iters;
|
||||
}
|
||||
in >> iters[row*NCol+col];
|
||||
}
|
||||
|
||||
|
||||
in.close();
|
||||
|
||||
return iters;
|
||||
}
|
||||
|
||||
void putIterationsInArray(int iter, int row, int col, int NCol, int* iters)
|
||||
{
|
||||
iters[row*NCol+col] = iter;
|
||||
}
|
||||
|
||||
void WriteIterations(int *iters, int NRows, int NCol)
|
||||
{
|
||||
ofstream out;
|
||||
out.open("iter_grad.txt",fstream::out);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
delete[] iters;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
out << iters[row*NCol+col] << "\t";
|
||||
}
|
||||
out << endl;
|
||||
}
|
||||
out.close();
|
||||
|
||||
delete[] iters;
|
||||
}
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
double kappa = 1.0;
|
||||
|
||||
double u_exact(const Vector &x)
|
||||
{
|
||||
int dim = x.Size();
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
return cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*cos(M_PI*x(3));
|
||||
}
|
||||
else { return 0.0; }
|
||||
}
|
||||
|
||||
double f_exact(const Vector &x)
|
||||
{
|
||||
int dim = x.Size();
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
return (kappa + 4.0 * M_PI*M_PI) * cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(
|
||||
2))*cos(M_PI*x(3));
|
||||
}
|
||||
else { return 0.0; }
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
bool verbose = (myid==0);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/cube4d_96.MFEM";
|
||||
int order = 1;
|
||||
bool static_cond = false;
|
||||
bool visualization = 1;
|
||||
int sequ_ref_levels = 0;
|
||||
int par_ref_levels = 0;
|
||||
double tol = 1e-6;
|
||||
bool set_bc = true;
|
||||
bool standardCG = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&sequ_ref_levels, "-sr", "--seqrefinement",
|
||||
"Number of sequential refinement steps.");
|
||||
args.AddOption(&par_ref_levels, "-pr", "--parrefinement",
|
||||
"Number of parallel refinement steps.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Polynomial order of the finite element space.");
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"A parameter.");
|
||||
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
|
||||
"Impose or not essential boundary conditions.");
|
||||
args.AddOption(&standardCG, "-sCG", "--stdCG", "-rCG", "--resCG",
|
||||
"Switch between standard PCG or recompute residuals in every step and use the residuals itself for the stopping criteria.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
if (verbose) { args.PrintOptions(cout); }
|
||||
|
||||
Mesh *mesh;
|
||||
ifstream imesh(mesh_file);
|
||||
if (!imesh)
|
||||
{
|
||||
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
mesh = new Mesh(imesh, 1, 1);
|
||||
imesh.close();
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
// if(dim !=4 || sdim != 4)
|
||||
// {
|
||||
// MPI_Finalize();
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
for (int i=0; i<sequ_ref_levels; i++) { mesh->UniformRefinement(); }
|
||||
if (verbose) { mesh->PrintCharacteristics(); }
|
||||
|
||||
if (verbose) { cout << "now we partition the mesh..." << endl << endl; }
|
||||
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
|
||||
for (int i=0; i<par_ref_levels; i++) { pmesh->UniformRefinement(); }
|
||||
|
||||
pmesh->PrintInfo(std::cout);
|
||||
if (verbose) { cout << endl; }
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use continuous Lagrange finite elements of the specified order. If
|
||||
// order < 1, we instead use an isoparametric/isogeometric space.
|
||||
FiniteElementCollection *fec;
|
||||
if (order > 0)
|
||||
{
|
||||
if (dim==4)
|
||||
{
|
||||
if (order==1) { fec = new LinearFECollection; }
|
||||
else { fec = new QuadraticFECollection; }
|
||||
}
|
||||
else { fec = new H1_FECollection(order, dim); }
|
||||
}
|
||||
else if (pmesh->GetNodes())
|
||||
{
|
||||
fec = pmesh->GetNodes()->OwnFEC();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Using isoparametric FEs: " << fec->Name() << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fec = new H1_FECollection(order = 1, dim);
|
||||
}
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes from the mesh as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = set_bc ? 1 : 0;
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
|
||||
FunctionCoefficient uExact(u_exact);
|
||||
ParGridFunction x(fespace);
|
||||
|
||||
int NExpo =8;
|
||||
for (int expo=-NExpo; expo<=NExpo; expo++)
|
||||
{
|
||||
double weight = pow(10.0,expo);
|
||||
kappa = weight;
|
||||
|
||||
x.ProjectCoefficient(uExact);
|
||||
|
||||
ParLinearForm *b = new ParLinearForm(fespace);
|
||||
FunctionCoefficient ffunc(f_exact);
|
||||
b->AddDomainIntegrator(new DomainLFIntegrator(ffunc));
|
||||
b->Assemble();
|
||||
|
||||
x = 0.0;
|
||||
|
||||
// 10. Set up the parallel bilinear form a(.,.) on the finite element space
|
||||
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
|
||||
// domain integrator.
|
||||
|
||||
// std::string permFile = "spe_perm.dat";
|
||||
// InversePermeabilityFunction::ReadPermeabilityFile(permFile, MPI_COMM_WORLD);
|
||||
// FunctionCoefficient *cspe10 = new FunctionCoefficient(InversePermeabilityFunction::Norm2Permeability);
|
||||
Coefficient *beta = new ConstantCoefficient(weight);
|
||||
|
||||
ParBilinearForm *a = new ParBilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator);
|
||||
a->AddDomainIntegrator(new MassIntegrator(*beta));
|
||||
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, static condensation, etc.
|
||||
if (static_cond) { a->EnableStaticCondensation(); }
|
||||
a->Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
|
||||
}
|
||||
|
||||
// 12. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
|
||||
// preconditioner from hypre.
|
||||
HypreSolver *amg = new HypreBoomerAMG(A);
|
||||
|
||||
int iter = -1;
|
||||
if (standardCG)
|
||||
{
|
||||
IterativeSolver *pcg = new CGSolver(MPI_COMM_WORLD);
|
||||
pcg->SetOperator(A);
|
||||
pcg->SetRelTol(tol);
|
||||
pcg->SetMaxIter(5000);
|
||||
pcg->SetPrintLevel(1);
|
||||
pcg->SetPreconditioner(*amg);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
iter = pcg->GetNumIterations();
|
||||
|
||||
delete pcg;
|
||||
}
|
||||
else
|
||||
{
|
||||
HyprePCG *pcg = new HyprePCG(A);
|
||||
pcg->SetTol(tol);
|
||||
pcg->SetMaxIter(5000);
|
||||
pcg->SetResidualConvergenceOptions(1,tol);
|
||||
pcg->SetPrintLevel(2);
|
||||
pcg->SetPreconditioner(*amg);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
pcg->GetNumIterations(iter);
|
||||
|
||||
delete pcg;
|
||||
}
|
||||
|
||||
|
||||
if (myid==0)
|
||||
{
|
||||
cout << "Weigth: " << weight << " " << iter << endl;
|
||||
|
||||
int *iters = LoadIterations(10, 2*NExpo+1);
|
||||
putIterationsInArray(iter, sequ_ref_levels+par_ref_levels, expo+NExpo,
|
||||
2*NExpo+1, iters);
|
||||
WriteIterations(iters, 10, 2*NExpo+1);
|
||||
}
|
||||
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
{
|
||||
double err = x.ComputeL2Error(uExact);
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "\n|| u - u_h ||_{L^2} = " << err << '\n' << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 14. Save the refined mesh and the solution in parallel. This output can
|
||||
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
// {
|
||||
// ostringstream mesh_name, sol_name;
|
||||
// mesh_name << "mesh." << setfill('0') << setw(6) << myid;
|
||||
// sol_name << "sol." << setfill('0') << setw(6) << myid;
|
||||
//
|
||||
// ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
// mesh_ofs.precision(8);
|
||||
// pmesh->Print(mesh_ofs);
|
||||
//
|
||||
// ofstream sol_ofs(sol_name.str().c_str());
|
||||
// sol_ofs.precision(8);
|
||||
// x.Save(sol_ofs);
|
||||
// }
|
||||
|
||||
// 15. Send the solution by socket to a GLVis server.
|
||||
// if (visualization)
|
||||
// {
|
||||
// char vishost[] = "localhost";
|
||||
// int visport = 19916;
|
||||
// socketstream sol_sock(vishost, visport);
|
||||
// sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
// sol_sock.precision(8);
|
||||
// sol_sock << "solution\n" << *pmesh << x << flush;
|
||||
// }
|
||||
|
||||
delete amg;
|
||||
delete a;
|
||||
delete beta;
|
||||
delete b;
|
||||
}
|
||||
|
||||
// 16. Free the used memory.
|
||||
|
||||
delete fespace;
|
||||
if (order > 0) { delete fec; }
|
||||
delete pmesh;
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
+12
-16
@@ -19,11 +19,8 @@
|
||||
// ex33 -m ../data/amr-quad.mesh -ver -alpha 2.6 -o 2 -r 2
|
||||
// ex33 -m ../data/inline-hex.mesh -ver -alpha 0.3 -o 2 -r 1
|
||||
//
|
||||
// Note: The manufactured solution used in this problem is
|
||||
//
|
||||
// u = ∏_{i=0}^{dim-1} sin(π x_i) ,
|
||||
//
|
||||
// regardless of the value of alpha.
|
||||
// Note: the analytic solution to this problem is u = ∏_{i=0}^{dim-1} sin(π x_i)
|
||||
// for all alpha.
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
@@ -117,8 +114,7 @@ int main(int argc, char *argv[])
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&verification, "-ver", "--verification", "-no-ver",
|
||||
"--no-verification",
|
||||
"Use sinusoidal function (f) for manufactured "
|
||||
"solution test.");
|
||||
"Use sinusoidal function (f) for analytic comparison.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
@@ -167,7 +163,7 @@ int main(int argc, char *argv[])
|
||||
// 5. Define a finite element space on the mesh.
|
||||
H1_FECollection fec(order, dim);
|
||||
FiniteElementSpace fespace(&mesh, &fec);
|
||||
cout << "Number of degrees of freedom: "
|
||||
cout << "Number of finite element unknowns: "
|
||||
<< fespace.GetTrueVSize() << endl;
|
||||
|
||||
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
@@ -383,29 +379,29 @@ int main(int argc, char *argv[])
|
||||
FunctionCoefficient sol(solution);
|
||||
real_t l2_error = u.ComputeL2Error(sol);
|
||||
|
||||
string manufactured_solution,expected_mesh;
|
||||
string analytic_solution,expected_mesh;
|
||||
switch (dim)
|
||||
{
|
||||
case 1:
|
||||
manufactured_solution = "sin(π x)";
|
||||
analytic_solution = "sin(π x)";
|
||||
expected_mesh = "inline_segment.mesh";
|
||||
break;
|
||||
case 2:
|
||||
manufactured_solution = "sin(π x) sin(π y)";
|
||||
analytic_solution = "sin(π x) sin(π y)";
|
||||
expected_mesh = "inline_quad.mesh";
|
||||
break;
|
||||
default:
|
||||
manufactured_solution = "sin(π x) sin(π y) sin(π z)";
|
||||
analytic_solution = "sin(π x) sin(π y) sin(π z)";
|
||||
expected_mesh = "inline_hex.mesh";
|
||||
break;
|
||||
}
|
||||
|
||||
mfem::out << "\n" << string(80,'=')
|
||||
<< "\n\nSolution Verification in "<< dim << "D \n\n"
|
||||
<< "Manufactured solution : " << manufactured_solution << "\n"
|
||||
<< "Expected mesh : " << expected_mesh <<"\n"
|
||||
<< "Your mesh : " << mesh_file << "\n"
|
||||
<< "L2 error : " << l2_error << "\n\n"
|
||||
<< "Analytic solution : " << analytic_solution << "\n"
|
||||
<< "Expected mesh : " << expected_mesh <<"\n"
|
||||
<< "Your mesh : " << mesh_file << "\n"
|
||||
<< "L2 error : " << l2_error << "\n\n"
|
||||
<< string(80,'=') << endl;
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -131,7 +131,7 @@ void RationalApproximation_AAA(const Vector &val, const Vector &pt,
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
DenseMatrixSVD svd(Am,'N','A');
|
||||
DenseMatrixSVD svd(Am,false,true);
|
||||
svd.Eval(Am);
|
||||
DenseMatrix &v = svd.RightSingularvectors();
|
||||
v.GetRow(k,w);
|
||||
@@ -346,7 +346,7 @@ void ComputePartialFractionApproximation(real_t & alpha,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (abs(alpha - 0.5) > eps)
|
||||
if (abs(alpha - 0.5) > eps && print_warning)
|
||||
{
|
||||
alpha = 0.5;
|
||||
}
|
||||
@@ -368,8 +368,6 @@ void ComputePartialFractionApproximation(real_t & alpha,
|
||||
|
||||
|
||||
return;
|
||||
#else
|
||||
MFEM_CONTRACT_VAR(print_warning);
|
||||
#endif
|
||||
|
||||
Vector x(npoints);
|
||||
|
||||
+14
-19
@@ -19,11 +19,8 @@
|
||||
// mpirun -np 4 ex33p -m ../data/amr-quad.mesh -ver -alpha 2.6 -o 2 -r 2
|
||||
// mpirun -np 4 ex33p -m ../data/inline-hex.mesh -ver -alpha 0.3 -o 2 -r 1
|
||||
|
||||
// Note: The manufactured solution used in this problem is
|
||||
//
|
||||
// u = ∏_{i=0}^{dim-1} sin(π x_i) ,
|
||||
//
|
||||
// regardless of the value of alpha.
|
||||
// Note: the analytic solution to this problem is u = ∏_{i=0}^{dim-1} sin(π x_i)
|
||||
// for all alpha.
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
@@ -123,8 +120,7 @@ int main(int argc, char *argv[])
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&verification, "-ver", "--verification", "-no-ver",
|
||||
"--no-verification",
|
||||
"Use sinusoidal function (f) for manufactured "
|
||||
"solution test.");
|
||||
"Use sinusoidal function (f) for analytic comparison.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
@@ -184,11 +180,10 @@ int main(int argc, char *argv[])
|
||||
// 5. Define a finite element space on the mesh.
|
||||
H1_FECollection fec(order, dim);
|
||||
ParFiniteElementSpace fespace(&pmesh, &fec);
|
||||
HYPRE_BigInt size = fespace.GlobalTrueVSize();
|
||||
if (Mpi::Root())
|
||||
{
|
||||
cout << "Number of degrees of freedom: "
|
||||
<< size << endl;
|
||||
cout << "Number of finite element unknowns: "
|
||||
<< fespace.GetTrueVSize() << endl;
|
||||
}
|
||||
|
||||
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
@@ -228,7 +223,7 @@ int main(int argc, char *argv[])
|
||||
if (verification)
|
||||
{
|
||||
// This statement is only relevant for the verification of the code. It
|
||||
// uses a different f such that an manufactured solution is known and easy
|
||||
// uses a different f such that an analytic solution is known and easy
|
||||
// to compare with the numerical one. The FPDE becomes:
|
||||
// (-Δ)^α u = (2\pi ^2)^α sin(\pi x) sin(\pi y) on [0,1]^2
|
||||
// -> u(x,y) = sin(\pi x) sin(\pi y)
|
||||
@@ -420,29 +415,29 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (Mpi::Root())
|
||||
{
|
||||
string manufactured_solution,expected_mesh;
|
||||
string analytic_solution,expected_mesh;
|
||||
switch (dim)
|
||||
{
|
||||
case 1:
|
||||
manufactured_solution = "sin(π x)";
|
||||
analytic_solution = "sin(π x)";
|
||||
expected_mesh = "inline_segment.mesh";
|
||||
break;
|
||||
case 2:
|
||||
manufactured_solution = "sin(π x) sin(π y)";
|
||||
analytic_solution = "sin(π x) sin(π y)";
|
||||
expected_mesh = "inline_quad.mesh";
|
||||
break;
|
||||
default:
|
||||
manufactured_solution = "sin(π x) sin(π y) sin(π z)";
|
||||
analytic_solution = "sin(π x) sin(π y) sin(π z)";
|
||||
expected_mesh = "inline_hex.mesh";
|
||||
break;
|
||||
}
|
||||
|
||||
mfem::out << "\n" << string(80,'=')
|
||||
<< "\n\nSolution Verification in "<< dim << "D \n\n"
|
||||
<< "Manufactured solution : " << manufactured_solution << "\n"
|
||||
<< "Expected mesh : " << expected_mesh <<"\n"
|
||||
<< "Your mesh : " << mesh_file << "\n"
|
||||
<< "L2 error : " << l2_error << "\n\n"
|
||||
<< "Analytic solution : " << analytic_solution << "\n"
|
||||
<< "Expected mesh : " << expected_mesh <<"\n"
|
||||
<< "Your mesh : " << mesh_file << "\n"
|
||||
<< "L2 error : " << l2_error << "\n\n"
|
||||
<< string(80,'=') << endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +199,7 @@ public:
|
||||
{
|
||||
mesh->GetElementTransformation(elem, &Tr);
|
||||
MFIRs.GetSurfaceIntegrationRule(Tr, ir);
|
||||
Vector w;
|
||||
MFIRs.GetSurfaceWeights(Tr, ir, w);
|
||||
SurfaceWeights.SetCol(elem, w);
|
||||
|
||||
|
||||
+9
-222
@@ -58,180 +58,6 @@ void f_exact(const Vector &, Vector &);
|
||||
real_t freq = 1.0, kappa;
|
||||
int dim;
|
||||
|
||||
class Curl4dPrec : public Solver
|
||||
{
|
||||
|
||||
private:
|
||||
HypreParMatrix *A;
|
||||
ParFiniteElementSpace *fespace;
|
||||
|
||||
HypreParMatrix *idMat;
|
||||
HypreParMatrix *H1VecLaplaceMat;
|
||||
HypreBoomerAMG *amgVecH1;
|
||||
|
||||
|
||||
HypreParMatrix *gradMat;
|
||||
HypreParMatrix *H1LaplaceMat;
|
||||
HypreBoomerAMG *amgH1;
|
||||
|
||||
HypreSmoother * smoother;
|
||||
CGSolver *pcgGrad;
|
||||
CGSolver *pcgH1Vec;
|
||||
|
||||
Vector *f;
|
||||
Vector *fGrad, *uGrad;
|
||||
Vector *fH1Vec, *uH1Vec;
|
||||
|
||||
bool exactSolves;
|
||||
|
||||
public:
|
||||
Curl4dPrec(HypreParMatrix *AUser, ParFiniteElementSpace *fespaceUser,
|
||||
const Array<int> &essBnd, int orderKernel=1, bool exactSolvesUser=false)
|
||||
{
|
||||
A = AUser;
|
||||
fespace = fespaceUser;
|
||||
ParMesh *pmesh = fespace->GetParMesh();
|
||||
int dim = pmesh->Dimension();
|
||||
|
||||
exactSolves = exactSolvesUser;
|
||||
|
||||
int orderIm=1; //vecH1 --> H(curl)
|
||||
int orderKer=orderKernel; //grad V --> H(curl)
|
||||
|
||||
smoother = new HypreSmoother(*A, 16, 3);
|
||||
|
||||
// //for the pure dirichlet case
|
||||
// Array<int> essBnd(pmesh->bdr_attributes.Max()); essBnd = 1;
|
||||
|
||||
Array<int> HCurl_essDof(fespace->GetVSize()); HCurl_essDof = 0;
|
||||
fespace->GetEssentialVDofs(essBnd, HCurl_essDof);
|
||||
|
||||
//setup the H1 FESpace
|
||||
FiniteElementCollection* fecH1;
|
||||
if (orderKer==1) { fecH1 = new LinearFECollection; }
|
||||
else { fecH1 = new QuadraticFECollection; }
|
||||
|
||||
ParFiniteElementSpace *H1FESpace = new ParFiniteElementSpace(pmesh, fecH1);
|
||||
Array<int> H1_essDof(H1FESpace->GetVSize()); H1_essDof = 0;
|
||||
H1FESpace->GetEssentialVDofs(essBnd, H1_essDof);
|
||||
|
||||
//setup the discrete gradient
|
||||
ParDiscreteLinearOperator *disGrad = new ParDiscreteLinearOperator(H1FESpace,
|
||||
fespace);
|
||||
disGrad->AddDomainInterpolator(new GradientInterpolator);
|
||||
disGrad->Assemble();
|
||||
disGrad->Finalize();
|
||||
SparseMatrix* smat = &(disGrad->SpMat());
|
||||
smat->EliminateCols(H1_essDof);
|
||||
for (int dof=0; dof<HCurl_essDof.Size(); dof++) if (HCurl_essDof[dof]<0) { smat->EliminateRow(dof); }
|
||||
gradMat = disGrad->ParallelAssemble();
|
||||
delete disGrad;
|
||||
|
||||
//setup the H1 preconditioner
|
||||
ParBilinearForm* H1Varf = new ParBilinearForm(H1FESpace);
|
||||
H1Varf->AddDomainIntegrator(new DiffusionIntegrator);
|
||||
H1Varf->AddDomainIntegrator(new MassIntegrator);
|
||||
H1Varf->Assemble();
|
||||
H1Varf->Finalize();
|
||||
|
||||
SparseMatrix &matH1(H1Varf->SpMat());
|
||||
for (int dof=0; dof<H1_essDof.Size(); dof++) if (H1_essDof[dof]<0) { matH1.EliminateRowCol(dof); }
|
||||
H1LaplaceMat = H1Varf->ParallelAssemble();
|
||||
delete H1Varf;
|
||||
amgH1 = new HypreBoomerAMG(*H1LaplaceMat);
|
||||
|
||||
|
||||
//setup the H1 injection
|
||||
FiniteElementCollection* fecH1Vec;
|
||||
if (orderIm==1) { fecH1Vec = new LinearFECollection; }
|
||||
else { fecH1Vec = new QuadraticFECollection; }
|
||||
ParFiniteElementSpace *H1VecFESpace = new ParFiniteElementSpace(pmesh, fecH1Vec,
|
||||
dim, Ordering::byVDIM);
|
||||
Array<int> H1Vec_essDof(H1VecFESpace->GetVSize()); H1Vec_essDof = 0;
|
||||
H1VecFESpace->GetEssentialVDofs(essBnd, H1Vec_essDof);
|
||||
|
||||
//setup the discrete gradient
|
||||
ParDiscreteLinearOperator *disInterpol = new ParDiscreteLinearOperator(
|
||||
H1VecFESpace, fespace);
|
||||
disInterpol->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpol->Assemble();
|
||||
disInterpol->Finalize();
|
||||
SparseMatrix* smatID = &(disInterpol->SpMat());
|
||||
smatID->EliminateCols(H1Vec_essDof);
|
||||
for (int dof=0; dof<HCurl_essDof.Size(); dof++) if (HCurl_essDof[dof]<0) { smatID->EliminateRow(dof); }
|
||||
idMat = disInterpol->ParallelAssemble();
|
||||
delete disInterpol;
|
||||
|
||||
//setup the H1-vec preconditioner
|
||||
ParBilinearForm* H1VecVarf = new ParBilinearForm(H1VecFESpace);
|
||||
H1VecVarf->AddDomainIntegrator(new VectorDiffusionIntegrator);
|
||||
H1VecVarf->AddDomainIntegrator(new VectorMassIntegrator);
|
||||
H1VecVarf->Assemble();
|
||||
H1VecVarf->Finalize();
|
||||
|
||||
SparseMatrix &matH1Vec(H1VecVarf->SpMat());
|
||||
for (int dof=0; dof<H1Vec_essDof.Size(); dof++) if (H1Vec_essDof[dof]<0) { matH1Vec.EliminateRowCol(dof); }
|
||||
H1VecLaplaceMat = H1VecVarf->ParallelAssemble();
|
||||
delete H1VecVarf;
|
||||
amgVecH1 = new HypreBoomerAMG(*H1VecLaplaceMat);
|
||||
amgVecH1->SetSystemsOptions(dim);
|
||||
|
||||
|
||||
f = new Vector(fespace->GetTrueVSize());
|
||||
|
||||
fGrad = new Vector(H1FESpace->GetTrueVSize());
|
||||
uGrad = new Vector(H1FESpace->GetTrueVSize());
|
||||
|
||||
fH1Vec = new Vector(H1VecFESpace->GetTrueVSize());
|
||||
uH1Vec = new Vector(H1VecFESpace->GetTrueVSize());;
|
||||
|
||||
|
||||
amgH1->Mult(*fGrad, *uGrad);
|
||||
amgVecH1->Mult(*fH1Vec, *uH1Vec);
|
||||
|
||||
pcgGrad = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgGrad->SetOperator(*H1LaplaceMat);
|
||||
pcgGrad->SetPreconditioner(*amgH1);
|
||||
pcgGrad->SetRelTol(1e-16);
|
||||
pcgGrad->SetMaxIter(100000000);
|
||||
pcgGrad->SetPrintLevel(-2);
|
||||
|
||||
pcgH1Vec = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgH1Vec->SetOperator(*H1VecLaplaceMat);
|
||||
pcgH1Vec->SetPreconditioner(*amgVecH1);
|
||||
pcgH1Vec->SetRelTol(1e-16);
|
||||
pcgH1Vec->SetMaxIter(100000000);
|
||||
pcgH1Vec->SetPrintLevel(-2);
|
||||
|
||||
}
|
||||
|
||||
void setExactSolve(bool exSol)
|
||||
{
|
||||
exactSolves = exSol;
|
||||
}
|
||||
|
||||
virtual void Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
smoother->Mult(x,y);
|
||||
|
||||
idMat->MultTranspose(x,*fH1Vec);
|
||||
*uH1Vec = 0.0;
|
||||
if (exactSolves) { pcgH1Vec->Mult(*fH1Vec, *uH1Vec); }
|
||||
else { amgVecH1->Mult(*fH1Vec, *uH1Vec); }
|
||||
idMat->Mult(1.0, *uH1Vec, 1.0, y);
|
||||
|
||||
gradMat->MultTranspose(x,*fGrad);
|
||||
*uGrad = 0.0;
|
||||
if (exactSolves) { pcgGrad->Mult(*fGrad, *uGrad); }
|
||||
else { amgH1->Mult(*fGrad, *uGrad); }
|
||||
gradMat->Mult(1.0, *uGrad, 1.0, y);
|
||||
|
||||
}
|
||||
|
||||
virtual void SetOperator(const Operator &op) {};
|
||||
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI and HYPRE.
|
||||
@@ -336,13 +162,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Nedelec finite elements of the specified order.
|
||||
FiniteElementCollection *fec;
|
||||
if (dim==4)
|
||||
{
|
||||
if (order==1) { fec = new ND1_4DFECollection; }
|
||||
else { fec = new ND2_4DFECollection; }
|
||||
}
|
||||
else { fec = new ND_FECollection(order, dim); }
|
||||
FiniteElementCollection *fec = new ND_FECollection(order, dim);
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
HYPRE_BigInt size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
@@ -428,29 +248,15 @@ int main(int argc, char *argv[])
|
||||
|
||||
ParFiniteElementSpace *prec_fespace =
|
||||
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
|
||||
Solver *prec;
|
||||
HypreAMS ams(*A.As<HypreParMatrix>(), prec_fespace);
|
||||
if (dim <= 3)
|
||||
{
|
||||
prec = new HypreAMS(*A.As<HypreParMatrix>(), prec_fespace);
|
||||
}
|
||||
else if (dim == 4)
|
||||
{
|
||||
prec = new Curl4dPrec(A.As<HypreParMatrix>(), fespace, ess_bdr, order, false);
|
||||
}
|
||||
IterativeSolver *pcg = new CGSolver(MPI_COMM_WORLD);
|
||||
pcg->SetOperator(*A.As<HypreParMatrix>());
|
||||
pcg->SetTol(1e-12);
|
||||
pcg->SetMaxIter(500);
|
||||
pcg->SetPrintLevel(2);
|
||||
pcg->SetPreconditioner(*prec);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
delete pcg;
|
||||
delete prec;
|
||||
HyprePCG pcg(*A.As<HypreParMatrix>());
|
||||
pcg.SetTol(1e-12);
|
||||
pcg.SetMaxIter(500);
|
||||
pcg.SetPrintLevel(2);
|
||||
pcg.SetPreconditioner(ams);
|
||||
pcg.Mult(B, X);
|
||||
}
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to X. This is the
|
||||
// 14. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
@@ -506,14 +312,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
void E_exact(const Vector &x, Vector &E)
|
||||
{
|
||||
if (dim==4)
|
||||
{
|
||||
E(0) = sin(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(1) = -cos(M_PI*x(0))*sin(M_PI*x(1))*cos(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(2) = cos(M_PI*x(0))*cos(M_PI*x(1))*sin(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(3) = -cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*sin(M_PI*x(3));
|
||||
}
|
||||
else if (dim == 3)
|
||||
if (dim == 3)
|
||||
{
|
||||
E(0) = sin(kappa * x(1));
|
||||
E(1) = sin(kappa * x(2));
|
||||
@@ -529,19 +328,7 @@ void E_exact(const Vector &x, Vector &E)
|
||||
|
||||
void f_exact(const Vector &x, Vector &f)
|
||||
{
|
||||
//f_exact = E + DivSkew P( curl E ), where P is the 4d permutation operator
|
||||
if (dim==4)
|
||||
{
|
||||
f(0) = (1.0+4.0*M_PI*M_PI)*sin(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(1) = -(1.0+4.0*M_PI*M_PI)*cos(M_PI*x(0))*sin(M_PI*x(1))*cos(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(2) = (1.0+4.0*M_PI*M_PI)*cos(M_PI*x(0))*cos(M_PI*x(1))*sin(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(3) = -(1.0+4.0*M_PI*M_PI)*cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*sin(
|
||||
M_PI*x(3));
|
||||
}
|
||||
else if (dim == 3)
|
||||
if (dim == 3)
|
||||
{
|
||||
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
|
||||
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
|
||||
|
||||
@@ -1,650 +0,0 @@
|
||||
// MFEM Example 3 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex3p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/escher.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/fichera.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
|
||||
// mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
|
||||
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
|
||||
//
|
||||
// Description: This example code solves a simple electromagnetic diffusion
|
||||
// problem corresponding to the second order definite Maxwell
|
||||
// equation curl curl E + E = f with boundary condition
|
||||
// E x n = <given tangential field>. Here, we use a given exact
|
||||
// solution E and compute the corresponding r.h.s. f.
|
||||
// We discretize with Nedelec finite elements in 2D or 3D.
|
||||
//
|
||||
// The example demonstrates the use of H(curl) finite element
|
||||
// spaces with the curl-curl and the (vector finite element) mass
|
||||
// bilinear form, as well as the computation of discretization
|
||||
// error when the exact solution is known. Static condensation is
|
||||
// also illustrated.
|
||||
//
|
||||
// We recommend viewing examples 1-2 before viewing this example.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "./spe10_coeff.cpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
|
||||
int* LoadIterations(int NRows, int NCol)
|
||||
{
|
||||
ifstream in("iter_curl.txt");
|
||||
|
||||
//initialize
|
||||
int *iters = new int[NCol*NRows];
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
iters[row*NCol+col] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
return iters;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
if (in.eof())
|
||||
{
|
||||
in.close();
|
||||
return iters;
|
||||
}
|
||||
in >> iters[row*NCol+col];
|
||||
}
|
||||
|
||||
|
||||
in.close();
|
||||
|
||||
return iters;
|
||||
}
|
||||
|
||||
void putIterationsInArray(int iter, int row, int col, int NCol, int* iters)
|
||||
{
|
||||
iters[row*NCol+col] = iter;
|
||||
}
|
||||
|
||||
void WriteIterations(int *iters, int NRows, int NCol)
|
||||
{
|
||||
ofstream out;
|
||||
out.open("iter_curl.txt",fstream::out);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
delete[] iters;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
out << iters[row*NCol+col] << "\t";
|
||||
}
|
||||
out << endl;
|
||||
}
|
||||
out.close();
|
||||
|
||||
delete[] iters;
|
||||
}
|
||||
|
||||
|
||||
// Exact solution, E, and r.h.s., f. See below for implementation.
|
||||
void E_exact(const Vector &, Vector &);
|
||||
void f_exact(const Vector &, Vector &);
|
||||
double freq = 1.0, kappa = 1.0;
|
||||
int dim;
|
||||
|
||||
double osziCoeff(const Vector &x)
|
||||
{
|
||||
return 1.0001 + sin(100*x(0))*sin(200*x(1))*sin(300*x(2))*sin(400*x(3));
|
||||
}
|
||||
|
||||
class Curl4dPrec : public Solver
|
||||
{
|
||||
|
||||
private:
|
||||
HypreParMatrix *A;
|
||||
ParFiniteElementSpace *fespace;
|
||||
Coefficient *alpha_, *beta_, *neg_beta_;
|
||||
|
||||
HypreParMatrix *idMat;
|
||||
HypreParMatrix *H1VecLaplaceMat;
|
||||
HypreBoomerAMG *amgVecH1;
|
||||
|
||||
|
||||
HypreParMatrix *gradMat;
|
||||
HypreParMatrix *H1LaplaceMat;
|
||||
HypreBoomerAMG *amgH1;
|
||||
|
||||
HypreSmoother * smoother;
|
||||
CGSolver *pcgGrad;
|
||||
CGSolver *pcgH1Vec;
|
||||
|
||||
Vector *f;
|
||||
Vector *fGrad, *uGrad;
|
||||
Vector *fH1Vec, *uH1Vec;
|
||||
|
||||
bool exactSolves;
|
||||
|
||||
public:
|
||||
~Curl4dPrec()
|
||||
{
|
||||
delete pcgH1Vec;
|
||||
delete pcgGrad;
|
||||
|
||||
delete f, fGrad, uGrad, fH1Vec, uH1Vec;
|
||||
|
||||
delete smoother;
|
||||
|
||||
delete amgVecH1, H1VecLaplaceMat;
|
||||
delete idMat;
|
||||
delete amgH1, H1LaplaceMat;
|
||||
delete gradMat;
|
||||
}
|
||||
|
||||
Curl4dPrec(HypreParMatrix *AUser, ParFiniteElementSpace *fespaceUser,
|
||||
Coefficient *alpha, Coefficient *beta, Coefficient *neg_beta,
|
||||
const Array<int> &essBnd, int orderKernel=1, bool exactSolvesUser=false)
|
||||
{
|
||||
A = AUser;
|
||||
fespace = fespaceUser;
|
||||
alpha_ = alpha;
|
||||
beta_ = beta;
|
||||
neg_beta_=neg_beta;
|
||||
|
||||
ParMesh *pmesh = fespace->GetParMesh();
|
||||
int dim = pmesh->Dimension();
|
||||
|
||||
exactSolves = exactSolvesUser;
|
||||
|
||||
int orderIm=1; //vecH1 --> H(curl)
|
||||
int orderKer=orderKernel; //grad V --> H(curl)
|
||||
|
||||
smoother = new HypreSmoother(*A, 16, 3);
|
||||
|
||||
// //for the pure dirichlet case
|
||||
// Array<int> essBnd(pmesh->bdr_attributes.Max()); essBnd = 1;
|
||||
|
||||
Array<int> HCurl_essDof(fespace->GetVSize()); HCurl_essDof = 0;
|
||||
fespace->GetEssentialVDofs(essBnd, HCurl_essDof);
|
||||
|
||||
//setup the H1 FESpace
|
||||
FiniteElementCollection* fecH1;
|
||||
if (orderKer==1) { fecH1 = new LinearFECollection; }
|
||||
else { fecH1 = new QuadraticFECollection; }
|
||||
|
||||
ParFiniteElementSpace *H1FESpace = new ParFiniteElementSpace(pmesh, fecH1);
|
||||
Array<int> H1_essDof(H1FESpace->GetVSize()); H1_essDof = 0;
|
||||
H1FESpace->GetEssentialVDofs(essBnd, H1_essDof);
|
||||
|
||||
//setup the discrete gradient
|
||||
ParDiscreteLinearOperator *disGrad = new ParDiscreteLinearOperator(H1FESpace,
|
||||
fespace);
|
||||
disGrad->AddDomainInterpolator(new GradientInterpolator);
|
||||
disGrad->Assemble();
|
||||
disGrad->Finalize();
|
||||
SparseMatrix* smat = &(disGrad->SpMat());
|
||||
smat->EliminateCols(H1_essDof);
|
||||
for (int dof=0; dof<HCurl_essDof.Size(); dof++) if (HCurl_essDof[dof]<0) { smat->EliminateRow(dof); }
|
||||
gradMat = disGrad->ParallelAssemble();
|
||||
delete disGrad;
|
||||
|
||||
//setup the H1 preconditioner
|
||||
ParBilinearForm* H1Varf = new ParBilinearForm(H1FESpace);
|
||||
H1Varf->AddDomainIntegrator(new DiffusionIntegrator(*beta_));
|
||||
// H1Varf->AddDomainIntegrator(new MassIntegrator);
|
||||
H1Varf->Assemble();
|
||||
H1Varf->Finalize();
|
||||
|
||||
SparseMatrix &matH1(H1Varf->SpMat());
|
||||
for (int dof=0; dof<H1_essDof.Size(); dof++) if (H1_essDof[dof]<0) { matH1.EliminateRowCol(dof); }
|
||||
H1LaplaceMat = H1Varf->ParallelAssemble();
|
||||
delete H1Varf;
|
||||
amgH1 = new HypreBoomerAMG(*H1LaplaceMat);
|
||||
|
||||
|
||||
//setup the H1 injection
|
||||
FiniteElementCollection* fecH1Vec;
|
||||
if (orderIm==1) { fecH1Vec = new LinearFECollection; }
|
||||
else { fecH1Vec = new QuadraticFECollection; }
|
||||
ParFiniteElementSpace *H1VecFESpace = new ParFiniteElementSpace(pmesh, fecH1Vec,
|
||||
dim, Ordering::byVDIM);
|
||||
Array<int> H1Vec_essDof(H1VecFESpace->GetVSize()); H1Vec_essDof = 0;
|
||||
H1VecFESpace->GetEssentialVDofs(essBnd, H1Vec_essDof);
|
||||
|
||||
//setup the discrete gradient
|
||||
ParDiscreteLinearOperator *disInterpol = new ParDiscreteLinearOperator(
|
||||
H1VecFESpace, fespace);
|
||||
disInterpol->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpol->Assemble();
|
||||
disInterpol->Finalize();
|
||||
SparseMatrix* smatID = &(disInterpol->SpMat());
|
||||
smatID->EliminateCols(H1Vec_essDof);
|
||||
for (int dof=0; dof<HCurl_essDof.Size(); dof++) if (HCurl_essDof[dof]<0) { smatID->EliminateRow(dof); }
|
||||
idMat = disInterpol->ParallelAssemble();
|
||||
delete disInterpol;
|
||||
|
||||
//setup the H1-vec preconditioner
|
||||
ParBilinearForm* H1VecVarf = new ParBilinearForm(H1VecFESpace);
|
||||
H1VecVarf->AddDomainIntegrator(new VectorDiffusionIntegrator(*alpha_));
|
||||
H1VecVarf->AddDomainIntegrator(new VectorMassIntegrator(*neg_beta_));
|
||||
H1VecVarf->Assemble();
|
||||
H1VecVarf->Finalize();
|
||||
|
||||
SparseMatrix &matH1Vec(H1VecVarf->SpMat());
|
||||
for (int dof=0; dof<H1Vec_essDof.Size(); dof++) if (H1Vec_essDof[dof]<0) { matH1Vec.EliminateRowCol(dof); }
|
||||
H1VecLaplaceMat = H1VecVarf->ParallelAssemble();
|
||||
delete H1VecVarf;
|
||||
amgVecH1 = new HypreBoomerAMG(*H1VecLaplaceMat);
|
||||
amgVecH1->SetSystemsOptions(dim);
|
||||
|
||||
|
||||
f = new Vector(fespace->GetTrueVSize());
|
||||
|
||||
fGrad = new Vector(H1FESpace->GetTrueVSize());
|
||||
uGrad = new Vector(H1FESpace->GetTrueVSize());
|
||||
|
||||
fH1Vec = new Vector(H1VecFESpace->GetTrueVSize());
|
||||
uH1Vec = new Vector(H1VecFESpace->GetTrueVSize());
|
||||
|
||||
|
||||
amgH1->Mult(*fGrad, *uGrad);
|
||||
amgVecH1->Mult(*fH1Vec, *uH1Vec);
|
||||
|
||||
pcgGrad = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgGrad->SetOperator(*H1LaplaceMat);
|
||||
pcgGrad->SetPreconditioner(*amgH1);
|
||||
pcgGrad->SetRelTol(1e-16);
|
||||
pcgGrad->SetMaxIter(100000000);
|
||||
pcgGrad->SetPrintLevel(-2);
|
||||
|
||||
pcgH1Vec = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgH1Vec->SetOperator(*H1VecLaplaceMat);
|
||||
pcgH1Vec->SetPreconditioner(*amgVecH1);
|
||||
pcgH1Vec->SetRelTol(1e-16);
|
||||
pcgH1Vec->SetMaxIter(100000000);
|
||||
pcgH1Vec->SetPrintLevel(-2);
|
||||
|
||||
delete H1FESpace; delete fecH1;
|
||||
delete H1VecFESpace; delete fecH1Vec;
|
||||
|
||||
}
|
||||
|
||||
void setExactSolve(bool exSol)
|
||||
{
|
||||
exactSolves = exSol;
|
||||
}
|
||||
|
||||
virtual void Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
smoother->Mult(x,y);
|
||||
|
||||
idMat->MultTranspose(x,*fH1Vec);
|
||||
*uH1Vec = 0.0;
|
||||
if (exactSolves) { pcgH1Vec->Mult(*fH1Vec, *uH1Vec); }
|
||||
else { amgVecH1->Mult(*fH1Vec, *uH1Vec); }
|
||||
idMat->Mult(1.0, *uH1Vec, 1.0, y);
|
||||
|
||||
gradMat->MultTranspose(x,*fGrad);
|
||||
*uGrad = 0.0;
|
||||
if (exactSolves) { pcgGrad->Mult(*fGrad, *uGrad); }
|
||||
else { amgH1->Mult(*fGrad, *uGrad); }
|
||||
gradMat->Mult(1.0, *uGrad, 1.0, y);
|
||||
|
||||
}
|
||||
|
||||
virtual void SetOperator(const Operator &op) {};
|
||||
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
bool verbose = (myid==0);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/cube4d_96.MFEM";
|
||||
int order = 1;
|
||||
bool set_bc = true;
|
||||
bool static_cond = false;
|
||||
bool visualization = 1;
|
||||
int sequ_ref_levels = 0;
|
||||
int par_ref_levels = 0;
|
||||
double tol = 1e-6;
|
||||
double coeffWeight = 1.0;
|
||||
bool exactH1Solver = false;
|
||||
bool spe10Coeff = false;
|
||||
bool standardCG = true;
|
||||
|
||||
int NExpo = 8;
|
||||
int weightStart = -NExpo;
|
||||
int weightEnd = NExpo;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&sequ_ref_levels, "-sr", "--seqrefinement",
|
||||
"Number of sequential refinement steps.");
|
||||
args.AddOption(&par_ref_levels, "-pr", "--parrefinement",
|
||||
"Number of parallel refinement steps.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Polynomial order of the finite element space.");
|
||||
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
|
||||
"Impose or not essential boundary conditions.");
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"A parameter.");
|
||||
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
|
||||
" solution.");
|
||||
args.AddOption(&coeffWeight, "-c", "--coeffMass",
|
||||
"the weight for the mass term.");
|
||||
args.AddOption(&exactH1Solver, "-exH1Sol", "--exactH1Solver", "-H1prec",
|
||||
"--H1preconditioner",
|
||||
"Use exact H1 solvers for the preconditioner.");
|
||||
args.AddOption(&spe10Coeff, "-spe10", "--useSPE10Coeff", "-constCoeff",
|
||||
"--constCoeff",
|
||||
"Switch between the coefficients for the mass bilinear form.");
|
||||
args.AddOption(&standardCG, "-sCG", "--stdCG", "-rCG", "--resCG",
|
||||
"Switch between standard PCG or recompute residuals in every step and use the residuals itself for the stopping criteria.");
|
||||
args.AddOption(&weightStart, "-ws", "--weightStart",
|
||||
"the exponent for the starting weight (for the mass term).");
|
||||
args.AddOption(&weightEnd, "-we", "--weightEnd",
|
||||
"the exponent for the weight at the end (for the mass term).");
|
||||
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
if (verbose) { args.PrintOptions(cout); }
|
||||
|
||||
kappa = freq * M_PI;
|
||||
|
||||
Mesh *mesh;
|
||||
ifstream imesh(mesh_file);
|
||||
if (!imesh)
|
||||
{
|
||||
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
mesh = new Mesh(imesh, 1, 1);
|
||||
imesh.close();
|
||||
|
||||
dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
|
||||
if (dim !=4 || sdim != 4)
|
||||
{
|
||||
MPI_Finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<sequ_ref_levels; i++) { mesh->UniformRefinement(); }
|
||||
if (verbose) { mesh->PrintCharacteristics(); }
|
||||
|
||||
if (verbose) { cout << "now we partition the mesh..." << endl << endl; }
|
||||
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
|
||||
for (int i=0; i<par_ref_levels; i++) { pmesh->UniformRefinement(); }
|
||||
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
pmesh->PrintInfo(std::cout);
|
||||
if (verbose) { cout << endl; }
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Nedelec finite elements of the specified order.
|
||||
FiniteElementCollection *fec;
|
||||
if (dim==4)
|
||||
{
|
||||
if (order==1) { fec = new ND1_4DFECollection; }
|
||||
else { fec = new ND2_4DFECollection; }
|
||||
}
|
||||
else { fec = new ND_FECollection(order, dim); }
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes from the mesh as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = set_bc ? 1 : 0;
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 8. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system, which in this case is
|
||||
// (f,phi_i) where f is given by the function f_exact and phi_i are the
|
||||
// basis functions in the finite element fespace.
|
||||
|
||||
|
||||
// 9. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x by projecting the exact
|
||||
// solution. Note that only values from the boundary edges will be used
|
||||
// when eliminating the non-homogeneous boundary condition to modify the
|
||||
// r.h.s. vector b.
|
||||
ParGridFunction x(fespace);
|
||||
VectorFunctionCoefficient E(sdim, E_exact);
|
||||
|
||||
for (int expo=weightStart; expo<=weightEnd; expo++)
|
||||
{
|
||||
double weight = pow(10.0,expo);
|
||||
kappa = weight;
|
||||
|
||||
VectorFunctionCoefficient f(sdim, f_exact);
|
||||
ParLinearForm *b = new ParLinearForm(fespace);
|
||||
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
|
||||
b->Assemble();
|
||||
|
||||
x.ProjectCoefficient(E);
|
||||
|
||||
// 10. Set up the parallel bilinear form corresponding to the EM diffusion
|
||||
// operator curl muinv curl + sigma I, by adding the curl-curl and the
|
||||
// mass domain integrators.
|
||||
// std::string permFile = "spe_perm.dat";
|
||||
// InversePermeabilityFunction::ReadPermeabilityFile(permFile, MPI_COMM_WORLD);
|
||||
|
||||
Coefficient *alpha = new ConstantCoefficient(1.0);
|
||||
Coefficient *beta;
|
||||
// if(spe10Coeff) beta = new FunctionCoefficient(InversePermeabilityFunction::Norm2Permeability);
|
||||
// else
|
||||
beta = new ConstantCoefficient(weight);
|
||||
Coefficient *neg_beta = new ConstantCoefficient(-weight);
|
||||
|
||||
ParBilinearForm *a = new ParBilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new CurlCurlIntegrator(*alpha));
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
|
||||
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, static condensation, etc.
|
||||
if (static_cond) { a->EnableStaticCondensation(); }
|
||||
a->Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
|
||||
}
|
||||
|
||||
// 12. Define and apply a parallel PCG solver for AX=B with the AMS
|
||||
// preconditioner from hypre.
|
||||
ParFiniteElementSpace *prec_fespace =
|
||||
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
|
||||
Solver *prec;
|
||||
if (dim<=3) { prec = new HypreAMS(A, prec_fespace); }
|
||||
else if (dim==4) { prec = new Curl4dPrec(&A, fespace, alpha, beta, neg_beta, ess_bdr, order, false); }
|
||||
IterativeSolver *pcg = new CGSolver(MPI_COMM_WORLD);
|
||||
pcg->SetOperator(A);
|
||||
pcg->SetRelTol(tol);
|
||||
pcg->SetMaxIter(5000);
|
||||
pcg->SetPrintLevel(1);
|
||||
pcg->SetPreconditioner(*prec);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
int iter = pcg->GetNumIterations();
|
||||
if (myid==0)
|
||||
{
|
||||
cout << "Weigth: " << weight << " " << iter << endl;
|
||||
|
||||
int *iters = LoadIterations(10, 2*NExpo+1);
|
||||
putIterationsInArray(iter, sequ_ref_levels+par_ref_levels, expo+NExpo,
|
||||
2*NExpo+1, iters);
|
||||
WriteIterations(iters, 10, 2*NExpo+1);
|
||||
}
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 14. Compute and print the L^2 norm of the error.
|
||||
{
|
||||
double err = x.ComputeL2Error(E);
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "\n|| E_h - E ||_{L^2} = " << err << '\n' << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 15. Save the refined mesh and the solution in parallel. This output can
|
||||
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
// {
|
||||
// ostringstream mesh_name, sol_name;
|
||||
// mesh_name << "mesh." << setfill('0') << setw(6) << myid;
|
||||
// sol_name << "sol." << setfill('0') << setw(6) << myid;
|
||||
//
|
||||
// ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
// mesh_ofs.precision(8);
|
||||
// pmesh->Print(mesh_ofs);
|
||||
//
|
||||
// ofstream sol_ofs(sol_name.str().c_str());
|
||||
// sol_ofs.precision(8);
|
||||
// x.Save(sol_ofs);
|
||||
// }
|
||||
|
||||
// // 16. Send the solution by socket to a GLVis server.
|
||||
// if (visualization)
|
||||
// {
|
||||
// char vishost[] = "localhost";
|
||||
// int visport = 19916;
|
||||
// socketstream sol_sock(vishost, visport);
|
||||
// sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
// sol_sock.precision(8);
|
||||
// sol_sock << "solution\n" << *pmesh << x << flush;
|
||||
// }
|
||||
|
||||
delete pcg;
|
||||
delete prec;
|
||||
delete a;
|
||||
delete alpha;
|
||||
delete beta;
|
||||
delete b;
|
||||
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete pmesh;
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void E_exact(const Vector &x, Vector &E)
|
||||
{
|
||||
if (dim==4)
|
||||
{
|
||||
E(0) = sin(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(1) = -cos(M_PI*x(0))*sin(M_PI*x(1))*cos(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(2) = cos(M_PI*x(0))*cos(M_PI*x(1))*sin(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(3) = -cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*sin(M_PI*x(3));
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
E(0) = sin(kappa * x(1));
|
||||
E(1) = sin(kappa * x(2));
|
||||
E(2) = sin(kappa * x(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
E(0) = sin(kappa * x(1));
|
||||
E(1) = sin(kappa * x(0));
|
||||
if (x.Size() == 3) { E(2) = 0.0; }
|
||||
}
|
||||
}
|
||||
|
||||
void f_exact(const Vector &x, Vector &f)
|
||||
{
|
||||
//f_exact = E + DivSkew P( curl E ), where P is the 4d permutation operator
|
||||
if (dim==4)
|
||||
{
|
||||
f(0) = (kappa+4.0*M_PI*M_PI)*sin(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(1) = -(kappa+4.0*M_PI*M_PI)*cos(M_PI*x(0))*sin(M_PI*x(1))*cos(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(2) = (kappa+4.0*M_PI*M_PI)*cos(M_PI*x(0))*cos(M_PI*x(1))*sin(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(3) = -(kappa+4.0*M_PI*M_PI)*cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*sin(
|
||||
M_PI*x(3));
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
|
||||
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
|
||||
f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
|
||||
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
|
||||
if (x.Size() == 3) { f(2) = 0.0; }
|
||||
}
|
||||
}
|
||||
+294
-257
@@ -2,53 +2,39 @@
|
||||
//
|
||||
// Compile with: make ex40
|
||||
//
|
||||
// Sample runs: ex40 -step 10 -gr 2.0
|
||||
// ex40 -step 10 -gr 2.0 -o 3 -r 1
|
||||
// ex40 -step 10 -gr 2.0 -r 4 -m ../data/l-shape.mesh
|
||||
// ex40 -step 10 -gr 2.0 -r 2 -m ../data/fichera.mesh
|
||||
// Sample runs: ex40 -o 2
|
||||
// ex40 -o 2 -r 4
|
||||
//
|
||||
// Description: This example code demonstrates how to use MFEM to solve the
|
||||
// eikonal equation,
|
||||
// Description: This example code demonstrates to how to use MFEM to solve
|
||||
// the Monge–Ampère equation
|
||||
//
|
||||
// |∇𝑢| = 1 in Ω, 𝑢 = g on ∂Ω.
|
||||
// det(∇²u) = f in Ω, u = 0 on ∂Ω.
|
||||
//
|
||||
// The solution of this problem coincides with the unique optimum of
|
||||
// the nonlinear program
|
||||
// This example highlights the ExponentialMatrixCoefficient
|
||||
// class, which is used in Newton's method to solve the
|
||||
// variational formulation
|
||||
//
|
||||
// maximize ∫_Ω 𝑢 d𝑥 subject to |∇𝑢| ≤ 1, 𝑢 = g on Ω, (⋆)
|
||||
// Find M ∈ H₀(div,Ω)ⁿ and u ∈ H₀¹(Ω) such that
|
||||
// (exp(M), N) + (∇u, ∇⋅N) = 0 ∀ N ∈ H₀(div,Ω)ⁿ
|
||||
// (tr(M), v) = (ln f, v) ∀ v ∈ H₀¹(Ω)
|
||||
//
|
||||
// which is the foundation for method implemented below.
|
||||
// where n is the spatial dimension of the domain Ω.
|
||||
//
|
||||
// Following the proximal Galerkin methodology [1] (see also Example
|
||||
// 36), we construct a Legendre function for the unit ball
|
||||
// 𝐵₁ := {𝑥 ∈ Rⁿ | |𝑥| < 1}. Our choice is the Hellinger entropy,
|
||||
//
|
||||
// h(𝑥) = −( 1 − |𝑥|² )^{1/2},
|
||||
// The linearized subproblem is
|
||||
//
|
||||
// although other choices are possible, each leading to a slightly
|
||||
// different algorithm. We then adaptively regularize the optimization
|
||||
// problem (⋆) with the Bregman divergence of the Hellinger entropy,
|
||||
// Find δM ∈ H₀(div,Ω)ⁿ and u ∈ H₀¹(Ω) such that
|
||||
// (exp(M) δM, N) + (∇u, ∇⋅N) = -(exp(M), N) ∀ N ∈ H₀(div,Ω)ⁿ
|
||||
// (tr(δM), v) = (ln f - tr(M), v) ∀ v ∈ H₀¹(Ω)
|
||||
//
|
||||
// maximize ∫_Ω 𝑢 d𝑥 - αₖ⁻¹ Dₕ(∇𝑢,∇𝑢ₖ₋₁) subject to 𝑢 = g on Ω.
|
||||
//
|
||||
// This results in a sequence of functions ( 𝜓ₖ , 𝑢ₖ ),
|
||||
// (exp(M) δM, N) ::: VectorFEMassIntegrator
|
||||
// (∇u, ∇⋅N) ::: MixedGradDivIntegrator
|
||||
// (tr(δM), v) ::: MixedDotProductIntegrator
|
||||
// (exp(M), N) ::: VectorFEDomainLFIntegrator
|
||||
// (ln f - tr(M), v) ::: DomainLFIntegrator
|
||||
//
|
||||
// 𝑢ₖ → 𝑢, 𝜓ₖ/|𝜓ₖ| → ∇𝑢 as k → \infty,
|
||||
//
|
||||
// defined by the nonlinear saddle-point problems
|
||||
//
|
||||
// Find 𝜓ₖ ∈ H(div,Ω) and 𝑢ₖ ∈ L²(Ω) such that
|
||||
// ( Zₖ(𝜓ₖ) , τ ) + ( 𝑢ₖ , ∇⋅τ ) = ⟨ g , τ⋅n ⟩ ∀ τ ∈ H(div,Ω)
|
||||
// ( ∇⋅𝜓ₖ , v ) = ( ∇⋅𝜓ₖ₋₁ - 1 , v ) ∀ v ∈ L²(Ω)
|
||||
//
|
||||
// where Zₖ(𝜓) := ∇h⁻¹(αₖ 𝜓) = 𝜓 / ( αₖ⁻² + |𝜓|² )^{1/2} and step size
|
||||
// αₖ > 0. These saddle-point problems are solved using a damped Newton's
|
||||
// method. This example assumes that g = 0 and allows the step size to
|
||||
// grow geometrically, αₖ = α₀rᵏ, where r ≥ 1 is the growth rate.
|
||||
//
|
||||
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
|
||||
// preserving finite element method for pointwise bound constraints.
|
||||
// arXiv:2307.12444 [math.NA]
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
@@ -57,53 +43,23 @@
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
class ZCoefficient : public VectorCoefficient
|
||||
{
|
||||
protected:
|
||||
GridFunction *psi;
|
||||
real_t alpha;
|
||||
|
||||
public:
|
||||
ZCoefficient(int vdim, GridFunction &psi_, real_t alpha_ = 1.0)
|
||||
: VectorCoefficient(vdim), psi(&psi_), alpha(alpha_) { }
|
||||
|
||||
virtual void Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
void SetAlpha(real_t alpha_) { alpha = alpha_; }
|
||||
};
|
||||
|
||||
class DZCoefficient : public MatrixCoefficient
|
||||
{
|
||||
protected:
|
||||
GridFunction *psi;
|
||||
real_t alpha;
|
||||
|
||||
public:
|
||||
DZCoefficient(int height, GridFunction &psi_, real_t alpha_ = 1.0)
|
||||
: MatrixCoefficient(height), psi(&psi_), alpha(alpha_) { }
|
||||
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
void SetAlpha(real_t alpha_) { alpha = alpha_; }
|
||||
};
|
||||
real_t exact_solution(const Vector &pt);
|
||||
void exact_solution_gradient(const Vector &pt, Vector &grad);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
int order = 1;
|
||||
int max_it = 5;
|
||||
int ref_levels = 3;
|
||||
real_t alpha = 1.0;
|
||||
real_t growth_rate = 1.0;
|
||||
real_t newton_scaling = 0.9;
|
||||
real_t tichonov = 1e-1;
|
||||
real_t tol = 1e-4;
|
||||
const char *mesh_file = "../data/disc-nurbs.mesh";
|
||||
// const char *mesh_file = "../data/star.mesh";
|
||||
int order = 2;
|
||||
int max_it = 10;
|
||||
int ref_levels = 1;
|
||||
real_t tol = 1e-5;
|
||||
bool visualization = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
"Mesh file.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&ref_levels, "-r", "--refs",
|
||||
@@ -113,10 +69,6 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"Stopping criteria based on the difference between"
|
||||
"successive solution updates");
|
||||
args.AddOption(&alpha, "-step", "--step",
|
||||
"Initial size alpha");
|
||||
args.AddOption(&growth_rate, "-gr", "--growth-rate",
|
||||
"Growth rate of the step size alpha");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
@@ -131,12 +83,11 @@ int main(int argc, char *argv[])
|
||||
// 2. Read the mesh from the mesh file.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
int sdim = mesh.SpaceDimension();
|
||||
|
||||
MFEM_ASSERT(mesh.bdr_attributes.Size(),
|
||||
"This example does not currently support meshes"
|
||||
" without boundary attributes."
|
||||
)
|
||||
if (dim != 2)
|
||||
{
|
||||
MFEM_ABORT("Example 40 currently only supports 2D problems")
|
||||
}
|
||||
|
||||
// 3. Postprocess the mesh.
|
||||
// 3A. Refine the mesh to increase the resolution.
|
||||
@@ -151,45 +102,73 @@ int main(int argc, char *argv[])
|
||||
mesh.SetCurvature(curvature_order);
|
||||
|
||||
// 4. Define the necessary finite element spaces on the mesh.
|
||||
RT_FECollection RTfec(order, dim);
|
||||
H1_FECollection H1fec(order, dim);
|
||||
FiniteElementSpace H1fes(&mesh, &H1fec);
|
||||
|
||||
RT_FECollection RTfec(order-1, dim);
|
||||
FiniteElementSpace RTfes(&mesh, &RTfec);
|
||||
|
||||
L2_FECollection L2fec(order, dim);
|
||||
FiniteElementSpace L2fes(&mesh, &L2fec);
|
||||
cout << "Number of H¹ degrees of freedom: "
|
||||
<< H1fes.GetTrueVSize() << endl;
|
||||
cout << "Number of H(div) degrees of freedom: "
|
||||
<< RTfes.GetTrueVSize() * dim << endl;
|
||||
|
||||
cout << "Number of H(div) dofs: "
|
||||
<< RTfes.GetTrueVSize() << endl;
|
||||
cout << "Number of L² dofs: "
|
||||
<< L2fes.GetTrueVSize() << endl;
|
||||
|
||||
// 5. Define the offsets for the block matrices
|
||||
Array<int> offsets(3);
|
||||
Array<int> offsets(4);
|
||||
offsets[0] = 0;
|
||||
offsets[1] = RTfes.GetVSize();
|
||||
offsets[2] = L2fes.GetVSize();
|
||||
offsets[2] = RTfes.GetVSize();
|
||||
offsets[3] = H1fes.GetVSize();
|
||||
offsets.PartialSum();
|
||||
|
||||
BlockVector x(offsets), rhs(offsets);
|
||||
x = 0.0; rhs = 0.0;
|
||||
|
||||
// 6. Define the solution vectors as a finite element grid functions
|
||||
// 5. Determine the list of true (i.e., conforming) essential boundary dofs.
|
||||
Array<int> ess_bdr;
|
||||
if (mesh.bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(mesh.bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
}
|
||||
|
||||
// 6. Define constants to be used later.
|
||||
ConstantCoefficient one(1.0);
|
||||
ConstantCoefficient neg_one(-1.0);
|
||||
ConstantCoefficient zero(0.0);
|
||||
Vector V1(2), V2(2);
|
||||
V1(0) = 1.0; V1(1) = 0.0;
|
||||
V2(0) = 0.0; V2(1) = 1.0;
|
||||
VectorConstantCoefficient onezero(V1);
|
||||
VectorConstantCoefficient zeroone(V2);
|
||||
ScalarVectorProductCoefficient neg_onezero(-1.0, onezero);
|
||||
ScalarVectorProductCoefficient neg_zeroone(-1.0, zeroone);
|
||||
|
||||
// 7. Define the solution vectors as finite element grid functions
|
||||
// corresponding to the fespaces.
|
||||
GridFunction u_gf, delta_psi_gf;
|
||||
delta_psi_gf.MakeRef(&RTfes,x,offsets[0]);
|
||||
u_gf.MakeRef(&L2fes,x,offsets[1]);
|
||||
GridFunction delta_M1_gf, delta_M2_gf, delta_u_gf;
|
||||
|
||||
GridFunction psi_old_gf(&RTfes);
|
||||
GridFunction psi_gf(&RTfes);
|
||||
GridFunction u_old_gf(&L2fes);
|
||||
delta_M1_gf.MakeRef(&RTfes,x,offsets[0]);
|
||||
delta_M2_gf.MakeRef(&RTfes,x,offsets[1]);
|
||||
delta_u_gf.MakeRef(&H1fes,x,offsets[2]);
|
||||
|
||||
// 7. Define initial guesses for the solution variables.
|
||||
delta_psi_gf = 0.0;
|
||||
psi_gf = 0.0;
|
||||
u_gf = 0.0;
|
||||
psi_old_gf = psi_gf;
|
||||
u_old_gf = u_gf;
|
||||
GridFunction M1_gf(&RTfes);
|
||||
GridFunction M2_gf(&RTfes);
|
||||
GridFunction u_gf(&H1fes);
|
||||
|
||||
// 8. Define the function coefficients for the solution and use them to
|
||||
// initialize the initial guess
|
||||
FunctionCoefficient exact_coef(exact_solution);
|
||||
VectorFunctionCoefficient exact_grad_coef(dim,exact_solution_gradient);
|
||||
ConstantCoefficient ln_rhs_coef(0.0);
|
||||
u_gf.ProjectCoefficient(exact_coef);
|
||||
// u_gf.ProjectCoefficient(zero);
|
||||
M1_gf = 0.0;
|
||||
M2_gf = 0.0;
|
||||
|
||||
delta_M1_gf = 0.0;
|
||||
delta_M2_gf = 0.0;
|
||||
delta_u_gf = 0.0;
|
||||
|
||||
// 8. Prepare for glvis output.
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock;
|
||||
@@ -199,176 +178,234 @@ int main(int argc, char *argv[])
|
||||
sol_sock.precision(8);
|
||||
}
|
||||
|
||||
// 9. Coefficients to be used later.
|
||||
ConstantCoefficient neg_one(-1.0);
|
||||
ConstantCoefficient zero(0.0);
|
||||
ConstantCoefficient tichonov_cf(tichonov);
|
||||
ConstantCoefficient neg_tichonov_cf(-1.0*tichonov);
|
||||
ZCoefficient Z(sdim, psi_gf, alpha);
|
||||
DZCoefficient DZ(sdim, psi_gf, alpha);
|
||||
ScalarVectorProductCoefficient neg_Z(-1.0, Z);
|
||||
DivergenceGridFunctionCoefficient div_psi_cf(&psi_gf);
|
||||
DivergenceGridFunctionCoefficient div_psi_old_cf(&psi_old_gf);
|
||||
SumCoefficient psi_old_minus_psi(div_psi_old_cf, div_psi_cf, 1.0, -1.0);
|
||||
|
||||
// 10. Assemble constant matrices/vectors to avoid reassembly in the loop.
|
||||
LinearForm b0, b1;
|
||||
b0.MakeRef(&RTfes,rhs.GetBlock(0),0);
|
||||
b1.MakeRef(&L2fes,rhs.GetBlock(1),0);
|
||||
|
||||
b0.AddDomainIntegrator(new VectorFEDomainLFIntegrator(neg_Z));
|
||||
b1.AddDomainIntegrator(new DomainLFIntegrator(neg_one));
|
||||
b1.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
|
||||
|
||||
BilinearForm a00(&RTfes);
|
||||
a00.AddDomainIntegrator(new VectorFEMassIntegrator(DZ));
|
||||
a00.AddDomainIntegrator(new VectorFEMassIntegrator(tichonov_cf));
|
||||
|
||||
MixedBilinearForm a10(&RTfes,&L2fes);
|
||||
a10.AddDomainIntegrator(new VectorFEDivergenceIntegrator());
|
||||
a10.Assemble();
|
||||
a10.Finalize();
|
||||
SparseMatrix &A10 = a10.SpMat();
|
||||
SparseMatrix *A01 = Transpose(A10);
|
||||
|
||||
BilinearForm a11(&L2fes);
|
||||
a11.AddDomainIntegrator(new MassIntegrator(neg_tichonov_cf));
|
||||
a11.Assemble();
|
||||
a11.Finalize();
|
||||
SparseMatrix &A11 = a11.SpMat();
|
||||
|
||||
// 11. Iterate.
|
||||
// 10. Iterate
|
||||
int k;
|
||||
int total_iterations = 0;
|
||||
real_t increment_u = 0.1;
|
||||
GridFunction u_tmp(&L2fes);
|
||||
for (k = 0; k < max_it; k++)
|
||||
{
|
||||
u_tmp = u_old_gf;
|
||||
Z.SetAlpha(alpha);
|
||||
DZ.SetAlpha(alpha);
|
||||
mfem::out << "\nITERATION " << k+1 << endl;
|
||||
|
||||
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
|
||||
LinearForm b0,b1,b2;
|
||||
b0.Update(&RTfes,rhs.GetBlock(0),0);
|
||||
b1.Update(&RTfes,rhs.GetBlock(1),0);
|
||||
b2.Update(&H1fes,rhs.GetBlock(2),0);
|
||||
|
||||
int j;
|
||||
for ( j = 0; j < 5; j++)
|
||||
VectorGridFunctionCoefficient M1(&M1_gf);
|
||||
VectorGridFunctionCoefficient M2(&M2_gf);
|
||||
|
||||
MatrixArrayVectorCoefficient M(dim);
|
||||
M.Set(0, &M1, false);
|
||||
M.Set(1, &M2, false);
|
||||
ExponentialMatrixCoefficient exp_M(M);
|
||||
|
||||
MatrixVectorProductCoefficient exp_M1(exp_M, onezero);
|
||||
MatrixVectorProductCoefficient exp_M2(exp_M, zeroone);
|
||||
InnerProductCoefficient exp_M11(exp_M1, onezero);
|
||||
InnerProductCoefficient exp_M12(exp_M1, zeroone);
|
||||
InnerProductCoefficient exp_M21(exp_M2, onezero);
|
||||
InnerProductCoefficient exp_M22(exp_M2, zeroone);
|
||||
|
||||
GradientGridFunctionCoefficient grad_u(&u_gf);
|
||||
InnerProductCoefficient neg_dudx(neg_onezero, grad_u);
|
||||
ScalarVectorProductCoefficient neg_exp_M1(-1.0, exp_M1);
|
||||
b0.AddDomainIntegrator(new VectorFEDomainLFDivIntegrator(neg_dudx));
|
||||
b0.AddDomainIntegrator(new VectorFEDomainLFIntegrator(neg_exp_M1));
|
||||
b0.Assemble();
|
||||
|
||||
InnerProductCoefficient neg_dudy(neg_zeroone, grad_u);
|
||||
b1.AddDomainIntegrator(new VectorFEDomainLFDivIntegrator(neg_dudy));
|
||||
ScalarVectorProductCoefficient neg_exp_M2(-1.0, exp_M2);
|
||||
b1.AddDomainIntegrator(new VectorFEDomainLFIntegrator(neg_exp_M2));
|
||||
b1.Assemble();
|
||||
|
||||
InnerProductCoefficient M11(M1, onezero);
|
||||
InnerProductCoefficient M22(M2, zeroone);
|
||||
SumCoefficient trace_M(M11, M22);
|
||||
SumCoefficient rhs2(ln_rhs_coef, trace_M, 1.0, -1.0);
|
||||
b2.AddDomainIntegrator(new DomainLFIntegrator(rhs2));
|
||||
b2.Assemble();
|
||||
|
||||
cout << "b0.Norml2() = " << b0.Norml2() << endl;
|
||||
cout << "b1.Norml2() = " << b1.Norml2() << endl;
|
||||
cout << "b2.Norml2() = " << b2.Norml2() << endl;
|
||||
|
||||
BilinearForm a00(&RTfes);
|
||||
a00.AddDomainIntegrator(new VectorFEMassIntegrator());
|
||||
// a00.AddDomainIntegrator(new VectorFEMassIntegrator(exp_M11));
|
||||
a00.Assemble();
|
||||
a00.EliminateEssentialBC(ess_bdr,x.GetBlock(0),rhs.GetBlock(0),mfem::Operator::DIAG_ONE);
|
||||
a00.Finalize();
|
||||
SparseMatrix &A00 = a00.SpMat();
|
||||
|
||||
BilinearForm a01(&RTfes);
|
||||
a01.AddDomainIntegrator(new VectorFEMassIntegrator(zero));
|
||||
// a01.AddDomainIntegrator(new VectorFEMassIntegrator(exp_M12));
|
||||
a01.Assemble();
|
||||
a01.EliminateEssentialBC(ess_bdr,mfem::Operator::DIAG_ZERO);
|
||||
a01.Finalize();
|
||||
SparseMatrix &A01 = a01.SpMat();
|
||||
|
||||
MixedBilinearForm a02(&H1fes,&RTfes);
|
||||
a02.AddDomainIntegrator(new MixedGradDivIntegrator(neg_onezero));
|
||||
a02.Assemble(false);
|
||||
a02.EliminateTrialDofs(ess_bdr,x.GetBlock(2),rhs.GetBlock(0));
|
||||
a02.EliminateTestDofs(ess_bdr);
|
||||
a02.Finalize();
|
||||
SparseMatrix &A02 = a02.SpMat();
|
||||
|
||||
BilinearForm a10(&RTfes);
|
||||
a10.AddDomainIntegrator(new VectorFEMassIntegrator(zero));
|
||||
// a10.AddDomainIntegrator(new VectorFEMassIntegrator(exp_M21));
|
||||
a10.Assemble();
|
||||
a10.EliminateEssentialBC(ess_bdr,mfem::Operator::DIAG_ZERO);
|
||||
a10.Finalize();
|
||||
SparseMatrix &A10 = a10.SpMat();
|
||||
|
||||
BilinearForm a11(&RTfes);
|
||||
a11.AddDomainIntegrator(new VectorFEMassIntegrator());
|
||||
// a11.AddDomainIntegrator(new VectorFEMassIntegrator(exp_M22));
|
||||
a11.Assemble();
|
||||
a11.EliminateEssentialBC(ess_bdr,x.GetBlock(1),rhs.GetBlock(1),mfem::Operator::DIAG_ONE);
|
||||
a11.Finalize();
|
||||
SparseMatrix &A11 = a11.SpMat();
|
||||
|
||||
MixedBilinearForm a12(&H1fes,&RTfes);
|
||||
a12.AddDomainIntegrator(new MixedGradDivIntegrator(neg_zeroone));
|
||||
a12.Assemble(false);
|
||||
a12.EliminateTrialDofs(ess_bdr,x.GetBlock(2),rhs.GetBlock(1));
|
||||
a12.EliminateTestDofs(ess_bdr);
|
||||
a12.Finalize();
|
||||
SparseMatrix &A12 = a12.SpMat();
|
||||
|
||||
MixedBilinearForm a20(&RTfes,&H1fes);
|
||||
a20.AddDomainIntegrator(new MixedDotProductIntegrator(onezero));
|
||||
a20.Assemble();
|
||||
a20.EliminateTrialDofs(ess_bdr,x.GetBlock(0),rhs.GetBlock(2));
|
||||
a20.EliminateTestDofs(ess_bdr);
|
||||
a20.Finalize();
|
||||
SparseMatrix &A20 = a20.SpMat();
|
||||
|
||||
MixedBilinearForm a21(&RTfes,&H1fes);
|
||||
a21.AddDomainIntegrator(new MixedDotProductIntegrator(zeroone));
|
||||
a21.Assemble();
|
||||
a21.EliminateTrialDofs(ess_bdr,x.GetBlock(1),rhs.GetBlock(2));
|
||||
a21.EliminateTestDofs(ess_bdr);
|
||||
a21.Finalize();
|
||||
SparseMatrix &A21 = a21.SpMat();
|
||||
|
||||
BilinearForm a22(&H1fes);
|
||||
// a22.AddDomainIntegrator(new MassIntegrator(neg_one));
|
||||
a22.AddDomainIntegrator(new MassIntegrator(zero));
|
||||
a22.Assemble(false);
|
||||
a22.EliminateEssentialBC(ess_bdr,x.GetBlock(2),rhs.GetBlock(2),mfem::Operator::DIAG_ONE);
|
||||
a22.Finalize();
|
||||
SparseMatrix &A22 = a22.SpMat();
|
||||
|
||||
cout << "b0.Norml2() = " << b0.Norml2() << endl;
|
||||
cout << "b1.Norml2() = " << b1.Norml2() << endl;
|
||||
cout << "b2.Norml2() = " << b2.Norml2() << endl;
|
||||
|
||||
// BlockOperator A(offsets);
|
||||
// A.SetBlock(0,0,&A00);
|
||||
// A.SetBlock(0,1,&A01);
|
||||
// A.SetBlock(0,2,&A02);
|
||||
// A.SetBlock(1,0,&A10);
|
||||
// A.SetBlock(1,1,&A11);
|
||||
// A.SetBlock(1,2,&A12);
|
||||
// A.SetBlock(2,0,&A20);
|
||||
// A.SetBlock(2,1,&A21);
|
||||
// A.SetBlock(2,2,&A22);
|
||||
|
||||
// BlockDiagonalPreconditioner prec(offsets);
|
||||
// prec.SetDiagonalBlock(0,new GSSmoother(A00));
|
||||
// prec.SetDiagonalBlock(1,new GSSmoother(A11));
|
||||
// prec.SetDiagonalBlock(1,new GSSmoother(A22));
|
||||
// prec.owns_blocks = 1;
|
||||
|
||||
// GMRES(A,prec,rhs,x,1,10000,500,1e-12,0.0);
|
||||
|
||||
BlockMatrix A(offsets);
|
||||
A.SetBlock(0,0,&A00);
|
||||
A.SetBlock(0,1,&A01);
|
||||
A.SetBlock(0,2,&A02);
|
||||
A.SetBlock(1,0,&A10);
|
||||
A.SetBlock(1,1,&A11);
|
||||
A.SetBlock(1,2,&A12);
|
||||
A.SetBlock(2,0,&A20);
|
||||
A.SetBlock(2,1,&A21);
|
||||
A.SetBlock(2,2,&A22);
|
||||
|
||||
SparseMatrix * A_mono = A.CreateMonolithic();
|
||||
UMFPackSolver umf(*A_mono);
|
||||
umf.Mult(rhs,x);
|
||||
|
||||
delta_M1_gf.MakeRef(&RTfes, x.GetBlock(0), 0);
|
||||
delta_M2_gf.MakeRef(&RTfes, x.GetBlock(1), 0);
|
||||
delta_u_gf.MakeRef(&H1fes, x.GetBlock(2), 0);
|
||||
|
||||
real_t Newton_update_size = delta_u_gf.ComputeL2Error(zero);
|
||||
|
||||
real_t gamma = 0.3;
|
||||
delta_M1_gf *= gamma;
|
||||
delta_M2_gf *= gamma;
|
||||
delta_u_gf *= gamma;
|
||||
M1_gf += delta_M1_gf;
|
||||
M2_gf += delta_M2_gf;
|
||||
u_gf += delta_u_gf;
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
total_iterations++;
|
||||
|
||||
b0.Assemble();
|
||||
b1.Assemble();
|
||||
|
||||
a00.Assemble(false);
|
||||
a00.Finalize(false);
|
||||
SparseMatrix &A00 = a00.SpMat();
|
||||
|
||||
// Construct Schur-complement preconditioner
|
||||
Vector A00_diag(a00.Height());
|
||||
A00.GetDiag(A00_diag);
|
||||
A00_diag.Reciprocal();
|
||||
SparseMatrix *S = Mult_AtDA(*A01, A00_diag);
|
||||
|
||||
BlockDiagonalPreconditioner prec(offsets);
|
||||
prec.SetDiagonalBlock(0,new DSmoother(A00));
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
prec.SetDiagonalBlock(1,new GSSmoother(*S));
|
||||
#else
|
||||
prec.SetDiagonalBlock(1,new UMFPackSolver(*S));
|
||||
#endif
|
||||
prec.owns_blocks = 1;
|
||||
|
||||
BlockOperator A(offsets);
|
||||
A.SetBlock(0,0,&A00);
|
||||
A.SetBlock(1,0,&A10);
|
||||
A.SetBlock(0,1,A01);
|
||||
A.SetBlock(1,1,&A11);
|
||||
|
||||
GMRES(A,prec,rhs,x,0,2000,500,1e-12,0.0);
|
||||
delete S;
|
||||
|
||||
u_tmp -= u_gf;
|
||||
real_t Newton_update_size = u_tmp.ComputeL2Error(zero);
|
||||
u_tmp = u_gf;
|
||||
|
||||
// Damped Newton update
|
||||
psi_gf.Add(newton_scaling, delta_psi_gf);
|
||||
a00.Update();
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
sol_sock << "solution\n" << mesh << u_gf << "window_title 'Discrete solution'"
|
||||
<< flush;
|
||||
}
|
||||
|
||||
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
|
||||
|
||||
if (Newton_update_size < increment_u)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// sol_sock << "solution\n" << mesh << delta_M1_gf << "window_title 'Discrete solution'"
|
||||
sol_sock << "solution\n" << mesh << u_gf << "window_title 'Discrete solution'"
|
||||
<< flush;
|
||||
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << Newton_update_size <<
|
||||
endl;
|
||||
}
|
||||
|
||||
u_tmp = u_gf;
|
||||
u_tmp -= u_old_gf;
|
||||
increment_u = u_tmp.ComputeL2Error(zero);
|
||||
// if (Newton_update_size < tol || k == max_it-1)
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
|
||||
mfem::out << "Number of Newton iterations = " << j+1 << endl;
|
||||
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
|
||||
real_t H1_error = u_gf.ComputeH1Error(&exact_coef,&exact_grad_coef);
|
||||
real_t L2_error = u_gf.ComputeL2Error(exact_coef);
|
||||
mfem::out << "L2-error (|| u - uₕᵏ||) = " << L2_error << endl;
|
||||
// mfem::out << "H1-error (|| u - uₕᵏ||) = " << H1_error << endl;
|
||||
|
||||
u_old_gf = u_gf;
|
||||
psi_old_gf = psi_gf;
|
||||
|
||||
if (increment_u < tol || k == max_it-1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
alpha *= max(growth_rate, 1_r);
|
||||
cin.get();
|
||||
|
||||
}
|
||||
|
||||
mfem::out << "\n Outer iterations: " << k+1
|
||||
<< "\n Total iterations: " << total_iterations
|
||||
<< "\n Total dofs: " << RTfes.GetTrueVSize() + L2fes.GetTrueVSize()
|
||||
mfem::out << "\n Total iterations: " << k+1
|
||||
<< "\n Total dofs: " << RTfes.GetTrueVSize() * 2 + H1fes.GetTrueVSize()
|
||||
<< endl;
|
||||
|
||||
delete A01;
|
||||
// 11. Exact solution.
|
||||
// if (visualization)
|
||||
// {
|
||||
// socketstream err_sock(vishost, visport);
|
||||
// err_sock.precision(8);
|
||||
|
||||
// GridFunction error_gf(&H1fes);
|
||||
// error_gf.ProjectCoefficient(exact_coef);
|
||||
// error_gf -= u_gf;
|
||||
|
||||
// err_sock << "solution\n" << mesh << error_gf << "window_title 'Error'" <<
|
||||
// flush;
|
||||
// }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ZCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
real_t exact_solution(const Vector &pt)
|
||||
{
|
||||
MFEM_ASSERT(psi != NULL, "grid function is not set");
|
||||
MFEM_ASSERT(alpha > 0, "alpha is not positive");
|
||||
|
||||
Vector psi_vals(vdim);
|
||||
psi->GetVectorValue(T, ip, psi_vals);
|
||||
real_t norm = psi_vals.Norml2();
|
||||
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
|
||||
|
||||
V = psi_vals;
|
||||
V *= phi;
|
||||
real_t x = pt(0), y = pt(1);
|
||||
return (x*x + y*y) / 2.0 - 4.0;
|
||||
}
|
||||
|
||||
void DZCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
void exact_solution_gradient(const Vector &pt, Vector &grad)
|
||||
{
|
||||
MFEM_ASSERT(psi != NULL, "grid function is not set");
|
||||
MFEM_ASSERT(alpha > 0, "alpha is not positive");
|
||||
real_t x = pt(0), y = pt(1);
|
||||
|
||||
Vector psi_vals(height);
|
||||
psi->GetVectorValue(T, ip, psi_vals);
|
||||
real_t norm = psi_vals.Norml2();
|
||||
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
|
||||
|
||||
K = 0.0;
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
K(i,i) = phi;
|
||||
for (int j = 0; j < height; j++)
|
||||
{
|
||||
K(i,j) -= psi_vals(i) * psi_vals(j) * pow(phi, 3);
|
||||
}
|
||||
}
|
||||
grad(0) = x;
|
||||
grad(1) = y;
|
||||
}
|
||||
|
||||
@@ -1,436 +0,0 @@
|
||||
// MFEM Example 40 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex40p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex40p -step 10 -gr 2.0
|
||||
// mpirun -np 4 ex40p -step 10 -gr 2.0 -o 3 -r 1
|
||||
// mpirun -np 4 ex40p -step 10 -gr 2.0 -r 4 -m ../data/l-shape.mesh
|
||||
// mpirun -np 4 ex40p -step 10 -gr 2.0 -r 2 -m ../data/fichera.mesh
|
||||
//
|
||||
// Description: This example code demonstrates how to use MFEM to solve the
|
||||
// eikonal equation,
|
||||
//
|
||||
// |∇𝑢| = 1 in Ω, 𝑢 = g on ∂Ω.
|
||||
//
|
||||
// The solution of this problem coincides with the unique optimum of
|
||||
// the nonlinear program
|
||||
//
|
||||
// maximize ∫_Ω 𝑢 d𝑥 subject to |∇𝑢| ≤ 1, 𝑢 = g on Ω, (⋆)
|
||||
//
|
||||
// which is the foundation for method implemented below.
|
||||
//
|
||||
// Following the proximal Galerkin methodology [1] (see also Example
|
||||
// 36), we construct a Legendre function for the unit ball
|
||||
// 𝐵₁ := {𝑥 ∈ Rⁿ | |𝑥| < 1}. Our choice is the Hellinger entropy,
|
||||
//
|
||||
// h(𝑥) = −( 1 − |𝑥|² )^{1/2},
|
||||
//
|
||||
// although other choices are possible, each leading to a slightly
|
||||
// different algorithm. We then adaptively regularize the optimization
|
||||
// problem (⋆) with the Bregman divergence of the Hellinger entropy,
|
||||
//
|
||||
// maximize ∫_Ω 𝑢 d𝑥 - αₖ⁻¹ Dₕ(∇𝑢,∇𝑢ₖ₋₁) subject to 𝑢 = g on Ω.
|
||||
//
|
||||
// This results in a sequence of functions ( 𝜓ₖ , 𝑢ₖ ),
|
||||
//
|
||||
// 𝑢ₖ → 𝑢, 𝜓ₖ/|𝜓ₖ| → ∇𝑢 as k → \infty,
|
||||
//
|
||||
// defined by the nonlinear saddle-point problems
|
||||
//
|
||||
// Find 𝜓ₖ ∈ H(div,Ω) and 𝑢ₖ ∈ L²(Ω) such that
|
||||
// ( Zₖ(𝜓ₖ) , τ ) + ( 𝑢ₖ , ∇⋅τ ) = ⟨ g , τ⋅n ⟩ ∀ τ ∈ H(div,Ω)
|
||||
// ( ∇⋅𝜓ₖ , v ) = ( ∇⋅𝜓ₖ₋₁ - 1 , v ) ∀ v ∈ L²(Ω)
|
||||
//
|
||||
// where Zₖ(𝜓) := ∇h⁻¹(αₖ 𝜓) = 𝜓 / ( αₖ⁻² + |𝜓|² )^{1/2} and step size
|
||||
// αₖ > 0. These saddle-point problems are solved using a damped Newton's
|
||||
// method. This example assumes that g = 0 and allows the step size to
|
||||
// grow geometrically, αₖ = α₀rᵏ, where r ≥ 1 is the growth rate.
|
||||
//
|
||||
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
|
||||
// preserving finite element method for pointwise bound constraints.
|
||||
// arXiv:2307.12444 [math.NA]
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
class ZCoefficient : public VectorCoefficient
|
||||
{
|
||||
protected:
|
||||
ParGridFunction *psi;
|
||||
real_t alpha;
|
||||
|
||||
public:
|
||||
ZCoefficient(int vdim, ParGridFunction &psi_, real_t alpha_ = 1.0)
|
||||
: VectorCoefficient(vdim), psi(&psi_), alpha(alpha_) { }
|
||||
|
||||
virtual void Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
void SetAlpha(real_t alpha_) { alpha = alpha_; }
|
||||
};
|
||||
|
||||
class DZCoefficient : public MatrixCoefficient
|
||||
{
|
||||
protected:
|
||||
ParGridFunction *psi;
|
||||
real_t alpha;
|
||||
|
||||
public:
|
||||
DZCoefficient(int height, ParGridFunction &psi_, real_t alpha_ = 1.0)
|
||||
: MatrixCoefficient(height), psi(&psi_), alpha(alpha_) { }
|
||||
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
void SetAlpha(real_t alpha_) { alpha = alpha_; }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 0. Initialize MPI and HYPRE.
|
||||
Mpi::Init();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
int order = 1;
|
||||
int max_it = 5;
|
||||
int ref_levels = 3;
|
||||
real_t alpha = 1.0;
|
||||
real_t growth_rate = 1.0;
|
||||
real_t newton_scaling = 0.9;
|
||||
real_t tichonov = 1e-1;
|
||||
real_t tol = 1e-4;
|
||||
bool visualization = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&ref_levels, "-r", "--refs",
|
||||
"Number of h-refinements.");
|
||||
args.AddOption(&max_it, "-mi", "--max-it",
|
||||
"Maximum number of iterations");
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"Stopping criteria based on the difference between"
|
||||
"successive solution updates");
|
||||
args.AddOption(&alpha, "-step", "--step",
|
||||
"Initial size alpha");
|
||||
args.AddOption(&growth_rate, "-gr", "--growth-rate",
|
||||
"Growth rate of the step size alpha");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
// 2. Read the mesh from the mesh file.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
int sdim = mesh.SpaceDimension();
|
||||
|
||||
MFEM_ASSERT(mesh.bdr_attributes.Size(),
|
||||
"This example does not currently support meshes"
|
||||
" without boundary attributes."
|
||||
)
|
||||
|
||||
// 3. Postprocess the mesh.
|
||||
// 3A. Refine the mesh to increase the resolution.
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
|
||||
// 3B. Interpolate the geometry after refinement to control geometry error.
|
||||
// NOTE: Minimum second-order interpolation is used to improve the accuracy.
|
||||
int curvature_order = max(order,2);
|
||||
mesh.SetCurvature(curvature_order);
|
||||
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
|
||||
// 4. Define the necessary finite element spaces on the mesh.
|
||||
RT_FECollection RTfec(order, dim);
|
||||
ParFiniteElementSpace RTfes(&pmesh, &RTfec);
|
||||
|
||||
L2_FECollection L2fec(order, dim);
|
||||
ParFiniteElementSpace L2fes(&pmesh, &L2fec);
|
||||
|
||||
int num_dofs_RT = RTfes.GlobalTrueVSize();
|
||||
int num_dofs_L2 = L2fes.GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of H(div) dofs: "
|
||||
<< num_dofs_RT << endl;
|
||||
cout << "Number of L² dofs: "
|
||||
<< num_dofs_L2 << endl;
|
||||
}
|
||||
|
||||
// 5. Define the offsets for the block matrices
|
||||
Array<int> offsets(3);
|
||||
offsets[0] = 0;
|
||||
offsets[1] = RTfes.GetVSize();
|
||||
offsets[2] = L2fes.GetVSize();
|
||||
offsets.PartialSum();
|
||||
|
||||
Array<int> toffsets(3);
|
||||
toffsets[0] = 0;
|
||||
toffsets[1] = RTfes.GetTrueVSize();
|
||||
toffsets[2] = L2fes.GetTrueVSize();
|
||||
toffsets.PartialSum();
|
||||
|
||||
BlockVector x(offsets), rhs(offsets);
|
||||
x = 0.0; rhs = 0.0;
|
||||
|
||||
BlockVector tx(toffsets), trhs(toffsets);
|
||||
tx = 0.0; trhs = 0.0;
|
||||
|
||||
// 6. Define the solution vectors as a finite element grid functions
|
||||
// corresponding to the fespaces.
|
||||
ParGridFunction u_gf, delta_psi_gf;
|
||||
delta_psi_gf.MakeRef(&RTfes,x,offsets[0]);
|
||||
u_gf.MakeRef(&L2fes,x,offsets[1]);
|
||||
|
||||
ParGridFunction psi_old_gf(&RTfes);
|
||||
ParGridFunction psi_gf(&RTfes);
|
||||
ParGridFunction u_old_gf(&L2fes);
|
||||
|
||||
// 7. Define initial guesses for the solution variables.
|
||||
delta_psi_gf = 0.0;
|
||||
psi_gf = 0.0;
|
||||
u_gf = 0.0;
|
||||
psi_old_gf = psi_gf;
|
||||
u_old_gf = u_gf;
|
||||
|
||||
// 8. Prepare for glvis output.
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock;
|
||||
if (visualization)
|
||||
{
|
||||
sol_sock.open(vishost,visport);
|
||||
sol_sock.precision(8);
|
||||
}
|
||||
|
||||
// 9. Coefficients to be used later.
|
||||
ConstantCoefficient neg_one(-1.0);
|
||||
ConstantCoefficient zero(0.0);
|
||||
ConstantCoefficient tichonov_cf(tichonov);
|
||||
ConstantCoefficient neg_tichonov_cf(-1.0*tichonov);
|
||||
ZCoefficient Z(sdim, psi_gf, alpha);
|
||||
DZCoefficient DZ(sdim, psi_gf, alpha);
|
||||
ScalarVectorProductCoefficient neg_Z(-1.0, Z);
|
||||
DivergenceGridFunctionCoefficient div_psi_cf(&psi_gf);
|
||||
DivergenceGridFunctionCoefficient div_psi_old_cf(&psi_old_gf);
|
||||
SumCoefficient psi_old_minus_psi(div_psi_old_cf, div_psi_cf, 1.0, -1.0);
|
||||
|
||||
// 10. Assemble constant matrices/vectors to avoid reassembly in the loop.
|
||||
ParLinearForm b0, b1;
|
||||
b0.MakeRef(&RTfes,rhs.GetBlock(0),0);
|
||||
b1.MakeRef(&L2fes,rhs.GetBlock(1),0);
|
||||
|
||||
b0.AddDomainIntegrator(new VectorFEDomainLFIntegrator(neg_Z));
|
||||
b1.AddDomainIntegrator(new DomainLFIntegrator(neg_one));
|
||||
b1.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
|
||||
|
||||
ParBilinearForm a00(&RTfes);
|
||||
a00.AddDomainIntegrator(new VectorFEMassIntegrator(DZ));
|
||||
a00.AddDomainIntegrator(new VectorFEMassIntegrator(tichonov_cf));
|
||||
|
||||
ParMixedBilinearForm a10(&RTfes,&L2fes);
|
||||
a10.AddDomainIntegrator(new VectorFEDivergenceIntegrator());
|
||||
a10.Assemble();
|
||||
a10.Finalize();
|
||||
HypreParMatrix *A10 = a10.ParallelAssemble();
|
||||
|
||||
HypreParMatrix *A01 = A10->Transpose();
|
||||
|
||||
ParBilinearForm a11(&L2fes);
|
||||
a11.AddDomainIntegrator(new MassIntegrator(neg_tichonov_cf));
|
||||
a11.Assemble();
|
||||
a11.Finalize();
|
||||
HypreParMatrix *A11 = a11.ParallelAssemble();
|
||||
|
||||
// 11. Iterate.
|
||||
int k;
|
||||
int total_iterations = 0;
|
||||
real_t increment_u = 0.1;
|
||||
ParGridFunction u_tmp(&L2fes);
|
||||
for (k = 0; k < max_it; k++)
|
||||
{
|
||||
u_tmp = u_old_gf;
|
||||
Z.SetAlpha(alpha);
|
||||
DZ.SetAlpha(alpha);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
|
||||
}
|
||||
|
||||
int j;
|
||||
for ( j = 0; j < 5; j++)
|
||||
{
|
||||
total_iterations++;
|
||||
|
||||
b0.Assemble();
|
||||
b0.ParallelAssemble(trhs.GetBlock(0));
|
||||
|
||||
b1.Assemble();
|
||||
b1.ParallelAssemble(trhs.GetBlock(1));
|
||||
|
||||
a00.Assemble(false);
|
||||
a00.Finalize(false);
|
||||
HypreParMatrix *A00 = a00.ParallelAssemble();
|
||||
|
||||
// Construct Schur-complement preconditioner
|
||||
HypreParVector A00_diag(MPI_COMM_WORLD, A00->GetGlobalNumRows(),
|
||||
A00->GetRowStarts());
|
||||
A00->GetDiag(A00_diag);
|
||||
HypreParMatrix S_tmp(*A01);
|
||||
S_tmp.InvScaleRows(A00_diag);
|
||||
HypreParMatrix *S = ParMult(A10, &S_tmp, true);
|
||||
|
||||
BlockDiagonalPreconditioner prec(toffsets);
|
||||
HypreBoomerAMG P00(*A00);
|
||||
P00.SetPrintLevel(0);
|
||||
HypreBoomerAMG P11(*S);
|
||||
P11.SetPrintLevel(0);
|
||||
prec.SetDiagonalBlock(0,&P00);
|
||||
prec.SetDiagonalBlock(1,&P11);
|
||||
|
||||
BlockOperator A(toffsets);
|
||||
A.SetBlock(0,0,A00);
|
||||
A.SetBlock(1,0,A10);
|
||||
A.SetBlock(0,1,A01);
|
||||
A.SetBlock(1,1,A11);
|
||||
|
||||
GMRESSolver gmres(MPI_COMM_WORLD);
|
||||
gmres.SetPrintLevel(-1);
|
||||
gmres.SetRelTol(1e-8);
|
||||
gmres.SetMaxIter(2000);
|
||||
gmres.SetKDim(500);
|
||||
gmres.SetOperator(A);
|
||||
gmres.SetPreconditioner(prec);
|
||||
gmres.Mult(trhs,tx);
|
||||
delete S;
|
||||
delete A00;
|
||||
|
||||
delta_psi_gf.SetFromTrueDofs(tx.GetBlock(0));
|
||||
u_gf.SetFromTrueDofs(tx.GetBlock(1));
|
||||
|
||||
u_tmp -= u_gf;
|
||||
real_t Newton_update_size = u_tmp.ComputeL2Error(zero);
|
||||
u_tmp = u_gf;
|
||||
|
||||
// Damped Newton update
|
||||
psi_gf.Add(newton_scaling, delta_psi_gf);
|
||||
a00.Update();
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock << "solution\n" << pmesh << u_gf << "window_title 'Discrete solution'"
|
||||
<< flush;
|
||||
}
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
|
||||
}
|
||||
|
||||
if (Newton_update_size < increment_u)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u_tmp = u_gf;
|
||||
u_tmp -= u_old_gf;
|
||||
increment_u = u_tmp.ComputeL2Error(zero);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "Number of Newton iterations = " << j+1 << endl;
|
||||
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
|
||||
}
|
||||
|
||||
u_old_gf = u_gf;
|
||||
psi_old_gf = psi_gf;
|
||||
|
||||
if (increment_u < tol || k == max_it-1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
alpha *= max(growth_rate, 1_r);
|
||||
|
||||
}
|
||||
|
||||
// 12. Print stats.
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "\n Outer iterations: " << k+1
|
||||
<< "\n Total iterations: " << total_iterations
|
||||
<< "\n Total dofs: " << RTfes.GetTrueVSize() + L2fes.GetTrueVSize()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// 13. Free the used memory.
|
||||
delete A01;
|
||||
delete A10;
|
||||
delete A11;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ZCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
MFEM_ASSERT(psi != NULL, "grid function is not set");
|
||||
MFEM_ASSERT(alpha > 0, "alpha is not positive");
|
||||
|
||||
Vector psi_vals(vdim);
|
||||
psi->GetVectorValue(T, ip, psi_vals);
|
||||
real_t norm = psi_vals.Norml2();
|
||||
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
|
||||
|
||||
V = psi_vals;
|
||||
V *= phi;
|
||||
}
|
||||
|
||||
void DZCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
MFEM_ASSERT(psi != NULL, "grid function is not set");
|
||||
MFEM_ASSERT(alpha > 0, "alpha is not positive");
|
||||
|
||||
Vector psi_vals(height);
|
||||
psi->GetVectorValue(T, ip, psi_vals);
|
||||
real_t norm = psi_vals.Norml2();
|
||||
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
|
||||
|
||||
K = 0.0;
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
K(i,i) = phi;
|
||||
for (int j = 0; j < height; j++)
|
||||
{
|
||||
K(i,j) -= psi_vals(i) * psi_vals(j) * pow(phi, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,782 +0,0 @@
|
||||
// MFEM Example 3 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex3p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/escher.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/fichera.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
|
||||
// mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
|
||||
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
|
||||
//
|
||||
// Description: This example code solves a simple electromagnetic diffusion
|
||||
// problem corresponding to the second order definite Maxwell
|
||||
// equation curl curl E + E = f with boundary condition
|
||||
// E x n = <given tangential field>. Here, we use a given exact
|
||||
// solution E and compute the corresponding r.h.s. f.
|
||||
// We discretize with Nedelec finite elements in 2D or 3D.
|
||||
//
|
||||
// The example demonstrates the use of H(curl) finite element
|
||||
// spaces with the curl-curl and the (vector finite element) mass
|
||||
// bilinear form, as well as the computation of discretization
|
||||
// error when the exact solution is known. Static condensation is
|
||||
// also illustrated.
|
||||
//
|
||||
// We recommend viewing examples 1-2 before viewing this example.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "./spe10_coeff.cpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
|
||||
int* LoadIterations(int NRows, int NCol)
|
||||
{
|
||||
ifstream in("iter_DivSkew.txt");
|
||||
|
||||
//initialize
|
||||
int *iters = new int[NCol*NRows];
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
iters[row*NCol+col] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
return iters;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
if (in.eof())
|
||||
{
|
||||
in.close();
|
||||
return iters;
|
||||
}
|
||||
in >> iters[row*NCol+col];
|
||||
}
|
||||
|
||||
in.close();
|
||||
|
||||
return iters;
|
||||
}
|
||||
|
||||
void putIterationsInArray(int iter, int row, int col, int NCol, int* iters)
|
||||
{
|
||||
iters[row*NCol+col] = iter;
|
||||
}
|
||||
|
||||
void WriteIterations(int *iters, int NRows, int NCol)
|
||||
{
|
||||
ofstream out;
|
||||
out.open("iter_DivSkew.txt",fstream::out);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
delete[] iters;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
out << iters[row*NCol+col] << "\t";
|
||||
}
|
||||
out << endl;
|
||||
}
|
||||
out.close();
|
||||
|
||||
delete[] iters;
|
||||
}
|
||||
|
||||
|
||||
// Exact solution, E, and r.h.s., f. See below for implementation.
|
||||
void E_exact_vec(const Vector &x, Vector &E);
|
||||
void E_exact(const Vector &, DenseMatrix &);
|
||||
void f_exact(const Vector &, DenseMatrix &);
|
||||
|
||||
|
||||
class DivSkew4dPrec : public Solver
|
||||
{
|
||||
|
||||
private:
|
||||
HypreParMatrix *A;
|
||||
ParFiniteElementSpace *fespace;
|
||||
Coefficient *alpha_, *beta_;
|
||||
|
||||
//kernel operators
|
||||
HypreParMatrix *P_d_HCurl_HDivSkew;
|
||||
|
||||
|
||||
HypreParMatrix *P_H1_HCurl;
|
||||
HypreParMatrix *H1_KernelMat;
|
||||
HypreBoomerAMG *amgH1_Kernel;
|
||||
|
||||
//"image" operators
|
||||
HypreParMatrix *P_H1_HDivSkew;
|
||||
HypreParMatrix *H1_ImageMat;
|
||||
HypreBoomerAMG *amgH1_Image;
|
||||
|
||||
|
||||
HypreParMatrix *HCurlMat;
|
||||
HypreSmoother * smootherDivSkew;
|
||||
HypreSmoother * smootherCurl;
|
||||
|
||||
CGSolver *pcgKernel;
|
||||
CGSolver *pcgImage;
|
||||
|
||||
Vector *f;
|
||||
Vector *fKernel, *uKernel;
|
||||
Vector *fImage, *uImage;
|
||||
Vector *fCurl, *uCurl;
|
||||
|
||||
bool exactSolves;
|
||||
|
||||
FiniteElementCollection* fecHCurlKernel;
|
||||
ParFiniteElementSpace *HCurlKernelFESpace;
|
||||
|
||||
|
||||
public:
|
||||
~DivSkew4dPrec()
|
||||
{
|
||||
delete pcgImage, pcgKernel;
|
||||
|
||||
delete f, fKernel, uKernel, fImage, uImage, fCurl, uCurl;
|
||||
|
||||
delete smootherCurl, HCurlMat;
|
||||
|
||||
delete P_d_HCurl_HDivSkew, P_H1_HDivSkew, P_H1_HCurl;
|
||||
|
||||
delete amgH1_Image, H1_ImageMat;
|
||||
delete amgH1_Kernel, H1_KernelMat;
|
||||
|
||||
delete smootherDivSkew;
|
||||
|
||||
delete HCurlKernelFESpace, fecHCurlKernel;
|
||||
}
|
||||
DivSkew4dPrec(HypreParMatrix *AUser, ParFiniteElementSpace *fespaceUser,
|
||||
Coefficient *alpha, Coefficient *beta,
|
||||
const Array<int> &essBnd, int orderKernel=1, bool exactSolvesUser=false)
|
||||
{
|
||||
A = AUser;
|
||||
fespace = fespaceUser;
|
||||
alpha_ = alpha;
|
||||
beta_ = beta;
|
||||
|
||||
ParMesh *pmesh = fespace->GetParMesh();
|
||||
int dim = pmesh->Dimension();
|
||||
|
||||
exactSolves = exactSolvesUser;
|
||||
|
||||
int orderIm=1; //H1 --> H(divSkew)
|
||||
int orderKer=orderKernel; //curl V --> H(divSkew)
|
||||
|
||||
smootherDivSkew = new HypreSmoother(*A, 16, 3);
|
||||
|
||||
Array<int> HDivSkew_essDof(fespace->GetVSize()); HDivSkew_essDof = 0;
|
||||
fespace->GetEssentialVDofs(essBnd, HDivSkew_essDof);
|
||||
|
||||
//setup the H1 FESpace for the kernel
|
||||
FiniteElementCollection* fecH1Kernel = new H1_FECollection(orderKer, 4);
|
||||
|
||||
ParFiniteElementSpace *H1KernelFESpace = new ParFiniteElementSpace(pmesh,
|
||||
fecH1Kernel, dim, Ordering::byVDIM);
|
||||
Array<int> H1Kernel_essDof(H1KernelFESpace->GetVSize()); H1Kernel_essDof = 0;
|
||||
H1KernelFESpace->GetEssentialVDofs(essBnd, H1Kernel_essDof);
|
||||
|
||||
|
||||
//setup the H(curl) FESpace for the kernel
|
||||
if (orderKer==1) { fecHCurlKernel = new ND1_4DFECollection; }
|
||||
else { fecHCurlKernel = new ND2_4DFECollection; }
|
||||
|
||||
HCurlKernelFESpace = new ParFiniteElementSpace(pmesh,
|
||||
fecHCurlKernel);
|
||||
Array<int> HCurlKernel_essDof(HCurlKernelFESpace->GetVSize());
|
||||
HCurlKernel_essDof = 0;
|
||||
HCurlKernelFESpace->GetEssentialVDofs(essBnd, HCurlKernel_essDof);
|
||||
|
||||
|
||||
//setup the FESpace for the H1 injection
|
||||
FiniteElementCollection* fecH1Vec;
|
||||
if (orderIm==1) { fecH1Vec = new LinearFECollection; }
|
||||
else { fecH1Vec = new QuadraticFECollection; }
|
||||
ParFiniteElementSpace *H1_ImageFESpace = new ParFiniteElementSpace(pmesh,
|
||||
fecH1Vec, 6, Ordering::byVDIM);
|
||||
Array<int> H1Image_essDof(H1_ImageFESpace->GetVSize()); H1Image_essDof = 0;
|
||||
H1_ImageFESpace->GetEssentialVDofs(essBnd, H1Image_essDof);
|
||||
|
||||
|
||||
|
||||
//setup the H1 preconditioner for the kernel
|
||||
ParBilinearForm* H1Varf = new ParBilinearForm(H1KernelFESpace);
|
||||
H1Varf->AddDomainIntegrator(new VectorDiffusionIntegrator(*beta_));
|
||||
// H1Varf->AddDomainIntegrator(new VectorMassIntegrator);
|
||||
H1Varf->Assemble();
|
||||
H1Varf->Finalize();
|
||||
SparseMatrix &matH1(H1Varf->SpMat());
|
||||
for (int dof = 0; dof < H1Kernel_essDof.Size(); dof++)
|
||||
if (H1Kernel_essDof[dof] < 0)
|
||||
{
|
||||
matH1.EliminateRowCol(dof);
|
||||
}
|
||||
H1_KernelMat = H1Varf->ParallelAssemble();
|
||||
delete H1Varf;
|
||||
amgH1_Kernel = new HypreBoomerAMG(*H1_KernelMat);
|
||||
amgH1_Kernel->SetSystemsOptions(dim);
|
||||
amgH1_Kernel->SetPrintLevel(0);
|
||||
|
||||
//setup the H1 preconditioner for the image
|
||||
ParBilinearForm* H1VecVarf = new ParBilinearForm(H1_ImageFESpace);
|
||||
VectorDiffusionIntegrator *alpha_integ = new VectorDiffusionIntegrator(*alpha_);
|
||||
alpha_integ->SetVDim(6);
|
||||
H1VecVarf->AddDomainIntegrator(alpha_integ);
|
||||
VectorMassIntegrator *beta_integ = new VectorMassIntegrator(*beta);
|
||||
beta_integ->SetVDim(6);
|
||||
H1VecVarf->AddDomainIntegrator(beta_integ);
|
||||
H1VecVarf->Assemble();
|
||||
H1VecVarf->Finalize();
|
||||
SparseMatrix &matH1Vec(H1VecVarf->SpMat());
|
||||
for (int dof=0; dof<H1Image_essDof.Size(); dof++) if (H1Image_essDof[dof]<0) { matH1Vec.EliminateRowCol(dof); }
|
||||
H1_ImageMat = H1VecVarf->ParallelAssemble();
|
||||
delete H1VecVarf;
|
||||
amgH1_Image = new HypreBoomerAMG(*H1_ImageMat);
|
||||
amgH1_Image->SetSystemsOptions(6);
|
||||
amgH1_Image->SetPrintLevel(0);
|
||||
|
||||
|
||||
//setup the injection of H1 into H(curl)
|
||||
ParDiscreteLinearOperator *disInterpol = new ParDiscreteLinearOperator(
|
||||
H1KernelFESpace, HCurlKernelFESpace);
|
||||
disInterpol->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpol->Assemble();
|
||||
disInterpol->Finalize();
|
||||
SparseMatrix* smatID = &(disInterpol->SpMat());
|
||||
smatID->EliminateCols(H1Kernel_essDof);
|
||||
for (int dof=0; dof<HCurlKernel_essDof.Size();
|
||||
dof++) if (HCurlKernel_essDof[dof]<0) { smatID->EliminateRow(dof); }
|
||||
P_H1_HCurl = disInterpol->ParallelAssemble();
|
||||
delete disInterpol;
|
||||
|
||||
//setup the injection of H1 into H(DivSkew)
|
||||
ParDiscreteLinearOperator *disInterpolIm = new ParDiscreteLinearOperator(
|
||||
H1_ImageFESpace, fespace);
|
||||
disInterpolIm->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpolIm->Assemble();
|
||||
disInterpolIm->Finalize();
|
||||
SparseMatrix* smatIDIm = &(disInterpolIm->SpMat());
|
||||
smatIDIm->EliminateCols(H1Image_essDof);
|
||||
for (int dof=0; dof<HDivSkew_essDof.Size(); dof++) if (HDivSkew_essDof[dof]<0) { smatIDIm->EliminateRow(dof); }
|
||||
P_H1_HDivSkew = disInterpolIm->ParallelAssemble();
|
||||
delete disInterpolIm;
|
||||
|
||||
|
||||
//setup the injection of the curl(H(curl)) into H(DivSkew)
|
||||
ParDiscreteLinearOperator *disCurl = new ParDiscreteLinearOperator(
|
||||
HCurlKernelFESpace, fespace);
|
||||
disCurl->AddDomainInterpolator(new CurlInterpolator);
|
||||
disCurl->Assemble();
|
||||
disCurl->Finalize();
|
||||
SparseMatrix* smatCurl = &(disCurl->SpMat());
|
||||
smatCurl->EliminateCols(HCurlKernel_essDof);
|
||||
for (int dof=0; dof<HDivSkew_essDof.Size(); dof++) if (HDivSkew_essDof[dof]<0) { smatCurl->EliminateRow(dof); }
|
||||
P_d_HCurl_HDivSkew = disCurl->ParallelAssemble();
|
||||
delete disCurl;
|
||||
|
||||
//setup the smoother for H(curl)
|
||||
// Coefficient *massC = new ConstantCoefficient(1.0);
|
||||
// Coefficient *CurlCurlC = new ConstantCoefficient(1.0);
|
||||
ParBilinearForm *a_HCurl = new ParBilinearForm(HCurlKernelFESpace);
|
||||
a_HCurl->AddDomainIntegrator(new CurlCurlIntegrator(*beta_));
|
||||
// a_HCurl->AddDomainIntegrator(new CurlCurlIntegrator(*CurlCurlC));
|
||||
// a_HCurl->AddDomainIntegrator(new VectorFEMassIntegrator(*massC));
|
||||
a_HCurl->Assemble();
|
||||
a_HCurl->Finalize();
|
||||
SparseMatrix &matHCurl(a_HCurl->SpMat());
|
||||
for (int dof=0; dof<HCurlKernel_essDof.Size();
|
||||
dof++) if (HCurlKernel_essDof[dof]<0) { matHCurl.EliminateRowCol(dof); }
|
||||
HCurlMat = a_HCurl->ParallelAssemble();
|
||||
delete a_HCurl;
|
||||
smootherCurl = new HypreSmoother(*HCurlMat, 16, 3);
|
||||
|
||||
f = new Vector(fespace->GetTrueVSize());
|
||||
|
||||
fKernel = new Vector(H1KernelFESpace->GetTrueVSize());
|
||||
uKernel = new Vector(H1KernelFESpace->GetTrueVSize());
|
||||
|
||||
fImage = new Vector(H1_ImageFESpace->GetTrueVSize());
|
||||
uImage = new Vector(H1_ImageFESpace->GetTrueVSize());
|
||||
|
||||
fCurl = new Vector(HCurlKernelFESpace->GetTrueVSize());
|
||||
uCurl = new Vector(HCurlKernelFESpace->GetTrueVSize());
|
||||
|
||||
|
||||
amgH1_Kernel->Mult(*fKernel, *uKernel);
|
||||
amgH1_Image->Mult(*fImage, *uImage);
|
||||
|
||||
pcgKernel = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgKernel->SetOperator(*H1_KernelMat);
|
||||
pcgKernel->SetPreconditioner(*amgH1_Kernel);
|
||||
pcgKernel->SetRelTol(1e-16);
|
||||
pcgKernel->SetMaxIter(100000000);
|
||||
pcgKernel->SetPrintLevel(-2);
|
||||
|
||||
pcgImage = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgImage->SetOperator(*H1_ImageMat);
|
||||
pcgImage->SetPreconditioner(*amgH1_Image);
|
||||
pcgImage->SetRelTol(1e-16);
|
||||
pcgImage->SetMaxIter(100000000);
|
||||
pcgImage->SetPrintLevel(-2);
|
||||
|
||||
delete H1KernelFESpace, fecH1Kernel;
|
||||
delete H1_ImageFESpace, fecH1Vec;
|
||||
}
|
||||
|
||||
void setExactSolve(bool exSol)
|
||||
{
|
||||
exactSolves = exSol;
|
||||
}
|
||||
|
||||
virtual void Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
smootherDivSkew->Mult(x,y);
|
||||
|
||||
P_H1_HDivSkew->MultTranspose(x,*fImage);
|
||||
*uImage = 0.0;
|
||||
if (exactSolves) { pcgImage->Mult(*fImage, *uImage); }
|
||||
else { amgH1_Image->Mult(*fImage, *uImage); }
|
||||
P_H1_HDivSkew->Mult(1.0, *uImage, 1.0, y);
|
||||
|
||||
*uCurl = 0.0;
|
||||
P_d_HCurl_HDivSkew->MultTranspose(x,*fCurl);
|
||||
|
||||
smootherCurl->Mult(*fCurl, *uCurl);
|
||||
|
||||
P_H1_HCurl->MultTranspose(*fCurl,*fKernel);
|
||||
*uKernel = 0.0;
|
||||
if (exactSolves) { pcgKernel->Mult(*fKernel, *uKernel); }
|
||||
else { amgH1_Kernel->Mult(*fKernel, *uKernel); }
|
||||
P_H1_HCurl->Mult(1.0, *uKernel, 1.0, *uCurl);
|
||||
|
||||
P_d_HCurl_HDivSkew->Mult(1.0, *uCurl, 1.0, y);
|
||||
}
|
||||
|
||||
virtual void SetOperator(const Operator &op) {};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
bool verbose = (myid==0);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/cube4d_96.MFEM";
|
||||
int order = 1;
|
||||
bool set_bc = true;
|
||||
bool static_cond = false;
|
||||
bool visualization = 1;
|
||||
int sequ_ref_levels = 0;
|
||||
int par_ref_levels = 0;
|
||||
double tol = 1e-6;
|
||||
double coeffWeight = 1.0;
|
||||
bool exactH1Solver = false;
|
||||
bool spe10Coeff = false;
|
||||
bool standardCG = true;
|
||||
|
||||
int NExpo = 8;
|
||||
int weightStart = -NExpo;
|
||||
int weightEnd = NExpo;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&sequ_ref_levels, "-sr", "--seqrefinement",
|
||||
"Number of sequential refinement steps.");
|
||||
args.AddOption(&par_ref_levels, "-pr", "--parrefinement",
|
||||
"Number of parallel refinement steps.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Polynomial order of the finite element space.");
|
||||
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
|
||||
"Impose or not essential boundary conditions.");
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"A parameter.");
|
||||
args.AddOption(&coeffWeight, "-c", "--coeffMass",
|
||||
"the weight for the mass term.");
|
||||
args.AddOption(&exactH1Solver, "-exH1Sol", "--exactH1Solver", "-H1prec",
|
||||
"--H1preconditioner",
|
||||
"Use exact H1 solvers for the preconditioner.");
|
||||
args.AddOption(&spe10Coeff, "-spe10", "--useSPE10Coeff", "-constCoeff",
|
||||
"--constCoeff",
|
||||
"Switch between the coefficients for the mass bilinear form.");
|
||||
args.AddOption(&standardCG, "-sCG", "--stdCG", "-rCG", "--resCG",
|
||||
"Switch between standard PCG or recompute residuals in every step and use the residuals itself for the stopping criteria.");
|
||||
args.AddOption(&weightStart, "-ws", "--weightStart",
|
||||
"the exponent for the starting weight (for the mass term).");
|
||||
args.AddOption(&weightEnd, "-we", "--weightEnd",
|
||||
"the exponent for the weight at the end (for the mass term).");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
if (verbose) { args.PrintOptions(cout); }
|
||||
|
||||
Mesh *mesh;
|
||||
ifstream imesh(mesh_file);
|
||||
if (!imesh)
|
||||
{
|
||||
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
mesh = new Mesh(imesh, 1, 1);
|
||||
imesh.close();
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
if (dim !=4 || sdim != 4)
|
||||
{
|
||||
MPI_Finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<sequ_ref_levels; i++) { mesh->UniformRefinement(); }
|
||||
if (verbose) { mesh->PrintCharacteristics(); }
|
||||
|
||||
if (verbose) { cout << "now we partition the mesh..." << endl << endl; }
|
||||
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
|
||||
for (int i=0; i<par_ref_levels; i++) { pmesh->UniformRefinement(); }
|
||||
|
||||
pmesh->PrintInfo(std::cout);
|
||||
if (verbose) { cout << endl; }
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Nedelec finite elements of the specified order.
|
||||
FiniteElementCollection *fec;
|
||||
if (order==1) { fec = new DivSkew1_4DFECollection; }
|
||||
// else fec = new F2K1_4DFECollection;
|
||||
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
fespace->SetUpdateOperatorType(Operator::Hypre_ParCSR);
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes from the mesh as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = set_bc ? 1 : 0;
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
|
||||
}
|
||||
|
||||
// 8. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system, which in this case is
|
||||
// (f,phi_i) where f is given by the function f_exact and phi_i are the
|
||||
// basis functions in the finite element fespace.
|
||||
MatrixFunctionCoefficient f(sdim, f_exact);
|
||||
MatrixFunctionCoefficient solMat(sdim, E_exact);
|
||||
VectorFunctionCoefficient solVec(6, E_exact_vec);
|
||||
|
||||
|
||||
|
||||
|
||||
// 9. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x by projecting the exact
|
||||
// solution. Note that only values from the boundary edges will be used
|
||||
// when eliminating the non-homogeneous boundary condition to modify the
|
||||
// r.h.s. vector b.
|
||||
ParGridFunction x(fespace);
|
||||
|
||||
for (int expo=weightStart; expo<=weightEnd; expo++)
|
||||
{
|
||||
double weight = pow(10.0,expo);
|
||||
|
||||
x.ProjectCoefficient(solVec);
|
||||
|
||||
ParLinearForm *b = new ParLinearForm(fespace);
|
||||
b->AddDomainIntegrator(new MatFEDomainLFIntegrator(f));
|
||||
b->Assemble();
|
||||
|
||||
// cout << x << endl;
|
||||
// x = 0.0;
|
||||
|
||||
// 10. Set up the parallel bilinear form corresponding to the EM diffusion
|
||||
// operator curl muinv curl + sigma I, by adding the curl-curl and the
|
||||
// mass domain integrators.
|
||||
// std::string permFile = "spe_perm.dat";
|
||||
// InversePermeabilityFunction::ReadPermeabilityFile(permFile, MPI_COMM_WORLD);
|
||||
|
||||
Coefficient *alpha = new ConstantCoefficient(1.0);
|
||||
Coefficient *beta;
|
||||
// if(spe10Coeff) beta = new FunctionCoefficient(InversePermeabilityFunction::Norm2Permeability);
|
||||
// else
|
||||
beta = new ConstantCoefficient(weight);
|
||||
|
||||
ParBilinearForm *a = new ParBilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new DivSkewDivSkewIntegrator(*alpha));
|
||||
a->AddDomainIntegrator(new VectorFE_DivSkewMassIntegrator(*beta));
|
||||
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, static condensation, etc.
|
||||
if (static_cond) { a->EnableStaticCondensation(); }
|
||||
a->Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
|
||||
}
|
||||
|
||||
//Define the preconditioner
|
||||
|
||||
if (myid == 0) { cout << "Set up the preconditioner" << endl; }
|
||||
Solver *prec;
|
||||
if (dim==4) { prec = new DivSkew4dPrec(&A, fespace, alpha, beta, ess_bdr, order, exactH1Solver); }
|
||||
|
||||
IterativeSolver *pcg = new CGSolver(MPI_COMM_WORLD);
|
||||
pcg->SetOperator(A);
|
||||
pcg->SetRelTol(tol);
|
||||
pcg->SetMaxIter(500);
|
||||
pcg->SetPrintLevel(1);
|
||||
pcg->SetPreconditioner(*prec);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
delete prec;
|
||||
|
||||
int iter = pcg->GetNumIterations();
|
||||
if (myid==0)
|
||||
{
|
||||
cout << "Weigth: " << weight << " " << iter << endl;
|
||||
|
||||
int *iters = LoadIterations(10, 2*NExpo+1);
|
||||
putIterationsInArray(iter, sequ_ref_levels+par_ref_levels, expo+NExpo,
|
||||
2*NExpo+1, iters);
|
||||
WriteIterations(iters, 10, 2*NExpo+1);
|
||||
}
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 14. Compute and print the L^2 norm of the error.
|
||||
{
|
||||
double error = 0.0;
|
||||
for (int i = 0; i < fespace->GetNE(); i++)
|
||||
{
|
||||
const FiniteElement* fe = fespace->GetFE(i);
|
||||
int fdof = fe->GetDof();
|
||||
ElementTransformation* transf = fespace->GetElementTransformation(i);
|
||||
DenseMatrix shape(fdof,dim*dim);
|
||||
|
||||
int intorder = 2*fe->GetOrder() + 1; // <----------
|
||||
const IntegrationRule *ir;
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
|
||||
Vector elSol(dim*dim);
|
||||
DenseMatrix elSolMat(dim,dim);
|
||||
DenseMatrix exactSol(dim,dim);
|
||||
Vector exactSolVec(dim*dim);
|
||||
|
||||
|
||||
|
||||
Array<int> vdofs;
|
||||
fespace->GetElementVDofs(i, vdofs);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
|
||||
fe->CalcVShape(*transf, shape);
|
||||
|
||||
elSol = 0.0;
|
||||
for (int k = 0; k < fdof; k++)
|
||||
{
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
for (int l=0; l<dim*dim; l++) { elSol(l) += shape(k,l)*x(vdofs[k]); }
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int l=0; l<dim*dim; l++) { elSol(l) -= shape(k,l)*x(-1-vdofs[k]); }
|
||||
}
|
||||
}
|
||||
for (int k=0; k<dim; k++)
|
||||
for (int l=0; l<dim; l++)
|
||||
{
|
||||
elSolMat(k,l) = elSol(dim*k+l);
|
||||
}
|
||||
|
||||
|
||||
solMat.Eval(exactSol,*transf, ip);
|
||||
for (int k=0; k<dim; k++)
|
||||
for (int l=0; l<dim; l++)
|
||||
{
|
||||
exactSolVec(dim*k+l) = exactSol(k,l);
|
||||
}
|
||||
elSol.Add(-1.0, exactSolVec);
|
||||
|
||||
error += ip.weight * fabs(transf->Weight()) * (elSol * elSol);
|
||||
}
|
||||
}
|
||||
double globalError = 0.0;
|
||||
MPI_Allreduce(&error, &globalError, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
|
||||
if (myid==0) { std::cout << "L2 error: " << sqrt(globalError) << std::endl; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
delete pcg;
|
||||
delete a;
|
||||
delete alpha;
|
||||
delete beta;
|
||||
|
||||
delete b;
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
|
||||
|
||||
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete pmesh;
|
||||
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void E_exact_vec(const Vector &x, Vector &E)
|
||||
{
|
||||
int dim = x.Size();
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
E.SetSize(6);
|
||||
|
||||
double s0 = sin(M_PI*x(0)), s1 = sin(M_PI*x(1)), s2 = sin(M_PI*x(2)),
|
||||
s3 = sin(M_PI*x(3));
|
||||
double c0 = cos(M_PI*x(0)), c1 = cos(M_PI*x(1)), c2 = cos(M_PI*x(2)),
|
||||
c3 = cos(M_PI*x(3));
|
||||
|
||||
E(0) = c0*c1*s2*s3;
|
||||
E(1) = -c0*s1*c2*s3;
|
||||
E(2) = c0*s1*s2*c3;
|
||||
E(3) = s0*c1*c2*s3;
|
||||
E(4) = -s0*c1*s2*c3;
|
||||
E(5) = s0*s1*c2*c3;
|
||||
}
|
||||
}
|
||||
|
||||
void E_exact(const Vector &x, DenseMatrix &E)
|
||||
{
|
||||
int dim = x.Size();
|
||||
|
||||
E.SetSize(dim*dim);
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
Vector vecE; E_exact_vec(x, vecE);
|
||||
|
||||
E = 0.0;
|
||||
|
||||
E(0,1) = vecE(0);
|
||||
E(0,2) = vecE(1);
|
||||
E(0,3) = vecE(2);
|
||||
E(1,2) = vecE(3);
|
||||
E(1,3) = vecE(4);
|
||||
E(2,3) = vecE(5);
|
||||
|
||||
E(1,0) = -E(0,1);
|
||||
E(2,0) = -E(0,2);
|
||||
E(3,0) = -E(0,3);
|
||||
E(2,1) = -E(1,2);
|
||||
E(3,1) = -E(1,3);
|
||||
E(3,2) = -E(2,3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//f_exact = E + 0.5 * P( curl DivSkew E ), where P is the 4d permutation operator
|
||||
void f_exact(const Vector &x, DenseMatrix &f)
|
||||
{
|
||||
int dim = x.Size();
|
||||
|
||||
f.SetSize(dim,dim);
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
f = 0.0;
|
||||
|
||||
double s0 = sin(M_PI*x(0)), s1 = sin(M_PI*x(1)), s2 = sin(M_PI*x(2)),
|
||||
s3 = sin(M_PI*x(3));
|
||||
double c0 = cos(M_PI*x(0)), c1 = cos(M_PI*x(1)), c2 = cos(M_PI*x(2)),
|
||||
c3 = cos(M_PI*x(3));
|
||||
|
||||
f(0,1) = (1.0 + 1.0 * M_PI*M_PI)*c0*c1*s2*s3;
|
||||
f(0,2) = -(1.0 + 0.0 * M_PI*M_PI)*c0*s1*c2*s3;
|
||||
f(0,3) = (1.0 + 1.0 * M_PI*M_PI)*c0*s1*s2*c3;
|
||||
f(1,2) = (1.0 - 1.0 * M_PI*M_PI)*s0*c1*c2*s3;
|
||||
f(1,3) = -(1.0 + 0.0 * M_PI*M_PI)*s0*c1*s2*c3;
|
||||
f(2,3) = (1.0 + 1.0 * M_PI*M_PI)*s0*s1*c2*c3;
|
||||
|
||||
f(1,0) = -f(0,1);
|
||||
f(2,0) = -f(0,2);
|
||||
f(3,0) = -f(0,3);
|
||||
f(2,1) = -f(1,2);
|
||||
f(3,1) = -f(1,3);
|
||||
f(3,2) = -f(2,3);
|
||||
}
|
||||
}
|
||||
@@ -1,800 +0,0 @@
|
||||
// MFEM Example 4 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex4p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex4p -m ../data/square-disc.mesh
|
||||
// mpirun -np 4 ex4p -m ../data/star.mesh
|
||||
// mpirun -np 4 ex4p -m ../data/beam-tet.mesh
|
||||
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh
|
||||
// mpirun -np 4 ex4p -m ../data/escher.mesh -o 2 -sc
|
||||
// mpirun -np 4 ex4p -m ../data/fichera.mesh -o 2 -hb
|
||||
// mpirun -np 4 ex4p -m ../data/fichera-q2.vtk
|
||||
// mpirun -np 4 ex4p -m ../data/fichera-q3.mesh -o 2 -sc
|
||||
// mpirun -np 4 ex4p -m ../data/square-disc-nurbs.mesh -o 3
|
||||
// mpirun -np 4 ex4p -m ../data/beam-hex-nurbs.mesh -o 3
|
||||
// mpirun -np 4 ex4p -m ../data/periodic-square.mesh -no-bc
|
||||
// mpirun -np 4 ex4p -m ../data/periodic-cube.mesh -no-bc
|
||||
// mpirun -np 4 ex4p -m ../data/amr-quad.mesh
|
||||
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc
|
||||
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
|
||||
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
|
||||
//
|
||||
// Description: This example code solves a simple 2D/3D H(div) diffusion
|
||||
// problem corresponding to the second order definite equation
|
||||
// -grad(alpha div F) + beta F = f with boundary condition F dot n
|
||||
// = <given normal field>. Here, we use a given exact solution F
|
||||
// and compute the corresponding r.h.s. f. We discretize with
|
||||
// Raviart-Thomas finite elements.
|
||||
//
|
||||
// The example demonstrates the use of H(div) finite element
|
||||
// spaces with the grad-div and H(div) vector finite element mass
|
||||
// bilinear form, as well as the computation of discretization
|
||||
// error when the exact solution is known. Bilinear form
|
||||
// hybridization and static condensation are also illustrated.
|
||||
//
|
||||
// We recommend viewing examples 1-3 before viewing this example.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "./spe10_coeff.cpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
|
||||
int* LoadIterations(int NRows, int NCol)
|
||||
{
|
||||
ifstream in("iter_div.txt");
|
||||
|
||||
//initialize
|
||||
int *iters = new int[NCol*NRows];
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
iters[row*NCol+col] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
return iters;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
if (in.eof())
|
||||
{
|
||||
in.close();
|
||||
return iters;
|
||||
}
|
||||
in >> iters[row*NCol+col];
|
||||
}
|
||||
|
||||
|
||||
in.close();
|
||||
|
||||
return iters;
|
||||
}
|
||||
|
||||
void putIterationsInArray(int iter, int row, int col, int NCol, int* iters)
|
||||
{
|
||||
iters[row*NCol+col] = iter;
|
||||
}
|
||||
|
||||
void WriteIterations(int *iters, int NRows, int NCol)
|
||||
{
|
||||
ofstream out;
|
||||
out.open("iter_div.txt",fstream::out);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
delete[] iters;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
out << iters[row*NCol+col] << "\t";
|
||||
}
|
||||
out << endl;
|
||||
}
|
||||
out.close();
|
||||
|
||||
delete[] iters;
|
||||
}
|
||||
|
||||
|
||||
// Exact solution, F, and r.h.s., f. See below for implementation.
|
||||
void F_exact(const Vector &, Vector &);
|
||||
void f_exact(const Vector &, Vector &);
|
||||
double freq = 1.0, kappa;
|
||||
|
||||
|
||||
|
||||
class div4dPrec : public Solver
|
||||
{
|
||||
|
||||
private:
|
||||
HypreParMatrix *A;
|
||||
ParFiniteElementSpace *fespace;
|
||||
|
||||
Coefficient *alpha_, *beta_;
|
||||
|
||||
//kernel operators
|
||||
HypreParMatrix *P_d_HSkewDiv_Hdiv;
|
||||
|
||||
HypreParMatrix *P_H1_HDivSkew;
|
||||
HypreParMatrix *H1_KernelMat;
|
||||
HypreBoomerAMG *amgH1_Kernel;
|
||||
|
||||
//"image" operators
|
||||
HypreParMatrix *P_H1_Hdiv;
|
||||
HypreParMatrix *H1_ImageMat;
|
||||
HypreBoomerAMG *amgH1_Image;
|
||||
|
||||
HypreParMatrix *HDivSkewMat;
|
||||
HypreSmoother * smootherdiv;
|
||||
HypreSmoother * smootherDivSkew;
|
||||
|
||||
CGSolver *pcgKernel;
|
||||
CGSolver *pcgImage;
|
||||
|
||||
Vector *f;
|
||||
Vector *fKernel, *uKernel;
|
||||
Vector *fImage, *uImage;
|
||||
Vector *fDivSkew, *uDivSkew;
|
||||
|
||||
FiniteElementCollection* fecHDivSkewKernel;
|
||||
ParFiniteElementSpace *HDivSkewKernelFESpace;
|
||||
|
||||
bool exactSolves;
|
||||
|
||||
public:
|
||||
~div4dPrec()
|
||||
{
|
||||
delete pcgImage;
|
||||
delete pcgKernel;
|
||||
|
||||
delete uDivSkew, fDivSkew, uImage, fImage, uKernel, fKernel, f;
|
||||
|
||||
delete smootherDivSkew;
|
||||
delete HDivSkewMat;
|
||||
|
||||
delete P_d_HSkewDiv_Hdiv;
|
||||
delete P_H1_Hdiv;
|
||||
delete P_H1_HDivSkew;
|
||||
|
||||
delete amgH1_Image, H1_ImageMat;
|
||||
delete amgH1_Kernel, H1_KernelMat;
|
||||
|
||||
delete smootherdiv;
|
||||
|
||||
delete HDivSkewKernelFESpace;
|
||||
delete fecHDivSkewKernel;
|
||||
}
|
||||
div4dPrec(HypreParMatrix *AUser, ParFiniteElementSpace *fespaceUser,
|
||||
Coefficient *alpha, Coefficient *beta, const Array<int> &essBnd,
|
||||
int orderKernel=1, bool exactSolvesUser=false)
|
||||
{
|
||||
A = AUser;
|
||||
fespace = fespaceUser;
|
||||
alpha_ = alpha;
|
||||
beta_ = beta;
|
||||
|
||||
|
||||
ParMesh *pmesh = fespace->GetParMesh();
|
||||
int dim = pmesh->Dimension();
|
||||
|
||||
exactSolves = exactSolvesUser;
|
||||
|
||||
|
||||
|
||||
|
||||
int orderIm=1; //H1 --> H(div)
|
||||
int orderKer=orderKernel; //DivSkew V --> H(div)
|
||||
|
||||
|
||||
|
||||
smootherdiv = new HypreSmoother(*A, 16, 3);
|
||||
|
||||
Array<int> Hdiv_essDof(fespace->GetVSize()); Hdiv_essDof = 0;
|
||||
fespace->GetEssentialVDofs(essBnd, Hdiv_essDof);
|
||||
|
||||
|
||||
|
||||
|
||||
//setup the H1 FESpace for the kernel
|
||||
FiniteElementCollection* fecH1Kernel;
|
||||
if (orderKer==1) { fecH1Kernel = new LinearFECollection; }
|
||||
else { fecH1Kernel = new QuadraticFECollection; }
|
||||
ParFiniteElementSpace *H1KernelFESpace = new ParFiniteElementSpace(pmesh,
|
||||
fecH1Kernel, 6, Ordering::byVDIM);
|
||||
Array<int> H1Kernel_essDof(H1KernelFESpace->GetVSize()); H1Kernel_essDof = 0;
|
||||
H1KernelFESpace->GetEssentialVDofs(essBnd, H1Kernel_essDof);
|
||||
|
||||
|
||||
//setup the H(DivSkew) FESpace for the kernel
|
||||
if (orderKer==1) { fecHDivSkewKernel = new DivSkew1_4DFECollection; }
|
||||
// else fecHDivSkewKernel = new DivSkewFull1_4DFECollection;
|
||||
HDivSkewKernelFESpace = new ParFiniteElementSpace(pmesh, fecHDivSkewKernel);
|
||||
Array<int> HDivSkewKernel_essDof(HDivSkewKernelFESpace->GetVSize());
|
||||
HDivSkewKernel_essDof = 0;
|
||||
HDivSkewKernelFESpace->GetEssentialVDofs(essBnd, HDivSkewKernel_essDof);
|
||||
|
||||
|
||||
//setup the FESpace for the H1 injection
|
||||
FiniteElementCollection* fecH1Vec;
|
||||
if (orderIm==1) { fecH1Vec = new LinearFECollection; }
|
||||
else { fecH1Vec = new QuadraticFECollection; }
|
||||
ParFiniteElementSpace *H1_ImageFESpace = new ParFiniteElementSpace(pmesh,
|
||||
fecH1Vec, dim, Ordering::byVDIM);
|
||||
Array<int> H1Image_essDof(H1_ImageFESpace->GetVSize()); H1Image_essDof = 0;
|
||||
H1_ImageFESpace->GetEssentialVDofs(essBnd, H1Image_essDof);
|
||||
|
||||
|
||||
|
||||
//setup the H1 preconditioner for the kernel
|
||||
ParBilinearForm* H1Varf = new ParBilinearForm(H1KernelFESpace);
|
||||
// H1Varf->AddDomainIntegrator(new VectorDiffusionIntegrator(*alpha_, 6));
|
||||
// H1Varf->AddDomainIntegrator(new VectorMassIntegrator(6, beta_));
|
||||
|
||||
H1Varf->AddDomainIntegrator(new VectorDiffusionIntegrator(*beta_, 6));
|
||||
H1Varf->Assemble();
|
||||
H1Varf->Finalize();
|
||||
SparseMatrix &matH1(H1Varf->SpMat());
|
||||
for (int dof=0; dof<H1Kernel_essDof.Size(); dof++) if (H1Kernel_essDof[dof]<0) { matH1.EliminateRowCol(dof); }
|
||||
H1_KernelMat = H1Varf->ParallelAssemble();
|
||||
delete H1Varf;
|
||||
amgH1_Kernel = new HypreBoomerAMG(*H1_KernelMat);
|
||||
amgH1_Kernel->SetSystemsOptions(6);
|
||||
|
||||
//setup the H1 preconditioner for the image
|
||||
ParBilinearForm* H1VecVarf = new ParBilinearForm(H1_ImageFESpace);
|
||||
H1VecVarf->AddDomainIntegrator(new VectorDiffusionIntegrator(*alpha_));
|
||||
H1VecVarf->AddDomainIntegrator(new VectorMassIntegrator(-1, beta_));
|
||||
H1VecVarf->Assemble();
|
||||
H1VecVarf->Finalize();
|
||||
SparseMatrix &matH1Vec(H1VecVarf->SpMat());
|
||||
for (int dof=0; dof<H1Image_essDof.Size(); dof++) if (H1Image_essDof[dof]<0) { matH1Vec.EliminateRowCol(dof); }
|
||||
H1_ImageMat = H1VecVarf->ParallelAssemble();
|
||||
delete H1VecVarf;
|
||||
amgH1_Image = new HypreBoomerAMG(*H1_ImageMat);
|
||||
amgH1_Image->SetSystemsOptions(dim);
|
||||
|
||||
|
||||
//setup the injection of H1 into H(DivSkew)
|
||||
ParDiscreteLinearOperator *disInterpolIm = new ParDiscreteLinearOperator(
|
||||
H1KernelFESpace, HDivSkewKernelFESpace);
|
||||
disInterpolIm->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpolIm->Assemble();
|
||||
disInterpolIm->Finalize();
|
||||
SparseMatrix* smatIDIm = &(disInterpolIm->SpMat());
|
||||
smatIDIm->EliminateCols(H1Kernel_essDof);
|
||||
for (int dof=0; dof<HDivSkewKernel_essDof.Size();
|
||||
dof++) if (HDivSkewKernel_essDof[dof]<0) { smatIDIm->EliminateRow(dof); }
|
||||
P_H1_HDivSkew = disInterpolIm->ParallelAssemble();
|
||||
delete disInterpolIm;
|
||||
|
||||
//setup the injection of H1 into H(div)
|
||||
ParDiscreteLinearOperator *disInterpol = new ParDiscreteLinearOperator(
|
||||
H1_ImageFESpace, fespace);
|
||||
disInterpol->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpol->Assemble();
|
||||
disInterpol->Finalize();
|
||||
SparseMatrix* smatID = &(disInterpol->SpMat());
|
||||
smatID->EliminateCols(H1Image_essDof);
|
||||
for (int dof=0; dof<Hdiv_essDof.Size(); dof++) if (Hdiv_essDof[dof]<0) { smatID->EliminateRow(dof); }
|
||||
P_H1_Hdiv = disInterpol->ParallelAssemble();
|
||||
delete disInterpol;
|
||||
|
||||
|
||||
|
||||
|
||||
//setup the injection of the DivSkew(H(DivSkew)) into H(div)
|
||||
ParDiscreteLinearOperator *disDivSkew = new ParDiscreteLinearOperator(
|
||||
HDivSkewKernelFESpace, fespace);
|
||||
disDivSkew->AddDomainInterpolator(new DivSkewInterpolator);
|
||||
disDivSkew->Assemble();
|
||||
disDivSkew->Finalize();
|
||||
SparseMatrix* smatDivSkew= &(disDivSkew->SpMat());
|
||||
smatDivSkew->EliminateCols(HDivSkewKernel_essDof);
|
||||
for (int dof=0; dof<Hdiv_essDof.Size(); dof++) if (Hdiv_essDof[dof]<0) { smatDivSkew->EliminateRow(dof); }
|
||||
P_d_HSkewDiv_Hdiv = disDivSkew->ParallelAssemble();
|
||||
delete disDivSkew;
|
||||
|
||||
|
||||
//setup the smoother for H(DivSkew)
|
||||
ParBilinearForm *a_HDivSkew = new ParBilinearForm(HDivSkewKernelFESpace);
|
||||
// a_HDivSkew->AddDomainIntegrator(new DivSkewDivSkewIntegrator(*alpha_));
|
||||
// a_HDivSkew->AddDomainIntegrator(new VectorFE_DivSkewMassIntegrator(*beta_));
|
||||
|
||||
a_HDivSkew->AddDomainIntegrator(new DivSkewDivSkewIntegrator(*beta_));
|
||||
|
||||
a_HDivSkew->Assemble();
|
||||
a_HDivSkew->Finalize();
|
||||
SparseMatrix &matHDivSkew(a_HDivSkew->SpMat());
|
||||
for (int dof=0; dof<HDivSkewKernel_essDof.Size();
|
||||
dof++) if (HDivSkewKernel_essDof[dof]<0) { matHDivSkew.EliminateRowCol(dof); }
|
||||
HDivSkewMat = a_HDivSkew->ParallelAssemble();
|
||||
delete a_HDivSkew;
|
||||
smootherDivSkew = new HypreSmoother(*HDivSkewMat, 16, 3);
|
||||
|
||||
|
||||
|
||||
f = new Vector(fespace->GetTrueVSize());
|
||||
|
||||
fKernel = new Vector(H1KernelFESpace->GetTrueVSize());
|
||||
uKernel = new Vector(H1KernelFESpace->GetTrueVSize());
|
||||
|
||||
fImage = new Vector(H1_ImageFESpace->GetTrueVSize());
|
||||
uImage = new Vector(H1_ImageFESpace->GetTrueVSize());
|
||||
|
||||
fDivSkew = new Vector(HDivSkewKernelFESpace->GetTrueVSize());
|
||||
uDivSkew = new Vector(HDivSkewKernelFESpace->GetTrueVSize());
|
||||
|
||||
amgH1_Kernel->Mult(*fKernel, *uKernel);
|
||||
amgH1_Image->Mult(*fImage, *uImage);
|
||||
|
||||
pcgKernel = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgKernel->SetOperator(*H1_KernelMat);
|
||||
pcgKernel->SetPreconditioner(*amgH1_Kernel);
|
||||
pcgKernel->SetRelTol(1e-16);
|
||||
pcgKernel->SetMaxIter(100000000);
|
||||
pcgKernel->SetPrintLevel(-2);
|
||||
|
||||
pcgImage = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgImage->SetOperator(*H1_ImageMat);
|
||||
pcgImage->SetPreconditioner(*amgH1_Image);
|
||||
pcgImage->SetRelTol(1e-16);
|
||||
pcgImage->SetMaxIter(100000000);
|
||||
pcgImage->SetPrintLevel(-2);
|
||||
|
||||
delete H1_ImageFESpace;
|
||||
delete H1KernelFESpace;
|
||||
delete fecH1Kernel;
|
||||
delete fecH1Vec;
|
||||
}
|
||||
|
||||
void setExactSolve(bool exSol)
|
||||
{
|
||||
exactSolves = exSol;
|
||||
}
|
||||
|
||||
virtual void Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
smootherdiv->Mult(x,y);
|
||||
|
||||
P_H1_Hdiv->MultTranspose(x,*fImage);
|
||||
*uImage = 0.0;
|
||||
if (exactSolves) { pcgImage->Mult(*fImage, *uImage); }
|
||||
else { amgH1_Image->Mult(*fImage, *uImage); }
|
||||
P_H1_Hdiv->Mult(1.0, *uImage, 1.0, y);
|
||||
|
||||
|
||||
*uDivSkew = 0.0;
|
||||
P_d_HSkewDiv_Hdiv->MultTranspose(x,*fDivSkew);
|
||||
|
||||
smootherDivSkew->Mult(*fDivSkew, *uDivSkew);
|
||||
|
||||
P_H1_HDivSkew->MultTranspose(*fDivSkew,*fKernel);
|
||||
*uKernel = 0.0;
|
||||
if (exactSolves) { pcgKernel->Mult(*fKernel, *uKernel); }
|
||||
else { amgH1_Kernel->Mult(*fKernel, *uKernel); }
|
||||
P_H1_HDivSkew->Mult(1.0, *uKernel, 1.0, *uDivSkew);
|
||||
|
||||
P_d_HSkewDiv_Hdiv->Mult(1.0, *uDivSkew, 1.0, y);
|
||||
}
|
||||
|
||||
virtual void SetOperator(const Operator &op) {};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
bool verbose = (myid==0);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
int order = 1;
|
||||
bool set_bc = true;
|
||||
bool static_cond = false;
|
||||
bool hybridization = false;
|
||||
bool visualization = 1;
|
||||
int sequ_ref_levels = 0;
|
||||
int par_ref_levels = 0;
|
||||
double tol = 1e-6;
|
||||
double coeffWeight = 1.0;
|
||||
bool spe10Coeff = false;
|
||||
bool exactH1Solver = false;
|
||||
bool standardCG = true;
|
||||
|
||||
int NExpo = 8;
|
||||
int weightStart = -NExpo;
|
||||
int weightEnd = NExpo;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&sequ_ref_levels, "-sr", "--seqrefinement",
|
||||
"Number of sequential refinement steps.");
|
||||
args.AddOption(&par_ref_levels, "-pr", "--parrefinement",
|
||||
"Number of parallel refinement steps.");
|
||||
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
|
||||
"Impose or not essential boundary conditions.");
|
||||
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
|
||||
" solution.");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
|
||||
"--no-hybridization", "Enable hybridization.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"A parameter.");
|
||||
args.AddOption(&coeffWeight, "-c", "--coeffMass",
|
||||
"the weight for the mass term.");
|
||||
args.AddOption(&exactH1Solver, "-exH1Sol", "--exactH1Solver", "-H1prec",
|
||||
"--H1preconditioner",
|
||||
"Use exact H1 solvers for the preconditioner.");
|
||||
args.AddOption(&spe10Coeff, "-spe10", "--useSPE10Coeff", "-constCoeff",
|
||||
"--constCoeff",
|
||||
"Switch between the coefficients for the mass bilinear form.");
|
||||
args.AddOption(&standardCG, "-sCG", "--stdCG", "-rCG", "--resCG",
|
||||
"Switch between standard PCG or recompute residuals in every step and use the residuals itself for the stopping criteria.");
|
||||
args.AddOption(&weightStart, "-ws", "--weightStart",
|
||||
"the exponent for the starting weight (for the mass term).");
|
||||
args.AddOption(&weightEnd, "-we", "--weightEnd",
|
||||
"the exponent for the weight at the end (for the mass term).");
|
||||
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
MPI_Finalize();
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
kappa = freq * M_PI;
|
||||
|
||||
// 3. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume, as well as periodic meshes with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
// 4. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement. We choose
|
||||
// 'ref_levels' to be the largest number that gives a final mesh with no
|
||||
// more than 1,000 elements.
|
||||
{
|
||||
for (int l = 0; l < sequ_ref_levels; l++)
|
||||
{
|
||||
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. Tetrahedral
|
||||
// meshes need to be reoriented before we can define high-order Nedelec
|
||||
// spaces on them (this is needed in the ADS solver below).
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
{
|
||||
for (int l = 0; l < par_ref_levels; l++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Raviart-Thomas finite elements of the specified order.
|
||||
FiniteElementCollection *fec;
|
||||
if (dim==4) { fec = new RT0_4DFECollection; }
|
||||
else { fec = new RT_FECollection(order-1, dim); }
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes from the mesh as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = set_bc ? 1 : 0;
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
|
||||
// 8. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system, which in this case is
|
||||
// (f,phi_i) where f is given by the function f_exact and phi_i are the
|
||||
// basis functions in the finite element fespace.
|
||||
|
||||
|
||||
// 9. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x by projecting the exact
|
||||
// solution. Note that only values from the boundary faces will be used
|
||||
// when eliminating the non-homogeneous boundary condition to modify the
|
||||
// r.h.s. vector b.
|
||||
ParGridFunction x(fespace);
|
||||
VectorFunctionCoefficient F(sdim, F_exact);
|
||||
|
||||
for (int expo=weightStart; expo<=weightEnd; expo++)
|
||||
{
|
||||
double weight = pow(10.0,expo);
|
||||
kappa = weight;
|
||||
|
||||
x.ProjectCoefficient(F);
|
||||
|
||||
VectorFunctionCoefficient f(sdim, f_exact);
|
||||
ParLinearForm *b = new ParLinearForm(fespace);
|
||||
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
|
||||
b->Assemble();
|
||||
|
||||
// 10. Set up the parallel bilinear form corresponding to the H(div)
|
||||
// diffusion operator grad alpha div + beta I, by adding the div-div and
|
||||
// the mass domain integrators.
|
||||
|
||||
// std::string permFile = "spe_perm.dat";
|
||||
// InversePermeabilityFunction::ReadPermeabilityFile(permFile, MPI_COMM_WORLD);
|
||||
|
||||
Coefficient *alpha = new ConstantCoefficient(1.0);
|
||||
Coefficient *beta;
|
||||
// if(spe10Coeff) beta = new FunctionCoefficient(InversePermeabilityFunction::Norm2Permeability);
|
||||
// else
|
||||
beta = new ConstantCoefficient(weight);
|
||||
|
||||
ParBilinearForm *a = new ParBilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
|
||||
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, static condensation,
|
||||
// hybridization, etc.
|
||||
FiniteElementCollection *hfec = NULL;
|
||||
ParFiniteElementSpace *hfes = NULL;
|
||||
if (static_cond)
|
||||
{
|
||||
a->EnableStaticCondensation();
|
||||
}
|
||||
else if (hybridization)
|
||||
{
|
||||
hfec = new DG_Interface_FECollection(order-1, dim);
|
||||
hfes = new ParFiniteElementSpace(pmesh, hfec);
|
||||
a->EnableHybridization(hfes, new NormalTraceJumpIntegrator(),
|
||||
ess_tdof_list);
|
||||
}
|
||||
a->Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
HYPRE_Int glob_size = A.GetGlobalNumRows();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Size of linear system: " << glob_size << endl;
|
||||
}
|
||||
|
||||
// 12. Define and apply a parallel PCG solver for A X = B with the 2D AMS or
|
||||
// the 3D ADS preconditioners from hypre. If using hybridization, the
|
||||
// system is preconditioned with hypre's BoomerAMG.
|
||||
Solver *prec = NULL;
|
||||
if (hybridization) { prec = new HypreBoomerAMG(A); }
|
||||
else
|
||||
{
|
||||
ParFiniteElementSpace *prec_fespace =
|
||||
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
|
||||
if (dim == 2) { prec = new HypreAMS(A, prec_fespace); }
|
||||
else if (dim==3) { prec = new HypreADS(A, prec_fespace); }
|
||||
else if (dim==4) { prec = new div4dPrec(&A, fespace, alpha, beta, ess_bdr, order, exactH1Solver); }
|
||||
else { prec = NULL; }
|
||||
}
|
||||
|
||||
int iter = -1;
|
||||
if (standardCG)
|
||||
{
|
||||
IterativeSolver *pcg = new CGSolver(MPI_COMM_WORLD);
|
||||
pcg->SetOperator(A);
|
||||
pcg->SetRelTol(tol);
|
||||
pcg->SetMaxIter(500);
|
||||
pcg->SetPrintLevel(1);
|
||||
pcg->SetPreconditioner(*prec);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
iter = pcg->GetNumIterations();
|
||||
|
||||
delete pcg;
|
||||
}
|
||||
else
|
||||
{
|
||||
HyprePCG *pcg = new HyprePCG(A);
|
||||
pcg->SetTol(tol);
|
||||
pcg->SetMaxIter(5000);
|
||||
pcg->SetResidualConvergenceOptions(1,tol);
|
||||
pcg->SetPrintLevel(2);
|
||||
// pcg->SetPreconditioner(*prec);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
pcg->GetNumIterations(iter);
|
||||
|
||||
delete pcg;
|
||||
}
|
||||
|
||||
if (myid==0)
|
||||
{
|
||||
cout << "Weigth: " << weight << " " << iter << endl;
|
||||
|
||||
int *iters = LoadIterations(10, 2*NExpo+1);
|
||||
putIterationsInArray(iter, sequ_ref_levels+par_ref_levels, expo+NExpo,
|
||||
2*NExpo+1, iters);
|
||||
WriteIterations(iters, 10, 2*NExpo+1);
|
||||
}
|
||||
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 14. Compute and print the L^2 norm of the error.
|
||||
{
|
||||
double err = x.ComputeL2Error(F);
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "\n|| F_h - F ||_{L^2} = " << err << '\n' << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 15. Save the refined mesh and the solution in parallel. This output can
|
||||
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
// {
|
||||
// ostringstream mesh_name, sol_name;
|
||||
// mesh_name << "mesh." << setfill('0') << setw(6) << myid;
|
||||
// sol_name << "sol." << setfill('0') << setw(6) << myid;
|
||||
//
|
||||
// ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
// mesh_ofs.precision(8);
|
||||
// pmesh->Print(mesh_ofs);
|
||||
//
|
||||
// ofstream sol_ofs(sol_name.str().c_str());
|
||||
// sol_ofs.precision(8);
|
||||
// x.Save(sol_ofs);
|
||||
// }
|
||||
|
||||
// 16. Send the solution by socket to a GLVis server.
|
||||
// if (visualization)
|
||||
// {
|
||||
// char vishost[] = "localhost";
|
||||
// int visport = 19916;
|
||||
// socketstream sol_sock(vishost, visport);
|
||||
// sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
// sol_sock.precision(8);
|
||||
// sol_sock << "solution\n" << *pmesh << x << flush;
|
||||
// }
|
||||
|
||||
if (prec!=NULL) { delete prec; }
|
||||
delete hfes;
|
||||
delete hfec;
|
||||
delete a;
|
||||
delete alpha;
|
||||
delete beta;
|
||||
|
||||
delete b;
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
|
||||
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete pmesh;
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// The exact solution (for non-surface meshes)
|
||||
void F_exact(const Vector &p, Vector &F)
|
||||
{
|
||||
int dim = p.Size();
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
double s0 = sin(M_PI*p(0)), s1 = sin(M_PI*p(1)), s2 = sin(M_PI*p(2)),
|
||||
s3 = sin(M_PI*p(3));
|
||||
double c0 = cos(M_PI*p(0)), c1 = cos(M_PI*p(1)), c2 = cos(M_PI*p(2)),
|
||||
c3 = cos(M_PI*p(3));
|
||||
|
||||
F(0) = c0 * s1 * s2 * s3;
|
||||
F(1) = s0 * c1 * s2 * s3;
|
||||
F(2) = s0 * s1 * c2 * s3;
|
||||
F(3) = s0 * s1 * s2 * c3;
|
||||
}
|
||||
else
|
||||
{
|
||||
double x = p(0);
|
||||
double y = p(1);
|
||||
// double z = (dim == 3) ? p(2) : 0.0;
|
||||
|
||||
F(0) = cos(kappa*x)*sin(kappa*y);
|
||||
F(1) = cos(kappa*y)*sin(kappa*x);
|
||||
if (dim == 3)
|
||||
{
|
||||
F(2) = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The right hand side
|
||||
void f_exact(const Vector &p, Vector &f)
|
||||
{
|
||||
int dim = p.Size();
|
||||
if (dim==4)
|
||||
{
|
||||
double s0 = sin(M_PI*p(0)), s1 = sin(M_PI*p(1)), s2 = sin(M_PI*p(2)),
|
||||
s3 = sin(M_PI*p(3));
|
||||
double c0 = cos(M_PI*p(0)), c1 = cos(M_PI*p(1)), c2 = cos(M_PI*p(2)),
|
||||
c3 = cos(M_PI*p(3));
|
||||
|
||||
f(0) = c0 * s1 * s2 * s3;
|
||||
f(1) = s0 * c1 * s2 * s3;
|
||||
f(2) = s0 * s1 * c2 * s3;
|
||||
f(3) = s0 * s1 * s2 * c3;
|
||||
|
||||
f *= (kappa + 4.0 * M_PI*M_PI);
|
||||
}
|
||||
else
|
||||
{
|
||||
double x = p(0);
|
||||
double y = p(1);
|
||||
// double z = (dim == 3) ? p(2) : 0.0;
|
||||
|
||||
double temp = 1 + 2*kappa*kappa;
|
||||
|
||||
f(0) = temp*cos(kappa*x)*sin(kappa*y);
|
||||
f(1) = temp*cos(kappa*y)*sin(kappa*x);
|
||||
if (dim == 3)
|
||||
{
|
||||
f(2) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-13
@@ -27,11 +27,10 @@ SEQ_EXAMPLES = ex0 ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 \
|
||||
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 \
|
||||
ex1p_4d ex3p_4d ex4D_DivSkew
|
||||
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
|
||||
ex37p ex39p ex40p
|
||||
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
|
||||
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p \
|
||||
ex24p ex25p ex26p ex34p ex35p
|
||||
|
||||
ifeq ($(MFEM_USE_LAPACK),YES)
|
||||
SEQ_EXAMPLES += ex38
|
||||
@@ -139,14 +138,6 @@ 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
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
// 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.
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <cstdlib>
|
||||
|
||||
@@ -709,7 +709,10 @@ real_t HyperelasticOperator::ElasticEnergy(const ParGridFunction &x) const
|
||||
|
||||
real_t HyperelasticOperator::KineticEnergy(const ParGridFunction &v) const
|
||||
{
|
||||
real_t energy = 0.5*M.ParInnerProduct(v, v);
|
||||
real_t loc_energy = 0.5*M.InnerProduct(v, v);
|
||||
real_t energy;
|
||||
MPI_Allreduce(&loc_energy, &energy, 1, MPITypeMap<real_t>::mpi_type, MPI_SUM,
|
||||
fespace.GetComm());
|
||||
return energy;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
* spe10_coeff.cpp
|
||||
*
|
||||
* Created on: Aug 23, 2017
|
||||
* Author: neumueller
|
||||
*/
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
class InversePermeabilityFunction
|
||||
{
|
||||
public:
|
||||
|
||||
enum SliceOrientation {NONE, XY, XZ, YZ};
|
||||
|
||||
static void SetNumberCells(int Nx_, int Ny_, int Nz_);
|
||||
static void SetMeshSizes(double hx, double hy, double hz);
|
||||
static void Set2DSlice(SliceOrientation o, int npos );
|
||||
|
||||
static void ReadPermeabilityFile(const std::string fileName);
|
||||
#ifdef MFEM_USE_MPI
|
||||
static void ReadPermeabilityFile(const std::string fileName, MPI_Comm comm);
|
||||
#endif
|
||||
static void SetConstantInversePermeability(double ipx, double ipy, double ipz);
|
||||
|
||||
template<class F>
|
||||
static void Transform(const F & f)
|
||||
{
|
||||
for (int i = 0; i < 3*Nx*Ny*Nz; ++i)
|
||||
{
|
||||
inversePermeability[i] = f(inversePermeability[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void InversePermeability(const Vector & x, Vector & val);
|
||||
static double PermeabilityXY(Vector &x);
|
||||
static void NegativeInversePermeability(const Vector & x, Vector & val);
|
||||
static void Permeability(const Vector & x, Vector & val);
|
||||
|
||||
static double Norm2Permeability(const Vector & x);
|
||||
|
||||
static double Norm2InversePermeability(const Vector & x);
|
||||
static double Norm1InversePermeability(const Vector & x);
|
||||
static double NormInfInversePermeability(const Vector & x);
|
||||
|
||||
static double InvNorm2(const Vector & x);
|
||||
static double InvNorm1(const Vector & x);
|
||||
static double InvNormInf(const Vector & x);
|
||||
|
||||
|
||||
static void ClearMemory();
|
||||
|
||||
private:
|
||||
static int Nx;
|
||||
static int Ny;
|
||||
static int Nz;
|
||||
static double hx;
|
||||
static double hy;
|
||||
static double hz;
|
||||
static double * inversePermeability;
|
||||
|
||||
static SliceOrientation orientation;
|
||||
static int npos;
|
||||
};
|
||||
|
||||
|
||||
void InversePermeabilityFunction::SetNumberCells(int Nx_, int Ny_, int Nz_)
|
||||
{
|
||||
Nx = Nx_;
|
||||
Ny = Ny_;
|
||||
Nz = Nz_;
|
||||
}
|
||||
|
||||
void InversePermeabilityFunction::SetMeshSizes(double hx_, double hy_,
|
||||
double hz_)
|
||||
{
|
||||
hx = hx_;
|
||||
hy = hy_;
|
||||
hz = hz_;
|
||||
}
|
||||
|
||||
void InversePermeabilityFunction::Set2DSlice(SliceOrientation o, int npos_ )
|
||||
{
|
||||
orientation = o;
|
||||
npos = npos_;
|
||||
}
|
||||
|
||||
void InversePermeabilityFunction::SetConstantInversePermeability(double ipx,
|
||||
double ipy, double ipz)
|
||||
{
|
||||
int compSize = Nx*Ny*Nz;
|
||||
int size = 3*compSize;
|
||||
inversePermeability = new double [size];
|
||||
double *ip = inversePermeability;
|
||||
|
||||
for (int i(0); i < compSize; ++i)
|
||||
{
|
||||
ip[i] = ipx;
|
||||
ip[i+compSize] = ipy;
|
||||
ip[i+2*compSize] = ipz;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
void InversePermeabilityFunction::ReadPermeabilityFile(const std::string
|
||||
fileName, MPI_Comm comm)
|
||||
{
|
||||
int num_procs, myid;
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
|
||||
StopWatch chrono;
|
||||
|
||||
chrono.Start();
|
||||
if (myid == 0)
|
||||
{
|
||||
ReadPermeabilityFile(fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
inversePermeability = new double [3*Nx*Ny*Nz];
|
||||
}
|
||||
chrono.Stop();
|
||||
|
||||
if (myid==0)
|
||||
{
|
||||
std::cout<<"Permeability file read in " << chrono.RealTime() << ".s \n";
|
||||
}
|
||||
|
||||
chrono.Clear();
|
||||
|
||||
chrono.Start();
|
||||
MPI_Bcast(inversePermeability, 3*Nx*Ny*Nz, MPI_DOUBLE, 0, comm);
|
||||
chrono.Stop();
|
||||
|
||||
if (myid==0)
|
||||
{
|
||||
std::cout<<"Permeability field distributed in " << chrono.RealTime() <<
|
||||
".s \n";
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void InversePermeabilityFunction::ReadPermeabilityFile(const std::string
|
||||
fileName)
|
||||
{
|
||||
std::ifstream permfile(fileName.c_str());
|
||||
|
||||
if (!permfile.is_open())
|
||||
{
|
||||
std::cout << "Error in opening file " << fileName << "\n";
|
||||
mfem_error("File do not exists");
|
||||
}
|
||||
|
||||
inversePermeability = new double [3*Nx*Ny*Nz];
|
||||
double *ip = inversePermeability;
|
||||
double tmp;
|
||||
for (int l = 0; l < 3; l++)
|
||||
{
|
||||
for (int k = 0; k < Nz; k++)
|
||||
{
|
||||
for (int j = 0; j < Ny; j++)
|
||||
{
|
||||
for (int i = 0; i < Nx; i++)
|
||||
{
|
||||
permfile >> *ip;
|
||||
*ip = 1./(*ip);
|
||||
ip++;
|
||||
}
|
||||
for (int i = 0; i < 60-Nx; i++)
|
||||
{
|
||||
permfile >> tmp; // skip unneeded part
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < 220-Ny; j++)
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
permfile >> tmp; // skip unneeded part
|
||||
}
|
||||
}
|
||||
|
||||
if (l < 2) // if not processing Kz, skip unneeded part
|
||||
for (int k = 0; k < 85-Nz; k++)
|
||||
for (int j = 0; j < 220; j++)
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
permfile >> tmp;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InversePermeabilityFunction::InversePermeability(const Vector & x,
|
||||
Vector & val)
|
||||
{
|
||||
val.SetSize(3);
|
||||
|
||||
unsigned int i,j,k;
|
||||
|
||||
switch (orientation)
|
||||
{
|
||||
case NONE:
|
||||
i = Nx-1-(int)floor(x[0]/hx/(1.+3e-16));
|
||||
j = (int)floor(x[1]/hy/(1.+3e-16));
|
||||
k = Nz-1-(int)floor(x[2]/hz/(1.+3e-16));
|
||||
break;
|
||||
case XY:
|
||||
i = Nx-1-(int)floor(x[0]/hx/(1.+3e-16));
|
||||
j = (int)floor(x[1]/hy/(1.+3e-16));
|
||||
k = npos;
|
||||
break;
|
||||
case XZ:
|
||||
i = Nx-1-(int)floor(x[0]/hx/(1.+3e-16));
|
||||
j = npos;
|
||||
k = Nz-1-(int)floor(x[2]/hz/(1.+3e-16));
|
||||
break;
|
||||
case YZ:
|
||||
i = npos;
|
||||
j = (int)floor(x[1]/hy/(1.+3e-16));
|
||||
k = Nz-1-(int)floor(x[2]/hz/(1.+3e-16));
|
||||
break;
|
||||
default:
|
||||
{
|
||||
mfem_error("InversePermeabilityFunction::InversePermeability");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int NMax = 3*Nx*Ny*Nz-1;
|
||||
if (Ny*Nx*k + Nx*j + i>NMax || Ny*Nx*k + Nx*j + i + Nx*Ny*Nz>NMax ||
|
||||
Ny*Nx*k + Nx*j + i + 2*Nx*Ny*Nz>NMax)
|
||||
{
|
||||
cout << " the indicies are wrong!" << endl;
|
||||
cout << i << " " << j << " " << k << endl;
|
||||
}
|
||||
|
||||
val[0] = inversePermeability[Ny*Nx*k + Nx*j + i];
|
||||
val[1] = inversePermeability[Ny*Nx*k + Nx*j + i + Nx*Ny*Nz];
|
||||
|
||||
if (orientation == NONE)
|
||||
{
|
||||
val[2] = inversePermeability[Ny*Nx*k + Nx*j + i + 2*Nx*Ny*Nz];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::PermeabilityXY(Vector &x)
|
||||
{
|
||||
unsigned int i,j,k;
|
||||
|
||||
i = Nx-1-(int)floor(x[0]/hx/(1.+3e-16));
|
||||
j = (int)floor(x[1]/hy/(1.+3e-16));
|
||||
k = npos;
|
||||
|
||||
return 1./inversePermeability[Ny*Nx*k + Nx*j + i];
|
||||
}
|
||||
|
||||
void InversePermeabilityFunction::NegativeInversePermeability(const Vector & x,
|
||||
Vector & val)
|
||||
{
|
||||
InversePermeability(x,val);
|
||||
val *= -1.;
|
||||
}
|
||||
|
||||
|
||||
void InversePermeabilityFunction::Permeability(const Vector & x, Vector & val)
|
||||
{
|
||||
InversePermeability(x,val);
|
||||
|
||||
for (double * it = val.GetData(), *end = val.GetData()+val.Size(); it != end;
|
||||
++it )
|
||||
{
|
||||
(*it) = 1./ (*it);
|
||||
}
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::Norm2Permeability(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
Permeability(x,val);
|
||||
return val.Norml2();
|
||||
}
|
||||
|
||||
|
||||
double InversePermeabilityFunction::Norm2InversePermeability(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return val.Norml2();
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::Norm1InversePermeability(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return val.Norml1();
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::NormInfInversePermeability(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return val.Normlinf();
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::InvNorm2(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return 1./val.Norml2();
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::InvNorm1(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return 1./val.Norml1();
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::InvNormInf(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return 1./val.Normlinf();
|
||||
}
|
||||
|
||||
|
||||
void InversePermeabilityFunction::ClearMemory()
|
||||
{
|
||||
delete[] inversePermeability;
|
||||
}
|
||||
|
||||
int InversePermeabilityFunction::Nx(60);
|
||||
int InversePermeabilityFunction::Ny(220);
|
||||
int InversePermeabilityFunction::Nz(85);
|
||||
double InversePermeabilityFunction::hx(20);
|
||||
double InversePermeabilityFunction::hy(10);
|
||||
double InversePermeabilityFunction::hz(2);
|
||||
double * InversePermeabilityFunction::inversePermeability(NULL);
|
||||
InversePermeabilityFunction::SliceOrientation
|
||||
InversePermeabilityFunction::orientation( InversePermeabilityFunction::NONE );
|
||||
int InversePermeabilityFunction::npos(-1);
|
||||
|
||||
|
||||
|
||||
@@ -856,7 +856,10 @@ double HyperelasticOperator::ElasticEnergy(const ParGridFunction &x) const
|
||||
|
||||
double HyperelasticOperator::KineticEnergy(const ParGridFunction &v) const
|
||||
{
|
||||
double energy = 0.5*M.ParInnerProduct(v, v);
|
||||
double loc_energy = 0.5*M.InnerProduct(v, v);
|
||||
double energy;
|
||||
MPI_Allreduce(&loc_energy, &energy, 1, MPI_DOUBLE, MPI_SUM,
|
||||
fespace.GetComm());
|
||||
return energy;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ set(SRCS
|
||||
integ/bilininteg_convection_pa.cpp
|
||||
integ/bilininteg_convection_ea.cpp
|
||||
integ/bilininteg_curlcurl_pa.cpp
|
||||
integ/bilininteg_dgdiffusion_pa.cpp
|
||||
integ/bilininteg_dgtrace_pa.cpp
|
||||
integ/bilininteg_dgtrace_ea.cpp
|
||||
integ/bilininteg_diffusion_mf.cpp
|
||||
@@ -118,7 +117,6 @@ set(SRCS
|
||||
quadinterpolator.cpp
|
||||
quadinterpolator_face.cpp
|
||||
restriction.cpp
|
||||
normal_deriv_restriction.cpp
|
||||
staticcond.cpp
|
||||
tmop.cpp
|
||||
tmop/tmop_pa.cpp
|
||||
@@ -230,7 +228,6 @@ set(HDRS
|
||||
quadinterpolator.hpp
|
||||
quadinterpolator_face.hpp
|
||||
restriction.hpp
|
||||
normal_deriv_restriction.hpp
|
||||
fespacehierarchy.hpp
|
||||
staticcond.hpp
|
||||
tbilinearform.hpp
|
||||
|
||||
@@ -1833,6 +1833,7 @@ void MixedBilinearForm::FormRectangularSystemMatrix(
|
||||
const Array<int> &trial_tdof_list,
|
||||
const Array<int> &test_tdof_list,
|
||||
OperatorHandle &A)
|
||||
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
@@ -1911,14 +1912,8 @@ void MixedBilinearForm::FormRectangularLinearSystem(
|
||||
B.SetSubVector(test_tdof_list, 0.0);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::Update(FiniteElementSpace *ntr_fes,
|
||||
FiniteElementSpace *nte_fes)
|
||||
void MixedBilinearForm::Update()
|
||||
{
|
||||
if ((ntr_fes && nte_fes) && (ntr_fes != trial_fes || nte_fes != test_fes))
|
||||
{
|
||||
trial_fes = ntr_fes;
|
||||
test_fes = nte_fes;
|
||||
}
|
||||
delete mat;
|
||||
mat = NULL;
|
||||
delete mat_e;
|
||||
|
||||
+6
-15
@@ -340,9 +340,9 @@ public:
|
||||
$ M^{-1} $ (currently returns NULL) */
|
||||
virtual MatrixInverse *Inverse() const;
|
||||
|
||||
/** @brief Finalizes the matrix initialization if the ::AssemblyLevel is
|
||||
/** @brief Finalizes the matrix initialization if the ::AssemblyLevel is
|
||||
AssemblyLevel::LEGACY.
|
||||
The matrix that gets finalized is different if you are using static
|
||||
THe matrix that gets finalized is different if you are using static
|
||||
condensation or hybridization.*/
|
||||
virtual void Finalize(int skip_zeros = 1);
|
||||
|
||||
@@ -643,7 +643,7 @@ public:
|
||||
void EliminateVDofs(const Array<int> &vdofs, const Vector &sol, Vector &rhs,
|
||||
DiagonalPolicy dpolicy = DIAG_ONE);
|
||||
|
||||
/** @brief Eliminate the given @a vdofs, storing the eliminated part
|
||||
/** @brief Eliminate the given @a vdofs, storing the eliminated part
|
||||
internally in $ M_e $.
|
||||
|
||||
This method works in conjunction with EliminateVDofsInRHS() and allows
|
||||
@@ -706,10 +706,6 @@ public:
|
||||
*/
|
||||
void SetDiagonalPolicy(DiagonalPolicy policy);
|
||||
|
||||
void SetIntegratorOwnership(int _extern_bfs)
|
||||
{
|
||||
extern_bfs = _extern_bfs;
|
||||
}
|
||||
/// Indicate that integrators are not owned by the BilinearForm
|
||||
void UseExternalIntegrators() { extern_bfs = 1; }
|
||||
|
||||
@@ -830,7 +826,7 @@ public:
|
||||
$ M^{-1} $ (currently unimplemented and returns NULL)*/
|
||||
virtual MatrixInverse *Inverse() const;
|
||||
|
||||
/** @brief Finalizes the matrix initialization if the ::AssemblyLevel is
|
||||
/** @brief Finalizes the matrix initialization if the ::AssemblyLevel is
|
||||
AssemblyLevel::LEGACY.*/
|
||||
virtual void Finalize(int skip_zeros = 1);
|
||||
|
||||
@@ -1072,13 +1068,8 @@ public:
|
||||
A.MakeRef(*A_ptr);
|
||||
}
|
||||
|
||||
virtual void Update(FiniteElementSpace *ntr_fes = NULL,
|
||||
FiniteElementSpace *nte_fes = NULL);
|
||||
|
||||
void SetIntegratorOwnership(int _extern_bfs)
|
||||
{
|
||||
extern_bfs = _extern_bfs;
|
||||
}
|
||||
/// Must be called after making changes to #trial_fes or #test_fes.
|
||||
void Update();
|
||||
|
||||
/// Return the trial FE space associated with the BilinearForm.
|
||||
FiniteElementSpace *TrialFESpace() { return trial_fes; }
|
||||
|
||||
+8
-136
@@ -282,22 +282,6 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
|
||||
int_face_X.SetSize(int_face_restrict_lex->Height(), Device::GetMemoryType());
|
||||
int_face_Y.SetSize(int_face_restrict_lex->Height(), Device::GetMemoryType());
|
||||
int_face_Y.UseDevice(true); // ensure 'int_face_Y = 0.0' is done on device
|
||||
|
||||
bool needs_normal_derivs = false;
|
||||
auto &integs = *a->GetFBFI();
|
||||
for (int i = 0; i < integs.Size(); ++i)
|
||||
{
|
||||
if (integs[i]->RequiresFaceNormalDerivatives())
|
||||
{
|
||||
needs_normal_derivs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (needs_normal_derivs)
|
||||
{
|
||||
int_face_dXdn.SetSize(int_face_restrict_lex->Height());
|
||||
int_face_dYdn.SetSize(int_face_restrict_lex->Height());
|
||||
}
|
||||
}
|
||||
|
||||
const bool has_bdr_integs = (a->GetBFBFI()->Size() > 0 ||
|
||||
@@ -312,22 +296,6 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
|
||||
bdr_face_Y.SetSize(bdr_face_restrict_lex->Height(), Device::GetMemoryType());
|
||||
bdr_face_Y.UseDevice(true); // ensure 'faceBoundY = 0.0' is done on device
|
||||
|
||||
bool needs_normal_derivs = false;
|
||||
auto &integs = *a->GetBFBFI();
|
||||
for (int i = 0; i < integs.Size(); ++i)
|
||||
{
|
||||
if (integs[i]->RequiresFaceNormalDerivatives())
|
||||
{
|
||||
needs_normal_derivs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (needs_normal_derivs)
|
||||
{
|
||||
bdr_face_dXdn.SetSize(bdr_face_restrict_lex->Height());
|
||||
bdr_face_dYdn.SetSize(bdr_face_restrict_lex->Height());
|
||||
}
|
||||
|
||||
const Mesh &mesh = *trial_fes->GetMesh();
|
||||
// See LinearFormExtension::Update for explanation of f_to_be logic.
|
||||
std::unordered_map<int,int> f_to_be;
|
||||
@@ -574,8 +542,8 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
localY = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
AddMultWithMarkers(*integrators[i], localX, elem_markers[i],
|
||||
elem_attributes, false, localY);
|
||||
AddMultWithMarkers(*integrators[i], localX, elem_markers[i], elem_attributes,
|
||||
false, localY);
|
||||
}
|
||||
elem_restrict->MultTranspose(localY, y);
|
||||
}
|
||||
@@ -589,57 +557,15 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
const int iFISz = intFaceIntegrators.Size();
|
||||
if (int_face_restrict_lex && iFISz>0)
|
||||
{
|
||||
// When assembling interior face integrators for DG spaces, we need to
|
||||
// exchange the face-neighbor information. This happens inside member
|
||||
// functions of the 'int_face_restrict_lex'. To avoid repeated calls to
|
||||
// ParGridFunction::ExchangeFaceNbrData, if we have a parallel space
|
||||
// with interior face integrators, we create a ParGridFunction that
|
||||
// will be used to cache the face-neighbor data. x_dg should be passed
|
||||
// to any restriction operator that may need to use face-neighbor data.
|
||||
const Vector *x_dg = &x;
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParGridFunction x_pgf;
|
||||
if (auto *pfes = dynamic_cast<ParFiniteElementSpace*>(a->FESpace()))
|
||||
{
|
||||
x_pgf.MakeRef(pfes, const_cast<Vector&>(x), 0);
|
||||
x_dg = &x_pgf;
|
||||
}
|
||||
#endif
|
||||
|
||||
int_face_restrict_lex->Mult(*x_dg, int_face_X);
|
||||
if (int_face_dXdn.Size() > 0)
|
||||
{
|
||||
int_face_restrict_lex->NormalDerivativeMult(*x_dg, int_face_dXdn);
|
||||
}
|
||||
if (int_face_X.Size() > 0)
|
||||
int_face_restrict_lex->Mult(x, int_face_X);
|
||||
if (int_face_X.Size()>0)
|
||||
{
|
||||
int_face_Y = 0.0;
|
||||
|
||||
// if normal derivatives are needed by at least one integrator...
|
||||
if (int_face_dYdn.Size() > 0)
|
||||
{
|
||||
int_face_dYdn = 0.0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < iFISz; ++i)
|
||||
{
|
||||
if (intFaceIntegrators[i]->RequiresFaceNormalDerivatives())
|
||||
{
|
||||
intFaceIntegrators[i]->AddMultPAFaceNormalDerivatives(
|
||||
int_face_X, int_face_dXdn,
|
||||
int_face_Y, int_face_dYdn);
|
||||
}
|
||||
else
|
||||
{
|
||||
intFaceIntegrators[i]->AddMultPA(int_face_X, int_face_Y);
|
||||
}
|
||||
intFaceIntegrators[i]->AddMultPA(int_face_X, int_face_Y);
|
||||
}
|
||||
int_face_restrict_lex->AddMultTransposeInPlace(int_face_Y, y);
|
||||
if (int_face_dYdn.Size() > 0)
|
||||
{
|
||||
int_face_restrict_lex->NormalDerivativeAddMultTranspose(
|
||||
int_face_dYdn, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,19 +579,9 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
Array<Array<int>*> &bdr_markers = *a->GetBBFI_Marker();
|
||||
Array<Array<int>*> &bdr_face_markers = *a->GetBFBFI_Marker();
|
||||
bdr_face_restrict_lex->Mult(x, bdr_face_X);
|
||||
if (bdr_face_dXdn.Size() > 0)
|
||||
{
|
||||
bdr_face_restrict_lex->NormalDerivativeMult(x, bdr_face_dXdn);
|
||||
}
|
||||
if (bdr_face_X.Size() > 0)
|
||||
if (bdr_face_X.Size()>0)
|
||||
{
|
||||
bdr_face_Y = 0.0;
|
||||
|
||||
// if normal derivatives are needed by at least one integrator...
|
||||
if (bdr_face_dYdn.Size() > 0)
|
||||
{
|
||||
bdr_face_dYdn = 0.0;
|
||||
}
|
||||
for (int i = 0; i < n_bdr_integs; ++i)
|
||||
{
|
||||
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i], bdr_attributes,
|
||||
@@ -673,23 +589,10 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
}
|
||||
for (int i = 0; i < n_bdr_face_integs; ++i)
|
||||
{
|
||||
if (bdr_face_integs[i]->RequiresFaceNormalDerivatives())
|
||||
{
|
||||
AddMultNormalDerivativesWithMarkers(
|
||||
*bdr_face_integs[i], bdr_face_X, bdr_face_dXdn,
|
||||
bdr_face_markers[i], bdr_attributes, bdr_face_Y, bdr_face_dYdn);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X, bdr_face_markers[i],
|
||||
bdr_attributes, false, bdr_face_Y);
|
||||
}
|
||||
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X, bdr_face_markers[i],
|
||||
bdr_attributes, false, bdr_face_Y);
|
||||
}
|
||||
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
|
||||
if (bdr_face_dYdn.Size() > 0)
|
||||
{
|
||||
bdr_face_restrict_lex->NormalDerivativeAddMultTranspose(bdr_face_dYdn, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -790,37 +693,6 @@ static void AddWithMarkers_(
|
||||
});
|
||||
}
|
||||
|
||||
void PABilinearFormExtension::AddMultNormalDerivativesWithMarkers(
|
||||
const BilinearFormIntegrator &integ,
|
||||
const Vector &x,
|
||||
const Vector &dxdn,
|
||||
const Array<int> *markers,
|
||||
const Array<int> &attributes,
|
||||
Vector &y,
|
||||
Vector &dydn) const
|
||||
{
|
||||
if (markers)
|
||||
{
|
||||
tmp_evec.SetSize(y.Size() + dydn.Size());
|
||||
tmp_evec = 0.0;
|
||||
Vector tmp_y(tmp_evec, 0, y.Size());
|
||||
Vector tmp_dydn(tmp_evec, y.Size(), dydn.Size());
|
||||
|
||||
integ.AddMultPAFaceNormalDerivatives(x, dxdn, tmp_y, tmp_dydn);
|
||||
|
||||
const int ne = attributes.Size();
|
||||
const int nd_1 = x.Size() / ne;
|
||||
const int nd_2 = dxdn.Size() / ne;
|
||||
|
||||
AddWithMarkers_(ne, nd_1, tmp_y, *markers, attributes, y);
|
||||
AddWithMarkers_(ne, nd_2, tmp_dydn, *markers, attributes, dydn);
|
||||
}
|
||||
else
|
||||
{
|
||||
integ.AddMultPAFaceNormalDerivatives(x, dxdn, y, dydn);
|
||||
}
|
||||
}
|
||||
|
||||
void PABilinearFormExtension::AddMultWithMarkers(
|
||||
const BilinearFormIntegrator &integ,
|
||||
const Vector &x,
|
||||
|
||||
@@ -74,8 +74,6 @@ protected:
|
||||
mutable Vector localX, localY;
|
||||
mutable Vector int_face_X, int_face_Y;
|
||||
mutable Vector bdr_face_X, bdr_face_Y;
|
||||
mutable Vector int_face_dXdn, int_face_dYdn;
|
||||
mutable Vector bdr_face_dXdn, bdr_face_dYdn;
|
||||
const Operator *elem_restrict; // Not owned
|
||||
const FaceRestriction *int_face_restrict_lex; // Not owned
|
||||
const FaceRestriction *bdr_face_restrict_lex; // Not owned
|
||||
@@ -115,23 +113,6 @@ protected:
|
||||
const Array<int> &attributes,
|
||||
const bool transpose,
|
||||
Vector &y) const;
|
||||
|
||||
/// @brief Performs the same function as AddMultWithMarkers, but takes as
|
||||
/// input and output face normal derivatives.
|
||||
///
|
||||
/// This is required when the integrator requires face normal derivatives,
|
||||
/// for example, DGDiffusionIntegrator.
|
||||
///
|
||||
/// This is called when the integrator's member function
|
||||
/// BilinearFormIntegrator::RequiresFaceNormalDerivatives() returns true.
|
||||
void AddMultNormalDerivativesWithMarkers(
|
||||
const BilinearFormIntegrator &integ,
|
||||
const Vector &x,
|
||||
const Vector &dxdn,
|
||||
const Array<int> *markers,
|
||||
const Array<int> &attributes,
|
||||
Vector &y,
|
||||
Vector &dydn) const;
|
||||
};
|
||||
|
||||
/// Data and methods for element-assembled bilinear forms
|
||||
|
||||
+14
-140
@@ -189,12 +189,6 @@ void BilinearFormIntegrator::AssembleTraceFaceMatrix (int elem,
|
||||
" Integrator class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AddMultPAFaceNormalDerivatives(
|
||||
const Vector &x, const Vector &dxdn, Vector &y, Vector &dydn) const
|
||||
{
|
||||
MFEM_ABORT("Not implemented.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AssembleElementVector(
|
||||
const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun,
|
||||
Vector &elvect)
|
||||
@@ -1999,11 +1993,7 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
dim = el.GetDim();
|
||||
// in main
|
||||
// int dimc = el.GetCurlDim();
|
||||
// Taken from 4d_dev:
|
||||
int dimc = (dim == 3) ? 3 : 1;
|
||||
if (dim==4) { dimc = 6; }
|
||||
int dimc = el.GetCurlDim();
|
||||
real_t w;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
@@ -2040,43 +2030,8 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
|
||||
Trans.SetIntPoint (&ip);
|
||||
|
||||
if (dim ==4)
|
||||
{
|
||||
DenseMatrix tSh(4,4);
|
||||
DenseMatrix trShTemp(4,4);
|
||||
|
||||
DenseMatrix J = Trans.Jacobian();
|
||||
DenseMatrix invJ(4,4); CalcInverse(J, invJ);
|
||||
DenseMatrix invJtr(invJ); invJtr.Transpose();
|
||||
|
||||
el.CalcCurlShape(ip, curlshape);
|
||||
for (int dof=0; dof<nd; dof++)
|
||||
{
|
||||
tSh = 0.; trShTemp = 0.;
|
||||
tSh(0,1) = curlshape(dof,0); tSh(0,2) = curlshape(dof,1);
|
||||
tSh(0,3) = curlshape(dof,2);
|
||||
tSh(1,0) = -curlshape(dof,0);
|
||||
tSh(1,2) = curlshape(dof,3); tSh(1,3) = curlshape(dof,4);
|
||||
tSh(2,0) = -curlshape(dof,1); tSh(2,1) = -curlshape(dof,3);
|
||||
tSh(2,3) = curlshape(dof,5);
|
||||
tSh(3,0) = -curlshape(dof,2); tSh(3,1) = -curlshape(dof,4);
|
||||
tSh(3,2) = -curlshape(dof,5);
|
||||
|
||||
Mult(tSh, invJ, trShTemp);
|
||||
Mult(invJtr, trShTemp, tSh);
|
||||
|
||||
curlshape_dFt(dof,0) = tSh(0,1);
|
||||
curlshape_dFt(dof,1) = tSh(0,2);
|
||||
curlshape_dFt(dof,2) = tSh(0,3);
|
||||
curlshape_dFt(dof,3) = tSh(1,2);
|
||||
curlshape_dFt(dof,4) = tSh(1,3);
|
||||
curlshape_dFt(dof,5) = tSh(2,3);
|
||||
}
|
||||
}
|
||||
else
|
||||
el.CalcPhysCurlShape(Trans, curlshape_dFt);
|
||||
|
||||
w = ip.weight * Trans.Weight();
|
||||
el.CalcPhysCurlShape(Trans, curlshape_dFt);
|
||||
|
||||
if (MQ)
|
||||
{
|
||||
@@ -3454,7 +3409,6 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
|
||||
}
|
||||
}
|
||||
}
|
||||
// elmat.PrintMatlab(std::cout);
|
||||
}
|
||||
|
||||
|
||||
@@ -3469,7 +3423,7 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
|
||||
const FiniteElement &el1, const FiniteElement &el2,
|
||||
FaceElementTransformations &Trans, DenseMatrix &elmat)
|
||||
{
|
||||
int ndof1, ndof2, ndofs;
|
||||
int dim, ndof1, ndof2, ndofs;
|
||||
bool kappa_is_nonzero = (kappa != 0.);
|
||||
real_t w, wq = 0.0;
|
||||
|
||||
@@ -3512,9 +3466,17 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
const int order = (ndof2) ? max(el1.GetOrder(),
|
||||
el2.GetOrder()) : el1.GetOrder();
|
||||
ir = &GetRule(order, Trans);
|
||||
// a simple choice for the integration order; is this OK?
|
||||
int order;
|
||||
if (ndof2)
|
||||
{
|
||||
order = 2*max(el1.GetOrder(), el2.GetOrder());
|
||||
}
|
||||
else
|
||||
{
|
||||
order = 2*el1.GetOrder();
|
||||
}
|
||||
ir = &IntRules.Get(Trans.GetGeometryType(), order);
|
||||
}
|
||||
|
||||
// assemble: < {(Q \nabla u).n},[v] > --> elmat
|
||||
@@ -3692,13 +3654,6 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
|
||||
}
|
||||
}
|
||||
|
||||
const IntegrationRule &DGDiffusionIntegrator::GetRule(
|
||||
int order, FaceElementTransformations &T)
|
||||
{
|
||||
// order is typically the maximum of the order of the left and right elements
|
||||
// neighboring the given face.
|
||||
return IntRules.Get(T.GetGeometryType(), 2*order);
|
||||
}
|
||||
|
||||
// static method
|
||||
void DGElasticityIntegrator::AssembleBlock(
|
||||
@@ -4595,85 +4550,4 @@ VectorInnerProductInterpolator::AssembleElementMatrix2(
|
||||
ran_fe.Project(dom_shape_coeff, Trans, elmat_as_vec);
|
||||
}
|
||||
|
||||
void HeatEquationIntegrator::AssembleElementMatrix
|
||||
( const FiniteElement &el, ElementTransformation &Trans,
|
||||
DenseMatrix &elmat )
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
int spaceDim = Trans.GetSpaceDim();
|
||||
double w;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix dshape(nd,dim), dshapedxt(nd,spaceDim), invdfdx(dim,spaceDim);
|
||||
Vector shape(nd), vec(nd);
|
||||
#else
|
||||
dshape.SetSize(nd,dim);
|
||||
dshapedxt.SetSize(nd,spaceDim);
|
||||
invdfdx.SetSize(dim,spaceDim);
|
||||
shape.SetSize(nd);
|
||||
dtshape.SetSize(nd);
|
||||
#endif
|
||||
elmat.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order;
|
||||
if (el.Space() == FunctionSpace::Pk)
|
||||
{
|
||||
order = 2*el.GetOrder() - 2;
|
||||
}
|
||||
else
|
||||
// order = 2*el.GetOrder() - 2; // <-- this seems to work fine too
|
||||
{
|
||||
order = 2*el.GetOrder() + dim - 1;
|
||||
}
|
||||
|
||||
if (el.Space() == FunctionSpace::rQk)
|
||||
{
|
||||
ir = &RefinedIntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &IntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
el.CalcShape(ip,shape);
|
||||
el.CalcDShape(ip, dshape);
|
||||
|
||||
Trans.SetIntPoint(&ip);
|
||||
w = Trans.Weight();
|
||||
w *= ip.weight;
|
||||
CalcInverse(Trans.Jacobian(), invdfdx);
|
||||
Mult(dshape, invdfdx, dshapedxt);
|
||||
|
||||
dshapedxt.GetColumn(spaceDim - 1, dtshape); // d_t u
|
||||
dshapedxt.SetCol(spaceDim - 1, 0.);
|
||||
|
||||
AddMult_a_VWt(w,shape,dtshape,elmat); // d_t u * v
|
||||
if (!MQ)
|
||||
{
|
||||
if (Q)
|
||||
{
|
||||
w *= Q->Eval(Trans, ip);
|
||||
}
|
||||
AddMult_a_AAt(w, dshapedxt, elmat);
|
||||
}
|
||||
else
|
||||
{
|
||||
MQ->Eval(invdfdx, Trans, ip);
|
||||
invdfdx *= w;
|
||||
Mult(dshapedxt, invdfdx, dshape);
|
||||
AddMultABt(dshape, dshapedxt, elmat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+4
-246
@@ -266,41 +266,6 @@ public:
|
||||
Vector &flux, Vector *d_energy = NULL)
|
||||
{ return 0.0; }
|
||||
|
||||
// I think this got deleted
|
||||
// void SetIntRule(const IntegrationRule *ir) { IntRule = ir; }
|
||||
|
||||
/** @brief For bilinear forms on element faces, specifies if the normal
|
||||
derivatives are needed on the faces or just the face restriction.
|
||||
|
||||
@details if RequiresFaceNormalDerivatives() == true, then
|
||||
AddMultPAFaceNormalDerivatives(...) should be invoked in place
|
||||
of AddMultPA(...) and L2NormalDerivativeFaceRestriction should
|
||||
be used to compute the normal derivatives. This is used for some
|
||||
DG integrators, for example DGDiffusionIntegrator.
|
||||
|
||||
@returns whether normal derivatives appear in the bilinear form.
|
||||
*/
|
||||
virtual bool RequiresFaceNormalDerivatives() const { return false; }
|
||||
|
||||
/// Method for partially assembled action.
|
||||
/** @brief For bilinear forms on element faces that depend on the normal
|
||||
derivative on the faces, computes the action of integrator to the
|
||||
face values @a x and reference-normal derivatives @a dxdn and adds
|
||||
the result to @a y and @a dydn.
|
||||
|
||||
@details This method can be called only after the method AssemblePA() has
|
||||
been called.
|
||||
|
||||
@param[in] x E-vector of face values (provided by
|
||||
FaceRestriction::Mult)
|
||||
@param[in] dxdn E-vector of face reference-normal derivatives
|
||||
(provided by FaceRestriction::NormalDerivativeMult)
|
||||
@param[in,out] y E-vector of face values to add action to.
|
||||
@param[in,out] dydn E-vector of face reference-normal derivative values to
|
||||
add action to.
|
||||
*/
|
||||
virtual void AddMultPAFaceNormalDerivatives(const Vector &x, const Vector &dxdn,
|
||||
Vector &y, Vector &dydn) const;
|
||||
virtual ~BilinearFormIntegrator() { }
|
||||
};
|
||||
|
||||
@@ -3264,13 +3229,6 @@ protected:
|
||||
Vector shape1, shape2, dshape1dn, dshape2dn, nor, nh, ni;
|
||||
DenseMatrix jmat, dshape1, dshape2, mq, adjJ;
|
||||
|
||||
|
||||
// PA extension
|
||||
Vector pa_data; // (Q, h, dot(n,J)|el0, dot(n,J)|el1)
|
||||
const DofToQuad *maps; ///< Not owned
|
||||
int dim, nf, nq, dofs1D, quad1D;
|
||||
IntegrationRules irs{0, Quadrature1D::GaussLobatto};
|
||||
|
||||
public:
|
||||
DGDiffusionIntegrator(const real_t s, const real_t k)
|
||||
: Q(NULL), MQ(NULL), sigma(s), kappa(k) { }
|
||||
@@ -3279,26 +3237,10 @@ public:
|
||||
DGDiffusionIntegrator(MatrixCoefficient &q, const real_t s, const real_t k)
|
||||
: Q(NULL), MQ(&q), sigma(s), kappa(k) { }
|
||||
using BilinearFormIntegrator::AssembleFaceMatrix;
|
||||
void AssembleFaceMatrix(const FiniteElement &el1,
|
||||
const FiniteElement &el2,
|
||||
FaceElementTransformations &Trans,
|
||||
DenseMatrix &elmat) override;
|
||||
|
||||
bool RequiresFaceNormalDerivatives() const override { return true; }
|
||||
|
||||
using BilinearFormIntegrator::AssemblePA;
|
||||
|
||||
void AssemblePAInteriorFaces(const FiniteElementSpace &fes) override;
|
||||
|
||||
void AssemblePABoundaryFaces(const FiniteElementSpace &fes) override;
|
||||
|
||||
void AddMultPAFaceNormalDerivatives(const Vector &x, const Vector &dxdn,
|
||||
Vector &y, Vector &dydn) const override;
|
||||
|
||||
const IntegrationRule &GetRule(int order, FaceElementTransformations &T);
|
||||
|
||||
private:
|
||||
void SetupPA(const FiniteElementSpace &fes, FaceType type);
|
||||
virtual void AssembleFaceMatrix(const FiniteElement &el1,
|
||||
const FiniteElement &el2,
|
||||
FaceElementTransformations &Trans,
|
||||
DenseMatrix &elmat);
|
||||
};
|
||||
|
||||
/** Integrator for the "BR2" diffusion stabilization term
|
||||
@@ -3682,16 +3624,6 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class DivSkewInterpolator : public DiscreteInterpolator
|
||||
{
|
||||
public:
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
||||
const FiniteElement &ran_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{ ran_fe.ProjectDivSkew(dom_fe, Trans, elmat); }
|
||||
};
|
||||
|
||||
/** Class for constructing the (local) discrete divergence matrix which can
|
||||
be used as an integrator in a DiscreteLinearOperator object to assemble
|
||||
the global discrete divergence matrix.
|
||||
@@ -3823,179 +3755,5 @@ protected:
|
||||
VectorCoefficient *VQ;
|
||||
};
|
||||
|
||||
class DivSkewDivSkewIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
DenseMatrix DivSkewshape, DivSkew_dFt;
|
||||
|
||||
Coefficient *Q;
|
||||
|
||||
public:
|
||||
DivSkewDivSkewIntegrator() { Q = NULL; }
|
||||
/// Construct a bilinear form integrator for Nedelec elements
|
||||
DivSkewDivSkewIntegrator(Coefficient &q) : Q(&q) { }
|
||||
|
||||
/* Given a particular Finite Element, compute the
|
||||
element DivSkew-DivSkew matrix elmat */
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
real_t w;
|
||||
|
||||
DivSkewshape.SetSize(nd,dim);
|
||||
DivSkew_dFt.SetSize(nd,dim);
|
||||
|
||||
elmat.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = 2*el.GetOrder()+2;
|
||||
|
||||
ir = &IntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
Trans.SetIntPoint (&ip);
|
||||
|
||||
el.CalcDivSkewShape(ip, DivSkewshape);
|
||||
|
||||
MultABt(DivSkewshape, Trans.Jacobian(), DivSkew_dFt);
|
||||
|
||||
DivSkew_dFt *= (1.0 / Trans.Weight());
|
||||
|
||||
w = ip.weight * fabs(Trans.Weight());
|
||||
|
||||
if (Q)
|
||||
{
|
||||
w *= Q->Eval(Trans, ip);
|
||||
}
|
||||
|
||||
AddMult_a_AAt(w, DivSkew_dFt, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class VectorFE_DivSkewMassIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
DenseMatrix shape;
|
||||
|
||||
Coefficient *Q;
|
||||
|
||||
public:
|
||||
VectorFE_DivSkewMassIntegrator() { Q = NULL; }
|
||||
/// Construct a bilinear form integrator for Nedelec elements
|
||||
VectorFE_DivSkewMassIntegrator(Coefficient &q) : Q(&q) { }
|
||||
|
||||
/* Given a particular Finite Element, compute the
|
||||
element curl-curl matrix elmat */
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
real_t w;
|
||||
|
||||
shape.SetSize(nd,dim*dim);
|
||||
|
||||
elmat.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = Trans.OrderW() + 2 * el.GetOrder();
|
||||
|
||||
ir = &IntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint (&ip);
|
||||
|
||||
w = ip.weight * fabs(Trans.Weight());
|
||||
|
||||
|
||||
el.CalcVShape(Trans, shape);
|
||||
|
||||
|
||||
if (Q)
|
||||
{
|
||||
w *= Q->Eval(Trans, ip);
|
||||
}
|
||||
|
||||
AddMult_a_AAt(w, shape, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** Class for integrating the bilinear form a(u,v) := (d_t u, v) + (Q grad_x u, grad_x v) where Q
|
||||
can be a scalar or a matrix coefficient and grad_x is the gradient wrt to the spatial variables.
|
||||
Here we use the space-time f.e. scheme by [Steinbach2015]. */
|
||||
class HeatEquationIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
Vector vec, pointflux, shape, dtshape;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
DenseMatrix dshape, dshapedxt, invdfdx, mq;
|
||||
DenseMatrix te_dshape, te_dshapedxt;
|
||||
#endif
|
||||
Coefficient *Q;
|
||||
MatrixCoefficient *MQ;
|
||||
|
||||
public:
|
||||
/// Construct a diffusion integrator with coefficient Q = 1
|
||||
HeatEquationIntegrator() { Q = NULL; MQ = NULL; }
|
||||
|
||||
/// Construct a diffusion integrator with a scalar coefficient q
|
||||
HeatEquationIntegrator (Coefficient &q) : Q(&q) { MQ = NULL; }
|
||||
|
||||
/// Construct a diffusion integrator with a matrix coefficient q
|
||||
HeatEquationIntegrator (MatrixCoefficient &q) : MQ(&q) { Q = NULL; }
|
||||
|
||||
/** Given a particular Finite Element
|
||||
computes the element stiffness matrix elmat. */
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
/** Given a trial and test Finite Element computes the element stiffness
|
||||
matrix elmat. */
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{ mfem_error("HeatEquationIntegrator::AssembleElementMatrix2: not implemented!"); }
|
||||
|
||||
/// Perform the local action of the BilinearFormIntegrator
|
||||
virtual void AssembleElementVector(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
const Vector &elfun, Vector &elvect)
|
||||
{ mfem_error("HeatEquationIntegrator::AssembleElementVector: not implemented!"); }
|
||||
|
||||
virtual void ComputeElementFlux(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
Vector &u, const FiniteElement &fluxelem,
|
||||
Vector &flux, int with_coef = 1)
|
||||
{ mfem_error("HeatEquationIntegrator::ComputeElementFlux: not implemented!"); }
|
||||
|
||||
virtual double ComputeFluxEnergy(const FiniteElement &fluxelem,
|
||||
ElementTransformation &Trans,
|
||||
Vector &flux, Vector *d_energy = NULL)
|
||||
{ mfem_error("HeatEquationIntegrator::ComputeFluxEnergy: not implemented!"); return -1;}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
+12
-13
@@ -129,10 +129,8 @@ real_t PWCoefficient::Eval(ElementTransformation &T,
|
||||
real_t FunctionCoefficient::Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
// real_t x[Geometry::MaxDim];
|
||||
// Vector transip(x, Geometry::MaxDim);
|
||||
real_t x[4];
|
||||
Vector transip(x, 4);
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
@@ -368,10 +366,8 @@ void PositionVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
void VectorFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
// real_t x[Geometry::MaxDim];
|
||||
// Vector transip(x, Geometry::MaxDim);
|
||||
real_t x[4];
|
||||
Vector transip(x, 4);
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
@@ -811,7 +807,6 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
|
||||
|
||||
QuadratureSpaceBase &qspace = *qf.GetSpace();
|
||||
const int ne = qspace.GetNE();
|
||||
qf.HostWrite();
|
||||
DenseMatrix values;
|
||||
DenseSymmetricMatrix matrix;
|
||||
for (int iel = 0; iel < ne; ++iel)
|
||||
@@ -823,7 +818,7 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
|
||||
{
|
||||
const IntegrationPoint &ip = ir[iq];
|
||||
T.SetIntPoint(&ip);
|
||||
matrix.UseExternalData(&values(0, iq), height);
|
||||
matrix.UseExternalData(&values(0, iq), vdim);
|
||||
Eval(matrix, T, ip);
|
||||
}
|
||||
}
|
||||
@@ -833,12 +828,13 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
|
||||
void SymmetricMatrixCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
Eval(mat_aux, T, ip);
|
||||
mat.SetSize(height);
|
||||
Eval(mat, T, ip);
|
||||
for (int j = 0; j < width; ++j)
|
||||
{
|
||||
for (int i = 0; i < height; ++ i)
|
||||
{
|
||||
K(i, j) = mat_aux(i, j);
|
||||
K(i, j) = mat(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -993,7 +989,10 @@ void MatrixArrayVectorCoefficient::Eval(DenseMatrix &K,
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
this->Eval(i, V, T, ip);
|
||||
K.SetRow(i, V);
|
||||
for (int j = 0; j < width; j++)
|
||||
{
|
||||
K(i,j) = V(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-13
@@ -1352,17 +1352,17 @@ public:
|
||||
/// Set the time for internally stored coefficients
|
||||
void SetTime(real_t t) override;
|
||||
|
||||
/// Get the vector coefficient located at the i-th row of the matrix
|
||||
/// Get the coefficient located at the iᵗʰ row of the matrix.
|
||||
VectorCoefficient* GetCoeff (int i) { return Coeff[i]; }
|
||||
|
||||
/** @brief Set the coefficient located at the i-th row of the matrix.
|
||||
/** @brief Set the coefficient located at the iᵗʰ row of the matrix.
|
||||
By this will take ownership of the Coefficient passed in, but this
|
||||
can be overridden with the @a own parameter. */
|
||||
void Set(int i, VectorCoefficient * c, bool own=true);
|
||||
|
||||
using MatrixCoefficient::Eval;
|
||||
|
||||
/// Evaluate coefficient located at the i-th row of the matrix using integration
|
||||
/// Evaluate coefficient located at the iᵗʰ row of the matrix using integration
|
||||
/// point @a ip.
|
||||
void Eval(int i, Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
@@ -1466,13 +1466,12 @@ public:
|
||||
class SymmetricMatrixCoefficient : public MatrixCoefficient
|
||||
{
|
||||
protected:
|
||||
|
||||
/// Internal matrix used when evaluating this coefficient as a DenseMatrix.
|
||||
mutable DenseSymmetricMatrix mat_aux;
|
||||
DenseSymmetricMatrix mat;
|
||||
public:
|
||||
/// Construct a dim x dim matrix coefficient.
|
||||
explicit SymmetricMatrixCoefficient(int dimension)
|
||||
: MatrixCoefficient(dimension, true), mat_aux(height) { }
|
||||
: MatrixCoefficient(dimension, true) { }
|
||||
|
||||
/// Get the size of the matrix.
|
||||
int GetSize() const { return height; }
|
||||
@@ -1505,9 +1504,8 @@ public:
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
|
||||
/// @deprecated Return a reference to the internal matrix used when evaluating this coefficient as a DenseMatrix.
|
||||
MFEM_DEPRECATED const DenseSymmetricMatrix& GetMatrix() { return mat_aux; }
|
||||
/// Return a reference to the constant matrix.
|
||||
const DenseSymmetricMatrix& GetMatrix() { return mat; }
|
||||
|
||||
virtual ~SymmetricMatrixCoefficient() { }
|
||||
};
|
||||
@@ -1527,10 +1525,6 @@ public:
|
||||
/// Evaluate the matrix coefficient at @a ip.
|
||||
virtual void Eval(DenseSymmetricMatrix &M, ElementTransformation &T,
|
||||
const IntegrationPoint &ip) { M = mat; }
|
||||
|
||||
/// Return a reference to the constant matrix.
|
||||
const DenseSymmetricMatrix& GetMatrix() { return mat; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
+12
-3
@@ -1243,16 +1243,25 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
HypreParMatrix * Ah;
|
||||
A_i.Get(Ah);
|
||||
hypre_ParCSRMatrix *Aih = *Ah;
|
||||
#if !defined(HYPRE_USING_GPU)
|
||||
ess_tdof_list.HostRead();
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
const int j = ess_tdof_list[k];
|
||||
Aih->diag->data[Aih->diag->i[j]] = 0.0;
|
||||
}
|
||||
#else
|
||||
Ah->HypreReadWrite();
|
||||
const int *d_ess_tdof_list =
|
||||
ess_tdof_list.GetMemory().Read(GetHypreMemoryClass(), n);
|
||||
HYPRE_Int *d_diag_i = Aih->diag->i;
|
||||
ess_tdof_list.GetMemory().Read(MemoryClass::DEVICE, n);
|
||||
const int *d_diag_i = Aih->diag->i;
|
||||
real_t *d_diag_data = Aih->diag->data;
|
||||
mfem::hypre_forall(n, [=] MFEM_HOST_DEVICE (int k)
|
||||
MFEM_GPU_FORALL(k, n,
|
||||
{
|
||||
const int j = d_ess_tdof_list[k];
|
||||
d_diag_data[d_diag_i[j]] = 0.0;
|
||||
});
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+1
-11
@@ -1,18 +1,8 @@
|
||||
// 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.
|
||||
|
||||
#include "convergence.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
|
||||
+2
-2
@@ -101,7 +101,7 @@ void DGMassInverse::SetRelTol(const real_t rel_tol_) { rel_tol = rel_tol_; }
|
||||
|
||||
void DGMassInverse::SetAbsTol(const real_t abs_tol_) { abs_tol = abs_tol_; }
|
||||
|
||||
void DGMassInverse::SetMaxIter(const int max_iter_) { max_iter = max_iter_; }
|
||||
void DGMassInverse::SetMaxIter(const real_t max_iter_) { max_iter = max_iter_; }
|
||||
|
||||
void DGMassInverse::Update()
|
||||
{
|
||||
@@ -137,7 +137,7 @@ void DGMassInverse::DGMassCGIteration(const Vector &b_, Vector &u_) const
|
||||
|
||||
const real_t RELTOL = rel_tol;
|
||||
const real_t ABSTOL = abs_tol;
|
||||
const int MAXIT = max_iter;
|
||||
const real_t MAXIT = max_iter;
|
||||
const bool IT_MODE = iterative_mode;
|
||||
const bool CHANGE_BASIS = (d2q != nullptr);
|
||||
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ public:
|
||||
/// Set the absolute tolerance.
|
||||
void SetAbsTol(const real_t abs_tol_);
|
||||
/// Set the maximum number of iterations.
|
||||
void SetMaxIter(const int max_iter_);
|
||||
void SetMaxIter(const real_t max_iter_);
|
||||
/// Recompute operator and preconditioner (when coefficient or mesh changes).
|
||||
void Update();
|
||||
|
||||
|
||||
+2
-6
@@ -180,7 +180,7 @@ int InverseElementTransformation::NewtonSolve(const Vector &pt,
|
||||
const int dim = T->GetDimension();
|
||||
const int sdim = T->GetSpaceDim();
|
||||
IntegrationPoint xip, prev_xip;
|
||||
double xd[4], yd[4], dxd[4], dx_norm = -1.0, err_phys, real_dx_norm = -1.0;
|
||||
real_t xd[3], yd[3], dxd[3], dx_norm = -1.0, err_phys, real_dx_norm = -1.0;
|
||||
Vector x(xd, dim), y(yd, sdim), dx(dxd, dim);
|
||||
bool hit_bdr = false, prev_hit_bdr = false;
|
||||
|
||||
@@ -389,8 +389,6 @@ void IsoparametricTransformation::SetIdentityTransformation(
|
||||
case Geometry::CUBE : FElem = &HexahedronFE; break;
|
||||
case Geometry::PRISM : FElem = &WedgeFE; break;
|
||||
case Geometry::PYRAMID : FElem = &PyramidFE; break;
|
||||
case Geometry::PENTATOPE: FElem = &PentatopeFE; break;
|
||||
case Geometry::TESSERACT: FElem = &TesseractFE; break;
|
||||
default:
|
||||
MFEM_ABORT("unknown Geometry::Type!");
|
||||
}
|
||||
@@ -545,9 +543,7 @@ void IsoparametricTransformation::Transform (const DenseMatrix &matrix,
|
||||
void IntegrationPointTransformation::Transform (const IntegrationPoint &ip1,
|
||||
IntegrationPoint &ip2)
|
||||
{
|
||||
// real_t vec[Geometry::MaxDim];
|
||||
real_t vec[4];
|
||||
|
||||
real_t vec[3];
|
||||
Vector v (vec, Transf.GetPointMat().Height());
|
||||
|
||||
Transf.Transform (ip1, v);
|
||||
|
||||
@@ -43,10 +43,6 @@ LinearWedgeFiniteElement WedgeFE;
|
||||
// Defined here to ensure it is constructed before 'Geometries'.
|
||||
LinearPyramidFiniteElement PyramidFE;
|
||||
|
||||
// Object declared in mesh/pentatope.hpp.
|
||||
// Defined here to ensure it is constructed before 'Geometries'.
|
||||
Linear4DFiniteElement PentatopeFE;
|
||||
|
||||
// Object declared in geom.hpp.
|
||||
// Construct 'Geometries' after 'TriangleFE', 'TetrahedronFE', 'WedgeFE', and
|
||||
// PyramidFE.
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#define MFEM_FACE_MAP_UTILS_HPP
|
||||
|
||||
#include "../../general/array.hpp"
|
||||
#include "../../general/backends.hpp"
|
||||
#include <utility> // std::pair
|
||||
#include <vector>
|
||||
|
||||
@@ -52,189 +51,6 @@ void FillFaceMap(const int n_face_dofs_per_component,
|
||||
void GetTensorFaceMap(const int dim, const int order, const int face_id,
|
||||
Array<int> &face_map);
|
||||
|
||||
/// @brief Given a face DOF index in native (counter-clockwise) ordering, return
|
||||
/// the corresponding DOF index in lexicographic ordering (for a quadrilateral
|
||||
/// element).
|
||||
MFEM_HOST_DEVICE
|
||||
inline int ToLexOrdering2D(const int face_id, const int size1d, const int i)
|
||||
{
|
||||
if (face_id==2 || face_id==3)
|
||||
{
|
||||
return size1d-1-i;
|
||||
}
|
||||
else
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Given a face DOF index on a shared face, ordered lexicographically
|
||||
/// relative to element 1, return the corresponding face DOF index ordered
|
||||
/// lexicographically relative to element 2.
|
||||
MFEM_HOST_DEVICE
|
||||
inline int PermuteFace2D(const int face_id1, const int face_id2,
|
||||
const int orientation, const int size1d,
|
||||
const int index)
|
||||
{
|
||||
int new_index;
|
||||
// Convert from element 1 lex ordering to native ordering
|
||||
if (face_id1 == 2 || face_id1 == 3)
|
||||
{
|
||||
new_index = size1d-1-index;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_index = index;
|
||||
}
|
||||
// Permute based on face orientations
|
||||
if (orientation == 1)
|
||||
{
|
||||
new_index = size1d-1-new_index;
|
||||
}
|
||||
// Covert to element 2 lex ordering
|
||||
return ToLexOrdering2D(face_id2, size1d, new_index);
|
||||
}
|
||||
|
||||
/// @brief Given a face DOF index in native (counter-clockwise) ordering, return
|
||||
/// the corresponding DOF index in lexicographic ordering (for a hexahedral
|
||||
/// element).
|
||||
MFEM_HOST_DEVICE
|
||||
inline int ToLexOrdering3D(const int face_id, const int size1d, const int i,
|
||||
const int j)
|
||||
{
|
||||
if (face_id==2 || face_id==1 || face_id==5)
|
||||
{
|
||||
return i + j*size1d;
|
||||
}
|
||||
else if (face_id==3 || face_id==4)
|
||||
{
|
||||
return (size1d-1-i) + j*size1d;
|
||||
}
|
||||
else // face_id==0
|
||||
{
|
||||
return i + (size1d-1-j)*size1d;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Given the index of a face DOF in lexicographic ordering relative
|
||||
/// element 1, permute the index so that it is lexicographically ordered
|
||||
/// relative to element 2.
|
||||
///
|
||||
/// The given face corresponds to local face index @a face_id1 relative to
|
||||
/// element 1, and @a face_id2 (with @a orientation) relative to element 2.
|
||||
MFEM_HOST_DEVICE
|
||||
inline int PermuteFace3D(const int face_id1, const int face_id2,
|
||||
const int orientation,
|
||||
const int size1d, const int index)
|
||||
{
|
||||
int i=0, j=0, new_i=0, new_j=0;
|
||||
i = index%size1d;
|
||||
j = index/size1d;
|
||||
// Convert from lex ordering
|
||||
if (face_id1==3 || face_id1==4)
|
||||
{
|
||||
i = size1d-1-i;
|
||||
}
|
||||
else if (face_id1==0)
|
||||
{
|
||||
j = size1d-1-j;
|
||||
}
|
||||
// Permute based on face orientations
|
||||
switch (orientation)
|
||||
{
|
||||
case 0:
|
||||
new_i = i;
|
||||
new_j = j;
|
||||
break;
|
||||
case 1:
|
||||
new_i = j;
|
||||
new_j = i;
|
||||
break;
|
||||
case 2:
|
||||
new_i = j;
|
||||
new_j = (size1d-1-i);
|
||||
break;
|
||||
case 3:
|
||||
new_i = (size1d-1-i);
|
||||
new_j = j;
|
||||
break;
|
||||
case 4:
|
||||
new_i = (size1d-1-i);
|
||||
new_j = (size1d-1-j);
|
||||
break;
|
||||
case 5:
|
||||
new_i = (size1d-1-j);
|
||||
new_j = (size1d-1-i);
|
||||
break;
|
||||
case 6:
|
||||
new_i = (size1d-1-j);
|
||||
new_j = i;
|
||||
break;
|
||||
case 7:
|
||||
new_i = i;
|
||||
new_j = (size1d-1-j);
|
||||
break;
|
||||
}
|
||||
return ToLexOrdering3D(face_id2, size1d, new_i, new_j);
|
||||
}
|
||||
|
||||
/// @brief Given a face DOF (or quadrature) index ordered lexicographically
|
||||
/// relative to element 1, return the associated (i, j) coordinates.
|
||||
///
|
||||
/// The returned coordinates will be relative to element 1 or element 2
|
||||
/// according to the value of side (side == 0 corresponds element 1).
|
||||
MFEM_HOST_DEVICE
|
||||
inline void FaceIdxToVolIdx2D(const int qi, const int nq, const int face_id0,
|
||||
const int face_id1, const int side, int &i, int &j)
|
||||
{
|
||||
// Note: in 2D, a consistently ordered mesh will always have the element 2
|
||||
// face reversed relative to element 1, so orientation is determined entirely
|
||||
// by side. (In 3D, separate orientation information is needed).
|
||||
const int orientation = side;
|
||||
|
||||
const int face_id = (side == 0) ? face_id0 : face_id1;
|
||||
const int edge_idx = (side == 0) ? qi : PermuteFace2D(face_id0, face_id1,
|
||||
orientation, nq, qi);
|
||||
|
||||
const int level = (face_id == 0 || face_id == 3) ? 0 : (nq-1);
|
||||
const bool x_axis = (face_id == 0 || face_id == 2);
|
||||
|
||||
i = x_axis ? edge_idx : level;
|
||||
j = x_axis ? level : edge_idx;
|
||||
}
|
||||
|
||||
/// @brief Given a face DOF (or quadrature) index ordered lexicographically
|
||||
/// relative to element 1, return the associated (i, j, k) coordinates.
|
||||
///
|
||||
/// The returned coordinates will be relative to element 1 or element 2
|
||||
/// according to the value of side (side == 0 corresponds element 1).
|
||||
MFEM_HOST_DEVICE
|
||||
inline void FaceIdxToVolIdx3D(const int index, const int size1d,
|
||||
const int face_id0, const int face_id1,
|
||||
const int side, const int orientation,
|
||||
int& i, int& j, int& k)
|
||||
{
|
||||
MFEM_VERIFY_KERNEL(face_id1 >= 0 || side == 0,
|
||||
"Accessing second side but face_id1 is not valid.");
|
||||
|
||||
const int face_id = (side == 0) ? face_id0 : face_id1;
|
||||
const int fidx = (side == 0) ? index
|
||||
: PermuteFace3D(face_id0, face_id1, orientation, size1d, index);
|
||||
|
||||
const bool xy_plane = (face_id == 0 || face_id == 5);
|
||||
const bool yz_plane = (face_id == 2 || face_id == 4);
|
||||
|
||||
const int level = (face_id == 0 || face_id == 1 || face_id == 4)
|
||||
? 0 : (size1d-1);
|
||||
|
||||
const int _i = fidx % size1d;
|
||||
const int _j = fidx / size1d;
|
||||
|
||||
k = xy_plane ? level : _j;
|
||||
j = yz_plane ? _i : xy_plane ? _j : level;
|
||||
i = yz_plane ? level : _i;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -93,13 +93,6 @@ void FiniteElement::CalcPhysCurlShape(ElementTransformation &Trans,
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElement::CalcDivSkewShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const
|
||||
{
|
||||
mfem_error ("FiniteElement::CalcDivSkewShape (ip, ...)\n"
|
||||
" is not implemented for this class!");
|
||||
}
|
||||
|
||||
void FiniteElement::GetFaceDofs(int face, int **dofs, int *ndofs) const
|
||||
{
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
@@ -186,14 +179,6 @@ void FiniteElement::ProjectDiv(
|
||||
MFEM_ABORT("method is not implemented for this element");
|
||||
}
|
||||
|
||||
void FiniteElement::ProjectDivSkew(
|
||||
const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &DivSkew) const
|
||||
{
|
||||
mfem_error("FiniteElement::ProjectDivSkew(...) is not implemented for "
|
||||
"this element!");
|
||||
}
|
||||
|
||||
void FiniteElement::CalcPhysShape(ElementTransformation &Trans,
|
||||
Vector &shape) const
|
||||
{
|
||||
@@ -1027,19 +1012,9 @@ void VectorFiniteElement::SetDerivMembers()
|
||||
deriv_range_type = SCALAR;
|
||||
deriv_map_type = INTEGRAL;
|
||||
break;
|
||||
case H_DIV_SKEW:
|
||||
deriv_type = DIV_SKEW;
|
||||
deriv_range_type = VECTOR;
|
||||
deriv_map_type = H_DIV;
|
||||
break;
|
||||
case H_CURL:
|
||||
switch (dim)
|
||||
{
|
||||
case 4: // curl: 4D H_CURL -> 4D H_DIV(skew)
|
||||
deriv_type = CURL;
|
||||
deriv_range_type = MAT_SKEW;
|
||||
deriv_map_type = H_DIV_SKEW;
|
||||
break;
|
||||
case 3: // curl: 3D H_CURL -> 3D H_DIV
|
||||
deriv_type = CURL;
|
||||
deriv_range_type = VECTOR;
|
||||
@@ -1088,74 +1063,6 @@ void VectorFiniteElement::CalcVShape_ND(
|
||||
Mult(vshape, Trans.InverseJacobian(), shape);
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcVShape_DivSkew (
|
||||
ElementTransformation &Trans, DenseMatrix &shape) const
|
||||
{
|
||||
if (dim!=4) { return; }
|
||||
|
||||
MFEM_ASSERT(map_type == H_DIV_SKEW, "");
|
||||
const DenseMatrix &J = Trans.Jacobian();
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix vshape(dof, dim*dim);
|
||||
DenseMatrix Jinv(J.Width(), J.Height());
|
||||
#else
|
||||
Jinv.SetSize(J.Width(), J.Height());
|
||||
#endif
|
||||
|
||||
if (vshape.Width()!=dim*dim) { vshape.SetSize(dof,dim*dim); }
|
||||
|
||||
CalcVShape(Trans.GetIntPoint(), vshape);
|
||||
|
||||
CalcInverse(J, Jinv);
|
||||
DenseMatrix invJtr(Jinv); invJtr.Transpose();
|
||||
|
||||
CalcVShape(Trans.GetIntPoint(), vshape);
|
||||
|
||||
DenseMatrix mat(dim,dim); mat = 0.0;
|
||||
DenseMatrix tempMat(dim,dim);
|
||||
|
||||
for (int o=0; o<dof; o++)
|
||||
{
|
||||
// for(int ik=0; ik<dim; ik++)
|
||||
// for(int jk=0; jk<dim; jk++)
|
||||
// {
|
||||
// mat(ik,jk) = vshape(o,dim*ik+jk);
|
||||
// }
|
||||
//
|
||||
// Mult(mat, Jinv, tempMat);
|
||||
// Mult(invJtr, tempMat, mat);
|
||||
//
|
||||
// for(int ik=0; ik<dim; ik++)
|
||||
// for(int jk=0; jk<dim; jk++)
|
||||
// {
|
||||
// shape(o,dim*ik+jk) = mat(ik,jk);
|
||||
// }
|
||||
|
||||
|
||||
mat(0,0) = 0.0; mat(0,1) = vshape(o,11);
|
||||
mat(0,2) = vshape(o,13); mat(0,3) = vshape(o,6);
|
||||
mat(1,0) = vshape(o,14); mat(1,1) = 0.0;
|
||||
mat(1,2) = vshape(o,3); mat(1,3) = vshape(o,8);
|
||||
mat(2,0) = vshape(o,7); mat(2,1) = vshape(o,12); mat(2,2) = 0.0;
|
||||
mat(2,3) = vshape(o,1);
|
||||
mat(3,0) = vshape(o,9); mat(3,1) = vshape(o,2);
|
||||
mat(3,2) = vshape(o,4); mat(3,3) = 0.0;
|
||||
|
||||
Mult(mat, Jinv, tempMat);
|
||||
Mult(invJtr, tempMat, mat);
|
||||
|
||||
shape(o,0) = 0.0; shape(o,1) = mat(2,3); shape(o,2) = mat(3,1);
|
||||
shape(o,3) = mat(1,2);
|
||||
shape(o,4) = mat(3,2); shape(o,5) = 0.0; shape(o,6) = mat(0,3);
|
||||
shape(o,7) = mat(2,0);
|
||||
shape(o,8) = mat(1,3); shape(o,9) = mat(3,0); shape(o,10) = 0.0;
|
||||
shape(o,11) = mat(0,1);
|
||||
shape(o,12) = mat(2,1); shape(o,13) = mat(0,2); shape(o,14) = mat(1,0);
|
||||
shape(o,15) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::Project_RT(
|
||||
const real_t *nk, const Array<int> &d2n,
|
||||
VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
|
||||
|
||||
+5
-19
@@ -259,7 +259,7 @@ protected:
|
||||
|
||||
public:
|
||||
/// Enumeration for range_type and deriv_range_type
|
||||
enum RangeType { UNKNOWN_RANGE_TYPE = -1, SCALAR, VECTOR, MAT_SKEW };
|
||||
enum RangeType { UNKNOWN_RANGE_TYPE = -1, SCALAR, VECTOR };
|
||||
|
||||
/** @brief Enumeration for MapType: defines how reference functions are
|
||||
mapped to physical space.
|
||||
@@ -281,11 +281,10 @@ public:
|
||||
$ u(x) = (1/w) \hat u(\hat x) $ */
|
||||
H_DIV, /**< For vector fields; preserves surface integrals of the
|
||||
normal component $ u(x) = (J/w) \hat u(\hat x) $ */
|
||||
H_CURL, /**< For vector fields; preserves line integrals of the
|
||||
H_CURL /**< For vector fields; preserves line integrals of the
|
||||
tangential component
|
||||
$ u(x) = J^{-t} \hat u(\hat x) $ (square J),
|
||||
$ u(x) = J(J^t J)^{-1} \hat u(\hat x) $ (general J) */
|
||||
H_DIV_SKEW
|
||||
};
|
||||
|
||||
/** @brief Enumeration for DerivType: defines which derivative method
|
||||
@@ -300,8 +299,7 @@ public:
|
||||
NONE, ///< No derivatives implemented
|
||||
GRAD, ///< Implements CalcDShape methods
|
||||
DIV, ///< Implements CalcDivShape methods
|
||||
CURL, ///< Implements CalcCurlShape methods
|
||||
DIV_SKEW
|
||||
CURL ///< Implements CalcCurlShape methods
|
||||
};
|
||||
|
||||
/** @brief Construct FiniteElement with given
|
||||
@@ -318,7 +316,7 @@ public:
|
||||
int GetDim() const { return dim; }
|
||||
|
||||
/** @brief Returns the vector dimension for vector-valued finite elements,
|
||||
which is also the dimension of the interpolation operation. */
|
||||
which is also the dimension of the interpolation operatrion. */
|
||||
int GetRangeDim() const { return vdim; }
|
||||
|
||||
/// Returns the dimension of the curl for vector-valued finite elements.
|
||||
@@ -450,10 +448,6 @@ public:
|
||||
virtual void CalcPhysCurlShape(ElementTransformation &Trans,
|
||||
DenseMatrix &curl_shape) const;
|
||||
|
||||
virtual void CalcDivSkewShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
|
||||
|
||||
/** @brief Get the dofs associated with the given @a face.
|
||||
@a *dofs is set to an internal array of the local dofc on the
|
||||
face, while *ndofs is set to the number of dofs on that face.
|
||||
@@ -583,10 +577,6 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &div) const;
|
||||
|
||||
virtual void ProjectDivSkew(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &DivSkew) const;
|
||||
|
||||
/** @brief Return a DofToQuad structure corresponding to the given
|
||||
IntegrationRule using the given DofToQuad::Mode. */
|
||||
/** See the documentation for DofToQuad for more details. */
|
||||
@@ -822,7 +812,7 @@ private:
|
||||
protected:
|
||||
bool is_nodal;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable DenseMatrix JtJ, J, Jinv;
|
||||
mutable DenseMatrix JtJ;
|
||||
mutable DenseMatrix curlshape, curlshape_J;
|
||||
#endif
|
||||
void SetDerivMembers();
|
||||
@@ -833,10 +823,6 @@ protected:
|
||||
void CalcVShape_ND(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
void CalcVShape_DivSkew(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
|
||||
/** @brief Project a vector coefficient onto the RT basis functions
|
||||
@param nk Face normal vectors for this element type
|
||||
@param d2n Offset into nk for each degree of freedom
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -450,74 +450,6 @@ public:
|
||||
{ dofs = 0.0; dofs(vertex) = 1.0; }
|
||||
};
|
||||
|
||||
/// Class for quad-linear FE on tesseract (4d element)
|
||||
class QuadLinear4DFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
public:
|
||||
/// Construct a quad-linear FE on tesseract
|
||||
QuadLinear4DFiniteElement();
|
||||
|
||||
/** virtual function which evaluates the values of all
|
||||
shape functions at a given point ip and stores
|
||||
them in the vector shape of dimension Dof (16) */
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
|
||||
/** virtual function which evaluates the values of all
|
||||
partial derivatives of all shape functions at a given
|
||||
point ip and stores them in the matrix dshape (Dof x Dim) (16 x 4)
|
||||
so that each row contains the derivatives of one shape function */
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
|
||||
virtual void CalcHessian (const IntegrationPoint &ip,
|
||||
DenseMatrix &h) const;
|
||||
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const
|
||||
{ dofs = 0.0; dofs(vertex) = 1.0; }
|
||||
};
|
||||
|
||||
/// Class for linear FE on a pentatope
|
||||
class Linear4DFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
public:
|
||||
/// Construct a linear FE on tetrahedron
|
||||
Linear4DFiniteElement();
|
||||
|
||||
/** virtual function which evaluates the values of all
|
||||
shape functions at a given point ip and stores
|
||||
them in the vector shape of dimension Dof (4) */
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
|
||||
/** virtual function which evaluates the values of all
|
||||
partial derivatives of all shape functions at a given
|
||||
point ip and stores them in the matrix dshape (Dof x Dim) (4 x 3)
|
||||
so that each row contains the derivatives of one shape function */
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const
|
||||
{ dofs = 0.0; dofs(vertex) = 1.0; }
|
||||
|
||||
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
|
||||
|
||||
virtual void CalcHessian(const IntegrationPoint &ip, DenseMatrix &h) const;
|
||||
};
|
||||
|
||||
/// Class for quadratic FE on pentatope
|
||||
class Quadratic4DFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
public:
|
||||
/// Construct a quadratic FE on pentatope
|
||||
Quadratic4DFiniteElement();
|
||||
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &h) const;
|
||||
};
|
||||
|
||||
/// A 2D Crouzeix-Raviart element on triangle
|
||||
class CrouzeixRaviartFiniteElement : public NodalFiniteElement
|
||||
@@ -1257,126 +1189,7 @@ public:
|
||||
DenseMatrix &dshape) const;
|
||||
};
|
||||
|
||||
//lowest order first kind nedelec element for a pentatope
|
||||
class Nedelec1PentFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double tk[10][4];
|
||||
|
||||
public:
|
||||
Nedelec1PentFiniteElement();
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_ND(Trans, shape); }
|
||||
virtual void CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
using FiniteElement::Project;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
virtual void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
};
|
||||
|
||||
//lowest order second kind nedelec element for a pentatope
|
||||
class Nedelec1FullPentFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double tk[10][4];
|
||||
|
||||
public:
|
||||
Nedelec1FullPentFiniteElement();
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_ND(Trans, shape); }
|
||||
virtual void CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const {};
|
||||
using FiniteElement::Project;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
virtual void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
};
|
||||
|
||||
class DivSkew1PentFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double tk1[10][4];
|
||||
static const double tk2[10][4];
|
||||
|
||||
public:
|
||||
DivSkew1PentFiniteElement();
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_DivSkew(Trans, shape); }
|
||||
virtual void CalcDivSkewShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &divSkew_shape) const;
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
using FiniteElement::Project;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
virtual void ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const;
|
||||
};
|
||||
|
||||
class RT0PentFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double nk[5][4];
|
||||
|
||||
public:
|
||||
RT0PentFiniteElement();
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_RT(Trans, shape); };
|
||||
|
||||
virtual void CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const;
|
||||
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
using FiniteElement::Project;
|
||||
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
virtual void ProjectDivSkew(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &DivSkew) const;
|
||||
};
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1040,345 +1040,4 @@ void H1_WedgeElement::CalcDShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
H1_PentatopeElement::H1_PentatopeElement(const int p, const int type)
|
||||
: NodalFiniteElement(4, Geometry::PENTATOPE,
|
||||
((p + 1)*(p + 2)*(p + 3)*(p + 4))/24,
|
||||
p, FunctionSpace::Pk)
|
||||
{
|
||||
const double *cp = poly1d.ClosedPoints(p, VerifyClosed(type));
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
shape_x.SetSize(p + 1);
|
||||
shape_y.SetSize(p + 1);
|
||||
shape_z.SetSize(p + 1);
|
||||
shape_t.SetSize(p + 1);
|
||||
shape_l.SetSize(p + 1);
|
||||
dshape_x.SetSize(p + 1);
|
||||
dshape_y.SetSize(p + 1);
|
||||
dshape_z.SetSize(p + 1);
|
||||
dshape_t.SetSize(p + 1);
|
||||
dshape_l.SetSize(p + 1);
|
||||
ddshape_x.SetSize(p + 1);
|
||||
ddshape_y.SetSize(p + 1);
|
||||
ddshape_z.SetSize(p + 1);
|
||||
ddshape_t.SetSize(p + 1);
|
||||
ddshape_l.SetSize(p + 1);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof, dim);
|
||||
ddu.SetSize(dof,dim*(dim+1)/2 );
|
||||
#else
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p+1),
|
||||
shape_l(p + 1);
|
||||
#endif
|
||||
|
||||
// vertices
|
||||
Nodes.IntPoint(0).Set4(cp[0], cp[0], cp[0], cp[0]);
|
||||
Nodes.IntPoint(1).Set4(cp[p], cp[0], cp[0], cp[0]);
|
||||
Nodes.IntPoint(2).Set4(cp[0], cp[p], cp[0], cp[0]);
|
||||
Nodes.IntPoint(3).Set4(cp[0], cp[0], cp[p], cp[0]);
|
||||
Nodes.IntPoint(4).Set4(cp[0], cp[0], cp[0], cp[p]);
|
||||
|
||||
// edges (see Tetrahedron::edges in mesh/tetrahedron.cpp)
|
||||
int o = 5;
|
||||
for (int i = 1; i < p; i++) // (0,1)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[i], cp[0], cp[0], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (0,2)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[i], cp[0], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (0,3)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[0], cp[i], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (0,4)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[0], cp[0], cp[i]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (1,2)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i], cp[i], cp[0], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (1,3)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i], cp[0], cp[i], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (1,4)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i], cp[0], cp[0], cp[i]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (2,3)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[p-i], cp[i], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (2,4)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[p-i], cp[0], cp[i]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (3,4)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[0], cp[p-i], cp[i]);
|
||||
}
|
||||
|
||||
// planars (see Mesh::GeneratePlanars in mesh/mesh.cpp)
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,1,2)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[j]/w, cp[0], cp[0]);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,1,3)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[0], cp[j]/w, cp[0]);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,1,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[0], cp[0], cp[j]/w);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,2,3)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[i]/w, cp[j]/w, cp[0]);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,2,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[i]/w, cp[0], cp[j]/w);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,3,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[0], cp[i]/w, cp[j]/w);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (1,2,3)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i-j]/w, cp[i]/w, cp[j]/w, cp[0]);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (1,2,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i-j]/w, cp[i]/w, cp[0], cp[j]/w);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (1,3,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i-j]/w, cp[0], cp[i]/w, cp[j]/w);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (2,3,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[p-i-j]/w, cp[i]/w, cp[j]/w);
|
||||
}
|
||||
|
||||
// face(volumes)s (see Mesh::GenerateFaces in mesh/mesh.cpp)
|
||||
for (int k = 1; k < p; k++)
|
||||
for (int j = 1; j + k < p; j++)
|
||||
for (int i = 1; i + j + k < p; i++) // (0,1,2,3)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[j]/w, cp[k]/w, cp[0]);
|
||||
}
|
||||
for (int k = 1; k < p; k++)
|
||||
for (int j = 1; j + k < p; j++)
|
||||
for (int i = 1; i + j + k < p; i++) // (0,2,1,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k];
|
||||
Nodes.IntPoint(o++).Set4(cp[j]/w, cp[i]/w, cp[0], cp[k]/w);
|
||||
}
|
||||
for (int k = 1; k < p; k++)
|
||||
for (int j = 1; j + k < p; j++)
|
||||
for (int i = 1; i + j + k < p; i++) // (0,1,3,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[0], cp[j]/w, cp[k]/w);
|
||||
}
|
||||
for (int k = 1; k < p; k++)
|
||||
for (int j = 1; j + k < p; j++)
|
||||
for (int i = 1; i + j + k < p; i++) // (0,3,2,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k];
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[j]/w, cp[i]/w, cp[k]/w);
|
||||
}
|
||||
for (int k = 1; k < p; k++)
|
||||
for (int j = 1; j + k < p; j++)
|
||||
for (int i = 1; i + j + k < p; i++) // (1,2,3,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k];
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i-j-k]/w, cp[i]/w, cp[j]/w, cp[k]/w);
|
||||
}
|
||||
|
||||
// interior
|
||||
for (int l = 1; l < p; l++)
|
||||
for (int k = 1; k + l < p; k++)
|
||||
for (int j = 1; j + k + l < p; j++)
|
||||
for (int i = 1; i + j + k + l < p; i++)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[l] + cp[p-i-j-k-l];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[j]/w, cp[k]/w, cp[l]/w);
|
||||
}
|
||||
|
||||
DenseMatrix T(dof);
|
||||
for (int m = 0; m < dof; m++)
|
||||
{
|
||||
IntegrationPoint &ip = Nodes.IntPoint(m);
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
|
||||
o = 0;
|
||||
for (int l = 0; l <= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k +l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
T(o++, m) = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
}
|
||||
}
|
||||
|
||||
Ti.Factor(T);
|
||||
// cout << "H1_PentatopeElement(" << p << ") : "; Ti.TestInversion();
|
||||
}
|
||||
|
||||
void H1_PentatopeElement::CalcShape(const IntegrationPoint &ip,
|
||||
Vector &shape) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p+1),
|
||||
shape_l(p + 1);
|
||||
Vector u(Dof);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k + l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
u(o++) = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
}
|
||||
|
||||
Ti.Mult(u, shape);
|
||||
}
|
||||
|
||||
void H1_PentatopeElement::CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p+1),
|
||||
shape_l(p + 1);
|
||||
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_t(p+1),
|
||||
dshape_l(p + 1);
|
||||
DenseMatrix du(Dof, Dim);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t, dshape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l, dshape_l);
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k + l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
int m = p - i - j - k - l;
|
||||
du(o,0) = ((dshape_x(i)* shape_l(m)) -
|
||||
( shape_x(i)*dshape_l(m)))*shape_y(j)*shape_z(k)*shape_t(l);
|
||||
du(o,1) = ((dshape_y(j)* shape_l(m)) -
|
||||
( shape_y(j)*dshape_l(m)))*shape_x(i)*shape_z(k)*shape_t(l);
|
||||
du(o,2) = ((dshape_z(k)* shape_l(m)) -
|
||||
( shape_z(k)*dshape_l(m)))*shape_x(i)*shape_y(j)*shape_t(l);
|
||||
du(o,3) = ((dshape_t(l)* shape_l(m)) -
|
||||
( shape_t(l)*dshape_l(m)))*shape_x(i)*shape_y(j)*shape_z(k);
|
||||
o++;
|
||||
}
|
||||
|
||||
Ti.Mult(du, dshape);
|
||||
}
|
||||
|
||||
void H1_PentatopeElement::CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &ddshape) const
|
||||
{
|
||||
const int p = order;
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p+1),
|
||||
shape_l(p + 1);
|
||||
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_t(p+1),
|
||||
dshape_l(p + 1);
|
||||
Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_z(p + 1), ddshape_t(p+1),
|
||||
ddshape_l(p + 1);
|
||||
DenseMatrix ddu(Dof, ((Dim+1)*Dim)/2);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y, ddshape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z, ddshape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t, dshape_t, ddshape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l, dshape_l,
|
||||
ddshape_l);
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k + l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
// u_xx, u_xy, u_xz, u_xt, u_yy, u_yz, u_yt, u_zz, u_zt, u_tt
|
||||
int m = p - i - j - k - l;
|
||||
ddu(o,0) = ((ddshape_x(i)*shape_l(m)) - 2.* (dshape_x(i)*dshape_l(m)) +
|
||||
(shape_x(i)*ddshape_l(m))) * shape_y(j) * shape_z(k) * shape_t(l);
|
||||
ddu(o,1) = ((dshape_y(j)* ( (dshape_x(i)*shape_l(m)) - (shape_x(i)*dshape_l(
|
||||
m))) ) + (shape_y(j)* ((ddshape_l(m)*shape_x(i)) - (dshape_x(i) * dshape_l(
|
||||
m)) ) ) )* shape_z(k) * shape_t(l);
|
||||
ddu(o,2) = ((dshape_z(k)* ( (dshape_x(i)*shape_l(m)) - (shape_x(i)*dshape_l(
|
||||
m))) ) + (shape_z(k)* ((ddshape_l(m)*shape_x(i)) - (dshape_x(i) * dshape_l(
|
||||
m)) ) ) )* shape_y(j) * shape_t(l);
|
||||
ddu(o,3) = ((dshape_t(l)* ( (dshape_x(i)*shape_l(m)) - (shape_x(i)*dshape_l(
|
||||
m))) ) + (shape_t(l)* ((ddshape_l(m)*shape_x(i)) - (dshape_x(i) * dshape_l(
|
||||
m)) ) ) )* shape_y(j) * shape_z(k);
|
||||
ddu(o,4) = ((ddshape_y(j)*shape_l(m)) - 2.* (dshape_y(j)*dshape_l(m)) +
|
||||
(shape_y(j)*ddshape_l(m))) * shape_x(i) * shape_z(k) * shape_t(l);
|
||||
ddu(o,5) = ((dshape_z(k)* ( (dshape_y(j)*shape_l(m)) - (shape_y(j)*dshape_l(
|
||||
m))) ) + (shape_z(k)* ((ddshape_l(m)*shape_y(j)) - (dshape_y(j) * dshape_l(
|
||||
m)) ) ) )* shape_x(i) * shape_t(l);
|
||||
ddu(o,6) = ((dshape_t(l)* ( (dshape_y(j)*shape_l(m)) - (shape_y(j)*dshape_l(
|
||||
m))) ) + (shape_t(l)* ((ddshape_l(m)*shape_y(j)) - (dshape_y(j) * dshape_l(
|
||||
m)) ) ) )* shape_x(i) * shape_z(k);
|
||||
ddu(o,7) = ((ddshape_z(k)*shape_l(m)) - 2.* (dshape_z(k)*dshape_l(m)) +
|
||||
(shape_z(k)*ddshape_l(m))) * shape_y(j) * shape_x(i) * shape_t(l);
|
||||
ddu(o,8) = ((dshape_t(l)* ( (dshape_z(k)*shape_l(m)) - (shape_z(k)*dshape_l(
|
||||
m))) ) + (shape_t(l)* ((ddshape_l(m)*shape_z(k)) - (dshape_z(k) * dshape_l(
|
||||
m)) ) ) )* shape_x(i) * shape_y(j);
|
||||
ddu(o,9) = ((ddshape_t(l)*shape_l(m)) - 2.* (dshape_t(l)*dshape_l(m)) +
|
||||
(shape_t(l)*ddshape_l(m))) * shape_y(j) * shape_x(i) * shape_z(k);
|
||||
o++;
|
||||
}
|
||||
Ti.Mult(ddu, ddshape);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -148,28 +148,6 @@ public:
|
||||
DenseMatrix &dshape) const;
|
||||
};
|
||||
|
||||
class H1_PentatopeElement : public NodalFiniteElement
|
||||
{
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, shape_y, shape_z, shape_t, shape_l;
|
||||
mutable Vector dshape_x, dshape_y, dshape_z, dshape_t, dshape_l, u;
|
||||
mutable Vector ddshape_x, ddshape_y, ddshape_z, ddshape_t, ddshape_l;
|
||||
mutable DenseMatrix du, ddu;
|
||||
#endif
|
||||
DenseMatrixInverse Ti;
|
||||
|
||||
public:
|
||||
H1_PentatopeElement(const int p,
|
||||
const int btype = BasisType::GaussLobatto);
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &ddshape) const;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
@@ -923,175 +923,4 @@ void L2_WedgeElement::CalcDShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
L2_PentatopeElement::L2_PentatopeElement(const int p, const int _type)
|
||||
: NodalFiniteElement(4, Geometry::PENTATOPE,
|
||||
((p + 1)*(p + 2)*(p + 3)*(p + 4))/24,
|
||||
p, FunctionSpace::Pk), T(dof)
|
||||
{
|
||||
const double *op;
|
||||
|
||||
type = _type;
|
||||
switch (type)
|
||||
{
|
||||
case 0: op = poly1d.OpenPoints(p); break;
|
||||
case 1:
|
||||
default: op = poly1d.ClosedPoints(p);
|
||||
}
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
shape_x.SetSize(p + 1);
|
||||
shape_y.SetSize(p + 1);
|
||||
shape_z.SetSize(p + 1);
|
||||
shape_t.SetSize(p + 1);
|
||||
shape_l.SetSize(p + 1);
|
||||
dshape_x.SetSize(p + 1);
|
||||
dshape_y.SetSize(p + 1);
|
||||
dshape_z.SetSize(p + 1);
|
||||
dshape_t.SetSize(p + 1);
|
||||
dshape_l.SetSize(p + 1);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof, dim);
|
||||
#else
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p + 1),
|
||||
shape_l(p + 1);
|
||||
#endif
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; l + k <= p; k++)
|
||||
for (int j = 0; j + l + k <= p; j++)
|
||||
for (int i = 0; i + j + l + k <= p; i++)
|
||||
{
|
||||
double w = op[i] + op[j] + op[k] + op[l] + op[p-i-j-k-l];
|
||||
Nodes.IntPoint(o++).Set4(op[i]/w, op[j]/w, op[k]/w, op[l]/w);
|
||||
}
|
||||
|
||||
for (int m = 0; m < dof; m++)
|
||||
{
|
||||
IntegrationPoint &ip = Nodes.IntPoint(m);
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; l + k <= p; k++)
|
||||
for (int j = 0; j + l + k <= p; j++)
|
||||
for (int i = 0; i + j + l + k <= p; i++)
|
||||
{
|
||||
T(o++, m) = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
}
|
||||
}
|
||||
|
||||
T.Invert();
|
||||
}
|
||||
|
||||
void L2_PentatopeElement::CalcShape(const IntegrationPoint &ip,
|
||||
Vector &shape) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
|
||||
Vector u(Dof);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; l + k <= p; k++)
|
||||
for (int j = 0; j + l + k <= p; j++)
|
||||
for (int i = 0; i + j + l + k <= p; i++)
|
||||
{
|
||||
u(o++) = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
}
|
||||
|
||||
T.Mult(u, shape);
|
||||
}
|
||||
|
||||
void L2_PentatopeElement::CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p + 1),
|
||||
shape_l(p + 1);
|
||||
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_t(p + 1),
|
||||
dshape_l(p + 1);
|
||||
DenseMatrix du(Dof, Dim);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t, dshape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l, dshape_l);
|
||||
|
||||
for (int o = 0, m = 0; m <= p; m++)
|
||||
for (int k = 0; k + m <= p; k++)
|
||||
for (int j = 0; j + k + m <= p; j++)
|
||||
for (int i = 0; i + j + k + m <= p; i++)
|
||||
{
|
||||
int l = p - i - j - k - m;
|
||||
du(o,0) = ((dshape_x(i)* shape_l(l)) -
|
||||
( shape_x(i)*dshape_l(l)))*shape_y(j)*shape_z(k)*shape_t(m);
|
||||
du(o,1) = ((dshape_y(j)* shape_l(l)) -
|
||||
( shape_y(j)*dshape_l(l)))*shape_x(i)*shape_z(k)*shape_t(m);
|
||||
du(o,2) = ((dshape_z(k)* shape_l(l)) -
|
||||
( shape_z(k)*dshape_l(l)))*shape_x(i)*shape_y(j)*shape_t(m);
|
||||
du(o,3) = ((dshape_t(m)* shape_l(l)) -
|
||||
( shape_t(m)*dshape_l(l)))*shape_x(i)*shape_y(j)*shape_z(k);
|
||||
o++;
|
||||
}
|
||||
|
||||
Mult(T, du, dshape);
|
||||
}
|
||||
|
||||
void L2_PentatopeElement::ProjectDelta(int vertex, Vector &dofs) const
|
||||
{
|
||||
switch (vertex)
|
||||
{
|
||||
case 0:
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(i);
|
||||
dofs[i] = pow(1.0 - ip.x - ip.y - ip.z - ip.t, order);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(i);
|
||||
dofs[i] = pow(ip.x, order);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(i);
|
||||
dofs[i] = pow(ip.y, order);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(i);
|
||||
dofs[i] = pow(ip.z, order);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(i);
|
||||
dofs[i] = pow(ip.t, order);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -183,25 +183,6 @@ public:
|
||||
DenseMatrix &dshape) const;
|
||||
};
|
||||
|
||||
class L2_PentatopeElement : public NodalFiniteElement
|
||||
{
|
||||
private:
|
||||
int type;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, shape_y, shape_z, shape_t, shape_l;
|
||||
mutable Vector dshape_x, dshape_y, dshape_z, dshape_t, dshape_l, u;
|
||||
mutable DenseMatrix du;
|
||||
#endif
|
||||
DenseMatrix T;
|
||||
|
||||
public:
|
||||
L2_PentatopeElement(const int p, const int _type = 0);
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2266,268 +2266,4 @@ void RT_R2D_QuadrilateralElement::CalcDivShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
const double RT_PentatopeElement::nk[20] =
|
||||
{ 0,0,0,-1, 0,0,-1,0, 0,-1,0,0, -1,0,0,0, 1,1,1,1};
|
||||
// { .5,.5,.5, -.5,0,0, 0,-.5,0, 0,0,-.5}; // n_F |F|
|
||||
|
||||
const double RT_PentatopeElement::c = 1./5.;
|
||||
|
||||
RT_PentatopeElement::RT_PentatopeElement(const int p)
|
||||
: VectorFiniteElement(4, Geometry::PENTATOPE, (p + 1)*(p + 2)*(p + 3)*(p + 5)/6,
|
||||
p + 1, H_DIV, FunctionSpace::Pk),
|
||||
dof2nk(dof)
|
||||
{
|
||||
const double *iop = (p > 0) ? poly1d.OpenPoints(p - 1) : NULL;
|
||||
const double *bop = poly1d.OpenPoints(p);
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
shape_x.SetSize(p + 1);
|
||||
shape_y.SetSize(p + 1);
|
||||
shape_z.SetSize(p + 1);
|
||||
shape_t.SetSize(p + 1);
|
||||
shape_l.SetSize(p + 1);
|
||||
dshape_x.SetSize(p + 1);
|
||||
dshape_y.SetSize(p + 1);
|
||||
dshape_z.SetSize(p + 1);
|
||||
dshape_t.SetSize(p + 1);
|
||||
dshape_l.SetSize(p + 1);
|
||||
u.SetSize(dof, dim);
|
||||
divu.SetSize(dof);
|
||||
#else
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p + 1),
|
||||
shape_l(p + 1);
|
||||
#endif
|
||||
|
||||
int o = 0;
|
||||
// faces (see Mesh::GenerateFaces in mesh/mesh.cpp,
|
||||
// the constructor of H1_PentatopeElement)
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++) // (0,1,2,3)
|
||||
{
|
||||
double w = bop[i] + bop[j] + bop[k] + bop[p-i-j-k];
|
||||
Nodes.IntPoint(o).Set4(bop[i]/w, bop[j]/w, bop[k]/w, 0.);
|
||||
dof2nk[o++] = 0;
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++) // (0,2,1,4)
|
||||
{
|
||||
double w = bop[i] + bop[j] + bop[k] + bop[p-i-j-k];
|
||||
Nodes.IntPoint(o).Set4(bop[j]/w, bop[i]/w, 0., bop[k]/w);
|
||||
dof2nk[o++] = 1;
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++) // (0,1,3,4)
|
||||
{
|
||||
double w = bop[i] + bop[j] + bop[k] + bop[p-i-j-k];
|
||||
Nodes.IntPoint(o).Set4(bop[i]/w, 0., bop[j]/w, bop[k]/w);
|
||||
dof2nk[o++] = 2;
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++) // (0,3,2,4)
|
||||
{
|
||||
double w = bop[i] + bop[j] + bop[k] + bop[p-i-j-k];
|
||||
Nodes.IntPoint(o).Set4(0., bop[j]/w, bop[i]/w, bop[k]/w);
|
||||
dof2nk[o++] = 3;
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++) // (1,2,3,4)
|
||||
{
|
||||
double w = bop[i] + bop[j] + bop[k] + bop[p-i-j-k];
|
||||
Nodes.IntPoint(o).Set4(bop[p-i-j-k]/w, bop[i]/w, bop[j]/w, bop[k]/w);
|
||||
dof2nk[o++] = 4;
|
||||
}
|
||||
|
||||
// interior
|
||||
for (int l = 0; l < p; l++)
|
||||
for (int k = 0; k + l < p; k++)
|
||||
for (int j = 0; j + k + l < p; j++)
|
||||
for (int i = 0; i + j + k + l < p; i++)
|
||||
{
|
||||
double w = iop[i] + iop[j] + iop[k] + iop[l] + iop[p-1-i-j-k-l];
|
||||
Nodes.IntPoint(o).Set4(iop[i]/w, iop[j]/w, iop[k]/w, iop[l]/w);
|
||||
dof2nk[o++] = 1;
|
||||
Nodes.IntPoint(o).Set4(iop[i]/w, iop[j]/w, iop[k]/w, iop[l]/w);
|
||||
dof2nk[o++] = 2;
|
||||
Nodes.IntPoint(o).Set4(iop[i]/w, iop[j]/w, iop[k]/w, iop[l]/w);
|
||||
dof2nk[o++] = 3;
|
||||
Nodes.IntPoint(o).Set4(iop[i]/w, iop[j]/w, iop[k]/w, iop[l]/w);
|
||||
dof2nk[o++] = 4;
|
||||
}
|
||||
|
||||
DenseMatrix T(dof);
|
||||
for (int m = 0; m < dof; m++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(m);
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
const double *nm = nk + 4*dof2nk[m];
|
||||
|
||||
o = 0;
|
||||
for (int l = 0; l<= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k + l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
T(o++, m) = s * nm[0];
|
||||
T(o++, m) = s * nm[1];
|
||||
T(o++, m) = s * nm[2];
|
||||
T(o++, m) = s * nm[3];
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++)
|
||||
{
|
||||
double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(p-i-j-k);
|
||||
T(o++, m) = s*((ip.x - c)*nm[0] + (ip.y - c)*nm[1] +
|
||||
(ip.z - c)*nm[2] + (ip.t - c)*nm[3]);
|
||||
}
|
||||
}
|
||||
|
||||
Ti.Factor(T);
|
||||
// mfem::out << "RT_TetrahedronElement(" << p << ") : "; Ti.TestInversion();
|
||||
}
|
||||
|
||||
void RT_PentatopeElement::CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
const int p = order - 1;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p + 1),
|
||||
shape_l(p + 1);
|
||||
DenseMatrix u(Dof, Dim);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
|
||||
int o = 0;
|
||||
for (int l = 0; l <= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k + l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
u(o,0) = s; u(o,1) = 0; u(o,2) = 0; u(o,3) = 0; o++;
|
||||
u(o,0) = 0; u(o,1) = s; u(o,2) = 0; u(o,3) = 0; o++;
|
||||
u(o,0) = 0; u(o,1) = 0; u(o,2) = s; u(o,3) = 0; o++;
|
||||
u(o,0) = 0; u(o,1) = 0; u(o,2) = 0; u(o,3) = s; o++;
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++)
|
||||
{
|
||||
double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(p-i-j-k);
|
||||
u(o,0) = (ip.x - c)*s; u(o,1) = (ip.y - c)*s; u(o,2) = (ip.z - c)*s;
|
||||
u(o,3) = (ip.t - c)*s;
|
||||
o++;
|
||||
}
|
||||
|
||||
Ti.Mult(u, shape);
|
||||
}
|
||||
|
||||
void RT_PentatopeElement::CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const
|
||||
{
|
||||
const int p = order - 1;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
|
||||
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1);
|
||||
Vector divu(Dof);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t, dshape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l, dshape_l);
|
||||
|
||||
int o = 0;
|
||||
for (int m = 0; m <= p; m++)
|
||||
for (int k = 0; k + m <= p; k++)
|
||||
for (int j = 0; j + k + m <= p; j++)
|
||||
for (int i = 0; i + j + k + m <= p; i++)
|
||||
{
|
||||
int l = p - i - j - k - m;
|
||||
divu(o++) = (dshape_x(i)*shape_l(l) -
|
||||
shape_x(i)*dshape_l(l))*shape_y(j)*shape_z(k)*shape_t(m);
|
||||
divu(o++) = (dshape_y(j)*shape_l(l) -
|
||||
shape_y(j)*dshape_l(l))*shape_x(i)*shape_z(k)*shape_t(m);
|
||||
divu(o++) = (dshape_z(k)*shape_l(l) -
|
||||
shape_z(k)*dshape_l(l))*shape_x(i)*shape_y(j)*shape_t(m);
|
||||
divu(o++) = (dshape_t(m)*shape_l(l) -
|
||||
shape_t(m)*dshape_l(l))*shape_x(i)*shape_y(j)*shape_z(k);
|
||||
}
|
||||
for (int l = 0; l <= p; l++)
|
||||
for (int j = 0; j + l<= p; j++)
|
||||
for (int i = 0; i + j + l <= p; i++)
|
||||
{
|
||||
int k = p - i - j - l;
|
||||
divu(o++) =
|
||||
(shape_x(i) + (ip.x - c)*dshape_x(i))*shape_y(j)*shape_z(l)*shape_t(k) +
|
||||
(shape_y(j) + (ip.y - c)*dshape_y(j))*shape_x(i)*shape_z(l)*shape_t(k) +
|
||||
(shape_z(l) + (ip.z - c)*dshape_z(l))*shape_x(i)*shape_y(j)*shape_t(k) +
|
||||
(shape_t(k) + (ip.t - c)*dshape_t(k))*shape_x(i)*shape_y(j)*shape_z(l);
|
||||
}
|
||||
|
||||
Ti.Mult(divu, divshape);
|
||||
}
|
||||
|
||||
void RT_PentatopeElement::ProjectDivSkew(const FiniteElement& fe,
|
||||
ElementTransformation& Trans, DenseMatrix& DivSkew) const
|
||||
{
|
||||
int dof = fe.GetDof();
|
||||
|
||||
mfem_warning("RT_PentatopeElement::ProjectDivSkew(...) Implementation not tested!"); // TODO
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix Jinv(dim, dim);
|
||||
#endif
|
||||
|
||||
DivSkew.SetSize(dof,dof);
|
||||
DivSkew = 0.0;
|
||||
|
||||
double n[4];
|
||||
Vector ni(n, 4);
|
||||
Vector vecF(4);
|
||||
|
||||
DenseMatrix DivSkewshape(dof,4);
|
||||
DenseMatrix DivSkew_dFt(dof,4);
|
||||
for (int k = 0; k < dof; k++)
|
||||
{
|
||||
Trans.SetIntPoint(&Nodes.IntPoint(k));
|
||||
const DenseMatrix &J = Trans.Jacobian();
|
||||
CalcAdjugateTranspose(J, Jinv);
|
||||
|
||||
fe.CalcDivSkewShape(Nodes.IntPoint(k), DivSkewshape);
|
||||
MultABt(DivSkewshape, J, DivSkew_dFt);
|
||||
DivSkew_dFt *= (1.0 / Trans.Weight());
|
||||
|
||||
Jinv.Mult(nk + dof2nk[k] * dim,n);
|
||||
|
||||
for (int j=0; j<dof; j++)
|
||||
{
|
||||
vecF(0) = DivSkew_dFt(j,0);
|
||||
vecF(1) = DivSkew_dFt(j,1);
|
||||
vecF(2) = DivSkew_dFt(j,2);
|
||||
vecF(3) = DivSkew_dFt(j,3);
|
||||
|
||||
DivSkew(k, j) = vecF * ni;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -524,53 +524,6 @@ public:
|
||||
Vector &divshape) const;
|
||||
};
|
||||
|
||||
class RT_PentatopeElement : public VectorFiniteElement
|
||||
{
|
||||
static const double nk[20], c;
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, shape_y, shape_z, shape_t, shape_l;
|
||||
mutable Vector dshape_x, dshape_y, dshape_z, dshape_t, dshape_l;
|
||||
mutable DenseMatrix u;
|
||||
mutable Vector divu;
|
||||
#endif
|
||||
Array<int> dof2nk;
|
||||
DenseMatrixInverse Ti;
|
||||
|
||||
public:
|
||||
RT_PentatopeElement(const int p);
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_RT(Trans, shape); }
|
||||
virtual void CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const;
|
||||
virtual void GetLocalInterpolation(ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{ LocalInterpolation_RT(*this, nk, dof2nk, Trans, I); }
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ LocalRestriction_RT(nk, dof2nk, Trans, R); }
|
||||
virtual void GetTransferMatrix(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{ LocalInterpolation_RT(CheckVectorFE(fe), nk, dof2nk, Trans, I); }
|
||||
using FiniteElement::Project;
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{ Project_RT(nk, dof2nk, fe, Trans, I); }
|
||||
virtual void ProjectDivSkew(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &DivSkew) const;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
|
||||
+2
-345
@@ -111,29 +111,12 @@ int FiniteElementCollection::HasFaceDofs(Geometry::Type geom, int p) const
|
||||
case Geometry::PYRAMID:
|
||||
return max(GetNumDof(Geometry::TRIANGLE, p),
|
||||
GetNumDof(Geometry::SQUARE, p));
|
||||
case Geometry::PENTATOPE:
|
||||
return GetNumDof(Geometry::TETRAHEDRON, p);
|
||||
case Geometry::TESSERACT:
|
||||
return GetNumDof(Geometry::CUBE, p);
|
||||
default:
|
||||
MFEM_ABORT("unknown geometry type");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FiniteElementCollection::HasPlanarDofs(Geometry::Type GeomType, int p) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::PENTATOPE: return GetNumDof(Geometry::TRIANGLE, p);
|
||||
case Geometry::TESSERACT: return GetNumDof(Geometry::SQUARE, p);
|
||||
default:
|
||||
mfem_error ("FiniteElementCollection::HasPlanarDofs:"
|
||||
" unknown geometry type.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
FiniteElementCollection *FiniteElementCollection::GetTraceCollection() const
|
||||
{
|
||||
MFEM_ABORT("this method is not implemented in this derived class!");
|
||||
@@ -670,8 +653,6 @@ LinearFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PYRAMID: return &PyramidFE;
|
||||
case Geometry::PENTATOPE: return &PentatopeFE;
|
||||
case Geometry::TESSERACT: return &TesseractFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("LinearFECollection: unknown geometry type.");
|
||||
@@ -691,8 +672,6 @@ int LinearFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PRISM: return 0;
|
||||
case Geometry::PYRAMID: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
case Geometry::TESSERACT: return 0;
|
||||
default:
|
||||
mfem_error ("LinearFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -718,7 +697,6 @@ QuadraticFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PENTATOPE: return &PentatopeFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("QuadraticFECollection: unknown geometry type.");
|
||||
@@ -737,7 +715,6 @@ int QuadraticFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TETRAHEDRON: return 0;
|
||||
case Geometry::CUBE: return 1;
|
||||
case Geometry::PRISM: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
default:
|
||||
mfem_error ("QuadraticFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -1564,135 +1541,6 @@ const int *ND1_3DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
return ind_neg;
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
ND1_4DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::PENTATOPE: return &NedPentatopFE;
|
||||
default:
|
||||
mfem_error ("ND1_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &NedPentatopFE; // Make some compilers happy
|
||||
}
|
||||
|
||||
int ND1_4DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::POINT: return 0;
|
||||
case Geometry::SEGMENT: return 1;
|
||||
case Geometry::TRIANGLE: return 0;
|
||||
case Geometry::SQUARE: return 0;
|
||||
case Geometry::TETRAHEDRON: return 0;
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
default:
|
||||
mfem_error ("ND1_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return 0; // Make some compilers happy
|
||||
}
|
||||
|
||||
const int * ND1_4DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or)
|
||||
const
|
||||
{
|
||||
static int ind_pos[] = { 0 };
|
||||
static int ind_neg[] = { -1 };
|
||||
|
||||
if (Or > 0)
|
||||
{
|
||||
return ind_pos;
|
||||
}
|
||||
return ind_neg;
|
||||
}
|
||||
|
||||
|
||||
const FiniteElement *
|
||||
ND2_4DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::PENTATOPE: return &NedPentatopFE;
|
||||
default:
|
||||
mfem_error ("ND2_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &NedPentatopFE; // Make some compilers happy
|
||||
}
|
||||
|
||||
int ND2_4DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::POINT: return 0;
|
||||
case Geometry::SEGMENT: return 2;
|
||||
case Geometry::TRIANGLE: return 0;
|
||||
case Geometry::SQUARE: return 0;
|
||||
case Geometry::TETRAHEDRON: return 0;
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
default:
|
||||
mfem_error ("ND2_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return 0; // Make some compilers happy
|
||||
}
|
||||
|
||||
const int * ND2_4DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or)
|
||||
const
|
||||
{
|
||||
static int ind_pos[] = { 0, 1 };
|
||||
static int ind_neg[] = { -2, -1};
|
||||
|
||||
if (Or > 0)
|
||||
{
|
||||
return ind_pos;
|
||||
}
|
||||
return ind_neg;
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
DivSkew1_4DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::PENTATOPE: return &DivSkew0PentatopFE;
|
||||
default:
|
||||
mfem_error ("DivSkew1_4DFECollection: unknown geometry type 1.");
|
||||
}
|
||||
return &DivSkew0PentatopFE; // Make some compilers happy
|
||||
}
|
||||
|
||||
int DivSkew1_4DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::POINT: return 0;
|
||||
case Geometry::SEGMENT: return 0;
|
||||
case Geometry::TRIANGLE: return 1;
|
||||
case Geometry::SQUARE: return 0;
|
||||
case Geometry::TETRAHEDRON: return 0;
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
default:
|
||||
mfem_error ("DivSkew1_4DFECollection: unknown geometry type 2.");
|
||||
}
|
||||
return 0; // Make some compilers happy
|
||||
}
|
||||
|
||||
const int * DivSkew1_4DFECollection::DofOrderForOrientation(
|
||||
Geometry::Type GeomType, int Or)
|
||||
const
|
||||
{
|
||||
static int ind_pos[] = { 0 };
|
||||
static int ind_neg[] = { -1 };
|
||||
|
||||
if (Or %2 == 0)
|
||||
{
|
||||
return ind_pos;
|
||||
}
|
||||
return ind_neg;
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
RT0_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
@@ -1798,57 +1646,13 @@ const int *RT1_3DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
}
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
RT0_4DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::PENTATOPE: return &PentatopeFE;
|
||||
default:
|
||||
mfem_error ("RT0_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &PentatopeFE; // Make some compilers happy
|
||||
}
|
||||
|
||||
int RT0_4DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::POINT: return 0;
|
||||
case Geometry::SEGMENT: return 0;
|
||||
case Geometry::TRIANGLE: return 0;
|
||||
case Geometry::SQUARE: return 0;
|
||||
case Geometry::TETRAHEDRON: return 1;
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
default:
|
||||
mfem_error ("RT0_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return 0; // Make some compilers happy
|
||||
}
|
||||
|
||||
const int * RT0_4DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or)
|
||||
const
|
||||
{
|
||||
static int ind_pos[] = { 0 };
|
||||
static int ind_neg[] = { -1 };
|
||||
|
||||
if (GeomType == Geometry::TETRAHEDRON)
|
||||
{
|
||||
if (Or % 2 == 0) { return ind_pos; }
|
||||
return ind_neg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
||||
: FiniteElementCollection(p)
|
||||
, dim(dim)
|
||||
{
|
||||
MFEM_VERIFY(p >= 1, "H1_FECollection requires order >= 1.");
|
||||
MFEM_VERIFY(dim >= 0 && dim <= 4, "H1_FECollection requires 0 <= dim <= 4.");
|
||||
MFEM_VERIFY(dim >= 0 && dim <= 3, "H1_FECollection requires 0 <= dim <= 3.");
|
||||
|
||||
const int pm1 = p - 1, pm2 = pm1 - 1, pm3 = pm2 - 1, pm4 = pm3 - 1;
|
||||
|
||||
@@ -2149,20 +1953,6 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dim >= 4)
|
||||
{
|
||||
H1_dof[Geometry::PENTATOPE] = (TriDof*pm3*pm4)/12;
|
||||
H1_dof[Geometry::TESSERACT] = QuadDof*pm1*pm1;
|
||||
if (b_type == BasisType::Positive)
|
||||
{
|
||||
mfem_error("H1_FECollection: BasisType::Positive not implemented");
|
||||
}
|
||||
else
|
||||
{
|
||||
H1_Elements[Geometry::PENTATOPE] = new H1_PentatopeElement(p, pt_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2540,38 +2330,6 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
|
||||
OtherDofOrd[j] = j; // for Or == 0
|
||||
}
|
||||
}
|
||||
else if (dim == 4)
|
||||
{
|
||||
if (b_type == BasisType::Positive)
|
||||
{
|
||||
mfem::err <<
|
||||
"L2_FECollection::L2_FECollection : BasisType::Positive not implemented" <<
|
||||
endl;
|
||||
mfem_error();
|
||||
}
|
||||
else
|
||||
{
|
||||
L2_Elements[Geometry::PENTATOPE] =
|
||||
new L2_PentatopeElement(p, btype);
|
||||
|
||||
// 2025 November: check this
|
||||
L2_Elements[Geometry::TESSERACT] = new L2_HexahedronElement(p, btype);
|
||||
}
|
||||
L2_Elements[Geometry::PENTATOPE]->SetMapType(map_type);
|
||||
L2_Elements[Geometry::TESSERACT]->SetMapType(map_type);
|
||||
// All trace element use the default Gauss-Legendre nodal points
|
||||
Tr_Elements[Geometry::TETRAHEDRON] = new L2_TetrahedronElement(p);
|
||||
Tr_Elements[Geometry::CUBE] = new L2_HexahedronElement(p);
|
||||
|
||||
const int PentDof = L2_Elements[Geometry::PENTATOPE]->GetDof();
|
||||
const int TessDof = L2_Elements[Geometry::TESSERACT]->GetDof();
|
||||
const int MaxDof = std::max(PentDof, TessDof);
|
||||
OtherDofOrd = new int[MaxDof];
|
||||
for (int j = 0; j < MaxDof; j++)
|
||||
{
|
||||
OtherDofOrd[j] = j; // for Or == 0
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem::err << "L2_FECollection::L2_FECollection : dim = "
|
||||
@@ -2610,9 +2368,6 @@ const int *L2_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
case Geometry::TETRAHEDRON:
|
||||
return TetDofOrd[Or%24];
|
||||
|
||||
case Geometry::PENTATOPE:
|
||||
return TetDofOrd[Or%120];
|
||||
|
||||
default:
|
||||
return (Or == 0) ? OtherDofOrd : NULL;
|
||||
}
|
||||
@@ -2697,13 +2452,6 @@ RT_FECollection::RT_FECollection(const int order, const int dim,
|
||||
RT_Elements[Geometry::PYRAMID] = new RT0PyrFiniteElement(false);
|
||||
RT_dof[Geometry::PYRAMID] = 0;
|
||||
}
|
||||
else if (dim == 4)
|
||||
{
|
||||
RT_Elements[Geometry::PENTATOPE] = new RT_PentatopeElement(p);
|
||||
RT_dof[Geometry::PENTATOPE] = p*pp1*(p + 2)*(p + 3)/6;
|
||||
|
||||
//TODO: tesseracts
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("invalid dim = " << dim);
|
||||
@@ -2736,7 +2484,7 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
|
||||
MFEM_VERIFY(Quadrature1D::CheckOpen(op_type) != Quadrature1D::Invalid,
|
||||
"invalid open point type");
|
||||
|
||||
const int pp1 = p + 1, pp2 = p + 2, pp3 = p + 3;
|
||||
const int pp1 = p + 1, pp2 = p + 2;
|
||||
|
||||
for (int g = 0; g < Geometry::NumGeom; g++)
|
||||
{
|
||||
@@ -2756,10 +2504,6 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
|
||||
{
|
||||
QuadDofOrd[i] = NULL;
|
||||
}
|
||||
for (int i = 0; i < 24; i++)
|
||||
{
|
||||
TetDofOrd[i] = NULL;
|
||||
}
|
||||
|
||||
if (dim_ == 2)
|
||||
{
|
||||
@@ -2848,89 +2592,6 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dim == 4)
|
||||
{
|
||||
L2_TetrahedronElement *l2_tet = new L2_TetrahedronElement(p, ob_type);
|
||||
l2_tet->SetMapType(map_type);
|
||||
RT_Elements[Geometry::TETRAHEDRON] = l2_tet;
|
||||
RT_dof[Geometry::TETRAHEDRON] = pp1*pp2*pp3/6;
|
||||
|
||||
int TetDof = RT_dof[Geometry::TETRAHEDRON];
|
||||
int TriDof2 = pp2*pp1/2;
|
||||
TetDofOrd[0] = new int[24*TetDof];
|
||||
for (int i = 1; i < 24; i++)
|
||||
{
|
||||
TetDofOrd[i] = TetDofOrd[i-1] + TetDof;
|
||||
}
|
||||
// see Mesh::GetTriOrientation in mesh/mesh.cpp,
|
||||
// the constructor of H1_FECollection
|
||||
for (int k=0; k<=p; k++)
|
||||
{
|
||||
for (int j=0; j+k<=p; j++)
|
||||
{
|
||||
for (int i=0; i+j+k<=p; i++)
|
||||
{
|
||||
int o = TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 - (pp2-j)*
|
||||
(pp1-j)/2 - k*j + i;
|
||||
int l = p-k-j-i;
|
||||
TetDofOrd[0][o] = o;
|
||||
TetDofOrd[1][o] = -1 - (TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 -
|
||||
(pp2-j)*(pp1-j)/2 - k*j + l);
|
||||
TetDofOrd[2][o] = TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - k*i + l;
|
||||
TetDofOrd[3][o] = -1 - (TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - k*l + i);
|
||||
TetDofOrd[4][o] = TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - k*l + j;
|
||||
TetDofOrd[5][o] = -1 - (TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - k*i + j);
|
||||
TetDofOrd[6][o] = TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - j*i + k;
|
||||
TetDofOrd[7][o] = -1 - (TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - j*l + k);
|
||||
TetDofOrd[8][o] = TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - i*l + k;
|
||||
TetDofOrd[9][o] = -1 - (TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - l*i + k);
|
||||
TetDofOrd[10][o] = TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-j)*(pp1-j)/2 - l*j + k;
|
||||
TetDofOrd[11][o] = -1 - (TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-j)*(pp1-j)/2 - i*j + k);
|
||||
TetDofOrd[12][o] = TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - i*k + j;
|
||||
TetDofOrd[13][o] = -1 - (TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - l*k + j);
|
||||
TetDofOrd[14][o] = TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - l*k + i;
|
||||
TetDofOrd[15][o] = -1 - (TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - i*k + l);
|
||||
TetDofOrd[16][o] = TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - j*k + l;
|
||||
TetDofOrd[17][o] = -1 - (TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - j*k + i);
|
||||
TetDofOrd[18][o] = TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - j*l + i;
|
||||
TetDofOrd[19][o] = -1 - (TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - j*i + l);
|
||||
TetDofOrd[20][o] = TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-j)*(pp1-j)/2 - i*j + l;
|
||||
TetDofOrd[21][o] = -1 - (TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-j)*(pp1-j)/2 - l*j + i);
|
||||
TetDofOrd[22][o] = TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - l*i + j;
|
||||
TetDofOrd[23][o] = -1 - (TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - i*l + j);
|
||||
if (!signs)
|
||||
{
|
||||
for (int m = 0; m < 24; m+=2)
|
||||
{
|
||||
TetDofOrd[m][o] = -1 - TetDofOrd[m][o];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
@@ -2964,10 +2625,6 @@ const int *RT_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
{
|
||||
return QuadDofOrd[Or%8];
|
||||
}
|
||||
else if (GeomType == Geometry::TETRAHEDRON)
|
||||
{
|
||||
return TetDofOrd[Or%24];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
+1
-85
@@ -94,8 +94,6 @@ public:
|
||||
|
||||
int HasFaceDofs(Geometry::Type geom, int p) const;
|
||||
|
||||
int HasPlanarDofs(Geometry::Type GeomType, int p) const;
|
||||
|
||||
virtual const FiniteElement *TraceFiniteElementForGeometry(
|
||||
Geometry::Type GeomType) const
|
||||
{
|
||||
@@ -393,7 +391,7 @@ protected:
|
||||
char rt_name[32];
|
||||
FiniteElement *RT_Elements[Geometry::NumGeom];
|
||||
int RT_dof[Geometry::NumGeom];
|
||||
int *SegDofOrd[2], *TriDofOrd[6], *QuadDofOrd[8], *TetDofOrd[24];
|
||||
int *SegDofOrd[2], *TriDofOrd[6], *QuadDofOrd[8];
|
||||
|
||||
// Initialize only the face elements
|
||||
void InitFaces(const int p, const int dim, const int map_type,
|
||||
@@ -748,8 +746,6 @@ private:
|
||||
const TriLinear3DFiniteElement ParallelepipedFE;
|
||||
const LinearWedgeFiniteElement WedgeFE;
|
||||
const LinearPyramidFiniteElement PyramidFE;
|
||||
const Linear4DFiniteElement PentatopeFE;
|
||||
const QuadLinear4DFiniteElement TesseractFE;
|
||||
public:
|
||||
LinearFECollection() : FiniteElementCollection(1) {}
|
||||
|
||||
@@ -777,7 +773,6 @@ private:
|
||||
const Quadratic3DFiniteElement TetrahedronFE;
|
||||
const LagrangeHexFiniteElement ParallelepipedFE;
|
||||
const H1_WedgeElement WedgeFE;
|
||||
const Quadratic4DFiniteElement PentatopeFE;
|
||||
|
||||
public:
|
||||
QuadraticFECollection()
|
||||
@@ -1295,65 +1290,6 @@ public:
|
||||
int GetContType() const override { return TANGENTIAL; }
|
||||
};
|
||||
|
||||
class ND1_4DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
const Nedelec1PentFiniteElement NedPentatopFE;
|
||||
|
||||
public:
|
||||
ND1_4DFECollection() { }
|
||||
|
||||
virtual const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual const int * DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const;
|
||||
|
||||
virtual const char * Name() const { return "ND1_4D"; }
|
||||
};
|
||||
|
||||
class ND2_4DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
const Nedelec1FullPentFiniteElement NedPentatopFE;
|
||||
|
||||
public:
|
||||
ND2_4DFECollection() { }
|
||||
|
||||
virtual const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual const int * DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const;
|
||||
|
||||
virtual const char * Name() const { return "ND2_4D"; }
|
||||
};
|
||||
|
||||
|
||||
class DivSkew1_4DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
const DivSkew1PentFiniteElement DivSkew0PentatopFE;
|
||||
|
||||
public:
|
||||
DivSkew1_4DFECollection() { }
|
||||
|
||||
virtual const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual const int * DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const;
|
||||
|
||||
virtual const char * Name() const { return "F2K0_4D"; }
|
||||
};
|
||||
|
||||
|
||||
/** @brief First order Raviart-Thomas finite elements in 3D. This class is kept
|
||||
only for backward compatibility, consider using RT_FECollection instead. */
|
||||
class RT0_3DFECollection : public FiniteElementCollection
|
||||
@@ -1405,26 +1341,6 @@ public:
|
||||
int GetContType() const override { return NORMAL; }
|
||||
};
|
||||
|
||||
/** First order Raviart-Thomas finite elements in 4D. */
|
||||
class RT0_4DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
const P0TetFiniteElement TetrahedronFE;
|
||||
const RT0PentFiniteElement PentatopeFE;
|
||||
public:
|
||||
RT0_4DFECollection() { };
|
||||
|
||||
virtual const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual const int * DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const;
|
||||
|
||||
virtual const char * Name() const { return "RT0_4D"; };
|
||||
};
|
||||
|
||||
/// Discontinuous collection defined locally by a given finite element.
|
||||
class Local_FECollection : public FiniteElementCollection
|
||||
{
|
||||
|
||||
+13
-356
@@ -58,8 +58,8 @@ DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim, Array<int> &dofs)
|
||||
|
||||
FiniteElementSpace::FiniteElementSpace()
|
||||
: mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
|
||||
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0), npdofs(0),
|
||||
bdofs(NULL), pdofs(NULL),
|
||||
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
|
||||
bdofs(NULL),
|
||||
elem_dof(NULL), elem_fos(NULL), bdr_elem_dof(NULL), bdr_elem_fos(NULL),
|
||||
face_dof(NULL),
|
||||
NURBSext(NULL), own_ext(false),
|
||||
@@ -319,12 +319,6 @@ void FiniteElementSpace::GetFaceVDofs(int i, Array<int> &vdofs) const
|
||||
DofsToVDofs(vdofs);
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetPlanarVDofs(int i, Array<int> &vdofs) const
|
||||
{
|
||||
GetPlanarDofs(i, vdofs);
|
||||
DofsToVDofs(vdofs);
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetEdgeVDofs(int i, Array<int> &vdofs) const
|
||||
{
|
||||
GetEdgeDofs(i, vdofs);
|
||||
@@ -546,13 +540,7 @@ void FiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
|
||||
// local DOFs affected by boundary elements on other processors
|
||||
if (Nonconforming())
|
||||
{
|
||||
Array<int> bdr_verts, bdr_edges, bdr_faces, bdr_planars;
|
||||
// if (mesh->Dimension() > 3)
|
||||
// {
|
||||
// mesh->ncmesh->GetBoundaryClosure(bdr_attr_is_ess, bdr_verts, bdr_edges,
|
||||
// bdr_faces, bdr_planars);
|
||||
// }
|
||||
// else
|
||||
Array<int> bdr_verts, bdr_edges, bdr_faces;
|
||||
mesh->ncmesh->GetBoundaryClosure(bdr_attr_is_ess, bdr_verts, bdr_edges,
|
||||
bdr_faces);
|
||||
for (auto v : bdr_verts)
|
||||
@@ -594,20 +582,6 @@ void FiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
|
||||
}
|
||||
MarkDofs(dofs, ess_vdofs);
|
||||
}
|
||||
for (int i = 0; i < bdr_planars.Size(); i++)
|
||||
{
|
||||
if (component < 0)
|
||||
{
|
||||
GetPlanarVDofs(bdr_planars[i], dofs);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetPlanarVDofs(bdr_planars[i], dofs);
|
||||
for (int d = 0; d < dofs.Size(); d++)
|
||||
{ dofs[d] = DofToVDof(dofs[d], component); }
|
||||
}
|
||||
MarkDofs(dofs, ess_vdofs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1015,8 +989,6 @@ void FiniteElementSpace::BuildConformingInterpolation() const
|
||||
"This method should not be used with a ParFiniteElementSpace!");
|
||||
#endif
|
||||
|
||||
if (mesh->Dimension() == 4) { BuildConformingInterpolation4D(); return; }
|
||||
|
||||
if (cP_is_set) { return; }
|
||||
cP_is_set = true;
|
||||
|
||||
@@ -1299,178 +1271,6 @@ void FiniteElementSpace::BuildConformingInterpolation() const
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::BuildConformingInterpolation4D() const
|
||||
{
|
||||
#if 0
|
||||
#ifdef MFEM_USE_MPI
|
||||
MFEM_VERIFY(dynamic_cast<const ParFiniteElementSpace*>(this) == NULL,
|
||||
"This method should not be used with a ParFiniteElementSpace!");
|
||||
#endif
|
||||
|
||||
if (cP_is_set) { return; }
|
||||
cP_is_set = true;
|
||||
|
||||
// For each slave DOF, the dependency matrix will contain a row that
|
||||
// expresses the slave DOF as a linear combination of its immediate master
|
||||
// DOFs. Rows of independent DOFs will remain empty.
|
||||
SparseMatrix deps(ndofs);
|
||||
|
||||
// collect local edge/planar/face dependencies
|
||||
for (int entity = 1; entity <= 3; entity++)
|
||||
{
|
||||
const NCMesh::NCList &list = (entity > 2) ? mesh->ncmesh->GetFaceList()
|
||||
/* */ : ( (entity > 1) ? mesh->ncmesh->GetPlanarList() :
|
||||
mesh->ncmesh->GetEdgeList() );
|
||||
if (!list.masters.size()) { continue; }
|
||||
|
||||
IsoparametricTransformation T;
|
||||
if (entity > 2) { T.SetFE(&TetrahedronFE); }
|
||||
else if (entity > 1) { T.SetFE(&TriangleFE); }
|
||||
else { T.SetFE(&SegmentFE); }
|
||||
|
||||
Geometry::Type geom = (entity > 2) ? Geometry::TETRAHEDRON : ( (
|
||||
entity > 1) ? Geometry::TRIANGLE : Geometry::SEGMENT );
|
||||
const FiniteElement* fe = fec->FiniteElementForGeometry(geom);
|
||||
if (!fe) { continue; }
|
||||
|
||||
Array<int> master_dofs, slave_dofs;
|
||||
DenseMatrix I(fe->GetDof());
|
||||
|
||||
// loop through all master edges/faces, constrain their slave edges/faces
|
||||
for (unsigned mi = 0; mi < list.masters.size(); mi++)
|
||||
{
|
||||
const NCMesh::Master &master = list.masters[mi];
|
||||
GetEntityDofs4D(entity, master.index, master_dofs);
|
||||
if (!master_dofs.Size()) { continue; }
|
||||
|
||||
// mfem::out << "--------------------\n";
|
||||
// master_dofs.Print(mfem::out,master_dofs.Size());
|
||||
|
||||
for (int si = master.slaves_begin; si < master.slaves_end; si++)
|
||||
{
|
||||
const NCMesh::Slave &slave = list.slaves[si];
|
||||
GetEntityDofs4D(entity, slave.index, slave_dofs);
|
||||
if (!slave_dofs.Size()) { continue; }
|
||||
|
||||
slave.OrientedPointMatrix(T.GetPointMat());
|
||||
T.FinalizeTransformation();
|
||||
fe->GetLocalInterpolation(T, I);
|
||||
|
||||
// mfem::out << "********************\n";
|
||||
// slave_dofs.Print(mfem::out,slave_dofs.Size());
|
||||
// mfem::out << "++++++++++++++++++++\n";
|
||||
// I.PrintMatlab(mfem::out);
|
||||
// mfem::out << "++++++++++++++++++++\n";
|
||||
|
||||
// make each slave DOF dependent on all master DOFs
|
||||
AddDependencies(deps, master_dofs, slave_dofs, I);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deps.Finalize();
|
||||
// deps.PrintMatlab(mfem::out);
|
||||
|
||||
// DOFs that stayed independent are true DOFs
|
||||
int n_true_dofs = 0;
|
||||
for (int i = 0; i < ndofs; i++)
|
||||
{
|
||||
if (!deps.RowSize(i)) { n_true_dofs++; }
|
||||
}
|
||||
|
||||
// if all dofs are true dofs leave cP and cR NULL
|
||||
if (n_true_dofs == ndofs)
|
||||
{
|
||||
cP = cR = NULL; // will be treated as identities
|
||||
return;
|
||||
}
|
||||
|
||||
// create the conforming restriction matrix cR
|
||||
int *cR_J;
|
||||
{
|
||||
int *cR_I = new int[n_true_dofs+1];
|
||||
double *cR_A = new double[n_true_dofs];
|
||||
cR_J = new int[n_true_dofs];
|
||||
for (int i = 0; i < n_true_dofs; i++)
|
||||
{
|
||||
cR_I[i] = i;
|
||||
cR_A[i] = 1.0;
|
||||
}
|
||||
cR_I[n_true_dofs] = n_true_dofs;
|
||||
cR = new SparseMatrix(cR_I, cR_J, cR_A, n_true_dofs, ndofs);
|
||||
}
|
||||
|
||||
// create the conforming prolongation matrix cP
|
||||
cP = new SparseMatrix(ndofs, n_true_dofs);
|
||||
|
||||
Array<bool> finalized(ndofs);
|
||||
finalized = false;
|
||||
|
||||
// put identity in the restriction and prolongation matrices for true DOFs
|
||||
for (int i = 0, true_dof = 0; i < ndofs; i++)
|
||||
{
|
||||
if (!deps.RowSize(i))
|
||||
{
|
||||
cR_J[true_dof] = i;
|
||||
cP->Add(i, true_dof++, 1.0);
|
||||
finalized[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Now calculate cP rows of slave DOFs as combinations of cP rows of their
|
||||
// master DOFs. It is possible that some slave DOFs depend on DOFs that are
|
||||
// themselves slaves. Here we resolve such indirect constraints by first
|
||||
// calculating rows of the cP matrix for DOFs whose master DOF cP rows are
|
||||
// already known (in the first iteration these are the true DOFs). In the
|
||||
// second iteration, slaves of slaves can be 'finalized' (given a row in the
|
||||
// cP matrix), in the third iteration slaves of slaves of slaves, etc.
|
||||
bool finished;
|
||||
int n_finalized = n_true_dofs;
|
||||
Array<int> cols;
|
||||
Vector srow;
|
||||
do
|
||||
{
|
||||
finished = true;
|
||||
for (int dof = 0; dof < ndofs; dof++)
|
||||
{
|
||||
if (!finalized[dof] && DofFinalizable(dof, finalized, deps))
|
||||
{
|
||||
const int* dep_col = deps.GetRowColumns(dof);
|
||||
const double* dep_coef = deps.GetRowEntries(dof);
|
||||
int n_dep = deps.RowSize(dof);
|
||||
|
||||
for (int j = 0; j < n_dep; j++)
|
||||
{
|
||||
cP->GetRow(dep_col[j], cols, srow);
|
||||
srow *= dep_coef[j];
|
||||
cP->AddRow(dof, cols, srow);
|
||||
}
|
||||
|
||||
finalized[dof] = true;
|
||||
n_finalized++;
|
||||
finished = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!finished);
|
||||
|
||||
// if everything is consistent (mesh, face orientations, etc.), we should
|
||||
// be able to finalize all slave DOFs, otherwise it's a serious error
|
||||
if (n_finalized != ndofs)
|
||||
{
|
||||
MFEM_ABORT("Error creating cP matrix.");
|
||||
}
|
||||
|
||||
cP->Finalize();
|
||||
|
||||
if (vdim > 1)
|
||||
{
|
||||
MakeVDimMatrix(*cP);
|
||||
MakeVDimMatrix(*cR);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FiniteElementSpace::MakeVDimMatrix(SparseMatrix &mat) const
|
||||
{
|
||||
if (vdim == 1) { return; }
|
||||
@@ -2504,10 +2304,8 @@ void FiniteElementSpace::UpdateNURBS()
|
||||
|
||||
nvdofs = 0;
|
||||
nedofs = 0;
|
||||
npdofs = 0;
|
||||
nfdofs = 0;
|
||||
nbdofs = 0;
|
||||
pdofs = NULL;
|
||||
bdofs = NULL;
|
||||
|
||||
delete face_dof;
|
||||
@@ -2590,8 +2388,6 @@ void FiniteElementSpace::Construct()
|
||||
face_dof = NULL;
|
||||
|
||||
ndofs = 0;
|
||||
npdofs = 0;
|
||||
pdofs = NULL;
|
||||
nvdofs = nedofs = nfdofs = nbdofs = 0;
|
||||
bdofs = NULL;
|
||||
|
||||
@@ -2664,24 +2460,6 @@ void FiniteElementSpace::Construct()
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh->Dimension() >= 4 && mesh->GetNE())
|
||||
{
|
||||
// Here we assume that all planars in the mesh have the same base
|
||||
// geometry -- the base geometry of the 0-th face element.
|
||||
int pdof = fec->DofForGeometry(mesh->GetPlanarBaseGeometry(0));
|
||||
if (pdof > 0)
|
||||
{
|
||||
pdofs = new int[mesh->GetNPlanars()+1];
|
||||
pdofs[0] = 0;
|
||||
for (int i = 0; i < mesh->GetNPlanars(); i++)
|
||||
{
|
||||
npdofs += pdof;
|
||||
// npdofs += fec->DofForGeometry(mesh->GetPlanarBaseGeometry(i));
|
||||
pdofs[i+1] = npdofs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assign internal ("bubble") DOFs
|
||||
if (mesh->GetNE() && dim > 0)
|
||||
{
|
||||
@@ -2705,7 +2483,7 @@ void FiniteElementSpace::Construct()
|
||||
}
|
||||
}
|
||||
|
||||
ndofs = nvdofs + nedofs + npdofs + nfdofs + nbdofs;
|
||||
ndofs = nvdofs + nedofs + nfdofs + nbdofs;
|
||||
|
||||
ConstructDoFTransArray();
|
||||
|
||||
@@ -2978,7 +2756,7 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
return;
|
||||
}
|
||||
|
||||
Array<int> V, E, Eo, F, Fo, P, Po; // TODO: LocalArray
|
||||
Array<int> V, E, Eo, F, Fo; // TODO: LocalArray
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
auto geom = mesh->GetElementGeometry(elem);
|
||||
@@ -2987,11 +2765,9 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
int nv = fec->GetNumDof(Geometry::POINT, order);
|
||||
int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
|
||||
int nb = (dim > 0) ? fec->GetNumDof(geom, order) : 0;
|
||||
int np = (dim > 3) ? fec->GetNumDof(Geometry::TRIANGLE, order) : 0;
|
||||
|
||||
if (nv) { mesh->GetElementVertices(elem, V); }
|
||||
if (ne) { mesh->GetElementEdges(elem, E, Eo); }
|
||||
if (np) { mesh->GetElementPlanars(elem, P, Po); }
|
||||
|
||||
int nfd = 0;
|
||||
if (dim > 2 && fec->HasFaceDofs(geom, order))
|
||||
@@ -3011,7 +2787,7 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
}
|
||||
|
||||
dofs.SetSize(0);
|
||||
dofs.Reserve(nv*V.Size() + ne*E.Size() + np*P.Size() + nfd + nb);
|
||||
dofs.Reserve(nv*V.Size() + ne*E.Size() + nfd + nb);
|
||||
|
||||
if (nv) // vertex DOFs
|
||||
{
|
||||
@@ -3038,20 +2814,6 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
}
|
||||
}
|
||||
|
||||
if(np)
|
||||
{
|
||||
for (int i = 0; i < P.Size(); i++)
|
||||
{
|
||||
int pbase = /* IsVariableOrder() ? FindEdgeDof(E[i], ne) : */P[i]*np;
|
||||
const int *ind = fec->GetDofOrdering(Geometry::TRIANGLE, order, Po[i]);
|
||||
|
||||
for (int j = 0; j < np; j++)
|
||||
{
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + pbase, ind[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nfd) // face DOFs
|
||||
{
|
||||
for (int i = 0; i < F.Size(); i++)
|
||||
@@ -3064,7 +2826,7 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
|
||||
for (int j = 0; j < nf; j++)
|
||||
{
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + npdofs + fbase, ind[j]));
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + fbase, ind[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3072,7 +2834,7 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
if (nb) // interior ("bubble") DOFs
|
||||
{
|
||||
int bbase = bdofs ? bdofs[elem] : elem*nb;
|
||||
bbase += nvdofs + nedofs + npdofs + nfdofs;
|
||||
bbase += nvdofs + nedofs + nfdofs;
|
||||
|
||||
for (int j = 0; j < nb; j++)
|
||||
{
|
||||
@@ -3110,7 +2872,7 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
return;
|
||||
}
|
||||
|
||||
Array<int> V, E, Eo, P, Po; // TODO: LocalArray
|
||||
Array<int> V, E, Eo; // TODO: LocalArray
|
||||
int F, oF;
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
@@ -3127,13 +2889,9 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
int nv = fec->GetNumDof(Geometry::POINT, order);
|
||||
int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
|
||||
int nf = (dim > 2) ? fec->GetNumDof(geom, order) : 0;
|
||||
int np = (dim > 3) ? fec->DofForGeometry(Geometry::TRIANGLE) : (0);
|
||||
|
||||
if (nv) { mesh->GetBdrElementVertices(bel, V); }
|
||||
if (ne) { mesh->GetBdrElementEdges(bel, E, Eo); }
|
||||
|
||||
if (np) { mesh->GetBdrElementPlanars(bel, P, Po); }
|
||||
|
||||
if (nf)
|
||||
{
|
||||
mesh->GetBdrElementFace(bel, &F, &oF);
|
||||
@@ -3150,7 +2908,7 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
}
|
||||
|
||||
dofs.SetSize(0);
|
||||
dofs.Reserve(nv*V.Size() + ne*E.Size() + np * P.Size() + nf);
|
||||
dofs.Reserve(nv*V.Size() + ne*E.Size() + nf);
|
||||
|
||||
if (nv) // vertex DOFs
|
||||
{
|
||||
@@ -3177,20 +2935,6 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
}
|
||||
}
|
||||
|
||||
if(np)
|
||||
{
|
||||
for (int i = 0; i < P.Size(); i++)
|
||||
{
|
||||
int pbase = /* IsVariableOrder() ? FindEdgeDof(E[i], ne) : */P[i]*np;
|
||||
const int *ind = fec->GetDofOrdering(Geometry::TRIANGLE, order, Po[i]);
|
||||
|
||||
for (int j = 0; j < np; j++)
|
||||
{
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + pbase, ind[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nf) // face DOFs
|
||||
{
|
||||
int fbase = (var_face_dofs.Size() > 0) ? FindFaceDof(F, nf) : F*nf;
|
||||
@@ -3260,12 +3004,10 @@ int FiniteElementSpace::GetFaceDofs(int face, Array<int> &dofs,
|
||||
// for 1D, 2D and 3D faces
|
||||
int nv = fec->GetNumDof(Geometry::POINT, order);
|
||||
int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
|
||||
int np = (dim > 3) ? fec->GetNumDof(Geometry::TRIANGLE, order) : 0;
|
||||
|
||||
Array<int> V, E, Eo, P, Po;
|
||||
Array<int> V, E, Eo;
|
||||
if (nv) { mesh->GetFaceVertices(face, V); }
|
||||
if (ne) { mesh->GetFaceEdges(face, E, Eo); }
|
||||
if (np) { mesh->GetFacePlanars(face, P, Po); }
|
||||
|
||||
dofs.SetSize(0);
|
||||
dofs.Reserve(V.Size() * nv + E.Size() * ne + nf);
|
||||
@@ -3293,92 +3035,14 @@ int FiniteElementSpace::GetFaceDofs(int face, Array<int> &dofs,
|
||||
}
|
||||
}
|
||||
}
|
||||
if(np)
|
||||
{
|
||||
for (int i = 0; i < P.Size(); i++)
|
||||
{
|
||||
int pbase = /* IsVariableOrder() ? FindEdgeDof(E[i], ne) : */P[i]*np;
|
||||
const int *ind = fec->GetDofOrdering(Geometry::TRIANGLE, order, Po[i]);
|
||||
|
||||
for (int j = 0; j < np; j++)
|
||||
{
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + pbase, ind[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < nf; j++)
|
||||
{
|
||||
dofs.Append(nvdofs + nedofs + npdofs + fbase + j);
|
||||
dofs.Append(nvdofs + nedofs + fbase + j);
|
||||
}
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetPlanarDofs(int planar, Array<int> &dofs) const
|
||||
{
|
||||
MFEM_VERIFY(!orders_changed, msg_orders_changed);
|
||||
|
||||
// if (planar_dof)
|
||||
// {
|
||||
// planar_dof->GetRow(planar, dofs);
|
||||
// return;
|
||||
// }
|
||||
|
||||
Array<int> V, E, Eo; // TODO: LocalArray
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
int order = fec->GetOrder();
|
||||
|
||||
// if (IsVariableOrder()) // determine order from adjacent element
|
||||
// {
|
||||
// int elem, info;
|
||||
// mesh->GetBdrElementAdjacentElement(bel, elem, info);
|
||||
// order = elem_order[elem];
|
||||
// }
|
||||
|
||||
int nv = fec->GetNumDof(Geometry::POINT, order);
|
||||
int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
|
||||
int np = fec->GetNumDof(Geometry::TRIANGLE, order);
|
||||
|
||||
if (nv) { mesh->GetPlanVertices(planar, V); }
|
||||
if (ne) { mesh->GetPlanarEdges(planar, E, Eo); }
|
||||
|
||||
dofs.SetSize(0);
|
||||
dofs.Reserve(nv*V.Size() + ne*E.Size() + np);
|
||||
|
||||
if (nv) // vertex DOFs
|
||||
{
|
||||
for (int i = 0; i < V.Size(); i++)
|
||||
{
|
||||
for (int j = 0; j < nv; j++)
|
||||
{
|
||||
dofs.Append(V[i]*nv + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ne) // edge DOFs
|
||||
{
|
||||
for (int i = 0; i < E.Size(); i++)
|
||||
{
|
||||
int ebase = IsVariableOrder() ? FindEdgeDof(E[i], ne) : E[i]*ne;
|
||||
const int *ind = fec->GetDofOrdering(Geometry::SEGMENT, order, Eo[i]);
|
||||
|
||||
for (int j = 0; j < ne; j++)
|
||||
{
|
||||
dofs.Append(EncodeDof(nvdofs + ebase, ind[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pbase = planar*np;
|
||||
for (int i = 0; i < np; i++)
|
||||
{
|
||||
dofs.Append(nvdofs + nedofs + pbase + i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int FiniteElementSpace::GetEdgeDofs(int edge, Array<int> &dofs,
|
||||
int variant) const
|
||||
{
|
||||
@@ -3445,7 +3109,7 @@ void FiniteElementSpace::GetElementInteriorDofs(int i, Array<int> &dofs) const
|
||||
int base = bdofs ? bdofs[i] : i*nb;
|
||||
|
||||
dofs.SetSize(nb);
|
||||
base += nvdofs + nedofs + npdofs + nfdofs;
|
||||
base += nvdofs + nedofs + nfdofs;
|
||||
for (int j = 0; j < nb; j++)
|
||||
{
|
||||
dofs[j] = base + j;
|
||||
@@ -3600,11 +3264,6 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const
|
||||
return fe;
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetPlanarElement(int i) const
|
||||
{
|
||||
return fec->FiniteElementForGeometry(mesh->GetPlanarBaseGeometry(i));
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetEdgeElement(int i,
|
||||
int variant) const
|
||||
{
|
||||
@@ -3674,8 +3333,6 @@ void FiniteElementSpace::Destroy()
|
||||
delete bdr_elem_fos;
|
||||
delete face_dof;
|
||||
delete [] bdofs;
|
||||
|
||||
delete [] pdofs;
|
||||
}
|
||||
ceed::RemoveBasisAndRestriction(this);
|
||||
}
|
||||
|
||||
+2
-14
@@ -245,9 +245,9 @@ protected:
|
||||
to be of the default order (fec->GetOrder()). */
|
||||
Array<char> elem_order;
|
||||
|
||||
int nvdofs, nedofs, nfdofs, nbdofs, npdofs;
|
||||
int nvdofs, nedofs, nfdofs, nbdofs;
|
||||
int uni_fdof; ///< # of single face DOFs if all faces uniform; -1 otherwise
|
||||
int *bdofs, *pdofs; ///< internal DOFs of elements if mixed/var-order; NULL otherwise
|
||||
int *bdofs; ///< internal DOFs of elements if mixed/var-order; NULL otherwise
|
||||
|
||||
/** Variable order spaces only: DOF assignments for edges and faces, see
|
||||
docs in MakeDofTable. For constant order spaces the tables are empty. */
|
||||
@@ -396,7 +396,6 @@ protected:
|
||||
|
||||
/// Calculate the cP and cR matrices for a nonconforming mesh.
|
||||
void BuildConformingInterpolation() const;
|
||||
void BuildConformingInterpolation4D() const;
|
||||
|
||||
static void AddDependencies(SparseMatrix& deps, Array<int>& master_dofs,
|
||||
Array<int>& slave_dofs, DenseMatrix& I,
|
||||
@@ -731,7 +730,6 @@ public:
|
||||
int GetNVDofs() const { return nvdofs; }
|
||||
/// Number of all scalar edge-interior dofs
|
||||
int GetNEDofs() const { return nedofs; }
|
||||
int GetNPDofs() const { return npdofs; }
|
||||
/// Number of all scalar face-interior dofs
|
||||
int GetNFDofs() const { return nfdofs; }
|
||||
|
||||
@@ -747,9 +745,6 @@ public:
|
||||
the edges. */
|
||||
inline int GetNF() const { return mesh->GetNumFaces(); }
|
||||
|
||||
/// Returns number of planars (i.e. co-dimension 2 entities) in the mesh.
|
||||
inline int GetNP() const { return mesh->GetNPlanars(); }
|
||||
|
||||
/// Returns number of boundary elements in the mesh.
|
||||
inline int GetNBE() const { return mesh->GetNBE(); }
|
||||
|
||||
@@ -791,8 +786,6 @@ public:
|
||||
|
||||
int GetBdrAttribute(int i) const { return mesh->GetBdrAttribute(i); }
|
||||
|
||||
virtual void GetPlanarDofs(int i, Array<int> &dofs) const;
|
||||
|
||||
/// @anchor getdof @name Local DoF Access Members
|
||||
/// These member functions produce arrays of local degree of freedom
|
||||
/// indices, see @ref ldof. If @b vdim == 1 these indices can be used to
|
||||
@@ -1094,9 +1087,6 @@ public:
|
||||
/// not necessarily equal to 1. See GetFaceDofs() for more information.
|
||||
void GetFaceVDofs(int i, Array<int> &vdofs) const;
|
||||
|
||||
/// Returns indexes of degrees of freedom for i'th planar element (4D).
|
||||
void GetPlanarVDofs(int i, Array<int> &vdofs) const;
|
||||
|
||||
/// @brief Returns the indices of the degrees of freedom for the specified
|
||||
/// edge, including the DOFs for the vertices of the edge.
|
||||
///
|
||||
@@ -1188,8 +1178,6 @@ public:
|
||||
points.*/
|
||||
const FiniteElement *GetFaceElement(int i) const;
|
||||
|
||||
const FiniteElement *GetPlanarElement(int i) const;
|
||||
|
||||
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
|
||||
associated with i'th edge in the mesh object. */
|
||||
const FiniteElement *GetEdgeElement(int i, int variant = 0) const;
|
||||
|
||||
+39
-371
@@ -19,11 +19,11 @@ namespace mfem
|
||||
const char *Geometry::Name[NumGeom] =
|
||||
{
|
||||
"Point", "Segment", "Triangle", "Square", "Tetrahedron", "Cube", "Prism",
|
||||
"Pyramid", "Pentatope", "Tesseract"
|
||||
"Pyramid"
|
||||
};
|
||||
|
||||
const real_t Geometry::Volume[NumGeom] =
|
||||
{ 1.0, 1.0, 0.5, 1.0, 1./6, 1.0, 0.5, 1./3, 1./24., 1.0 };
|
||||
{ 1.0, 1.0, 0.5, 1.0, 1./6, 1.0, 0.5, 1./3 };
|
||||
|
||||
Geometry::Geometry()
|
||||
{
|
||||
@@ -165,36 +165,6 @@ Geometry::Geometry()
|
||||
GeomVert[7]->IntPoint(4).y = 0.0;
|
||||
GeomVert[7]->IntPoint(4).z = 1.0;
|
||||
|
||||
// Vertices for Geometry::PENTATOPE
|
||||
GeomVert[8] = new IntegrationRule(5);
|
||||
GeomVert[8]->IntPoint(0).x = 0.0;
|
||||
GeomVert[8]->IntPoint(0).y = 0.0;
|
||||
GeomVert[8]->IntPoint(0).z = 0.0;
|
||||
GeomVert[8]->IntPoint(0).t = 0.0;
|
||||
|
||||
GeomVert[8]->IntPoint(1).x = 1.0;
|
||||
GeomVert[8]->IntPoint(1).y = 0.0;
|
||||
GeomVert[8]->IntPoint(1).z = 0.0;
|
||||
GeomVert[8]->IntPoint(1).t = 0.0;
|
||||
|
||||
GeomVert[8]->IntPoint(2).x = 0.0;
|
||||
GeomVert[8]->IntPoint(2).y = 1.0;
|
||||
GeomVert[8]->IntPoint(2).z = 0.0;
|
||||
GeomVert[8]->IntPoint(2).t = 0.0;
|
||||
|
||||
GeomVert[8]->IntPoint(3).x = 0.0;
|
||||
GeomVert[8]->IntPoint(3).y = 0.0;
|
||||
GeomVert[8]->IntPoint(3).z = 1.0;
|
||||
GeomVert[8]->IntPoint(3).t = 0.0;
|
||||
|
||||
GeomVert[8]->IntPoint(4).x = 0.0;
|
||||
GeomVert[8]->IntPoint(4).y = 0.0;
|
||||
GeomVert[8]->IntPoint(4).z = 0.0;
|
||||
GeomVert[8]->IntPoint(4).t = 1.0;
|
||||
|
||||
// Vertices for Geometry::TESSERACT
|
||||
// TODO
|
||||
|
||||
GeomCenter[POINT].x = 0.0;
|
||||
GeomCenter[POINT].y = 0.0;
|
||||
GeomCenter[POINT].z = 0.0;
|
||||
@@ -227,14 +197,6 @@ Geometry::Geometry()
|
||||
GeomCenter[PYRAMID].y = 0.375;
|
||||
GeomCenter[PYRAMID].z = 0.25;
|
||||
|
||||
GeomCenter[PENTATOPE].x = 0.2;
|
||||
GeomCenter[PENTATOPE].y = 0.2;
|
||||
GeomCenter[PENTATOPE].z = 0.2;
|
||||
GeomCenter[PENTATOPE].t = 0.2;
|
||||
|
||||
// GeomCenter[TESSERACT]
|
||||
// TODO
|
||||
|
||||
GeomToPerfGeomJac[POINT] = NULL;
|
||||
GeomToPerfGeomJac[SEGMENT] = new DenseMatrix(1);
|
||||
GeomToPerfGeomJac[TRIANGLE] = new DenseMatrix(2);
|
||||
@@ -243,7 +205,6 @@ Geometry::Geometry()
|
||||
GeomToPerfGeomJac[CUBE] = new DenseMatrix(3);
|
||||
GeomToPerfGeomJac[PRISM] = new DenseMatrix(3);
|
||||
GeomToPerfGeomJac[PYRAMID] = new DenseMatrix(3);
|
||||
GeomToPerfGeomJac[PENTATOPE] = new DenseMatrix(4);
|
||||
|
||||
PerfGeomToGeomJac[POINT] = NULL;
|
||||
PerfGeomToGeomJac[SEGMENT] = NULL;
|
||||
@@ -253,7 +214,6 @@ Geometry::Geometry()
|
||||
PerfGeomToGeomJac[CUBE] = NULL;
|
||||
PerfGeomToGeomJac[PRISM] = new DenseMatrix(3);
|
||||
PerfGeomToGeomJac[PYRAMID] = new DenseMatrix(3);
|
||||
PerfGeomToGeomJac[PENTATOPE] = new DenseMatrix(4);
|
||||
|
||||
GeomToPerfGeomJac[SEGMENT]->Diag(1.0, 1);
|
||||
{
|
||||
@@ -290,16 +250,6 @@ Geometry::Geometry()
|
||||
*GeomToPerfGeomJac[PYRAMID] = pyr_T.Jacobian();
|
||||
CalcInverse(pyr_T.Jacobian(), *PerfGeomToGeomJac[PYRAMID]);
|
||||
}
|
||||
{
|
||||
Linear4DFiniteElement PentFE;
|
||||
IsoparametricTransformation pent_T;
|
||||
pent_T.SetFE(&PentFE);
|
||||
GetPerfPointMat (PENTATOPE, pent_T.GetPointMat());
|
||||
// pent_T.FinalizeTransformation();
|
||||
pent_T.SetIntPoint(&GeomCenter[PENTATOPE]);
|
||||
*GeomToPerfGeomJac[PENTATOPE] = pent_T.Jacobian();
|
||||
CalcInverse(pent_T.Jacobian(), *PerfGeomToGeomJac[PENTATOPE]);
|
||||
}
|
||||
}
|
||||
|
||||
template <Geometry::Type GEOM>
|
||||
@@ -352,8 +302,6 @@ const IntegrationRule *Geometry::GetVertices(int GeomType) const
|
||||
case Geometry::CUBE: return GeomVert[5];
|
||||
case Geometry::PRISM: return GeomVert[6];
|
||||
case Geometry::PYRAMID: return GeomVert[7];
|
||||
case Geometry::PENTATOPE: return GeomVert[8];
|
||||
case Geometry::TESSERACT: return GeomVert[9];
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
mfem_error("Geometry::GetVertices(...)");
|
||||
@@ -451,45 +399,6 @@ void Geometry::GetRandomPoint(int GeomType, IntegrationPoint &ip)
|
||||
ip.x = 1.0 - z;
|
||||
}
|
||||
break;
|
||||
case Geometry::PENTATOPE:
|
||||
ip.x = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.y = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.z = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.t = real_t(rand()) / real_t(RAND_MAX);
|
||||
// map to the triangular 4D wedge obtained by extruding the reference
|
||||
// tetrahedron in t direction
|
||||
// needs to be updated
|
||||
// if (ip.x + ip.y > 1.0)
|
||||
// {
|
||||
// ip.x = 1.0 - ip.x;
|
||||
// ip.y = 1.0 - ip.y;
|
||||
// }
|
||||
// // split the prism into 3 parts: 1 is the reference tet, and the
|
||||
// // other two tets (as given below) are mapped to the reference tet
|
||||
// if (ip.x + ip.z > 1.0)
|
||||
// {
|
||||
// // tet with vertices: (0,0,1),(1,0,1),(0,1,1),(1,0,0)
|
||||
// ip.x = ip.x + ip.z - 1.0;
|
||||
// // ip.y = ip.y;
|
||||
// ip.z = 1.0 - ip.z;
|
||||
// // mapped to: (0,0,0),(1,0,0),(0,1,0),(0,0,1)
|
||||
// }
|
||||
// else if (ip.x + ip.y + ip.z > 1.0)
|
||||
// {
|
||||
// // tet with vertices: (0,1,1),(0,1,0),(0,0,1),(1,0,0)
|
||||
// real_t x = ip.x;
|
||||
// ip.x = 1.0 - x - ip.z;
|
||||
// ip.y = 1.0 - x - ip.y;
|
||||
// ip.z = x;
|
||||
// // mapped to: (0,0,0),(1,0,0),(0,1,0),(0,0,1)
|
||||
// }
|
||||
// break;
|
||||
case Geometry::TESSERACT:
|
||||
ip.x = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.y = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.z = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.t = real_t(rand()) / real_t(RAND_MAX);
|
||||
break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -556,14 +465,6 @@ bool Geometry::CheckPoint(int GeomType, const IntegrationPoint &ip)
|
||||
if (ip.x < 0.0 || ip.y < 0.0 || ip.x+ip.z > 1.0 || ip.y+ip.z > 1.0 ||
|
||||
ip.z < 0.0 || ip.z > 1.0) { return false; }
|
||||
break;
|
||||
case Geometry::PENTATOPE:
|
||||
if (ip.x < 0.0 || ip.y < 0.0 || ip.z < 0.0 || ip.t < 0 ||
|
||||
ip.x+ip.y+ip.z+ip.t > 1.0) { return false; }
|
||||
break;
|
||||
case Geometry::TESSERACT:
|
||||
if (ip.x < 0.0 || ip.x > 1.0 || ip.y < 0.0 || ip.y > 1.0 ||
|
||||
ip.z < 0.0 || ip.z > 1.0 || ip.t < 0.0 || ip.t > 1.0) { return false; }
|
||||
break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -647,29 +548,6 @@ bool Geometry::CheckPoint(int GeomType, const IntegrationPoint &ip, real_t eps)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Geometry::PENTATOPE:
|
||||
if ( internal::FuzzyLT(ip.x, 0.0, eps)
|
||||
|| internal::FuzzyLT(ip.y, 0.0, eps)
|
||||
|| internal::FuzzyLT(ip.z, 0.0, eps)
|
||||
|| internal::FuzzyLT(ip.t, 0.0, eps)
|
||||
|| internal::FuzzyGT(ip.x+ip.y+ip.z+ip.t, 1.0, eps) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Geometry::TESSERACT:
|
||||
if ( internal::FuzzyLT(ip.x, 0.0, eps)
|
||||
|| internal::FuzzyGT(ip.x, 1.0, eps)
|
||||
|| internal::FuzzyLT(ip.y, 0.0, eps)
|
||||
|| internal::FuzzyGT(ip.y, 1.0, eps)
|
||||
|| internal::FuzzyLT(ip.z, 0.0, eps)
|
||||
|| internal::FuzzyGT(ip.z, 1.0, eps)
|
||||
|| internal::FuzzyLT(ip.t, 0.0, eps)
|
||||
|| internal::FuzzyGT(ip.t, 1.0, eps) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -732,81 +610,6 @@ inline bool ProjectTriangle(real_t &x, real_t &y)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ProjectTetrahedron(double &x, double &y, double &z)
|
||||
{
|
||||
if (z < 0.0)
|
||||
{
|
||||
z = 0.0;
|
||||
internal::ProjectTriangle(x, y);
|
||||
return false;
|
||||
}
|
||||
if (y < 0.0)
|
||||
{
|
||||
y = 0.0;
|
||||
internal::ProjectTriangle(x, z);
|
||||
return false;
|
||||
}
|
||||
if (x < 0.0)
|
||||
{
|
||||
x = 0.0;
|
||||
internal::ProjectTriangle(y, z);
|
||||
return false;
|
||||
}
|
||||
const double l4 = 1.0-x-y-z;
|
||||
if (l4 < 0.0)
|
||||
{
|
||||
const double l4_3 = l4/3;
|
||||
x += l4_3;
|
||||
y += l4_3;
|
||||
internal::ProjectTriangle(x, y);
|
||||
z = 1.0-x-y;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ProjectPentatope(double &x, double &y, double &z, double &t)
|
||||
{
|
||||
if (t < 0.0)
|
||||
{
|
||||
t = 0.0;
|
||||
internal::ProjectTetrahedron(x, y, z);
|
||||
return false;
|
||||
}
|
||||
if (z < 0.0)
|
||||
{
|
||||
z = 0.0;
|
||||
internal::ProjectTetrahedron(x, y, t);
|
||||
return false;
|
||||
}
|
||||
if (y < 0.0)
|
||||
{
|
||||
y = 0.0;
|
||||
internal::ProjectTetrahedron(x, z, t);
|
||||
return false;
|
||||
}
|
||||
if (x < 0.0)
|
||||
{
|
||||
x = 0.0;
|
||||
internal::ProjectTetrahedron(y, z, t);
|
||||
return false;
|
||||
}
|
||||
const double l5 = 1.0-x-y-z-t;
|
||||
if (l5 < 0.0)
|
||||
{
|
||||
const double l5_4 = l5/4;
|
||||
// TODO
|
||||
// In Geometry::ProjectPoint 4d origianlly had const double l5_4 = l5/5
|
||||
x += l5_4;
|
||||
y += l5_4;
|
||||
z += l5_4;
|
||||
internal::ProjectTetrahedron(x, y, z);
|
||||
t = 1.0-x-y-z;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// static method
|
||||
@@ -872,22 +675,6 @@ bool Geometry::ProjectPoint(int GeomType, const IntegrationPoint &beg,
|
||||
};
|
||||
return internal::IntersectSegment<6,3>(lbeg, lend, end);
|
||||
}
|
||||
case Geometry::PENTATOPE:
|
||||
{
|
||||
real_t lend[5] = { end.x, end.y, end.z, end.t, fone-end.x-end.y-end.z-end.t };
|
||||
real_t lbeg[5] = { beg.x, beg.y, beg.z, beg.t, fone-beg.x-beg.y-beg.z-beg.t };
|
||||
return internal::IntersectSegment<5,4>(lbeg,lend,end);
|
||||
}
|
||||
case Geometry::TESSERACT:
|
||||
{
|
||||
real_t lend[8] = { end.x, end.y, end.z, end.t,
|
||||
fone-end.x, fone-end.y, fone-end.z, fone-end.t
|
||||
};
|
||||
real_t lbeg[8] = { beg.x, beg.y, beg.z, beg.t,
|
||||
fone-beg.x, fone-beg.y, fone-beg.z, fone-beg.t
|
||||
};
|
||||
return internal::IntersectSegment<8,3>(lbeg, lend, end);
|
||||
}
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -930,7 +717,35 @@ bool Geometry::ProjectPoint(int GeomType, IntegrationPoint &ip)
|
||||
|
||||
case TETRAHEDRON:
|
||||
{
|
||||
return internal::ProjectTetrahedron(ip.x, ip.y, ip.z);
|
||||
if (ip.z < 0.0)
|
||||
{
|
||||
ip.z = 0.0;
|
||||
internal::ProjectTriangle(ip.x, ip.y);
|
||||
return false;
|
||||
}
|
||||
if (ip.y < 0.0)
|
||||
{
|
||||
ip.y = 0.0;
|
||||
internal::ProjectTriangle(ip.x, ip.z);
|
||||
return false;
|
||||
}
|
||||
if (ip.x < 0.0)
|
||||
{
|
||||
ip.x = 0.0;
|
||||
internal::ProjectTriangle(ip.y, ip.z);
|
||||
return false;
|
||||
}
|
||||
const real_t l4 = 1.0-ip.x-ip.y-ip.z;
|
||||
if (l4 < 0.0)
|
||||
{
|
||||
const real_t l4_3 = l4/3;
|
||||
ip.x += l4_3;
|
||||
ip.y += l4_3;
|
||||
internal::ProjectTriangle(ip.x, ip.y);
|
||||
ip.z = 1.0-ip.x-ip.y;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case CUBE:
|
||||
@@ -995,29 +810,6 @@ bool Geometry::ProjectPoint(int GeomType, IntegrationPoint &ip)
|
||||
}
|
||||
}
|
||||
|
||||
case PENTATOPE:
|
||||
{
|
||||
return internal::ProjectPentatope(ip.x, ip.y, ip.z, ip.t);
|
||||
}
|
||||
|
||||
case TESSERACT:
|
||||
{
|
||||
bool in_x, in_y, in_z, in_t;
|
||||
if (ip.x < 0.0) { in_x = false; ip.x = 0.0; }
|
||||
else if (ip.x > 1.0) { in_x = false; ip.x = 1.0; }
|
||||
else { in_x = true; }
|
||||
if (ip.y < 0.0) { in_y = false; ip.y = 0.0; }
|
||||
else if (ip.y > 1.0) { in_y = false; ip.y = 1.0; }
|
||||
else { in_y = true; }
|
||||
if (ip.z < 0.0) { in_z = false; ip.z = 0.0; }
|
||||
else if (ip.z > 1.0) { in_z = false; ip.z = 1.0; }
|
||||
else { in_z = true; }
|
||||
if (ip.t < 0.0) { in_t = false; ip.t = 0.0; }
|
||||
else if (ip.t > 1.0) { in_t = false; ip.t = 1.0; }
|
||||
else { in_t = true; }
|
||||
return in_x && in_y && in_z && in_t;
|
||||
}
|
||||
|
||||
case Geometry::POINT:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
case Geometry::INVALID:
|
||||
@@ -1106,42 +898,6 @@ void Geometry::GetPerfPointMat(int GeomType, DenseMatrix &pm) const
|
||||
}
|
||||
break;
|
||||
|
||||
case Geometry::PENTATOPE:
|
||||
{
|
||||
pm.SetSize(4,5);
|
||||
pm(0,0) = 0.0; pm(1,0) = 0.0; pm(2,0) = 0.0; pm(3,0) = 0.0;
|
||||
pm(0,1) = 1.0; pm(1,1) = 0.0; pm(2,1) = 0.0; pm(3,1) = 0.0;
|
||||
pm(0,2) = 0.5; pm(1,2) = 0.86602540378443864676; pm(2,2) = 0.0; pm(3,2) = 0.0;
|
||||
pm(0,3) = 0.5; pm(1,3) = 0.28867513459481288225;
|
||||
pm(2,3) = 0.81649658092772603273; pm(3,3) = 0.0;
|
||||
pm(0,4) = 0.5; pm(1,4) = 0.28867513459481288225;
|
||||
pm(2,4) = 0.20412414523193150819; pm(3,4) = 0.7905694150420948330;
|
||||
}
|
||||
break;
|
||||
|
||||
case Geometry::TESSERACT:
|
||||
{
|
||||
pm.SetSize (4, 16);
|
||||
pm(0,0) = 0.0; pm(1,0) = 0.0; pm(2,0) = 0.0; pm(4,0) = 0.0;
|
||||
pm(0,1) = 1.0; pm(1,1) = 0.0; pm(2,1) = 0.0; pm(4,1) = 0.0;
|
||||
pm(0,2) = 1.0; pm(1,2) = 1.0; pm(2,2) = 0.0; pm(4,2) = 0.0;
|
||||
pm(0,3) = 0.0; pm(1,3) = 1.0; pm(2,3) = 0.0; pm(4,3) = 0.0;
|
||||
pm(0,4) = 0.0; pm(1,4) = 0.0; pm(2,4) = 1.0; pm(4,4) = 0.0;
|
||||
pm(0,5) = 1.0; pm(1,5) = 0.0; pm(2,5) = 1.0; pm(4,5) = 0.0;
|
||||
pm(0,6) = 1.0; pm(1,6) = 1.0; pm(2,6) = 1.0; pm(4,6) = 0.0;
|
||||
pm(0,7) = 0.0; pm(1,7) = 1.0; pm(2,7) = 1.0; pm(4,7) = 0.0;
|
||||
|
||||
pm(0,8) = 0.0; pm(1,8) = 0.0; pm(2,8) = 0.0; pm(4,8) = 1.0;
|
||||
pm(0,9) = 1.0; pm(1,9) = 0.0; pm(2,9) = 0.0; pm(4,9) = 1.0;
|
||||
pm(0,10) = 1.0; pm(1,10) = 1.0; pm(2,10) = 0.0; pm(4,10) = 1.0;
|
||||
pm(0,11) = 0.0; pm(1,11) = 1.0; pm(2,11) = 0.0; pm(4,11) = 1.0;
|
||||
pm(0,12) = 0.0; pm(1,12) = 0.0; pm(2,12) = 1.0; pm(4,12) = 1.0;
|
||||
pm(0,13) = 1.0; pm(1,13) = 0.0; pm(2,13) = 1.0; pm(4,13) = 1.0;
|
||||
pm(0,14) = 1.0; pm(1,14) = 1.0; pm(2,14) = 1.0; pm(4,14) = 1.0;
|
||||
pm(0,15) = 0.0; pm(1,15) = 1.0; pm(2,15) = 1.0; pm(4,15) = 1.0;
|
||||
}
|
||||
break;
|
||||
|
||||
case Geometry::POINT:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
case Geometry::INVALID:
|
||||
@@ -1163,13 +919,13 @@ void Geometry::JacToPerfJac(int GeomType, const DenseMatrix &J,
|
||||
}
|
||||
}
|
||||
|
||||
const int Geometry::NumBdrArray[NumGeom] = { 0, 2, 3, 4, 4, 6, 5, 5, 5, 24 };
|
||||
const int Geometry::Dimension[NumGeom] = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4 };
|
||||
const int Geometry::DimStart[MaxDim+2] =
|
||||
{ POINT, SEGMENT, TRIANGLE, TETRAHEDRON, PENTATOPE, NUM_GEOMETRIES };
|
||||
const int Geometry::NumVerts[NumGeom] = { 1, 2, 3, 4, 4, 8, 6, 5, 5, 16 };
|
||||
const int Geometry::NumEdges[NumGeom] = { 0, 1, 3, 4, 6, 12, 9, 8, 10, 32 };
|
||||
const int Geometry::NumFaces[NumGeom] = { 0, 0, 1, 1, 4, 6, 5, 5, 5, 24 };
|
||||
const int Geometry::NumBdrArray[NumGeom] = { 0, 2, 3, 4, 4, 6, 5, 5 };
|
||||
const int Geometry::Dimension[NumGeom] = { 0, 1, 2, 2, 3, 3, 3, 3 };
|
||||
const int Geometry::DimStart[MaxDim+2] =
|
||||
{ POINT, SEGMENT, TRIANGLE, TETRAHEDRON, NUM_GEOMETRIES };
|
||||
const int Geometry::NumVerts[NumGeom] = { 1, 2, 3, 4, 4, 8, 6, 5 };
|
||||
const int Geometry::NumEdges[NumGeom] = { 0, 1, 3, 4, 6, 12, 9, 8 };
|
||||
const int Geometry::NumFaces[NumGeom] = { 0, 0, 1, 1, 4, 6, 5, 5 };
|
||||
|
||||
const int Geometry::
|
||||
Constants<Geometry::POINT>::Orient[1][1] = {{0}};
|
||||
@@ -1340,63 +1096,6 @@ Constants<Geometry::PYRAMID>::VertToVert::J[8][2] =
|
||||
{4, 7} // 3,4:7
|
||||
};
|
||||
|
||||
const int Geometry::
|
||||
Constants<Geometry::PENTATOPE>::Edges[10][2] =
|
||||
{{0, 1}, {0, 2}, {0, 3}, {0, 4}, {1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4}, {3, 4}};
|
||||
const int Geometry::
|
||||
Constants<Geometry::PENTATOPE>::FaceTypes[5] =
|
||||
{
|
||||
Geometry::TETRAHEDRON, Geometry::TETRAHEDRON,
|
||||
Geometry::TETRAHEDRON, Geometry::TETRAHEDRON,
|
||||
Geometry::TETRAHEDRON
|
||||
};
|
||||
const int Geometry::
|
||||
Constants<Geometry::PENTATOPE>::FaceVert[5][4] =
|
||||
{
|
||||
// {0, 1, 2, 3}, {0, 1, 2, 4},
|
||||
// {0, 1, 3, 4}, {0, 2, 3, 4},
|
||||
// {1, 2, 3, 4}
|
||||
{0, 1, 2, 3}, {0, 2, 1, 4}, //<---- sorted such that the normal vectors are outer normal vectors
|
||||
{0, 1, 3, 4}, {0, 3, 2, 4},
|
||||
{1, 2, 3, 4}
|
||||
};
|
||||
const int Geometry::
|
||||
Constants<Geometry::PENTATOPE>::PlanarVert[10][3] =
|
||||
{
|
||||
{0, 1, 2}, {0, 1, 3}, {0, 1, 4},
|
||||
{0, 2, 3}, {0, 2, 4}, {0, 3, 4},
|
||||
{1, 2, 3}, {1, 2, 4}, {1, 3, 4},
|
||||
{2, 3, 4}
|
||||
};
|
||||
|
||||
//const int Geometry::
|
||||
//Constants<Geometry::PENTATOPE>::VertToVert::I[4] = {0, 3, 5, 6};
|
||||
//const int Geometry::
|
||||
//Constants<Geometry::PENTATOPE>::VertToVert::J[6][2] =
|
||||
//{{1, 0}, {2, 1}, {3, 2}, {2, 3}, {3, 4}, {3, 5}};
|
||||
|
||||
|
||||
const int Geometry::
|
||||
Constants<Geometry::TESSERACT>::FaceVert[8][8] =
|
||||
{
|
||||
// {8,11,12,15,0,3,4,7}, //x bottom
|
||||
// {1,2,6,5,9,10,14,13}, //x top
|
||||
// {0,1,5,4,8,9,13,12}, //y bottom
|
||||
// {2,3,7,6,10,11,15,14}, //y top
|
||||
// {8,9,10,11,0,1,2,3}, // z bottom
|
||||
// {4,5,6,7,12,13,14,15}, //z top
|
||||
// {0,1,2,3,4,5,6,7}, //t botom
|
||||
// {12,13,14,15,8,9,10,11} //t top
|
||||
{8,11,15,12,0,3,7,4}, //x bottom
|
||||
{1,2,6,5,9,10,14,13}, //x top
|
||||
{0,1,5,4,8,9,13,12}, //y bottom
|
||||
{2,3,7,6,10,11,15,14}, //y top
|
||||
{8,9,10,11,0,1,2,3}, // z bottom
|
||||
{4,5,6,7,12,13,14,15}, //z top
|
||||
{0,1,2,3,4,5,6,7}, //t botom
|
||||
{12,13,14,15,8,9,10,11} //t top
|
||||
};
|
||||
|
||||
|
||||
GeometryRefiner::~GeometryRefiner()
|
||||
{
|
||||
@@ -1957,9 +1656,7 @@ RefinedGeometry *GeometryRefiner::Refine(Geometry::Type Geom, int Times,
|
||||
RGeom[Geometry::PRISM].Append(RG);
|
||||
}
|
||||
break;
|
||||
case Geometry::PENTATOPE:
|
||||
case Geometry::TESSERACT:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -2071,8 +1768,6 @@ const IntegrationRule *GeometryRefiner::RefineInterior(Geometry::Type Geom,
|
||||
case Geometry::CUBE:
|
||||
case Geometry::PYRAMID:
|
||||
case Geometry::PRISM:
|
||||
case Geometry::PENTATOPE:
|
||||
case Geometry::TESSERACT:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
@@ -2142,24 +1837,6 @@ int GeometryRefiner::GetRefinementLevelFromPoints(Geometry::Type geom, int Npts)
|
||||
}
|
||||
case Geometry::PYRAMID:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
case Geometry::PENTATOPE:
|
||||
{
|
||||
for (int n = 0, np = 0; (n < 15) && (np < Npts) ; n++)
|
||||
{
|
||||
np = (n+4)*(n+3)*(n+2)*(n+1)/24;
|
||||
if (np == Npts) { return n; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
case Geometry::TESSERACT:
|
||||
{
|
||||
for (int n = 0, np = 0; (n < 15) && (np < Npts) ; n++)
|
||||
{
|
||||
np = (n+1)*(n+1)*(n+1)*(n+1);
|
||||
if (np == Npts) { return n; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -2202,15 +1879,6 @@ int GeometryRefiner::GetRefinementLevelFromElems(Geometry::Type geom, int Nels)
|
||||
}
|
||||
case Geometry::PYRAMID:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
case Geometry::PENTATOPE:
|
||||
case Geometry::TESSERACT:
|
||||
{
|
||||
for (int n = 0; (n < 15) && (n*n*n*n < Nels+1) ; n++)
|
||||
{
|
||||
if (n*n*n*n == Nels) { return n-1; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
|
||||
+2
-52
@@ -28,8 +28,6 @@ namespace mfem
|
||||
Geometry::CUBE - the unit cube
|
||||
Geometry::PRISM - w/ vert. (0,0,0),(1,0,0),(0,1,0),(0,0,1),(1,0,1),(0,1,1)
|
||||
Geometry::PYRAMID - w/ vert. (0,0,0),(1,0,0),(1,1,0),(0,1,0),(0,0,1)
|
||||
Geometry::PENTATOPE - w/ vert. (0,0,0,0),(1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1)
|
||||
Geometry::TESSERACT - the 4d unit cube
|
||||
*/
|
||||
class MFEM_EXPORT Geometry
|
||||
{
|
||||
@@ -37,12 +35,12 @@ public:
|
||||
enum Type
|
||||
{
|
||||
INVALID = -1,
|
||||
POINT = 0, SEGMENT, TRIANGLE, SQUARE, TETRAHEDRON, CUBE, PRISM, PYRAMID, PENTATOPE, TESSERACT,
|
||||
POINT = 0, SEGMENT, TRIANGLE, SQUARE, TETRAHEDRON, CUBE, PRISM, PYRAMID,
|
||||
NUM_GEOMETRIES
|
||||
};
|
||||
|
||||
static const int NumGeom = NUM_GEOMETRIES;
|
||||
static const int MaxDim = 4;
|
||||
static const int MaxDim = 3;
|
||||
static const int NumBdrArray[NumGeom];
|
||||
static const char *Name[NumGeom];
|
||||
static const real_t Volume[NumGeom];
|
||||
@@ -120,7 +118,6 @@ public:
|
||||
case 1: return SEGMENT;
|
||||
case 2: return SQUARE;
|
||||
case 3: return CUBE;
|
||||
case 4: return TESSERACT;
|
||||
default: MFEM_ABORT("Invalid dimension."); return INVALID;
|
||||
}
|
||||
}
|
||||
@@ -308,53 +305,6 @@ template <> struct
|
||||
};
|
||||
};
|
||||
|
||||
template <> struct
|
||||
/// @cond Suppress_Doxygen_warnings
|
||||
MFEM_EXPORT
|
||||
/// @endcond
|
||||
Geometry::Constants<Geometry::PENTATOPE>
|
||||
{
|
||||
static const int Dimension = 4;
|
||||
static const int NumVert = 5;
|
||||
static const int NumEdges = 10;
|
||||
static const int Edges[NumEdges][2];
|
||||
static const int NumFaces = 5;
|
||||
static const int FaceTypes[NumFaces];
|
||||
static const int MaxFaceVert = 4;
|
||||
static const int FaceVert[NumFaces][MaxFaceVert];
|
||||
static const int NumPlanar = 10;
|
||||
static const int MaxPlanarVert = 3;
|
||||
static const int PlanarVert[NumPlanar][MaxPlanarVert];
|
||||
// Lower-triangular part of the local vertex-to-vertex graph.
|
||||
struct VertToVert
|
||||
{
|
||||
static const int I[NumVert];
|
||||
static const int J[NumEdges][2]; // {end,edge_idx}
|
||||
};
|
||||
};
|
||||
|
||||
template <> struct
|
||||
/// @cond Suppress_Doxygen_warnings
|
||||
MFEM_EXPORT
|
||||
/// @endcond
|
||||
Geometry::Constants<Geometry::TESSERACT>
|
||||
{
|
||||
static const int Dimension = 4;
|
||||
static const int NumVert = 16;
|
||||
static const int NumEdges = 32;
|
||||
static const int Edges[NumEdges][2];
|
||||
static const int NumFaces = 8;
|
||||
static const int FaceTypes[NumFaces];
|
||||
static const int MaxFaceVert = 8;
|
||||
static const int FaceVert[NumFaces][MaxFaceVert];
|
||||
// Lower-triangular part of the local vertex-to-vertex graph.
|
||||
struct VertToVert
|
||||
{
|
||||
static const int I[NumVert];
|
||||
static const int J[NumEdges][2]; // {end,edge_idx}
|
||||
};
|
||||
};
|
||||
|
||||
// Defined in fe.cpp to ensure construction after 'mfem::TriangleFE' and
|
||||
// `mfem::TetrahedronFE`.
|
||||
extern MFEM_EXPORT Geometry Geometries;
|
||||
|
||||
+53
-113
@@ -39,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();
|
||||
@@ -81,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)
|
||||
@@ -153,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,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
|
||||
@@ -349,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
|
||||
{
|
||||
@@ -1321,9 +1321,9 @@ void GridFunction::ProjectVectorFieldOn(GridFunction &vec_field, int comp)
|
||||
}
|
||||
}
|
||||
|
||||
void GridFunction::AccumulateAndCountDerivativeValues(
|
||||
int comp, int der_comp, GridFunction &der,
|
||||
Array<int> &zones_per_dof) const
|
||||
void GridFunction::AccumulateAndCountDerivativeValues(int comp, int der_comp,
|
||||
GridFunction &der,
|
||||
Array<int> &zones_per_dof)
|
||||
{
|
||||
FiniteElementSpace * der_fes = der.FESpace();
|
||||
ElementTransformation * transf;
|
||||
@@ -1374,8 +1374,7 @@ void GridFunction::AccumulateAndCountDerivativeValues(
|
||||
}
|
||||
}
|
||||
|
||||
void GridFunction::GetDerivative(int comp, int der_comp,
|
||||
GridFunction &der) const
|
||||
void GridFunction::GetDerivative(int comp, int der_comp, GridFunction &der)
|
||||
{
|
||||
Array<int> overlap;
|
||||
AccumulateAndCountDerivativeValues(comp, der_comp, der, overlap);
|
||||
@@ -2062,37 +2061,41 @@ void GridFunction::AccumulateAndCountBdrValues(
|
||||
Coefficient *coeff[], VectorCoefficient *vcoeff, const Array<int> &attr,
|
||||
Array<int> &values_counter)
|
||||
{
|
||||
int i, j, fdof, d, ind, vdim;
|
||||
real_t val;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *transf;
|
||||
Array<int> vdofs;
|
||||
Vector vc;
|
||||
|
||||
values_counter.SetSize(Size());
|
||||
values_counter = 0;
|
||||
|
||||
const int vdim = fes->GetVDim();
|
||||
vdim = fes->GetVDim();
|
||||
|
||||
HostReadWrite();
|
||||
|
||||
for (int i = 0; i < fes->GetNBE(); i++)
|
||||
for (i = 0; i < fes->GetNBE(); i++)
|
||||
{
|
||||
if (attr[fes->GetBdrAttribute(i) - 1] == 0) { continue; }
|
||||
|
||||
const FiniteElement *fe = fes->GetBE(i);
|
||||
const int fdof = fe->GetDof();
|
||||
ElementTransformation *transf = fes->GetBdrElementTransformation(i);
|
||||
fe = fes->GetBE(i);
|
||||
fdof = fe->GetDof();
|
||||
transf = fes->GetBdrElementTransformation(i);
|
||||
const IntegrationRule &ir = fe->GetNodes();
|
||||
fes->GetBdrElementVDofs(i, vdofs);
|
||||
|
||||
for (int j = 0; j < fdof; j++)
|
||||
for (j = 0; j < fdof; j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
if (vcoeff) { vcoeff->Eval(vc, *transf, ip); }
|
||||
for (int d = 0; d < vdim; d++)
|
||||
for (d = 0; d < vdim; d++)
|
||||
{
|
||||
if (!vcoeff && !coeff[d]) { continue; }
|
||||
|
||||
real_t val = vcoeff ? vc(d) : coeff[d]->Eval(*transf, ip);
|
||||
int ind = vdofs[fdof*d+j];
|
||||
if ( ind < 0 )
|
||||
val = vcoeff ? vc(d) : coeff[d]->Eval(*transf, ip);
|
||||
if ( (ind = vdofs[fdof*d+j]) < 0 )
|
||||
{
|
||||
val = -val, ind = -1-ind;
|
||||
}
|
||||
@@ -2114,38 +2117,37 @@ void GridFunction::AccumulateAndCountBdrValues(
|
||||
// iff A_ij != 0. It is sufficient to resolve just the first level of
|
||||
// dependency, since A is a projection matrix: A^n = A due to cR.cP = I.
|
||||
// Cases like these arise in 3D when boundary edges are constrained by
|
||||
// (depend on) internal faces/elements, or for internal boundaries in 2 or
|
||||
// 3D. We use the virtual method GetBoundaryClosure from NCMesh to resolve
|
||||
// the dependencies.
|
||||
if (fes->Nonconforming() && (fes->GetMesh()->Dimension() == 2 ||
|
||||
fes->GetMesh()->Dimension() == 3))
|
||||
// (depend on) internal faces/elements. We use the virtual method
|
||||
// GetBoundaryClosure from NCMesh to resolve the dependencies.
|
||||
|
||||
if (fes->Nonconforming() && fes->GetMesh()->Dimension() == 3)
|
||||
{
|
||||
Vector vals;
|
||||
Mesh *mesh = fes->GetMesh();
|
||||
NCMesh *ncmesh = mesh->ncmesh;
|
||||
Array<int> bdr_edges, bdr_vertices, bdr_faces, bdr_planars;
|
||||
// if (mesh->Dimension() < 4)
|
||||
// {
|
||||
ncmesh->GetBoundaryClosure(attr, bdr_vertices, bdr_edges, bdr_faces);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ncmesh->GetBoundaryClosure(attr, bdr_vertices, bdr_edges, bdr_faces, bdr_planars);
|
||||
// }
|
||||
Array<int> bdr_edges, bdr_vertices, bdr_faces;
|
||||
ncmesh->GetBoundaryClosure(attr, bdr_vertices, bdr_edges, bdr_faces);
|
||||
|
||||
auto mark_dofs = [&](ElementTransformation &transf, const FiniteElement &fe)
|
||||
for (i = 0; i < bdr_edges.Size(); i++)
|
||||
{
|
||||
int edge = bdr_edges[i];
|
||||
fes->GetEdgeVDofs(edge, vdofs);
|
||||
if (vdofs.Size() == 0) { continue; }
|
||||
|
||||
transf = mesh->GetEdgeTransformation(edge);
|
||||
transf->Attribute = -1; // TODO: set the boundary attribute
|
||||
fe = fes->GetEdgeElement(edge);
|
||||
if (!vcoeff)
|
||||
{
|
||||
vals.SetSize(fe.GetDof());
|
||||
for (int d = 0; d < vdim; d++)
|
||||
vals.SetSize(fe->GetDof());
|
||||
for (d = 0; d < vdim; d++)
|
||||
{
|
||||
if (!coeff[d]) { continue; }
|
||||
|
||||
fe.Project(*coeff[d], transf, vals);
|
||||
fe->Project(*coeff[d], *transf, vals);
|
||||
for (int k = 0; k < vals.Size(); k++)
|
||||
{
|
||||
const int ind = vdofs[d*vals.Size()+k];
|
||||
ind = vdofs[d*vals.Size()+k];
|
||||
if (++values_counter[ind] == 1)
|
||||
{
|
||||
(*this)(ind) = vals(k);
|
||||
@@ -2159,62 +2161,11 @@ void GridFunction::AccumulateAndCountBdrValues(
|
||||
}
|
||||
else // vcoeff != NULL
|
||||
{
|
||||
vals.SetSize(vdim*fe.GetDof());
|
||||
fe.Project(*vcoeff, transf, vals);
|
||||
vals.SetSize(vdim*fe->GetDof());
|
||||
fe->Project(*vcoeff, *transf, vals);
|
||||
for (int k = 0; k < vals.Size(); k++)
|
||||
{
|
||||
const int ind = vdofs[k];
|
||||
if (++values_counter[ind] == 1)
|
||||
{
|
||||
(*this)(ind) = vals(k);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*this)(ind) += vals(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (auto edge : bdr_edges)
|
||||
{
|
||||
fes->GetEdgeVDofs(edge, vdofs);
|
||||
if (vdofs.Size() == 0) { continue; }
|
||||
|
||||
ElementTransformation *transf = mesh->GetEdgeTransformation(edge);
|
||||
const FiniteElement *fe = fes->GetEdgeElement(edge);
|
||||
mark_dofs(*transf, *fe);
|
||||
}
|
||||
|
||||
for (auto face : bdr_faces)
|
||||
{
|
||||
fes->GetFaceVDofs(face, vdofs);
|
||||
if (vdofs.Size() == 0) { continue; }
|
||||
|
||||
ElementTransformation *transf = mesh->GetFaceTransformation(face);
|
||||
const FiniteElement *fe = fes->GetFaceElement(face);
|
||||
mark_dofs(*transf, *fe);
|
||||
}
|
||||
for (int i = 0; i < bdr_planars.Size(); i++)
|
||||
{
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *transf;
|
||||
int planar = bdr_planars[i];
|
||||
fes->GetPlanarVDofs(planar, vdofs);
|
||||
if (vdofs.Size() == 0) { continue; }
|
||||
|
||||
transf = mesh->GetPlanarTransformation(planar);
|
||||
transf->Attribute = -1; // FIXME: set the boundary attribute
|
||||
fe = fes->GetPlanarElement(planar);
|
||||
vals.SetSize(fe->GetDof());
|
||||
for (int d = 0; d < vdim; d++)
|
||||
{
|
||||
if (!coeff[d]) { continue; }
|
||||
|
||||
fe->Project(*coeff[d], *transf, vals);
|
||||
for (int k = 0; k < vals.Size(); k++)
|
||||
{
|
||||
int ind = vdofs[d*vals.Size()+k];
|
||||
ind = vdofs[k];
|
||||
if (++values_counter[ind] == 1)
|
||||
{
|
||||
(*this)(ind) = vals(k);
|
||||
@@ -2277,37 +2228,26 @@ void GridFunction::AccumulateAndCountBdrTangentValues(
|
||||
accumulate_dofs(dofs, lvec, *this, values_counter);
|
||||
}
|
||||
|
||||
if (fes->Nonconforming() && (fes->GetMesh()->Dimension() == 2 ||
|
||||
fes->GetMesh()->Dimension() == 3))
|
||||
if (fes->Nonconforming() && fes->GetMesh()->Dimension() == 3)
|
||||
{
|
||||
Mesh *mesh = fes->GetMesh();
|
||||
NCMesh *ncmesh = mesh->ncmesh;
|
||||
Array<int> bdr_edges, bdr_vertices, bdr_faces;
|
||||
ncmesh->GetBoundaryClosure(bdr_attr, bdr_vertices, bdr_edges, bdr_faces);
|
||||
|
||||
for (auto edge : bdr_edges)
|
||||
for (int i = 0; i < bdr_edges.Size(); i++)
|
||||
{
|
||||
int edge = bdr_edges[i];
|
||||
fes->GetEdgeDofs(edge, dofs);
|
||||
if (dofs.Size() == 0) { continue; }
|
||||
|
||||
T = mesh->GetEdgeTransformation(edge);
|
||||
T->Attribute = -1; // TODO: set the boundary attribute
|
||||
fe = fes->GetEdgeElement(edge);
|
||||
lvec.SetSize(fe->GetDof());
|
||||
fe->Project(vcoeff, *T, lvec);
|
||||
accumulate_dofs(dofs, lvec, *this, values_counter);
|
||||
}
|
||||
|
||||
for (auto face : bdr_faces)
|
||||
{
|
||||
fes->GetFaceDofs(face, dofs);
|
||||
if (dofs.Size() == 0) { continue; }
|
||||
|
||||
T = mesh->GetFaceTransformation(face);
|
||||
fe = fes->GetFaceElement(face);
|
||||
lvec.SetSize(fe->GetDof());
|
||||
fe->Project(vcoeff, *T, lvec);
|
||||
accumulate_dofs(dofs, lvec, *this, values_counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3964,7 +3904,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
-13
@@ -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;
|
||||
@@ -321,7 +321,7 @@ public:
|
||||
@param[out] der The resulting derivative (scalar function). The
|
||||
FiniteElementSpace of this function must be set
|
||||
before the call. */
|
||||
void GetDerivative(int comp, int der_comp, GridFunction &der) const;
|
||||
void GetDerivative(int comp, int der_comp, GridFunction &der);
|
||||
|
||||
real_t GetDivergence(ElementTransformation &tr) const;
|
||||
|
||||
@@ -443,7 +443,7 @@ protected:
|
||||
GetDerivative() method; see its documentation. */
|
||||
void AccumulateAndCountDerivativeValues(int comp, int der_comp,
|
||||
GridFunction &der,
|
||||
Array<int> &zones_per_dof) const;
|
||||
Array<int> &zones_per_dof);
|
||||
|
||||
void AccumulateAndCountBdrValues(Coefficient *coeff[],
|
||||
VectorCoefficient *vcoeff,
|
||||
|
||||
@@ -1352,85 +1352,6 @@ void OversetFindPointsGSLIB::Interpolate(const Vector &point_pos,
|
||||
Interpolate(field_in, field_out);
|
||||
}
|
||||
|
||||
GSOPGSLIB::GSOPGSLIB(Array<long long> &ids)
|
||||
{
|
||||
gsl_comm = new gslib::comm;
|
||||
cr = new gslib::crystal;
|
||||
#ifdef MFEM_USE_MPI
|
||||
int initialized;
|
||||
MPI_Initialized(&initialized);
|
||||
if (!initialized) { MPI_Init(NULL, NULL); }
|
||||
MPI_Comm comm = MPI_COMM_WORLD;
|
||||
comm_init(gsl_comm, comm);
|
||||
#else
|
||||
comm_init(gsl_comm, 0);
|
||||
#endif
|
||||
crystal_init(cr, gsl_comm);
|
||||
UpdateIdentifiers(ids);
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
GSOPGSLIB::GSOPGSLIB(MPI_Comm comm_, Array<long long> &ids)
|
||||
: cr(NULL), gsl_comm(NULL)
|
||||
{
|
||||
gsl_comm = new gslib::comm;
|
||||
cr = new gslib::crystal;
|
||||
comm_init(gsl_comm, comm_);
|
||||
crystal_init(cr, gsl_comm);
|
||||
UpdateIdentifiers(ids);
|
||||
}
|
||||
#endif
|
||||
|
||||
GSOPGSLIB::~GSOPGSLIB()
|
||||
{
|
||||
crystal_free(cr);
|
||||
gslib_gs_free(gsl_data);
|
||||
comm_free(gsl_comm);
|
||||
delete gsl_comm;
|
||||
delete cr;
|
||||
}
|
||||
|
||||
void GSOPGSLIB::UpdateIdentifiers(const Array<long long> &ids)
|
||||
{
|
||||
long long minval = ids.Min();
|
||||
#ifdef MFEM_USE_MPI
|
||||
MPI_Allreduce(MPI_IN_PLACE, &minval, 1, MPI_LONG_LONG_INT,
|
||||
MPI_MIN, gsl_comm->c);
|
||||
#endif
|
||||
MFEM_VERIFY(minval >= 0, "Unique identifier cannot be negative.");
|
||||
if (gsl_data != NULL) { gslib_gs_free(gsl_data); }
|
||||
num_ids = ids.Size();
|
||||
gsl_data = gslib_gs_setup(ids.GetData(),
|
||||
ids.Size(),
|
||||
gsl_comm, 0,
|
||||
gslib::gs_crystal_router, 0);
|
||||
}
|
||||
|
||||
void GSOPGSLIB::GS(Vector &senddata, GSOp op)
|
||||
{
|
||||
MFEM_VERIFY(senddata.Size() == num_ids,
|
||||
"Incompatible setup and GOP operation.");
|
||||
if (op == GSOp::ADD)
|
||||
{
|
||||
gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_add,0,gsl_data,0);
|
||||
}
|
||||
else if (op == GSOp::MUL)
|
||||
{
|
||||
gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_mul,0,gsl_data,0);
|
||||
}
|
||||
else if (op == GSOp::MAX)
|
||||
{
|
||||
gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_max,0,gsl_data,0);
|
||||
}
|
||||
else if (op == GSOp::MIN)
|
||||
{
|
||||
gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_min,0,gsl_data,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Invalid GSOp operation.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
|
||||
+1
-62
@@ -23,16 +23,13 @@ struct comm;
|
||||
struct findpts_data_2;
|
||||
struct findpts_data_3;
|
||||
struct crystal;
|
||||
struct gs_data;
|
||||
}
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/** \brief FindPointsGSLIB can robustly evaluate a GridFunction on an arbitrary
|
||||
* collection of points.
|
||||
*
|
||||
* There are three key functions in FindPointsGSLIB:
|
||||
* collection of points. There are three key functions in FindPointsGSLIB:
|
||||
*
|
||||
* 1. Setup - constructs the internal data structures of gslib.
|
||||
*
|
||||
@@ -229,7 +226,6 @@ public:
|
||||
|
||||
/** \brief OversetFindPointsGSLIB enables use of findpts for arbitrary number of
|
||||
overlapping grids.
|
||||
|
||||
The parameters in this class are the same as FindPointsGSLIB with the
|
||||
difference of additional inputs required to account for more than 1 mesh. */
|
||||
class OversetFindPointsGSLIB : public FindPointsGSLIB
|
||||
@@ -294,63 +290,6 @@ public:
|
||||
using FindPointsGSLIB::Interpolate;
|
||||
};
|
||||
|
||||
/** \brief Class for gather-scatter (gs) operations on Vectors based on
|
||||
corresponding global identifiers.
|
||||
|
||||
This functionality is useful for gs-ops on DOF values across processor
|
||||
boundary, where the global identifier would be the corresponding true DOF
|
||||
index. Operations currently supported are min, max, sum, and multiplication.
|
||||
Note: identifier 0 does not participate in the gather-scatter operation and
|
||||
a given identifier can be included multiple times on a given rank.
|
||||
For example, consider a vector, v:
|
||||
- v = [0.3, 0.4, 0.25, 0.7] on rank1,
|
||||
- v = [0.6, 0.1] on rank 2,
|
||||
- v = [-0.2, 0.3, 0.7, 0.] on rank 3.
|
||||
|
||||
Consider a corresponding Array<int>, a:
|
||||
- a = [1, 2, 3, 1] on rank 1,
|
||||
- a = [3, 2] on rank 2,
|
||||
- a = [1, 2, 0, 3] on rank 3.
|
||||
|
||||
A gather-scatter "minimum" operation, done as follows:
|
||||
GSOPGSLIB gs = GSOPGSLIB(MPI_COMM_WORLD, a);
|
||||
gs.GS(v, GSOp::MIN);
|
||||
would return into v:
|
||||
- v = [-0.2, 0.1, 0., -0.2] on rank 1,
|
||||
- v = [0., 0.1] on rank 2,
|
||||
- v = [-0.2, 0.1, 0.7, 0.] on rank 3,
|
||||
where the values have been compared across all processors based on the
|
||||
integer identifier. */
|
||||
class GSOPGSLIB
|
||||
{
|
||||
protected:
|
||||
struct gslib::crystal *cr; // gslib's internal data
|
||||
struct gslib::comm *gsl_comm; // gslib's internal data
|
||||
struct gslib::gs_data *gsl_data = NULL;
|
||||
int num_ids;
|
||||
|
||||
public:
|
||||
GSOPGSLIB(Array<long long> &ids);
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
GSOPGSLIB(MPI_Comm comm_, Array<long long> &ids);
|
||||
#endif
|
||||
|
||||
virtual ~GSOPGSLIB();
|
||||
|
||||
/// Supported operation types. See class description.
|
||||
enum GSOp {ADD, MUL, MIN, MAX};
|
||||
|
||||
/// Update the identifiers used for the gather-scatter operator.
|
||||
/// Same @a ids get grouped together and id == 0 does not participate.
|
||||
/// See class description.
|
||||
void UpdateIdentifiers(const Array<long long> &ids);
|
||||
|
||||
/// Gather-Scatter operation on senddata. Must match length of unique
|
||||
/// identifiers used in the constructor. See class description.
|
||||
void GS(Vector &senddata, GSOp op);
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_USE_GSLIB
|
||||
|
||||
+6
-5
@@ -18,6 +18,7 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
|
||||
void HyperbolicFormIntegrator::AssembleElementVector(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
const Vector &elfun,
|
||||
@@ -28,7 +29,7 @@ void HyperbolicFormIntegrator::AssembleElementVector(const FiniteElement &el,
|
||||
const int dof = el.GetDof();
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
// Local storages for element integration
|
||||
|
||||
// shape function value at an integration point
|
||||
Vector shape(dof);
|
||||
@@ -61,7 +62,7 @@ void HyperbolicFormIntegrator::AssembleElementVector(const FiniteElement &el,
|
||||
ir = &IntRules.Get(Tr.GetGeometryType(), order);
|
||||
}
|
||||
|
||||
// loop over integration points
|
||||
// loop over interation points
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
@@ -91,7 +92,7 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
|
||||
const int dof2 = el2.GetDof();
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
// Local storages for element integration
|
||||
|
||||
// shape function value at an integration point - first elem
|
||||
Vector shape1(dof1);
|
||||
@@ -121,7 +122,7 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
|
||||
DenseMatrix elvect2_mat(elvect.GetData() + dof1 * num_equations, dof2,
|
||||
num_equations);
|
||||
|
||||
// Obtain integration rule. If integration is rule is given, then use it.
|
||||
// obtain integration rule. If integration is rule is given, then use it.
|
||||
// Otherwise, get (2*p + IntOrderOffset) order integration rule
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
@@ -148,7 +149,7 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
|
||||
if (nor.Size() == 1) // if 1D, use 1 or -1.
|
||||
{
|
||||
// This assume the 1D integration point is in (0,1). This may not work
|
||||
// if this changes.
|
||||
// if this chages.
|
||||
nor(0) = (Tr.GetElement1IntPoint().x - 0.5) * 2.0;
|
||||
}
|
||||
else
|
||||
|
||||
+34
-27
@@ -18,36 +18,43 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// This file contains general hyperbolic conservation element/face form
|
||||
// integrators. HyperbolicFormIntegrator and RiemannSolver are defined.
|
||||
// MFEM Hyperbolic Conservation Laws
|
||||
//
|
||||
// HyperbolicFormIntegrator is a NonlinearFormIntegrator that implements
|
||||
// element weak divergence and interface flux
|
||||
// Description:
|
||||
//
|
||||
// ∫_T F(u):∇v, -∫_e F̂(u)⋅[[v]]
|
||||
// This file contains general hyperbolic conservation element/face form
|
||||
// integrators.
|
||||
//
|
||||
// Here, T is an element, e is an edge, and [[⋅]] is jump. This form integrator
|
||||
// is coupled with RiemannSolver that implements the numerical flux F̂. For
|
||||
// RiemannSolver, the Rusanov flux, also known as local Lax-Friedrichs flux, is
|
||||
// provided.
|
||||
// HyperbolicFormIntegrator and RiemannSolver are defined.
|
||||
// HyperbolicFormIntegrator is a NonlinearFormIntegrator that implements
|
||||
// element weak divergence and interface flux
|
||||
//
|
||||
// To implement a specific hyperbolic conservation laws, users can create
|
||||
// derived classes from FluxFunction with overloaded ComputeFlux. One can
|
||||
// optionally overload ComputeFluxDotN to avoid creating dense matrix when
|
||||
// computing normal flux. Several example equations are also defined including:
|
||||
// advection, Burgers', shallow water, and Euler equations. Users can control
|
||||
// the quadrature rule by either providing the integration rule, or integration
|
||||
// order offset. Integration will use 2*p + IntOrderOffset order quadrature
|
||||
// rule.
|
||||
// ∫_T F(u):∇v, -∫_e F̂(u)⋅[[v]]
|
||||
//
|
||||
// At each call of HyperbolicFormIntegrator::AssembleElementVector
|
||||
// HyperbolicFormIntegrator::AssembleFaceVector, the maximum characteristic
|
||||
// speed will be updated. This will not be reinitialized automatically. To
|
||||
// reinitialize, use HyperbolicFormIntegrator::ResetMaxCharSpeed. See, ex18.hpp.
|
||||
// Here, T is an element, e is an edge, and [[⋅]] is jump. This form
|
||||
// integrator is coupled with RiemannSolver that implements the numerical
|
||||
// flux F̂. For RiemannSolver, the Rusanov flux, also known as local
|
||||
// Lax-Friedrichs flux, is provided.
|
||||
//
|
||||
// To implement a specific hyperbolic conservation laws, users can create
|
||||
// derived classes from FluxFunction with overloaded ComputeFlux. One can
|
||||
// optionally overload ComputeFluxDotN to avoid creating dense matrix when
|
||||
// computing normal flux. Several example equations are also defined
|
||||
// including: advection, Burgers', shallow water, and Euler equations. Users
|
||||
// can control the quadrature rule by either providing the integration rule,
|
||||
// or integration order offset. Integration will use 2*p + IntOrderOffset
|
||||
// order quadrature rule.
|
||||
//
|
||||
// At each call of HyperbolicFormIntegrator::AssembleElementVector
|
||||
// HyperbolicFormIntegrator::AssembleFaceVector, the maximum characteristic
|
||||
// speed will be updated. This will not be reinitialized automatically.
|
||||
// To reinitialize, use HyperbolicFormIntegrator::ResetMaxCharSpeed. See,
|
||||
// ex18.hpp.
|
||||
//
|
||||
// Note: To avoid communication overhead, we update the maximum
|
||||
// characteristic speed within each process. Use a proper MPI routine to
|
||||
// gather the information.
|
||||
//
|
||||
// Note: To avoid communication overhead, we update the maximum characteristic
|
||||
// speed within each MPI process only. Use the appropriate MPI routine to gather
|
||||
// the information.
|
||||
|
||||
/**
|
||||
* @brief Abstract class for hyperbolic flux for a system of hyperbolic
|
||||
@@ -81,7 +88,7 @@ public:
|
||||
virtual real_t ComputeFlux(const Vector &state, ElementTransformation &Tr,
|
||||
DenseMatrix &flux) const = 0;
|
||||
/**
|
||||
* @brief Compute normal flux. Optionally overloaded in the
|
||||
* @brief Compute normal flux. Optionally overloadded in the
|
||||
* derived class to avoid creating full dense matrix for flux.
|
||||
*
|
||||
* @param[in] state state at the current integration point
|
||||
@@ -161,13 +168,13 @@ protected:
|
||||
class HyperbolicFormIntegrator : public NonlinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
// The maximum characteristic speed, updated during element/face vector assembly
|
||||
// The maximum characterstic speed, updated during element/face vector assembly
|
||||
real_t max_char_speed;
|
||||
const RiemannSolver &rsolver; // Numerical flux that maps F(u±,x) to hat(F)
|
||||
const FluxFunction &fluxFunction;
|
||||
const int IntOrderOffset; // integration order offset, 2*p + IntOrderOffset.
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
// Local storages for element integration
|
||||
Vector shape; // shape function value at an integration point
|
||||
Vector state; // state value at an integration point
|
||||
DenseMatrix flux; // flux value at an integration point
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -563,7 +563,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_fullQuadrature(
|
||||
cdofs.SetSize(maxw[0], maxw[1], maxw[2]);
|
||||
|
||||
// Compute sparsity of the sparse matrix
|
||||
smati = Memory<int>(ndof+1);
|
||||
smati = new int[ndof+1];
|
||||
smati[0] = 0;
|
||||
|
||||
for (int dof_j=0; dof_j<ndof; ++dof_j)
|
||||
@@ -586,8 +586,8 @@ void DiffusionIntegrator::AssemblePatchMatrix_fullQuadrature(
|
||||
nnz += ndd;
|
||||
}
|
||||
|
||||
smatj = Memory<int>(nnz);
|
||||
smata = Memory<real_t>(nnz);
|
||||
smatj = new int[nnz];
|
||||
smata = new real_t[nnz];
|
||||
|
||||
for (int i=0; i<nnz; ++i)
|
||||
{
|
||||
@@ -973,7 +973,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
|
||||
cdofs.SetSize(maxw[0], maxw[1], maxw[2]);
|
||||
|
||||
// Compute sparsity of the sparse matrix
|
||||
smati = Memory<int>(ndof+1);
|
||||
smati = new int[ndof+1];
|
||||
smati[0] = 0;
|
||||
|
||||
for (int dof_j=0; dof_j<ndof; ++dof_j)
|
||||
@@ -996,8 +996,8 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
|
||||
nnz += ndd;
|
||||
}
|
||||
|
||||
smatj = Memory<int>(nnz);
|
||||
smata = Memory<real_t>(nnz);
|
||||
smatj = new int[nnz];
|
||||
smata = new real_t[nnz];
|
||||
|
||||
for (int i=0; i<nnz; ++i)
|
||||
{
|
||||
|
||||
@@ -157,7 +157,7 @@ void ElasticityAddMultPA_(const int nDofs, const FiniteElementSpace &fespace,
|
||||
static constexpr int aSize = aUpper-aLower;
|
||||
static constexpr bool isComponent = (i_block >= 0);
|
||||
|
||||
// Assuming all elements are the same
|
||||
//Assuming all elements are the same
|
||||
const auto &ir = QVec.GetIntRule(0);
|
||||
const QuadratureInterpolator *E_To_Q_Map = fespace.GetQuadratureInterpolator(
|
||||
ir);
|
||||
@@ -180,7 +180,7 @@ void ElasticityAddMultPA_(const int nDofs, const FiniteElementSpace &fespace,
|
||||
auto invJ = inv(make_tensor<d, d>(
|
||||
[&](int i, int j) { return J(p, i, j, e); }));
|
||||
tensor<real_t, aSize, d> gradx;
|
||||
// load grad(x) into gradx
|
||||
//load grad(x) into gradx
|
||||
if (isComponent)
|
||||
{
|
||||
for (int i = 0; i < d; i++)
|
||||
@@ -198,11 +198,11 @@ void ElasticityAddMultPA_(const int nDofs, const FiniteElementSpace &fespace,
|
||||
}
|
||||
}
|
||||
}
|
||||
// compute divergence
|
||||
//compute divergence
|
||||
real_t div = 0.;
|
||||
for (int i = aLower; i < aUpper; i++)
|
||||
{
|
||||
// take size of gradx into account
|
||||
//take size of gradx into account
|
||||
const int iIndex = isComponent ? 0 : i;
|
||||
div += gradx(iIndex,i);
|
||||
}
|
||||
@@ -211,11 +211,11 @@ void ElasticityAddMultPA_(const int nDofs, const FiniteElementSpace &fespace,
|
||||
{
|
||||
for (int q = qLower; q < qUpper; q++)
|
||||
{
|
||||
// compute contraction of 4*sym(grad(u))sym(grad(v)) term.
|
||||
// this contraction could be made slightly cheaper using Voigt
|
||||
// notation, but repeated entries are summed for simplicity.
|
||||
//compute contraction of 4*sym(grad(u))sym(grad(v)) term.
|
||||
//this contraction could be made slightly cheaper using Voigt
|
||||
//notation, but repeated entries are summed for simplicity.
|
||||
real_t contraction = 0.;
|
||||
// not sure how to combine cases
|
||||
//not sure how to combine cases
|
||||
if (isComponent)
|
||||
{
|
||||
for (int a = 0; a < d; a++)
|
||||
@@ -276,7 +276,7 @@ void ElasticityAssembleDiagonalPA_(const int nDofs,
|
||||
const CoefficientVector &mu, const GeometricFactors &geom,
|
||||
const DofToQuad &maps, QuadratureFunction &QVec, Vector &diag)
|
||||
{
|
||||
// Assuming all elements are the same
|
||||
//Assuming all elements are the same
|
||||
const auto &ir = QVec.GetIntRule(0);
|
||||
static constexpr int d = dim;
|
||||
const int numPoints = ir.GetNPoints();
|
||||
@@ -299,9 +299,9 @@ void ElasticityAssembleDiagonalPA_(const int nDofs,
|
||||
{
|
||||
for (int q = 0; q < d; q++)
|
||||
{
|
||||
// compute contraction of 4*sym(grad(u))sym(grad(v)) term.
|
||||
// this contraction could be made slightly cheaper using Voigt
|
||||
// notation, but repeated entries are summed for simplicity.
|
||||
//compute contraction of 4*sym(grad(u))sym(grad(v)) term.
|
||||
//this contraction could be made slightly cheaper using Voigt
|
||||
//notation, but repeated entries are summed for simplicity.
|
||||
real_t contraction = 0.;
|
||||
for (int a = 0; a < d; a++)
|
||||
{
|
||||
@@ -321,7 +321,7 @@ void ElasticityAssembleDiagonalPA_(const int nDofs,
|
||||
}
|
||||
});
|
||||
|
||||
// Reduce quadrature function to an E-Vector
|
||||
//Reduce quadrature function to an E-Vector
|
||||
const auto QRead = Reshape(QVec.Read(), numPoints, d, d, d, numEls);
|
||||
auto diagDev = Reshape(diag.Write(), nDofs, d, numEls);
|
||||
const auto G = Reshape(maps.G.Read(), numPoints, d, nDofs);
|
||||
@@ -348,7 +348,7 @@ void ElasticityAssembleDiagonalPA_(const int nDofs,
|
||||
});
|
||||
}
|
||||
|
||||
// Templated implementation of ElasticityAssembleEA.
|
||||
//Templated implementation of ElasticityAssembleEA.
|
||||
template<int dim>
|
||||
void ElasticityAssembleEA_(const int i_block,
|
||||
const int j_block,
|
||||
@@ -360,7 +360,7 @@ void ElasticityAssembleEA_(const int i_block,
|
||||
const DofToQuad &maps,
|
||||
Vector &emat)
|
||||
{
|
||||
// Assuming all elements are the same
|
||||
//Assuming all elements are the same
|
||||
static constexpr int d = dim;
|
||||
const int numPoints = ir.GetNPoints();
|
||||
const int numEls = lambda.Size()/numPoints;
|
||||
@@ -386,7 +386,7 @@ void ElasticityAssembleEA_(const int i_block,
|
||||
{
|
||||
for (int m = 0; m < d; m++)
|
||||
{
|
||||
// compute contraction of 4*sym(grad(u))sym(grad(v)) term.
|
||||
//compute contraction of 4*sym(grad(u))sym(grad(v)) term.
|
||||
real_t contraction = 0.;
|
||||
for (int a = 0; a < d; a++)
|
||||
{
|
||||
|
||||
+1
-194
@@ -151,14 +151,10 @@ void IntegrationRule::GrundmannMollerSimplexRule(int s, int n)
|
||||
ip.weight = weight;
|
||||
ip.x = real_t(2*beta[0] + 1)/(d + n - 2*i);
|
||||
ip.y = real_t(2*beta[1] + 1)/(d + n - 2*i);
|
||||
if (n >= 3)
|
||||
if (n == 3)
|
||||
{
|
||||
ip.z = real_t(2*beta[2] + 1)/(d + n - 2*i);
|
||||
}
|
||||
if (n == 4)
|
||||
{
|
||||
ip.t = real_t(2*beta[3] + 1)/(d + n - 2*i);
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
while (sums[j] == k)
|
||||
@@ -998,12 +994,6 @@ IntegrationRules::IntegrationRules(int ref, int type)
|
||||
CubeIntRules.SetSize(32, h_mt);
|
||||
CubeIntRules = NULL;
|
||||
|
||||
PentatopeIntRules.SetSize(32, h_mt);
|
||||
PentatopeIntRules = NULL;
|
||||
|
||||
TesseractIntRules.SetSize(32, h_mt);
|
||||
TesseractIntRules = NULL;
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
IntRuleLocks.SetSize(Geometry::NUM_GEOMETRIES, h_mt);
|
||||
for (int i = 0; i < Geometry::NUM_GEOMETRIES; i++)
|
||||
@@ -1027,8 +1017,6 @@ const IntegrationRule &IntegrationRules::Get(int GeomType, int Order)
|
||||
case Geometry::CUBE: ir_array = &CubeIntRules; break;
|
||||
case Geometry::PRISM: ir_array = &PrismIntRules; break;
|
||||
case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
|
||||
case Geometry::PENTATOPE: ir_array = &PentatopeIntRules; break;
|
||||
case Geometry::TESSERACT: ir_array = &TesseractIntRules; break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -1079,8 +1067,6 @@ void IntegrationRules::Set(int GeomType, int Order, IntegrationRule &IntRule)
|
||||
case Geometry::CUBE: ir_array = &CubeIntRules; break;
|
||||
case Geometry::PRISM: ir_array = &PrismIntRules; break;
|
||||
case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
|
||||
case Geometry::PENTATOPE: ir_array = &PentatopeIntRules; break;
|
||||
case Geometry::TESSERACT: ir_array = &TesseractIntRules; break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -1139,8 +1125,6 @@ IntegrationRules::~IntegrationRules()
|
||||
DeleteIntRuleArray(CubeIntRules);
|
||||
DeleteIntRuleArray(PrismIntRules);
|
||||
DeleteIntRuleArray(PyramidIntRules);
|
||||
DeleteIntRuleArray(PentatopeIntRules);
|
||||
DeleteIntRuleArray(TesseractIntRules);
|
||||
}
|
||||
|
||||
|
||||
@@ -1165,10 +1149,6 @@ IntegrationRule *IntegrationRules::GenerateIntegrationRule(int GeomType,
|
||||
return PrismIntegrationRule(Order);
|
||||
case Geometry::PYRAMID:
|
||||
return PyramidIntegrationRule(Order);
|
||||
case Geometry::PENTATOPE:
|
||||
return PentatopeIntegrationRule(Order);
|
||||
case Geometry::TESSERACT:
|
||||
return TesseractIntegrationRule(Order);
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -1882,179 +1862,6 @@ IntegrationRule *IntegrationRules::CubeIntegrationRule(int Order)
|
||||
return CubeIntRules[Order];
|
||||
}
|
||||
|
||||
IntegrationRule *IntegrationRules::PentatopeIntegrationRule(int Order)
|
||||
{
|
||||
IntegrationRule *ir;
|
||||
|
||||
#ifdef MFEM_DEBUG_INTRULES
|
||||
mfem::out << "requesting integration rules for pentatopes ( order = " << Order << " )!" << endl;
|
||||
#endif
|
||||
|
||||
switch (Order)
|
||||
{
|
||||
case 0: // 1 point - degree 1
|
||||
case 1:
|
||||
PentatopeIntRules[0] = PentatopeIntRules[1] = ir = new IntegrationRule(1);
|
||||
ir->AddPentMidPoint(0, 1./24.);
|
||||
ir->SetOrder(1);
|
||||
return ir;
|
||||
|
||||
case 2: // 5 points - degree 2 -- taken from https://doi.org/10.1016/j.camwa.2020.07.004
|
||||
PentatopeIntRules[2] = ir = new IntegrationRule(5);
|
||||
ir->AddPentPoints5(0, 0.11835034190722738822731940899757, 1/120.);
|
||||
ir->SetOrder(2);
|
||||
return ir;
|
||||
|
||||
case 3: // 15 points - degree 3 -- taken from https://doi.org/10.1016/j.camwa.2020.07.004
|
||||
PentatopeIntRules[3] = ir = new IntegrationRule(15);
|
||||
ir->AddPentPoints5(0, 0.05666638104005152637432374262971, 0.01971744594977651449108080328187 / 24.);
|
||||
ir->AddPentPoints10(5, 0.08282378463560803594223358459203, 0.5 - 1.5 * 0.08282378463560803594223358459203, 0.09014127702511173789723386562400 / 24.);
|
||||
ir->SetOrder(3);
|
||||
return ir;
|
||||
|
||||
case 4: // 35 points - degree 5 -- taken from https://doi.org/10.1016/j.camwa.2020.07.004
|
||||
case 5:
|
||||
PentatopeIntRules[4] = PentatopeIntRules[5] = ir = new IntegrationRule(35);
|
||||
ir->AddPentPoints5(0, 0.08639272923225102540634168235556, 0.05144687284129603743743075483508 / 24.);
|
||||
ir->AddPentPoints10(5, 0.02401496720062019571417799568280, 0.5 - 1.5 * 0.02401496720062019571417799568280, 0.01075810672318828174753857496171 / 24.);
|
||||
ir->AddPentPoints20(15, 0.29381800402893687440553094347706, 0.06247517556258090631882140542075, 0.03175922842808185514451579933848 / 24.);
|
||||
ir->SetOrder(5);
|
||||
return ir;
|
||||
|
||||
case 6: // 70 points - degree 6 -- taken from https://doi.org/10.1016/j.camwa.2020.07.004
|
||||
PentatopeIntRules[6] = ir = new IntegrationRule(70);
|
||||
ir->AddPentPoints5(0, 0.154743213149364, 0.027287104452858 / 24.);
|
||||
ir->AddPentPoints5(5, 0.243583446244066, 0.030022493650412 / 24.);
|
||||
ir->AddPentPoints10(10, 0.045742589279674, 0.5 - 1.5 * 0.045742589279674, 0.010857537843152 / 24.);
|
||||
ir->AddPentPoints20(20, 0.034061388191316, 0.153237752298796, 0.004213752156913 / 24.);
|
||||
ir->AddPentPoints30(40, 0.042203997139861, 0.211681755872075, 0.017353386263795 / 24.);
|
||||
ir->SetOrder(6);
|
||||
return ir;
|
||||
|
||||
case 7: // 126 points - degree 8 -- taken from https://doi.org/10.1016/j.camwa.2020.07.004
|
||||
case 8:
|
||||
PentatopeIntRules[7] = PentatopeIntRules[8] = ir = new IntegrationRule(126);
|
||||
ir->AddPentMidPoint(0, 0.018477072894310 / 24.);
|
||||
ir->AddPentPoints5(1, 0.041850193209872, 0.003356028785577 / 24.);
|
||||
ir->AddPentPoints20(6, 0.013234490721597, 0.279965061732618, 0.001166950584118 / 24.);
|
||||
ir->AddPentPoints20(26, 0.183538643543872, 0.051063845643639, 0.019804745119265 / 24.);
|
||||
ir->AddPentPoints20(46, 0.311385773831175, 0.014631015332223, 0.005373375682319 / 24.);
|
||||
ir->AddPentPoints30(66, 0.032042227982220, 0.160928155464441, 0.007544402046650 / 24.);
|
||||
ir->AddPentPoints30(96, 0.088725307776945, 0.403464343042675, 0.007050309802142 / 24.);
|
||||
ir->SetOrder(8);
|
||||
return ir;
|
||||
|
||||
case -1:
|
||||
{
|
||||
//construct the higher integration rules with the duffy transformation --> 1d integral in time and a tet quad-rule w.r.t space
|
||||
|
||||
IntegrationRule *timeIR = SegmentIntegrationRule(Order + 2);
|
||||
IntegrationRule *tetIR = TetrahedronIntegrationRule(Order);
|
||||
|
||||
int NIP = timeIR->GetNPoints() * tetIR->GetNPoints();
|
||||
AllocIntRule(PentatopeIntRules, Order);
|
||||
PentatopeIntRules[Order] = ir = new IntegrationRule(NIP);
|
||||
|
||||
#ifdef MFEM_DEBUG
|
||||
mfem::out << "higher integration rules for pentatopes implemented with duffy ( order = " << Order << " ) --> " << NIP << " int. points!" << endl;
|
||||
#endif
|
||||
|
||||
double xi,yi,zi,ti, weight;
|
||||
|
||||
int pos = 0;
|
||||
for (int i=0; i<timeIR->GetNPoints(); i++)
|
||||
{
|
||||
ti = timeIR->IntPoint(i).x;
|
||||
|
||||
for (int j=0; j<tetIR->GetNPoints(); j++)
|
||||
{
|
||||
xi = (1. - ti) * tetIR->IntPoint(j).x;
|
||||
yi = (1. - ti) * tetIR->IntPoint(j).y;
|
||||
zi = (1. - ti) * tetIR->IntPoint(j).z;
|
||||
weight = timeIR->IntPoint(i).weight * tetIR->IntPoint(j).weight * (1.-ti) *
|
||||
(1.-ti) * (1.-ti);
|
||||
#ifdef MFEM_DEBUG
|
||||
if(weight<0) mfem::out << "warning weight is negative!" << endl;
|
||||
#endif
|
||||
ir->AddPentPoint(pos, xi,yi,zi,ti,weight);
|
||||
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
#ifdef MFEM_DEBUG_INTRULES
|
||||
char str[256];
|
||||
mfem::out << "The points and weights are:" << endl;
|
||||
for (int k = 0; k < ir->Size(); ++k)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(k);
|
||||
sprintf(str, "{%.16f, {%.16f, %.16f, %.16f, %.16f}},", ip.weight, ip.x, ip.y, ip.z, ip.t);
|
||||
mfem::out << str << endl;
|
||||
}
|
||||
#endif
|
||||
// 2025 November: Don't we need "return ir;"? It was not there
|
||||
return ir;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
int i = (Order / 2) * 2 + 1; // Get closest odd # >= Order
|
||||
AllocIntRule(PentatopeIntRules, i);
|
||||
ir = new IntegrationRule;
|
||||
ir->GrundmannMollerSimplexRule(i/2,4);
|
||||
PentatopeIntRules[i-1] = PentatopeIntRules[i] = ir;
|
||||
return ir;
|
||||
}
|
||||
}
|
||||
|
||||
return PentatopeIntRules[Order];
|
||||
|
||||
}
|
||||
|
||||
IntegrationRule *IntegrationRules::TesseractIntegrationRule(int Order)
|
||||
{
|
||||
int k, l, m, n, np, index;
|
||||
int i = (Order / 2) * 2 + 1; // Get closest odd # >= Order
|
||||
|
||||
if (!HaveIntRule(SegmentIntRules, i))
|
||||
{
|
||||
SegmentIntegrationRule(i);
|
||||
}
|
||||
AllocIntRule(TesseractIntRules, i);
|
||||
np = SegmentIntRules[i] -> GetNPoints();
|
||||
TesseractIntRules[i-1] = TesseractIntRules[i] = new IntegrationRule(
|
||||
np*np*np*np);
|
||||
index = 0;
|
||||
for (k = 0; k < np; k++)
|
||||
for (l = 0; l < np; l++)
|
||||
for (m = 0; m < np; m++)
|
||||
for (n = 0; n < np; n++)
|
||||
{
|
||||
// index = ((k*np+l)*np+m)*np + n;
|
||||
|
||||
TesseractIntRules[i] -> IntPoint(index).x =
|
||||
SegmentIntRules[i] -> IntPoint(n).x;
|
||||
|
||||
TesseractIntRules[i] -> IntPoint(index).y =
|
||||
SegmentIntRules[i] -> IntPoint(m).x;
|
||||
|
||||
TesseractIntRules[i] -> IntPoint(index).z =
|
||||
SegmentIntRules[i] -> IntPoint(l).x;
|
||||
|
||||
TesseractIntRules[i] -> IntPoint(index).t =
|
||||
SegmentIntRules[i] -> IntPoint(k).x;
|
||||
|
||||
TesseractIntRules[i] -> IntPoint(index).weight =
|
||||
SegmentIntRules[i] -> IntPoint(k).weight *
|
||||
SegmentIntRules[i] -> IntPoint(l).weight *
|
||||
SegmentIntRules[i] -> IntPoint(m).weight *
|
||||
SegmentIntRules[i] -> IntPoint(n).weight;
|
||||
|
||||
index++;
|
||||
}
|
||||
TesseractIntRules[i]->SetOrder(i);
|
||||
return TesseractIntRules[i];
|
||||
}
|
||||
|
||||
IntegrationRule& NURBSMeshRules::GetElementRule(const int elem,
|
||||
const int patch, const int *ijk,
|
||||
Array<const KnotVector*> const& kv,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user