Compare commits

..
13 Commits
Author SHA1 Message Date
Brendan Keith e7e0ed79e6 fixed BC issue 2024-04-14 14:59:23 -04:00
Brendan Keith 7359466ce4 fix sign error 2024-04-12 08:12:42 -04:00
Brendan Keith d5814b9d8e fixed invertibility bug 2024-04-11 22:28:15 -04:00
Brendan Keith 7dd2312ec4 minor 2024-04-11 18:56:53 -04:00
Brendan Keith aa25a12086 changing to direct solver 2024-04-11 18:05:56 -04:00
Brendan Keith 3341feb1d3 linearized problem solved. memory leak 2024-04-11 17:37:39 -04:00
Brendan Keith a6f7baeede fixed the runtime issues with integrators 2024-04-10 11:32:58 -04:00
Brendan Keith bc2ee7f3a9 layout of ex40.cpp done 2024-04-10 10:17:49 -04:00
Brendan Keith 2bcae01f71 outline of MA code 2024-04-09 21:17:45 -04:00
Brendan Keith cde13ad145 Merge branch '2x2_matrix_exponential' into MA 2024-04-09 15:26:27 -04:00
Brendan Keith f728fadcf7 more work on ex40 2024-04-07 22:11:21 -04:00
Brendan Keith 3db9688894 Merge branch '2x2_matrix_exponential' into MA
Adding coefficients from 2x2_matrix_exponential
2024-04-06 15:33:30 -04:00
Brendan Keith d9dc18c32b starting ex40 2024-04-05 12:36:35 -04:00
238 changed files with 2437 additions and 24461 deletions
+9 -36
View File
@@ -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 }}
+5 -5
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
-3
View File
@@ -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
-4
View File
@@ -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:
+4 -3
View File
@@ -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]
+1 -1
View File
@@ -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
+4 -4
View File
@@ -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
+2 -2
View File
@@ -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
+41 -76
View File
@@ -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
View File
@@ -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
View File
@@ -151,8 +151,7 @@ The MFEM source code has the following structure:
│ ├── solvers
│ ├── spde
│ ├── tools
── toys
│ └── tribol
── toys
└── tests
├── benchmarks
├── convergence
+1 -19
View File
@@ -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:
-4
View File
@@ -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()
-1
View File
@@ -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@")
+1 -10
View File
@@ -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)
+2 -6
View File
@@ -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)
+3 -13
View File
@@ -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
-22
View File
@@ -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)
-9
View File
@@ -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
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-1
View File
@@ -92,5 +92,4 @@ vertices
-0.70710678 -0.70710678
0 -1
0.70710678 -0.70710678
mfem_mesh_end
-102
View File
@@ -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
-102
View File
@@ -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
-231
View File
@@ -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
-36
View File
@@ -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
-52
View File
@@ -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
+3 -4
View File
@@ -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
+1 -7
View File
@@ -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
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-412
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
+1
View File
@@ -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
View File
@@ -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));
-650
View File
@@ -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
View File
@@ -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 MongeAmpè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;
}
-436
View File
@@ -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);
}
}
}
-782
View File
@@ -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);
}
}
-800
View File
@@ -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
View File
@@ -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
-11
View File
@@ -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>
+4 -1
View File
@@ -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;
}
+1
View File
@@ -66,6 +66,7 @@ int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI) and HYPRE.
Mpi::Init(argc, argv);
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
+2
View File
@@ -80,6 +80,8 @@ int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI) and HYPRE.
Mpi::Init(argc, argv);
int num_proc = Mpi::WorldSize();
int myId = Mpi::WorldRank();
Hypre::Init();
// 2. Parse command-line options.
-352
View File
@@ -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);
+4 -1
View File
@@ -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;
}
-3
View File
@@ -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
+2 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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,
-19
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
-4
View File
@@ -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.
-184
View File
@@ -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
View File
@@ -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
View File
@@ -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
-187
View File
@@ -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
-341
View File
@@ -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);
}
}
-22
View File
@@ -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
-171
View File
@@ -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;
}
}
}
-19
View File
@@ -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
-264
View File
@@ -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;
}
}
}
}
-47
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -30,14 +30,14 @@ namespace mfem
class GridFunction : public Vector
{
protected:
/// FE space on which the grid function lives. Owned if #fec_owned is not NULL.
/// FE space on which the grid function lives. Owned if #fec is not NULL.
FiniteElementSpace *fes;
/** @brief Used when the grid function is read from a file. It can also be
set explicitly, see MakeOwner().
If not NULL, this pointer is owned by the GridFunction. */
FiniteElementCollection *fec_owned;
FiniteElementCollection *fec;
long fes_sequence; // see FiniteElementSpace::sequence, Mesh::sequence
@@ -72,16 +72,16 @@ protected:
public:
GridFunction() { fes = NULL; fec_owned = NULL; fes_sequence = 0; UseDevice(true); }
GridFunction() { fes = NULL; fec = NULL; fes_sequence = 0; UseDevice(true); }
/// Copy constructor. The internal true-dof vector #t_vec is not copied.
GridFunction(const GridFunction &orig)
: Vector(orig), fes(orig.fes), fec_owned(NULL), fes_sequence(orig.fes_sequence)
: Vector(orig), fes(orig.fes), fec(NULL), fes_sequence(orig.fes_sequence)
{ UseDevice(true); }
/// Construct a GridFunction associated with the FiniteElementSpace @a *f.
GridFunction(FiniteElementSpace *f) : Vector(f->GetVSize())
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/// Construct a GridFunction using previously allocated array @a data.
/** The GridFunction does not assume ownership of @a data which is assumed to
@@ -91,13 +91,13 @@ public:
*/
GridFunction(FiniteElementSpace *f, real_t *data)
: Vector(data, f->GetVSize())
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/** @brief Construct a GridFunction using previously allocated Vector @a base
starting at the given offset, @a base_offset. */
GridFunction(FiniteElementSpace *f, Vector &base, int base_offset = 0)
: Vector(base, base_offset, f->GetVSize())
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/// Construct a GridFunction on the given Mesh, using the data from @a input.
/** The content of @a input should be in the format created by the method
@@ -116,12 +116,12 @@ public:
GridFunction &operator=(const GridFunction &rhs)
{ return operator=((const Vector &)rhs); }
/// Make the GridFunction the owner of #fec_owned and #fes.
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec_owned
/// Make the GridFunction the owner of #fec and #fes.
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec
and #fes is taken away. */
void MakeOwner(FiniteElementCollection *fec_) { fec_owned = fec_; }
void MakeOwner(FiniteElementCollection *fec_) { fec = fec_; }
FiniteElementCollection *OwnFEC() { return fec_owned; }
FiniteElementCollection *OwnFEC() { return fec; }
int VectorDim() const;
int CurlDim() const;
@@ -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,
-79
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+6 -6
View File
@@ -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)
{
+16 -16
View File
@@ -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
View File
@@ -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