Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bcd14bcfb | ||
|
|
04029239d4 | ||
|
|
331b15563d | ||
|
|
13a48c2058 | ||
|
|
95a0d63574 | ||
|
|
75a1fd2388 | ||
|
|
d47185fdd3 | ||
|
|
55951f3778 | ||
|
|
6d2e45576d | ||
|
|
f61773132d | ||
|
|
cda16bf147 | ||
|
|
298417664b | ||
|
|
d386bdd4b4 | ||
|
|
4798173ecf | ||
|
|
0aed9d2752 | ||
|
|
ed3df1c25a | ||
|
|
9898923e66 |
+7
-6
@@ -26,18 +26,19 @@ install:
|
||||
- cd ..
|
||||
|
||||
# Install hypre
|
||||
- ps: Start-FileDownload 'https://github.com/hypre-space/hypre/archive/V2-10-0b.tar.gz'
|
||||
- 7z x V2-10-0b.tar.gz -so | 7z x -si -ttar > nul
|
||||
- cd hypre-2-10-0b
|
||||
- cmake -H. -Bbuild -DHYPRE_USING_FEI=OFF -DMPI_C_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DMPI_C_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include"
|
||||
- ps: Start-FileDownload 'https://computation.llnl.gov/project/linear_solvers/download/hypre-2.10.0b.tar.gz'
|
||||
- 7z x hypre-2.10.0b.tar.gz -so | 7z x -si -ttar > nul
|
||||
- cd hypre-2.10.0b
|
||||
- cmake -Hsrc -Bbuild -DMPI_C_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DMPI_C_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include"
|
||||
# - cmake -Hsrc -Bbuild -DCMAKE_BUILD_TYPE=Release -DMPI_C_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DMPI_C_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include"
|
||||
- cmake --build build
|
||||
- cmake --build build --target install
|
||||
- cd ..
|
||||
|
||||
# MFEM
|
||||
before_build:
|
||||
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_parallel -DMFEM_USE_MPI=TRUE -DMFEM_USE_METIS_5=TRUE -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DHYPRE_LIBRARIES=%cd%\hypre-2-10-0b\hypre\lib\HYPRE.lib -DHYPRE_INCLUDE_DIRS=%cd%\hypre-2-10-0b\hypre\include -DHYPRE_VERSION=21000 -DMETIS_LIBRARIES=%cd%\metis-5.1.0\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%cd%\metis-5.1.0\include
|
||||
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_serial -DMFEM_USE_MPI=FALSE
|
||||
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_parallel -DMFEM_USE_MPI=TRUE -DMFEM_USE_METIS_5=TRUE -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DHYPRE_LIBRARIES=%cd%\hypre-2.10.0b\src\hypre\lib\HYPRE.lib -DHYPRE_INCLUDE_DIRS=%cd%\hypre-2.10.0b\src\hypre\include -DHYPRE_VERSION=21000 -DMETIS_LIBRARIES=%cd%\metis-5.1.0\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%cd%\metis-5.1.0\include
|
||||
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_serial -DMFEM_USE_MPI=FALSE -DMFEM_USE_METIS_5=TRUE -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DHYPRE_LIBRARIES=%cd%\hypre-2.10.0b\src\hypre\lib\HYPRE.lib -DHYPRE_INCLUDE_DIRS=%cd%\hypre-2.10.0b\src\hypre\include -DHYPRE_VERSION=21000 -DMETIS_LIBRARIES=%cd%\metis-5.1.0\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%cd%\metis-5.1.0\include
|
||||
|
||||
build_script:
|
||||
- cmake --build build_parallel
|
||||
|
||||
+7
-6
@@ -39,6 +39,9 @@ doc/CodeDocumentation
|
||||
*.dSYM
|
||||
.DS_Store
|
||||
|
||||
# Editor files
|
||||
.vscode
|
||||
|
||||
# Example and miniapp binaries and outputs
|
||||
|
||||
examples/ex[1-9]
|
||||
@@ -82,9 +85,10 @@ examples/ex20.dat
|
||||
examples/ex20p_?????.dat
|
||||
examples/gnuplot_ex20.inp
|
||||
examples/gnuplot_ex20p.inp
|
||||
examples/ex21*.mesh
|
||||
examples/ex21*.sol
|
||||
examples/ex21p_*.*
|
||||
examples/ex22*.mesh
|
||||
examples/ex22*.sol
|
||||
examples/ex22p_*.*
|
||||
examples/exSBP*
|
||||
|
||||
examples/sundials/ex9
|
||||
examples/sundials/ex1[06]
|
||||
@@ -183,6 +187,3 @@ miniapps/nurbs/Example1*
|
||||
# Unit test binary and outputs
|
||||
tests/unit/output_meshes
|
||||
tests/unit/unit_tests
|
||||
|
||||
# VPATH builds
|
||||
build-*/*
|
||||
|
||||
@@ -8,59 +8,22 @@
|
||||
http://mfem.org
|
||||
|
||||
|
||||
Version 4.0.1 (development)
|
||||
===========================
|
||||
Version 4.0-RC2, Apr 24, 2019
|
||||
=============================
|
||||
|
||||
Improved GPU support
|
||||
--------------------
|
||||
- Added initial support for AMD GPUs based on HIP: a C++ runtime API and kernel
|
||||
language that can run on both AMD and NVIDIA hardware. With this change, the
|
||||
list of backends is: "occa-cuda", "raja-cuda", "cuda", "hip", "occa-omp",
|
||||
"raja-omp", "omp", "occa-cpu", "raja-cpu", and "cpu".
|
||||
Requirements and Limitations
|
||||
----------------------------
|
||||
- This is a release candidate for mfem-4.0.
|
||||
- Use at your own risk -- not everything will work and the API may change.
|
||||
- We are looking for feedback from friendly users.
|
||||
- Unlike previous MFEM releases, this version requires a C++11 compiler.
|
||||
|
||||
- Improved RAJA backend and multi-GPU MPI communications.
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
- Added support for non-conforming prism AMR, including coarsening and parallel
|
||||
load balancing. Anisotropic prism refinement is only available in the serial
|
||||
version at the moment.
|
||||
|
||||
Meshing improvements
|
||||
--------------------
|
||||
- The TMOP mesh optimization algorithms were extended to support r-adaptivity.
|
||||
Target matrices can now be constructed either via a given analytical function
|
||||
(e.g. spatial dependence of size, aspect ratio, etc., for each element) or via
|
||||
a (Par)GridFunction specified on the original mesh.
|
||||
|
||||
- The TMOP mesh optimization algorithms have been improved to support AMR meshes.
|
||||
|
||||
- Added support for creating refined versions of periodic meshes, making use of
|
||||
the new L2ElementRestriction class. This class also allows for computing
|
||||
geometric factors on periodic meshes using partial assembly.
|
||||
|
||||
- Improved element numbering after uniform mesh refinement.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- The mesh-optimizer and pmesh-optimizer miniapps have been updated to
|
||||
demonstrate the new r-adaptivity capabilities of TMOP.
|
||||
|
||||
- The (p)mesh-optimizer miniapp has been updated to demonstrate mesh
|
||||
optimization for an AMR mesh.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- Upgraded the SUNDIALS interface to utilize SUNDIALS version 5.0. This
|
||||
necessitated a complete rework of the interface and requires changes at
|
||||
the application level. Example usage of this new interface can be found
|
||||
in the examples/sundials directory.
|
||||
|
||||
|
||||
Version 4.0, released on May 24, 2019
|
||||
=====================================
|
||||
|
||||
Unlike previous MFEM releases, this version requires a C++11 compiler.
|
||||
- GPU-related limitations:
|
||||
* Hypre preconditioners are not yet available in GPU mode.
|
||||
* Only constant coefficients are currently supported on GPUs.
|
||||
* Full-assembly (on device), element assembly, and matrix-free bilinear forms
|
||||
are not supported yet. Element batching is currently ignored.
|
||||
* Partial assembly kernels are not implemented yet for simplices.
|
||||
|
||||
GPU support
|
||||
-----------
|
||||
@@ -71,7 +34,7 @@ GPU support
|
||||
seamlessly with a new lightweight device/host memory manager. The kernels can
|
||||
be implemented either in OCCA, or as a simple wrapper around for-loops, which
|
||||
can then be dispatched to RAJA and native backends. See the files forall.hpp
|
||||
and mem_manager.hpp in the general/ directory for more details.
|
||||
and mem_manager.hpp in the general/ directory.
|
||||
|
||||
- Several of the MFEM example codes (ex1, ex1p, ex6, and ex6p) can now take
|
||||
advantage of GPU acceleration with the backend selectable at runtime. Many of
|
||||
@@ -79,43 +42,26 @@ GPU support
|
||||
bilinear forms) have been extended to take advantage of kernel acceleration by
|
||||
simply replacing loops with the MFEM_FORALL() macro.
|
||||
|
||||
- In addition to native CUDA kernels, the library currently supports OCCA, RAJA
|
||||
and OpenMP kernels, which could be mixed and matched in different parts of the
|
||||
same application. We plan on adding support for more programming models and
|
||||
devices in the future, without the need for significant modifications in user
|
||||
code. The list of current backends is: "occa-cuda", "raja-cuda", "cuda",
|
||||
"occa-omp", "raja-omp", "omp", "occa-cpu", "raja-cpu", and "cpu".
|
||||
|
||||
- GPU-related limitations:
|
||||
* Hypre preconditioners are not yet available in GPU mode, and in particular
|
||||
hypre must be built in CPU mode.
|
||||
* Only constant coefficients are currently supported on GPUs.
|
||||
* Optimized element assembly, and matrix-free bilinear forms are not
|
||||
implemented yet. Element batching is currently ignored.
|
||||
* In device mode, full assembly is performed on the host (but the matvec
|
||||
action is performed on the device).
|
||||
* Partial assembly kernels are not implemented yet for simplices.
|
||||
- In addition to pure CUDA, the library currently supports OCCA, RAJA and OpenMP
|
||||
kernels, which could be mixed and matched in different parts of the same
|
||||
application. We plan on adding support for more programming models and devices
|
||||
in the future, without the need for significant modifications in user code.
|
||||
The list of current backends is: "occa-cuda", "raja-cuda", "cuda", "occa-omp",
|
||||
"raja-omp", "omp", "occa-cpu", "raja-cpu", and "cpu".
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
- Partial assembled finite element operators are now available in the core
|
||||
library, based on the new classes PABilinearFormExtension, ElementRestriction,
|
||||
DofToQuad and GeometricFactors (associated with the classes BilinearForm,
|
||||
FiniteElementSpace, FiniteElement and Mesh, respectively). The kernels for
|
||||
partial assembled Setup/Assembly and Action/Mult are implemented in the
|
||||
BilinearFormIntegrator methods AssemblePA and AddMultPA.
|
||||
|
||||
- Added support for a general "low-order refined"-to-"high-order" transfer of
|
||||
GridFunction data from a "low-order refined" (LOR) space defined on a refined
|
||||
mesh to a "high-order" (HO) finite element space defined on a coarse mesh. See
|
||||
the new classes InterpolationGridTransfer and L2ProjectionGridTransfer and the
|
||||
new LOR Transfer miniapp: miniapps/tools/lor-transfer.cpp.
|
||||
|
||||
- Added support for derefinement of vector (RT + ND) spaces.
|
||||
|
||||
- Added element flux, and flux energy computation in class ElasticityIntegrator,
|
||||
allowing for the use of Zienkiewicz-Zhu type error estimators with the
|
||||
integrator. For an illustration of this addition, see the new Example 21.
|
||||
|
||||
- Added support for derefinement of vector (RT + ND) spaces.
|
||||
integrator. For an illustration of this addition, see the new Example 22.
|
||||
|
||||
- Added a variety of coefficients which are sums or products of existing
|
||||
coefficients as well as grid function coefficients which return the
|
||||
@@ -127,13 +73,13 @@ Support for wedge elements and meshes with mixed element types
|
||||
type PRISM) which have two triangular faces and three quadrilateral faces.
|
||||
Several examples of such meshes can be found in the data/ directory.
|
||||
|
||||
- Added H1 and L2 finite elements of arbitrary order for Wedge elements.
|
||||
|
||||
- Added support for mixed meshes containing triangles and quadrilaterals in 2D
|
||||
or tetrahedra, wedges, and hexahedra in 3D. This includes support for uniform
|
||||
refinement of such meshes. Several examples of such meshes can be found in the
|
||||
data/ directory.
|
||||
|
||||
- Added H1 and L2 finite elements of arbitrary order for Wedge elements.
|
||||
|
||||
- Added support for reading and writing linear and quadratic meshes containing
|
||||
wedge elements in VTK mesh format. Several examples of such meshes can be
|
||||
found in the data/ directory.
|
||||
@@ -154,10 +100,6 @@ Other meshing improvements
|
||||
This guarantees that the shape regularity of the elements will be preserved
|
||||
under refinement.
|
||||
|
||||
- The TMOP mesh optimization algorithms were extended to support user-defined
|
||||
space-dependent limiting terms. Improved the TMOP objective functions by more
|
||||
accurate normalization of the different terms.
|
||||
|
||||
- Added support for parallel communication groups on non-conforming meshes.
|
||||
|
||||
- Improved parallel partitioning of non-conforming meshes. If the coarse mesh
|
||||
@@ -171,6 +113,10 @@ Other meshing improvements
|
||||
- Added support for reading linear and quadratic 2D quadrilateral and triangular
|
||||
Cubit meshes.
|
||||
|
||||
- The TMOP mesh optimization algorithms were extended to support user-defined
|
||||
space-dependent limiting terms. Improved the TMOP objective functions by more
|
||||
accurate normalization of the different terms.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- Added a new meshing miniapp, Toroid, which can produce a variety of torus
|
||||
@@ -186,7 +132,7 @@ New and updated examples and miniapps
|
||||
from a Hamiltonian. The example demonstrates the use of the variable order,
|
||||
symplectic integration algorithm implemented in class SIAVSolver.
|
||||
|
||||
- Added a new example, Example 21/21p, that illustrates the use of AMR to solve
|
||||
- Added a new example, Example 22/22p, that illustrates the use of AMR to solve
|
||||
a linear elasticity problem. This is an extension of Example 2/2p.
|
||||
|
||||
New and improved solvers and preconditioners
|
||||
@@ -198,24 +144,21 @@ New and improved solvers and preconditioners
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- Added unit tests based on the Catch++ library in the test/ directory.
|
||||
- In SparseMatrix added the option to perform MultTranspose() by matvec with
|
||||
computed and stored transpose matrix. This is required for deterministic
|
||||
results when using devices such as CUDA and OpenMP.
|
||||
|
||||
- Added unit tests based on the Catch++ library.
|
||||
|
||||
- Renamed the option MFEM_USE_OPENMP to MFEM_USE_LEGACY_OPENMP. This legacy
|
||||
option is deprecated and planned for removal in a future release. The original
|
||||
option name, MFEM_USE_OPENMP, is now used to enable the new OpenMP backends in
|
||||
the new kernels.
|
||||
|
||||
- In SparseMatrix added the option to perform MultTranspose() by matvec with
|
||||
computed and stored transpose matrix. This is required for deterministic
|
||||
results when using devices such as CUDA and OpenMP.
|
||||
|
||||
- Altered the way FGMRES counts its iterations so that it matches GMRES.
|
||||
|
||||
- Various other simplifications, extensions, and bugfixes in the code.
|
||||
|
||||
- Construct abstract parallel rectangular truedof-to-truedof operators via
|
||||
Operator::FormDiscreteOperator().
|
||||
|
||||
API changes
|
||||
-----------
|
||||
- In multiple places, use Geometry::Type instead of int, where appropriate.
|
||||
|
||||
+7
-6
@@ -50,7 +50,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.0.1)
|
||||
set(${PROJECT_NAME}_VERSION 3.4.1)
|
||||
|
||||
# Prohibit in-source build
|
||||
if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR})
|
||||
@@ -254,7 +254,7 @@ endif()
|
||||
|
||||
# Axom/Sidre
|
||||
if (MFEM_USE_SIDRE)
|
||||
find_package(Axom REQUIRED Axom)
|
||||
find_package(Axom REQUIRED Sidre SLIC axom_utils)
|
||||
endif()
|
||||
|
||||
# PUMI
|
||||
@@ -286,6 +286,7 @@ if (MFEM_USE_CUDA)
|
||||
set(CUDA_CCBIN_COMPILER ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
string(APPEND CMAKE_CUDA_FLAGS " -ccbin ${CUDA_CCBIN_COMPILER}")
|
||||
set(MFEM_USE_MM YES CACHE BOOL "Enable MFEM's memory manager" FORCE)
|
||||
endif()
|
||||
|
||||
# OCCA
|
||||
@@ -395,11 +396,11 @@ endif()
|
||||
set_target_properties(mfem PROPERTIES VERSION "${mfem_VERSION}")
|
||||
set_target_properties(mfem PROPERTIES SOVERSION "${mfem_VERSION}")
|
||||
|
||||
# If building out-of-source, define MFEM_CONFIG_FILE to point to the config file
|
||||
# inside the build directory.
|
||||
# If building out-of-source, define MFEM_BUILD_DIR to point to the build
|
||||
# directory.
|
||||
if (NOT ("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}"))
|
||||
target_compile_definitions(mfem PRIVATE
|
||||
"MFEM_CONFIG_FILE=\"${PROJECT_BINARY_DIR}/config/_config.hpp\"")
|
||||
"MFEM_BUILD_DIR=${PROJECT_BINARY_DIR}")
|
||||
endif()
|
||||
|
||||
# Generate configuration file in the build directory: config/_config.hpp.
|
||||
@@ -415,7 +416,7 @@ if (NOT ("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}"))
|
||||
"Writing substitute header --> \"${Header}\"")
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/${Header}"
|
||||
"// Auto-generated file.
|
||||
#define MFEM_CONFIG_FILE \"${PROJECT_BINARY_DIR}/config/_config.hpp\"
|
||||
#define MFEM_BUILD_DIR ${PROJECT_BINARY_DIR}
|
||||
#include \"${PROJECT_SOURCE_DIR}/${Header}\"
|
||||
")
|
||||
# This version will be installed in the top include directory:
|
||||
|
||||
@@ -28,16 +28,13 @@ The METIS dependency can be disabled but that is not generally recommended, see
|
||||
the option MFEM_USE_METIS.
|
||||
|
||||
MFEM also includes support for devices such as GPUs, and programming models such
|
||||
as CUDA, HIP, OCCA, OpenMP and RAJA.
|
||||
as CUDA, OCCA, OpenMP and RAJA.
|
||||
|
||||
- Starting with version 4.0, MFEM requires a C++11 compiler
|
||||
|
||||
- CUDA support requires an NVIDIA GPU and an installation of the CUDA Toolkit
|
||||
https://developer.nvidia.com/cuda-toolkit
|
||||
|
||||
- HIP support requires an AMD GPU and an installation of the ROCm software stack
|
||||
https://rocm.github.io/ROCmInstall.html#installing-from-amd-rocm-repositories
|
||||
|
||||
- OCCA support requires the OCCA library
|
||||
https://libocca.org
|
||||
|
||||
@@ -78,10 +75,6 @@ CUDA build:
|
||||
make cuda -j 4
|
||||
(build for a specific compute capability: 'make cuda -j 4 CUDA_ARCH=sm_30')
|
||||
|
||||
HIP build:
|
||||
make hip -j 4
|
||||
(build for a specific AMD GPU chip: 'make hip -j 4 HIP_ARCH=gfx900')
|
||||
|
||||
Example codes (serial/parallel, depending on the build):
|
||||
cd examples
|
||||
make -j 4
|
||||
@@ -168,18 +161,14 @@ Note that re-configuration is only needed to change the currently configured
|
||||
options. Several shortcut targets combining (re-)configuration and compilation
|
||||
are also defined:
|
||||
|
||||
make serial -> Builds serial optimized version of the library
|
||||
make parallel -> Builds parallel optimized version of the library
|
||||
make debug -> Builds serial debug version of the library
|
||||
make pdebug -> Builds parallel debug version of the library
|
||||
make cuda -> Builds serial cuda optimized version of the library
|
||||
make pcuda -> Builds parallel cuda optimized version of the library
|
||||
make cudebug -> Builds serial cuda debug version of the library
|
||||
make pcudebug -> Builds parallel cuda debug version of the library
|
||||
make hip -> Builds serial hip optimized version of the library
|
||||
make phip -> Builds parallel hip optimized version of the library
|
||||
make hipdebug -> Builds serial hip debug version of the library
|
||||
make phipdebug -> Builds parallel hip debug version of the library
|
||||
make serial -> Builds serial optimized version of the library
|
||||
make parallel -> Builds parallel optimized version of the library
|
||||
make debug -> Builds serial debug version of the library
|
||||
make pdebug -> Builds parallel debug version of the library
|
||||
make cuda -> Builds serial cuda optimized version of the library
|
||||
make pcuda -> Builds parallel cuda optimized version of the library
|
||||
make cudebug -> Builds serial cuda debug version of the library
|
||||
make pcudebug -> Builds parallel cuda debug version of the library
|
||||
|
||||
Note that any of the above shortcuts accept configuration options, either at the
|
||||
command line or through a user configuration file.
|
||||
@@ -383,11 +372,11 @@ MFEM_USE_MPFR = YES/NO
|
||||
see below.
|
||||
|
||||
MFEM_USE_SIDRE = YES/NO
|
||||
Sidre is a component of LLNL's axom project, https://github.com/LLNL/axom,
|
||||
that provides an HDF5-based file format for visualization or restart
|
||||
capability following the Conduit (https://github.com/LLNL/conduit) mesh
|
||||
blueprint specification. When enabled, this option requires installation of
|
||||
HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project.
|
||||
Sidre is a component of LLNL's axom project, http://goo.gl/cZyJdn, that
|
||||
provides an HDF5-based file format for visualization or restart capability
|
||||
following the Conduit (https://github.com/LLNL/conduit) mesh blueprint
|
||||
specification. When enabled, this option requires installation of HDF5 (see
|
||||
also MFEM_USE_NETCDF), Conduit and LLNL's axom project.
|
||||
|
||||
MFEM_USE_CONDUIT = YES/NO
|
||||
Enables support for converting MFEM Mesh and Grid Function objects to and
|
||||
@@ -415,19 +404,18 @@ MFEM_USE_PUMI = YES/NO
|
||||
models and effectively supports automated adaptive analysis. PUMI enables
|
||||
support for parallel unstructured mesh modifications in MFEM.
|
||||
|
||||
MFEM_USE_MM = YES/NO
|
||||
Enables support for the MFEM's memory manager (MM), which is required to
|
||||
support devices with different memory spaces. This option is required when
|
||||
CUDA support is enabled, i.e. when MFEM_USE_CUDA=YES.
|
||||
|
||||
MFEM_USE_CUDA = YES/NO
|
||||
Enables support for CUDA devices in MFEM. CUDA is a parallel computing
|
||||
platform and programming model for general computing on graphical processing
|
||||
units (GPUs). The variable CUDA_ARCH is used to specify the CUDA compute
|
||||
capability used during compilation (by default, CUDA_ARCH=sm_60). When
|
||||
enabled, this option uses the CUDA_* build options, see below.
|
||||
|
||||
MFEM_USE_HIP = YES/NO
|
||||
Enables support for AMD devices in MFEM. HIP is a heterogeneous-compute
|
||||
interface for portability developed by AMD that can target both AMD and
|
||||
NVIDIA GPUs. The variable HIP_ARCH is used to specify the AMD GPU processor
|
||||
used during compilation (by default, HIP_ARCH=gfx900). When enabled, this
|
||||
option uses the HIP_* build options, see below.
|
||||
units (GPUs). This option requires MFEM_USE_MM. The variable CUDA_ARCH is
|
||||
used to specify the CUDA compute capability used during compilation (by
|
||||
default, CUDA_ARCH=sm_60). When enabled, this option uses the CUDA_* build
|
||||
options, see below.
|
||||
|
||||
MFEM_USE_RAJA = YES/NO
|
||||
Enable support for the RAJA performance portability layer in MFEM. RAJA
|
||||
@@ -488,7 +476,6 @@ The specific libraries and their options are:
|
||||
- SUNDIALS (optional), used when MFEM_USE_SUNDIALS = YES.
|
||||
Beginning with MFEM v3.3, SUNDIALS v2.7.0 is supported.
|
||||
Beginning with MFEM v3.3.2, SUNDIALS v3.0.0 is also supported.
|
||||
Beginning with MFEM v4.1, only SUNDIALS v5.0.0+ is supported.
|
||||
If MFEM_USE_MPI is enabled, we expect that SUNDIALS is built with support for
|
||||
both MPI and hypre.
|
||||
URL: http://computation.llnl.gov/projects/sundials/sundials-software
|
||||
@@ -543,8 +530,7 @@ The specific libraries and their options are:
|
||||
Options: PETSC_OPT, PETSC_LIB.
|
||||
|
||||
- Sidre (optional), part of LLNL's axom project, used when MFEM_USE_SIDRE = YES.
|
||||
Starting with MFEM v4.1, Axom version 0.3.1 or later is required.
|
||||
URL: https://github.com/LLNL/axom
|
||||
URL: http://goo.gl/cZyJdn (axom, to be released)
|
||||
https://github.com/LLNL/conduit (Conduit)
|
||||
https://support.hdfgroup.org/HDF5 (HDF5)
|
||||
Options: SIDRE_OPT, SIDRE_LIB.
|
||||
@@ -563,16 +549,11 @@ The specific libraries and their options are:
|
||||
URL: https://developer.nvidia.com/cuda-toolkit
|
||||
Options: CUDA_CXX, CUDA_ARCH, CUDA_OPT, CUDA_LIB.
|
||||
|
||||
- HIP, used when MFEM_USE_HIP = YES.
|
||||
URL: https://rocm.github.io/ROCmInstall.html
|
||||
Options: HIP_CXX, HIP_ARCH, HIP_OPT, HIP_LIB.
|
||||
|
||||
- OCCA, used when MFEM_USE_OCCA = YES.
|
||||
URL: https://libocca.org
|
||||
Options: OCCA_DIR, OCCA_OPT, OCCA_LIB.
|
||||
|
||||
- RAJA, used when MFEM_USE_RAJA = YES.
|
||||
Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported.
|
||||
URL: https://github.com/LLNL/RAJA
|
||||
Options: RAJA_DIR, RAJA_OPT, RAJA_LIB.
|
||||
|
||||
@@ -715,7 +696,7 @@ MFEM_USE_PUMI
|
||||
MFEM_USE_CUDA
|
||||
MFEM_USE_OCCA
|
||||
MFEM_USE_RAJA
|
||||
MFEM_USE_SIDRE
|
||||
MFEM_USE_MM
|
||||
|
||||
The following options are CMake specific:
|
||||
|
||||
@@ -764,7 +745,6 @@ The CMake build system adds auto-detection for the following packages/libraries:
|
||||
- PUMI
|
||||
- OCCA
|
||||
- RAJA
|
||||
- AXOM - Used when MFEM_USE_SIDRE is enabled
|
||||
|
||||
The following built-in CMake packages are also used:
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ set(MFEM_USE_MPFR @MFEM_USE_MPFR@)
|
||||
set(MFEM_USE_SIDRE @MFEM_USE_SIDRE@)
|
||||
set(MFEM_USE_CONDUIT @MFEM_USE_CONDUIT@)
|
||||
set(MFEM_USE_PUMI @MFEM_USE_PUMI@)
|
||||
set(MFEM_USE_MM @MFEM_USE_MM@)
|
||||
set(MFEM_USE_CUDA @MFEM_USE_CUDA@)
|
||||
set(MFEM_USE_OCCA @MFEM_USE_OCCA@)
|
||||
set(MFEM_USE_RAJA @MFEM_USE_RAJA@)
|
||||
|
||||
@@ -120,6 +120,9 @@
|
||||
// Enable MFEM functionality based on the OCCA library
|
||||
#cmakedefine MFEM_USE_OCCA
|
||||
|
||||
// Enable MFEM's internal Memory Manager (needed e.g. for MFEM_USE_CUDA)
|
||||
#cmakedefine MFEM_USE_MM
|
||||
|
||||
// Which library functions to use in class StopWatch for measuring time.
|
||||
// For a list of the available options, see INSTALL.
|
||||
// If not defined, an option is selected automatically.
|
||||
|
||||
@@ -18,4 +18,6 @@ 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 Axom "include" axom/config.hpp "lib" axom)
|
||||
ADD_COMPONENT Sidre "include" sidre/sidre.hpp "lib" sidre
|
||||
ADD_COMPONENT SLIC "include" slic/slic.hpp "lib" slic
|
||||
ADD_COMPONENT axom_utils "include" axom_utils/Utilities.hpp "lib" axom_utils)
|
||||
|
||||
@@ -720,7 +720,8 @@ function(mfem_export_mk_files)
|
||||
MFEM_USE_MEMALLOC MFEM_USE_SUNDIALS MFEM_USE_MESQUITE MFEM_USE_SUITESPARSE
|
||||
MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GECKO MFEM_USE_GNUTLS
|
||||
MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE
|
||||
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_CUDA MFEM_USE_OCCA MFEM_USE_RAJA)
|
||||
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_MM MFEM_USE_CUDA MFEM_USE_OCCA
|
||||
MFEM_USE_RAJA)
|
||||
foreach(var ${CONFIG_MK_BOOL_VARS})
|
||||
if (${var})
|
||||
set(${var} YES)
|
||||
|
||||
+11
-3
@@ -10,15 +10,18 @@
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
|
||||
// Support out-of-source builds: if MFEM_CONFIG_FILE is defined, include it.
|
||||
// Support out-of-source builds: if MFEM_BUILD_DIR is defined, load the config
|
||||
// file MFEM_BUILD_DIR/config/_config.hpp.
|
||||
//
|
||||
// Otherwise, use the local file: _config.hpp.
|
||||
|
||||
#ifndef MFEM_CONFIG_HPP
|
||||
#define MFEM_CONFIG_HPP
|
||||
|
||||
#ifdef MFEM_CONFIG_FILE
|
||||
#include MFEM_CONFIG_FILE
|
||||
#ifdef MFEM_BUILD_DIR
|
||||
#define MFEM_QUOTE(a) #a
|
||||
#define MFEM_MAKE_PATH(x,y) MFEM_QUOTE(x/y)
|
||||
#include MFEM_MAKE_PATH(MFEM_BUILD_DIR,config/_config.hpp)
|
||||
#else
|
||||
#include "_config.hpp"
|
||||
#endif
|
||||
@@ -53,4 +56,9 @@
|
||||
#endif
|
||||
#endif // MFEM_USE_MPI not defined
|
||||
|
||||
// CUDA requires the memory manager
|
||||
#if defined(MFEM_USE_CUDA) && !defined(MFEM_USE_MM)
|
||||
#error Building with CUDA (MFEM_USE_CUDA=YES) requires MFEM_USE_MM=YES
|
||||
#endif
|
||||
|
||||
#endif // MFEM_CONFIG_HPP
|
||||
|
||||
@@ -121,20 +121,19 @@
|
||||
// Enable MFEM functionality based on the PUMI library
|
||||
// #define MFEM_USE_PUMI
|
||||
|
||||
// Build the NVIDIA GPU/CUDA-enabled version of the MFEM library.
|
||||
// Build the GPU/CUDA-enabled version of the MFEM library.
|
||||
// Requires a CUDA compiler (nvcc).
|
||||
// #define MFEM_USE_CUDA
|
||||
|
||||
// Build the AMD GPU/HIP-enabled version of the MFEM library.
|
||||
// Requires a HIP compiler (hipcc).
|
||||
// #define MFEM_USE_HIP
|
||||
|
||||
// Enable functionality based on the RAJA library.
|
||||
// #define MFEM_USE_RAJA
|
||||
|
||||
// Enable functionality based on the OCCA library.
|
||||
// #define MFEM_USE_OCCA
|
||||
|
||||
// Enable MFEM's internal Memory Manager (needed e.g. for MFEM_USE_CUDA)
|
||||
// #define MFEM_USE_MM
|
||||
|
||||
// Version of HYPRE used for building MFEM.
|
||||
// #define MFEM_HYPRE_VERSION @MFEM_HYPRE_VERSION@
|
||||
|
||||
|
||||
+1
-1
@@ -42,9 +42,9 @@ MFEM_USE_SIDRE = @MFEM_USE_SIDRE@
|
||||
MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@
|
||||
MFEM_USE_PUMI = @MFEM_USE_PUMI@
|
||||
MFEM_USE_CUDA = @MFEM_USE_CUDA@
|
||||
MFEM_USE_HIP = @MFEM_USE_HIP@
|
||||
MFEM_USE_RAJA = @MFEM_USE_RAJA@
|
||||
MFEM_USE_OCCA = @MFEM_USE_OCCA@
|
||||
MFEM_USE_MM = @MFEM_USE_MM@
|
||||
|
||||
# Compiler, compile options, and link options
|
||||
MFEM_CXX = @MFEM_CXX@
|
||||
|
||||
@@ -42,6 +42,7 @@ option(MFEM_USE_MPFR "Enable MPFR usage." OFF)
|
||||
option(MFEM_USE_SIDRE "Enable Axom/Sidre usage" OFF)
|
||||
option(MFEM_USE_CONDUIT "Enable Conduit usage" OFF)
|
||||
option(MFEM_USE_PUMI "Enable PUMI" OFF)
|
||||
option(MFEM_USE_MM "Enable MFEM's memory manager" OFF)
|
||||
option(MFEM_USE_CUDA "Enable CUDA" OFF)
|
||||
option(MFEM_USE_OCCA "Enable OCCA" OFF)
|
||||
option(MFEM_USE_RAJA "Enable RAJA" OFF)
|
||||
@@ -81,7 +82,7 @@ set(METIS_DIR "${MFEM_DIR}/../metis-4.0" CACHE PATH "Path to the METIS library."
|
||||
|
||||
set(LIBUNWIND_DIR "" CACHE PATH "Path to Libunwind.")
|
||||
|
||||
set(SUNDIALS_DIR "${MFEM_DIR}/../sundials-5.0.0/instdir" CACHE PATH
|
||||
set(SUNDIALS_DIR "${MFEM_DIR}/../sundials-3.0.0" CACHE PATH
|
||||
"Path to the SUNDIALS library.")
|
||||
# The following may be necessary, if SUNDIALS was built with KLU:
|
||||
# set(SUNDIALS_REQUIRED_PACKAGES "SuiteSparse/KLU/AMD/BTF/COLAMD/config"
|
||||
@@ -154,7 +155,7 @@ 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.
|
||||
set(Axom_REQUIRED_PACKAGES "Conduit/relay/blueprint" CACHE STRING
|
||||
set(Axom_REQUIRED_PACKAGES "Conduit/relay" CACHE STRING
|
||||
"Additional packages required by Axom.")
|
||||
|
||||
set(PUMI_DIR "${MFEM_DIR}/../pumi-2.1.0" CACHE STRING
|
||||
|
||||
+5
-17
@@ -46,14 +46,6 @@ CUDA_FLAGS = -x=cu --expt-extended-lambda -arch=$(CUDA_ARCH)
|
||||
CUDA_XCOMPILER = -Xcompiler=
|
||||
CUDA_XLINKER = -Xlinker=
|
||||
|
||||
# HIP configuration options
|
||||
HIP_CXX = hipcc
|
||||
# The HIP_ARCH option specifies the AMD GPU processor, similar to CUDA_ARCH. For
|
||||
# example: gfx600 (tahiti), gfx700 (kaveri), gfx701 (hawaii), gfx801 (carrizo),
|
||||
# gfx900, gfx1010, etc.
|
||||
HIP_ARCH = gfx900
|
||||
HIP_FLAGS = --amdgpu-target=$(HIP_ARCH)
|
||||
|
||||
ifneq ($(NOTMAC),)
|
||||
AR = ar
|
||||
ARFLAGS = cruv
|
||||
@@ -130,9 +122,9 @@ MFEM_USE_SIDRE = NO
|
||||
MFEM_USE_CONDUIT = NO
|
||||
MFEM_USE_PUMI = NO
|
||||
MFEM_USE_CUDA = NO
|
||||
MFEM_USE_HIP = NO
|
||||
MFEM_USE_RAJA = NO
|
||||
MFEM_USE_OCCA = NO
|
||||
MFEM_USE_MM = NO
|
||||
|
||||
# Compile and link options for zlib.
|
||||
ZLIB_DIR =
|
||||
@@ -182,9 +174,9 @@ OPENMP_LIB =
|
||||
POSIX_CLOCKS_LIB = -lrt
|
||||
|
||||
# SUNDIALS library configuration
|
||||
SUNDIALS_DIR = @MFEM_DIR@/../sundials-5.0.0/instdir
|
||||
SUNDIALS_DIR = @MFEM_DIR@/../sundials-3.0.0
|
||||
SUNDIALS_OPT = -I$(SUNDIALS_DIR)/include
|
||||
SUNDIALS_LIB = -Wl,-rpath,$(SUNDIALS_DIR)/lib64 -L$(SUNDIALS_DIR)/lib64\
|
||||
SUNDIALS_LIB = -Wl,-rpath,$(SUNDIALS_DIR)/lib -L$(SUNDIALS_DIR)/lib\
|
||||
-lsundials_arkode -lsundials_cvode -lsundials_nvecserial -lsundials_kinsol
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),YES)
|
||||
@@ -209,7 +201,7 @@ SUITESPARSE_LIB = -Wl,-rpath,$(SUITESPARSE_DIR)/lib -L$(SUITESPARSE_DIR)/lib\
|
||||
# SuperLU library configuration
|
||||
SUPERLU_DIR = @MFEM_DIR@/../SuperLU_DIST_5.1.0
|
||||
SUPERLU_OPT = -I$(SUPERLU_DIR)/SRC
|
||||
SUPERLU_LIB = -Wl,-rpath,$(SUPERLU_DIR)/lib -L$(SUPERLU_DIR)/lib -lsuperlu_dist_5.1.0
|
||||
SUPERLU_LIB = -Wl,-rpath,$(SUPERLU_DIR)/SRC -L$(SUPERLU_DIR)/SRC -lsuperlu_dist
|
||||
|
||||
# SCOTCH library configuration (required by STRUMPACK <= v2.1.0, optional in
|
||||
# STRUMPACK >= v2.2.0)
|
||||
@@ -299,7 +291,7 @@ SIDRE_LIB = \
|
||||
-Wl,-rpath,$(SIDRE_DIR)/lib -L$(SIDRE_DIR)/lib \
|
||||
-Wl,-rpath,$(CONDUIT_DIR)/lib -L$(CONDUIT_DIR)/lib \
|
||||
-Wl,-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib \
|
||||
-laxom -lconduit -lconduit_relay -lconduit_blueprint -lhdf5 $(ZLIB_LIB) -ldl
|
||||
-lsidre -lslic -laxom_utils -lconduit -lconduit_relay -lhdf5 $(ZLIB_LIB) -ldl
|
||||
|
||||
# PUMI
|
||||
# Note that PUMI_DIR is needed -- it is used to check for gmi_sim.h
|
||||
@@ -312,10 +304,6 @@ PUMI_LIB = -L$(PUMI_DIR)/lib -lpumi -lcrv -lma -lmds -lapf -lpcu -lgmi -lparma\
|
||||
CUDA_OPT =
|
||||
CUDA_LIB =
|
||||
|
||||
# HIP library configuration (currently not needed)
|
||||
HIP_OPT =
|
||||
HIP_LIB =
|
||||
|
||||
# OCCA library configuration
|
||||
OCCA_DIR = @MFEM_DIR@/../occa
|
||||
OCCA_OPT = -I$(OCCA_DIR)/include
|
||||
|
||||
+1
-2
@@ -36,7 +36,6 @@ CONFIG_MK = config.mk
|
||||
all: header config-mk
|
||||
|
||||
MPI = $(MFEM_USE_MPI:NO=)
|
||||
GHV_CXX ?= $(MFEM_CXX)
|
||||
GHV = get_hypre_version
|
||||
GHV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(HYPRE_OPT))
|
||||
SMX = $(if $(MFEM_USE_PUMI:NO=),MFEM_USE_SIMMETRIX)
|
||||
@@ -45,7 +44,7 @@ SMX_FILE = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(SMX_PATH))
|
||||
|
||||
$(GHV): $(SRC)$(GHV).cpp
|
||||
$(call mfem-info, Determining HYPRE version ...)
|
||||
$(GHV_CXX) ${GHV_FLAGS} $(SRC)$(GHV).cpp -o $(GHV)
|
||||
$(MFEM_CXX) ${GHV_FLAGS} $(SRC)$(GHV).cpp -o $(GHV)
|
||||
$(GHV).out: $(GHV)
|
||||
./$(GHV) > $(GHV).out
|
||||
.INTERMEDIATE: $(GHV) $(GHV).out
|
||||
|
||||
@@ -276,7 +276,8 @@ case "$1" in
|
||||
;;
|
||||
-dev)
|
||||
device_runs="yes"
|
||||
mfem_config+=" MFEM_USE_CUDA=YES MFEM_USE_OCCA=YES MFEM_USE_RAJA=YES MFEM_USE_OPENMP=YES"
|
||||
mfem_config+=" MFEM_USE_CUDA=YES MFEM_USE_MM=YES \
|
||||
MFEM_USE_OCCA=YES MFEM_USE_RAJA=YES MFEM_USE_OPENMP=YES"
|
||||
;;
|
||||
-v)
|
||||
valgrind="yes"
|
||||
|
||||
+3
-2
@@ -43,14 +43,15 @@
|
||||
#define MFEM_ALIGN_SIZE(size,type) \
|
||||
MFEM_ROUNDUP(size,(MFEM_SIMD_SIZE)/sizeof(type))
|
||||
|
||||
#ifdef MFEM_COUNT_FLOPS
|
||||
namespace mfem
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
extern long long flop_count;
|
||||
long long flop_count;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MFEM_COUNT_FLOPS
|
||||
#define MFEM_FLOPS_RESET() (mfem::internal::flop_count = 0)
|
||||
#define MFEM_FLOPS_ADD(cnt) (mfem::internal::flop_count += (cnt))
|
||||
#define MFEM_FLOPS_GET() (mfem::internal::flop_count)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@ PROJECT_NAME = "MFEM"
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = v4.0.1
|
||||
PROJECT_NUMBER = v3.4.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
|
||||
|
||||
@@ -37,9 +37,7 @@ namespace mfem {
|
||||
*
|
||||
* <H3>Main GPU classes</H3>
|
||||
* - Device
|
||||
* - Memory
|
||||
* - MemoryManager
|
||||
* - MFEM_FORALL macro in forall.hpp
|
||||
*
|
||||
* <H3>Example codes</H3>
|
||||
* - <a class="el" href="examples_2ex1_8cpp_source.html">Example 1</a>: nodal H1 FEM for the Laplace problem
|
||||
@@ -79,8 +77,8 @@ namespace mfem {
|
||||
* - <a class="el" href="ex19p_8cpp_source.html">Example 19p</a>: parallel incompressible nonlinear elasticity
|
||||
* - <a class="el" href="ex20_8cpp_source.html">Example 20</a>: symplectic ODE integration
|
||||
* - <a class="el" href="ex20p_8cpp_source.html">Example 20p</a>: parallel symplectic ODE integration
|
||||
* - <a class="el" href="ex21_8cpp_source.html">Example 21</a>: adaptive mesh refinement for linear elasticity
|
||||
* - <a class="el" href="ex21p_8cpp_source.html">Example 21p</a>: parallel adaptive mesh refinement for linear elasticity
|
||||
* - <a class="el" href="ex22_8cpp_source.html">Example 22</a>: adaptive mesh refinement for linear elasticity
|
||||
* - <a class="el" href="ex22p_8cpp_source.html">Example 22p</a>: parallel adaptive mesh refinement for linear elasticity
|
||||
*
|
||||
* <H4>SUNDIALS Examples</H4>
|
||||
* - Variants of Examples
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 134 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 66 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 73 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 128 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 66 KiB |
@@ -27,7 +27,7 @@ list(APPEND ALL_EXE_SRCS
|
||||
ex18.cpp
|
||||
ex19.cpp
|
||||
ex20.cpp
|
||||
ex21.cpp
|
||||
ex22.cpp
|
||||
)
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
@@ -52,7 +52,7 @@ if (MFEM_USE_MPI)
|
||||
ex18p.cpp
|
||||
ex19p.cpp
|
||||
ex20p.cpp
|
||||
ex21p.cpp
|
||||
ex22p.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
+164
-245
File diff suppressed because one or more lines are too long
+19
-15
@@ -62,7 +62,7 @@ int main(int argc, char *argv[])
|
||||
int order = 1;
|
||||
bool static_cond = false;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
const char *device = "cpu";
|
||||
bool visualization = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
@@ -75,7 +75,7 @@ int main(int argc, char *argv[])
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
args.AddOption(&device, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
@@ -88,18 +88,13 @@ 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, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 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. We choose 'ref_levels' to be the
|
||||
// largest number that gives a final mesh with no more than 50,000
|
||||
// elements.
|
||||
@@ -112,7 +107,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use continuous
|
||||
// 4. Define a finite element space on the mesh. Here we use continuous
|
||||
// Lagrange finite elements of the specified order. If order < 1, we
|
||||
// instead use an isoparametric/isogeometric space.
|
||||
FiniteElementCollection *fec;
|
||||
@@ -133,7 +128,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Number of finite element unknowns: "
|
||||
<< fespace->GetTrueVSize() << endl;
|
||||
|
||||
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined by marking all
|
||||
// the boundary attributes from the mesh as essential (Dirichlet) and
|
||||
// converting them to a list of true dofs.
|
||||
@@ -145,7 +140,7 @@ int main(int argc, char *argv[])
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 7. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
|
||||
// the basis functions in the finite element fespace.
|
||||
LinearForm *b = new LinearForm(fespace);
|
||||
@@ -153,6 +148,12 @@ int main(int argc, char *argv[])
|
||||
b->AddDomainIntegrator(new DomainLFIntegrator(one));
|
||||
b->Assemble();
|
||||
|
||||
// 7. Set device config parameters from the command line options and switch
|
||||
// to working on the device.
|
||||
Device::Configure(device);
|
||||
Device::Print();
|
||||
Device::Enable();
|
||||
|
||||
// 8. Define the solution vector x as a finite element grid function
|
||||
// corresponding to fespace. Initialize x with initial guess of zero,
|
||||
// which satisfies the boundary conditions.
|
||||
@@ -202,7 +203,10 @@ int main(int argc, char *argv[])
|
||||
// 12. Recover the solution as a finite element grid function.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 13. Save the refined mesh and the solution. This output can be viewed later
|
||||
// 13. Switch back to the host.
|
||||
Device::Disable();
|
||||
|
||||
// 14. 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);
|
||||
@@ -211,7 +215,7 @@ int main(int argc, char *argv[])
|
||||
sol_ofs.precision(8);
|
||||
x.Save(sol_ofs);
|
||||
|
||||
// 14. Send the solution by socket to a GLVis server.
|
||||
// 15. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
@@ -221,7 +225,7 @@ int main(int argc, char *argv[])
|
||||
sol_sock << "solution\n" << *mesh << x << flush;
|
||||
}
|
||||
|
||||
// 15. Free the used memory.
|
||||
// 16. Free the used memory.
|
||||
delete a;
|
||||
delete b;
|
||||
delete fespace;
|
||||
|
||||
+4
-4
@@ -5,11 +5,11 @@
|
||||
// Sample runs:
|
||||
// mpirun -np 4 ex12p -m ../data/beam-tri.mesh
|
||||
// mpirun -np 4 ex12p -m ../data/beam-quad.mesh
|
||||
// mpirun -np 4 ex12p -m ../data/beam-tet.mesh -s 462 -n 10 -o 2 -elast
|
||||
// mpirun -np 4 ex12p -m ../data/beam-hex.mesh -s 3878
|
||||
// mpirun -np 4 ex12p -m ../data/beam-wedge.mesh -s 81
|
||||
// mpirun -np 4 ex12p -m ../data/beam-tet.mesh -s 79 -n 10 -o 2 -elast
|
||||
// mpirun -np 4 ex12p -m ../data/beam-hex.mesh -s 3876
|
||||
// mpirun -np 4 ex12p -m ../data/beam-wedge.mesh -s 79
|
||||
// mpirun -np 4 ex12p -m ../data/beam-tri.mesh -s 3876 -o 2 -sys
|
||||
// mpirun -np 4 ex12p -m ../data/beam-quad.mesh -s 4544 -n 6 -o 3 -elast
|
||||
// mpirun -np 4 ex12p -m ../data/beam-quad.mesh -s 4526 -n 6 -o 3 -elast
|
||||
// mpirun -np 4 ex12p -m ../data/beam-quad-nurbs.mesh
|
||||
// mpirun -np 4 ex12p -m ../data/beam-hex-nurbs.mesh
|
||||
//
|
||||
|
||||
+1
-1
@@ -252,7 +252,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
GMRES(A, M, B, X, 3, 5000, 100, rtol*rtol, 0.0);
|
||||
GMRES(A, M, B, X, 3, 5000, 50, rtol*rtol, 0.0);
|
||||
}
|
||||
#else
|
||||
// 11. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ void InitialDeformation(const Vector &x, Vector &y);
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options
|
||||
const char *mesh_file = "../data/beam-tet.mesh";
|
||||
const char *mesh_file = "../data/beam-hex.mesh";
|
||||
int ref_levels = 0;
|
||||
int order = 2;
|
||||
bool visualization = true;
|
||||
|
||||
+1
-1
@@ -150,7 +150,7 @@ int main(int argc, char *argv[])
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
// 2. Parse command-line options
|
||||
const char *mesh_file = "../data/beam-tet.mesh";
|
||||
const char *mesh_file = "../data/beam-hex.mesh";
|
||||
int ser_ref_levels = 0;
|
||||
int par_ref_levels = 0;
|
||||
int order = 2;
|
||||
|
||||
+20
-16
@@ -65,7 +65,7 @@ int main(int argc, char *argv[])
|
||||
int order = 1;
|
||||
bool static_cond = false;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
const char *device = "cpu";
|
||||
bool visualization = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
@@ -78,7 +78,7 @@ int main(int argc, char *argv[])
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
args.AddOption(&device, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
@@ -98,18 +98,13 @@ int main(int argc, char *argv[])
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
// 3. Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
if (myid == 0) { device.Print(); }
|
||||
|
||||
// 4. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// 3. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 5. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// 4. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement. We choose
|
||||
// 'ref_levels' to be the largest number that gives a final mesh with no
|
||||
// more than 10,000 elements.
|
||||
@@ -122,7 +117,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
@@ -135,7 +130,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// 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;
|
||||
@@ -162,7 +157,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 8. Determine the list of true (i.e. parallel conforming) essential
|
||||
// 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.
|
||||
@@ -174,7 +169,7 @@ int main(int argc, char *argv[])
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 9. Set up the parallel linear form b(.) which corresponds to the
|
||||
// 8. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system, which in this case is
|
||||
// (1,phi_i) where phi_i are the basis functions in fespace.
|
||||
ParLinearForm *b = new ParLinearForm(fespace);
|
||||
@@ -182,6 +177,12 @@ int main(int argc, char *argv[])
|
||||
b->AddDomainIntegrator(new DomainLFIntegrator(one));
|
||||
b->Assemble();
|
||||
|
||||
// 9. Set device config parameters from the command line options and switch
|
||||
// to working on the device.
|
||||
Device::Configure(device);
|
||||
if (myid == 0) { Device::Print(); }
|
||||
Device::Enable();
|
||||
|
||||
// 10. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x with initial guess of zero,
|
||||
// which satisfies the boundary conditions.
|
||||
@@ -224,7 +225,10 @@ int main(int argc, char *argv[])
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 15. Save the refined mesh and the solution in parallel. This output can
|
||||
// 15. Switch back to the host.
|
||||
Device::Disable();
|
||||
|
||||
// 16. Save the refined mesh and the solution in parallel. This output can
|
||||
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
{
|
||||
ostringstream mesh_name, sol_name;
|
||||
@@ -240,7 +244,7 @@ int main(int argc, char *argv[])
|
||||
x.Save(sol_ofs);
|
||||
}
|
||||
|
||||
// 16. Send the solution by socket to a GLVis server.
|
||||
// 17. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
@@ -251,7 +255,7 @@ int main(int argc, char *argv[])
|
||||
sol_sock << "solution\n" << *pmesh << x << flush;
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
// 18. Free the used memory.
|
||||
delete a;
|
||||
delete b;
|
||||
delete fespace;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
// MFEM Example 21
|
||||
// MFEM Example 22
|
||||
//
|
||||
// Compile with: make ex21
|
||||
// Compile with: make ex22
|
||||
//
|
||||
// Sample runs: ex21
|
||||
// ex21 -o 3
|
||||
// ex21 -m ../data/beam-quad.mesh
|
||||
// ex21 -m ../data/beam-quad.mesh -o 3
|
||||
// ex21 -m ../data/beam-quad.mesh -o 3 -f 1
|
||||
// ex21 -m ../data/beam-tet.mesh
|
||||
// ex21 -m ../data/beam-tet.mesh -o 2
|
||||
// ex21 -m ../data/beam-hex.mesh
|
||||
// ex21 -m ../data/beam-hex.mesh -o 2
|
||||
// Sample runs: ex22
|
||||
// ex22 -o 3
|
||||
// ex22 -m ../data/beam-quad.mesh
|
||||
// ex22 -m ../data/beam-quad.mesh -o 3
|
||||
// ex22 -m ../data/beam-quad.mesh -o 3 -f 1
|
||||
// ex22 -m ../data/beam-tet.mesh
|
||||
// ex22 -m ../data/beam-tet.mesh -o 2
|
||||
// ex22 -m ../data/beam-hex.mesh
|
||||
// ex22 -m ../data/beam-hex.mesh -o 2
|
||||
//
|
||||
// Description: This is a version of Example 2 with a simple adaptive mesh
|
||||
// refinement loop. The problem being solved is again the linear
|
||||
@@ -287,11 +287,11 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
{
|
||||
ofstream mesh_ref_out("ex21_reference.mesh");
|
||||
ofstream mesh_ref_out("ex22_reference.mesh");
|
||||
mesh_ref_out.precision(16);
|
||||
mesh.Print(mesh_ref_out);
|
||||
|
||||
ofstream mesh_out("ex21_deformed.mesh");
|
||||
ofstream mesh_out("ex22_deformed.mesh");
|
||||
mesh_out.precision(16);
|
||||
GridFunction nodes(&fespace), *nodes_p = &nodes;
|
||||
mesh.GetNodes(nodes);
|
||||
@@ -301,7 +301,7 @@ int main(int argc, char *argv[])
|
||||
mesh.Print(mesh_out);
|
||||
mesh.SwapNodes(nodes_p, own_nodes);
|
||||
|
||||
ofstream x_out("ex21_displacement.sol");
|
||||
ofstream x_out("ex22_displacement.sol");
|
||||
x_out.precision(16);
|
||||
x.Save(x_out);
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
// MFEM Example 21
|
||||
// MFEM Example 22
|
||||
//
|
||||
// Compile with: make ex21p
|
||||
// Compile with: make ex22p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex21p
|
||||
// mpirun -np 4 ex21p -o 3
|
||||
// mpirun -np 4 ex21p -m ../data/beam-quad.mesh
|
||||
// mpirun -np 4 ex21p -m ../data/beam-quad.mesh -o 3
|
||||
// mpirun -np 4 ex21p -m ../data/beam-tet.mesh
|
||||
// mpirun -np 4 ex21p -m ../data/beam-tet.mesh -o 2
|
||||
// mpirun -np 4 ex21p -m ../data/beam-hex.mesh
|
||||
// mpirun -np 4 ex21p -m ../data/beam-hex.mesh -o 2
|
||||
// Sample runs: mpirun -np 4 ex22p
|
||||
// mpirun -np 4 ex22p -o 3
|
||||
// mpirun -np 4 ex22p -m ../data/beam-quad.mesh
|
||||
// mpirun -np 4 ex22p -m ../data/beam-quad.mesh -o 3
|
||||
// mpirun -np 4 ex22p -m ../data/beam-tet.mesh
|
||||
// mpirun -np 4 ex22p -m ../data/beam-tet.mesh -o 2
|
||||
// mpirun -np 4 ex22p -m ../data/beam-hex.mesh
|
||||
// mpirun -np 4 ex22p -m ../data/beam-hex.mesh -o 2
|
||||
//
|
||||
// Description: This is a version of Example 2p with a simple adaptive mesh
|
||||
// refinement loop. The problem being solved is again the linear
|
||||
@@ -330,7 +330,7 @@ int main(int argc, char *argv[])
|
||||
x.Update();
|
||||
}
|
||||
|
||||
// 21. Inform also the bilinear and linear forms that the space has
|
||||
// 22. Inform also the bilinear and linear forms that the space has
|
||||
// changed.
|
||||
a.Update();
|
||||
b.Update();
|
||||
@@ -338,9 +338,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
{
|
||||
ostringstream mref_name, mesh_name, sol_name;
|
||||
mref_name << "ex21p_reference_mesh." << setfill('0') << setw(6) << myid;
|
||||
mesh_name << "ex21p_deformed_mesh." << setfill('0') << setw(6) << myid;
|
||||
sol_name << "ex21p_displacement." << setfill('0') << setw(6) << myid;
|
||||
mref_name << "ex22p_reference_mesh." << setfill('0') << setw(6) << myid;
|
||||
mesh_name << "ex22p_deformed_mesh." << setfill('0') << setw(6) << myid;
|
||||
sol_name << "ex22p_displacement." << setfill('0') << setw(6) << myid;
|
||||
|
||||
ofstream mesh_ref_out(mref_name.str().c_str());
|
||||
mesh_ref_out.precision(16);
|
||||
+2
-1
@@ -102,7 +102,8 @@ int main(int argc, char *argv[])
|
||||
// 'ref_levels' to be the largest number that gives a final mesh with no
|
||||
// more than 1,000 elements.
|
||||
{
|
||||
int ref_levels = (int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
|
||||
int ref_levels =
|
||||
(int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
|
||||
+12
-11
@@ -49,7 +49,7 @@ int main(int argc, char *argv[])
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
int order = 1;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
const char *device = "cpu";
|
||||
bool visualization = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
@@ -59,7 +59,7 @@ int main(int argc, char *argv[])
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
args.AddOption(&device, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
@@ -72,19 +72,14 @@ 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, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
int sdim = mesh.SpaceDimension();
|
||||
|
||||
// 4. Since a NURBS mesh can currently only be refined uniformly, we need to
|
||||
// 3. Since a NURBS mesh can currently only be refined uniformly, we need to
|
||||
// convert it to a piecewise-polynomial curved mesh. First we refine the
|
||||
// NURBS mesh a bit more and then project the curvature to quadratic Nodes.
|
||||
if (mesh.NURBSext)
|
||||
@@ -96,11 +91,15 @@ int main(int argc, char *argv[])
|
||||
mesh.SetCurvature(2);
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. The polynomial order is
|
||||
// 4. Define a finite element space on the mesh. The polynomial order is
|
||||
// one (linear) by default, but this can be changed on the command line.
|
||||
H1_FECollection fec(order, dim);
|
||||
FiniteElementSpace fespace(&mesh, &fec);
|
||||
|
||||
// 5. Set device config parameters from the command line options.
|
||||
Device::Configure(device);
|
||||
Device::Print();
|
||||
|
||||
// 6. As in Example 1, we set up bilinear and linear forms corresponding to
|
||||
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
|
||||
// problem yet, this will be done in the main loop.
|
||||
@@ -169,7 +168,8 @@ int main(int argc, char *argv[])
|
||||
x.ProjectBdrCoefficient(zero, ess_bdr);
|
||||
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
|
||||
// 15. Assemble the stiffness matrix.
|
||||
// 15. Switch to the device and assemble the stiffness matrix.
|
||||
Device::Enable();
|
||||
a.Assemble();
|
||||
|
||||
// 16. Create the linear system: eliminate boundary conditions, constrain
|
||||
@@ -204,6 +204,7 @@ int main(int argc, char *argv[])
|
||||
// 18. After solving the linear system, reconstruct the solution as a
|
||||
// finite element GridFunction. Constrained nodes are interpolated
|
||||
// from true DOFs (it may therefore happen that x.Size() >= X.Size()).
|
||||
Device::Disable();
|
||||
a.RecoverFEMSolution(X, b, x);
|
||||
|
||||
// 19. Send solution by socket to the GLVis server.
|
||||
|
||||
+16
-15
@@ -55,7 +55,7 @@ int main(int argc, char *argv[])
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
int order = 1;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
const char *device = "cpu";
|
||||
bool visualization = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
@@ -65,7 +65,7 @@ int main(int argc, char *argv[])
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
args.AddOption(&device, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
@@ -85,19 +85,14 @@ int main(int argc, char *argv[])
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
// 3. Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
if (myid == 0) { device.Print(); }
|
||||
|
||||
// 4. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// 3. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
// 5. Refine the serial mesh on all processors to increase the resolution.
|
||||
// 4. Refine the serial mesh on all processors to increase the resolution.
|
||||
// Also project a NURBS mesh to a piecewise-quadratic curved mesh. Make
|
||||
// sure that the mesh is non-conforming.
|
||||
if (mesh->NURBSext)
|
||||
@@ -107,7 +102,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
mesh->EnsureNCMesh();
|
||||
|
||||
// 6. Define a parallel mesh by partitioning the serial mesh.
|
||||
// 5. Define a parallel mesh by partitioning the serial mesh.
|
||||
// Once the parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
@@ -117,11 +112,15 @@ int main(int argc, char *argv[])
|
||||
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
|
||||
// 7. Define a finite element space on the mesh. The polynomial order is
|
||||
// 6. Define a finite element space on the mesh. The polynomial order is
|
||||
// one (linear) by default, but this can be changed on the command line.
|
||||
H1_FECollection fec(order, dim);
|
||||
ParFiniteElementSpace fespace(&pmesh, &fec);
|
||||
|
||||
// 7. Set device config parameters from the command line options.
|
||||
Device::Configure(device);
|
||||
if (myid == 0) { Device::Print(); }
|
||||
|
||||
// 8. As in Example 1p, we set up bilinear and linear forms corresponding to
|
||||
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
|
||||
// problem yet, this will be done in the main loop.
|
||||
@@ -201,10 +200,11 @@ int main(int argc, char *argv[])
|
||||
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
b.Assemble();
|
||||
|
||||
// 15. Assemble the stiffness matrix. Note that MFEM doesn't care at this
|
||||
// point that the mesh is nonconforming and parallel. The FE space is
|
||||
// considered 'cut' along hanging edges/faces, and also across
|
||||
// processor boundaries.
|
||||
// 15. Switch to the device and assemble the stiffness matrix. Note that
|
||||
// MFEM doesn't care at this point that the mesh is nonconforming and
|
||||
// parallel. The FE space is considered 'cut' along hanging
|
||||
// edges/faces, and also across processor boundaries.
|
||||
Device::Enable();
|
||||
a.Assemble();
|
||||
|
||||
// 16. Create the parallel linear system: eliminate boundary conditions.
|
||||
@@ -232,6 +232,7 @@ int main(int argc, char *argv[])
|
||||
// 18. Switch back to the host and extract the parallel grid function
|
||||
// corresponding to the finite element approximation X. This is the
|
||||
// local solution on each processor.
|
||||
Device::Disable();
|
||||
a.RecoverFEMSolution(X, b, x);
|
||||
|
||||
// 19. Send the solution by socket to a GLVis server.
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
// MFEM Example 1
|
||||
//
|
||||
// Compile with: make exSBP
|
||||
//
|
||||
// Sample runs: exSBP -sbp -o 0 -p 0 -r 1
|
||||
// exSBP -sbp -o 4 -p 3
|
||||
//
|
||||
//
|
||||
// Description: This example code builds on Example 1 but adds SBP operators.
|
||||
// It 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 or SBP 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 <chrono>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
int problem;
|
||||
|
||||
// Prescribed time-independent boundary and right-hand side functions.
|
||||
double bdr_func(const Vector &pt);
|
||||
double rhs_func(const Vector &pt);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../data/unitGridTestMesh.msh";
|
||||
int order = 1;
|
||||
bool static_cond = false;
|
||||
bool visualization = 1;
|
||||
bool sbp = 1;
|
||||
problem = 1;
|
||||
int ref_levels = 0;
|
||||
bool convOut = false;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&sbp, "-sbp", "--summationbyparts", "-no-sbp",
|
||||
"--no-summationbyparts",
|
||||
"Enable or disable use of SBP operators.");
|
||||
args.AddOption(&problem, "-p", "--problem",
|
||||
"Problem setup to use: 0 = transcendental manufactured solution, "
|
||||
"1 = linear displacement, "
|
||||
"2 = quadratic displacement, "
|
||||
"3 = cubic displacement, "
|
||||
"4 = quartic displacement.");
|
||||
args.AddOption(&ref_levels, "-r", "--ref-levels",
|
||||
"Number of initial uniform refinement levels.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
// 2. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 3. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
|
||||
// largest number that gives a final mesh with no more than 50,000
|
||||
// elements.
|
||||
{
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Define a finite element space on the mesh. Here we use continuous
|
||||
// Lagrange finite elements of the specified order. If order < 1, we
|
||||
// instead use an isoparametric/isogeometric space.
|
||||
FiniteElementCollection *fec;
|
||||
if (sbp)
|
||||
{
|
||||
fec = new C_SBPCollection(order, dim);
|
||||
}
|
||||
else if (order > 0)
|
||||
{
|
||||
fec = new H1_FECollection(order, dim);
|
||||
}
|
||||
else if (mesh->GetNodes())
|
||||
{
|
||||
fec = mesh->GetNodes()->OwnFEC();
|
||||
cout << "Using isoparametric FEs: " << fec->Name() << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
fec = new H1_FECollection(order = 1, dim);
|
||||
}
|
||||
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
|
||||
cout << "Number of finite element unknowns: "
|
||||
<< fespace->GetTrueVSize() << endl;
|
||||
|
||||
// 7. Define the solution vector x as a finite element grid function
|
||||
// corresponding to fespace. Initialize x with initial guess of zero,
|
||||
// which satisfies the boundary conditions.
|
||||
GridFunction x(fespace);
|
||||
x = 0.0;
|
||||
|
||||
// Create function coefficient bdr which holds the exact solution and is
|
||||
// used to strongly impose boundary conditions.
|
||||
FunctionCoefficient bdr(bdr_func);
|
||||
|
||||
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined by marking all
|
||||
// the boundary attributes from the mesh as essential (Dirichlet) and
|
||||
// converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
|
||||
// Project boundary conditions onto grid function to strongly impose
|
||||
// boundary conditions. BC's are defined in the function `bdr_func`.
|
||||
x.ProjectBdrCoefficient(bdr, ess_bdr);
|
||||
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
|
||||
// the basis functions in the finite element fespace.
|
||||
LinearForm *b = new LinearForm(fespace);
|
||||
|
||||
FunctionCoefficient rhs(rhs_func);
|
||||
b->AddDomainIntegrator(new DomainLFIntegrator(rhs));
|
||||
|
||||
if (problem < 0 || problem > 4)
|
||||
{
|
||||
mfem::out << "Invalid problem type: " << problem << "\n";
|
||||
delete mesh;
|
||||
return 3;
|
||||
}
|
||||
|
||||
// // Start timing
|
||||
// std::chrono::time_point<std::chrono::high_resolution_clock> start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
b->Assemble();
|
||||
|
||||
// // End timing and compute interval
|
||||
// std::chrono::time_point<std::chrono::high_resolution_clock> finish = std::chrono::high_resolution_clock::now();
|
||||
// std::chrono::duration<double> elapsed = finish - start;
|
||||
// std::cout << "\nb->Assemble() elapsed time: " << elapsed.count() << " s\n";
|
||||
|
||||
// 8. Set up the bilinear form a(.,.) on the finite element space
|
||||
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
|
||||
// domain integrator.
|
||||
BilinearForm *a = new BilinearForm(fespace);
|
||||
ConstantCoefficient one(1.0);
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
|
||||
// 9. Assemble the bilinear form and the corresponding linear system,
|
||||
// applying any necessary transformations such as: eliminating boundary
|
||||
// conditions, applying conforming constraints for non-conforming AMR,
|
||||
// static condensation, etc.
|
||||
if (static_cond) { a->EnableStaticCondensation(); }
|
||||
|
||||
// // Start timing
|
||||
// start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
a->Assemble();
|
||||
|
||||
// // End timing and compute interval
|
||||
// finish = std::chrono::high_resolution_clock::now();
|
||||
// elapsed = finish - start;
|
||||
// std::cout << "\na->Assemble() elapsed time: " << elapsed.count() << " s\n";
|
||||
|
||||
SparseMatrix A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
mfem::out << "Size of linear system: " << A.Height() << endl;
|
||||
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
// 10. Define a simple symmetric Gauss-Seidel preconditioner and use it to
|
||||
// solve the system A X = B with PCG.
|
||||
GSSmoother M(A);
|
||||
PCG(A, M, B, X, 1, 1000, 1e-12, 0.0);
|
||||
#else
|
||||
// 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
|
||||
UMFPackSolver umf_solver;
|
||||
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
|
||||
umf_solver.SetOperator(A);
|
||||
umf_solver.Mult(B, X);
|
||||
#endif
|
||||
|
||||
// 11. Recover the solution as a finite element grid function.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 12. Compute and print the L^2 norm of the error.
|
||||
mfem::out << "\n|| u_h - u ||_{L^2} = " << x.ComputeL2Error(bdr) << '\n' << endl;
|
||||
// mfem::out << "h: " << 0.1 / pow(2, ref_levels) << "\n";
|
||||
|
||||
// 12. Save the refined mesh and the solution. This output can be viewed later
|
||||
// using GLVis: "glvis -m refined.mesh -g sol.gf".
|
||||
ofstream mesh_ofs("refined.mesh");
|
||||
mesh_ofs.precision(8);
|
||||
mesh->Print(mesh_ofs);
|
||||
// mesh->PrintVTK(mesh_ofs);
|
||||
ofstream sol_ofs("sol.gf");
|
||||
sol_ofs.precision(8);
|
||||
x.Save(sol_ofs);
|
||||
|
||||
// Save solution mesh in vtk file
|
||||
char solFileName[32];
|
||||
if (sbp)
|
||||
{
|
||||
snprintf(solFileName, 32, "exSBP_SBP_O%d_P%d.vtk", order, problem);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(solFileName, 32, "exSBP_FE_O%d_P%d.vtk", order, problem);
|
||||
}
|
||||
|
||||
if (convOut)
|
||||
{
|
||||
// Save convergence study information in output file
|
||||
char outfileName[32];
|
||||
if (problem == 0)
|
||||
{
|
||||
snprintf(outfileName, 32, "convOutputP%d_manufactured.txt", order);
|
||||
}
|
||||
else if (problem == 1)
|
||||
{
|
||||
snprintf(outfileName, 32, "convOutputP%d_lin.txt", order);
|
||||
}
|
||||
else if (problem == 2)
|
||||
{
|
||||
snprintf(outfileName, 32, "convOutputP%d_quad.txt", order);
|
||||
}
|
||||
else if (problem == 3)
|
||||
{
|
||||
snprintf(outfileName, 32, "convOutputP%d_cubic.txt", order);
|
||||
}
|
||||
else if (problem == 4)
|
||||
{
|
||||
snprintf(outfileName, 32, "convOutputP%d_quartic.txt", order);
|
||||
}
|
||||
|
||||
|
||||
ofstream outputFile;
|
||||
outputFile.open(outfileName, ios::out | ios::app);
|
||||
|
||||
if (outputFile.is_open())
|
||||
{
|
||||
outputFile << x.ComputeL2Error(bdr) << ", " << 0.1 / pow(2, ref_levels) << "\n";
|
||||
}
|
||||
outputFile.close();
|
||||
}
|
||||
|
||||
ofstream omesh(solFileName);
|
||||
omesh.precision(14);
|
||||
mesh->PrintVTK(omesh, 1);
|
||||
x.SaveVTK(omesh, "sol", 1);
|
||||
|
||||
// 13. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *mesh << x << flush;
|
||||
}
|
||||
|
||||
// 14. Free the used memory.
|
||||
delete a;
|
||||
delete b;
|
||||
delete fespace;
|
||||
if (order > 0) { delete fec; }
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Exact solution, used for the Dirichlet BC.
|
||||
double bdr_func(const Vector &pt)
|
||||
{
|
||||
double x = pt(0), y = pt(1), z = 0.0;
|
||||
|
||||
if (problem == 0) // manufactured solution
|
||||
{
|
||||
z = sin(M_PI*x)*sin(M_PI*y);
|
||||
}
|
||||
else if (problem == 1) // linear displacement
|
||||
{
|
||||
z = 0.5*x + 0.5*y;
|
||||
}
|
||||
else if (problem == 2) // quadratic displacement
|
||||
{
|
||||
z = 0.5*x*x + 0.5*y*y;
|
||||
}
|
||||
else if (problem == 3) // manufactured solution
|
||||
{
|
||||
z = 0.5*x*x*x + 0.5*y*y*y;
|
||||
}
|
||||
else if (problem == 4) // manufactured solution
|
||||
{
|
||||
z = 0.5*x*x*x*x + 0.5*y*y*y*y;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
// right hand side function for manufactured solution
|
||||
double rhs_func(const Vector &pt)
|
||||
{
|
||||
double x = pt(0), y = pt(1), z = 0.0;
|
||||
if (problem == 0)
|
||||
{
|
||||
z = 2*M_PI*M_PI*sin(M_PI*x)*sin(M_PI*y);
|
||||
}
|
||||
else if (problem == 1)
|
||||
{
|
||||
z = 0;
|
||||
}
|
||||
else if (problem == 2)
|
||||
{
|
||||
z = -2;
|
||||
}
|
||||
else if (problem == 3)
|
||||
{
|
||||
z = -3*(x+y);
|
||||
}
|
||||
else if (problem == 4)
|
||||
{
|
||||
z = -6*(x*x + y*y);
|
||||
}
|
||||
return z;
|
||||
}
|
||||
+3
-3
@@ -22,9 +22,9 @@ MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
SEQ_EXAMPLES = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 ex17\
|
||||
ex18 ex19 ex20 ex21
|
||||
ex18 ex19 ex20 ex22 exSBP
|
||||
PAR_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p ex12p\
|
||||
ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p
|
||||
ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex22p
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
EXAMPLES = $(SEQ_EXAMPLES)
|
||||
@@ -125,4 +125,4 @@ clean-exec:
|
||||
@rm -f vortex-mesh.* vortex.mesh vortex-?-init.* vortex-?-final.*
|
||||
@rm -f deformation.* pressure.*
|
||||
@rm -f ex20.dat ex20p_?????.dat gnuplot_ex20.inp gnuplot_ex20p.inp
|
||||
@rm -f ex21*.mesh ex21*.sol ex21p_*.*
|
||||
@rm -f ex22*.mesh ex22*.sol ex22p_*.*
|
||||
|
||||
@@ -27,11 +27,8 @@
|
||||
// method HyperelasticOperator::ImplicitSolve is the only
|
||||
// requirement for high-order implicit (SDIRK) time integration.
|
||||
// If using PETSc to solve the nonlinear problem, use the option
|
||||
// files provided (see rc_ex10p, rc_ex10p_mf, rc_ex10p_mfop) that
|
||||
// customize the Newton-Krylov method.
|
||||
// When option --jfnk is used, PETSc will use a Jacobian-free
|
||||
// Newton-Krylov method, using a user-defined preconditioner
|
||||
// constructed with the PetscPreconditionerFactory class.
|
||||
// file provided (rc_ex10p) that customizes the
|
||||
// Newton-Krylov method.
|
||||
//
|
||||
// We recommend viewing examples 2 and 9 before viewing this
|
||||
// example.
|
||||
@@ -89,15 +86,12 @@ protected:
|
||||
Solver *J_solver;
|
||||
/// Preconditioner for the Jacobian solve in the Newton method
|
||||
Solver *J_prec;
|
||||
/// Preconditioner factory for JFNK
|
||||
PetscPreconditionerFactory *J_factory;
|
||||
|
||||
mutable Vector z; // auxiliary vector
|
||||
|
||||
public:
|
||||
HyperelasticOperator(ParFiniteElementSpace &f, Array<int> &ess_bdr,
|
||||
double visc, double mu, double K,
|
||||
bool use_petsc, bool petsc_use_jfnk);
|
||||
double visc, double mu, double K, bool use_petsc);
|
||||
|
||||
/// Compute the right-hand side of the ODE system.
|
||||
virtual void Mult(const Vector &vx, Vector &dvx_dt) const;
|
||||
@@ -142,21 +136,8 @@ public:
|
||||
virtual Operator &GetGradient(const Vector &k) const;
|
||||
|
||||
virtual ~ReducedSystemOperator();
|
||||
|
||||
};
|
||||
|
||||
/** Auxiliary class to provide preconditioners for matrix-free methods */
|
||||
class PreconditionerFactory : public PetscPreconditionerFactory
|
||||
{
|
||||
private:
|
||||
// const ReducedSystemOperator& op; // unused for now (generates warning)
|
||||
|
||||
public:
|
||||
PreconditionerFactory(const ReducedSystemOperator& op_, const string& name_)
|
||||
: PetscPreconditionerFactory(name_) /* , op(op_) */ {}
|
||||
virtual mfem::Solver* NewPreconditioner(const mfem::OperatorHandle&);
|
||||
virtual ~PreconditionerFactory() {}
|
||||
};
|
||||
|
||||
/** Function representing the elastic energy density for the given hyperelastic
|
||||
model+deformation. Used in HyperelasticOperator::GetElasticEnergyDensity. */
|
||||
@@ -206,7 +187,6 @@ int main(int argc, char *argv[])
|
||||
int vis_steps = 1;
|
||||
bool use_petsc = true;
|
||||
const char *petscrc_file = "";
|
||||
bool petsc_use_jfnk = false;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
@@ -241,9 +221,6 @@ int main(int argc, char *argv[])
|
||||
"Use or not PETSc to solve the nonlinear system.");
|
||||
args.AddOption(&petscrc_file, "-petscopts", "--petscopts",
|
||||
"PetscOptions file to use.");
|
||||
args.AddOption(&petsc_use_jfnk, "-jfnk", "--jfnk", "-no-jfnk",
|
||||
"--no-jfnk",
|
||||
"Use JFNK with user-defined preconditioner factory.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
@@ -367,8 +344,7 @@ int main(int argc, char *argv[])
|
||||
// 9. Initialize the hyperelastic operator, the GLVis visualization and print
|
||||
// the initial energies.
|
||||
HyperelasticOperator *oper = new HyperelasticOperator(fespace, ess_bdr, visc,
|
||||
mu, K, use_petsc,
|
||||
petsc_use_jfnk);
|
||||
mu, K, use_petsc);
|
||||
|
||||
socketstream vis_v, vis_w;
|
||||
if (visualization)
|
||||
@@ -544,7 +520,7 @@ Operator &ReducedSystemOperator::GetGradient(const Vector &k) const
|
||||
add(*v, dt, k, w);
|
||||
add(*x, dt, w, z);
|
||||
localJ->Add(dt*dt, H->GetLocalGradient(z));
|
||||
// if we are using PETSc, the HypreParCSR Jacobian will be converted to
|
||||
// if we are using PETSc, the HypreParCSR jacobian will be converted to
|
||||
// PETSc's AIJ on the fly
|
||||
Jacobian = M->ParallelAssemble(localJ);
|
||||
delete localJ;
|
||||
@@ -561,8 +537,7 @@ ReducedSystemOperator::~ReducedSystemOperator()
|
||||
|
||||
HyperelasticOperator::HyperelasticOperator(ParFiniteElementSpace &f,
|
||||
Array<int> &ess_bdr, double visc,
|
||||
double mu, double K, bool use_petsc,
|
||||
bool use_petsc_factory)
|
||||
double mu, double K, bool use_petsc)
|
||||
: TimeDependentOperator(2*f.TrueVSize(), 0.0), fespace(f),
|
||||
M(&fespace), S(&fespace), H(&fespace),
|
||||
viscosity(visc), M_solver(f.GetComm()),
|
||||
@@ -615,8 +590,6 @@ HyperelasticOperator::HyperelasticOperator(ParFiniteElementSpace &f,
|
||||
J_minres->SetPreconditioner(*J_prec);
|
||||
J_solver = J_minres;
|
||||
|
||||
J_factory = NULL;
|
||||
|
||||
newton_solver.iterative_mode = false;
|
||||
newton_solver.SetSolver(*J_solver);
|
||||
newton_solver.SetOperator(*reduced_oper);
|
||||
@@ -627,20 +600,12 @@ HyperelasticOperator::HyperelasticOperator(ParFiniteElementSpace &f,
|
||||
}
|
||||
else
|
||||
{
|
||||
// if using PETSc, we create the same solver (Newton + MINRES + Jacobi)
|
||||
// if using PETSc, we create the same solver (NEWTON+MINRES+Jacobi)
|
||||
// by command line options (see rc_ex10p)
|
||||
J_solver = NULL;
|
||||
J_prec = NULL;
|
||||
J_factory = NULL;
|
||||
pnewton_solver = new PetscNonlinearSolver(f.GetComm(),
|
||||
*reduced_oper);
|
||||
|
||||
// we can setup a factory to construct a "physics-based" preconditioner
|
||||
if (use_petsc_factory)
|
||||
{
|
||||
J_factory = new PreconditionerFactory(*reduced_oper, "JFNK preconditioner");
|
||||
pnewton_solver->SetPreconditionerFactory(J_factory);
|
||||
}
|
||||
pnewton_solver->SetPrintLevel(1); // print Newton iterations
|
||||
pnewton_solver->SetRelTol(rel_tol);
|
||||
pnewton_solver->SetAbsTol(0.0);
|
||||
@@ -726,26 +691,12 @@ HyperelasticOperator::~HyperelasticOperator()
|
||||
{
|
||||
delete J_solver;
|
||||
delete J_prec;
|
||||
delete J_factory;
|
||||
delete reduced_oper;
|
||||
delete model;
|
||||
delete Mmat;
|
||||
delete pnewton_solver;
|
||||
}
|
||||
|
||||
// This method gets called every time we need a preconditioner "oh"
|
||||
// contains the PetscParMatrix that wraps the operator constructed in
|
||||
// the GetGradient() method (see also PetscSolver::SetJacobianType()).
|
||||
// In this example, we just return a customizable PetscPreconditioner
|
||||
// using that matrix. However, the OperatorHandle argument can be
|
||||
// ignored, and any "physics-based" solver can be constructed since we
|
||||
// have access to the HyperElasticOperator class.
|
||||
Solver* PreconditionerFactory::NewPreconditioner(const mfem::OperatorHandle& oh)
|
||||
{
|
||||
PetscParMatrix *pP;
|
||||
oh.Get(pP);
|
||||
return new PetscPreconditioner(*pP,"jfnk_");
|
||||
}
|
||||
|
||||
double ElasticEnergyCoefficient::Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
@@ -759,8 +710,8 @@ double ElasticEnergyCoefficient::Eval(ElementTransformation &T,
|
||||
|
||||
void InitialDeformation(const Vector &x, Vector &y)
|
||||
{
|
||||
// set the initial configuration to be the same as the reference,
|
||||
// stress free, configuration
|
||||
// set the initial configuration to be the same as the reference, stress
|
||||
// free, configuration
|
||||
y = x;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,10 +84,6 @@ EX9_E_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts r
|
||||
EX9_ES_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step
|
||||
EX9_IS_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5
|
||||
EX10_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3
|
||||
EX10_MF_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mf -tf 6 -s 3 -rs 0 -dt 3
|
||||
EX10_MFOP_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mfop -tf 6 -s 3 -rs 0 -dt 3
|
||||
EX10_JFNK_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_jfnk --jfnk -tf 6 -s 3 -rs 0 -dt 3
|
||||
|
||||
ex1p-test-par: ex1p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_W))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_P))
|
||||
@@ -111,9 +107,6 @@ ex9p-test-par: ex9p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX9_IS_ARGS))
|
||||
ex10p-test-par: ex10p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_ARGS))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_MF_ARGS))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_MFOP_ARGS))
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_JFNK_ARGS))
|
||||
|
||||
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# matrix-free Jacobian action, preconditioner constructed using PetscPreconditionerFactory
|
||||
-snes_monitor
|
||||
-snes_mf_operator
|
||||
-ksp_type minres
|
||||
-jfnk_pc_type jacobi
|
||||
@@ -1,4 +0,0 @@
|
||||
# matrix free -> no preconditioner
|
||||
-snes_monitor
|
||||
-snes_mf
|
||||
-ksp_type minres
|
||||
@@ -1,5 +0,0 @@
|
||||
# matrix-free Jacobian action, preconditioner constructed from the matrix obtained by the GetGradient() method
|
||||
-snes_monitor
|
||||
-snes_mf_operator
|
||||
-ksp_type minres
|
||||
-pc_type jacobi
|
||||
@@ -42,12 +42,12 @@ add_mfem_examples(SUNDIALS_EXAMPLES_SRCS ${PFX} "" test_sundials)
|
||||
# ctest -R sundials
|
||||
|
||||
# Command line options for the tests.
|
||||
# Example 9: test CVODE with CV_ADAMS (non-stiff implicit) time stepping
|
||||
set(EX9_COMMON_OPTS -m ../../data/periodic-hexagon.mesh -p 0 -s 7)
|
||||
# Example 9: test explicit CVODE time stepping
|
||||
set(EX9_COMMON_OPTS -m ../../data/periodic-hexagon.mesh -p 0 -s 11)
|
||||
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 -dt 0.0018 -vs 25)
|
||||
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS} -rp 1 -dt 0.0009 -vs 50)
|
||||
# Example 10: test CVODE with CV_BDF (stiff implicit) time stepping
|
||||
set(EX10_COMMON_OPTS -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -tf 6 -vs 10)
|
||||
# Example 10: test implicit CVODE time stepping
|
||||
set(EX10_COMMON_OPTS -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -vs 10)
|
||||
set(EX10_TEST_OPTS ${EX10_COMMON_OPTS} -r 2)
|
||||
set(EX10P_TEST_OPTS ${EX10_COMMON_OPTS} -rp 1)
|
||||
# Example 16: use the default options
|
||||
|
||||
+210
-204
@@ -4,16 +4,16 @@
|
||||
// Compile with: make ex10
|
||||
//
|
||||
// Sample runs:
|
||||
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 12 -dt 0.15 -vs 10
|
||||
// ex10 -m ../../data/beam-tri.mesh -r 2 -o 2 -s 16 -dt 0.3 -vs 5
|
||||
// ex10 -m ../../data/beam-hex.mesh -r 1 -o 2 -s 12 -dt 0.2 -vs 5
|
||||
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 5 -dt 0.15 -vs 10
|
||||
// ex10 -m ../../data/beam-tri.mesh -r 2 -o 2 -s 7 -dt 0.3 -vs 5
|
||||
// ex10 -m ../../data/beam-hex.mesh -r 1 -o 2 -s 5 -dt 0.2 -vs 5
|
||||
// ex10 -m ../../data/beam-tri.mesh -r 2 -o 2 -s 2 -dt 3 -nls kinsol
|
||||
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 2 -dt 3 -nls kinsol
|
||||
// ex10 -m ../../data/beam-hex.mesh -r 1 -o 2 -s 2 -dt 3 -nls kinsol
|
||||
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 14 -dt 0.15 -vs 10
|
||||
// ex10 -m ../../data/beam-tri.mesh -r 2 -o 2 -s 17 -dt 0.01 -vs 30
|
||||
// ex10 -m ../../data/beam-hex.mesh -r 1 -o 2 -s 14 -dt 0.15 -vs 10
|
||||
// ex10 -m ../../data/beam-quad-amr.mesh -r 2 -o 2 -s 12 -dt 0.15 -vs 10
|
||||
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 15 -dt 5e-3 -vs 60
|
||||
// ex10 -m ../../data/beam-tri.mesh -r 2 -o 2 -s 16 -dt 0.01 -vs 30
|
||||
// ex10 -m ../../data/beam-hex.mesh -r 1 -o 2 -s 15 -dt 0.01 -vs 30
|
||||
// ex10 -m ../../data/beam-quad-amr.mesh -r 2 -o 2 -s 5 -dt 0.15 -vs 10
|
||||
//
|
||||
// Description: This examples solves a time dependent nonlinear elasticity
|
||||
// problem of the form dv/dt = H(x) + S v, dx/dt = v, where H is a
|
||||
@@ -53,6 +53,7 @@ using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
class ReducedSystemOperator;
|
||||
class SundialsJacSolver;
|
||||
|
||||
/** After spatial discretization, the hyperelastic model can be written as a
|
||||
* system of ODEs:
|
||||
@@ -91,17 +92,12 @@ protected:
|
||||
|
||||
mutable Vector z; // auxiliary vector
|
||||
|
||||
SparseMatrix *grad_H;
|
||||
SparseMatrix *Jacobian;
|
||||
|
||||
double saved_gamma; // saved gamma value from implicit setup
|
||||
|
||||
public:
|
||||
/// Solver type to use in the ImplicitSolve() method, used by SDIRK methods.
|
||||
enum NonlinearSolverType
|
||||
{
|
||||
NEWTON = 0, ///< Use MFEM's plain NewtonSolver
|
||||
KINSOL = 1 ///< Use SUNDIALS' KINSOL (through MFEM's class KINSolver)
|
||||
KINSOL = 1 ///< Use SUNDIALS' KINSOL (through MFEM's class KinSolver)
|
||||
};
|
||||
|
||||
HyperelasticOperator(FiniteElementSpace &f, Array<int> &ess_bdr,
|
||||
@@ -110,41 +106,15 @@ public:
|
||||
|
||||
/// Compute the right-hand side of the ODE system.
|
||||
virtual void Mult(const Vector &vx, Vector &dvx_dt) const;
|
||||
|
||||
/** Solve the Backward-Euler equation: k = f(x + dt*k, t), for the unknown k.
|
||||
This is the only requirement for high-order SDIRK implicit integration.*/
|
||||
virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k);
|
||||
|
||||
|
||||
/// Custom Jacobian system solver for the SUNDIALS time integrators.
|
||||
/** For the ODE system represented by HyperelasticOperator
|
||||
|
||||
M dv/dt = -(H(x) + S*v)
|
||||
dx/dt = v,
|
||||
|
||||
this class facilitates the solution of linear systems of the form
|
||||
|
||||
(M + γS) yv + γJ yx = M bv, J=(dH/dx)(x)
|
||||
- γ yv + yx = bx
|
||||
|
||||
for given bv, bx, x, and γ = GetTimeStep(). */
|
||||
|
||||
/** Linear solve applicable to the SUNDIALS format.
|
||||
Solves (Mass - dt J) y = Mass b, where in our case:
|
||||
Mass = | M 0 | J = | -S -grad_H | y = | v_hat | b = | b_v |
|
||||
| 0 I | | I 0 | | x_hat | | b_x |
|
||||
The result replaces the rhs b.
|
||||
We substitute x_hat = b_x + dt v_hat and solve
|
||||
(M + dt S + dt^2 grad_H) v_hat = M b_v - dt grad_H b_x. */
|
||||
|
||||
/** Setup the linear system. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSetup(const Vector &y, const Vector &fy,
|
||||
int jok, int *jcur, double gamma);
|
||||
|
||||
/** Solve the linear system. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSolve(const Vector &b, Vector &x, double tol);
|
||||
/** Connect the Jacobian linear system solver (SundialsJacSolver) used by
|
||||
SUNDIALS' CVODE and ARKODE time integrators to the internal objects
|
||||
created by HyperelasticOperator. This method is called by the InitSystem
|
||||
method of SundialsJacSolver. */
|
||||
void InitSundialsJacSolver(SundialsJacSolver &sjsolv);
|
||||
|
||||
double ElasticEnergy(const Vector &x) const;
|
||||
double KineticEnergy(const Vector &v) const;
|
||||
@@ -182,6 +152,53 @@ public:
|
||||
virtual ~ReducedSystemOperator();
|
||||
};
|
||||
|
||||
/// Custom Jacobian system solver for the SUNDIALS time integrators.
|
||||
/** For the ODE system represented by HyperelasticOperator
|
||||
|
||||
M dv/dt = -(H(x) + S*v)
|
||||
dx/dt = v,
|
||||
|
||||
this class facilitates the solution of linear systems of the form
|
||||
|
||||
(M + γS) yv + γJ yx = M bv, J=(dH/dx)(x)
|
||||
- γ yv + yx = bx
|
||||
|
||||
for given bv, bx, x, and γ = GetTimeStep(). */
|
||||
class SundialsJacSolver : public SundialsODELinearSolver
|
||||
{
|
||||
private:
|
||||
BilinearForm *M, *S;
|
||||
NonlinearForm *H;
|
||||
SparseMatrix *grad_H, *Jacobian;
|
||||
Solver *J_solver;
|
||||
|
||||
public:
|
||||
SundialsJacSolver()
|
||||
: M(), S(), H(), grad_H(), Jacobian(), J_solver() { }
|
||||
|
||||
/// Connect the solver to the objects created inside HyperelasticOperator.
|
||||
void SetOperators(BilinearForm &M_, BilinearForm &S_,
|
||||
NonlinearForm &H_, Solver &solver)
|
||||
{
|
||||
M = &M_; S = &S_; H = &H_; J_solver = &solver;
|
||||
}
|
||||
|
||||
/** Linear solve applicable to the SUNDIALS format.
|
||||
Solves (Mass - dt J) y = Mass b, where in our case:
|
||||
Mass = | M 0 | J = | -S -grad_H | y = | v_hat | b = | b_v |
|
||||
| 0 I | | I 0 | | x_hat | | b_x |
|
||||
The result replaces the rhs b.
|
||||
We substitute x_hat = b_x + dt v_hat and solve
|
||||
(M + dt S + dt^2 grad_H) v_hat = M b_v - dt grad_H b_x. */
|
||||
int InitSystem(void *sundials_mem);
|
||||
int SetupSystem(void *sundials_mem, int conv_fail,
|
||||
const Vector &y_pred, const Vector &f_pred, int &jac_cur,
|
||||
Vector &v_temp1, Vector &v_temp2, Vector &v_temp3);
|
||||
int SolveSystem(void *sundials_mem, Vector &b, const Vector &weight,
|
||||
const Vector &y_cur, const Vector &f_cur);
|
||||
int FreeSystem(void *sundials_mem);
|
||||
};
|
||||
|
||||
|
||||
/** Function representing the elastic energy density for the given hyperelastic
|
||||
model+deformation. Used in HyperelasticOperator::GetElasticEnergyDensity. */
|
||||
@@ -226,12 +243,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Relative and absolute tolerances for CVODE and ARKODE.
|
||||
const double reltol = 1e-1, abstol = 1e-1;
|
||||
// Since this example uses the loose tolerances defined above, it is
|
||||
// necessary to lower the linear solver tolerance for CVODE which is relative
|
||||
// to the above tolerances.
|
||||
const double cvode_eps_lin = 1e-4;
|
||||
// Similarly, the nonlinear tolerance for ARKODE needs to be tightened.
|
||||
const double arkode_eps_nonlin = 1e-6;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
@@ -241,24 +252,15 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver:\n\t"
|
||||
"1 - Backward Euler,\n\t"
|
||||
"2 - SDIRK2, L-stable\n\t"
|
||||
"3 - SDIRK3, L-stable\n\t"
|
||||
"4 - Implicit Midpoint,\n\t"
|
||||
"5 - SDIRK2, A-stable,\n\t"
|
||||
"6 - SDIRK3, A-stable,\n\t"
|
||||
"7 - Forward Euler,\n\t"
|
||||
"8 - RK2,\n\t"
|
||||
"9 - RK3 SSP,\n\t"
|
||||
"10 - RK4,\n\t"
|
||||
"11 - CVODE implicit BDF, approximate Jacobian,\n\t"
|
||||
"12 - CVODE implicit BDF, specified Jacobian,\n\t"
|
||||
"13 - CVODE implicit ADAMS, approximate Jacobian,\n\t"
|
||||
"14 - CVODE implicit ADAMS, specified Jacobian,\n\t"
|
||||
"15 - ARKODE implicit, approximate Jacobian,\n\t"
|
||||
"16 - ARKODE implicit, specified Jacobian,\n\t"
|
||||
"17 - ARKODE explicit, 4th order.");
|
||||
"ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
|
||||
" 4 - CVODE implicit, approximate Jacobian,\n\t"
|
||||
" 5 - CVODE implicit, specified Jacobian,\n\t"
|
||||
" 6 - ARKODE implicit, approximate Jacobian,\n\t"
|
||||
" 7 - ARKODE implicit, specified Jacobian,\n\t"
|
||||
" 11 - Forward Euler, 12 - RK2,\n\t"
|
||||
" 13 - RK3 SSP, 14 - RK4,\n\t"
|
||||
" 15 - CVODE (adaptive order) explicit,\n\t"
|
||||
" 16 - ARKODE default (4th order) explicit.");
|
||||
args.AddOption(&nls, "-nls", "--nonlinear-solver",
|
||||
"Nonlinear systems solver: "
|
||||
"\"newton\" (plain Newton) or \"kinsol\" (KINSOL).");
|
||||
@@ -285,19 +287,72 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
// check for vaild ODE solver option
|
||||
if (ode_solver_type < 1 || ode_solver_type > 17)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 2. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral and hexahedral meshes with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 3. Setup the nonlinear solver
|
||||
// 3. Define the ODE solver used for time integration. Several implicit
|
||||
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
|
||||
// explicit Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKODESolver *arkode = NULL;
|
||||
SundialsJacSolver *sjsolver = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Implicit L-stable methods
|
||||
case 1: ode_solver = new BackwardEulerSolver; break;
|
||||
case 2: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 3: ode_solver = new SDIRK33Solver; break;
|
||||
case 4:
|
||||
case 5:
|
||||
cvode = new CVODESolver(CV_BDF, CV_NEWTON);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 5)
|
||||
{
|
||||
sjsolver = new SundialsJacSolver;
|
||||
cvode->SetLinearSolver(*sjsolver);
|
||||
}
|
||||
ode_solver = cvode; break;
|
||||
case 6:
|
||||
case 7:
|
||||
arkode = new ARKODESolver(ARKODESolver::IMPLICIT);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 7)
|
||||
{
|
||||
// Custom Jacobian inversion.
|
||||
sjsolver = new SundialsJacSolver;
|
||||
arkode->SetLinearSolver(*sjsolver);
|
||||
}
|
||||
ode_solver = arkode; break;
|
||||
// Explicit methods
|
||||
case 11: ode_solver = new ForwardEulerSolver; break;
|
||||
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 13: ode_solver = new RK3SSPSolver; break;
|
||||
case 14: ode_solver = new RK4Solver; break;
|
||||
case 15:
|
||||
cvode = new CVODESolver(CV_ADAMS, CV_FUNCTIONAL);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 16:
|
||||
arkode = new ARKODESolver(ARKODESolver::IMPLICIT);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
// Implicit A-stable methods (not L-stable)
|
||||
case 22: ode_solver = new ImplicitMidpointSolver; break;
|
||||
case 23: ode_solver = new SDIRK23Solver; break;
|
||||
case 24: ode_solver = new SDIRK34Solver; break;
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
delete mesh;
|
||||
return 3;
|
||||
}
|
||||
|
||||
map<string,HyperelasticOperator::NonlinearSolverType> nls_map;
|
||||
nls_map["newton"] = HyperelasticOperator::NEWTON;
|
||||
nls_map["kinsol"] = HyperelasticOperator::KINSOL;
|
||||
@@ -384,82 +439,11 @@ int main(int argc, char *argv[])
|
||||
cout << "initial kinetic energy (KE) = " << ke0 << endl;
|
||||
cout << "initial total energy (TE) = " << (ee0 + ke0) << endl;
|
||||
|
||||
// 8. Define the ODE solver used for time integration. Several implicit
|
||||
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
|
||||
// explicit Runge-Kutta methods are available.
|
||||
double t = 0.0;
|
||||
oper.SetTime(t);
|
||||
ode_solver->Init(oper);
|
||||
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKStepSolver *arkode = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Implicit L-stable methods
|
||||
case 1: ode_solver = new BackwardEulerSolver; break;
|
||||
case 2: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 3: ode_solver = new SDIRK33Solver; break;
|
||||
// Implicit A-stable methods (not L-stable)
|
||||
case 4: ode_solver = new ImplicitMidpointSolver; break;
|
||||
case 5: ode_solver = new SDIRK23Solver; break;
|
||||
case 6: ode_solver = new SDIRK34Solver; break;
|
||||
// Explicit methods
|
||||
case 7: ode_solver = new ForwardEulerSolver; break;
|
||||
case 8: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 9: ode_solver = new RK3SSPSolver; break;
|
||||
case 10: ode_solver = new RK4Solver; break;
|
||||
// CVODE BDF
|
||||
case 11:
|
||||
case 12:
|
||||
cvode = new CVODESolver(CV_BDF);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
CVodeSetEpsLin(cvode->GetMem(), cvode_eps_lin);
|
||||
cvode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 11)
|
||||
{
|
||||
cvode->UseSundialsLinearSolver();
|
||||
}
|
||||
ode_solver = cvode; break;
|
||||
// CVODE Adams
|
||||
case 13:
|
||||
case 14:
|
||||
cvode = new CVODESolver(CV_ADAMS);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
CVodeSetEpsLin(cvode->GetMem(), cvode_eps_lin);
|
||||
cvode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 13)
|
||||
{
|
||||
cvode->UseSundialsLinearSolver();
|
||||
}
|
||||
ode_solver = cvode; break;
|
||||
// ARKStep Implicit methods
|
||||
case 15:
|
||||
case 16:
|
||||
arkode = new ARKStepSolver(ARKStepSolver::IMPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
ARKStepSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 15)
|
||||
{
|
||||
arkode->UseSundialsLinearSolver();
|
||||
}
|
||||
ode_solver = arkode; break;
|
||||
// ARKStep Explicit methods
|
||||
case 17:
|
||||
arkode = new ARKStepSolver(ARKStepSolver::EXPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
}
|
||||
|
||||
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
|
||||
if (ode_solver_type < 11) { ode_solver->Init(oper); }
|
||||
|
||||
// 9. Perform time-integration (looping over the time iterations, ti, with a
|
||||
// 8. Perform time-integration (looping over the time iterations, ti, with a
|
||||
// time-step dt).
|
||||
bool last_step = false;
|
||||
for (int ti = 1; !last_step; ti++)
|
||||
@@ -494,7 +478,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 10. Save the displaced mesh, the velocity and elastic energy.
|
||||
// 9. Save the displaced mesh, the velocity and elastic energy.
|
||||
{
|
||||
v.SetFromTrueVector(); x.SetFromTrueVector();
|
||||
GridFunction *nodes = &x;
|
||||
@@ -513,8 +497,9 @@ int main(int argc, char *argv[])
|
||||
w.Save(ee_ofs);
|
||||
}
|
||||
|
||||
// 11. Free the used memory.
|
||||
// 10. Free the used memory.
|
||||
delete ode_solver;
|
||||
delete sjsolver;
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
@@ -594,14 +579,81 @@ ReducedSystemOperator::~ReducedSystemOperator()
|
||||
}
|
||||
|
||||
|
||||
int SundialsJacSolver::InitSystem(void *sundials_mem)
|
||||
{
|
||||
TimeDependentOperator *td_oper = GetTimeDependentOperator(sundials_mem);
|
||||
HyperelasticOperator *he_oper;
|
||||
|
||||
// During development, we use dynamic_cast<> to ensure the setup is correct:
|
||||
he_oper = dynamic_cast<HyperelasticOperator*>(td_oper);
|
||||
MFEM_VERIFY(he_oper, "operator is not HyperelasticOperator");
|
||||
|
||||
// When the implementation is finalized, we can switch to static_cast<>:
|
||||
// he_oper = static_cast<HyperelasticOperator*>(td_oper);
|
||||
|
||||
he_oper->InitSundialsJacSolver(*this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::SetupSystem(void *sundials_mem, int conv_fail,
|
||||
const Vector &y_pred, const Vector &f_pred,
|
||||
int &jac_cur, Vector &v_temp1,
|
||||
Vector &v_temp2, Vector &v_temp3)
|
||||
{
|
||||
int sc = y_pred.Size() / 2;
|
||||
const Vector x(y_pred.GetData() + sc, sc);
|
||||
double dt = GetTimeStep(sundials_mem);
|
||||
|
||||
// J = M + dt*(S + dt*grad(H))
|
||||
delete Jacobian;
|
||||
Jacobian = Add(1.0, M->SpMat(), dt, S->SpMat());
|
||||
grad_H = dynamic_cast<SparseMatrix *>(&H->GetGradient(x));
|
||||
Jacobian->Add(dt * dt, *grad_H);
|
||||
|
||||
J_solver->SetOperator(*Jacobian);
|
||||
|
||||
jac_cur = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::SolveSystem(void *sundials_mem, Vector &b,
|
||||
const Vector &weight, const Vector &y_cur,
|
||||
const Vector &f_cur)
|
||||
{
|
||||
int sc = b.Size() / 2;
|
||||
// Vector x(y_cur.GetData() + sc, sc);
|
||||
Vector b_v(b.GetData() + 0, sc);
|
||||
Vector b_x(b.GetData() + sc, sc);
|
||||
Vector rhs(sc);
|
||||
double dt = GetTimeStep(sundials_mem);
|
||||
|
||||
// rhs = M b_v - dt*grad(H) b_x
|
||||
grad_H->Mult(b_x, rhs);
|
||||
rhs *= -dt;
|
||||
M->AddMult(b_v, rhs);
|
||||
|
||||
J_solver->iterative_mode = false;
|
||||
J_solver->Mult(rhs, b_v);
|
||||
|
||||
b_x.Add(dt, b_v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::FreeSystem(void *sundials_mem)
|
||||
{
|
||||
delete Jacobian;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
HyperelasticOperator::HyperelasticOperator(FiniteElementSpace &f,
|
||||
Array<int> &ess_bdr, double visc,
|
||||
double mu, double K,
|
||||
NonlinearSolverType nls_type)
|
||||
: TimeDependentOperator(2*f.GetTrueVSize(), 0.0), fespace(f),
|
||||
M(&fespace), S(&fespace), H(&fespace),
|
||||
viscosity(visc), z(height/2),
|
||||
grad_H(NULL), Jacobian(NULL)
|
||||
viscosity(visc), z(height/2)
|
||||
{
|
||||
const double rel_tol = 1e-8;
|
||||
const int skip_zero_entries = 0;
|
||||
@@ -650,24 +702,23 @@ HyperelasticOperator::HyperelasticOperator(FiniteElementSpace &f,
|
||||
|
||||
if (nls_type == KINSOL)
|
||||
{
|
||||
KINSolver *kinsolver = new KINSolver(KIN_NONE, true);
|
||||
KinSolver *kinsolver = new KinSolver(KIN_NONE, true);
|
||||
kinsolver->SetMaxSetupCalls(4);
|
||||
newton_solver = kinsolver;
|
||||
newton_solver->SetOperator(*reduced_oper);
|
||||
newton_solver->SetMaxIter(200);
|
||||
newton_solver->SetRelTol(rel_tol);
|
||||
newton_solver->SetPrintLevel(0);
|
||||
kinsolver->SetMaxSetupCalls(4);
|
||||
}
|
||||
else
|
||||
{
|
||||
newton_solver = new NewtonSolver();
|
||||
newton_solver->SetOperator(*reduced_oper);
|
||||
newton_solver->SetMaxIter(10);
|
||||
newton_solver->SetRelTol(rel_tol);
|
||||
newton_solver->SetPrintLevel(-1);
|
||||
}
|
||||
newton_solver->SetSolver(*J_solver);
|
||||
newton_solver->iterative_mode = false;
|
||||
newton_solver->SetOperator(*reduced_oper);
|
||||
}
|
||||
|
||||
void HyperelasticOperator::Mult(const Vector &vx, Vector &dvx_dt) const
|
||||
@@ -717,53 +768,9 @@ void HyperelasticOperator::ImplicitSolve(const double dt,
|
||||
add(v, dt, dv_dt, dx_dt);
|
||||
}
|
||||
|
||||
int HyperelasticOperator::SUNImplicitSetup(const Vector &y,
|
||||
const Vector &fy, int jok, int *jcur,
|
||||
double gamma)
|
||||
void HyperelasticOperator::InitSundialsJacSolver(SundialsJacSolver &sjsolv)
|
||||
{
|
||||
int sc = y.Size() / 2;
|
||||
const Vector x(y.GetData() + sc, sc);
|
||||
|
||||
// J = M + dt*(S + dt*grad(H))
|
||||
if (Jacobian) { delete Jacobian; }
|
||||
Jacobian = Add(1.0, M.SpMat(), gamma, S.SpMat());
|
||||
grad_H = dynamic_cast<SparseMatrix *>(&H.GetGradient(x));
|
||||
Jacobian->Add(gamma * gamma, *grad_H);
|
||||
|
||||
// Set Jacobian solve operator
|
||||
J_solver->SetOperator(*Jacobian);
|
||||
|
||||
// Indicate that the Jacobian was updated
|
||||
*jcur = 1;
|
||||
|
||||
// Save gamma for use in solve
|
||||
saved_gamma = gamma;
|
||||
|
||||
// Return success
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HyperelasticOperator::SUNImplicitSolve(const Vector &b, Vector &x,
|
||||
double tol)
|
||||
{
|
||||
int sc = b.Size() / 2;
|
||||
Vector b_v(b.GetData() + 0, sc);
|
||||
Vector b_x(b.GetData() + sc, sc);
|
||||
Vector x_v(x.GetData() + 0, sc);
|
||||
Vector x_x(x.GetData() + sc, sc);
|
||||
Vector rhs(sc);
|
||||
|
||||
// rhs = M b_v - dt*grad(H) b_x
|
||||
grad_H->Mult(b_x, rhs);
|
||||
rhs *= -saved_gamma;
|
||||
M.AddMult(b_v, rhs);
|
||||
|
||||
J_solver->iterative_mode = false;
|
||||
J_solver->Mult(rhs, x_v);
|
||||
|
||||
add(b_x, saved_gamma, x_v, x_x);
|
||||
|
||||
return 0;
|
||||
sjsolv.SetOperators(M, S, H, *J_solver);
|
||||
}
|
||||
|
||||
double HyperelasticOperator::ElasticEnergy(const Vector &x) const
|
||||
@@ -785,7 +792,6 @@ void HyperelasticOperator::GetElasticEnergyDensity(
|
||||
|
||||
HyperelasticOperator::~HyperelasticOperator()
|
||||
{
|
||||
delete Jacobian;
|
||||
delete newton_solver;
|
||||
delete J_solver;
|
||||
delete J_prec;
|
||||
|
||||
+229
-219
@@ -4,16 +4,16 @@
|
||||
// Compile with: make ex10p
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 12 -dt 0.15 -vs 10
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-tri.mesh -rp 1 -o 2 -s 16 -dt 0.25 -vs 10
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-hex.mesh -rp 0 -o 2 -s 12 -dt 0.15 -vs 10
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 5 -dt 0.15 -vs 10
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-tri.mesh -rp 1 -o 2 -s 7 -dt 0.25 -vs 10
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-hex.mesh -rp 0 -o 2 -s 5 -dt 0.15 -vs 10
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-tri.mesh -rp 1 -o 2 -s 2 -dt 3 -nls kinsol
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 2 -dt 3 -nls kinsol
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-hex.mesh -rs 1 -o 2 -s 2 -dt 3 -nls kinsol
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 14 -dt 0.15 -vs 10
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-tri.mesh -rp 1 -o 2 -s 17 -dt 5e-3 -vs 60
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-hex.mesh -rp 0 -o 2 -s 14 -dt 0.15 -vs 10
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-quad-amr.mesh -rp 1 -o 2 -s 12 -dt 0.15 -vs 10
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 15 -dt 3e-3 -vs 120
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-tri.mesh -rp 1 -o 2 -s 16 -dt 5e-3 -vs 60
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-hex.mesh -rp 0 -o 2 -s 15 -dt 5e-3 -vs 60
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-quad-amr.mesh -rp 1 -o 2 -s 5 -dt 0.15 -vs 10
|
||||
//
|
||||
// Description: This examples solves a time dependent nonlinear elasticity
|
||||
// problem of the form dv/dt = H(x) + S v, dx/dt = v, where H is a
|
||||
@@ -53,6 +53,7 @@ using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
class ReducedSystemOperator;
|
||||
class SundialsJacSolver;
|
||||
|
||||
/** After spatial discretization, the hyperelastic model can be written as a
|
||||
* system of ODEs:
|
||||
@@ -93,17 +94,12 @@ protected:
|
||||
|
||||
mutable Vector z; // auxiliary vector
|
||||
|
||||
const SparseMatrix *local_grad_H;
|
||||
HypreParMatrix *Jacobian;
|
||||
|
||||
double saved_gamma; // saved gamma value from implicit setup
|
||||
|
||||
public:
|
||||
/// Solver type to use in the ImplicitSolve() method, used by SDIRK methods.
|
||||
enum NonlinearSolverType
|
||||
{
|
||||
NEWTON = 0, ///< Use MFEM's plain NewtonSolver
|
||||
KINSOL = 1 ///< Use SUNDIALS' KINSOL (through MFEM's class KINSolver)
|
||||
KINSOL = 1 ///< Use SUNDIALS' KINSOL (through MFEM's class KinSolver)
|
||||
};
|
||||
|
||||
HyperelasticOperator(ParFiniteElementSpace &f, Array<int> &ess_bdr,
|
||||
@@ -112,41 +108,15 @@ public:
|
||||
|
||||
/// Compute the right-hand side of the ODE system.
|
||||
virtual void Mult(const Vector &vx, Vector &dvx_dt) const;
|
||||
|
||||
/** Solve the Backward-Euler equation: k = f(x + dt*k, t), for the unknown k.
|
||||
This is the only requirement for high-order SDIRK implicit integration.*/
|
||||
virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k);
|
||||
|
||||
|
||||
/// Custom Jacobian system solver for the SUNDIALS time integrators.
|
||||
/** For the ODE system represented by HyperelasticOperator
|
||||
|
||||
M dv/dt = -(H(x) + S*v)
|
||||
dx/dt = v,
|
||||
|
||||
this class facilitates the solution of linear systems of the form
|
||||
|
||||
(M + γS) yv + γJ yx = M bv, J=(dH/dx)(x)
|
||||
- γ yv + yx = bx
|
||||
|
||||
for given bv, bx, x, and γ = GetTimeStep(). */
|
||||
|
||||
/** Linear solve applicable to the SUNDIALS format.
|
||||
Solves (Mass - dt J) y = Mass b, where in our case:
|
||||
Mass = | M 0 | J = | -S -grad_H | y = | v_hat | b = | b_v |
|
||||
| 0 I | | I 0 | | x_hat | | b_x |
|
||||
The result replaces the rhs b.
|
||||
We substitute x_hat = b_x + dt v_hat and solve
|
||||
(M + dt S + dt^2 grad_H) v_hat = M b_v - dt grad_H b_x. */
|
||||
|
||||
/** Setup the linear system. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSetup(const Vector &y, const Vector &fy,
|
||||
int jok, int *jcur, double gamma);
|
||||
|
||||
/** Solve the linear system. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSolve(const Vector &b, Vector &x, double tol);
|
||||
/** Connect the Jacobian linear system solver (SundialsJacSolver) used by
|
||||
SUNDIALS' CVODE and ARKODE time integrators to the internal objects
|
||||
created by HyperelasticOperator. This method is called by the InitSystem
|
||||
method of SundialsJacSolver. */
|
||||
void InitSundialsJacSolver(SundialsJacSolver &sjsolv);
|
||||
|
||||
double ElasticEnergy(const ParGridFunction &x) const;
|
||||
double KineticEnergy(const ParGridFunction &v) const;
|
||||
@@ -187,6 +157,57 @@ public:
|
||||
virtual ~ReducedSystemOperator();
|
||||
};
|
||||
|
||||
/// Custom Jacobian system solver for the SUNDIALS time integrators.
|
||||
/** For the ODE system represented by HyperelasticOperator
|
||||
|
||||
M dv/dt = -(H(x) + S*v)
|
||||
dx/dt = v,
|
||||
|
||||
this class facilitates the solution of linear systems of the form
|
||||
|
||||
(M + γS) yv + γJ yx = M bv, J=(dH/dx)(x)
|
||||
- γ yv + yx = bx
|
||||
|
||||
for given bv, bx, x, and γ = GetTimeStep(). */
|
||||
class SundialsJacSolver : public SundialsODELinearSolver
|
||||
{
|
||||
private:
|
||||
ParBilinearForm *M, *S;
|
||||
ParNonlinearForm *H;
|
||||
const SparseMatrix *local_grad_H;
|
||||
HypreParMatrix *Jacobian;
|
||||
Solver *J_solver;
|
||||
const Array<int> *ess_tdof_list;
|
||||
|
||||
public:
|
||||
SundialsJacSolver()
|
||||
: M(), S(), H(), local_grad_H(), Jacobian(), J_solver() { }
|
||||
|
||||
/// Connect the solver to the objects created inside HyperelasticOperator.
|
||||
void SetOperators(ParBilinearForm &M_, ParBilinearForm &S_,
|
||||
ParNonlinearForm &H_, Solver &solver,
|
||||
const Array<int> &ess_tdof_list_)
|
||||
{
|
||||
M = &M_; S = &S_; H = &H_; J_solver = &solver;
|
||||
ess_tdof_list = &ess_tdof_list_;
|
||||
}
|
||||
|
||||
/** Linear solve applicable to the SUNDIALS format.
|
||||
Solves (Mass - dt J) y = Mass b, where in our case:
|
||||
Mass = | M 0 | J = | -S -grad_H | y = | v_hat | b = | b_v |
|
||||
| 0 I | | I 0 | | x_hat | | b_x |
|
||||
The result replaces the rhs b.
|
||||
We substitute x_hat = b_x + dt v_hat and solve
|
||||
(M + dt S + dt^2 grad_H) v_hat = M b_v - dt grad_H b_x. */
|
||||
int InitSystem(void *sundials_mem);
|
||||
int SetupSystem(void *sundials_mem, int conv_fail,
|
||||
const Vector &y_pred, const Vector &f_pred, int &jac_cur,
|
||||
Vector &v_temp1, Vector &v_temp2, Vector &v_temp3);
|
||||
int SolveSystem(void *sundials_mem, Vector &b, const Vector &weight,
|
||||
const Vector &y_cur, const Vector &f_cur);
|
||||
int FreeSystem(void *sundials_mem);
|
||||
};
|
||||
|
||||
|
||||
/** Function representing the elastic energy density for the given hyperelastic
|
||||
model+deformation. Used in HyperelasticOperator::GetElasticEnergyDensity. */
|
||||
@@ -238,12 +259,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Relative and absolute tolerances for CVODE and ARKODE.
|
||||
const double reltol = 1e-1, abstol = 1e-1;
|
||||
// Since this example uses the loose tolerances defined above, it is
|
||||
// necessary to lower the linear solver tolerance for CVODE which is relative
|
||||
// to the above tolerances.
|
||||
const double cvode_eps_lin = 1e-4;
|
||||
// Similarly, the nonlinear tolerance for ARKODE needs to be tightened.
|
||||
const double arkode_eps_nonlin = 1e-6;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
@@ -255,24 +270,15 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver:\n\t"
|
||||
"1 - Backward Euler,\n\t"
|
||||
"2 - SDIRK2, L-stable\n\t"
|
||||
"3 - SDIRK3, L-stable\n\t"
|
||||
"4 - Implicit Midpoint,\n\t"
|
||||
"5 - SDIRK2, A-stable,\n\t"
|
||||
"6 - SDIRK3, A-stable,\n\t"
|
||||
"7 - Forward Euler,\n\t"
|
||||
"8 - RK2,\n\t"
|
||||
"9 - RK3 SSP,\n\t"
|
||||
"10 - RK4,\n\t"
|
||||
"11 - CVODE implicit BDF, approximate Jacobian,\n\t"
|
||||
"12 - CVODE implicit BDF, specified Jacobian,\n\t"
|
||||
"13 - CVODE implicit ADAMS, approximate Jacobian,\n\t"
|
||||
"14 - CVODE implicit ADAMS, specified Jacobian,\n\t"
|
||||
"15 - ARKODE implicit, approximate Jacobian,\n\t"
|
||||
"16 - ARKODE implicit, specified Jacobian,\n\t"
|
||||
"17 - ARKODE explicit, 4th order.");
|
||||
"ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
|
||||
" 4 - CVODE implicit, approximate Jacobian,\n\t"
|
||||
" 5 - CVODE implicit, specified Jacobian,\n\t"
|
||||
" 6 - ARKODE implicit, approximate Jacobian,\n\t"
|
||||
" 7 - ARKODE implicit, specified Jacobian,\n\t"
|
||||
" 11 - Forward Euler, 12 - RK2,\n\t"
|
||||
" 13 - RK3 SSP, 14 - RK4,\n\t"
|
||||
" 15 - CVODE (adaptive order) explicit,\n\t"
|
||||
" 16 - ARKODE default (4th order) explicit.");
|
||||
args.AddOption(&nls, "-nls", "--nonlinear-solver",
|
||||
"Nonlinear systems solver: "
|
||||
"\"newton\" (plain Newton) or \"kinsol\" (KINSOL).");
|
||||
@@ -306,24 +312,76 @@ int main(int argc, char *argv[])
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
// check for vaild ODE solver option
|
||||
if (ode_solver_type < 1 || ode_solver_type > 17)
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
}
|
||||
MPI_Finalize();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 3. Read the serial mesh from the given mesh file on all processors. We can
|
||||
// handle triangular, quadrilateral, tetrahedral and hexahedral meshes
|
||||
// with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 4. Nonlinear solver
|
||||
// 4. Define the ODE solver used for time integration. Several implicit
|
||||
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
|
||||
// explicit Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKODESolver *arkode = NULL;
|
||||
SundialsJacSolver *sjsolver = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Implicit L-stable methods
|
||||
case 1: ode_solver = new BackwardEulerSolver; break;
|
||||
case 2: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 3: ode_solver = new SDIRK33Solver; break;
|
||||
case 4:
|
||||
case 5:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_BDF, CV_NEWTON);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 5)
|
||||
{
|
||||
sjsolver = new SundialsJacSolver;
|
||||
cvode->SetLinearSolver(*sjsolver); // Custom Jacobian inversion.
|
||||
}
|
||||
ode_solver = cvode; break;
|
||||
case 6:
|
||||
case 7:
|
||||
arkode = new ARKODESolver(MPI_COMM_WORLD, ARKODESolver::IMPLICIT);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 7)
|
||||
{
|
||||
sjsolver = new SundialsJacSolver;
|
||||
arkode->SetLinearSolver(*sjsolver); // Custom Jacobian inversion.
|
||||
}
|
||||
ode_solver = arkode; break;
|
||||
// Explicit methods
|
||||
case 11: ode_solver = new ForwardEulerSolver; break;
|
||||
case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 13: ode_solver = new RK3SSPSolver; break;
|
||||
case 14: ode_solver = new RK4Solver; break;
|
||||
case 15:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_ADAMS, CV_FUNCTIONAL);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 16:
|
||||
arkode = new ARKODESolver(MPI_COMM_WORLD, ARKODESolver::EXPLICIT);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
// Implicit A-stable methods (not L-stable)
|
||||
case 22: ode_solver = new ImplicitMidpointSolver; break;
|
||||
case 23: ode_solver = new SDIRK23Solver; break;
|
||||
case 24: ode_solver = new SDIRK34Solver; break;
|
||||
default:
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
}
|
||||
delete mesh;
|
||||
MPI_Finalize();
|
||||
return 3;
|
||||
}
|
||||
|
||||
map<string,HyperelasticOperator::NonlinearSolverType> nls_map;
|
||||
nls_map["newton"] = HyperelasticOperator::NEWTON;
|
||||
nls_map["kinsol"] = HyperelasticOperator::KINSOL;
|
||||
@@ -333,6 +391,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
cout << "Unknown type of nonlinear solver: " << nls << endl;
|
||||
}
|
||||
delete ode_solver;
|
||||
delete mesh;
|
||||
MPI_Finalize();
|
||||
return 4;
|
||||
@@ -436,82 +495,11 @@ int main(int argc, char *argv[])
|
||||
cout << "initial total energy (TE) = " << (ee0 + ke0) << endl;
|
||||
}
|
||||
|
||||
// 10. Define the ODE solver used for time integration. Several implicit
|
||||
// singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
|
||||
// explicit Runge-Kutta methods are available.
|
||||
double t = 0.0;
|
||||
oper.SetTime(t);
|
||||
ode_solver->Init(oper);
|
||||
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKStepSolver *arkode = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// Implicit L-stable methods
|
||||
case 1: ode_solver = new BackwardEulerSolver; break;
|
||||
case 2: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 3: ode_solver = new SDIRK33Solver; break;
|
||||
// Implicit A-stable methods (not L-stable)
|
||||
case 4: ode_solver = new ImplicitMidpointSolver; break;
|
||||
case 5: ode_solver = new SDIRK23Solver; break;
|
||||
case 6: ode_solver = new SDIRK34Solver; break;
|
||||
// Explicit methods
|
||||
case 7: ode_solver = new ForwardEulerSolver; break;
|
||||
case 8: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 9: ode_solver = new RK3SSPSolver; break;
|
||||
case 10: ode_solver = new RK4Solver; break;
|
||||
// CVODE BDF
|
||||
case 11:
|
||||
case 12:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_BDF);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
CVodeSetEpsLin(cvode->GetMem(), cvode_eps_lin);
|
||||
cvode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 11)
|
||||
{
|
||||
cvode->UseSundialsLinearSolver();
|
||||
}
|
||||
ode_solver = cvode; break;
|
||||
// CVODE Adams
|
||||
case 13:
|
||||
case 14:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_ADAMS);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
CVodeSetEpsLin(cvode->GetMem(), cvode_eps_lin);
|
||||
cvode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 13)
|
||||
{
|
||||
cvode->UseSundialsLinearSolver();
|
||||
}
|
||||
ode_solver = cvode; break;
|
||||
// ARKStep Implicit methods
|
||||
case 15:
|
||||
case 16:
|
||||
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::IMPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
ARKStepSetNonlinConvCoef(arkode->GetMem(), arkode_eps_nonlin);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 15)
|
||||
{
|
||||
arkode->UseSundialsLinearSolver();
|
||||
}
|
||||
ode_solver = arkode; break;
|
||||
// ARKStep Explicit methods
|
||||
case 17:
|
||||
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::EXPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
}
|
||||
|
||||
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
|
||||
if (ode_solver_type < 11) { ode_solver->Init(oper); }
|
||||
|
||||
// 11. Perform time-integration
|
||||
// 10. Perform time-integration
|
||||
// (looping over the time iterations, ti, with a time-step dt).
|
||||
bool last_step = false;
|
||||
for (int ti = 1; !last_step; ti++)
|
||||
@@ -550,7 +538,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 12. Save the displaced mesh, the velocity and elastic energy.
|
||||
// 11. Save the displaced mesh, the velocity and elastic energy.
|
||||
{
|
||||
v_gf.SetFromTrueVector(); x_gf.SetFromTrueVector();
|
||||
GridFunction *nodes = &x_gf;
|
||||
@@ -575,8 +563,9 @@ int main(int argc, char *argv[])
|
||||
w_gf.Save(ee_ofs);
|
||||
}
|
||||
|
||||
// 13. Free the used memory.
|
||||
// 12. Free the used memory.
|
||||
delete ode_solver;
|
||||
delete sjsolver;
|
||||
delete pmesh;
|
||||
|
||||
MPI_Finalize();
|
||||
@@ -664,14 +653,92 @@ ReducedSystemOperator::~ReducedSystemOperator()
|
||||
}
|
||||
|
||||
|
||||
int SundialsJacSolver::InitSystem(void *sundials_mem)
|
||||
{
|
||||
TimeDependentOperator *td_oper = GetTimeDependentOperator(sundials_mem);
|
||||
HyperelasticOperator *he_oper;
|
||||
|
||||
// During development, we use dynamic_cast<> to ensure the setup is correct:
|
||||
he_oper = dynamic_cast<HyperelasticOperator*>(td_oper);
|
||||
MFEM_VERIFY(he_oper, "operator is not HyperelasticOperator");
|
||||
|
||||
// When the implementation is finalized, we can switch to static_cast<>:
|
||||
// he_oper = static_cast<HyperelasticOperator*>(td_oper);
|
||||
|
||||
he_oper->InitSundialsJacSolver(*this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::SetupSystem(void *sundials_mem, int conv_fail,
|
||||
const Vector &y_pred, const Vector &f_pred,
|
||||
int &jac_cur, Vector &v_temp1,
|
||||
Vector &v_temp2, Vector &v_temp3)
|
||||
{
|
||||
int sc = y_pred.Size() / 2;
|
||||
const Vector x(y_pred.GetData() + sc, sc);
|
||||
double dt = GetTimeStep(sundials_mem);
|
||||
|
||||
// J = M + dt*(S + dt*grad(H))
|
||||
delete Jacobian;
|
||||
SparseMatrix *localJ = Add(1.0, M->SpMat(), dt, S->SpMat());
|
||||
local_grad_H = &H->GetLocalGradient(x);
|
||||
localJ->Add(dt*dt, *local_grad_H);
|
||||
Jacobian = M->ParallelAssemble(localJ);
|
||||
delete localJ;
|
||||
HypreParMatrix *Je = Jacobian->EliminateRowsCols(*ess_tdof_list);
|
||||
delete Je;
|
||||
|
||||
J_solver->SetOperator(*Jacobian);
|
||||
|
||||
jac_cur = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::SolveSystem(void *sundials_mem, Vector &b,
|
||||
const Vector &weight, const Vector &y_cur,
|
||||
const Vector &f_cur)
|
||||
{
|
||||
int sc = b.Size() / 2;
|
||||
ParFiniteElementSpace *fes = H->ParFESpace();
|
||||
// Vector x(y_cur.GetData() + sc, sc);
|
||||
Vector b_v(b.GetData() + 0, sc);
|
||||
Vector b_x(b.GetData() + sc, sc);
|
||||
Vector rhs(sc);
|
||||
double dt = GetTimeStep(sundials_mem);
|
||||
|
||||
// We can assume that b_v and b_x have zeros at essential tdofs.
|
||||
|
||||
// rhs = M b_v - dt*grad(H) b_x
|
||||
ParGridFunction lb_x(fes), lrhs(fes);
|
||||
lb_x.Distribute(b_x);
|
||||
local_grad_H->Mult(lb_x, lrhs);
|
||||
lrhs.ParallelAssemble(rhs);
|
||||
rhs *= -dt;
|
||||
M->TrueAddMult(b_v, rhs);
|
||||
rhs.SetSubVector(*ess_tdof_list, 0.0);
|
||||
|
||||
J_solver->iterative_mode = false;
|
||||
J_solver->Mult(rhs, b_v);
|
||||
|
||||
b_x.Add(dt, b_v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::FreeSystem(void *sundials_mem)
|
||||
{
|
||||
delete Jacobian;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
HyperelasticOperator::HyperelasticOperator(ParFiniteElementSpace &f,
|
||||
Array<int> &ess_bdr, double visc,
|
||||
double mu, double K,
|
||||
NonlinearSolverType nls_type)
|
||||
: TimeDependentOperator(2*f.TrueVSize(), 0.0), fespace(f),
|
||||
M(&fespace), S(&fespace), H(&fespace),
|
||||
viscosity(visc), M_solver(f.GetComm()), z(height/2),
|
||||
local_grad_H(NULL), Jacobian(NULL)
|
||||
viscosity(visc), M_solver(f.GetComm()), z(height/2)
|
||||
{
|
||||
const double rel_tol = 1e-8;
|
||||
const int skip_zero_entries = 0;
|
||||
@@ -721,24 +788,23 @@ HyperelasticOperator::HyperelasticOperator(ParFiniteElementSpace &f,
|
||||
|
||||
if (nls_type == KINSOL)
|
||||
{
|
||||
KINSolver *kinsolver = new KINSolver(f.GetComm(), KIN_NONE, true);
|
||||
KinSolver *kinsolver = new KinSolver(f.GetComm(), KIN_NONE, true);
|
||||
kinsolver->SetMaxSetupCalls(4);
|
||||
newton_solver = kinsolver;
|
||||
newton_solver->SetOperator(*reduced_oper);
|
||||
newton_solver->SetMaxIter(200);
|
||||
newton_solver->SetRelTol(rel_tol);
|
||||
newton_solver->SetPrintLevel(0);
|
||||
kinsolver->SetMaxSetupCalls(4);
|
||||
}
|
||||
else
|
||||
{
|
||||
newton_solver = new NewtonSolver(f.GetComm());
|
||||
newton_solver->SetOperator(*reduced_oper);
|
||||
newton_solver->SetMaxIter(10);
|
||||
newton_solver->SetRelTol(rel_tol);
|
||||
newton_solver->SetPrintLevel(-1);
|
||||
}
|
||||
newton_solver->SetSolver(*J_solver);
|
||||
newton_solver->iterative_mode = false;
|
||||
newton_solver->SetOperator(*reduced_oper);
|
||||
}
|
||||
|
||||
void HyperelasticOperator::Mult(const Vector &vx, Vector &dvx_dt) const
|
||||
@@ -792,64 +858,9 @@ void HyperelasticOperator::ImplicitSolve(const double dt,
|
||||
add(v, dt, dv_dt, dx_dt);
|
||||
}
|
||||
|
||||
int HyperelasticOperator::SUNImplicitSetup(const Vector &y,
|
||||
const Vector &fy, int jok, int *jcur,
|
||||
double gamma)
|
||||
void HyperelasticOperator::InitSundialsJacSolver(SundialsJacSolver &sjsolv)
|
||||
{
|
||||
int sc = y.Size() / 2;
|
||||
const Vector x(y.GetData() + sc, sc);
|
||||
|
||||
// J = M + dt*(S + dt*grad(H))
|
||||
if (Jacobian) { delete Jacobian; }
|
||||
SparseMatrix *localJ = Add(1.0, M.SpMat(), gamma, S.SpMat());
|
||||
local_grad_H = &H.GetLocalGradient(x);
|
||||
localJ->Add(gamma*gamma, *local_grad_H);
|
||||
Jacobian = M.ParallelAssemble(localJ);
|
||||
delete localJ;
|
||||
HypreParMatrix *Je = Jacobian->EliminateRowsCols(ess_tdof_list);
|
||||
delete Je;
|
||||
|
||||
// Set Jacobian solve operator
|
||||
J_solver->SetOperator(*Jacobian);
|
||||
|
||||
// Indicate that the Jacobian was updated
|
||||
*jcur = 1;
|
||||
|
||||
// Save gamma for use in solve
|
||||
saved_gamma = gamma;
|
||||
|
||||
// Return success
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HyperelasticOperator::SUNImplicitSolve(const Vector &b, Vector &x,
|
||||
double tol)
|
||||
{
|
||||
int sc = b.Size() / 2;
|
||||
ParFiniteElementSpace *fes = H.ParFESpace();
|
||||
Vector b_v(b.GetData() + 0, sc);
|
||||
Vector b_x(b.GetData() + sc, sc);
|
||||
Vector x_v(x.GetData() + 0, sc);
|
||||
Vector x_x(x.GetData() + sc, sc);
|
||||
Vector rhs(sc);
|
||||
|
||||
// We can assume that b_v and b_x have zeros at essential tdofs.
|
||||
|
||||
// rhs = M b_v - dt*grad(H) b_x
|
||||
ParGridFunction lb_x(fes), lrhs(fes);
|
||||
lb_x.Distribute(b_x);
|
||||
local_grad_H->Mult(lb_x, lrhs);
|
||||
lrhs.ParallelAssemble(rhs);
|
||||
rhs *= -saved_gamma;
|
||||
M.TrueAddMult(b_v, rhs);
|
||||
rhs.SetSubVector(ess_tdof_list, 0.0);
|
||||
|
||||
J_solver->iterative_mode = false;
|
||||
J_solver->Mult(rhs, x_v);
|
||||
|
||||
add(b_x, saved_gamma, x_v, x_x);
|
||||
|
||||
return 0;
|
||||
sjsolv.SetOperators(M, S, H, *J_solver, ess_tdof_list);
|
||||
}
|
||||
|
||||
double HyperelasticOperator::ElasticEnergy(const ParGridFunction &x) const
|
||||
@@ -875,7 +886,6 @@ void HyperelasticOperator::GetElasticEnergyDensity(
|
||||
|
||||
HyperelasticOperator::~HyperelasticOperator()
|
||||
{
|
||||
delete Jacobian;
|
||||
delete newton_solver;
|
||||
delete J_solver;
|
||||
delete J_prec;
|
||||
|
||||
+165
-124
@@ -7,9 +7,9 @@
|
||||
// ex16 -m ../../data/inline-tri.mesh
|
||||
// ex16 -m ../../data/disc-nurbs.mesh -tf 2
|
||||
// ex16 -s 12 -a 0.0 -k 1.0
|
||||
// ex16 -s 8 -a 1.0 -k 0.0 -dt 1e-4 -tf 5e-2 -vs 25
|
||||
// ex16 -s 9 -a 0.5 -k 0.5 -o 4 -dt 1e-4 -tf 2e-2 -vs 25
|
||||
// ex16 -s 10 -dt 1.0e-4 -tf 4.0e-2 -vs 40
|
||||
// ex16 -s 1 -a 1.0 -k 0.0 -dt 1e-4 -tf 5e-2 -vs 25
|
||||
// ex16 -s 2 -a 0.5 -k 0.5 -o 4 -dt 1e-4 -tf 2e-2 -vs 25
|
||||
// ex16 -s 3 -dt 1.0e-4 -tf 4.0e-2 -vs 40
|
||||
// ex16 -m ../../data/fichera-q2.mesh
|
||||
// ex16 -m ../../data/escher.mesh
|
||||
// ex16 -m ../../data/beam-tet.mesh -tf 10 -dt 0.1
|
||||
@@ -58,6 +58,7 @@ protected:
|
||||
|
||||
SparseMatrix Mmat, Kmat;
|
||||
SparseMatrix *T; // T = M + dt K
|
||||
double current_dt;
|
||||
|
||||
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
|
||||
DSmoother M_prec; // Preconditioner for the mass matrix M
|
||||
@@ -74,30 +75,13 @@ public:
|
||||
const Vector &u);
|
||||
|
||||
virtual void Mult(const Vector &u, Vector &du_dt) const;
|
||||
|
||||
/** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
|
||||
This is the only requirement for high-order SDIRK implicit integration.*/
|
||||
virtual void ImplicitSolve(const double dt, const Vector &u, Vector &k);
|
||||
|
||||
/// Custom Jacobian system solver for the SUNDIALS time integrators.
|
||||
/** For the ODE system represented by ConductionOperator
|
||||
|
||||
M du/dt = -K(u),
|
||||
|
||||
this class facilitates the solution of linear systems of the form
|
||||
|
||||
(M + γK) y = M b,
|
||||
|
||||
for given b, u (not used), and γ = GetTimeStep(). */
|
||||
|
||||
/** Setup the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
|
||||
int jok, int *jcur, double gamma);
|
||||
|
||||
/** Solve the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSolve(const Vector &b, Vector &x, double tol);
|
||||
/** Solve the system (M + dt K) y = M b. The result y replaces the input b.
|
||||
This method is used by the implicit SUNDIALS solvers. */
|
||||
void SundialsSolve(const double dt, Vector &b);
|
||||
|
||||
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
|
||||
void SetParameters(const Vector &u);
|
||||
@@ -105,6 +89,33 @@ public:
|
||||
virtual ~ConductionOperator();
|
||||
};
|
||||
|
||||
/// Custom Jacobian system solver for the SUNDIALS time integrators.
|
||||
/** For the ODE system represented by ConductionOperator
|
||||
|
||||
M du/dt = -K(u),
|
||||
|
||||
this class facilitates the solution of linear systems of the form
|
||||
|
||||
(M + γK) y = M b,
|
||||
|
||||
for given b, u (not used), and γ = GetTimeStep(). */
|
||||
class SundialsJacSolver : public SundialsODELinearSolver
|
||||
{
|
||||
private:
|
||||
ConductionOperator *oper;
|
||||
|
||||
public:
|
||||
SundialsJacSolver() : oper(NULL) { }
|
||||
|
||||
int InitSystem(void *sundials_mem);
|
||||
int SetupSystem(void *sundials_mem, int conv_fail,
|
||||
const Vector &y_pred, const Vector &f_pred, int &jac_cur,
|
||||
Vector &v_temp1, Vector &v_temp2, Vector &v_temp3);
|
||||
int SolveSystem(void *sundials_mem, Vector &b, const Vector &weight,
|
||||
const Vector &y_cur, const Vector &f_cur);
|
||||
int FreeSystem(void *sundials_mem);
|
||||
};
|
||||
|
||||
double InitialTemperature(const Vector &x);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -113,7 +124,7 @@ int main(int argc, char *argv[])
|
||||
const char *mesh_file = "../../data/star.mesh";
|
||||
int ref_levels = 2;
|
||||
int order = 2;
|
||||
int ode_solver_type = 9; // CVODE implicit BDF
|
||||
int ode_solver_type = 11; // 11 = CVODE implicit
|
||||
double t_final = 0.5;
|
||||
double dt = 1.0e-2;
|
||||
double alpha = 1.0e-2;
|
||||
@@ -136,19 +147,12 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver:\n\t"
|
||||
"1 - Forward Euler,\n\t"
|
||||
"2 - RK2,\n\t"
|
||||
"3 - RK3 SSP,\n\t"
|
||||
"4 - RK4,\n\t"
|
||||
"5 - Backward Euler,\n\t"
|
||||
"6 - SDIRK 2,\n\t"
|
||||
"7 - SDIRK 3,\n\t"
|
||||
"8 - CVODE (implicit Adams),\n\t"
|
||||
"9 - CVODE (implicit BDF),\n\t"
|
||||
"10 - ARKODE (default explicit),\n\t"
|
||||
"11 - ARKODE (explicit Fehlberg-6-4-5),\n\t"
|
||||
"12 - ARKODE (default impicit).");
|
||||
"ODE solver:\n"
|
||||
"\t 1/11 - CVODE (explicit/implicit),\n"
|
||||
"\t 2/12 - ARKODE (default explicit/implicit),\n"
|
||||
"\t 3 - ARKODE (Fehlberg-6-4-5)\n"
|
||||
"\t 4 - Forward Euler, 5 - RK2, 6 - RK3 SSP, 7 - RK4,\n"
|
||||
"\t 8 - Backward Euler, 9 - SDIRK23, 10 - SDIRK33.");
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -171,11 +175,6 @@ int main(int argc, char *argv[])
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
if (ode_solver_type < 1 || ode_solver_type > 12)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 3;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
// 2. Read the mesh from the given mesh file. We can handle triangular,
|
||||
@@ -183,7 +182,61 @@ int main(int argc, char *argv[])
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 3. Refine the mesh to increase the resolution. In this example we do
|
||||
// 3. Define the ODE solver used for time integration. Several
|
||||
// SUNDIALS solvers are available, as well as included both
|
||||
// explicit and implicit MFEM ODE solvers.
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKODESolver *arkode = NULL;
|
||||
SundialsJacSolver sun_solver; // Used by the implicit SUNDIALS ode solvers.
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// SUNDIALS solvers
|
||||
case 1:
|
||||
cvode = new CVODESolver(CV_ADAMS, CV_FUNCTIONAL);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 11:
|
||||
cvode = new CVODESolver(CV_BDF, CV_NEWTON);
|
||||
cvode->SetLinearSolver(sun_solver);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 2:
|
||||
case 3:
|
||||
arkode = new ARKODESolver(ARKODESolver::EXPLICIT);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 3) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
|
||||
ode_solver = arkode; break;
|
||||
case 12:
|
||||
arkode = new ARKODESolver(ARKODESolver::IMPLICIT);
|
||||
arkode->SetLinearSolver(sun_solver);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
// Other MFEM explicit methods
|
||||
case 4: ode_solver = new ForwardEulerSolver; break;
|
||||
case 5: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 6: ode_solver = new RK3SSPSolver; break;
|
||||
case 7: ode_solver = new RK4Solver; break;
|
||||
// MFEM implicit L-stable methods
|
||||
case 8: ode_solver = new BackwardEulerSolver; break;
|
||||
case 9: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 10: ode_solver = new SDIRK33Solver; break;
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
delete mesh;
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Since we want to update the diffusion coefficient after every time step,
|
||||
// we need to use the "one-step" mode of the SUNDIALS solvers.
|
||||
if (cvode) { cvode->SetStepMode(CV_ONE_STEP); }
|
||||
if (arkode) { arkode->SetStepMode(ARK_ONE_STEP); }
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
|
||||
// command-line parameter.
|
||||
for (int lev = 0; lev < ref_levels; lev++)
|
||||
@@ -191,7 +244,7 @@ int main(int argc, char *argv[])
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 4. Define the vector finite element space representing the current and the
|
||||
// 5. Define the vector finite element space representing the current and the
|
||||
// initial temperature, u_ref.
|
||||
H1_FECollection fe_coll(order, dim);
|
||||
FiniteElementSpace fespace(mesh, &fe_coll);
|
||||
@@ -201,14 +254,14 @@ int main(int argc, char *argv[])
|
||||
|
||||
GridFunction u_gf(&fespace);
|
||||
|
||||
// 5. Set the initial conditions for u. All boundaries are considered
|
||||
// 6. Set the initial conditions for u. All boundaries are considered
|
||||
// natural.
|
||||
FunctionCoefficient u_0(InitialTemperature);
|
||||
u_gf.ProjectCoefficient(u_0);
|
||||
Vector u;
|
||||
u_gf.GetTrueDofs(u);
|
||||
|
||||
// 6. Initialize the conduction operator and the visualization.
|
||||
// 7. Initialize the conduction operator and the visualization.
|
||||
ConductionOperator oper(fespace, alpha, kappa, u);
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
@@ -254,65 +307,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Define the ODE solver used for time integration.
|
||||
double t = 0.0;
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKStepSolver *arkode = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// MFEM explicit methods
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
// MFEM implicit L-stable methods
|
||||
case 5: ode_solver = new BackwardEulerSolver; break;
|
||||
case 6: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 7: ode_solver = new SDIRK33Solver; break;
|
||||
// CVODE
|
||||
case 8:
|
||||
cvode = new CVODESolver(CV_ADAMS);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 9:
|
||||
cvode = new CVODESolver(CV_BDF);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
// ARKODE
|
||||
case 10:
|
||||
case 11:
|
||||
arkode = new ARKStepSolver(ARKStepSolver::EXPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 11) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
|
||||
ode_solver = arkode; break;
|
||||
case 12:
|
||||
arkode = new ARKStepSolver(ARKStepSolver::IMPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
}
|
||||
|
||||
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
|
||||
if (ode_solver_type < 8) { ode_solver->Init(oper); }
|
||||
|
||||
// Since we want to update the diffusion coefficient after every time step,
|
||||
// we need to use the "one-step" mode of the SUNDIALS solvers.
|
||||
if (cvode) { cvode->SetStepMode(CV_ONE_STEP); }
|
||||
if (arkode) { arkode->SetStepMode(ARK_ONE_STEP); }
|
||||
|
||||
// 8. Perform time-integration (looping over the time iterations, ti, with a
|
||||
// time-step dt).
|
||||
cout << "Integrating the ODE ..." << endl;
|
||||
tic_toc.Clear();
|
||||
tic_toc.Start();
|
||||
ode_solver->Init(oper);
|
||||
double t = 0.0;
|
||||
|
||||
bool last_step = false;
|
||||
for (int ti = 1; !last_step; ti++)
|
||||
@@ -370,7 +371,7 @@ int main(int argc, char *argv[])
|
||||
ConductionOperator::ConductionOperator(FiniteElementSpace &f, double al,
|
||||
double kap, const Vector &u)
|
||||
: TimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL), K(NULL),
|
||||
T(NULL), z(height)
|
||||
T(NULL), current_dt(0.0), z(height)
|
||||
{
|
||||
const double rel_tol = 1e-8;
|
||||
|
||||
@@ -416,14 +417,32 @@ void ConductionOperator::ImplicitSolve(const double dt,
|
||||
// Solve the equation:
|
||||
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
|
||||
// for du_dt
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
T_solver.SetOperator(*T);
|
||||
if (!T)
|
||||
{
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
current_dt = dt;
|
||||
T_solver.SetOperator(*T);
|
||||
}
|
||||
MFEM_VERIFY(dt == current_dt, ""); // SDIRK methods use the same dt
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg();
|
||||
T_solver.Mult(z, du_dt);
|
||||
}
|
||||
|
||||
void ConductionOperator::SundialsSolve(const double dt, Vector &b)
|
||||
{
|
||||
// Solve the system (M + dt K) y = M b. The result y replaces the input b.
|
||||
if (!T || dt != current_dt)
|
||||
{
|
||||
delete T;
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
current_dt = dt;
|
||||
T_solver.SetOperator(*T);
|
||||
}
|
||||
Mmat.Mult(b, z);
|
||||
T_solver.Mult(z, b);
|
||||
}
|
||||
|
||||
void ConductionOperator::SetParameters(const Vector &u)
|
||||
{
|
||||
GridFunction u_alpha_gf(&fespace);
|
||||
@@ -441,26 +460,8 @@ void ConductionOperator::SetParameters(const Vector &u)
|
||||
K->AddDomainIntegrator(new DiffusionIntegrator(u_coeff));
|
||||
K->Assemble();
|
||||
K->FormSystemMatrix(ess_tdof_list, Kmat);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSetup(const Vector &x,
|
||||
const Vector &fx, int jok, int *jcur,
|
||||
double gamma)
|
||||
{
|
||||
// Setup the ODE Jacobian T = M + gamma K.
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, gamma, Kmat);
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &b, Vector &x, double tol)
|
||||
{
|
||||
// Solve the system A x = z => (M - gamma K) x = M b.
|
||||
Mmat.Mult(b, z);
|
||||
T_solver.Mult(z, x);
|
||||
return (0);
|
||||
delete T;
|
||||
T = NULL; // re-compute T on the next ImplicitSolve or SundialsSolve
|
||||
}
|
||||
|
||||
ConductionOperator::~ConductionOperator()
|
||||
@@ -470,6 +471,46 @@ ConductionOperator::~ConductionOperator()
|
||||
delete K;
|
||||
}
|
||||
|
||||
|
||||
int SundialsJacSolver::InitSystem(void *sundials_mem)
|
||||
{
|
||||
TimeDependentOperator *td_oper = GetTimeDependentOperator(sundials_mem);
|
||||
|
||||
// During development, we use dynamic_cast<> to ensure the setup is correct:
|
||||
oper = dynamic_cast<ConductionOperator*>(td_oper);
|
||||
MFEM_VERIFY(oper, "operator is not ConductionOperator");
|
||||
|
||||
// When the implementation is finalized, we can switch to static_cast<>:
|
||||
// oper = static_cast<ConductionOperator*>(td_oper);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::SetupSystem(void *sundials_mem, int conv_fail,
|
||||
const Vector &y_pred, const Vector &f_pred,
|
||||
int &jac_cur, Vector &v_temp1,
|
||||
Vector &v_temp2, Vector &v_temp3)
|
||||
{
|
||||
jac_cur = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::SolveSystem(void *sundials_mem, Vector &b,
|
||||
const Vector &weight, const Vector &y_cur,
|
||||
const Vector &f_cur)
|
||||
{
|
||||
oper->SundialsSolve(GetTimeStep(sundials_mem), b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::FreeSystem(void *sundials_mem)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
double InitialTemperature(const Vector &x)
|
||||
{
|
||||
if (x.Norml2() < 0.5)
|
||||
|
||||
+161
-116
@@ -8,9 +8,9 @@
|
||||
// mpirun -np 4 ex16p -m ../../data/inline-tri.mesh
|
||||
// mpirun -np 4 ex16p -m ../../data/disc-nurbs.mesh -tf 2
|
||||
// mpirun -np 4 ex16p -s 12 -a 0.0 -k 1.0
|
||||
// mpirun -np 4 ex16p -s 8 -a 1.0 -k 0.0 -dt 4e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 8 ex16p -s 9 -a 0.5 -k 0.5 -o 4 -dt 8e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 4 ex16p -s 10 -dt 2.0e-4 -tf 4.0e-2
|
||||
// mpirun -np 4 ex16p -s 1 -a 1.0 -k 0.0 -dt 4e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 8 ex16p -s 2 -a 0.5 -k 0.5 -o 4 -dt 8e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 4 ex16p -s 3 -dt 2.0e-4 -tf 4.0e-2
|
||||
// mpirun -np 16 ex16p -m ../../data/fichera-q2.mesh
|
||||
// mpirun -np 16 ex16p -m ../../data/escher-p2.mesh
|
||||
// mpirun -np 8 ex16p -m ../../data/beam-tet.mesh -tf 10 -dt 0.1
|
||||
@@ -77,19 +77,13 @@ public:
|
||||
const Vector &u);
|
||||
|
||||
virtual void Mult(const Vector &u, Vector &du_dt) const;
|
||||
|
||||
/** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
|
||||
This is the only requirement for high-order SDIRK implicit integration.*/
|
||||
virtual void ImplicitSolve(const double dt, const Vector &u, Vector &k);
|
||||
|
||||
/** Setup the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
|
||||
int jok, int *jcur, double gamma);
|
||||
|
||||
/** Solve the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSolve(const Vector &b, Vector &x, double tol);
|
||||
/** Solve the system (M + dt K) y = M b. The result y replaces the input b.
|
||||
This method is used by the implicit SUNDIALS solvers. */
|
||||
void SundialsSolve(const double dt, Vector &b);
|
||||
|
||||
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
|
||||
void SetParameters(const Vector &u);
|
||||
@@ -97,6 +91,33 @@ public:
|
||||
virtual ~ConductionOperator();
|
||||
};
|
||||
|
||||
/// Custom Jacobian system solver for the SUNDIALS time integrators.
|
||||
/** For the ODE system represented by ConductionOperator
|
||||
|
||||
M du/dt = -K(u),
|
||||
|
||||
this class facilitates the solution of linear systems of the form
|
||||
|
||||
(M + γK) y = M b,
|
||||
|
||||
for given b, u (not used), and γ = GetTimeStep(). */
|
||||
class SundialsJacSolver : public SundialsODELinearSolver
|
||||
{
|
||||
private:
|
||||
ConductionOperator *oper;
|
||||
|
||||
public:
|
||||
SundialsJacSolver() : oper(NULL) { }
|
||||
|
||||
int InitSystem(void *sundials_mem);
|
||||
int SetupSystem(void *sundials_mem, int conv_fail,
|
||||
const Vector &y_pred, const Vector &f_pred, int &jac_cur,
|
||||
Vector &v_temp1, Vector &v_temp2, Vector &v_temp3);
|
||||
int SolveSystem(void *sundials_mem, Vector &b, const Vector &weight,
|
||||
const Vector &y_cur, const Vector &f_cur);
|
||||
int FreeSystem(void *sundials_mem);
|
||||
};
|
||||
|
||||
double InitialTemperature(const Vector &x);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -112,7 +133,7 @@ int main(int argc, char *argv[])
|
||||
int ser_ref_levels = 2;
|
||||
int par_ref_levels = 1;
|
||||
int order = 2;
|
||||
int ode_solver_type = 9; // CVODE implicit BDF
|
||||
int ode_solver_type = 11; // 11 = CVODE implicit
|
||||
double t_final = 0.5;
|
||||
double dt = 1.0e-2;
|
||||
double alpha = 1.0e-2;
|
||||
@@ -137,19 +158,12 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver:\n\t"
|
||||
"1 - Forward Euler,\n\t"
|
||||
"2 - RK2,\n\t"
|
||||
"3 - RK3 SSP,\n\t"
|
||||
"4 - RK4,\n\t"
|
||||
"5 - Backward Euler,\n\t"
|
||||
"6 - SDIRK 2,\n\t"
|
||||
"7 - SDIRK 3,\n\t"
|
||||
"8 - CVODE (implicit Adams),\n\t"
|
||||
"9 - CVODE (implicit BDF),\n\t"
|
||||
"10 - ARKODE (default explicit),\n\t"
|
||||
"11 - ARKODE (explicit Fehlberg-6-4-5),\n\t"
|
||||
"12 - ARKODE (default impicit).");
|
||||
"ODE solver:\n"
|
||||
"\t 1/11 - CVODE (explicit/implicit),\n"
|
||||
"\t 2/12 - ARKODE (default explicit/implicit),\n"
|
||||
"\t 3 - ARKODE (Fehlberg-6-4-5)\n"
|
||||
"\t 4 - Forward Euler, 5 - RK2, 6 - RK3 SSP, 7 - RK4,\n"
|
||||
"\t 8 - Backward Euler, 9 - SDIRK23, 10 - SDIRK33.");
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -179,24 +193,67 @@ int main(int argc, char *argv[])
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
// check for vaild ODE solver option
|
||||
if (ode_solver_type < 1 || ode_solver_type > 12)
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
}
|
||||
MPI_Finalize();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 3. Read the serial mesh from the given mesh file on all processors. We can
|
||||
// handle triangular, quadrilateral, tetrahedral and hexahedral meshes
|
||||
// with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 4. Refine the mesh in serial to increase the resolution. In this example
|
||||
// 4. Define the ODE solver used for time integration. Several
|
||||
// SUNDIALS solvers are available, as well as included both
|
||||
// explicit and implicit MFEM ODE solvers.
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKODESolver *arkode = NULL;
|
||||
SundialsJacSolver sun_solver; // Used by the implicit SUNDIALS ode solvers.
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// SUNDIALS solvers
|
||||
case 1:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_ADAMS, CV_FUNCTIONAL);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 11:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_BDF, CV_NEWTON);
|
||||
cvode->SetLinearSolver(sun_solver);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 2:
|
||||
case 3:
|
||||
arkode = new ARKODESolver(MPI_COMM_WORLD, ARKODESolver::EXPLICIT);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 3) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
|
||||
ode_solver = arkode; break;
|
||||
case 12:
|
||||
arkode = new ARKODESolver(MPI_COMM_WORLD, ARKODESolver::IMPLICIT);
|
||||
arkode->SetLinearSolver(sun_solver);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
// Other MFEM explicit methods
|
||||
case 4: ode_solver = new ForwardEulerSolver; break;
|
||||
case 5: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 6: ode_solver = new RK3SSPSolver; break;
|
||||
case 7: ode_solver = new RK4Solver; break;
|
||||
// MFEM implicit L-stable methods
|
||||
case 8: ode_solver = new BackwardEulerSolver; break;
|
||||
case 9: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 10: ode_solver = new SDIRK33Solver; break;
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
delete mesh;
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Since we want to update the diffusion coefficient after every time step,
|
||||
// we need to use the "one-step" mode of the SUNDIALS solvers.
|
||||
if (cvode) { cvode->SetStepMode(CV_ONE_STEP); }
|
||||
if (arkode) { arkode->SetStepMode(ARK_ONE_STEP); }
|
||||
|
||||
// 5. Refine the mesh in serial to increase the resolution. In this example
|
||||
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
|
||||
// a command-line parameter.
|
||||
for (int lev = 0; lev < ser_ref_levels; lev++)
|
||||
@@ -204,7 +261,7 @@ int main(int argc, char *argv[])
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
@@ -214,7 +271,7 @@ int main(int argc, char *argv[])
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 6. Define the vector finite element space representing the current and the
|
||||
// 7. Define the vector finite element space representing the current and the
|
||||
// initial temperature, u_ref.
|
||||
H1_FECollection fe_coll(order, dim);
|
||||
ParFiniteElementSpace fespace(pmesh, &fe_coll);
|
||||
@@ -227,14 +284,14 @@ int main(int argc, char *argv[])
|
||||
|
||||
ParGridFunction u_gf(&fespace);
|
||||
|
||||
// 7. Set the initial conditions for u. All boundaries are considered
|
||||
// 8. Set the initial conditions for u. All boundaries are considered
|
||||
// natural.
|
||||
FunctionCoefficient u_0(InitialTemperature);
|
||||
u_gf.ProjectCoefficient(u_0);
|
||||
Vector u;
|
||||
u_gf.GetTrueDofs(u);
|
||||
|
||||
// 8. Initialize the conduction operator and the VisIt visualization.
|
||||
// 9. Initialize the conduction operator and the VisIt visualization.
|
||||
ConductionOperator oper(fespace, alpha, kappa, u);
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
@@ -293,60 +350,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 9. Define the ODE solver used for time integration.
|
||||
double t = 0.0;
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKStepSolver *arkode = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// MFEM explicit methods
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
// MFEM implicit L-stable methods
|
||||
case 5: ode_solver = new BackwardEulerSolver; break;
|
||||
case 6: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 7: ode_solver = new SDIRK33Solver; break;
|
||||
// CVODE
|
||||
case 8:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_ADAMS);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 9:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_BDF);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
// ARKODE
|
||||
case 10:
|
||||
case 11:
|
||||
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::EXPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 11) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
|
||||
ode_solver = arkode; break;
|
||||
case 12:
|
||||
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::IMPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
}
|
||||
|
||||
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
|
||||
if (ode_solver_type < 8) { ode_solver->Init(oper); }
|
||||
|
||||
// Since we want to update the diffusion coefficient after every time step,
|
||||
// we need to use the "one-step" mode of the SUNDIALS solvers.
|
||||
if (cvode) { cvode->SetStepMode(CV_ONE_STEP); }
|
||||
if (arkode) { arkode->SetStepMode(ARK_ONE_STEP); }
|
||||
|
||||
// 10. Perform time-integration (looping over the time iterations, ti, with a
|
||||
// time-step dt).
|
||||
if (myid == 0)
|
||||
@@ -355,6 +358,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
tic_toc.Clear();
|
||||
tic_toc.Start();
|
||||
ode_solver->Init(oper);
|
||||
double t = 0.0;
|
||||
|
||||
bool last_step = false;
|
||||
for (int ti = 1; !last_step; ti++)
|
||||
@@ -423,7 +428,7 @@ int main(int argc, char *argv[])
|
||||
ConductionOperator::ConductionOperator(ParFiniteElementSpace &f, double al,
|
||||
double kap, const Vector &u)
|
||||
: TimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL), K(NULL),
|
||||
T(NULL),
|
||||
T(NULL), current_dt(0.0),
|
||||
M_solver(f.GetComm()), T_solver(f.GetComm()), z(height)
|
||||
{
|
||||
const double rel_tol = 1e-8;
|
||||
@@ -471,32 +476,30 @@ void ConductionOperator::ImplicitSolve(const double dt,
|
||||
// Solve the equation:
|
||||
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
|
||||
// for du_dt
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
T_solver.SetOperator(*T);
|
||||
if (!T)
|
||||
{
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
current_dt = dt;
|
||||
T_solver.SetOperator(*T);
|
||||
}
|
||||
MFEM_VERIFY(dt == current_dt, ""); // SDIRK methods use the same dt
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg();
|
||||
T_solver.Mult(z, du_dt);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSetup(const Vector &x,
|
||||
const Vector &fx, int jok, int *jcur,
|
||||
double gamma)
|
||||
void ConductionOperator::SundialsSolve(const double dt, Vector &b)
|
||||
{
|
||||
// Setup the ODE Jacobian T = M + gamma K.
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, gamma, Kmat);
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &b, Vector &x, double tol)
|
||||
{
|
||||
// Solve the system A x = z => (M - gamma K) x = M b.
|
||||
// Solve the system (M + dt K) y = M b. The result y replaces the input b.
|
||||
if (!T || dt != current_dt)
|
||||
{
|
||||
delete T;
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
current_dt = dt;
|
||||
T_solver.SetOperator(*T);
|
||||
}
|
||||
Mmat.Mult(b, z);
|
||||
T_solver.Mult(z, x);
|
||||
return (0);
|
||||
T_solver.Mult(z, b);
|
||||
}
|
||||
|
||||
void ConductionOperator::SetParameters(const Vector &u)
|
||||
@@ -516,6 +519,8 @@ void ConductionOperator::SetParameters(const Vector &u)
|
||||
K->AddDomainIntegrator(new DiffusionIntegrator(u_coeff));
|
||||
K->Assemble(0); // keep sparsity pattern of M and K the same
|
||||
K->FormSystemMatrix(ess_tdof_list, Kmat);
|
||||
delete T;
|
||||
T = NULL; // re-compute T on the next ImplicitSolve or SundialsSolve
|
||||
}
|
||||
|
||||
ConductionOperator::~ConductionOperator()
|
||||
@@ -525,6 +530,46 @@ ConductionOperator::~ConductionOperator()
|
||||
delete K;
|
||||
}
|
||||
|
||||
|
||||
int SundialsJacSolver::InitSystem(void *sundials_mem)
|
||||
{
|
||||
TimeDependentOperator *td_oper = GetTimeDependentOperator(sundials_mem);
|
||||
|
||||
// During development, we use dynamic_cast<> to ensure the setup is correct:
|
||||
oper = dynamic_cast<ConductionOperator*>(td_oper);
|
||||
MFEM_VERIFY(oper, "operator is not ConductionOperator");
|
||||
|
||||
// When the implementation is finalized, we can switch to static_cast<>:
|
||||
// oper = static_cast<ConductionOperator*>(td_oper);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::SetupSystem(void *sundials_mem, int conv_fail,
|
||||
const Vector &y_pred, const Vector &f_pred,
|
||||
int &jac_cur, Vector &v_temp1,
|
||||
Vector &v_temp2, Vector &v_temp3)
|
||||
{
|
||||
jac_cur = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::SolveSystem(void *sundials_mem, Vector &b,
|
||||
const Vector &weight, const Vector &y_cur,
|
||||
const Vector &f_cur)
|
||||
{
|
||||
oper->SundialsSolve(GetTimeStep(sundials_mem), b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SundialsJacSolver::FreeSystem(void *sundials_mem)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
double InitialTemperature(const Vector &x)
|
||||
{
|
||||
if (x.Norml2() < 0.5)
|
||||
|
||||
+63
-74
@@ -4,14 +4,14 @@
|
||||
// Compile with: make ex9
|
||||
//
|
||||
// Sample runs:
|
||||
// ex9 -m ../../data/periodic-segment.mesh -p 0 -r 2 -s 7 -dt 0.005
|
||||
// ex9 -m ../../data/periodic-square.mesh -p 1 -r 2 -s 8 -dt 0.005 -tf 9
|
||||
// ex9 -m ../../data/periodic-hexagon.mesh -p 0 -r 2 -s 7 -dt 0.0018 -vs 25
|
||||
// ex9 -m ../../data/periodic-hexagon.mesh -p 0 -r 2 -s 9 -dt 0.01 -vs 15
|
||||
// ex9 -m ../../data/amr-quad.mesh -p 1 -r 2 -s 9 -dt 0.002 -tf 9
|
||||
// ex9 -m ../../data/star-q3.mesh -p 1 -r 2 -s 9 -dt 0.005 -tf 9
|
||||
// ex9 -m ../../data/disc-nurbs.mesh -p 1 -r 3 -s 7 -dt 0.005 -tf 9
|
||||
// ex9 -m ../../data/periodic-cube.mesh -p 0 -r 2 -s 8 -dt 0.02 -tf 8 -o 2
|
||||
// ex9 -m ../../data/periodic-segment.mesh -p 0 -r 2 -s 11 -dt 0.005
|
||||
// ex9 -m ../../data/periodic-square.mesh -p 1 -r 2 -s 12 -dt 0.005 -tf 9
|
||||
// ex9 -m ../../data/periodic-hexagon.mesh -p 0 -r 2 -s 11 -dt 0.0018 -vs 25
|
||||
// ex9 -m ../../data/periodic-hexagon.mesh -p 0 -r 2 -s 13 -dt 0.01 -vs 15
|
||||
// ex9 -m ../../data/amr-quad.mesh -p 1 -r 2 -s 13 -dt 0.002 -tf 9
|
||||
// ex9 -m ../../data/star-q3.mesh -p 1 -r 2 -s 13 -dt 0.005 -tf 9
|
||||
// ex9 -m ../../data/disc-nurbs.mesh -p 1 -r 3 -s 11 -dt 0.005 -tf 9
|
||||
// ex9 -m ../../data/periodic-cube.mesh -p 0 -r 2 -s 12 -dt 0.02 -tf 8 -o 2
|
||||
//
|
||||
// Description: This example code solves the time-dependent advection equation
|
||||
// du/dt + v.grad(u) = 0, where v is a given fluid velocity, and
|
||||
@@ -109,15 +109,11 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver:\n\t"
|
||||
"1 - Forward Euler,\n\t"
|
||||
"2 - RK2 SSP,\n\t"
|
||||
"3 - RK3 SSP,\n\t"
|
||||
"4 - RK4,\n\t"
|
||||
"6 - RK6,\n\t"
|
||||
"7 - CVODE (adaptive order implicit Adams),\n\t"
|
||||
"8 - ARKODE default (4th order) explicit,\n\t"
|
||||
"9 - ARKODE RK8.");
|
||||
"ODE solver: 1 - Forward Euler,\n\t"
|
||||
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6,\n\t"
|
||||
" 11 - CVODE (adaptive order) explicit,\n\t"
|
||||
" 12 - ARKODE default (4th order) explicit,\n\t"
|
||||
" 13 - ARKODE RK8.");
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -139,41 +135,65 @@ int main(int argc, char *argv[])
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
// check for vaild ODE solver option
|
||||
if (ode_solver_type < 1 || ode_solver_type > 9)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 3;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
// 2. Read the mesh from the given mesh file. We can handle geometrically
|
||||
// periodic meshes in this code.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 3. Refine the mesh to increase the resolution. In this example we do
|
||||
// 3. Define the ODE solver used for time integration. Several explicit
|
||||
// Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKODESolver *arkode = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(1.0); break;
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 6: ode_solver = new RK6Solver; break;
|
||||
case 11:
|
||||
cvode = new CVODESolver(CV_ADAMS, CV_FUNCTIONAL);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 12:
|
||||
case 13:
|
||||
arkode = new ARKODESolver(ARKODESolver::EXPLICIT);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 13) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
|
||||
ode_solver = arkode; break;
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
delete mesh;
|
||||
return 3;
|
||||
}
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement, where 'ref_levels' is a
|
||||
// command-line parameter. If the mesh is of NURBS type, we convert it to
|
||||
// a (piecewise-polynomial) high-order mesh.
|
||||
for (int lev = 0; lev < ref_levels; lev++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
if (mesh.NURBSext)
|
||||
if (mesh->NURBSext)
|
||||
{
|
||||
mesh.SetCurvature(max(order, 1));
|
||||
mesh->SetCurvature(max(order, 1));
|
||||
}
|
||||
mesh.GetBoundingBox(bb_min, bb_max, max(order, 1));
|
||||
mesh->GetBoundingBox(bb_min, bb_max, max(order, 1));
|
||||
|
||||
// 4. Define the discontinuous DG finite element space of the given
|
||||
// 5. Define the discontinuous DG finite element space of the given
|
||||
// polynomial order on the refined mesh.
|
||||
DG_FECollection fec(order, dim);
|
||||
FiniteElementSpace fes(&mesh, &fec);
|
||||
FiniteElementSpace fes(mesh, &fec);
|
||||
|
||||
cout << "Number of unknowns: " << fes.GetVSize() << endl;
|
||||
|
||||
// 5. Set up and assemble the bilinear and linear forms corresponding to the
|
||||
// 6. Set up and assemble the bilinear and linear forms corresponding to the
|
||||
// DG discretization. The DGTraceIntegrator involves integrals over mesh
|
||||
// interior faces.
|
||||
VectorFunctionCoefficient velocity(dim, velocity_function);
|
||||
@@ -200,7 +220,7 @@ int main(int argc, char *argv[])
|
||||
k.Finalize(skip_zeros);
|
||||
b.Assemble();
|
||||
|
||||
// 6. Define the initial conditions, save the corresponding grid function to
|
||||
// 7. Define the initial conditions, save the corresponding grid function to
|
||||
// a file and (optionally) save data in the VisIt format and initialize
|
||||
// GLVis visualization.
|
||||
GridFunction u(&fes);
|
||||
@@ -209,7 +229,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
ofstream omesh("ex9.mesh");
|
||||
omesh.precision(precision);
|
||||
mesh.Print(omesh);
|
||||
mesh->Print(omesh);
|
||||
ofstream osol("ex9-init.gf");
|
||||
osol.precision(precision);
|
||||
u.Save(osol);
|
||||
@@ -223,14 +243,14 @@ int main(int argc, char *argv[])
|
||||
if (binary)
|
||||
{
|
||||
#ifdef MFEM_USE_SIDRE
|
||||
dc = new SidreDataCollection("Example9", &mesh);
|
||||
dc = new SidreDataCollection("Example9", mesh);
|
||||
#else
|
||||
MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
dc = new VisItDataCollection("Example9", &mesh);
|
||||
dc = new VisItDataCollection("Example9", mesh);
|
||||
dc->SetPrecision(precision);
|
||||
}
|
||||
dc->RegisterField("solution", &u);
|
||||
@@ -255,7 +275,7 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
{
|
||||
sout.precision(precision);
|
||||
sout << "solution\n" << mesh << u;
|
||||
sout << "solution\n" << *mesh << u;
|
||||
sout << "pause\n";
|
||||
sout << flush;
|
||||
cout << "GLVis visualization paused."
|
||||
@@ -263,46 +283,15 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Define the time-dependent evolution operator describing the ODE
|
||||
// right-hand side, and define the ODE solver used for time integration.
|
||||
// 8. Define the time-dependent evolution operator describing the ODE
|
||||
// right-hand side, and perform time-integration (looping over the time
|
||||
// iterations, ti, with a time-step dt).
|
||||
FE_Evolution adv(m.SpMat(), k.SpMat(), b);
|
||||
|
||||
double t = 0.0;
|
||||
adv.SetTime(t);
|
||||
ode_solver->Init(adv);
|
||||
|
||||
// Create the time integrator
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKStepSolver *arkode = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(1.0); break;
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 6: ode_solver = new RK6Solver; break;
|
||||
case 7:
|
||||
cvode = new CVODESolver(CV_ADAMS);
|
||||
cvode->Init(adv);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
cvode->UseSundialsLinearSolver();
|
||||
ode_solver = cvode; break;
|
||||
case 8:
|
||||
case 9:
|
||||
arkode = new ARKStepSolver(ARKStepSolver::EXPLICIT);
|
||||
arkode->Init(adv);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 9) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
|
||||
ode_solver = arkode; break;
|
||||
}
|
||||
|
||||
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
|
||||
if (ode_solver_type < 7) { ode_solver->Init(adv); }
|
||||
|
||||
// 8. Perform time-integration (looping over the time iterations, ti,
|
||||
// with a time-step dt).
|
||||
bool done = false;
|
||||
for (int ti = 0; !done; )
|
||||
{
|
||||
@@ -320,7 +309,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
sout << "solution\n" << mesh << u << flush;
|
||||
sout << "solution\n" << *mesh << u << flush;
|
||||
}
|
||||
|
||||
if (visit)
|
||||
|
||||
+56
-67
@@ -4,14 +4,14 @@
|
||||
// Compile with: make ex9p
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-segment.mesh -p 1 -rp 1 -s 7 -dt 0.0025
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-square.mesh -p 1 -rp 1 -s 8 -dt 0.0025 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-hexagon.mesh -p 0 -rp 1 -s 7 -dt 0.0009 -vs 25
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-hexagon.mesh -p 0 -rp 1 -s 9 -dt 0.005 -vs 15
|
||||
// mpirun -np 4 ex9p -m ../../data/amr-quad.mesh -p 1 -rp 1 -s 9 -dt 0.001 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../../data/star-q3.mesh -p 1 -rp 1 -s 9 -dt 0.0025 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../../data/disc-nurbs.mesh -p 1 -rp 2 -s 7 -dt 0.0025 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-cube.mesh -p 0 -rp 1 -s 8 -dt 0.01 -tf 8 -o 2
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-segment.mesh -p 1 -rp 1 -s 11 -dt 0.0025
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-square.mesh -p 1 -rp 1 -s 12 -dt 0.0025 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-hexagon.mesh -p 0 -rp 1 -s 11 -dt 0.0009 -vs 25
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-hexagon.mesh -p 0 -rp 1 -s 13 -dt 0.005 -vs 15
|
||||
// mpirun -np 4 ex9p -m ../../data/amr-quad.mesh -p 1 -rp 1 -s 13 -dt 0.001 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../../data/star-q3.mesh -p 1 -rp 1 -s 13 -dt 0.0025 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../../data/disc-nurbs.mesh -p 1 -rp 2 -s 11 -dt 0.0025 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-cube.mesh -p 0 -rp 1 -s 12 -dt 0.01 -tf 8 -o 2
|
||||
//
|
||||
// Description: This example code solves the time-dependent advection equation
|
||||
// du/dt + v.grad(u) = 0, where v is a given fluid velocity, and
|
||||
@@ -117,15 +117,11 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
|
||||
"ODE solver:\n\t"
|
||||
"1 - Forward Euler,\n\t"
|
||||
"2 - RK2 SSP,\n\t"
|
||||
"3 - RK3 SSP,\n\t"
|
||||
"4 - RK4,\n\t"
|
||||
"6 - RK6,\n\t"
|
||||
"7 - CVODE (adaptive order implicit Adams),\n\t"
|
||||
"8 - ARKODE default (4th order) explicit,\n\t"
|
||||
"9 - ARKODE RK8.");
|
||||
"ODE solver: 1 - Forward Euler,\n\t"
|
||||
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6,\n\t"
|
||||
" 11 - CVODE (adaptive order) explicit,\n\t"
|
||||
" 12 - ARKODE default (4th order) explicit,\n\t"
|
||||
" 13 - ARKODE RK8.");
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -155,23 +151,47 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
// check for vaild ODE solver option
|
||||
if (ode_solver_type < 1 || ode_solver_type > 9)
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
}
|
||||
MPI_Finalize();
|
||||
return 3;
|
||||
}
|
||||
|
||||
// 3. Read the serial mesh from the given mesh file on all processors. We can
|
||||
// handle geometrically periodic meshes in this code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 4. Refine the mesh in serial to increase the resolution. In this example
|
||||
// 4. Define the ODE solver used for time integration. Several explicit
|
||||
// Runge-Kutta methods are available.
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKODESolver *arkode = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(1.0); break;
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 6: ode_solver = new RK6Solver; break;
|
||||
case 11:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_ADAMS, CV_FUNCTIONAL);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 12:
|
||||
case 13:
|
||||
arkode = new ARKODESolver(MPI_COMM_WORLD, ARKODESolver::EXPLICIT);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 13) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
|
||||
ode_solver = arkode; break;
|
||||
default:
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
}
|
||||
delete mesh;
|
||||
MPI_Finalize();
|
||||
return 3;
|
||||
}
|
||||
|
||||
// 5. Refine the mesh in serial to increase the resolution. In this example
|
||||
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
|
||||
// a command-line parameter. If the mesh is of NURBS type, we convert it
|
||||
// to a (piecewise-polynomial) high-order mesh.
|
||||
@@ -185,7 +205,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
mesh->GetBoundingBox(bb_min, bb_max, max(order, 1));
|
||||
|
||||
// 5. Define the parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// 6. Define the parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
@@ -195,7 +215,7 @@ int main(int argc, char *argv[])
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 6. Define the parallel discontinuous DG finite element space on the
|
||||
// 7. Define the parallel discontinuous DG finite element space on the
|
||||
// parallel refined mesh of the given polynomial order.
|
||||
DG_FECollection fec(order, dim);
|
||||
ParFiniteElementSpace *fes = new ParFiniteElementSpace(pmesh, &fec);
|
||||
@@ -206,7 +226,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Number of unknowns: " << global_vSize << endl;
|
||||
}
|
||||
|
||||
// 7. Set up and assemble the parallel bilinear and linear forms (and the
|
||||
// 8. Set up and assemble the parallel bilinear and linear forms (and the
|
||||
// parallel hypre matrices) corresponding to the DG discretization. The
|
||||
// DGTraceIntegrator involves integrals over mesh interior faces.
|
||||
VectorFunctionCoefficient velocity(dim, velocity_function);
|
||||
@@ -237,7 +257,7 @@ int main(int argc, char *argv[])
|
||||
HypreParMatrix *K = k->ParallelAssemble();
|
||||
HypreParVector *B = b->ParallelAssemble();
|
||||
|
||||
// 8. Define the initial conditions, save the corresponding grid function to
|
||||
// 9. Define the initial conditions, save the corresponding grid function to
|
||||
// a file and (optionally) save data in the VisIt format and initialize
|
||||
// GLVis visualization.
|
||||
ParGridFunction *u = new ParGridFunction(fes);
|
||||
@@ -310,46 +330,15 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 9. Define the time-dependent evolution operator describing the ODE
|
||||
// right-hand side, and define the ODE solver used for time integration.
|
||||
// 10. Define the time-dependent evolution operator describing the ODE
|
||||
// right-hand side, and perform time-integration (looping over the time
|
||||
// iterations, ti, with a time-step dt).
|
||||
FE_Evolution adv(*M, *K, *B);
|
||||
|
||||
double t = 0.0;
|
||||
adv.SetTime(t);
|
||||
ode_solver->Init(adv);
|
||||
|
||||
// Create the time integrator
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKStepSolver *arkode = NULL;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(1.0); break;
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 6: ode_solver = new RK6Solver; break;
|
||||
case 7:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_ADAMS);
|
||||
cvode->Init(adv);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
cvode->UseSundialsLinearSolver();
|
||||
ode_solver = cvode; break;
|
||||
case 8:
|
||||
case 9:
|
||||
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::EXPLICIT);
|
||||
arkode->Init(adv);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 9) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
|
||||
ode_solver = arkode; break;
|
||||
}
|
||||
|
||||
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
|
||||
if (ode_solver_type < 7) { ode_solver->Init(adv); }
|
||||
|
||||
// 10. Perform time-integration (looping over the time iterations, ti,
|
||||
// with a time-step dt).
|
||||
bool done = false;
|
||||
for (int ti = 0; !done; )
|
||||
{
|
||||
|
||||
@@ -60,15 +60,15 @@ PARALLEL_NAME := Parallel SUNDIALS example
|
||||
@$(call mfem-test,$<,, $(SERIAL_NAME))
|
||||
|
||||
# Testing: Specific execution options:
|
||||
# Example 9: test CVODE with CV_ADAMS (non-stiff implicit) time stepping
|
||||
EX9_COMMON_ARGS := -m ../../data/periodic-hexagon.mesh -p 0 -s 7
|
||||
# Example 9: test explicit CVODE time stepping
|
||||
EX9_COMMON_ARGS := -m ../../data/periodic-hexagon.mesh -p 0 -s 11
|
||||
EX9_ARGS := $(EX9_COMMON_ARGS) -r 2 -dt 0.0018 -vs 25
|
||||
EX9P_ARGS := $(EX9_COMMON_ARGS) -rp 1 -dt 0.0009 -vs 50
|
||||
ex9-test-seq: ex9
|
||||
@$(call mfem-test,$<,, $(SERIAL_NAME),$(EX9_ARGS))
|
||||
ex9p-test-par: ex9p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME),$(EX9P_ARGS))
|
||||
# Example 10: test CVODE with CV_BDF (stiff implicit) time stepping
|
||||
# Example 10: test implicit CVODE time stepping
|
||||
EX10_COMMON_ARGS := -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -tf 6 -vs 10
|
||||
EX10_ARGS := $(EX10_COMMON_ARGS) -r 2
|
||||
EX10P_ARGS := $(EX10_COMMON_ARGS) -rp 1
|
||||
|
||||
+2
-4
@@ -13,8 +13,7 @@ set(SRCS
|
||||
bilinearform.cpp
|
||||
bilinearform_ext.cpp
|
||||
bilininteg.cpp
|
||||
bilininteg_diffusion.cpp
|
||||
bilininteg_mass.cpp
|
||||
bilininteg_ext.cpp
|
||||
coefficient.cpp
|
||||
datacollection.cpp
|
||||
eltrans.cpp
|
||||
@@ -32,13 +31,13 @@ set(SRCS
|
||||
nonlininteg.cpp
|
||||
staticcond.cpp
|
||||
tmop.cpp
|
||||
tmop_tools.cpp
|
||||
)
|
||||
|
||||
set(HDRS
|
||||
bilinearform.hpp
|
||||
bilinearform_ext.hpp
|
||||
bilininteg.hpp
|
||||
bilininteg_ext.hpp
|
||||
coefficient.hpp
|
||||
datacollection.hpp
|
||||
eltrans.hpp
|
||||
@@ -65,7 +64,6 @@ set(HDRS
|
||||
tfespace.hpp
|
||||
tintrules.hpp
|
||||
tmop.hpp
|
||||
tmop_tools.hpp
|
||||
)
|
||||
|
||||
if (MFEM_USE_SIDRE)
|
||||
|
||||
+55
-272
@@ -55,7 +55,7 @@ void BilinearForm::AllocMat()
|
||||
|
||||
int *I = dof_dof.GetI();
|
||||
int *J = dof_dof.GetJ();
|
||||
double *data = new double[I[height]];
|
||||
double *data = mfem::New<double>(I[height]);
|
||||
|
||||
mat = new SparseMatrix(I, J, data, height, height, true, true, true);
|
||||
*mat = 0.0;
|
||||
@@ -122,7 +122,11 @@ void BilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
|
||||
switch (assembly)
|
||||
{
|
||||
case AssemblyLevel::FULL:
|
||||
// ext = new FABilinearFormExtension(this);
|
||||
if (Device::IsEnabled())
|
||||
{
|
||||
mfem_error("Full assembly not supported yet in device mode!");
|
||||
// ext = new FABilinearFormExtension(this);
|
||||
}
|
||||
// Use the original BilinearForm implementation for now
|
||||
break;
|
||||
case AssemblyLevel::ELEMENT:
|
||||
@@ -294,33 +298,6 @@ void BilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat)
|
||||
}
|
||||
}
|
||||
|
||||
void BilinearForm::ComputeBdrElementMatrix(int i, DenseMatrix &elmat)
|
||||
{
|
||||
if (bbfi.Size())
|
||||
{
|
||||
const FiniteElement &be = *fes->GetBE(i);
|
||||
ElementTransformation *eltrans = fes->GetBdrElementTransformation(i);
|
||||
bbfi[0]->AssembleElementMatrix(be, *eltrans, elmat);
|
||||
for (int k = 1; k < bbfi.Size(); k++)
|
||||
{
|
||||
bbfi[k]->AssembleElementMatrix(be, *eltrans, elemmat);
|
||||
elmat += elemmat;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fes->GetBdrElementVDofs(i, vdofs);
|
||||
elmat.SetSize(vdofs.Size());
|
||||
elmat = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void BilinearForm::AssembleElementMatrix(
|
||||
int i, const DenseMatrix &elmat, int skip_zeros)
|
||||
{
|
||||
AssembleElementMatrix(i, elmat, vdofs, skip_zeros);
|
||||
}
|
||||
|
||||
void BilinearForm::AssembleElementMatrix(
|
||||
int i, const DenseMatrix &elmat, Array<int> &vdofs, int skip_zeros)
|
||||
{
|
||||
@@ -343,12 +320,6 @@ void BilinearForm::AssembleElementMatrix(
|
||||
}
|
||||
}
|
||||
|
||||
void BilinearForm::AssembleBdrElementMatrix(
|
||||
int i, const DenseMatrix &elmat, int skip_zeros)
|
||||
{
|
||||
AssembleBdrElementMatrix(i, elmat, vdofs, skip_zeros);
|
||||
}
|
||||
|
||||
void BilinearForm::AssembleBdrElementMatrix(
|
||||
int i, const DenseMatrix &elmat, Array<int> &vdofs, int skip_zeros)
|
||||
{
|
||||
@@ -373,6 +344,11 @@ void BilinearForm::AssembleBdrElementMatrix(
|
||||
|
||||
void BilinearForm::Assemble(int skip_zeros)
|
||||
{
|
||||
if (Device::IsEnabled() && (assembly != AssemblyLevel::PARTIAL))
|
||||
{
|
||||
mfem_error("Chosen assembly level not supported yet in device mode!");
|
||||
}
|
||||
|
||||
if (ext)
|
||||
{
|
||||
ext->Assemble();
|
||||
@@ -616,6 +592,10 @@ void BilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x,
|
||||
|
||||
if (ext)
|
||||
{
|
||||
if (P != NULL && assembly != AssemblyLevel::FULL && Device::IsEnabled())
|
||||
{
|
||||
P->BuildTranspose();
|
||||
}
|
||||
ext->FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
|
||||
return;
|
||||
}
|
||||
@@ -645,8 +625,8 @@ void BilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x,
|
||||
{
|
||||
// A, X and B point to the same data as mat, x and b
|
||||
EliminateVDofsInRHS(ess_tdof_list, x, b);
|
||||
X.NewMemoryAndSize(x.GetMemory(), x.Size(), false);
|
||||
B.NewMemoryAndSize(b.GetMemory(), b.Size(), false);
|
||||
X.NewDataAndSize(x.GetData(), x.Size());
|
||||
B.NewDataAndSize(b.GetData(), b.Size());
|
||||
if (!copy_interior) { X.SetSubVectorComplement(ess_tdof_list, 0.0); }
|
||||
}
|
||||
}
|
||||
@@ -747,10 +727,6 @@ void BilinearForm::RecoverFEMSolution(const Vector &X,
|
||||
else
|
||||
{
|
||||
// X and x point to the same data
|
||||
|
||||
// If the validity flags of X's Memory were changed (e.g. if it was
|
||||
// moved to device memory) then we need to tell x about that.
|
||||
x.SyncMemory(X);
|
||||
}
|
||||
}
|
||||
else // non-conforming space
|
||||
@@ -1049,13 +1025,9 @@ MixedBilinearForm::MixedBilinearForm (FiniteElementSpace *tr_fes,
|
||||
extern_bfs = 1;
|
||||
|
||||
// Copy the pointers to the integrators
|
||||
dbfi = mbf->dbfi;
|
||||
bbfi = mbf->bbfi;
|
||||
tfbfi = mbf->tfbfi;
|
||||
btfbfi = mbf->btfbfi;
|
||||
|
||||
bbfi_marker = mbf->bbfi_marker;
|
||||
btfbfi_marker = mbf->btfbfi_marker;
|
||||
dom = mbf->dom;
|
||||
bdr = mbf->bdr;
|
||||
skt = mbf->skt;
|
||||
}
|
||||
|
||||
double & MixedBilinearForm::Elem (int i, int j)
|
||||
@@ -1109,42 +1081,22 @@ void MixedBilinearForm::GetBlocks(Array2D<SparseMatrix *> &blocks) const
|
||||
|
||||
void MixedBilinearForm::AddDomainIntegrator (BilinearFormIntegrator * bfi)
|
||||
{
|
||||
dbfi.Append (bfi);
|
||||
dom.Append (bfi);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddBoundaryIntegrator (BilinearFormIntegrator * bfi)
|
||||
{
|
||||
bbfi.Append (bfi);
|
||||
bbfi_marker.Append(NULL); // NULL marker means apply everywhere
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddBoundaryIntegrator (BilinearFormIntegrator * bfi,
|
||||
Array<int> &bdr_marker)
|
||||
{
|
||||
bbfi.Append (bfi);
|
||||
bbfi_marker.Append(&bdr_marker);
|
||||
bdr.Append (bfi);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddTraceFaceIntegrator (BilinearFormIntegrator * bfi)
|
||||
{
|
||||
tfbfi.Append (bfi);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddBdrTraceFaceIntegrator(BilinearFormIntegrator *bfi)
|
||||
{
|
||||
btfbfi.Append(bfi);
|
||||
btfbfi_marker.Append(NULL); // NULL marker means apply everywhere
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddBdrTraceFaceIntegrator(BilinearFormIntegrator *bfi,
|
||||
Array<int> &bdr_marker)
|
||||
{
|
||||
btfbfi.Append(bfi);
|
||||
btfbfi_marker.Append(&bdr_marker);
|
||||
skt.Append (bfi);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::Assemble (int skip_zeros)
|
||||
{
|
||||
int i, k;
|
||||
Array<int> tr_vdofs, te_vdofs;
|
||||
ElementTransformation *eltrans;
|
||||
DenseMatrix elemmat;
|
||||
@@ -1156,75 +1108,48 @@ void MixedBilinearForm::Assemble (int skip_zeros)
|
||||
mat = new SparseMatrix(height, width);
|
||||
}
|
||||
|
||||
if (dbfi.Size())
|
||||
if (dom.Size())
|
||||
{
|
||||
for (int i = 0; i < test_fes -> GetNE(); i++)
|
||||
for (i = 0; i < test_fes -> GetNE(); i++)
|
||||
{
|
||||
trial_fes -> GetElementVDofs (i, tr_vdofs);
|
||||
test_fes -> GetElementVDofs (i, te_vdofs);
|
||||
eltrans = test_fes -> GetElementTransformation (i);
|
||||
for (int k = 0; k < dbfi.Size(); k++)
|
||||
for (k = 0; k < dom.Size(); k++)
|
||||
{
|
||||
dbfi[k] -> AssembleElementMatrix2 (*trial_fes -> GetFE(i),
|
||||
*test_fes -> GetFE(i),
|
||||
*eltrans, elemmat);
|
||||
dom[k] -> AssembleElementMatrix2 (*trial_fes -> GetFE(i),
|
||||
*test_fes -> GetFE(i),
|
||||
*eltrans, elemmat);
|
||||
mat -> AddSubMatrix (te_vdofs, tr_vdofs, elemmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bbfi.Size())
|
||||
if (bdr.Size())
|
||||
{
|
||||
// Which boundary attributes need to be processed?
|
||||
Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
|
||||
mesh->bdr_attributes.Max() : 0);
|
||||
bdr_attr_marker = 0;
|
||||
for (int k = 0; k < bbfi.Size(); k++)
|
||||
for (i = 0; i < test_fes -> GetNBE(); i++)
|
||||
{
|
||||
if (bbfi_marker[k] == NULL)
|
||||
{
|
||||
bdr_attr_marker = 1;
|
||||
break;
|
||||
}
|
||||
Array<int> &bdr_marker = *bbfi_marker[k];
|
||||
MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
|
||||
"invalid boundary marker for boundary integrator #"
|
||||
<< k << ", counting from zero");
|
||||
for (int i = 0; i < bdr_attr_marker.Size(); i++)
|
||||
{
|
||||
bdr_attr_marker[i] |= bdr_marker[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < test_fes -> GetNBE(); i++)
|
||||
{
|
||||
const int bdr_attr = mesh->GetBdrAttribute(i);
|
||||
if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
|
||||
|
||||
trial_fes -> GetBdrElementVDofs (i, tr_vdofs);
|
||||
test_fes -> GetBdrElementVDofs (i, te_vdofs);
|
||||
eltrans = test_fes -> GetBdrElementTransformation (i);
|
||||
for (int k = 0; k < bbfi.Size(); k++)
|
||||
for (k = 0; k < bdr.Size(); k++)
|
||||
{
|
||||
if (bbfi_marker[k] &&
|
||||
(*bbfi_marker[k])[bdr_attr-1] == 0) { continue; }
|
||||
|
||||
bbfi[k] -> AssembleElementMatrix2 (*trial_fes -> GetBE(i),
|
||||
*test_fes -> GetBE(i),
|
||||
*eltrans, elemmat);
|
||||
bdr[k] -> AssembleElementMatrix2 (*trial_fes -> GetBE(i),
|
||||
*test_fes -> GetBE(i),
|
||||
*eltrans, elemmat);
|
||||
mat -> AddSubMatrix (te_vdofs, tr_vdofs, elemmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tfbfi.Size())
|
||||
if (skt.Size())
|
||||
{
|
||||
FaceElementTransformations *ftr;
|
||||
Array<int> te_vdofs2;
|
||||
const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
|
||||
|
||||
int nfaces = mesh->GetNumFaces();
|
||||
for (int i = 0; i < nfaces; i++)
|
||||
for (i = 0; i < nfaces; i++)
|
||||
{
|
||||
ftr = mesh->GetFaceElementTransformations(i);
|
||||
trial_fes->GetFaceVDofs(i, tr_vdofs);
|
||||
@@ -1244,70 +1169,14 @@ void MixedBilinearForm::Assemble (int skip_zeros)
|
||||
// want to actually make a fake element.
|
||||
test_fe2 = test_fe1;
|
||||
}
|
||||
for (int k = 0; k < tfbfi.Size(); k++)
|
||||
for (int k = 0; k < skt.Size(); k++)
|
||||
{
|
||||
tfbfi[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1, *test_fe2,
|
||||
*ftr, elemmat);
|
||||
skt[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1, *test_fe2,
|
||||
*ftr, elemmat);
|
||||
mat->AddSubMatrix(te_vdofs, tr_vdofs, elemmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (btfbfi.Size())
|
||||
{
|
||||
FaceElementTransformations *ftr;
|
||||
Array<int> te_vdofs2;
|
||||
const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
|
||||
|
||||
// Which boundary attributes need to be processed?
|
||||
Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
|
||||
mesh->bdr_attributes.Max() : 0);
|
||||
bdr_attr_marker = 0;
|
||||
for (int k = 0; k < btfbfi.Size(); k++)
|
||||
{
|
||||
if (btfbfi_marker[k] == NULL)
|
||||
{
|
||||
bdr_attr_marker = 1;
|
||||
break;
|
||||
}
|
||||
Array<int> &bdr_marker = *btfbfi_marker[k];
|
||||
MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
|
||||
"invalid boundary marker for boundary trace face integrator #"
|
||||
<< k << ", counting from zero");
|
||||
for (int i = 0; i < bdr_attr_marker.Size(); i++)
|
||||
{
|
||||
bdr_attr_marker[i] |= bdr_marker[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < trial_fes -> GetNBE(); i++)
|
||||
{
|
||||
const int bdr_attr = mesh->GetBdrAttribute(i);
|
||||
if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
|
||||
|
||||
ftr = mesh->GetBdrFaceTransformations(i);
|
||||
if (ftr)
|
||||
{
|
||||
trial_fes->GetFaceVDofs(i, tr_vdofs);
|
||||
test_fes->GetElementVDofs(ftr->Elem1No, te_vdofs);
|
||||
trial_face_fe = trial_fes->GetFaceElement(i);
|
||||
test_fe1 = test_fes->GetFE(ftr->Elem1No);
|
||||
// The test_fe2 object is really a dummy and not used on the
|
||||
// boundaries, but we can't dereference a NULL pointer, and we don't
|
||||
// want to actually make a fake element.
|
||||
test_fe2 = test_fe1;
|
||||
for (int k = 0; k < btfbfi.Size(); k++)
|
||||
{
|
||||
if (btfbfi_marker[k] &&
|
||||
(*btfbfi_marker[k])[bdr_attr-1] == 0) { continue; }
|
||||
|
||||
btfbfi[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1, *test_fe2,
|
||||
*ftr, elemmat);
|
||||
mat->AddSubMatrix(te_vdofs, tr_vdofs, elemmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MixedBilinearForm::ConformingAssemble()
|
||||
@@ -1336,93 +1205,8 @@ void MixedBilinearForm::ConformingAssemble()
|
||||
width = mat->Width();
|
||||
}
|
||||
|
||||
|
||||
void MixedBilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat)
|
||||
{
|
||||
if (dbfi.Size())
|
||||
{
|
||||
const FiniteElement &trial_fe = *trial_fes->GetFE(i);
|
||||
const FiniteElement &test_fe = *test_fes->GetFE(i);
|
||||
ElementTransformation *eltrans = test_fes->GetElementTransformation(i);
|
||||
dbfi[0]->AssembleElementMatrix2(trial_fe, test_fe, *eltrans, elmat);
|
||||
for (int k = 1; k < dbfi.Size(); k++)
|
||||
{
|
||||
dbfi[k]->AssembleElementMatrix2(trial_fe, test_fe, *eltrans, elemmat);
|
||||
elmat += elemmat;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trial_fes->GetElementVDofs(i, trial_vdofs);
|
||||
test_fes->GetElementVDofs(i, test_vdofs);
|
||||
elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
|
||||
elmat = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void MixedBilinearForm::ComputeBdrElementMatrix(int i, DenseMatrix &elmat)
|
||||
{
|
||||
if (bbfi.Size())
|
||||
{
|
||||
const FiniteElement &trial_be = *trial_fes->GetBE(i);
|
||||
const FiniteElement &test_be = *test_fes->GetBE(i);
|
||||
ElementTransformation *eltrans = test_fes->GetBdrElementTransformation(i);
|
||||
bbfi[0]->AssembleElementMatrix2(trial_be, test_be, *eltrans, elmat);
|
||||
for (int k = 1; k < bbfi.Size(); k++)
|
||||
{
|
||||
bbfi[k]->AssembleElementMatrix2(trial_be, test_be, *eltrans, elemmat);
|
||||
elmat += elemmat;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trial_fes->GetBdrElementVDofs(i, trial_vdofs);
|
||||
test_fes->GetBdrElementVDofs(i, test_vdofs);
|
||||
elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
|
||||
elmat = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AssembleElementMatrix(
|
||||
int i, const DenseMatrix &elmat, int skip_zeros)
|
||||
{
|
||||
AssembleElementMatrix(i, elmat, trial_vdofs, test_vdofs, skip_zeros);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AssembleElementMatrix(
|
||||
int i, const DenseMatrix &elmat, Array<int> &trial_vdofs,
|
||||
Array<int> &test_vdofs, int skip_zeros)
|
||||
{
|
||||
trial_fes->GetElementVDofs(i, trial_vdofs);
|
||||
test_fes->GetElementVDofs(i, test_vdofs);
|
||||
if (mat == NULL)
|
||||
{
|
||||
mat = new SparseMatrix(height, width);
|
||||
}
|
||||
mat->AddSubMatrix(test_vdofs, trial_vdofs, elmat, skip_zeros);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AssembleBdrElementMatrix(
|
||||
int i, const DenseMatrix &elmat, int skip_zeros)
|
||||
{
|
||||
AssembleBdrElementMatrix(i, elmat, trial_vdofs, test_vdofs, skip_zeros);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AssembleBdrElementMatrix(
|
||||
int i, const DenseMatrix &elmat, Array<int> &trial_vdofs,
|
||||
Array<int> &test_vdofs, int skip_zeros)
|
||||
{
|
||||
trial_fes->GetBdrElementVDofs(i, trial_vdofs);
|
||||
test_fes->GetBdrElementVDofs(i, test_vdofs);
|
||||
if (mat == NULL)
|
||||
{
|
||||
mat = new SparseMatrix(height, width);
|
||||
}
|
||||
mat->AddSubMatrix(test_vdofs, trial_vdofs, elmat, skip_zeros);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::EliminateTrialDofs (
|
||||
const Array<int> &bdr_attr_is_ess, const Vector &sol, Vector &rhs )
|
||||
Array<int> &bdr_attr_is_ess, const Vector &sol, Vector &rhs )
|
||||
{
|
||||
int i, j, k;
|
||||
Array<int> tr_vdofs, cols_marker (trial_fes -> GetVSize());
|
||||
@@ -1445,12 +1229,12 @@ void MixedBilinearForm::EliminateTrialDofs (
|
||||
}
|
||||
|
||||
void MixedBilinearForm::EliminateEssentialBCFromTrialDofs (
|
||||
const Array<int> &marked_vdofs, const Vector &sol, Vector &rhs)
|
||||
Array<int> &marked_vdofs, const Vector &sol, Vector &rhs)
|
||||
{
|
||||
mat -> EliminateCols (marked_vdofs, &sol, &rhs);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::EliminateTestDofs (const Array<int> &bdr_attr_is_ess)
|
||||
void MixedBilinearForm::EliminateTestDofs (Array<int> &bdr_attr_is_ess)
|
||||
{
|
||||
int i, j, k;
|
||||
Array<int> te_vdofs;
|
||||
@@ -1484,10 +1268,9 @@ MixedBilinearForm::~MixedBilinearForm()
|
||||
if (!extern_bfs)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < dbfi.Size(); i++) { delete dbfi[i]; }
|
||||
for (i = 0; i < bbfi.Size(); i++) { delete bbfi[i]; }
|
||||
for (i = 0; i < tfbfi.Size(); i++) { delete tfbfi[i]; }
|
||||
for (i = 0; i < btfbfi.Size(); i++) { delete btfbfi[i]; }
|
||||
for (i = 0; i < dom.Size(); i++) { delete dom[i]; }
|
||||
for (i = 0; i < bdr.Size(); i++) { delete bdr[i]; }
|
||||
for (i = 0; i < skt.Size(); i++) { delete skt[i]; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1504,7 +1287,7 @@ void DiscreteLinearOperator::Assemble(int skip_zeros)
|
||||
mat = new SparseMatrix(height, width);
|
||||
}
|
||||
|
||||
if (dbfi.Size() > 0)
|
||||
if (dom.Size() > 0)
|
||||
{
|
||||
for (int i = 0; i < test_fes->GetNE(); i++)
|
||||
{
|
||||
@@ -1514,17 +1297,17 @@ void DiscreteLinearOperator::Assemble(int skip_zeros)
|
||||
dom_fe = trial_fes->GetFE(i);
|
||||
ran_fe = test_fes->GetFE(i);
|
||||
|
||||
dbfi[0]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, totelmat);
|
||||
for (int j = 1; j < dbfi.Size(); j++)
|
||||
dom[0]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, totelmat);
|
||||
for (int j = 1; j < dom.Size(); j++)
|
||||
{
|
||||
dbfi[j]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, elmat);
|
||||
dom[j]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, elmat);
|
||||
totelmat += elmat;
|
||||
}
|
||||
mat->SetSubMatrix(ran_vdofs, dom_vdofs, totelmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
|
||||
if (tfbfi.Size())
|
||||
if (skt.Size())
|
||||
{
|
||||
const int nfaces = test_fes->GetMesh()->GetNumFaces();
|
||||
for (int i = 0; i < nfaces; i++)
|
||||
@@ -1535,10 +1318,10 @@ void DiscreteLinearOperator::Assemble(int skip_zeros)
|
||||
dom_fe = trial_fes->GetFaceElement(i);
|
||||
ran_fe = test_fes->GetFaceElement(i);
|
||||
|
||||
tfbfi[0]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, totelmat);
|
||||
for (int j = 1; j < tfbfi.Size(); j++)
|
||||
skt[0]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, totelmat);
|
||||
for (int j = 1; j < skt.Size(); j++)
|
||||
{
|
||||
tfbfi[j]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, elmat);
|
||||
skt[j]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, elmat);
|
||||
totelmat += elmat;
|
||||
}
|
||||
mat->SetSubMatrix(ran_vdofs, dom_vdofs, totelmat, skip_zeros);
|
||||
|
||||
+12
-130
@@ -413,49 +413,9 @@ public:
|
||||
void FreeElementMatrices()
|
||||
{ delete element_matrices; element_matrices = NULL; }
|
||||
|
||||
/// Compute the element matrix of the given element
|
||||
/** The element matrix is computed by calling the domain integrators
|
||||
or the one stored internally by a prior call of ComputeElementMatrices()
|
||||
is returned when available.
|
||||
*/
|
||||
void ComputeElementMatrix(int i, DenseMatrix &elmat);
|
||||
|
||||
/// Compute the boundary element matrix of the given boundary element
|
||||
void ComputeBdrElementMatrix(int i, DenseMatrix &elmat);
|
||||
|
||||
/// Assemble the given element matrix
|
||||
/** The element matrix @a elmat is assembled for the element @a i, i.e.
|
||||
added to the system matrix. The flag @a skip_zeros skips the zero
|
||||
elements of the matrix, unless they are breaking the symmetry of
|
||||
the system matrix.
|
||||
*/
|
||||
void AssembleElementMatrix(int i, const DenseMatrix &elmat,
|
||||
int skip_zeros = 1);
|
||||
|
||||
/// Assemble the given element matrix
|
||||
/** The element matrix @a elmat is assembled for the element @a i, i.e.
|
||||
added to the system matrix. The vdofs of the element are returned
|
||||
in @a vdofs. The flag @a skip_zeros skips the zero elements of the
|
||||
matrix, unless they are breaking the symmetry of the system matrix.
|
||||
*/
|
||||
void AssembleElementMatrix(int i, const DenseMatrix &elmat,
|
||||
Array<int> &vdofs, int skip_zeros = 1);
|
||||
|
||||
/// Assemble the given boundary element matrix
|
||||
/** The boundary element matrix @a elmat is assembled for the boundary
|
||||
element @a i, i.e. added to the system matrix. The flag @a skip_zeros
|
||||
skips the zero elements of the matrix, unless they are breaking the
|
||||
symmetry of the system matrix.
|
||||
*/
|
||||
void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat,
|
||||
int skip_zeros = 1);
|
||||
|
||||
/// Assemble the given boundary element matrix
|
||||
/** The boundary element matrix @a elmat is assembled for the boundary
|
||||
element @a i, i.e. added to the system matrix. The vdofs of the element
|
||||
are returned in @a vdofs. The flag @a skip_zeros skips the zero elements
|
||||
of the matrix, unless they are breaking the symmetry of the system matrix.
|
||||
*/
|
||||
void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat,
|
||||
Array<int> &vdofs, int skip_zeros = 1);
|
||||
|
||||
@@ -553,26 +513,16 @@ protected:
|
||||
FiniteElementSpace *trial_fes, ///< Not owned
|
||||
*test_fes; ///< Not owned
|
||||
|
||||
/** @brief Indicates the BilinearFormIntegrator%s stored in #dbfi, #bbfi,
|
||||
#tfbfi and #btfbfi are owned by another MixedBilinearForm. */
|
||||
/** @brief Indicates the BilinearFormIntegrator%s stored in #dom, #bdr, and
|
||||
#skt are owned by another MixedBilinearForm. */
|
||||
int extern_bfs;
|
||||
|
||||
/// Domain integrators.
|
||||
Array<BilinearFormIntegrator*> dbfi;
|
||||
|
||||
Array<BilinearFormIntegrator*> dom;
|
||||
/// Boundary integrators.
|
||||
Array<BilinearFormIntegrator*> bbfi;
|
||||
Array<Array<int>*> bbfi_marker;///< Entries are not owned.
|
||||
|
||||
Array<BilinearFormIntegrator*> bdr;
|
||||
/// Trace face (skeleton) integrators.
|
||||
Array<BilinearFormIntegrator*> tfbfi;
|
||||
|
||||
/// Boundary trace face (skeleton) integrators.
|
||||
Array<BilinearFormIntegrator*> btfbfi;
|
||||
Array<Array<int>*> btfbfi_marker;///< Entries are not owned.
|
||||
|
||||
DenseMatrix elemmat;
|
||||
Array<int> trial_vdofs, test_vdofs;
|
||||
Array<BilinearFormIntegrator*> skt;
|
||||
|
||||
private:
|
||||
/// Copy construction is not supported; body is undefined.
|
||||
@@ -636,10 +586,6 @@ public:
|
||||
/// Adds a boundary integrator. Assumes ownership of @a bfi.
|
||||
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi);
|
||||
|
||||
/// Adds a boundary integrator. Assumes ownership of @a bfi.
|
||||
void AddBoundaryIntegrator (BilinearFormIntegrator * bfi,
|
||||
Array<int> &bdr_marker);
|
||||
|
||||
/** @brief Add a trace face integrator. Assumes ownership of @a bfi.
|
||||
|
||||
This type of integrator assembles terms over all faces of the mesh using
|
||||
@@ -647,32 +593,14 @@ public:
|
||||
test space. */
|
||||
void AddTraceFaceIntegrator(BilinearFormIntegrator *bfi);
|
||||
|
||||
/// Adds a boundary trace face integrator. Assumes ownership of @a bfi.
|
||||
void AddBdrTraceFaceIntegrator (BilinearFormIntegrator * bfi);
|
||||
|
||||
/// Adds a boundary trace face integrator. Assumes ownership of @a bfi.
|
||||
void AddBdrTraceFaceIntegrator (BilinearFormIntegrator * bfi,
|
||||
Array<int> &bdr_marker);
|
||||
|
||||
/// Access all integrators added with AddDomainIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetDBFI() { return &dbfi; }
|
||||
Array<BilinearFormIntegrator*> *GetDBFI() { return &dom; }
|
||||
|
||||
/// Access all integrators added with AddBoundaryIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetBBFI() { return &bbfi; }
|
||||
/** @brief Access all boundary markers added with AddBoundaryIntegrator().
|
||||
If no marker was specified when the integrator was added, the
|
||||
corresponding pointer (to Array<int>) will be NULL. */
|
||||
Array<Array<int>*> *GetBBFI_Marker() { return &bbfi_marker; }
|
||||
Array<BilinearFormIntegrator*> *GetBBFI() { return &bdr; }
|
||||
|
||||
/// Access all integrators added with AddTraceFaceIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetTFBFI() { return &tfbfi; }
|
||||
|
||||
/// Access all integrators added with AddBdrTraceFaceIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetBTFBFI() { return &btfbfi; }
|
||||
/** @brief Access all boundary markers added with AddBdrTraceFaceIntegrator().
|
||||
If no marker was specified when the integrator was added, the
|
||||
corresponding pointer (to Array<int>) will be NULL. */
|
||||
Array<Array<int>*> *GetBTFBFI_Marker() { return &btfbfi_marker; }
|
||||
Array<BilinearFormIntegrator*> *GetTFBFI() { return &skt; }
|
||||
|
||||
void operator=(const double a) { *mat = a; }
|
||||
|
||||
@@ -685,59 +613,13 @@ public:
|
||||
MixedBilinearForm becomes an operator on the conforming FE spaces. */
|
||||
void ConformingAssemble();
|
||||
|
||||
/// Compute the element matrix of the given element
|
||||
void ComputeElementMatrix(int i, DenseMatrix &elmat);
|
||||
|
||||
/// Compute the boundary element matrix of the given boundary element
|
||||
void ComputeBdrElementMatrix(int i, DenseMatrix &elmat);
|
||||
|
||||
/// Assemble the given element matrix
|
||||
/** The element matrix @a elmat is assembled for the element @a i, i.e.
|
||||
added to the system matrix. The flag @a skip_zeros skips the zero
|
||||
elements of the matrix, unless they are breaking the symmetry of
|
||||
the system matrix.
|
||||
*/
|
||||
void AssembleElementMatrix(int i, const DenseMatrix &elmat,
|
||||
int skip_zeros = 1);
|
||||
|
||||
/// Assemble the given element matrix
|
||||
/** The element matrix @a elmat is assembled for the element @a i, i.e.
|
||||
added to the system matrix. The vdofs of the element are returned
|
||||
in @a trial_vdofs and @a test_vdofs. The flag @a skip_zeros skips
|
||||
the zero elements of the matrix, unless they are breaking the symmetry
|
||||
of the system matrix.
|
||||
*/
|
||||
void AssembleElementMatrix(int i, const DenseMatrix &elmat,
|
||||
Array<int> &trial_vdofs, Array<int> &test_vdofs,
|
||||
int skip_zeros = 1);
|
||||
|
||||
/// Assemble the given boundary element matrix
|
||||
/** The boundary element matrix @a elmat is assembled for the boundary
|
||||
element @a i, i.e. added to the system matrix. The flag @a skip_zeros
|
||||
skips the zero elements of the matrix, unless they are breaking the
|
||||
symmetry of the system matrix.
|
||||
*/
|
||||
void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat,
|
||||
int skip_zeros = 1);
|
||||
|
||||
/// Assemble the given boundary element matrix
|
||||
/** The boundary element matrix @a elmat is assembled for the boundary
|
||||
element @a i, i.e. added to the system matrix. The vdofs of the element
|
||||
are returned in @a trial_vdofs and @a test_vdofs. The flag @a skip_zeros
|
||||
skips the zero elements of the matrix, unless they are breaking the
|
||||
symmetry of the system matrix.
|
||||
*/
|
||||
void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat,
|
||||
Array<int> &trial_vdofs, Array<int> &test_vdofs,
|
||||
int skip_zeros = 1);
|
||||
|
||||
void EliminateTrialDofs(const Array<int> &bdr_attr_is_ess,
|
||||
void EliminateTrialDofs(Array<int> &bdr_attr_is_ess,
|
||||
const Vector &sol, Vector &rhs);
|
||||
|
||||
void EliminateEssentialBCFromTrialDofs(const Array<int> &marked_vdofs,
|
||||
void EliminateEssentialBCFromTrialDofs(Array<int> &marked_vdofs,
|
||||
const Vector &sol, Vector &rhs);
|
||||
|
||||
virtual void EliminateTestDofs(const Array<int> &bdr_attr_is_ess);
|
||||
virtual void EliminateTestDofs(Array<int> &bdr_attr_is_ess);
|
||||
|
||||
void Update();
|
||||
|
||||
@@ -802,7 +684,7 @@ public:
|
||||
{ AddTraceFaceIntegrator(di); }
|
||||
|
||||
/// Access all interpolators added with AddDomainInterpolator().
|
||||
Array<BilinearFormIntegrator*> *GetDI() { return &dbfi; }
|
||||
Array<BilinearFormIntegrator*> *GetDI() { return &dom; }
|
||||
|
||||
/** @brief Construct the internal matrix representation of the discrete
|
||||
linear operator. */
|
||||
|
||||
+135
-50
@@ -36,18 +36,16 @@ const Operator *BilinearFormExtension::GetRestriction() const
|
||||
|
||||
|
||||
// Data and methods for partially-assembled bilinear forms
|
||||
PABilinearFormExtension::PABilinearFormExtension(BilinearForm *form)
|
||||
: BilinearFormExtension(form),
|
||||
trialFes(a->FESpace()), testFes(a->FESpace())
|
||||
PABilinearFormExtension::PABilinearFormExtension(BilinearForm *form) :
|
||||
BilinearFormExtension(form),
|
||||
trialFes(a->FESpace()), testFes(a->FESpace()),
|
||||
localX(trialFes->GetNE() * trialFes->GetFE(0)->GetDof() * trialFes->GetVDim()),
|
||||
localY( testFes->GetNE() * testFes->GetFE(0)->GetDof() * testFes->GetVDim()),
|
||||
elem_restrict(new ElemRestriction(*a->FESpace())) { }
|
||||
|
||||
PABilinearFormExtension::~PABilinearFormExtension()
|
||||
{
|
||||
elem_restrict_lex = trialFes->GetElementRestriction(
|
||||
ElementDofOrdering::LEXICOGRAPHIC);
|
||||
if (elem_restrict_lex)
|
||||
{
|
||||
localX.SetSize(elem_restrict_lex->Height(), Device::GetMemoryType());
|
||||
localY.SetSize(elem_restrict_lex->Height(), Device::GetMemoryType());
|
||||
localY.UseDevice(true); // ensure 'localY = 0.0' is done on device
|
||||
}
|
||||
delete elem_restrict;
|
||||
}
|
||||
|
||||
void PABilinearFormExtension::Assemble()
|
||||
@@ -56,7 +54,7 @@ void PABilinearFormExtension::Assemble()
|
||||
const int integratorCount = integrators.Size();
|
||||
for (int i = 0; i < integratorCount; ++i)
|
||||
{
|
||||
integrators[i]->AssemblePA(*a->FESpace());
|
||||
integrators[i]->Assemble(*a->FESpace());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,13 +64,12 @@ void PABilinearFormExtension::Update()
|
||||
height = width = fes->GetVSize();
|
||||
trialFes = fes;
|
||||
testFes = fes;
|
||||
elem_restrict_lex = trialFes->GetElementRestriction(
|
||||
ElementDofOrdering::LEXICOGRAPHIC);
|
||||
if (elem_restrict_lex)
|
||||
{
|
||||
localX.SetSize(elem_restrict_lex->Height());
|
||||
localY.SetSize(elem_restrict_lex->Height());
|
||||
}
|
||||
localX.SetSize(trialFes->GetNE() * trialFes->GetFE(0)->GetDof() *
|
||||
trialFes->GetVDim());
|
||||
localY.SetSize(testFes->GetNE() * testFes->GetFE(0)->GetDof() *
|
||||
testFes->GetVDim());
|
||||
delete elem_restrict;
|
||||
elem_restrict = new ElemRestriction(*fes);
|
||||
}
|
||||
|
||||
void PABilinearFormExtension::FormSystemMatrix(const Array<int> &ess_tdof_list,
|
||||
@@ -100,52 +97,140 @@ void PABilinearFormExtension::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
|
||||
|
||||
elem_restrict->Mult(x, localX);
|
||||
localY = 0.0;
|
||||
const int iSz = integrators.Size();
|
||||
if (elem_restrict_lex)
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
elem_restrict_lex->Mult(x, localX);
|
||||
localY = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
integrators[i]->AddMultPA(localX, localY);
|
||||
}
|
||||
elem_restrict_lex->MultTranspose(localY, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
y.UseDevice(true); // typically this is a large vector, so store on device
|
||||
y = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
integrators[i]->AddMultPA(x, y);
|
||||
}
|
||||
integrators[i]->MultAssembled(localX, localY);
|
||||
}
|
||||
elem_restrict->MultTranspose(localY, y);
|
||||
}
|
||||
|
||||
void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
|
||||
{
|
||||
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
|
||||
elem_restrict->Mult(x, localX);
|
||||
localY = 0.0;
|
||||
const int iSz = integrators.Size();
|
||||
if (elem_restrict_lex)
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
elem_restrict_lex->Mult(x, localX);
|
||||
localY = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
integrators[i]->AddMultTransposePA(localX, localY);
|
||||
}
|
||||
elem_restrict_lex->MultTranspose(localY, y);
|
||||
integrators[i]->MultAssembledTranspose(localX, localY);
|
||||
}
|
||||
else
|
||||
elem_restrict->MultTranspose(localY, y);
|
||||
}
|
||||
|
||||
|
||||
ElemRestriction::ElemRestriction(const FiniteElementSpace &f)
|
||||
: fes(f),
|
||||
ne(fes.GetNE()),
|
||||
vdim(fes.GetVDim()),
|
||||
byvdim(fes.GetOrdering() == Ordering::byVDIM),
|
||||
ndofs(fes.GetNDofs()),
|
||||
dof(fes.GetFE(0)->GetDof()),
|
||||
nedofs(ne*dof),
|
||||
offsets(ndofs+1),
|
||||
indices(ne*dof)
|
||||
{
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
y.UseDevice(true);
|
||||
y = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
const FiniteElement *fe = fes.GetFE(e);
|
||||
const TensorBasisElement* el =
|
||||
dynamic_cast<const TensorBasisElement*>(fe);
|
||||
if (el) { continue; }
|
||||
mfem_error("Finite element not supported with partial assembly");
|
||||
}
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
const TensorBasisElement* el = dynamic_cast<const TensorBasisElement*>(fe);
|
||||
const Array<int> &dof_map = el->GetDofMap();
|
||||
const bool dof_map_is_identity = (dof_map.Size()==0);
|
||||
const Table& e2dTable = fes.GetElementToDofTable();
|
||||
const int* elementMap = e2dTable.GetJ();
|
||||
// We'll be keeping a count of how many local nodes point to its global dof
|
||||
for (int i = 0; i <= ndofs; ++i)
|
||||
{
|
||||
offsets[i] = 0;
|
||||
}
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
for (int d = 0; d < dof; ++d)
|
||||
{
|
||||
integrators[i]->AddMultTransposePA(x, y);
|
||||
const int gid = elementMap[dof*e + d];
|
||||
++offsets[gid + 1];
|
||||
}
|
||||
}
|
||||
// Aggregate to find offsets for each global dof
|
||||
for (int i = 1; i <= ndofs; ++i)
|
||||
{
|
||||
offsets[i] += offsets[i - 1];
|
||||
}
|
||||
// For each global dof, fill in all local nodes that point to it
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
for (int d = 0; d < dof; ++d)
|
||||
{
|
||||
const int did = dof_map_is_identity?d:dof_map[d];
|
||||
const int gid = elementMap[dof*e + did];
|
||||
const int lid = dof*e + d;
|
||||
indices[offsets[gid]++] = lid;
|
||||
}
|
||||
}
|
||||
// We shifted the offsets vector by 1 by using it as a counter
|
||||
// Now we shift it back.
|
||||
for (int i = ndofs; i > 0; --i)
|
||||
{
|
||||
offsets[i] = offsets[i - 1];
|
||||
}
|
||||
offsets[0] = 0;
|
||||
}
|
||||
|
||||
void ElemRestriction::Mult(const Vector& x, Vector& y) const
|
||||
{
|
||||
const int vd = vdim;
|
||||
const bool t = byvdim;
|
||||
const DeviceArray d_offsets(offsets, ndofs+1);
|
||||
const DeviceArray d_indices(indices, nedofs);
|
||||
const DeviceMatrix d_x(x, t?vd:ndofs, t?ndofs:vd);
|
||||
DeviceMatrix d_y(y, t?vd:nedofs, t?nedofs:vd);
|
||||
MFEM_FORALL(i, ndofs,
|
||||
{
|
||||
const int offset = d_offsets[i];
|
||||
const int nextOffset = d_offsets[i+1];
|
||||
for (int c = 0; c < vd; ++c)
|
||||
{
|
||||
const double dofValue = d_x(t?c:i,t?i:c);
|
||||
for (int j = offset; j < nextOffset; ++j)
|
||||
{
|
||||
const int idx_j = d_indices[j];
|
||||
d_y(t?c:idx_j,t?idx_j:c) = dofValue;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ElemRestriction::MultTranspose(const Vector& x, Vector& y) const
|
||||
{
|
||||
const int vd = vdim;
|
||||
const bool t = byvdim;
|
||||
const DeviceArray d_offsets(offsets, ndofs+1);
|
||||
const DeviceArray d_indices(indices, nedofs);
|
||||
const DeviceMatrix d_x(x, t?vd:nedofs, t?nedofs:vd);
|
||||
DeviceMatrix d_y(y, t?vd:ndofs, t?ndofs:vd);
|
||||
MFEM_FORALL(i, ndofs,
|
||||
{
|
||||
const int offset = d_offsets[i];
|
||||
const int nextOffset = d_offsets[i + 1];
|
||||
for (int c = 0; c < vd; ++c)
|
||||
{
|
||||
double dofValue = 0;
|
||||
for (int j = offset; j < nextOffset; ++j)
|
||||
{
|
||||
const int idx_j = d_indices[j];
|
||||
dofValue += d_x(t?c:idx_j,t?idx_j:c);
|
||||
}
|
||||
d_y(t?c:i,t?i:c) = dofValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+23
-11
@@ -14,16 +14,32 @@
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "fespace.hpp"
|
||||
#include "../general/device.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
class BilinearForm;
|
||||
|
||||
/// Element restriction operator
|
||||
class ElemRestriction: public Operator
|
||||
{
|
||||
public:
|
||||
const FiniteElementSpace &fes;
|
||||
const int ne;
|
||||
const int vdim;
|
||||
const bool byvdim;
|
||||
const int ndofs;
|
||||
const int dof;
|
||||
const int nedofs;
|
||||
Array<int> offsets;
|
||||
Array<int> indices;
|
||||
public:
|
||||
ElemRestriction(const FiniteElementSpace&);
|
||||
void Mult(const Vector &x, Vector &y) const;
|
||||
void MultTranspose(const Vector &x, Vector &y) const;
|
||||
};
|
||||
|
||||
|
||||
/** @brief Class extending the BilinearForm class to support the different
|
||||
AssemblyLevel%s. */
|
||||
class BilinearFormExtension : public Operator
|
||||
{
|
||||
protected:
|
||||
@@ -32,9 +48,6 @@ protected:
|
||||
public:
|
||||
BilinearFormExtension(BilinearForm *form);
|
||||
|
||||
virtual MemoryClass GetMemoryClass() const
|
||||
{ return Device::GetMemoryClass(); }
|
||||
|
||||
/// Get the finite element space prolongation matrix
|
||||
virtual const Operator *GetProlongation() const;
|
||||
|
||||
@@ -67,7 +80,6 @@ public:
|
||||
int copy_interior = 0) {}
|
||||
void Mult(const Vector &x, Vector &y) const {}
|
||||
void MultTranspose(const Vector &x, Vector &y) const {}
|
||||
void Update() {}
|
||||
~FABilinearFormExtension() {}
|
||||
};
|
||||
|
||||
@@ -87,7 +99,6 @@ public:
|
||||
int copy_interior = 0) {}
|
||||
void Mult(const Vector &x, Vector &y) const {}
|
||||
void MultTranspose(const Vector &x, Vector &y) const {}
|
||||
void Update() {}
|
||||
~EABilinearFormExtension() {}
|
||||
};
|
||||
|
||||
@@ -95,9 +106,9 @@ public:
|
||||
class PABilinearFormExtension : public BilinearFormExtension
|
||||
{
|
||||
protected:
|
||||
const FiniteElementSpace *trialFes, *testFes; // Not owned
|
||||
const FiniteElementSpace *trialFes, *testFes;
|
||||
mutable Vector localX, localY;
|
||||
const Operator *elem_restrict_lex; // Not owned
|
||||
ElemRestriction *elem_restrict;
|
||||
|
||||
public:
|
||||
PABilinearFormExtension(BilinearForm*);
|
||||
@@ -112,6 +123,8 @@ public:
|
||||
void Mult(const Vector &x, Vector &y) const;
|
||||
void MultTranspose(const Vector &x, Vector &y) const;
|
||||
void Update();
|
||||
|
||||
~PABilinearFormExtension();
|
||||
};
|
||||
|
||||
/// Data and methods for matrix-free bilinear forms
|
||||
@@ -130,7 +143,6 @@ public:
|
||||
int copy_interior = 0) {}
|
||||
void Mult(const Vector &x, Vector &y) const {}
|
||||
void MultTranspose(const Vector &x, Vector &y) const {}
|
||||
void Update() {}
|
||||
~MFBilinearFormExtension() {}
|
||||
};
|
||||
|
||||
|
||||
+109
-55
@@ -19,20 +19,19 @@ using namespace std;
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&)
|
||||
void BilinearFormIntegrator::Assemble(const FiniteElementSpace&)
|
||||
{
|
||||
mfem_error ("BilinearFormIntegrator::Assemble (...)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AddMultPA(const Vector &, Vector &) const
|
||||
void BilinearFormIntegrator::MultAssembled(Vector&, Vector&)
|
||||
{
|
||||
mfem_error ("BilinearFormIntegrator::MultAssembled (...)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AddMultTransposePA(const Vector &, Vector &) const
|
||||
void BilinearFormIntegrator::MultAssembledTranspose(Vector&, Vector&)
|
||||
{
|
||||
mfem_error ("BilinearFormIntegrator::MultAssembledTranspose (...)\n"
|
||||
" is not implemented for this class.");
|
||||
@@ -379,7 +378,6 @@ void MixedScalarVectorIntegrator::AssembleElementMatrix2(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DiffusionIntegrator::AssembleElementMatrix
|
||||
( const FiniteElement &el, ElementTransformation &Trans,
|
||||
DenseMatrix &elmat )
|
||||
@@ -399,7 +397,36 @@ void DiffusionIntegrator::AssembleElementMatrix
|
||||
#endif
|
||||
elmat.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
|
||||
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 if (el.Space() == FunctionSpace::SBPk)
|
||||
{
|
||||
ir = &el.GetNodes(); // SBP elements have collocated quadrature nodes
|
||||
// and DOFs, weights are included in element
|
||||
// construction so complete integration rule is
|
||||
// defined by the element's `Nodes`
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &IntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
@@ -455,7 +482,28 @@ void DiffusionIntegrator::AssembleElementMatrix2(
|
||||
#endif
|
||||
elmat.SetSize(te_nd, tr_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe);
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order;
|
||||
if (trial_fe.Space() == FunctionSpace::Pk)
|
||||
{
|
||||
order = trial_fe.GetOrder() + test_fe.GetOrder() - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
order = trial_fe.GetOrder() + test_fe.GetOrder() + dim - 1;
|
||||
}
|
||||
|
||||
if (trial_fe.Space() == FunctionSpace::rQk)
|
||||
{
|
||||
ir = &RefinedIntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
@@ -510,7 +558,29 @@ void DiffusionIntegrator::AssembleElementVector(
|
||||
|
||||
elvect.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
elvect = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
@@ -670,27 +740,6 @@ double DiffusionIntegrator::ComputeFluxEnergy
|
||||
return energy;
|
||||
}
|
||||
|
||||
const IntegrationRule &DiffusionIntegrator::GetRule(
|
||||
const FiniteElement &trial_fe, const FiniteElement &test_fe)
|
||||
{
|
||||
int order;
|
||||
if (trial_fe.Space() == FunctionSpace::Pk)
|
||||
{
|
||||
order = trial_fe.GetOrder() + test_fe.GetOrder() - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// order = 2*el.GetOrder() - 2; // <-- this seems to work fine too
|
||||
order = trial_fe.GetOrder() + test_fe.GetOrder() + trial_fe.GetDim() - 1;
|
||||
}
|
||||
|
||||
if (trial_fe.Space() == FunctionSpace::rQk)
|
||||
{
|
||||
return RefinedIntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
return IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
|
||||
void MassIntegrator::AssembleElementMatrix
|
||||
( const FiniteElement &el, ElementTransformation &Trans,
|
||||
@@ -706,7 +755,21 @@ void MassIntegrator::AssembleElementMatrix
|
||||
elmat.SetSize(nd);
|
||||
shape.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
// int order = 2 * el.GetOrder();
|
||||
int order = 2 * el.GetOrder() + Trans.OrderW();
|
||||
|
||||
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++)
|
||||
@@ -741,8 +804,13 @@ void MassIntegrator::AssembleElementMatrix2(
|
||||
shape.SetSize(tr_nd);
|
||||
te_shape.SetSize(te_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule :
|
||||
&GetRule(trial_fe, test_fe, Trans);
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW();
|
||||
|
||||
ir = &IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
@@ -763,20 +831,6 @@ void MassIntegrator::AssembleElementMatrix2(
|
||||
}
|
||||
}
|
||||
|
||||
const IntegrationRule &MassIntegrator::GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans)
|
||||
{
|
||||
// int order = trial_fe.GetOrder() + test_fe.GetOrder();
|
||||
const int order = trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW();
|
||||
|
||||
if (trial_fe.Space() == FunctionSpace::rQk)
|
||||
{
|
||||
return RefinedIntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
return IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
|
||||
void BoundaryMassIntegrator::AssembleFaceMatrix(
|
||||
const FiniteElement &el1, const FiniteElement &el2,
|
||||
@@ -848,7 +902,7 @@ void ConvectionIntegrator::AssembleElementMatrix(
|
||||
ir = &IntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
|
||||
Q->Eval(Q_ir, Trans, *ir);
|
||||
Q.Eval(Q_ir, Trans, *ir);
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
@@ -889,7 +943,7 @@ void GroupConvectionIntegrator::AssembleElementMatrix(
|
||||
ir = &IntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
|
||||
Q->Eval(Q_nodal, Trans, el.GetNodes()); // sets the size of Q_nodal
|
||||
Q.Eval(Q_nodal, Trans, el.GetNodes()); // sets the size of Q_nodal
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
@@ -1370,7 +1424,7 @@ void DerivativeIntegrator::AssembleElementMatrix2 (
|
||||
dshapedxi(l) = dshapedxt(l,xi);
|
||||
}
|
||||
|
||||
shape *= Q->Eval(Trans,ip) * det * ip.weight;
|
||||
shape *= Q.Eval(Trans,ip) * det * ip.weight;
|
||||
AddMultVWt (shape, dshapedxi, elmat);
|
||||
}
|
||||
}
|
||||
@@ -3216,7 +3270,7 @@ ScalarProductInterpolator::AssembleElementMatrix2(const FiniteElement &dom_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
internal::ShapeCoefficient dom_shape_coeff(*Q, dom_fe);
|
||||
internal::ShapeCoefficient dom_shape_coeff(Q, dom_fe);
|
||||
|
||||
elmat.SetSize(ran_fe.GetDof(),dom_fe.GetDof());
|
||||
|
||||
@@ -3251,7 +3305,7 @@ ScalarVectorProductInterpolator::AssembleElementMatrix2(
|
||||
}
|
||||
};
|
||||
|
||||
VShapeCoefficient dom_shape_coeff(*Q, dom_fe, Trans.GetSpaceDim());
|
||||
VShapeCoefficient dom_shape_coeff(Q, dom_fe, Trans.GetSpaceDim());
|
||||
|
||||
elmat.SetSize(ran_fe.GetDof(),dom_fe.GetDof());
|
||||
|
||||
@@ -3289,7 +3343,7 @@ VectorScalarProductInterpolator::AssembleElementMatrix2(
|
||||
}
|
||||
};
|
||||
|
||||
VecShapeCoefficient dom_shape_coeff(*VQ, dom_fe);
|
||||
VecShapeCoefficient dom_shape_coeff(VQ, dom_fe);
|
||||
|
||||
elmat.SetSize(ran_fe.GetDof(),dom_fe.GetDof());
|
||||
|
||||
@@ -3336,11 +3390,11 @@ VectorCrossProductInterpolator::AssembleElementMatrix2(
|
||||
}
|
||||
};
|
||||
|
||||
VCrossVShapeCoefficient dom_shape_coeff(*VQ, dom_fe);
|
||||
VCrossVShapeCoefficient dom_shape_coeff(VQ, dom_fe);
|
||||
|
||||
if (ran_fe.GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
elmat.SetSize(ran_fe.GetDof()*VQ->GetVDim(),dom_fe.GetDof());
|
||||
elmat.SetSize(ran_fe.GetDof()*VQ.GetVDim(),dom_fe.GetDof());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3389,7 +3443,7 @@ VectorInnerProductInterpolator::AssembleElementMatrix2(
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
internal::VDotVShapeCoefficient dom_shape_coeff(*VQ, dom_fe);
|
||||
internal::VDotVShapeCoefficient dom_shape_coeff(VQ, dom_fe);
|
||||
|
||||
elmat.SetSize(ran_fe.GetDof(),dom_fe.GetDof());
|
||||
|
||||
|
||||
+63
-128
@@ -15,6 +15,7 @@
|
||||
#include "../config/config.hpp"
|
||||
#include "nonlininteg.hpp"
|
||||
#include "fespace.hpp"
|
||||
#include "bilininteg_ext.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -22,45 +23,19 @@ namespace mfem
|
||||
/// Abstract base class BilinearFormIntegrator
|
||||
class BilinearFormIntegrator : public NonlinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
BilinearFormIntegrator(const IntegrationRule *ir = NULL)
|
||||
: NonlinearFormIntegrator(ir) { }
|
||||
public:
|
||||
BilinearFormIntegrator(const IntegrationRule *ir = NULL) :
|
||||
NonlinearFormIntegrator(ir) { }
|
||||
|
||||
public:
|
||||
// TODO: add support for other assembly levels (in addition to PA) and their
|
||||
// actions.
|
||||
|
||||
// TODO: for mixed meshes the quadrature rules to be used by methods like
|
||||
// AssemblePA() can be given as a QuadratureSpace, e.g. using a new method:
|
||||
// SetQuadratureSpace().
|
||||
|
||||
// TODO: the methods for the various assembly levels make sense even in the
|
||||
// base class NonlinearFormIntegrator, except that not all assembly levels
|
||||
// make sense for the action of the nonlinear operator (but they all make
|
||||
// sense for its Jacobian).
|
||||
|
||||
/// Method defining partial assembly.
|
||||
/** The result of the partial assembly is stored internally so that it can be
|
||||
used later in the methods AddMultPA() and AddMultTransposePA(). */
|
||||
virtual void AssemblePA(const FiniteElementSpace &fes);
|
||||
virtual void Assemble(const FiniteElementSpace&);
|
||||
|
||||
/// Method for partially assembled action.
|
||||
/** Perform the action of integrator on the input @a x and add the result to
|
||||
the output @a y. Both @a x and @a y are E-vectors, i.e. they represent
|
||||
the element-wise discontinuous version of the FE space.
|
||||
|
||||
This method can be called only after the method AssemblePA() has been
|
||||
called. */
|
||||
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
||||
virtual void MultAssembled(Vector&, Vector&);
|
||||
|
||||
/// Method for partially assembled transposed action.
|
||||
/** Perform the transpose action of integrator on the input @a x and add the
|
||||
result to the output @a y. Both @a x and @a y are E-vectors, i.e. they
|
||||
represent the element-wise discontinuous version of the FE space.
|
||||
|
||||
This method can be called only after the method AssemblePA() has been
|
||||
called. */
|
||||
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
|
||||
virtual void MultAssembledTranspose(Vector&, Vector&);
|
||||
|
||||
/// Given a particular Finite Element computes the element matrix elmat.
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
@@ -309,10 +284,10 @@ protected:
|
||||
Vector & shape)
|
||||
{ trial_fe.CalcPhysShape(Trans, shape); }
|
||||
|
||||
Coefficient *Q;
|
||||
|
||||
private:
|
||||
|
||||
Coefficient *Q;
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector test_shape;
|
||||
Vector trial_shape;
|
||||
@@ -383,13 +358,13 @@ protected:
|
||||
DenseMatrix & shape)
|
||||
{ trial_fe.CalcVShape(Trans, shape); }
|
||||
|
||||
private:
|
||||
|
||||
Coefficient *Q;
|
||||
VectorCoefficient *VQ;
|
||||
VectorCoefficient *DQ;
|
||||
MatrixCoefficient *MQ;
|
||||
|
||||
private:
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector V;
|
||||
Vector D;
|
||||
@@ -464,12 +439,12 @@ protected:
|
||||
Vector & shape)
|
||||
{ scalar_fe.CalcPhysShape(Trans, shape); }
|
||||
|
||||
private:
|
||||
|
||||
VectorCoefficient *VQ;
|
||||
bool transpose;
|
||||
bool cross_2d; // In 2D use a cross product rather than a dot product
|
||||
|
||||
private:
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector V;
|
||||
DenseMatrix vshape;
|
||||
@@ -1662,34 +1637,27 @@ protected:
|
||||
can be a scalar or a matrix coefficient. */
|
||||
class DiffusionIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
MatrixCoefficient *MQ;
|
||||
|
||||
private:
|
||||
Vector vec, pointflux, shape;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
DenseMatrix dshape, dshapedxt, invdfdx, mq;
|
||||
DenseMatrix te_dshape, te_dshapedxt;
|
||||
#endif
|
||||
|
||||
Coefficient *Q;
|
||||
MatrixCoefficient *MQ;
|
||||
// PA extension
|
||||
const DofToQuad *maps; ///< Not owned
|
||||
const GeometricFactors *geom; ///< Not owned
|
||||
DofToQuad *maps;
|
||||
GeometryExtension *geom;
|
||||
int dim, ne, dofs1D, quad1D;
|
||||
Vector pa_data;
|
||||
|
||||
public:
|
||||
/// Construct a diffusion integrator with coefficient Q = 1
|
||||
DiffusionIntegrator() { Q = NULL; MQ = NULL; maps = NULL; geom = NULL; }
|
||||
|
||||
/// Construct a diffusion integrator with a scalar coefficient q
|
||||
DiffusionIntegrator(Coefficient &q)
|
||||
: Q(&q) { MQ = NULL; maps = NULL; geom = NULL; }
|
||||
DiffusionIntegrator (Coefficient &q) : Q(&q) { MQ = NULL; maps = NULL; geom = NULL; }
|
||||
|
||||
/// Construct a diffusion integrator with a matrix coefficient q
|
||||
DiffusionIntegrator(MatrixCoefficient &q)
|
||||
: MQ(&q) { Q = NULL; maps = NULL; geom = NULL; }
|
||||
DiffusionIntegrator (MatrixCoefficient &q) : MQ(&q) { Q = NULL; maps = NULL; geom = NULL; }
|
||||
|
||||
/** Given a particular Finite Element
|
||||
computes the element stiffness matrix elmat. */
|
||||
@@ -1717,12 +1685,11 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
Vector &flux, Vector *d_energy = NULL);
|
||||
|
||||
virtual void AssemblePA(const FiniteElementSpace&);
|
||||
/// PA extension
|
||||
virtual void Assemble(const FiniteElementSpace&);
|
||||
virtual void MultAssembled(Vector&, Vector&);
|
||||
|
||||
virtual void AddMultPA(const Vector&, Vector&) const;
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe);
|
||||
virtual ~DiffusionIntegrator();
|
||||
};
|
||||
|
||||
/** Class for local mass matrix assembling a(u,v) := (Q u, v) */
|
||||
@@ -1734,15 +1701,13 @@ protected:
|
||||
#endif
|
||||
Coefficient *Q;
|
||||
// PA extension
|
||||
Vector pa_data;
|
||||
const DofToQuad *maps; ///< Not owned
|
||||
const GeometricFactors *geom; ///< Not owned
|
||||
Vector vec;
|
||||
DofToQuad *maps;
|
||||
GeometryExtension *geom;
|
||||
int dim, ne, nq, dofs1D, quad1D;
|
||||
|
||||
public:
|
||||
MassIntegrator(const IntegrationRule *ir = NULL)
|
||||
: BilinearFormIntegrator(ir) { Q = NULL; maps = NULL; geom = NULL; }
|
||||
|
||||
/// Construct a mass integrator with coefficient q
|
||||
MassIntegrator(Coefficient &q, const IntegrationRule *ir = NULL)
|
||||
: BilinearFormIntegrator(ir), Q(&q) { maps = NULL; geom = NULL; }
|
||||
@@ -1756,14 +1721,11 @@ public:
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
/// PA extension
|
||||
virtual void Assemble(const FiniteElementSpace&);
|
||||
virtual void MultAssembled(Vector&, Vector&);
|
||||
|
||||
virtual void AssemblePA(const FiniteElementSpace&);
|
||||
|
||||
virtual void AddMultPA(const Vector&, Vector&) const;
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans);
|
||||
virtual ~MassIntegrator();
|
||||
};
|
||||
|
||||
class BoundaryMassIntegrator : public MassIntegrator
|
||||
@@ -1782,19 +1744,17 @@ public:
|
||||
/// alpha (q . grad u, v)
|
||||
class ConvectionIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
VectorCoefficient *Q;
|
||||
double alpha;
|
||||
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
DenseMatrix dshape, adjJ, Q_ir;
|
||||
Vector shape, vec2, BdFidxT;
|
||||
#endif
|
||||
VectorCoefficient &Q;
|
||||
double alpha;
|
||||
|
||||
public:
|
||||
ConvectionIntegrator(VectorCoefficient &q, double a = 1.0)
|
||||
: Q(&q) { alpha = a; }
|
||||
: Q(q) { alpha = a; }
|
||||
virtual void AssembleElementMatrix(const FiniteElement &,
|
||||
ElementTransformation &,
|
||||
DenseMatrix &);
|
||||
@@ -1803,17 +1763,15 @@ public:
|
||||
/// alpha (q . grad u, v) using the "group" FE discretization
|
||||
class GroupConvectionIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
VectorCoefficient *Q;
|
||||
double alpha;
|
||||
|
||||
private:
|
||||
DenseMatrix dshape, adjJ, Q_nodal, grad;
|
||||
Vector shape;
|
||||
VectorCoefficient &Q;
|
||||
double alpha;
|
||||
|
||||
public:
|
||||
GroupConvectionIntegrator(VectorCoefficient &q, double a = 1.0)
|
||||
: Q(&q) { alpha = a; }
|
||||
: Q(q) { alpha = a; }
|
||||
virtual void AssembleElementMatrix(const FiniteElement &,
|
||||
ElementTransformation &,
|
||||
DenseMatrix &);
|
||||
@@ -1829,17 +1787,16 @@ private:
|
||||
Vector shape, te_shape, vec;
|
||||
DenseMatrix partelmat;
|
||||
DenseMatrix mcoeff;
|
||||
int Q_order;
|
||||
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
VectorCoefficient *VQ;
|
||||
MatrixCoefficient *MQ;
|
||||
|
||||
int Q_order;
|
||||
|
||||
public:
|
||||
/// Construct an integrator with coefficient 1.0
|
||||
VectorMassIntegrator()
|
||||
: vdim(-1), Q_order(0), Q(NULL), VQ(NULL), MQ(NULL) { }
|
||||
: vdim(-1), Q(NULL), VQ(NULL), MQ(NULL), Q_order(0) { }
|
||||
/** Construct an integrator with scalar coefficient q.
|
||||
If possible, save memory by using a scalar integrator since
|
||||
the resulting matrix is block diagonal with the same diagonal
|
||||
@@ -1878,14 +1835,11 @@ public:
|
||||
does NOT depend on the ElementTransformation Trans. */
|
||||
class VectorFEDivergenceIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
|
||||
private:
|
||||
Coefficient *Q;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector divshape, shape;
|
||||
#endif
|
||||
|
||||
public:
|
||||
VectorFEDivergenceIntegrator() { Q = NULL; }
|
||||
VectorFEDivergenceIntegrator(Coefficient &q) { Q = &q; }
|
||||
@@ -1903,17 +1857,14 @@ public:
|
||||
This is equivalent to a weak divergence of the Nedelec basis functions. */
|
||||
class VectorFEWeakDivergenceIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
|
||||
private:
|
||||
Coefficient *Q;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
DenseMatrix dshape;
|
||||
DenseMatrix dshapedxt;
|
||||
DenseMatrix vshape;
|
||||
DenseMatrix invdfdx;
|
||||
#endif
|
||||
|
||||
public:
|
||||
VectorFEWeakDivergenceIntegrator() { Q = NULL; }
|
||||
VectorFEWeakDivergenceIntegrator(Coefficient &q) { Q = &q; }
|
||||
@@ -1930,16 +1881,13 @@ public:
|
||||
test spaces are switched, assembles the form (u, curl v). */
|
||||
class VectorFECurlIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
|
||||
private:
|
||||
Coefficient *Q;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
DenseMatrix curlshapeTrial;
|
||||
DenseMatrix vshapeTest;
|
||||
DenseMatrix curlshapeTrial_dFT;
|
||||
#endif
|
||||
|
||||
public:
|
||||
VectorFECurlIntegrator() { Q = NULL; }
|
||||
VectorFECurlIntegrator(Coefficient &q) { Q = &q; }
|
||||
@@ -1952,19 +1900,17 @@ public:
|
||||
DenseMatrix &elmat);
|
||||
};
|
||||
|
||||
|
||||
/// Class for integrating (Q D_i(u), v); u and v are scalars
|
||||
class DerivativeIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
Coefficient* Q;
|
||||
|
||||
private:
|
||||
Coefficient & Q;
|
||||
int xi;
|
||||
DenseMatrix dshape, dshapedxt, invdfdx;
|
||||
Vector shape, dshapedxi;
|
||||
|
||||
public:
|
||||
DerivativeIntegrator(Coefficient &q, int i) : Q(&q), xi(i) { }
|
||||
DerivativeIntegrator(Coefficient &q, int i) : Q(q), xi(i) { }
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
@@ -1984,8 +1930,6 @@ private:
|
||||
DenseMatrix curlshape, curlshape_dFt, M;
|
||||
DenseMatrix vshape, projcurl;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
MatrixCoefficient *MQ;
|
||||
|
||||
@@ -2019,8 +1963,6 @@ private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
DenseMatrix dshape_hat, dshape, curlshape, Jadj, grad_hat, grad;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
|
||||
public:
|
||||
@@ -2042,6 +1984,9 @@ public:
|
||||
class VectorFEMassIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
Coefficient *Q;
|
||||
VectorCoefficient *VQ;
|
||||
MatrixCoefficient *MQ;
|
||||
void Init(Coefficient *q, VectorCoefficient *vq, MatrixCoefficient *mq)
|
||||
{ Q = q; VQ = vq; MQ = mq; }
|
||||
|
||||
@@ -2053,11 +1998,6 @@ private:
|
||||
DenseMatrix trial_vshape;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
VectorCoefficient *VQ;
|
||||
MatrixCoefficient *MQ;
|
||||
|
||||
public:
|
||||
VectorFEMassIntegrator() { Init(NULL, NULL, NULL); }
|
||||
VectorFEMassIntegrator(Coefficient *_q) { Init(_q, NULL, NULL); }
|
||||
@@ -2080,10 +2020,9 @@ public:
|
||||
scalar FE space; p is also in a (different) scalar FE space. */
|
||||
class VectorDivergenceIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
private:
|
||||
Coefficient *Q;
|
||||
|
||||
private:
|
||||
Vector shape;
|
||||
Vector divshape;
|
||||
DenseMatrix dshape;
|
||||
@@ -2104,10 +2043,9 @@ public:
|
||||
/// (Q div u, div v) for RT elements
|
||||
class DivDivIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
private:
|
||||
Coefficient *Q;
|
||||
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector divshape;
|
||||
#endif
|
||||
@@ -2129,10 +2067,9 @@ public:
|
||||
diffusion matrix in each diagonal block. */
|
||||
class VectorDiffusionIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
private:
|
||||
Coefficient *Q;
|
||||
|
||||
private:
|
||||
DenseMatrix Jinv;
|
||||
DenseMatrix dshape;
|
||||
DenseMatrix gshape;
|
||||
@@ -2157,11 +2094,10 @@ public:
|
||||
using multiple copies of a scalar FE space. */
|
||||
class ElasticityIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
private:
|
||||
double q_lambda, q_mu;
|
||||
Coefficient *lambda, *mu;
|
||||
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector shape;
|
||||
DenseMatrix dshape, gshape, pelmat;
|
||||
@@ -2218,12 +2154,11 @@ public:
|
||||
points. */
|
||||
class DGTraceIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
private:
|
||||
Coefficient *rho;
|
||||
VectorCoefficient *u;
|
||||
double alpha, beta;
|
||||
|
||||
private:
|
||||
Vector shape1, shape2;
|
||||
|
||||
public:
|
||||
@@ -2510,7 +2445,7 @@ public:
|
||||
class ScalarProductInterpolator : public DiscreteInterpolator
|
||||
{
|
||||
public:
|
||||
ScalarProductInterpolator(Coefficient & sc) : Q(&sc) { }
|
||||
ScalarProductInterpolator(Coefficient & sc) : Q(sc) { }
|
||||
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
||||
const FiniteElement &ran_fe,
|
||||
@@ -2518,7 +2453,7 @@ public:
|
||||
DenseMatrix &elmat);
|
||||
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
Coefficient &Q;
|
||||
};
|
||||
|
||||
/** Interpolator of a scalar coefficient multiplied by a vector field onto
|
||||
@@ -2528,14 +2463,14 @@ class ScalarVectorProductInterpolator : public DiscreteInterpolator
|
||||
{
|
||||
public:
|
||||
ScalarVectorProductInterpolator(Coefficient & sc)
|
||||
: Q(&sc) { }
|
||||
: Q(sc) { }
|
||||
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
||||
const FiniteElement &ran_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
Coefficient &Q;
|
||||
};
|
||||
|
||||
/** Interpolator of a vector coefficient multiplied by a scalar field onto
|
||||
@@ -2545,14 +2480,14 @@ class VectorScalarProductInterpolator : public DiscreteInterpolator
|
||||
{
|
||||
public:
|
||||
VectorScalarProductInterpolator(VectorCoefficient & vc)
|
||||
: VQ(&vc) { }
|
||||
: VQ(vc) { }
|
||||
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
||||
const FiniteElement &ran_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
protected:
|
||||
VectorCoefficient *VQ;
|
||||
VectorCoefficient &VQ;
|
||||
};
|
||||
|
||||
/** Interpolator of the cross product between a vector coefficient and an
|
||||
@@ -2562,14 +2497,14 @@ class VectorCrossProductInterpolator : public DiscreteInterpolator
|
||||
{
|
||||
public:
|
||||
VectorCrossProductInterpolator(VectorCoefficient & vc)
|
||||
: VQ(&vc) { }
|
||||
: VQ(vc) { }
|
||||
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &nd_fe,
|
||||
const FiniteElement &rt_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
protected:
|
||||
VectorCoefficient *VQ;
|
||||
VectorCoefficient &VQ;
|
||||
};
|
||||
|
||||
/** Interpolator of the inner product between a vector coefficient and an
|
||||
@@ -2578,14 +2513,14 @@ protected:
|
||||
class VectorInnerProductInterpolator : public DiscreteInterpolator
|
||||
{
|
||||
public:
|
||||
VectorInnerProductInterpolator(VectorCoefficient & vc) : VQ(&vc) { }
|
||||
VectorInnerProductInterpolator(VectorCoefficient & vc) : VQ(vc) { }
|
||||
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &rt_fe,
|
||||
const FiniteElement &l2_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
protected:
|
||||
VectorCoefficient *VQ;
|
||||
VectorCoefficient &VQ;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
||||
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
||||
// reserved. See file COPYRIGHT for details.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability see http://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU Lesser General Public License (as published by the Free
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
#ifndef MFEM_BILININTEG_EXT
|
||||
#define MFEM_BILININTEG_EXT
|
||||
|
||||
#include "fespace.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// GeometryExtension
|
||||
class GeometryExtension
|
||||
{
|
||||
public:
|
||||
Array<int> eMap;
|
||||
Array<double> nodes;
|
||||
Array<double> X, J, invJ, detJ;
|
||||
static GeometryExtension* Get(const FiniteElementSpace&,
|
||||
const IntegrationRule&);
|
||||
static GeometryExtension* Get(const FiniteElementSpace&,
|
||||
const IntegrationRule&,
|
||||
const Vector&);
|
||||
static void ReorderByVDim(const GridFunction*);
|
||||
static void ReorderByNodes(const GridFunction*);
|
||||
};
|
||||
|
||||
/// DofToQuad
|
||||
class DofToQuad
|
||||
{
|
||||
private:
|
||||
std::string hash;
|
||||
public:
|
||||
~DofToQuad();
|
||||
void operator=(DofToQuad&);
|
||||
void operator=(DofToQuad const&);
|
||||
public:
|
||||
Array<double> W, B, G, Bt, Gt;
|
||||
public:
|
||||
static DofToQuad* Get(const FiniteElementSpace&,
|
||||
const IntegrationRule&,
|
||||
const bool = false);
|
||||
static DofToQuad* Get(const FiniteElementSpace&,
|
||||
const FiniteElementSpace&,
|
||||
const IntegrationRule&,
|
||||
const bool = false);
|
||||
static DofToQuad* Get(const FiniteElement&,
|
||||
const FiniteElement&,
|
||||
const IntegrationRule&,
|
||||
const bool = false);
|
||||
static DofToQuad* GetTensorMaps(const FiniteElement&,
|
||||
const FiniteElement&,
|
||||
const IntegrationRule&,
|
||||
const bool = false);
|
||||
static DofToQuad* GetD2QTensorMaps(const FiniteElement&,
|
||||
const IntegrationRule&,
|
||||
const bool = false);
|
||||
static DofToQuad* GetSimplexMaps(const FiniteElement&,
|
||||
const IntegrationRule&,
|
||||
const bool = false);
|
||||
static DofToQuad* GetSimplexMaps(const FiniteElement&,
|
||||
const FiniteElement&,
|
||||
const IntegrationRule&,
|
||||
const bool = false);
|
||||
static DofToQuad* GetD2QSimplexMaps(const FiniteElement&,
|
||||
const IntegrationRule&,
|
||||
const bool = false);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,801 +0,0 @@
|
||||
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
||||
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
||||
// reserved. See file COPYRIGHT for details.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability see http://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU Lesser General Public License (as published by the Free
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
#include "../general/forall.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// PA Mass Integrator
|
||||
|
||||
// PA Mass Assemble kernel
|
||||
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
// Assuming the same element type
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
if (mesh->GetNE() == 0) { return; }
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
ElementTransformation *T = mesh->GetElementTransformation(0);
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, *T);
|
||||
dim = mesh->Dimension();
|
||||
ne = fes.GetMesh()->GetNE();
|
||||
nq = ir->GetNPoints();
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::COORDINATES |
|
||||
GeometricFactors::JACOBIANS);
|
||||
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
pa_data.SetSize(ne*nq, Device::GetMemoryType());
|
||||
Vector coeff;
|
||||
if (Q == nullptr)
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = 1.0;
|
||||
}
|
||||
else if (ConstantCoefficient* cQ = dynamic_cast<ConstantCoefficient*>(Q))
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = cQ->constant;
|
||||
}
|
||||
else
|
||||
{
|
||||
coeff.SetSize(nq * ne);
|
||||
auto C = Reshape(coeff.Write(), nq, ne);
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
ElementTransformation& T = *fes.GetElementTransformation(e);
|
||||
for (int q = 0; q < nq; ++q)
|
||||
{
|
||||
C(q,e) = Q->Eval(T, ir->IntPoint(q));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim==1) { MFEM_ABORT("Not supported yet... stay tuned!"); }
|
||||
if (dim==2)
|
||||
{
|
||||
const int NE = ne;
|
||||
const int NQ = nq;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
auto w = ir->GetWeights().Read();
|
||||
auto J = Reshape(geom->J.Read(), NQ,2,2,NE);
|
||||
auto C =
|
||||
const_c ? Reshape(coeff.Read(), 1,1) : Reshape(coeff.Read(), NQ,NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J12 = J(q,1,0,e);
|
||||
const double J21 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double detJ = (J11*J22)-(J21*J12);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
v(q,e) = w[q] * coeff * detJ;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (dim==3)
|
||||
{
|
||||
const int NE = ne;
|
||||
const int NQ = nq;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
auto W = ir->GetWeights().Read();
|
||||
auto J = Reshape(geom->J.Read(), NQ,3,3,NE);
|
||||
auto C =
|
||||
const_c ? Reshape(coeff.Read(), 1,1) : Reshape(coeff.Read(), NQ,NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ,NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
const double J11 = J(q,0,0,e), J12 = J(q,0,1,e), J13 = J(q,0,2,e);
|
||||
const double J21 = J(q,1,0,e), J22 = J(q,1,1,e), J23 = J(q,1,2,e);
|
||||
const double J31 = J(q,2,0,e), J32 = J(q,2,1,e), J33 = J(q,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
v(q,e) = W[q] * coeff * detJ;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_OCCA
|
||||
// OCCA PA Mass Apply 2D kernel
|
||||
static void OccaPAMassApply2D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const Array<double> &B,
|
||||
const Array<double> &Bt,
|
||||
const Vector &op,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
occa::properties props;
|
||||
props["defines/D1D"] = D1D;
|
||||
props["defines/Q1D"] = Q1D;
|
||||
const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
|
||||
const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
|
||||
const occa::memory o_op = OccaMemoryRead(op.GetMemory(), op.Size());
|
||||
const occa::memory o_x = OccaMemoryRead(x.GetMemory(), x.Size());
|
||||
occa::memory o_y = OccaMemoryReadWrite(y.GetMemory(), y.Size());
|
||||
const occa_id_t id = std::make_pair(D1D,Q1D);
|
||||
if (!Device::Allows(Backend::OCCA_CUDA))
|
||||
{
|
||||
static occa_kernel_t OccaMassApply2D_cpu;
|
||||
if (OccaMassApply2D_cpu.find(id) == OccaMassApply2D_cpu.end())
|
||||
{
|
||||
const occa::kernel MassApply2D_CPU =
|
||||
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
|
||||
"MassApply2D_CPU", props);
|
||||
OccaMassApply2D_cpu.emplace(id, MassApply2D_CPU);
|
||||
}
|
||||
OccaMassApply2D_cpu.at(id)(NE, o_B, o_Bt, o_op, o_x, o_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
static occa_kernel_t OccaMassApply2D_gpu;
|
||||
if (OccaMassApply2D_gpu.find(id) == OccaMassApply2D_gpu.end())
|
||||
{
|
||||
const occa::kernel MassApply2D_GPU =
|
||||
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
|
||||
"MassApply2D_GPU", props);
|
||||
OccaMassApply2D_gpu.emplace(id, MassApply2D_GPU);
|
||||
}
|
||||
OccaMassApply2D_gpu.at(id)(NE, o_B, o_Bt, o_op, o_x, o_y);
|
||||
}
|
||||
}
|
||||
|
||||
// OCCA PA Mass Apply 3D kernel
|
||||
static void OccaPAMassApply3D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const Array<double> &B,
|
||||
const Array<double> &Bt,
|
||||
const Vector &op,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
occa::properties props;
|
||||
props["defines/D1D"] = D1D;
|
||||
props["defines/Q1D"] = Q1D;
|
||||
const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
|
||||
const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
|
||||
const occa::memory o_op = OccaMemoryRead(op.GetMemory(), op.Size());
|
||||
const occa::memory o_x = OccaMemoryRead(x.GetMemory(), x.Size());
|
||||
occa::memory o_y = OccaMemoryReadWrite(y.GetMemory(), y.Size());
|
||||
const occa_id_t id = std::make_pair(D1D,Q1D);
|
||||
if (!Device::Allows(Backend::OCCA_CUDA))
|
||||
{
|
||||
static occa_kernel_t OccaMassApply3D_cpu;
|
||||
if (OccaMassApply3D_cpu.find(id) == OccaMassApply3D_cpu.end())
|
||||
{
|
||||
const occa::kernel MassApply3D_CPU =
|
||||
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
|
||||
"MassApply3D_CPU", props);
|
||||
OccaMassApply3D_cpu.emplace(id, MassApply3D_CPU);
|
||||
}
|
||||
OccaMassApply3D_cpu.at(id)(NE, o_B, o_Bt, o_op, o_x, o_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
static occa_kernel_t OccaMassApply3D_gpu;
|
||||
if (OccaMassApply3D_gpu.find(id) == OccaMassApply3D_gpu.end())
|
||||
{
|
||||
const occa::kernel MassApply3D_GPU =
|
||||
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
|
||||
"MassApply3D_GPU", props);
|
||||
OccaMassApply3D_gpu.emplace(id, MassApply3D_GPU);
|
||||
}
|
||||
OccaMassApply3D_gpu.at(id)(NE, o_B, o_Bt, o_op, o_x, o_y);
|
||||
}
|
||||
}
|
||||
#endif // MFEM_USE_OCCA
|
||||
|
||||
template<const int T_D1D = 0,
|
||||
const int T_Q1D = 0>
|
||||
static void PAMassApply2D(const int NE,
|
||||
const Array<double> &B_,
|
||||
const Array<double> &Bt_,
|
||||
const Vector &op_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
auto B = Reshape(B_.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(Bt_.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d; // nvcc workaround
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
// the following variables are evaluated at compile time
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
double sol_xy[max_Q1D][max_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
double sol_x[max_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
sol_x[qy] = 0.0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double s = x(dx,dy,e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_x[qx] += B(qx,dx)* s;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double d2q = B(qy,dy);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] += d2q * sol_x[qx];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] *= op(qx,qy,e);
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double sol_x[max_D1D];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double s = sol_xy[qy][qx];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] += Bt(dx,qx) * s;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double q2d = Bt(dy,qy);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
y(dx,dy,e) += q2d * sol_x[dx];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<const int T_D1D = 0,
|
||||
const int T_Q1D = 0,
|
||||
const int T_NBZ = 0>
|
||||
static void SmemPAMassApply2D(const int NE,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &bt_,
|
||||
const Vector &op_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= MD1, "");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "");
|
||||
auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
MFEM_SHARED double BBt[MQ1*MD1];
|
||||
double (*B)[MD1] = (double (*)[MD1]) BBt;
|
||||
double (*Bt)[MQ1] = (double (*)[MQ1]) BBt;
|
||||
MFEM_SHARED double sm0[NBZ][MDQ*MDQ];
|
||||
MFEM_SHARED double sm1[NBZ][MDQ*MDQ];
|
||||
double (*X)[MD1] = (double (*)[MD1]) (sm0 + tidz);
|
||||
double (*DQ)[MQ1] = (double (*)[MQ1]) (sm1 + tidz);
|
||||
double (*QQ)[MQ1] = (double (*)[MQ1]) (sm0 + tidz);
|
||||
double (*QD)[MD1] = (double (*)[MD1]) (sm1 + tidz);
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
X[dy][dx] = x(dx,dy,e);
|
||||
}
|
||||
}
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B[q][d] = b(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double dq = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
dq += X[dy][dx] * B[qx][dx];
|
||||
}
|
||||
DQ[dy][qx] = dq;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double qq = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
qq += DQ[dy][qx] * B[qy][dy];
|
||||
}
|
||||
QQ[qy][qx] = qq * op(qx, qy, e);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
Bt[d][q] = b(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double dq = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
dq += QQ[qy][qx] * Bt[dx][qx];
|
||||
}
|
||||
QD[qy][dx] = dq;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double dd = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
dd += (QD[qy][dx] * Bt[dy][qy]);
|
||||
}
|
||||
y(dx, dy, e) += dd;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<const int T_D1D = 0,
|
||||
const int T_Q1D = 0>
|
||||
static void PAMassApply3D(const int NE,
|
||||
const Array<double> &B_,
|
||||
const Array<double> &Bt_,
|
||||
const Vector &op_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
|
||||
auto B = Reshape(B_.Read(), Q1D, D1D);
|
||||
auto Bt = Reshape(Bt_.Read(), D1D, Q1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, NE);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
double sol_xyz[max_Q1D][max_Q1D][max_Q1D];
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xyz[qz][qy][qx] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
double sol_xy[max_Q1D][max_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
double sol_x[max_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_x[qx] = 0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double s = x(dx,dy,dz,e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_x[qx] += B(qx,dx) * s;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double wy = B(qy,dy);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xy[qy][qx] += wy * sol_x[qx];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const double wz = B(qz,dz);
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xyz[qz][qy][qx] += wz * sol_xy[qy][qx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
sol_xyz[qz][qy][qx] *= op(qx,qy,qz,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
double sol_xy[max_D1D][max_D1D];
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_xy[dy][dx] = 0;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double sol_x[max_D1D];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] = 0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double s = sol_xyz[qz][qy][qx];
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_x[dx] += Bt(dx,qx) * s;
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double wy = Bt(dy,qy);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
sol_xy[dy][dx] += wy * sol_x[dx];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
const double wz = Bt(dz,qz);
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
y(dx,dy,dz,e) += wz * sol_xy[dy][dx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<const int T_D1D = 0,
|
||||
const int T_Q1D = 0>
|
||||
static void SmemPAMassApply3D(const int NE,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &bt_,
|
||||
const Vector &op_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int M1Q = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int M1D = T_D1D ? T_D1D : MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= M1D, "");
|
||||
MFEM_VERIFY(Q1D <= M1Q, "");
|
||||
auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, NE);
|
||||
auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
|
||||
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
MFEM_SHARED double sDQ[MQ1*MD1];
|
||||
double (*B)[MD1] = (double (*)[MD1]) sDQ;
|
||||
double (*Bt)[MQ1] = (double (*)[MQ1]) sDQ;
|
||||
MFEM_SHARED double sm0[MDQ*MDQ*MDQ];
|
||||
MFEM_SHARED double sm1[MDQ*MDQ*MDQ];
|
||||
double (*X)[MD1][MD1] = (double (*)[MD1][MD1]) sm0;
|
||||
double (*DDQ)[MD1][MQ1] = (double (*)[MD1][MQ1]) sm1;
|
||||
double (*DQQ)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) sm0;
|
||||
double (*QQQ)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) sm1;
|
||||
double (*QQD)[MQ1][MD1] = (double (*)[MQ1][MD1]) sm0;
|
||||
double (*QDD)[MD1][MD1] = (double (*)[MD1][MD1]) sm1;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
X[dz][dy][dx] = x(dx,dy,dz,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B[q][d] = b(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
u += X[dz][dy][dx] * B[qx][dx];
|
||||
}
|
||||
DDQ[dz][dy][qx] = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
u += DDQ[dz][dy][qx] * B[qy][dy];
|
||||
}
|
||||
DQQ[dz][qy][qx] = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
u += DQQ[dz][qy][qx] * B[qz][dz];
|
||||
}
|
||||
QQQ[qz][qy][qx] = u * op(qx,qy,qz,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
Bt[d][q] = b(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
u += QQQ[qz][qy][qx] * Bt[dx][qx];
|
||||
}
|
||||
QQD[qz][qy][dx] = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
u += QQD[qz][qy][dx] * Bt[dy][qy];
|
||||
}
|
||||
QDD[qz][dy][dx] = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
u += QDD[qz][dy][dx] * Bt[dz][qz];
|
||||
}
|
||||
y(dx,dy,dz,e) += u;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void PAMassApply(const int dim,
|
||||
const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const Array<double> &B,
|
||||
const Array<double> &Bt,
|
||||
const Vector &op,
|
||||
const Vector &x,
|
||||
Vector &y)
|
||||
{
|
||||
#ifdef MFEM_USE_OCCA
|
||||
if (DeviceCanUseOcca())
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
OccaPAMassApply2D(D1D, Q1D, NE, B, Bt, op, x, y);
|
||||
return;
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
OccaPAMassApply3D(D1D, Q1D, NE, B, Bt, op, x, y);
|
||||
return;
|
||||
}
|
||||
MFEM_ABORT("OCCA PA Mass Apply unknown kernel!");
|
||||
}
|
||||
#endif // MFEM_USE_OCCA
|
||||
if (dim == 2)
|
||||
{
|
||||
switch ((D1D << 4) | Q1D)
|
||||
{
|
||||
case 0x22: return SmemPAMassApply2D<2,2,16>(NE, B, Bt, op, x, y);
|
||||
case 0x33: return SmemPAMassApply2D<3,3,16>(NE, B, Bt, op, x, y);
|
||||
case 0x44: return SmemPAMassApply2D<4,4,8>(NE, B, Bt, op, x, y);
|
||||
case 0x55: return SmemPAMassApply2D<5,5,8>(NE, B, Bt, op, x, y);
|
||||
case 0x66: return SmemPAMassApply2D<6,6,4>(NE, B, Bt, op, x, y);
|
||||
case 0x77: return SmemPAMassApply2D<7,7,4>(NE, B, Bt, op, x, y);
|
||||
case 0x88: return SmemPAMassApply2D<8,8,2>(NE, B, Bt, op, x, y);
|
||||
case 0x99: return SmemPAMassApply2D<9,9,2>(NE, B, Bt, op, x, y);
|
||||
default: return PAMassApply2D(NE, B, Bt, op, x, y, D1D, Q1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch ((D1D << 4) | Q1D)
|
||||
{
|
||||
case 0x23: return SmemPAMassApply3D<2,3>(NE, B, Bt, op, x, y);
|
||||
case 0x34: return SmemPAMassApply3D<3,4>(NE, B, Bt, op, x, y);
|
||||
case 0x45: return SmemPAMassApply3D<4,5>(NE, B, Bt, op, x, y);
|
||||
case 0x56: return SmemPAMassApply3D<5,6>(NE, B, Bt, op, x, y);
|
||||
case 0x67: return SmemPAMassApply3D<6,7>(NE, B, Bt, op, x, y);
|
||||
case 0x78: return SmemPAMassApply3D<7,8>(NE, B, Bt, op, x, y);
|
||||
case 0x89: return SmemPAMassApply3D<8,9>(NE, B, Bt, op, x, y);
|
||||
default: return PAMassApply3D(NE, B, Bt, op, x, y, D1D, Q1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
}
|
||||
|
||||
void MassIntegrator::AddMultPA(const Vector &x, Vector &y) const
|
||||
{
|
||||
PAMassApply(dim, dofs1D, quad1D, ne, maps->B, maps->Bt, pa_data, x, y);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
+12
-20
@@ -28,6 +28,11 @@ double PWConstCoefficient::Eval(ElementTransformation & T,
|
||||
return (constants(att-1));
|
||||
}
|
||||
|
||||
DeviceFunctionCoefficientPtr FunctionCoefficient::GetDeviceFunction()
|
||||
{
|
||||
return DeviceFunction;
|
||||
}
|
||||
|
||||
double FunctionCoefficient::Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
@@ -40,6 +45,10 @@ double FunctionCoefficient::Eval(ElementTransformation & T,
|
||||
{
|
||||
return ((*Function)(transip));
|
||||
}
|
||||
else if (DeviceFunction)
|
||||
{
|
||||
return ((*DeviceFunction)(Vector3(x)));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (*TDFunction)(transip, GetTime());
|
||||
@@ -125,27 +134,19 @@ void VectorFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
}
|
||||
|
||||
VectorArrayCoefficient::VectorArrayCoefficient (int dim)
|
||||
: VectorCoefficient(dim), Coeff(dim), ownCoeff(dim)
|
||||
: VectorCoefficient(dim), Coeff(dim)
|
||||
{
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
Coeff[i] = NULL;
|
||||
ownCoeff[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void VectorArrayCoefficient::Set(int i, Coefficient *c, bool own)
|
||||
{
|
||||
if (ownCoeff[i]) { delete Coeff[i]; }
|
||||
Coeff[i] = c;
|
||||
ownCoeff[i] = own;
|
||||
}
|
||||
|
||||
VectorArrayCoefficient::~VectorArrayCoefficient()
|
||||
{
|
||||
for (int i = 0; i < vdim; i++)
|
||||
{
|
||||
if (ownCoeff[i]) { delete Coeff[i]; }
|
||||
delete Coeff[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,26 +318,17 @@ MatrixArrayCoefficient::MatrixArrayCoefficient (int dim)
|
||||
: MatrixCoefficient (dim)
|
||||
{
|
||||
Coeff.SetSize(height*width);
|
||||
ownCoeff.SetSize(height*width);
|
||||
for (int i = 0; i < (height*width); i++)
|
||||
{
|
||||
Coeff[i] = NULL;
|
||||
ownCoeff[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void MatrixArrayCoefficient::Set(int i, int j, Coefficient * c, bool own)
|
||||
{
|
||||
if (ownCoeff[i*width+j]) { delete Coeff[i*width+j]; }
|
||||
Coeff[i*width+j] = c;
|
||||
ownCoeff[i*width+j] = own;
|
||||
}
|
||||
|
||||
MatrixArrayCoefficient::~MatrixArrayCoefficient ()
|
||||
{
|
||||
for (int i=0; i < height*width; i++)
|
||||
{
|
||||
if (ownCoeff[i]) { delete Coeff[i]; }
|
||||
delete Coeff[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+22
-8
@@ -112,6 +112,7 @@ public:
|
||||
const IntegrationPoint &ip);
|
||||
};
|
||||
|
||||
typedef double (*DeviceFunctionCoefficientPtr)(const Vector3&);
|
||||
|
||||
/// class for C-function coefficient
|
||||
class FunctionCoefficient : public Coefficient
|
||||
@@ -119,6 +120,7 @@ class FunctionCoefficient : public Coefficient
|
||||
protected:
|
||||
double (*Function)(const Vector &);
|
||||
double (*TDFunction)(const Vector &, double);
|
||||
double (*DeviceFunction)(const Vector3&);
|
||||
|
||||
public:
|
||||
/// Define a time-independent coefficient from a C-function
|
||||
@@ -126,6 +128,7 @@ public:
|
||||
{
|
||||
Function = f;
|
||||
TDFunction = NULL;
|
||||
DeviceFunction = NULL;
|
||||
}
|
||||
|
||||
/// Define a time-dependent coefficient from a C-function
|
||||
@@ -133,6 +136,16 @@ public:
|
||||
{
|
||||
Function = NULL;
|
||||
TDFunction = tdf;
|
||||
DeviceFunction = NULL;
|
||||
}
|
||||
|
||||
/// Define a time-independent coefficient from a C-function using
|
||||
/// Vector3 instead of a Vector.
|
||||
FunctionCoefficient(double (*df)(const Vector3 &))
|
||||
{
|
||||
Function = NULL;
|
||||
TDFunction = NULL;
|
||||
DeviceFunction = df;
|
||||
}
|
||||
|
||||
/// (DEPRECATED) Define a time-independent coefficient from a C-function
|
||||
@@ -142,6 +155,7 @@ public:
|
||||
{
|
||||
Function = reinterpret_cast<double(*)(const Vector&)>(f);
|
||||
TDFunction = NULL;
|
||||
DeviceFunction = NULL;
|
||||
}
|
||||
|
||||
/// (DEPRECATED) Define a time-dependent coefficient from a C-function
|
||||
@@ -151,11 +165,17 @@ public:
|
||||
{
|
||||
Function = NULL;
|
||||
TDFunction = reinterpret_cast<double(*)(const Vector&,double)>(tdf);
|
||||
DeviceFunction = NULL;
|
||||
}
|
||||
|
||||
/// Evaluate coefficient
|
||||
virtual double Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
/// Return the coefficient's C-function that uses Vector3.
|
||||
/// Warning: for now, the returned function can only be used on the
|
||||
/// host inside a MFEM_FORALL.
|
||||
DeviceFunctionCoefficientPtr GetDeviceFunction();
|
||||
};
|
||||
|
||||
class GridFunction;
|
||||
@@ -369,7 +389,6 @@ class VectorArrayCoefficient : public VectorCoefficient
|
||||
{
|
||||
private:
|
||||
Array<Coefficient*> Coeff;
|
||||
Array<bool> ownCoeff;
|
||||
|
||||
public:
|
||||
/// Construct vector of dim coefficients.
|
||||
@@ -381,7 +400,7 @@ public:
|
||||
Coefficient **GetCoeffs() { return Coeff; }
|
||||
|
||||
/// Sets coefficient in the vector.
|
||||
void Set(int i, Coefficient *c, bool own=true);
|
||||
void Set(int i, Coefficient *c) { delete Coeff[i]; Coeff[i] = c; }
|
||||
|
||||
/// Evaluates i'th component of the vector.
|
||||
double Eval(int i, ElementTransformation &T, const IntegrationPoint &ip)
|
||||
@@ -501,13 +520,9 @@ public:
|
||||
void SetDeltaCoefficient(const DeltaCoefficient& _d) { d = _d; }
|
||||
/// Return the associated scalar DeltaCoefficient.
|
||||
DeltaCoefficient& GetDeltaCoefficient() { return d; }
|
||||
|
||||
void SetScale(double s) { d.SetScale(s); }
|
||||
void SetDirection(const Vector& _d);
|
||||
|
||||
void SetDeltaCenter(const Vector& center) { d.SetDeltaCenter(center); }
|
||||
void GetDeltaCenter(Vector& center) { d.GetDeltaCenter(center); }
|
||||
|
||||
/** @brief Return the specified direction vector multiplied by the value
|
||||
returned by DeltaCoefficient::EvalDelta() of the associated scalar
|
||||
DeltaCoefficient. */
|
||||
@@ -633,7 +648,6 @@ class MatrixArrayCoefficient : public MatrixCoefficient
|
||||
{
|
||||
private:
|
||||
Array<Coefficient *> Coeff;
|
||||
Array<bool> ownCoeff;
|
||||
|
||||
public:
|
||||
|
||||
@@ -641,7 +655,7 @@ public:
|
||||
|
||||
Coefficient* GetCoeff (int i, int j) { return Coeff[i*width+j]; }
|
||||
|
||||
void Set(int i, int j, Coefficient * c, bool own=true);
|
||||
void Set(int i, int j, Coefficient * c) { delete Coeff[i*width+j]; Coeff[i*width+j] = c; }
|
||||
|
||||
double Eval(int i, int j, ElementTransformation &T, const IntegrationPoint &ip)
|
||||
{ return Coeff[i*width+j] ? Coeff[i*width+j] -> Eval(T, ip, GetTime()) : 0.0; }
|
||||
|
||||
+4
-17
@@ -108,7 +108,6 @@ DataCollection::DataCollection(const std::string& collection_name, Mesh *mesh_)
|
||||
precision = precision_default;
|
||||
pad_digits_cycle = pad_digits_rank = pad_digits_default;
|
||||
format = SERIAL_FORMAT; // use serial mesh format
|
||||
compression = false;
|
||||
error = NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -162,14 +161,6 @@ void DataCollection::SetFormat(int fmt)
|
||||
format = fmt;
|
||||
}
|
||||
|
||||
void DataCollection::SetCompression(bool comp)
|
||||
{
|
||||
compression = comp;
|
||||
#ifdef MFEM_USE_GZSTREAM
|
||||
MFEM_ASSERT(!compression, "GZStream not enabled in MFEM build.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void DataCollection::SetPrefixPath(const std::string& prefix)
|
||||
{
|
||||
if (!prefix.empty())
|
||||
@@ -228,8 +219,7 @@ void DataCollection::SaveMesh()
|
||||
}
|
||||
|
||||
std::string mesh_name = GetMeshFileName();
|
||||
const char *mode = (compression) ? "zwb6" : "w";
|
||||
ofgzstream mesh_file(mesh_name.c_str(), mode);
|
||||
std::ofstream mesh_file(mesh_name.c_str());
|
||||
mesh_file.precision(precision);
|
||||
#ifdef MFEM_USE_MPI
|
||||
const ParMesh *pmesh = dynamic_cast<const ParMesh*>(mesh);
|
||||
@@ -277,9 +267,7 @@ const
|
||||
|
||||
void DataCollection::SaveOneField(const FieldMapIterator &it)
|
||||
{
|
||||
const char *mode = (compression) ? "zwb6" : "w";
|
||||
ofgzstream field_file(GetFieldFileName(it->first).c_str(), mode);
|
||||
|
||||
std::ofstream field_file(GetFieldFileName(it->first).c_str());
|
||||
field_file.precision(precision);
|
||||
(it->second)->Save(field_file);
|
||||
if (!field_file)
|
||||
@@ -291,8 +279,7 @@ void DataCollection::SaveOneField(const FieldMapIterator &it)
|
||||
|
||||
void DataCollection::SaveOneQField(const QFieldMapIterator &it)
|
||||
{
|
||||
const char *mode = (compression) ? "zwb6" : "w";
|
||||
ofgzstream q_field_file(GetFieldFileName(it->first).c_str(), mode);
|
||||
std::ofstream q_field_file(GetFieldFileName(it->first).c_str());
|
||||
q_field_file.precision(precision);
|
||||
(it->second)->Save(q_field_file);
|
||||
if (!q_field_file)
|
||||
@@ -589,7 +576,7 @@ void VisItDataCollection::LoadFields()
|
||||
it != field_info_map.end(); ++it)
|
||||
{
|
||||
std::string fname = path_left + it->first + path_right;
|
||||
ifgzstream file(fname.c_str());
|
||||
std::ifstream file(fname.c_str());
|
||||
// TODO: in parallel, check for errors on all processors
|
||||
if (!file)
|
||||
{
|
||||
|
||||
@@ -205,7 +205,6 @@ protected:
|
||||
|
||||
/// Output mesh format: see the #Format enumeration
|
||||
int format;
|
||||
bool compression;
|
||||
|
||||
/// Should the collection delete its mesh and fields
|
||||
bool own_data;
|
||||
@@ -347,9 +346,6 @@ public:
|
||||
validation. */
|
||||
virtual void SetFormat(int fmt);
|
||||
|
||||
/// Set the flag for use of gz compressed files
|
||||
void SetCompression(bool comp);
|
||||
|
||||
/// Set the path where the DataCollection will be saved.
|
||||
void SetPrefixPath(const std::string &prefix);
|
||||
|
||||
|
||||
+370
-110
@@ -203,22 +203,6 @@ void FiniteElement::CalcPhysDShape(ElementTransformation &Trans,
|
||||
Mult(vshape, Trans.InverseJacobian(), dshape);
|
||||
}
|
||||
|
||||
const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &,
|
||||
DofToQuad::Mode) const
|
||||
{
|
||||
mfem_error("FiniteElement::GetDofToQuad(...) is not implemented for "
|
||||
"this element!");
|
||||
return *dof2quad_array[0]; // suppress a warning
|
||||
}
|
||||
|
||||
FiniteElement::~FiniteElement()
|
||||
{
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
delete dof2quad_array[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ScalarFiniteElement::NodalLocalInterpolation (
|
||||
ElementTransformation &Trans, DenseMatrix &I,
|
||||
@@ -294,95 +278,6 @@ void ScalarFiniteElement::ScalarLocalInterpolation(
|
||||
}
|
||||
}
|
||||
|
||||
const DofToQuad &ScalarFiniteElement::GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode == DofToQuad::FULL, "invalid mode requested");
|
||||
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const int nqpt = ir.GetNPoints();
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = Dof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*Dof);
|
||||
d2q->Bt.SetSize(Dof*nqpt);
|
||||
d2q->G.SetSize(nqpt*Dim*Dof);
|
||||
d2q->Gt.SetSize(Dof*nqpt*Dim);
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector c_shape(Dof);
|
||||
DenseMatrix vshape(Dof, Dim);
|
||||
#endif
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcShape(ip, c_shape);
|
||||
for (int j = 0; j < Dof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+Dof*i] = c_shape(j);
|
||||
}
|
||||
CalcDShape(ip, vshape);
|
||||
for (int d = 0; d < Dim; d++)
|
||||
{
|
||||
for (int j = 0; j < Dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*(d+Dim*j)] = d2q->Gt[j+Dof*(i+nqpt*d)] = vshape(j,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
// protected method
|
||||
const DofToQuad &ScalarFiniteElement::GetTensorDofToQuad(
|
||||
const TensorBasisElement &tb,
|
||||
const IntegrationRule &ir, DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
|
||||
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const Poly_1D::Basis &basis_1d = tb.GetBasis1D();
|
||||
const int ndof = Order + 1;
|
||||
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/Dim) + 0.5);
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = ndof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*ndof);
|
||||
d2q->Bt.SetSize(ndof*nqpt);
|
||||
d2q->G.SetSize(nqpt*ndof);
|
||||
d2q->Gt.SetSize(ndof*nqpt);
|
||||
Vector val(ndof), grad(ndof);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
|
||||
// of the 1D rule.
|
||||
basis_1d.Eval(ir.IntPoint(i).x, val, grad);
|
||||
for (int j = 0; j < ndof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
|
||||
}
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
|
||||
void NodalFiniteElement::ProjectCurl_2D(
|
||||
const FiniteElement &fe, ElementTransformation &Trans,
|
||||
@@ -9635,7 +9530,6 @@ void L2_TetrahedronElement::ProjectDelta(int vertex, Vector &dofs) const
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(i);
|
||||
dofs[i] = pow(ip.y, Order);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for (int i = 0; i < Dof; i++)
|
||||
{
|
||||
@@ -11951,6 +11845,376 @@ void NURBS3DFiniteElement::CalcDShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
/// SBP_SegmentElement is a segment element with nodes at Gauss Lobatto
|
||||
/// points with ordering consistent with SBP_TriangleElement's edges.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// Not currently implemented as collocated SBP type element
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
SBP_SegmentElement::SBP_SegmentElement(const int p)
|
||||
: NodalTensorFiniteElement(1, p+1, BasisType::GaussLobatto, H1_DOF_MAP)
|
||||
{
|
||||
const double *cp = poly1d.ClosedPoints(p+1, b_type);
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
shape_x.SetSize(p+2);
|
||||
dshape_x.SetSize(p+2);
|
||||
#endif
|
||||
|
||||
Nodes.IntPoint(0).x = cp[0];
|
||||
Nodes.IntPoint(1).x = cp[p+1];
|
||||
|
||||
switch (p)
|
||||
{
|
||||
case 1:
|
||||
Nodes.IntPoint(2).x = cp[1];
|
||||
break;
|
||||
case 2:
|
||||
Nodes.IntPoint(2).x = cp[1];
|
||||
Nodes.IntPoint(3).x = cp[2];
|
||||
break;
|
||||
case 3:
|
||||
Nodes.IntPoint(2).x = cp[2];
|
||||
Nodes.IntPoint(3).x = cp[1];
|
||||
Nodes.IntPoint(4).x = cp[3];
|
||||
break;
|
||||
case 4:
|
||||
Nodes.IntPoint(2).x = cp[2];
|
||||
Nodes.IntPoint(3).x = cp[3];
|
||||
Nodes.IntPoint(4).x = cp[1];
|
||||
Nodes.IntPoint(5).x = cp[4];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SBP_SegmentElement::CalcShape(const IntegrationPoint &ip,
|
||||
Vector &shape) const
|
||||
{
|
||||
const int p = Order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p+2);
|
||||
#endif
|
||||
|
||||
basis1d.Eval(ip.x, shape_x);
|
||||
|
||||
shape(0) = shape_x(0);
|
||||
shape(1) = shape_x(p+1);
|
||||
|
||||
switch (p)
|
||||
{
|
||||
case 1:
|
||||
shape(2) = shape_x(1);
|
||||
break;
|
||||
case 2:
|
||||
shape(2) = shape_x(1);
|
||||
shape(3) = shape_x(2);
|
||||
break;
|
||||
case 3:
|
||||
shape(2) = shape_x(2);
|
||||
shape(3) = shape_x(1);
|
||||
shape(4) = shape_x(3);
|
||||
break;
|
||||
case 4:
|
||||
shape(2) = shape_x(2);
|
||||
shape(3) = shape_x(3);
|
||||
shape(4) = shape_x(1);
|
||||
shape(5) = shape_x(4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SBP_SegmentElement::CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const
|
||||
{
|
||||
const int p = Order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p+2), dshape_x(p+2);
|
||||
#endif
|
||||
|
||||
basis1d.Eval(ip.x, shape_x, dshape_x);
|
||||
|
||||
dshape(0,0) = dshape_x(0);
|
||||
dshape(1,0) = dshape_x(p+1);
|
||||
|
||||
switch (p)
|
||||
{
|
||||
case 1:
|
||||
dshape(2,0) = dshape_x(1);
|
||||
break;
|
||||
case 2:
|
||||
dshape(2,0) = dshape_x(1);
|
||||
dshape(3,0) = dshape_x(2);
|
||||
break;
|
||||
case 3:
|
||||
dshape(2,0) = dshape_x(2);
|
||||
dshape(3,0) = dshape_x(1);
|
||||
dshape(4,0) = dshape_x(3);
|
||||
break;
|
||||
case 4:
|
||||
dshape(2,0) = dshape_x(2);
|
||||
dshape(3,0) = dshape_x(3);
|
||||
dshape(4,0) = dshape_x(1);
|
||||
dshape(5,0) = dshape_x(4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Leftover function from H1_Segment element
|
||||
// void SBP_SegmentElement::ProjectDelta(int vertex, Vector &dofs) const
|
||||
// {
|
||||
// const int p = Order;
|
||||
// const double *cp = poly1d.ClosedPoints(p, b_type);
|
||||
|
||||
// switch (vertex)
|
||||
// {
|
||||
// case 0:
|
||||
// dofs(0) = poly1d.CalcDelta(p, (1.0 - cp[0]));
|
||||
// dofs(1) = poly1d.CalcDelta(p, (1.0 - cp[p]));
|
||||
// for (int i = 1; i < p; i++)
|
||||
// {
|
||||
// dofs(i+1) = poly1d.CalcDelta(p, (1.0 - cp[i]));
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case 1:
|
||||
// dofs(0) = poly1d.CalcDelta(p, cp[0]);
|
||||
// dofs(1) = poly1d.CalcDelta(p, cp[p]);
|
||||
// for (int i = 1; i < p; i++)
|
||||
// {
|
||||
// dofs(i+1) = poly1d.CalcDelta(p, cp[i]);
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
SBP_TriangleElement::SBP_TriangleElement(const int p, const int Do)
|
||||
: NodalFiniteElement(2, Geometry::TRIANGLE, Do, p,
|
||||
FunctionSpace::SBPk)
|
||||
{
|
||||
/// Header file including SBP Dx and Dy matrix data
|
||||
#include "fe_sbp.hpp"
|
||||
|
||||
// Create Dx and Dy matrixes
|
||||
Dx = new DenseMatrix(Dof);
|
||||
Dy = new DenseMatrix(Dof);
|
||||
|
||||
// Populate the Dx and Dy matrices and create the element's Nodes
|
||||
switch (p)
|
||||
{
|
||||
case 0:
|
||||
*Dx=p0Dx;
|
||||
*Dy=p0Dy;
|
||||
|
||||
Nodes.IntPoint(0).Set2w(0.0, 0.0, 0.16666666666666666);
|
||||
Nodes.IntPoint(1).Set2w(1.0, 0.0, 0.16666666666666666);
|
||||
Nodes.IntPoint(2).Set2w(0.0, 1.0, 0.16666666666666666);
|
||||
break;
|
||||
case 1:
|
||||
*Dx=p1Dx;
|
||||
*Dy=p1Dy;
|
||||
|
||||
Nodes.IntPoint(0).Set2w(0.0, 0.0, 0.024999999999999998);
|
||||
Nodes.IntPoint(1).Set2w(1.0, 0.0, 0.024999999999999998);
|
||||
Nodes.IntPoint(2).Set2w(0.0, 1.0, 0.024999999999999998);
|
||||
Nodes.IntPoint(3).Set2w(0.5, 0.0, 0.06666666666666667);
|
||||
Nodes.IntPoint(4).Set2w(0.5, 0.5, 0.06666666666666667);
|
||||
Nodes.IntPoint(5).Set2w(0.0, 0.5, 0.06666666666666667);
|
||||
Nodes.IntPoint(6).Set2w(0.3333333333333333, 0.3333333333333333, 0.22500000000000006);
|
||||
break;
|
||||
case 2:
|
||||
*Dx=p2Dx;
|
||||
*Dy=p2Dy;
|
||||
|
||||
// vertices
|
||||
Nodes.IntPoint(0).Set2w(0.0, 0.0, 0.006261126504899741);
|
||||
Nodes.IntPoint(1).Set2w(1.0, 0.0, 0.006261126504899741);
|
||||
Nodes.IntPoint(2).Set2w(0.0, 1.0, 0.006261126504899741);
|
||||
|
||||
// edges
|
||||
Nodes.IntPoint(3).Set2w(0.27639320225002106, 0.0, 0.026823800250389242);
|
||||
Nodes.IntPoint(4).Set2w(0.7236067977499789, 0.0, 0.026823800250389242);
|
||||
Nodes.IntPoint(5).Set2w(0.7236067977499789, 0.27639320225002106, 0.026823800250389242);
|
||||
Nodes.IntPoint(6).Set2w(0.27639320225002106, 0.7236067977499789, 0.026823800250389242);
|
||||
Nodes.IntPoint(7).Set2w(0.0, 0.7236067977499789, 0.026823800250389242);
|
||||
Nodes.IntPoint(8).Set2w(0.0, 0.27639320225002106, 0.026823800250389242);
|
||||
|
||||
// interior
|
||||
Nodes.IntPoint(9).Set2w(0.21285435711180825, 0.5742912857763836, 0.10675793966098839);
|
||||
Nodes.IntPoint(10).Set2w(0.21285435711180825, 0.21285435711180825, 0.10675793966098839);
|
||||
Nodes.IntPoint(11).Set2w(0.5742912857763836, 0.21285435711180825, 0.10675793966098839);
|
||||
break;
|
||||
case 3:
|
||||
*Dx=p3Dx;
|
||||
*Dy=p3Dy;
|
||||
|
||||
// vertices
|
||||
Nodes.IntPoint(0).Set2w(0.0, 0.0, 0.0022825661430496253);
|
||||
Nodes.IntPoint(1).Set2w(1.0, 0.0, 0.0022825661430496253);
|
||||
Nodes.IntPoint(2).Set2w(0.0, 1.0, 0.0022825661430496253);
|
||||
|
||||
// edges
|
||||
Nodes.IntPoint(3).Set2w(0.5, 0.0, 0.015504052643022513);
|
||||
Nodes.IntPoint(4).Set2w(0.17267316464601146, 0.0, 0.011342592592592586);
|
||||
Nodes.IntPoint(5).Set2w(0.8273268353539885, 0.0, 0.011342592592592586);
|
||||
|
||||
Nodes.IntPoint(6).Set2w(0.5, 0.5, 0.015504052643022513);
|
||||
Nodes.IntPoint(7).Set2w(0.8273268353539885, 0.17267316464601146, 0.011342592592592586);
|
||||
Nodes.IntPoint(8).Set2w(0.17267316464601146, 0.8273268353539885, 0.011342592592592586);
|
||||
|
||||
Nodes.IntPoint(9).Set2w(0.0, 0.5, 0.015504052643022513);
|
||||
Nodes.IntPoint(10).Set2w(0.0, 0.8273268353539885, 0.011342592592592586);
|
||||
Nodes.IntPoint(11).Set2w(0.0, 0.17267316464601146, 0.011342592592592586);
|
||||
|
||||
// interior
|
||||
Nodes.IntPoint(12).Set2w(0.4243860251718814, 0.1512279496562372, 0.07467669469983994);
|
||||
Nodes.IntPoint(13).Set2w(0.4243860251718814, 0.4243860251718814, 0.07467669469983994);
|
||||
Nodes.IntPoint(14).Set2w(0.1512279496562372, 0.4243860251718814, 0.07467669469983994);
|
||||
|
||||
Nodes.IntPoint(15).Set2w(0.14200508409677795, 0.7159898318064442, 0.051518167995569394);
|
||||
Nodes.IntPoint(16).Set2w(0.14200508409677795, 0.14200508409677795, 0.051518167995569394);
|
||||
Nodes.IntPoint(17).Set2w(0.7159898318064442, 0.14200508409677795, 0.051518167995569394);
|
||||
|
||||
break;
|
||||
case 4:
|
||||
*Dx=p4Dx;
|
||||
*Dy=p4Dy;
|
||||
|
||||
// vertices
|
||||
Nodes.IntPoint(0).Set2w(0.000000000000000000,0.000000000000000000,0.001090393904993471);
|
||||
Nodes.IntPoint(1).Set2w(1.000000000000000000,0.000000000000000000,0.001090393904993471);
|
||||
Nodes.IntPoint(2).Set2w(0.000000000000000000,1.000000000000000000,0.001090393904993471);
|
||||
|
||||
// edges
|
||||
Nodes.IntPoint(3).Set2w(0.357384241759677534,0.000000000000000000,0.006966942871463700);
|
||||
Nodes.IntPoint(4).Set2w(0.642615758240322466,0.000000000000000000,0.006966942871463700);
|
||||
Nodes.IntPoint(5).Set2w(0.117472338035267576,0.000000000000000000,0.005519747637357106);
|
||||
Nodes.IntPoint(6).Set2w(0.882527661964732424,0.000000000000000000,0.005519747637357106);
|
||||
|
||||
Nodes.IntPoint(7).Set2w(0.642615758240322466,0.357384241759677534,0.006966942871463700);
|
||||
Nodes.IntPoint(8).Set2w(0.357384241759677534,0.642615758240322466,0.006966942871463700);
|
||||
Nodes.IntPoint(9).Set2w(0.882527661964732424,0.117472338035267576,0.005519747637357106);
|
||||
Nodes.IntPoint(10).Set2w(0.117472338035267576,0.882527661964732424,0.005519747637357106);
|
||||
|
||||
Nodes.IntPoint(11).Set2w(0.000000000000000000,0.642615758240322466,0.006966942871463700);
|
||||
Nodes.IntPoint(12).Set2w(0.000000000000000000,0.357384241759677534,0.006966942871463700);
|
||||
Nodes.IntPoint(13).Set2w(0.000000000000000000,0.882527661964732424,0.005519747637357106);
|
||||
Nodes.IntPoint(14).Set2w(0.000000000000000000,0.117472338035267576,0.005519747637357106);
|
||||
|
||||
// interior
|
||||
Nodes.IntPoint(15).Set2w(0.103677508142805172,0.792644983714389628,0.028397190663911491);
|
||||
Nodes.IntPoint(16).Set2w(0.103677508142805172,0.103677508142805172,0.028397190663911491);
|
||||
Nodes.IntPoint(17).Set2w(0.792644983714389628,0.103677508142805172,0.028397190663911491);
|
||||
Nodes.IntPoint(18).Set2w(0.265331380484209678,0.469337239031580644,0.039960048027851809);
|
||||
Nodes.IntPoint(19).Set2w(0.265331380484209678,0.265331380484209678,0.039960048027851809);
|
||||
Nodes.IntPoint(20).Set2w(0.469337239031580644,0.265331380484209678,0.039960048027851809);
|
||||
Nodes.IntPoint(21).Set2w(0.587085567133367348,0.088273960601581103,0.036122826526134168);
|
||||
Nodes.IntPoint(22).Set2w(0.324640472265051494,0.088273960601581103,0.036122826526134168);
|
||||
Nodes.IntPoint(23).Set2w(0.324640472265051494,0.587085567133367348,0.036122826526134168);
|
||||
Nodes.IntPoint(24).Set2w(0.587085567133367348,0.324640472265051494,0.036122826526134168);
|
||||
Nodes.IntPoint(25).Set2w(0.088273960601581103,0.324640472265051494,0.036122826526134168);
|
||||
Nodes.IntPoint(26).Set2w(0.088273960601581103,0.587085567133367348,0.036122826526134168);
|
||||
|
||||
break;
|
||||
default:
|
||||
mfem_error("SBP elements are currently only supported for 0 <= order <= 4");
|
||||
break;
|
||||
}
|
||||
|
||||
// populate unordered_map with mapping from IntPoint address to index
|
||||
for (int i = 0; i < Dof; i++)
|
||||
{
|
||||
ipIdxMap[&(Nodes.IntPoint(i))] = i;
|
||||
}
|
||||
}
|
||||
|
||||
/// CalcShape outputs ndofx1 vector shape based on Kronecker \delta_{i, ip}
|
||||
/// where ip is the integration point CalcShape is evaluated at.
|
||||
void SBP_TriangleElement::CalcShape(const IntegrationPoint &ip,
|
||||
Vector &shape) const
|
||||
{
|
||||
int ipIdx;
|
||||
try
|
||||
{
|
||||
ipIdx = ipIdxMap.at(&ip);
|
||||
}
|
||||
catch (const std::out_of_range& oor)
|
||||
// error handling code to handle cases where the pointer to ip is not
|
||||
// in the map. Problems arise in GridFunction::SaveVTK() -> GridFunction::GetValues()
|
||||
// which calls CalcShape() with an `IntegrationPoint` defined by a refined
|
||||
// geometry type. Since the IntegrationPoint is not in Nodes, its address is
|
||||
// not in the ipIdxMap, and an out_of_range error is thrown. This code catches
|
||||
// the error and uses float comparisons to determine the IntegrationPoint
|
||||
// index.
|
||||
{
|
||||
double tol = 1e-12;
|
||||
for (int i = 0; i < Dof; i++)
|
||||
{
|
||||
double delta_x = ip.x - Nodes.IntPoint(i).x;
|
||||
double delta_y = ip.y - Nodes.IntPoint(i).y;
|
||||
if (delta_x*delta_x + delta_y*delta_y < tol)
|
||||
{
|
||||
ipIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
shape = 0.0;
|
||||
shape(ipIdx) = 1.0;
|
||||
}
|
||||
|
||||
/// CalcDShape outputs ndof x ndim DenseMatrix dshape, where the first column
|
||||
/// is the ith row of Dx, and the second column is the ith row of Dy, where i
|
||||
/// is the integration point CalcDShape is evaluated at. Since DenseMatrices
|
||||
/// are stored a column major we should store the transpose so accessing a row
|
||||
/// is faster, but this is not done here.
|
||||
void SBP_TriangleElement::CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const
|
||||
{
|
||||
int ipIdx;
|
||||
try
|
||||
{
|
||||
ipIdx = ipIdxMap.at(&ip);
|
||||
}
|
||||
catch (const std::out_of_range& oor)
|
||||
// error handling code to handle cases where the pointer to ip is not
|
||||
// in the map. Problems arise in GridFunction::SaveVTK() -> GridFunction::GetValues()
|
||||
// which calls CalcShape() with an `IntegrationPoint` defined by a refined
|
||||
// geometry type. Since the IntegrationPoint is not in Nodes, its address is
|
||||
// not in the ipIdxMap, and an out_of_range error is thrown. This code catches
|
||||
// the error and uses float comparisons to determine the IntegrationPoint
|
||||
// index.
|
||||
{
|
||||
double tol = 1e-12;
|
||||
for (int i = 0; i < Dof; i++)
|
||||
{
|
||||
double delta_x = ip.x - Nodes.IntPoint(i).x;
|
||||
double delta_y = ip.y - Nodes.IntPoint(i).y;
|
||||
if (delta_x*delta_x + delta_y*delta_y < tol)
|
||||
{
|
||||
ipIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dshape = 0.0;
|
||||
|
||||
Vector tempVec(Dof);
|
||||
|
||||
// when we switch to storing Dx and Dy transpose so that access to the row we want
|
||||
// is faster Dx->GetRow() will be replaced with Dx->GetColumnReference()
|
||||
Dx->GetRow(ipIdx, tempVec);
|
||||
dshape.SetCol(0, tempVec);
|
||||
Dy->GetRow(ipIdx, tempVec);
|
||||
dshape.SetCol(1, tempVec);
|
||||
}
|
||||
|
||||
SBP_TriangleElement::~SBP_TriangleElement()
|
||||
{
|
||||
delete Dx;
|
||||
delete Dy;
|
||||
}
|
||||
|
||||
// Global object definitions
|
||||
|
||||
@@ -11966,10 +12230,6 @@ Linear3DFiniteElement TetrahedronFE;
|
||||
// Object declared in mesh/wedge.hpp.
|
||||
// Defined here to ensure it is constructed after 'poly1d' and before
|
||||
// 'Geometries'.
|
||||
// TODO: define as thread_local to prevent race conditions in GLVis, because
|
||||
// there is no "LinearWedgeFiniteElement" and WedgeFE is in turn used from two
|
||||
// different threads for different things in GLVis. We also don't want to turn
|
||||
// MFEM_THREAD_SAFE on globally. (See PR #731)
|
||||
H1_WedgeElement WedgeFE(1);
|
||||
|
||||
// Object declared in geom.hpp.
|
||||
|
||||
+43
-125
@@ -19,6 +19,7 @@
|
||||
#include "geom.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -116,92 +117,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @brief Structure representing the matrices/tensors needed to evaluate (in
|
||||
reference space) the values, gradients, divergences, or curls of a
|
||||
FiniteElement at a the quadrature points of a given IntegrationRule. */
|
||||
/** Object of this type are typically created and owned by the respective
|
||||
FiniteElement object. */
|
||||
class DofToQuad
|
||||
{
|
||||
public:
|
||||
/// The FiniteElement that created and owns this object.
|
||||
/** This pointer is not owned. */
|
||||
const class FiniteElement *FE;
|
||||
|
||||
/** @brief IntegrationRule that defines the quadrature points at which the
|
||||
basis functions of the #FE are evaluated. */
|
||||
/** This pointer is not owned. */
|
||||
const IntegrationRule *IntRule;
|
||||
|
||||
/// Type of data stored in the arrays #B, #Bt, #G, and #Gt.
|
||||
enum Mode
|
||||
{
|
||||
/** @brief Full multidimensional representation which does not use tensor
|
||||
product structure. The ordering of the degrees of freedom is as
|
||||
defined by #FE */
|
||||
FULL,
|
||||
|
||||
/** @brief Tensor product representation using 1D matrices/tensors with
|
||||
dimensions using 1D number of quadrature points and degrees of
|
||||
freedom. */
|
||||
/** When representing a vector-valued FiniteElement, two DofToQuad objects
|
||||
are used to describe the "closed" and "open" 1D basis functions
|
||||
(TODO). */
|
||||
TENSOR
|
||||
};
|
||||
|
||||
/// Describes the contents of the #B, #Bt, #G, and #Gt arrays, see #Mode.
|
||||
Mode mode;
|
||||
|
||||
/** @brief Number of degrees of freedom = number of basis functions. When
|
||||
#mode is TENSOR, this is the 1D number. */
|
||||
int ndof;
|
||||
|
||||
/** @brief Number of quadrature points. When #mode is TENSOR, this is the 1D
|
||||
number. */
|
||||
int nqpt;
|
||||
|
||||
/// Basis functions evaluated at quadrature points.
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #nqpt x #ndof, for scalar elements, or
|
||||
- #nqpt x dim x #ndof, for vector elements, (TODO)
|
||||
|
||||
where
|
||||
|
||||
- dim = dimension of the finite element reference space when #mode is
|
||||
FULL, and dim = 1 when #mode is TENSOR. */
|
||||
Array<double> B;
|
||||
|
||||
/// Transpose of #B.
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #ndof x #nqpt, for scalar elements, or
|
||||
- #ndof x #nqpt x dim, for vector elements (TODO). */
|
||||
Array<double> Bt;
|
||||
|
||||
/** @brief Gradients/divergences/curls of basis functions evaluated at
|
||||
quadrature points. */
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #nqpt x dim x #ndof, for scalar elements, or
|
||||
- #nqpt x #ndof, for H(div) vector elements (TODO), or
|
||||
- #nqpt x cdim x #ndof, for H(curl) vector elements (TODO),
|
||||
|
||||
where
|
||||
|
||||
- dim = dimension of the finite element reference space when #mode is
|
||||
FULL, and 1 when #mode is TENSOR,
|
||||
- cdim = 1/1/3 in 1D/2D/3D, respectively, when #mode is FULL, and cdim =
|
||||
1 when #mode is TENSOR. */
|
||||
Array<double> G;
|
||||
|
||||
/// Transpose of #G.
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #ndof x #nqpt x dim, for scalar elements, or
|
||||
- #ndof x #nqpt, for H(div) vector elements (TODO), or
|
||||
- #ndof x #nqpt x cdim, for H(curl) vector elements (TODO). */
|
||||
Array<double> Gt;
|
||||
};
|
||||
|
||||
// Base and derived classes for finite elements
|
||||
|
||||
/// Describes the space on each element
|
||||
class FunctionSpace
|
||||
@@ -211,7 +127,8 @@ public:
|
||||
{
|
||||
Pk, ///< Polynomials of order k
|
||||
Qk, ///< Tensor products of polynomials of order k
|
||||
rQk ///< Refined tensor products of polynomials of order k
|
||||
rQk,///< Refined tensor products of polynomials of order k
|
||||
SBPk///< Summation-by-parts operator of order k with no explicit basis
|
||||
};
|
||||
};
|
||||
|
||||
@@ -221,10 +138,6 @@ class VectorCoefficient;
|
||||
class MatrixCoefficient;
|
||||
class KnotVector;
|
||||
|
||||
|
||||
// Base and derived classes for finite elements
|
||||
|
||||
|
||||
/// Abstract class for Finite Elements
|
||||
class FiniteElement
|
||||
{
|
||||
@@ -241,10 +154,6 @@ protected:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable DenseMatrix vshape; // Dof x Dim
|
||||
#endif
|
||||
/// Container for all DofToQuad objects created by the FiniteElement.
|
||||
/** Multiple DofToQuad objects may be needed when different quadrature rules
|
||||
or different DofToQuad::Mode are used. */
|
||||
mutable Array<DofToQuad*> dof2quad_array;
|
||||
|
||||
public:
|
||||
/// Enumeration for RangeType and DerivRangeType
|
||||
@@ -510,13 +419,7 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &div) const;
|
||||
|
||||
/** Return a DofToQuad structure corresponding to the given IntegrationRule
|
||||
using the given DofToQuad::Mode. */
|
||||
/** See the documentation for DofToQuad for more details. */
|
||||
virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const;
|
||||
|
||||
virtual ~FiniteElement();
|
||||
virtual ~FiniteElement () { }
|
||||
|
||||
static bool IsClosedType(int b_type)
|
||||
{
|
||||
@@ -563,10 +466,6 @@ protected:
|
||||
return static_cast<const ScalarFiniteElement &>(fe);
|
||||
}
|
||||
|
||||
const DofToQuad &GetTensorDofToQuad(const class TensorBasisElement &tb,
|
||||
const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const;
|
||||
|
||||
public:
|
||||
ScalarFiniteElement(int D, Geometry::Type G, int Do, int O,
|
||||
int F = FunctionSpace::Pk)
|
||||
@@ -597,9 +496,6 @@ public:
|
||||
void ScalarLocalInterpolation(ElementTransformation &Trans,
|
||||
DenseMatrix &I,
|
||||
const ScalarFiniteElement &fine_fe) const;
|
||||
|
||||
virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const;
|
||||
};
|
||||
|
||||
class NodalFiniteElement : public ScalarFiniteElement
|
||||
@@ -1856,14 +1752,6 @@ class NodalTensorFiniteElement : public NodalFiniteElement,
|
||||
public:
|
||||
NodalTensorFiniteElement(const int dims, const int p, const int btype,
|
||||
const DofMapType dmtype);
|
||||
|
||||
const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
return (mode == DofToQuad::FULL) ?
|
||||
ScalarFiniteElement::GetDofToQuad(ir, mode) :
|
||||
ScalarFiniteElement::GetTensorDofToQuad(*this, ir, mode);
|
||||
}
|
||||
};
|
||||
|
||||
class PositiveTensorFiniteElement : public PositiveFiniteElement,
|
||||
@@ -1872,14 +1760,6 @@ class PositiveTensorFiniteElement : public PositiveFiniteElement,
|
||||
public:
|
||||
PositiveTensorFiniteElement(const int dims, const int p,
|
||||
const DofMapType dmtype);
|
||||
|
||||
const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
return (mode == DofToQuad::FULL) ?
|
||||
ScalarFiniteElement::GetDofToQuad(ir, mode) :
|
||||
ScalarFiniteElement::GetTensorDofToQuad(*this, ir, mode);
|
||||
}
|
||||
};
|
||||
|
||||
class H1_SegmentElement : public NodalTensorFiniteElement
|
||||
@@ -2941,6 +2821,44 @@ public:
|
||||
DenseMatrix &dshape) const;
|
||||
};
|
||||
|
||||
/// Class for summation-by-parts operator on interval
|
||||
class SBP_SegmentElement : public NodalTensorFiniteElement
|
||||
{
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, dshape_x;
|
||||
#endif
|
||||
|
||||
public:
|
||||
SBP_SegmentElement(const int p);
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
|
||||
// ProjectDelta is leftover function from H1_SegmentElement
|
||||
// virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
};
|
||||
|
||||
/// Class for (diagonal-norm) summation-by-parts operator on triangles
|
||||
class SBP_TriangleElement : public NodalFiniteElement
|
||||
{
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, shape_y, shape_l, dshape_x, dshape_y, dshape_l, u;
|
||||
mutable Vector ddshape_x, ddshape_y, ddshape_l;
|
||||
mutable DenseMatrix du, ddu;
|
||||
#endif
|
||||
DenseMatrix *Dx, *Dy;
|
||||
std::unordered_map<const IntegrationPoint*, int> ipIdxMap;
|
||||
|
||||
public:
|
||||
SBP_TriangleElement(const int p, const int Do);
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual ~SBP_TriangleElement();
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
+159
@@ -274,6 +274,10 @@ FiniteElementCollection *FiniteElementCollection::New(const char *name)
|
||||
fec = new NURBSFECollection();
|
||||
}
|
||||
}
|
||||
else if (!strncmp(name, "SBP_", 4))
|
||||
{
|
||||
fec = new C_SBPCollection(atoi(name+8), atoi(name+4));
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("unknown FiniteElementCollection: " << name);
|
||||
@@ -2542,4 +2546,159 @@ FiniteElementCollection *NURBSFECollection::GetTraceCollection() const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
C_SBPCollection::C_SBPCollection(const int p, const int dim)
|
||||
{
|
||||
MFEM_VERIFY(p >= 0 && p <= 4, "C_SBPCollection requires 0 <= order <= 4.");
|
||||
MFEM_VERIFY(dim == 2, "C_SBPCollection requires dim == 2.");
|
||||
|
||||
snprintf(c_SBPname, 32, "SBP_%dD_P%d", dim, p);
|
||||
|
||||
for (int g = 0; g < Geometry::NumGeom; g++)
|
||||
{
|
||||
C_SBPdof[g] = 0;
|
||||
C_SBPElements[g] = NULL;
|
||||
}
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
SegDofOrd[i] = NULL;
|
||||
}
|
||||
|
||||
C_SBPdof[Geometry::POINT] = 1;
|
||||
C_SBPElements[Geometry::POINT] = new PointFiniteElement;
|
||||
|
||||
if (dim >= 1)
|
||||
{
|
||||
C_SBPdof[Geometry::SEGMENT] = p;
|
||||
|
||||
C_SBPElements[Geometry::SEGMENT] = new SBP_SegmentElement(p);
|
||||
|
||||
int nodeOrder0[] = {};
|
||||
int nodeOrder1[1] = {0};
|
||||
int nodeOrder2[2] = {0, 1};
|
||||
int nodeOrder3[3] = {0, 1, 2};
|
||||
int nodeOrder4[4] = {0, 1, 2, 3};
|
||||
|
||||
int revNodeOrder0[] = {};
|
||||
int revNodeOrder1[1] = {0};
|
||||
int revNodeOrder2[2] = {1, 0};
|
||||
int revNodeOrder3[3] = {0, 2, 1};
|
||||
int revNodeOrder4[4] = {1, 0, 3, 2};
|
||||
|
||||
switch (p)
|
||||
{
|
||||
case 0:
|
||||
SegDofOrd[0] = new int[p];
|
||||
SegDofOrd[1] = new int[p];
|
||||
for (int i = 0; i < p; i++)
|
||||
{
|
||||
SegDofOrd[0][i] = nodeOrder0[i];
|
||||
SegDofOrd[1][i] = revNodeOrder0[i];
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
SegDofOrd[0] = new int[p];
|
||||
SegDofOrd[1] = new int[p];
|
||||
for (int i = 0; i < p; i++)
|
||||
{
|
||||
SegDofOrd[0][i] = nodeOrder1[i];
|
||||
SegDofOrd[1][i] = revNodeOrder1[i];
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
SegDofOrd[0] = new int[p];
|
||||
SegDofOrd[1] = new int[p];
|
||||
for (int i = 0; i < p; i++)
|
||||
{
|
||||
SegDofOrd[0][i] = nodeOrder2[i];
|
||||
SegDofOrd[1][i] = revNodeOrder2[i];
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
SegDofOrd[0] = new int[p];
|
||||
SegDofOrd[1] = new int[p];
|
||||
for (int i = 0; i < p; i++)
|
||||
{
|
||||
SegDofOrd[0][i] = nodeOrder3[i];
|
||||
SegDofOrd[1][i] = revNodeOrder3[i];
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
SegDofOrd[0] = new int[p];
|
||||
SegDofOrd[1] = new int[p];
|
||||
for (int i = 0; i < p; i++)
|
||||
{
|
||||
SegDofOrd[0][i] = nodeOrder4[i];
|
||||
SegDofOrd[1][i] = revNodeOrder4[i];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mfem_error("SBP elements are currently only supported for 0 <= order <= 4");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (dim >= 2)
|
||||
{
|
||||
switch (p)
|
||||
{
|
||||
case 0:
|
||||
C_SBPdof[Geometry::TRIANGLE] = 3 - 3 - 3*p;
|
||||
break;
|
||||
case 1:
|
||||
C_SBPdof[Geometry::TRIANGLE] = 7 - 3 - 3*p;
|
||||
break;
|
||||
case 2:
|
||||
C_SBPdof[Geometry::TRIANGLE] = 12 - 3 - 3*p;
|
||||
break;
|
||||
case 3:
|
||||
C_SBPdof[Geometry::TRIANGLE] = 18 - 3 - 3*p;
|
||||
break;
|
||||
case 4:
|
||||
C_SBPdof[Geometry::TRIANGLE] = 27 - 3 - 3*p;
|
||||
break;
|
||||
default:
|
||||
mfem_error("SBP elements are currently only supported for 0 <= order <= 4");
|
||||
break;
|
||||
}
|
||||
|
||||
const int &TriDof = C_SBPdof[Geometry::TRIANGLE] + 3*C_SBPdof[Geometry::POINT] + 3*C_SBPdof[Geometry::SEGMENT];
|
||||
|
||||
C_SBPElements[Geometry::TRIANGLE] = new SBP_TriangleElement(p, TriDof);
|
||||
}
|
||||
}
|
||||
|
||||
const FiniteElement *C_SBPCollection::FiniteElementForGeometry(
|
||||
Geometry::Type GeomType) const
|
||||
{
|
||||
if (GeomType == Geometry::TRIANGLE || GeomType == Geometry::SEGMENT || GeomType == Geometry::POINT)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unsupported geometry type " << GeomType);
|
||||
}
|
||||
return C_SBPElements[GeomType];
|
||||
}
|
||||
|
||||
const int *C_SBPCollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const
|
||||
{
|
||||
if (GeomType == Geometry::SEGMENT)
|
||||
{
|
||||
return (Or > 0) ? SegDofOrd[0] : SegDofOrd[1];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
C_SBPCollection::~C_SBPCollection()
|
||||
{
|
||||
delete [] SegDofOrd[0];
|
||||
for (int g = 0; g < Geometry::NumGeom; g++)
|
||||
{
|
||||
delete C_SBPElements[g];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -884,6 +884,30 @@ public:
|
||||
virtual ~Local_FECollection() { delete Local_Element; }
|
||||
};
|
||||
|
||||
/// Arbitrary order H1-conforming (continuous) Summation By Parts
|
||||
/// opperators.
|
||||
class C_SBPCollection : public FiniteElementCollection
|
||||
{
|
||||
|
||||
protected:
|
||||
char c_SBPname[32];
|
||||
FiniteElement *C_SBPElements[Geometry::NumGeom];
|
||||
int C_SBPdof[Geometry::NumGeom];
|
||||
int *SegDofOrd[2];
|
||||
|
||||
public:
|
||||
explicit C_SBPCollection(const int p, const int dim = 2);
|
||||
|
||||
virtual const FiniteElement *FiniteElementForGeometry(
|
||||
Geometry::Type GeomType) const;
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const
|
||||
{ return C_SBPdof[GeomType]; }
|
||||
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const;
|
||||
virtual const char *Name() const { return c_SBPname; }
|
||||
virtual ~C_SBPCollection();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/// SBP Triangle Dx and Dy matrix data arrays, stored column major format
|
||||
const double p0Dx[9] = {-0.9999999999999984,-1.000000000000001,-0.9999999999999988,
|
||||
1.000000000000001,0.9999999999999974,0.9999999999999994,
|
||||
1.3322676295501878e-15,-1.9984014443252818e-15,9.992007221626409e-16};
|
||||
const double p0Dy[9] = {-0.9999999999999974,-0.9999999999999994,-1.0000000000000009,
|
||||
1.9984014443252818e-15,-9.992007221626409e-16,-1.7486012637846216e-15,
|
||||
1.0000000000000009,0.9999999999999991,0.9999999999999984};
|
||||
const double p1Dx[49] = {-3.333333333333333, 0.21647921352995003, 0.10823960676497299, -0.8824293926518367, 0.7863909022744312, -0.051249687578105226, -0.362809297675581,
|
||||
-0.21647921352995003, 3.333333333333333, -0.10823960676497392, 0.8824293926518368, 0.05124968757810527, -0.7863909022744306, 0.3628092976755813,
|
||||
-0.10823960676497299, 0.10823960676497392, 0.0, 7.406681257404114e-16, -0.8311797050737315, 0.8311797050737307, -1.9769834191462048e-16,
|
||||
2.3531450470715645, -2.353145047071565, -1.9751150019744302e-15, 0.0, -0.2351412146963257, 0.23514121469632399, 3.1540140465066577e-17,
|
||||
-2.09704240606515, -0.13666583354161405, 2.2164792135299507, 0.2351412146963257, 5.0, 0.47028242939265, 1.2743814046488378,
|
||||
0.13666583354161393, 2.0970424060651482, -2.2164792135299485, -0.23514121469632399, -0.47028242939265, -5.0, -1.2743814046488378,
|
||||
3.2652836790802304, -3.2652836790802326, 1.7792850772315852e-15, -1.0644797406959973e-16, -4.301037240689829, 4.301037240689829, 0.0};
|
||||
const double p1Dy[49] = {-3.333333333333333, 0.10823960676497733, 0.21647921352994814, -0.0512496875781027, 0.7863909022744318, -0.8824293926518388, -0.3628092976755811,
|
||||
-0.10823960676497733, 0.0, 0.10823960676497837, 0.8311797050737281, -0.8311797050737287, 9.745633233426465e-17, -3.4329014409980615e-16,
|
||||
-0.21647921352994814, -0.10823960676497837, 3.333333333333333, -0.7863909022744319, 0.051249687578102346, 0.8824293926518396, 0.3628092976755813,
|
||||
0.1366658335416072, -2.216479213529942, 2.0970424060651514, -5.0, -0.4702824293926414, -0.23514121469633495, -1.274381404648838,
|
||||
-2.0970424060651514, 2.216479213529943, -0.13666583354160625, 0.4702824293926414, 5.0, 0.235141214696336, 1.2743814046488384,
|
||||
2.3531450470715702, -2.5988355289137243e-16, -2.3531450470715725, 0.23514121469633495, -0.235141214696336, 0.0, 3.7848168558079887e-16,
|
||||
3.2652836790802313, 3.0896112968982564e-15, -3.2652836790802326, 4.30103724068983, -4.301037240689832, -1.2773756888351966e-15, 0.0};
|
||||
|
||||
const double p2Dx[144] = {-6.654819485608504, -0.2644800033235228, -0.13224000166175998, -1.4588736121976598, 0.16568196946098376, -0.18364010800322192, -0.49629408766969996, 0.18676496181247967, -0.32850861828832895, 0.17877251381228318, -0.18297783134208934, 0.16855922332582518,
|
||||
0.2644800033235228, 6.654819485608504, 0.13224000166176486, -0.1656819694609847, 1.4588736121976598, 0.3285086182883251, -0.18676496181248323, 0.4962940876696997, 0.18364010800322153, -0.1787725138122836, -0.16855922332582482, 0.18297783134208834,
|
||||
0.13224000166175998, -0.13224000166176486, 0.0, -0.31265397966647923, 0.3126539796664765, -0.021082992351498762, -1.1303649939093317, 1.1303649939093305, 0.0210829923514981, -3.1850260779507576e-16, 0.010213290486458549, -0.010213290486458991,
|
||||
6.25007885298757, 0.7098115731146227, 1.3394662911697857, 0.0, -1.0987526276656132, 0.8391459038761706, -0.7493297423228898, -1.0608454694676046, 0.7982718911706455, 0.47711018331982885, -0.20709875867432972, -0.4372738402113571,
|
||||
-0.7098115731146187, -6.25007885298757, -1.339466291169774, 1.0987526276656132, 0.0, -0.7982718911706481, 1.0608454694676077, 0.7493297423228901, -0.8391459038761684, -0.47711018331982796, 0.4372738402113582, 0.20709875867432867,
|
||||
0.7867474920341369, -1.407390435347625, 0.09032335875573284, -0.8391459038761706, 0.7982718911706481, 7.766734444360106, 0.549376313832808, -1.8999913733437686, 1.4986594846457786, 0.7173852412251129, -0.7042577654543215, 1.9425023749691277,
|
||||
2.126213783203917, 0.8001349318703544, 4.842688417639932, 0.7493297423228898, -1.0608454694676077, -0.549376313832808, 7.766734444360106, 1.5965437823412956, -1.8999913733437699, 1.7354036162948008, -0.2271475821344933, 0.2801114010137556,
|
||||
-0.8001349318703392, -2.1262137832039163, -4.842688417639927, 1.0608454694676046, -0.7493297423228901, 1.8999913733437686, -1.5965437823412956, -7.766734444360106, 0.5493763138328077, -1.7354036162947999, -0.28011140101375603, 0.22714758213449346,
|
||||
1.4073904353476412, -0.7867474920341352, -0.09032335875573, -0.7982718911706455, 0.8391459038761684, -1.4986594846457786, 1.8999913733437699, -0.5493763138328077, -7.766734444360106, -0.7173852412251128, -1.9425023749691277, 0.7042577654543228,
|
||||
-3.0482350464695736, 3.0482350464695807, 5.4307610872012924e-15, -1.8988845609884182, 1.8988845609884146, -2.8551722567827746, -6.906855584460779, 6.906855584460776, 2.855172256782774, 0.0, 1.0883892687387082, -1.088389268738702,
|
||||
3.11993956078517, 2.8740890922806273, -0.1741459541889496, 0.8242469961764219, -1.7403370817278376, 2.8029252875555524, 0.904040726567137, 1.114835175054942, 7.73110258063719, -1.0883892687387082, 0.0, -2.176778537477416,
|
||||
-2.8740890922806335, -3.119939560785153, 0.17414595418895715, 1.7403370817278334, -0.8242469961764177, -7.73110258063719, -1.1148351750549401, -0.9040407265671375, -2.8029252875555577, 1.088389268738702, 2.176778537477416, 0.0};
|
||||
|
||||
const double p2Dy[144] = {-6.654819485608504, -0.13224000166176303, -0.26448000332352145, -0.3285086182883249, 0.1867649618124839, -0.49629408766970096, -0.18364010800322322, 0.16568196946098196, -1.4588736121976569, 0.16855922332582438, -0.1829778313420883, 0.17877251381228437,
|
||||
0.13224000166176303, 0.0, -0.13224000166176358, 0.021082992351497333, 1.1303649939093325, -1.13036499390933, -0.0210829923514987, 0.31265397966647596, -0.3126539796664774, -0.010213290486459194, 0.010213290486458717, 1.7550143694830702e-16,
|
||||
0.26448000332352145, 0.13224000166176358, 6.654819485608504, 0.18364010800321912, 0.49629408766969646, -0.18676496181248112, 0.32850861828832506, 1.4588736121976555, -0.16568196946098368, 0.18297783134208803, -0.16855922332582496, -0.17877251381228357,
|
||||
1.4073904353476239, -0.09032335875572672, -0.7867474920341248, -7.766734444360106, -0.5493763138328086, 1.8999913733437714, -1.498659484645771, 0.8391459038761694, -0.7982718911706419, 0.7042577654543205, -1.9425023749691286, -0.7173852412251152,
|
||||
-0.8001349318703573, -4.842688417639936, -2.1262137832039025, 0.5493763138328086, -7.766734444360106, -1.5965437823412931, 1.8999913733437763, -0.7493297423228881, 1.060845469467605, 0.22714758213449282, -0.28011140101375637, -1.7354036162948017,
|
||||
2.1262137832039216, 4.842688417639926, 0.8001349318703455, -1.8999913733437714, 1.5965437823412931, 7.766734444360106, -0.5493763138328039, -1.0608454694675977, 0.7493297423228871, 0.280111401013755, -0.22714758213449193, 1.7354036162947997,
|
||||
0.7867474920341424, 0.09032335875573258, -1.4073904353476248, 1.498659484645771, -1.8999913733437763, 0.5493763138328039, 7.766734444360106, 0.7982718911706495, -0.8391459038761694, 1.942502374969129, -0.7042577654543208, 0.7173852412251135,
|
||||
-0.709811573114611, -1.3394662911697717, -6.250078852987552, -0.8391459038761694, 0.7493297423228881, 1.0608454694675977, -0.7982718911706495, 0.0, 1.0987526276656179, 0.20709875867432867, 0.43727384021135907, -0.47711018331982974,
|
||||
6.250078852987558, 1.339466291169778, 0.7098115731146183, 0.7982718911706419, -1.060845469467605, -0.7493297423228871, 0.8391459038761694, -1.0987526276656179, 0.0, -0.4372738402113571, -0.20709875867432725, 0.4771101833198306,
|
||||
-2.8740890922806197, 0.17414595418896062, -3.1199395607851477, -2.8029252875555484, -0.904040726567135, -1.114835175054938, -7.731102580637195, -0.8242469961764177, 1.7403370817278334, 0.0, 2.1767785374774147, 1.0883892687387102,
|
||||
3.119939560785152, -0.17414595418895248, 2.8740890922806295, 7.731102580637194, 1.1148351750549435, 0.9040407265671315, 2.8029252875555497, -1.7403370817278412, 0.8242469961764122, -2.1767785374774147, 0.0, -1.0883892687387073,
|
||||
-3.048235046469594, -2.9924601909068347e-15, 3.04823504646958, 2.8551722567827835, 6.906855584460783, -6.906855584460775, -2.855172256782777, 1.8988845609884217, -1.8988845609884253, -1.0883892687387102, 1.0883892687387073, 0.0};
|
||||
|
||||
const double p3Dx[324] = {-10.952585131486583, -0.1691685246371182, -0.08458426231856121, 0.2782043329268357, -2.305479077267717, -0.07465619884488185, 0.08251879096720546, 0.22849304912079002, 0.5302407771816927, 0.28327860677318784, -0.11951297527437506, -0.5003055437372067, 0.12448476066856992, -0.09239160861978224, 0.10362923976480765, -0.16947318256573993, -0.12955658105892584, -0.0720914264099959,
|
||||
0.1691685246371182, 10.952585131486583, 0.08458426231855752, -0.2782043329268405, 0.0746561988448885, 2.3054790772677194, -0.2832786067731876, 0.5003055437372037, 0.11951297527437463, -0.08251879096721035, -0.5302407771816938, -0.2284930491207896, -0.12448476066856932, -0.10362923976480676, 0.09239160861978266, 0.16947318256574107, 0.07209142640999573, 0.12955658105892595,
|
||||
0.08458426231856121, -0.08458426231855752, 0.0, 1.1683416656308464e-15, 0.3017477280608998, -0.3017477280609013, -0.005074273846349578, 0.04485677642949094, -1.8051735335305155, 0.0050742738463512614, 1.805173533530519, -0.04485677642949147, 4.205982075638532e-16, 0.020855520903763268, -0.020855520903761818, 7.395777588076851e-16, -0.0973817561557449, 0.09738175615574554,
|
||||
-1.8896690623176595, 1.8896690623176922, -7.935818527815355e-15, 0.0, 2.0050512471695137, -2.0050512471695145, -0.8926105190374908, 1.6696076717446249, 0.020736328416563414, 0.8926105190375015, -0.020736328416544252, -1.669607671744625, -4.429107086712402e-16, 0.4633133883374836, -0.46331338833748054, 1.783666940029547e-15, 0.7834980551346994, -0.783498055134701,
|
||||
11.456452196936608, -0.3709837064689789, -1.4994533917700335, -1.4668732071255282, 0.0, 0.43808614602067847, -0.03454227374421423, -0.36820417663301963, 0.6765153661826107, -1.2393619133905875, 1.2485385227460366, 1.2932580655616601, -0.24307113935772914, 0.052425055137118155, 0.44269118420721065, -0.48976278487794334, -0.3768721550070895, 0.17743932374896715,
|
||||
0.3709837064689459, -11.45645219693662, 1.4994533917700408, 1.4668732071255288, -0.43808614602067847, 0.0, 1.2393619133905824, -1.2932580655616563, -1.2485385227460208, 0.034542273744204106, -0.6765153661826184, 0.36820417663302096, 0.24307113935772948, -0.44269118420720915, -0.052425055137118384, 0.4897627848779442, -0.1774393237489731, 0.3768721550070885,
|
||||
-0.5604988416610844, 1.924135449667926, 0.03446638735025072, 0.8926105190374908, 0.04721541624352583, -1.6940688111740314, 11.466536000042892, -1.1244968786658345, 0.8805543685036823, 1.785221038074984, -3.363676482918665, 0.026479087826965113, -0.42363907421033664, 2.460011157605557, -0.8869524625478119, 1.3603474091530658, 0.13068371284607608, 0.5768493540183615,
|
||||
-1.135434157870106, -2.486132536271146, -0.22290356912810128, -1.2214664156593342, 0.36820417663301963, 1.2932580655616563, 0.8226694181207354, 12.000000000000005, -0.21904307301033732, 0.01937180635024931, 1.6167426993790468, -1.3530307323652335, -0.6132774672199158, 0.43432201350751304, -0.11093602189671813, -0.6100947628964166, 0.7813784140227625, 2.7998077074825853,
|
||||
-2.634887549640154, -0.5938872755970562, 8.97031966066547, -0.01517046739396432, -0.6765153661826107, 1.2485385227460208, -0.6442037890047951, 0.21904307301033732, 12.000000000000005, -2.460828329049918, 2.586516131123318, 1.6167426993790477, -0.0585109667596005, 0.19125087414978273, -0.17058628301270465, 2.4229355524754963, 0.29161562914482175, -0.43265543914744503,
|
||||
-1.9241354496679275, 0.5604988416611175, -0.034466387350262154, -0.8926105190375015, 1.6940688111740383, -0.047215416243512, -1.785221038074984, -0.026479087826961595, 3.3636764829186583, -11.466536000042892, -0.8805543685036843, 1.1244968786658245, 0.42363907421033115, 0.8869524625478146, -2.4600111576055554, -1.3603474091530607, -0.5768493540183651, -0.13068371284607755,
|
||||
0.5938872755970585, 2.634887549640159, -8.97031966066549, 0.0151704673939503, -1.2485385227460366, 0.6765153661826184, 2.460828329049923, -1.6167426993790468, -2.586516131123318, 0.6442037890047966, -12.000000000000005, -0.21904307301033812, 0.05851096675959981, 0.17058628301270434, -0.19125087414978267, -2.422935552475496, 0.43265543914744814, -0.29161562914482114,
|
||||
2.486132536271161, 1.1354341578701037, 0.22290356912810394, 1.2214664156593344, -1.2932580655616601, -0.36820417663302096, -0.019371806350251885, 1.3530307323652335, -1.6167426993790477, -0.822669418120728, 0.21904307301033812, -12.000000000000005, 0.613277467219916, 0.11093602189671813, -0.43432201350751237, 0.6100947628964153, -2.7998077074825867, -0.7813784140227636,
|
||||
-4.072657651361357, 4.072657651361338, -1.3760339008438063e-14, 2.133320141015979e-15, 1.6003174861462979, -1.6003174861463, 2.0404965421712293, 4.037660156795314, 0.38522106525739636, -2.0404965421712027, -0.38522106525739186, -4.037660156795315, 0.0, -1.4579314260766258, 1.4579314260766234, 2.0161871961592337e-15, 3.273923136675281, -3.2739231366752755,
|
||||
3.0226944225627097, 3.3903460469074083, -0.6823116044539523, -2.2315915230588144, -0.34515299788282433, 2.914564209151067, -11.84886986676902, -2.859463754812241, -1.2591462686659354, -4.272088065230016, -1.1230959476442317, -0.7303740631402172, 1.4579314260766258, 0.0, 2.9158628521532504, 1.6703256795818853, -0.3883097004508776, -1.603597457093401,
|
||||
-3.390346046907437, -3.022694422562723, 0.6823116044539049, 2.2315915230587997, -2.914564209151077, 0.34515299788282583, 4.272088065230004, 0.7303740631402172, 1.1230959476442337, 11.84886986676901, 1.2591462686659352, 2.8594637548122366, -1.4579314260766234, -2.9158628521532504, 0.0, -1.6703256795818826, 1.6035974570934062, 0.3883097004508795,
|
||||
3.825058001824472, -3.8250580018244977, -1.669248067139698e-14, -5.926918282616925e-15, 2.2245074239726854, -2.2245074239726894, -4.520276599333233, 2.771056460992968, -11.004997298094699, 4.520276599333215, 11.004997298094697, -2.7710564609929618, -1.3909328887646931e-15, -1.1523289737701476, 1.1523289737701459, 0.0, -0.9410755641839665, 0.9410755641839751,
|
||||
2.9241289363066816, -1.6271240279890726, 2.1979339738354153, -2.6034731278339045, 1.7117570640055604, 0.8059311674378296, -0.4342468145397358, -3.5490285023571575, -1.3245210783844836, 1.9168034714993238, -1.9651252935551593, 12.716754362100263, -2.258623293890646, 0.26788818737287284, -1.1062943201205055, 0.9410755641839665, 0.0, 1.8821511283679513,
|
||||
1.6271240279890764, -2.9241289363066834, -2.1979339738354295, 2.60347312783391, -0.8059311674378026, -1.711757064005556, -1.9168034714993114, -12.716754362100257, 1.9651252935551453, 0.4342468145397406, 1.324521078384481, 3.5490285023571624, 2.258623293890642, 1.106294320120502, -0.2678881873728741, -0.9410755641839751, -1.8821511283679513, 0.0};
|
||||
|
||||
const double p3Dy[324] = {-10.952585131486583, -0.08458426231856092, -0.16916852463712426, 0.28327860677318756, -0.5003055437372038, -0.11951297527437327, 0.0825187909672079, 0.5302407771816892, 0.22849304912079044, 0.2782043329268377, -0.07465619884488649, -2.305479077267721, 0.1036292397648074, -0.09239160861978217, 0.12448476066856967, -0.07209142640999439, -0.12955658105892628, -0.16947318256574065,
|
||||
0.08458426231856092, 0.0, -0.08458426231857115, 0.00507427384635043, -0.044856776429489494, 1.8051735335305168, -0.005074273846348987, -1.805173533530519, 0.04485677642949065, -2.536797215167323e-16, -0.30174772806090094, 0.3017477280609018, -0.020855520903761887, 0.020855520903762893, 3.895409306444457e-16, 0.09738175615574617, -0.09738175615574511, -2.518495690291951e-17,
|
||||
0.16916852463712426, 0.08458426231857115, 10.952585131486583, -0.08251879096720664, -0.2284930491207953, -0.5302407771816934, -0.2832786067731896, 0.11951297527436967, 0.5003055437372073, -0.2782043329268386, 2.305479077267721, 0.07465619884488589, 0.09239160861978252, -0.10362923976480695, -0.12448476066856902, 0.12955658105892542, 0.07209142640999575, 0.1694731825657405,
|
||||
-1.9241354496679255, -0.034466387350256505, 0.5604988416610924, -11.466536000042892, 1.124496878665824, -0.8805543685036857, -1.7852210380749862, 3.3636764829186614, -0.026479087826939977, -0.8926105190374863, -0.04721541624350879, 1.6940688111740283, -2.4600111576055577, 0.8869524625478143, 0.42363907421033403, -0.13068371284608143, -0.5768493540183609, -1.3603474091530663,
|
||||
2.4861325362711466, 0.2229035691280941, 1.1354341578701321, -0.8226694181207276, -12.000000000000005, 0.21904307301034107, -0.01937180635025535, -1.6167426993790432, 1.3530307323652313, 1.2214664156593333, -0.3682041766330094, -1.2932580655616668, -0.4343220135075129, 0.11093602189671664, 0.6132774672199158, -0.7813784140227632, -2.799807707482588, 0.6100947628964168,
|
||||
0.5938872755970495, -8.97031966066548, 2.634887549640157, 0.6442037890047976, -0.21904307301034107, -12.000000000000005, 2.4608283290499164, -2.586516131123313, -1.6167426993790395, 0.015170467393960869, 0.6765153661826211, -1.2485385227460257, -0.19125087414978525, 0.17058628301270676, 0.058510966759598895, -0.2916156291448204, 0.43265543914744725, -2.4229355524754985,
|
||||
-0.560498841661101, 0.03446638735024671, 1.9241354496679397, 1.7852210380749862, 0.026479087826969852, -3.363676482918656, 11.466536000042892, 0.8805543685036855, -1.1244968786658387, 0.8926105190374908, -1.6940688111740407, 0.047215416243521366, -0.8869524625478177, 2.460011157605558, -0.4236390742103285, 0.5768493540183687, 0.13068371284607674, 1.360347409153062,
|
||||
-2.634887549640136, 8.97031966066549, -0.5938872755970316, -2.4608283290499204, 1.6167426993790432, 2.586516131123313, -0.6442037890047975, 12.000000000000005, 0.2190430730103402, -0.015170467393955334, 1.2485385227460235, -0.6765153661826085, -0.17058628301270545, 0.19125087414978356, -0.05851096675960009, -0.432655439147446, 0.2916156291448159, 2.4229355524755003,
|
||||
-1.135434157870108, -0.22290356912809986, -2.4861325362711635, 0.019371806350233497, -1.3530307323652313, 1.6167426993790395, 0.8226694181207385, -0.2190430730103402, 12.000000000000005, -1.221466415659336, 1.2932580655616515, 0.3682041766330148, -0.11093602189671982, 0.43432201350751376, -0.6132774672199166, 2.7998077074825862, 0.781378414022764, -0.6100947628964163,
|
||||
-1.889669062317673, 1.72308862498413e-15, 1.8896690623176793, 0.8926105190374863, -1.6696076717446235, -0.0207363284165587, -0.8926105190374908, 0.020736328416551132, 1.669607671744627, 0.0, -2.005051247169507, 2.005051247169518, -0.46331338833748403, 0.4633133883374836, -7.923728999874815e-16, -0.7834980551347012, 0.7834980551346985, 2.487535508292328e-15,
|
||||
0.37098370646896894, 1.499453391770039, -11.456452196936628, 0.03454227374420177, 0.3682041766330094, -0.6765153661826211, 1.2393619133905893, -1.2485385227460235, -1.2932580655616515, 1.4668732071255233, 0.0, -0.43808614602068285, -0.0524250551371181, -0.44269118420721065, 0.24307113935773086, 0.37687215500708976, -0.17743932374896845, 0.48976278487794267,
|
||||
11.456452196936628, -1.4994533917700434, -0.37098370646896595, -1.2393619133905802, 1.2932580655616668, 1.2485385227460257, -0.03454227374421096, 0.6765153661826085, -0.3682041766330148, -1.4668732071255315, 0.43808614602068285, 0.0, 0.44269118420721193, 0.05242505513711802, -0.24307113935772984, 0.17743932374897087, -0.37687215500708626, -0.48976278487794556,
|
||||
-3.3903460469074287, 0.682311604453907, -3.022694422562719, 11.848869866769022, 2.85946375481224, 1.2591462686659523, 4.272088065230031, 1.123095947644239, 0.7303740631402283, 2.2315915230588166, 0.34515299788282394, -2.9145642091510853, 0.0, -2.9158628521532504, -1.4579314260766258, 0.3883097004508778, 1.6035974570934002, -1.6703256795818757,
|
||||
3.0226944225627075, -0.68231160445394, 3.3903460469074145, -4.272088065230015, -0.7303740631402075, -1.1230959476442475, -11.848869866769023, -1.259146268665941, -2.859463754812246, -2.2315915230588144, 2.914564209151077, -0.3451529978828235, 2.9158628521532504, 0.0, 1.4579314260766267, -1.6035974570933964, -0.3883097004508765, 1.6703256795818802,
|
||||
-4.072657651361349, -1.2744265588712169e-14, 4.072657651361328, -2.040496542171217, -4.037660156795314, -0.3852210652573858, 2.04049654217119, 0.3852210652573937, 4.037660156795319, 3.816536908330339e-15, -1.6003174861463092, 1.6003174861463025, 1.4579314260766258, -1.4579314260766267, 0.0, -3.2739231366752795, 3.273923136675281, -1.5485517097979382e-15,
|
||||
1.6271240279890422, -2.1979339738354438, -2.924128936306672, 0.43424681453975356, 3.5490285023571606, 1.3245210783844776, -1.9168034714993356, 1.9651252935551495, -12.71675436210026, 2.6034731278339103, -1.7117570640055617, -0.8059311674378195, -0.26788818737287295, 1.1062943201204989, 2.2586232938906448, 0.0, -1.8821511283679437, -0.941075564183975,
|
||||
2.9241289363066914, 2.1979339738354198, -1.627124027989073, 1.9168034714993096, 12.71675436210027, -1.9651252935551553, -0.434246814539738, -1.324521078384457, -3.549028502357164, -2.6034731278339014, 0.8059311674378086, 1.7117570640055457, -1.1062943201205013, 0.26788818737287207, -2.258623293890646, 1.8821511283679437, 0.0, 0.9410755641839769,
|
||||
3.825058001824488, 5.68431650770163e-16, -3.825058001824485, 4.520276599333235, -2.7710564609929693, 11.00499729809471, -4.5202765993332195, -11.004997298094716, 2.7710564609929667, -8.265791864994906e-15, -2.2245074239726823, 2.2245074239726956, 1.152328973770141, -1.152328973770144, 1.0683192052870465e-15, 0.941075564183975, -0.9410755641839769, 0.0};
|
||||
|
||||
const double p4Dx[729] = {-15.28499617463146, 0.1965429454017319, 0.09827147270087869, 0.4207579292099769, -0.03011871770800639, -3.318562255325795, -0.12660138709292057, -0.20489551789966803, -0.1525100012592784, -0.02465488205886147, -0.44232233201277743, -0.16408537644014787, 0.28709832395121765, 0.06989189152237547, -0.445234967991587, 0.1446267442307163, -0.13342014677484493, 0.04884580398085625, -0.06120785634410805, -0.0065053622920859784, -0.055536979099377465, -0.05310883929020609, 0.137613494649232, 0.09694858537476729, 0.05875484376287877, 0.11266078234486253, -0.10900916485152536,
|
||||
-0.1965429454017319, 15.28499617463146, -0.09827147270085763, 0.030118717708007003, -0.42075792920997546, 0.12660138709291616, 3.318562255325798, -0.28709832395121665, 0.16408537644014565, 0.4452349679915819, -0.06989189152237295, 0.15251000125928654, 0.20489551789967583, 0.44232233201277626, 0.024654882058862064, -0.14462674423071573, -0.048845803980857666, 0.13342014677484318, 0.06120785634410922, 0.055536979099377264, 0.006505362292085202, -0.13761349464923325, 0.0531088392902052, 0.10900916485152572, -0.11266078234486292, -0.05875484376287771, -0.09694858537476635,
|
||||
-0.09827147270087869, 0.09827147270085763, 0.0, 0.05238551664039212, -0.05238551664039154, -0.41766744995391064, 0.41766744995391425, 0.13396665873213762, 0.13365960525875686, -0.19649327861528906, -2.87332728733421, -0.1336596052587585, -0.13396665873213948, 2.873327287334207, 0.19649327861529092, 7.071416687303329e-16, 0.0957809402498582, -0.09578094024985911, 5.095198309682238e-16, -0.005670877244732207, 0.005670877244731516, -0.0381937416118884, 0.03819374161188797, 0.024952712304370763, 0.055900325561320505, -0.05590032556132075, -0.02495271230436985,
|
||||
-2.688383016538256, -0.19243998400255485, -0.3347110618046863, 0.0, -1.8584179757445634, 2.9254109394468375, 0.5544784209743959, -0.09619204170147806, 0.9621335517719756, -0.7640240022365051, -0.17045575971749122, -0.32599503457469536, 1.5819839652391803, -0.1673484738314025, -2.1466117678065375, 0.20084022575022525, 0.8121668775566188, 0.28698839120282377, 0.22242408399761535, 0.1007642564284906, 0.1396610379722831, -0.4047350379804057, -0.19103788701331148, -0.4861845324334061, 0.0708248987102739, -0.5390429074476013, 0.02706866117436579,
|
||||
0.1924399840025509, 2.688383016538247, 0.3347110618046826, 1.8584179757445634, 0.0, -0.5544784209744025, -2.9254109394468055, -1.5819839652391763, 0.32599503457469153, 2.1466117678065477, 0.1673484738314174, -0.9621335517719789, 0.09619204170146632, 0.1704557597174755, 0.7640240022365011, -0.20084022575022814, -0.28698839120282255, -0.8121668775566167, -0.22242408399761296, -0.13966103797228493, -0.10076425642849256, 0.19103788701331245, 0.40473503798040156, -0.027068661174367476, 0.5390429074475989, -0.07082489871027405, 0.48618453243340803,
|
||||
16.79909075460827, -0.6408763879659072, 2.114299162464476, -2.3177353997619106, 0.43930042352937404, 0.0, 0.23758827371798064, 0.14587872928125803, -0.026683834684955113, 0.27594927228434313, -0.8508769996321647, 1.733847812899358, -1.9338802842578322, -1.4125593711637086, 1.7702761450361215, 0.49385180688379604, -0.48895648790844665, -0.15872007418498266, -0.09920419307861998, 0.12317929238116793, 0.08585557349611746, 0.09370614907316197, -0.2607460957437406, -0.00372051314937977, -0.04020180712625255, 0.5265453421646704, -0.4929563256972127,
|
||||
0.6408763879659295, -16.79909075460828, -2.1142991624644942, -0.4393004235293688, 2.3177353997618853, -0.23758827371798064, 0.0, 1.9338802842578542, -1.733847812899381, -1.7702761450361162, 1.4125593711636986, 0.026683834684962007, -0.14587872928127077, 0.8508769996321606, -0.27594927228435256, -0.4938518068837918, 0.15872007418498413, 0.4889564879084464, 0.0992041930786239, -0.08585557349611386, -0.1231792923811642, 0.26074609574374336, -0.09370614907315725, 0.49295632569721404, -0.5265453421646692, 0.040201807126253306, 0.0037205131493783417,
|
||||
1.3091556741914314, 1.834380779552396, -0.8559641188321434, 0.09619204170147806, 1.5819839652391763, -0.1841259491984436, -2.440914756589403, 19.910396398833793, 0.9292089878722896, -0.6009288150226979, -0.17768908386483087, -0.22980299287322684, -1.9242671035439767, 2.9524607667234655, 0.2041356965652301, -1.1190995177139584, -0.24116380960165718, 0.7245564881296083, -0.49029775323051117, -0.04870816987800388, -0.7132041988172136, -0.454608663355292, 0.08758856822375095, 1.0907550537346067, 4.030854005025503, 0.7748473349352286, 0.07689148379455818,
|
||||
0.9744446123867609, -1.0484041028347049, -0.8540022369858385, -0.9621335517719756, -0.32599503457469153, 0.03367993684774262, 2.18843676448695, -0.9292089878722896, 19.910396398833793, 0.3767893371095702, 2.3244821244241383, 3.163967930478371, -0.22980299287321784, -4.587526524395932, -0.3514744230298633, 1.53672336568623, -0.04032358385143443, -0.832111126511136, -0.6124399423887177, 0.1737159141196091, -0.3506367152582221, 0.14771638250483257, 0.2886628025018225, 3.839816118012189, 0.6860200157542047, 0.11465722939811557, -0.9936515708028879,
|
||||
0.12480694029056734, -2.253850330037397, 0.9946802760235417, 0.6053185391404056, -1.7007108357677436, -0.27594927228434313, 1.7702761450361162, 0.47610199597409236, -0.29852147371705867, 17.141859608597226, -0.11879413685898123, -0.27846505302304264, 0.16173198913849687, -1.6885086434480685, 1.7017539992643287, 0.5994748509692391, -0.6941668393814941, 3.674640424508895, -0.09744008746280787, 0.20279671720873968, -0.3963039467276607, -0.7855375215315802, 0.6600584756782935, -0.4640248521828324, 0.7038226731025359, -0.1687199363657259, 0.20287631854527582,
|
||||
2.2391061027550703, 0.35380388805763474, 14.545240424570853, 0.13504815445355628, -0.13258632374176726, 0.8508769996321647, -1.4125593711636986, 0.14077894981231426, -1.8416334037878173, 0.11879413685898123, 17.141859608597226, -3.634591120025567, 2.339166352039784, 3.5405522900722497, -1.6885086434480694, 3.1856839366004506, -0.20031503249770058, 0.44075477678425123, -0.2731246543464956, 0.10359252413012018, -0.0115845139666891, 0.16267451141902461, -0.1724404495151067, 0.4430765773587932, -0.3703187031096739, 0.1671021499810791, -0.2589921793669097,
|
||||
1.048404102834719, -0.9744446123868129, 0.8540022369858489, 0.32599503457469536, 0.9621335517719789, -2.1884367644869207, -0.03367993684775132, 0.22980299287322684, -3.163967930478371, 0.3514744230298829, 4.587526524395912, -19.910396398833793, 0.9292089878722776, -2.324482124424116, -0.37678933710957857, -1.536723365686234, 0.8321111265111332, 0.04032358385143004, 0.612439942388719, 0.35063671525822543, -0.17371591411960696, -0.28866280250182014, -0.14771638250483188, 0.9936515708028864, -0.11465722939811639, -0.6860200157542059, -3.8398161180121906,
|
||||
-1.8343807795524023, -1.3091556741914812, 0.8559641188321553, -1.5819839652391803, -0.09619204170146632, 2.440914756589375, 0.18412594919845968, 1.9242671035439767, 0.22980299287321784, -0.2041356965652155, -2.9524607667234513, -0.9292089878722776, -19.910396398833793, 0.17768908386480717, 0.6009288150227365, 1.1190995177139624, -0.7245564881296058, 0.24116380960166542, 0.49029775323050956, 0.7132041988172101, 0.04870816987800567, -0.08758856822375086, 0.4546086633552912, -0.07689148379455372, -0.7748473349352273, -4.030854005025498, -1.0907550537346087,
|
||||
-0.35380388805764745, -2.2391061027550645, -14.545240424570837, 0.13258632374175544, -0.13504815445354384, 1.4125593711637086, -0.8508769996321606, -2.3391663520397947, 3.6345911200255827, 1.6885086434480685, -3.5405522900722497, 1.8416334037877997, -0.1407789498122955, -17.141859608597226, -0.11879413685897054, -3.1856839366004435, -0.44075477678425035, 0.20031503249770535, 0.2731246543464969, 0.01158451396669102, -0.10359252413011845, 0.17244044951510712, -0.16267451141902445, 0.25899217936691005, -0.16710214998107684, 0.37031870310967413, -0.44307657735879563,
|
||||
2.2538503300374226, -0.12480694029057034, -0.994680276023551, 1.7007108357677354, -0.6053185391404025, -1.7702761450361215, 0.27594927228435256, -0.16173198913850842, 0.2784650530230271, -1.7017539992643287, 1.6885086434480694, 0.29852147371706533, -0.476101995974123, 0.11879413685897054, -17.141859608597226, -0.5994748509692417, -3.6746404245088935, 0.6941668393814934, 0.09744008746280555, 0.39630394672766056, -0.2027967172087368, -0.6600584756782925, 0.7855375215315809, -0.20287631854527904, 0.16871993636572646, -0.7038226731025339, 0.4640248521828319,
|
||||
-3.766522549523058, 3.7665225495230428, -1.8416130814168517e-14, -0.8186227860390011, 0.818622786039013, -2.5406965754889375, 2.5406965754889157, 4.561438634236725, -6.263669333621437, -3.0840905707320223, -16.389240973690264, 6.263669333621453, -4.561438634236742, 16.38924097369023, 3.0840905707320356, 0.0, 0.8064071592627126, -0.8064071592627154, -3.27587819047868e-15, -0.2376302079323201, 0.23763020793230094, -0.5181032452374912, 0.5181032452374866, -2.3969263418417017, 0.8425636809391238, -0.8425636809391335, 2.396926341841694,
|
||||
3.474668492754472, 1.2720940592425334, -2.494428490280513, -3.3103842098885403, 1.169761861647588, 2.5155118541145702, -0.8165598329744024, 0.9829813174648175, 0.1643585314258267, 3.571248068855471, 1.030551493366546, -3.3916767725891264, 2.953285123732874, 2.267530737757596, 18.904752827804817, -0.8064071592627126, 0.0, -1.6128143185254504, 0.281848015316382, -1.069973391943026, 0.5194782232486872, 1.842445782443736, -3.2355644271100483, -0.020449207033394267, -0.5385524522708879, -0.8386380852683435, 0.9998821015046064,
|
||||
-1.2720940592424965, -3.474668492754426, 2.4944284902805367, -1.169761861647593, 3.310384209888532, 0.8165598329743948, -2.515511854114569, -2.953285123732884, 3.391676772589138, -18.904752827804824, -2.2675307377576006, -0.1643585314258088, -0.9829813174648512, -1.0305514933665705, -3.571248068855467, 0.8064071592627154, 1.6128143185254504, 0.0, -0.2818480153163751, -0.5194782232487007, 1.0699733919430288, 3.235564427110037, -1.8424457824437297, -0.9998821015046048, 0.8386380852683486, 0.5385524522708905, 0.020449207033400366,
|
||||
2.2431057877263694, -2.243105787726412, -1.867255202307378e-14, -1.275749958493393, 1.2757499584933791, 0.7181857904438594, -0.7181857904438878, 2.8121834969091495, 3.512750134965057, 0.7054146005697136, 1.977277771072542, -3.5127501349650645, -2.8121834969091406, -1.9772777710725515, -0.705414600569697, 4.609760570128499e-15, -0.39661177621033, 0.3966117762103203, 0.0, 1.473286325955928, -1.4732863259559217, 0.03294149361242836, -0.0329414936124289, -3.953179136944931, -1.408551582879458, 1.4085515828794593, 3.9531791369449287,
|
||||
0.23840429448465078, -2.035283159571775, 0.20782262815464633, -0.5779499847581375, 0.8010488801122674, -0.8917528051961954, 0.6215488579847753, 0.27937372870475113, -0.996376229788628, -1.468140772361843, -0.749954981917987, -2.0111346167968778, -4.090700119723205, -0.08386574258491672, -2.869030576268716, 0.3343892230125261, 1.5056485212427524, 0.7310009992228542, -1.473286325955928, 0.0, -2.9465726519118554, -0.8795833962368981, 0.19919319766269372, 0.49291247512221925, 0.5258539687346377, 4.152372334607633, 0.5289681866425602,
|
||||
2.035283159571782, -0.23840429448462236, -0.20782262815462102, -0.801048880112257, 0.5779499847581487, -0.6215488579848013, 0.8917528051961683, 4.090700119723225, 2.0111346167968587, 2.869030576268717, 0.0838657425849028, 0.9963762297886157, -0.27937372870476146, 0.7499549819179745, 1.468140772361822, -0.3343892230124991, -0.7310009992228351, -1.5056485212427564, 1.4732863259559217, 2.9465726519118554, 0.0, -0.19919319766269705, 0.8795833962369017, -0.5289681866425588, -4.152372334607625, -0.5258539687346414, -0.49291247512221426,
|
||||
1.759402157237792, 4.558892315982919, 1.2652912826383578, 2.0985063083979236, -0.9905102682507421, -0.6132401678100317, -1.706397937502056, 2.357095527641503, -0.7658930694187117, 5.140784956908139, -1.0645890975962542, 1.4966846336620354, 0.4541370173391847, -1.1285002237720632, 4.319613754198333, 0.6590565197748737, -2.3436948454060653, -4.115820254824023, -0.029778238966182636, 0.795120126366912, 0.1800653822873389, 0.0, 3.1163752731045724, 0.15960718397414111, -0.7346658981606436, -0.1973888096528869, -0.7116415547893532,
|
||||
-4.558892315982878, -1.7594021572377623, -1.2652912826383433, 0.9905102682507371, -2.0985063083979023, 1.7063979375020377, 0.6132401678100009, -0.4541370173391852, -1.4966846336620476, -4.319613754198339, 1.1285002237720605, 0.7658930694187083, -2.357095527641499, 1.064589097596253, -5.140784956908144, -0.6590565197748679, 4.115820254824037, 2.3436948454060573, 0.029778238966183125, -0.1800653822873359, -0.7951201263669153, -3.1163752731045724, 0.0, 0.71164155478935, 0.1973888096528901, 0.7346658981606372, -0.15960718397413862,
|
||||
-3.2117356080303803, -3.6112813302216713, -0.8266393399665194, 2.520812908731641, 0.14034800771819048, 0.024348115151799948, -3.2260489080343286, -5.655444047050364, -19.909020941069866, 3.0367129695880832, -2.8996213945368607, -5.151973251646951, 0.3986738203099664, -1.6949198009668083, 1.3276813620016823, 3.049025358424062, 0.026012543529633645, 1.271906370130427, 3.57356938337672, -0.4455798406197396, 0.47817325020768053, -0.15960718397414111, -0.71164155478935, 0.0, -1.5581876365522882, -0.3569959936270113, 1.46933179632127,
|
||||
-1.9464443253920187, 3.7322529760164143, -1.8518791729839088, -0.3672192491087197, -2.794877724005471, 0.26309226440541583, 3.4458651559413247, -20.899531209320617, -3.556937738652459, -4.606019332038912, 2.4234728017780744, 0.594485025057365, 4.017497542393682, 1.0935648461639937, -1.1041521086202575, -1.071788475275629, 0.6850690633045105, -1.0667948963999776, 1.2732933765745933, -0.4753580795859133, 3.753634765664056, 0.7346658981606436, -0.1973888096528901, 1.5581876365522882, 0.0, -1.4232831095787026, -0.35699599362703105,
|
||||
-3.7322529760164014, 1.9464443253919836, 1.8518791729839168, 2.794877724005484, 0.36721924910872045, -3.4458651559413327, -0.26309226440542083, -4.017497542393689, -0.5944850250573608, 1.1041521086202537, -1.0935648461640088, 3.5569377386524654, 20.89953120932059, -2.423472801778076, 4.6060193320388985, 1.0717884752756415, 1.0667948963999712, -0.6850690633045139, -1.2732933765745946, -3.753634765664064, 0.47535807958591664, 0.1973888096528869, -0.7346658981606372, 0.3569959936270113, 1.4232831095787026, 0.0, -1.5581876365522849,
|
||||
3.6112813302216593, 3.2117356080303487, 0.8266393399664891, -0.14034800771818173, -2.5208129087316506, 3.2260489080343198, -0.024348115151790604, -0.3986738203099895, 5.151973251646959, -1.3276813620016612, 1.694919800966806, 19.909020941069873, 5.6554440470503735, 2.8996213945368763, -3.03671296958808, -3.0490253584240525, -1.2719063701304292, -0.026012543529641403, -3.5735693833767184, -0.47817325020768164, 0.4455798406197351, 0.7116415547893532, 0.15960718397413862, -1.46933179632127, 0.35699599362703105, 1.5581876365522849, 0.0};
|
||||
|
||||
const double p4Dy[729] = {-15.28499617463146, 0.09827147270086124, 0.19654294540174796, 0.2870983239512125, -0.164085376440144, -0.4452349679915834, 0.06989189152237135, -0.15251000125927563, -0.2048955178996692, -0.44232233201278237, -0.024654882058863847, -0.03011871770800668, 0.42075792920998006, -0.12660138709291216, -3.3185622553257907, 0.048845803980856306, -0.13342014677484385, 0.14462674423071498, -0.05553697909937705, -0.006505362292085907, -0.06120785634410891, -0.10900916485152638, 0.11266078234486171, 0.05875484376287875, 0.09694858537476714, 0.1376134946492328, -0.05310883929020566,
|
||||
-0.09827147270086124, 0.0, 0.09827147270087347, -0.13396665873213587, -0.13365960525875817, 0.19649327861528584, 2.8733272873342135, 0.1336596052587607, 0.13396665873214064, -2.873327287334207, -0.19649327861528823, -0.052385516640395494, 0.05238551664038741, 0.4176674499539139, -0.41766744995391747, -0.095780940249859, 0.09578094024985785, -9.030965889809071e-16, 0.00567087724473144, -0.0056708772447323225, -2.468104976161084e-16, -0.024952712304370517, -0.05590032556132032, 0.05590032556132042, 0.02495271230436975, 0.03819374161188785, -0.03819374161188903,
|
||||
-0.19654294540174796, -0.09827147270087347, 15.28499617463146, 0.20489551789967816, 0.15251000125928516, 0.024654882058868614, 0.44232233201278004, 0.16408537644014445, -0.2870983239512186, -0.06989189152236565, 0.445234967991583, -0.42075792920997346, 0.03011871770800419, 3.3185622553257907, 0.12660138709291832, 0.13342014677484448, -0.04884580398085644, -0.14462674423071606, 0.0065053622920860695, 0.055536979099378284, 0.06120785634410899, -0.0969485853747657, -0.058754843762877665, -0.11266078234486313, 0.1090091648515255, 0.05310883929020579, -0.1376134946492322,
|
||||
-1.8343807795523694, 0.8559641188321322, -1.309155674191496, -19.910396398833793, -0.9292089878722894, 0.6009288150227082, 0.1776890838648202, 0.22980299287321443, 1.9242671035439682, -2.9524607667234357, -0.20413569656523223, -0.09619204170148214, -1.581983965239188, 0.18412594919846403, 2.4409147565893874, 0.24116380960165718, -0.7245564881296103, 1.1190995177139629, 0.048708169878006975, 0.7132041988172096, 0.49029775323050717, -1.0907550537346093, -4.0308540050255, -0.774847334935228, -0.07689148379455714, 0.45460866335528777, -0.0875885682237497,
|
||||
1.0484041028346944, 0.8540022369858469, -0.9744446123868041, 0.9292089878722894, -19.910396398833793, -0.376789337109576, -2.3244821244241085, -3.163967930478372, 0.22980299287322126, 4.587526524395933, 0.35147442302985465, 0.9621335517719841, 0.32599503457468426, -0.03367993684773616, -2.1884367644869362, 0.0403235838514332, 0.8321111265111371, -1.5367233656862271, -0.17371591411960613, 0.3506367152582226, 0.6124399423887191, -3.8398161180121875, -0.686020015754205, -0.11465722939811551, 0.99365157080289, -0.14771638250483227, -0.2886628025018202,
|
||||
2.2538503300374044, -0.9946802760235254, -0.1248069402906035, -0.4761019959741005, 0.2985214737170633, -17.141859608597226, 0.1187941368589855, 0.27846505302302493, -0.1617319891384971, 1.6885086434480594, -1.7017539992643365, -0.605318539140416, 1.700710835767743, 0.2759492722843605, -1.7702761450361306, 0.6941668393814986, -3.674640424508889, -0.5994748509692356, -0.20279671720873876, 0.3963039467276609, 0.097440087462807, 0.4640248521828354, -0.703822673102532, 0.16871993636572868, -0.20287631854527582, 0.7855375215315806, -0.6600584756782898,
|
||||
-0.35380388805762664, -14.545240424570872, -2.2391061027550836, -0.14077894981230582, 1.8416334037877937, -0.1187941368589855, -17.141859608597226, 3.6345911200255987, -2.339166352039789, -3.540552290072251, 1.6885086434480605, -0.135048154453527, 0.13258632374176318, -0.8508769996321724, 1.4125593711637054, 0.20031503249770397, -0.44075477678425157, -3.1856839366004435, -0.103592524130115, 0.01158451396669216, 0.2731246543464982, -0.44307657735879197, 0.37031870310967574, -0.16710214998107722, 0.2589921793669143, -0.16267451141902012, 0.17244044951510798,
|
||||
0.9744446123867433, -0.854002236985863, -1.048404102834697, -0.22980299287321443, 3.163967930478372, -0.35147442302986054, -4.587526524395952, 19.910396398833793, -0.9292089878722678, 2.324482124424122, 0.37678933710956625, -0.32599503457469653, -0.9621335517719883, 2.188436764486939, 0.03367993684775833, -0.8321111265111345, -0.0403235838514329, 1.5367233656862256, -0.3506367152582263, 0.17371591411960866, -0.612439942388722, -0.9936515708028895, 0.11465722939811439, 0.686020015754204, 3.839816118012191, 0.28866280250181964, 0.1477163825048354,
|
||||
1.3091556741914387, -0.8559641188321627, 1.8343807795524083, -1.9242671035439682, -0.22980299287322126, 0.20413569656521577, 2.952460766723458, 0.9292089878722678, 19.910396398833793, -0.17768908386481014, -0.6009288150226963, 1.5819839652391892, 0.09619204170147512, -2.440914756589397, -0.18412594919844522, 0.7245564881296075, -0.24116380960166175, -1.119099517713959, -0.7132041988172084, -0.04870816987800363, -0.4902977532305103, 0.0768914837945529, 0.774847334935229, 4.030854005025501, 1.090755053734602, 0.08758856822374894, -0.4546086633552895,
|
||||
2.2391061027550956, 14.545240424570837, 0.3538038880575977, 2.3391663520397716, -3.634591120025584, -1.6885086434480594, 3.540552290072251, -1.8416334037878042, 0.14077894981229783, 17.141859608597226, 0.1187941368589982, -0.13258632374177015, 0.13504815445355095, -1.4125593711636983, 0.8508769996321621, 0.4407547767842533, -0.200315032497699, 3.1856839366004475, -0.011584513966690685, 0.10359252413011888, -0.27312465434649635, -0.2589921793669082, 0.16710214998107692, -0.37031870310967424, 0.4430765773587957, -0.17244044951510495, 0.16267451141902212,
|
||||
0.12480694029057937, 0.9946802760235375, -2.253850330037402, 0.16173198913851014, -0.27846505302302027, 1.7017539992643365, -1.6885086434480605, -0.29852147371705556, 0.47610199597409114, -0.1187941368589982, 17.141859608597226, -1.7007108357677325, 0.6053185391404096, 1.7702761450361277, -0.27594927228436483, 3.674640424508897, -0.694166839381494, 0.5994748509692353, -0.39630394672765873, 0.2027967172087418, -0.09744008746280586, 0.2028763185452754, -0.1687199363657282, 0.7038226731025327, -0.4640248521828344, 0.6600584756782918, -0.7855375215315795,
|
||||
0.1924399840025528, 0.33471106180470783, 2.6883830165382343, 0.09619204170148214, -0.9621335517719841, 0.7640240022365183, 0.17045575971745425, 0.32599503457469653, -1.5819839652391892, 0.16734847383142104, 2.1466117678065335, 0.0, 1.8584179757445463, -2.9254109394468206, -0.5544784209744086, -0.8121668775566203, -0.286988391202826, -0.20084022575023078, -0.10076425642849045, -0.13966103797228321, -0.2224240839976154, 0.4861845324334064, -0.07082489871027524, 0.5390429074475949, -0.027068661174365027, 0.4047350379803992, 0.1910378870133102,
|
||||
-2.6883830165382765, -0.33471106180465615, -0.19243998400253687, 1.581983965239188, -0.32599503457468426, -2.146611767806547, -0.16734847383141227, 0.9621335517719883, -0.09619204170147512, -0.1704557597174845, -0.7640240022365101, -1.8584179757445463, 0.0, 0.554478420974375, 2.925410939446845, 0.2869883912028199, 0.8121668775566261, 0.20084022575022775, 0.1396610379722875, 0.10076425642848952, 0.22242408399761332, 0.027068661174365592, -0.5390429074475985, 0.07082489871027872, -0.4861845324334045, -0.191037887013308, -0.40473503798040444,
|
||||
0.640876387965887, -2.114299162464493, -16.799090754608244, -0.14587872928127424, 0.026683834684949993, -0.2759492722843605, 0.8508769996321724, -1.7338478128993726, 1.9338802842578497, 1.4125593711636983, -1.7702761450361277, 2.3177353997618972, -0.43930042352935234, 0.0, -0.23758827371795765, 0.4889564879084486, 0.15872007418498785, -0.4938518068837892, -0.12317929238116428, -0.08585557349611499, 0.09920419307862376, 0.0037205131493781296, 0.04020180712624783, -0.5265453421646701, 0.49295632569721504, -0.09370614907316001, 0.26074609574373936,
|
||||
16.799090754608244, 2.1142991624645107, -0.6408763879659182, -1.933880284257842, 1.7338478128993704, 1.7702761450361306, -1.4125593711637054, -0.02668383468496756, 0.1458787292812593, -0.8508769996321621, 0.27594927228436483, 0.4393004235293789, -2.317735399761917, 0.23758827371795765, 0.0, -0.15872007418498993, -0.4889564879084488, 0.4938518068837932, 0.08585557349611653, 0.12317929238116535, -0.0992041930786226, -0.4929563256972161, 0.52654534216467, -0.04020180712625487, -0.0037205131493803054, -0.2607460957437367, 0.09370614907315984,
|
||||
-1.2720940592424979, 2.494428490280534, -3.4746684927544607, -0.9829813174648175, -0.16435853142582169, -3.5712480688554935, -1.0305514933665634, 3.3916767725891317, -2.953285123732881, -2.2675307377576113, -18.904752827804835, 3.310384209888547, -1.1697618616475773, -2.5155118541145804, 0.8165598329744322, 0.0, 1.6128143185254429, 0.806407159262733, 1.0699733919430285, -0.5194782232486954, -0.2818480153163862, 0.020449207033393636, 0.538552452270888, 0.8386380852683486, -0.9998821015046098, -1.842445782443737, 3.2355644271100434,
|
||||
3.4746684927544433, -2.4944284902805043, 1.2720940592425014, 2.9532851237328925, -3.3916767725891424, 18.904752827804796, 2.2675307377576024, 0.1643585314258205, 0.9829813174648363, 1.0305514933665378, 3.5712480688554704, 1.1697618616476022, -3.3103842098885705, -0.8165598329744215, 2.5155118541145813, -1.6128143185254429, 0.0, -0.8064071592627268, 0.5194782232486914, -1.069973391943029, 0.28184801531637504, 0.9998821015046067, -0.838638085268352, -0.5385524522708939, -0.020449207033397976, -3.2355644271100372, 1.8424457824437361,
|
||||
-3.7665225495230237, 2.3519395979540512e-14, 3.7665225495230517, -4.561438634236743, 6.263669333621425, 3.084090570732004, 16.38924097369023, -6.263669333621419, 4.561438634236729, -16.38924097369025, -3.0840905707320028, 0.8186227860390236, -0.8186227860390113, 2.5406965754889024, -2.540696575488923, -0.806407159262733, 0.8064071592627268, 0.0, 0.23763020793230993, -0.23763020793231787, 4.300846213266488e-15, 2.39692634184169, -0.8425636809391248, 0.8425636809391247, -2.3969263418416866, 0.5181032452374869, -0.5181032452374932,
|
||||
2.035283159571767, -0.20782262815461824, -0.2384042944846541, -0.27937372870476895, 0.9963762297886111, 1.4681407723618363, 0.7499549819179495, 2.011134616796883, 4.090700119723195, 0.08386574258491429, 2.8690305762687025, 0.5779499847581366, -0.801048880112282, 0.891752805196169, -0.6215488579847945, -1.5056485212427562, -0.7310009992228411, -0.3343892230125118, 0.0, 2.9465726519118554, 1.4732863259559286, -0.4929124751222108, -0.5258539687346461, -4.1523723346076205, -0.5289681866425575, 0.8795833962369044, -0.1991931976626978,
|
||||
0.2384042944846482, 0.2078226281546506, -2.0352831595718124, -4.090700119723202, -2.0111346167968613, -2.8690305762687185, -0.08386574258492496, -0.9963762297886256, 0.27937372870474975, -0.7499549819179776, -1.4681407723618582, 0.8010488801122575, -0.5779499847581313, 0.6215488579847835, -0.8917528051961766, 0.7310009992228468, 1.5056485212427566, 0.334389223012523, -2.9465726519118554, 0.0, -1.47328632595593, 0.5289681866425614, 4.152372334607627, 0.5258539687346433, 0.4929124751222133, 0.19919319766269775, -0.8795833962368973,
|
||||
2.243105787726401, 9.044950905679127e-15, -2.2431057877264036, -2.812183496909127, -3.512750134965065, -0.7054146005697074, -1.9772777710725609, 3.512750134965082, 2.8121834969091446, 1.9772777710725475, 0.7054146005696991, 1.2757499584933931, -1.2757499584933811, -0.7181857904438868, 0.7181857904438784, 0.39661177621033594, -0.39661177621032023, -6.052078294524533e-15, -1.4732863259559286, 1.47328632595593, 0.0, 3.9531791369449296, 1.4085515828794586, -1.4085515828794646, -3.953179136944927, -0.03294149361242823, 0.032941493612420415,
|
||||
3.6112813302216935, 0.8266393399665112, 3.2117356080303274, 5.655444047050377, 19.909020941069855, -3.0367129695881028, 2.8996213945368523, 5.151973251646967, -0.3986738203099622, 1.6949198009667963, -1.3276813620016585, -2.520812908731642, -0.1403480077181807, -0.024348115151789213, 3.226048908034342, -0.026012543529632844, -1.2719063701304294, -3.049025358424047, 0.445579840619732, -0.4781732502076828, -3.573569383376719, 0.0, 1.5581876365522862, 0.35699599362702117, -1.4693317963212784, 0.159607183974139, 0.7116415547893488,
|
||||
-3.7322529760163743, 1.8518791729839026, 1.946444325391982, 20.899531209320596, 3.556937738652461, 4.606019332038886, -2.4234728017780864, -0.5944850250573547, -4.01749754239369, -1.0935648461639944, 1.1041521086202688, 0.3672192491087266, 2.7948777240054694, -0.26309226440538497, -3.4458651559413305, -0.6850690633045106, 1.066794896399982, 1.0717884752756304, 0.4753580795859208, -3.7536347656640583, -1.273293376574594, -1.5581876365522862, 0.0, 1.4232831095787029, 0.3569959936270241, -0.7346658981606364, 0.19738880965288536,
|
||||
-1.9464443253920178, -1.8518791729839061, 3.7322529760164214, 4.017497542393685, 0.5944850250573606, -1.104152108620272, 1.0935648461639964, -3.5569377386524557, -20.8995312093206, 2.4234728017780762, -4.6060193320388905, -2.7948777240054508, -0.36721924910874476, 3.445865155941331, 0.26309226440543104, -1.0667948963999776, 0.685069063304518, -1.0717884752756304, 3.753634765664053, -0.47535807958591836, 1.2732933765745995, -0.35699599362702117, -1.4232831095787029, 0.0, 1.5581876365522802, -0.19738880965288783, 0.73466589816063,
|
||||
-3.211735608030375, -0.8266393399664858, -3.611281330221664, 0.39867382030998416, -5.15197325164697, 1.3276813620016612, -1.6949198009668363, -19.909020941069876, -5.65544404705034, -2.8996213945368767, 3.0367129695880966, 0.14034800771817776, 2.5208129087316324, -3.226048908034335, 0.024348115151803455, 1.2719063701304334, 0.026012543529638363, 3.0490253584240428, 0.4781732502076793, -0.4455798406197342, 3.573569383376717, 1.4693317963212784, -0.3569959936270241, -1.5581876365522802, 0.0, -0.7116415547893499, -0.1596071839741321,
|
||||
-4.558892315982905, -1.2652912826383393, -1.7594021572377818, -2.3570955276414813, 0.7658930694187103, -5.140784956908142, 1.0645890975962247, -1.496684633662033, -0.4541370173391748, 1.1285002237720492, -4.319613754198328, -2.09850630839789, 0.9905102682507191, 0.6132401678100189, 1.7063979375020122, 2.3436948454060667, 4.115820254824023, -0.6590565197748682, -0.7951201263669176, -0.18006538228733954, 0.029778238966182518, -0.159607183974139, 0.7346658981606364, 0.19738880965288783, 0.7116415547893499, 0.0, -3.11637527310457,
|
||||
1.7594021572377778, 1.2652912826383786, 4.5588923159828845, 0.4541370173391787, 1.4966846336620356, 4.319613754198315, -1.1285002237720687, -0.7658930694187266, 2.35709552764149, -1.064589097596238, 5.140784956908135, -0.9905102682507304, 2.098506308397917, -1.7063979375020297, -0.6132401678100178, -4.115820254824031, -2.3436948454060658, 0.6590565197748763, 0.1800653822873396, 0.7951201263669113, -0.029778238966175454, -0.7116415547893488, -0.19738880965288536, -0.73466589816063, 0.1596071839741321, 3.11637527310457, 0.0};
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "estimators.hpp"
|
||||
#include "staticcond.hpp"
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_tools.hpp"
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include "pfespace.hpp"
|
||||
|
||||
+43
-700
@@ -12,7 +12,6 @@
|
||||
// Implementation of FiniteElementSpace
|
||||
|
||||
#include "../general/text.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../mesh/mesh_headers.hpp"
|
||||
#include "fem.hpp"
|
||||
|
||||
@@ -386,7 +385,6 @@ void FiniteElementSpace::MarkerToList(const Array<int> &marker,
|
||||
Array<int> &list)
|
||||
{
|
||||
int num_marked = 0;
|
||||
marker.HostRead(); // make sure we can read the array on host
|
||||
for (int i = 0; i < marker.Size(); i++)
|
||||
{
|
||||
if (marker[i]) { num_marked++; }
|
||||
@@ -567,40 +565,6 @@ bool FiniteElementSpace::DofFinalizable(int dof, const Array<bool>& finalized,
|
||||
return true;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetDegenerateFaceDofs(int index,
|
||||
Array<int> &dofs) const
|
||||
{
|
||||
// In NC meshes with prisms, a special constraint occurs where a prism edge
|
||||
// is slave to a quadrilateral face. Rather than introduce a new edge-face
|
||||
// constraint type, we handle such cases as degenerate face-face constraints,
|
||||
// where the point-matrix rectangle has zero height. This method returns
|
||||
// DOFs for the first edge of the rectangle, duplicated in the orthogonal
|
||||
// direction, to resemble DOFs for a quadrilateral face. The extra DOFs are
|
||||
// ignored by FiniteElementSpace::AddDependencies.
|
||||
|
||||
Array<int> edof;
|
||||
GetEdgeDofs(-1 - index, edof);
|
||||
|
||||
int nv = fec->DofForGeometry(Geometry::POINT);
|
||||
int ne = fec->DofForGeometry(Geometry::SEGMENT);
|
||||
int nn = 2*nv + ne;
|
||||
|
||||
dofs.SetSize(nn*nn);
|
||||
dofs = edof[0];
|
||||
|
||||
// copy first two vertex DOFs
|
||||
for (int i = 0; i < nv; i++)
|
||||
{
|
||||
dofs[i] = edof[i];
|
||||
dofs[nv+i] = edof[nv+i];
|
||||
}
|
||||
// copy first edge DOFs
|
||||
for (int i = 0; i < ne; i++)
|
||||
{
|
||||
dofs[4*nv + i] = edof[2*nv + i];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FiniteElementSpace::GetEntityDofs(int entity, int index, Array<int> &dofs) const
|
||||
{
|
||||
@@ -608,8 +572,7 @@ FiniteElementSpace::GetEntityDofs(int entity, int index, Array<int> &dofs) const
|
||||
{
|
||||
case 0: GetVertexDofs(index, dofs); break;
|
||||
case 1: GetEdgeDofs(index, dofs); break;
|
||||
case 2: (index >= 0) ? GetFaceDofs(index, dofs)
|
||||
/* */ : GetDegenerateFaceDofs(index, dofs);
|
||||
case 2: GetFaceDofs(index, dofs); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,33 +595,28 @@ void FiniteElementSpace::BuildConformingInterpolation() const
|
||||
// collect local edge/face dependencies
|
||||
for (int entity = 1; entity <= 2; entity++)
|
||||
{
|
||||
const NCMesh::NCList &list = mesh->ncmesh->GetNCList(entity);
|
||||
const NCMesh::NCList &list = (entity > 1) ? mesh->ncmesh->GetFaceList()
|
||||
/* */ : mesh->ncmesh->GetEdgeList();
|
||||
if (!list.masters.size()) { continue; }
|
||||
|
||||
Array<int> master_dofs, slave_dofs;
|
||||
|
||||
IsoparametricTransformation T;
|
||||
DenseMatrix I;
|
||||
if (entity > 1) { T.SetFE(&QuadrilateralFE); }
|
||||
else { T.SetFE(&SegmentFE); }
|
||||
|
||||
Geometry::Type geom = (entity > 1) ? Geometry::SQUARE : 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];
|
||||
|
||||
GetEntityDofs(entity, master.index, master_dofs);
|
||||
if (!master_dofs.Size()) { continue; }
|
||||
|
||||
const FiniteElement* fe = fec->FiniteElementForGeometry(master.Geom());
|
||||
if (!fe) { continue; }
|
||||
|
||||
switch (master.geom)
|
||||
{
|
||||
case Geometry::SQUARE: T.SetFE(&QuadrilateralFE); break;
|
||||
case Geometry::TRIANGLE: T.SetFE(&TriangleFE); break;
|
||||
case Geometry::SEGMENT: T.SetFE(&SegmentFE); break;
|
||||
default: MFEM_ABORT("unsupported geometry");
|
||||
}
|
||||
|
||||
for (int si = master.slaves_begin; si < master.slaves_end; si++)
|
||||
{
|
||||
const NCMesh::Slave &slave = list.slaves[si];
|
||||
@@ -694,9 +652,9 @@ void FiniteElementSpace::BuildConformingInterpolation() const
|
||||
// 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];
|
||||
int *cR_I = mfem::New<int>(n_true_dofs+1);
|
||||
double *cR_A = mfem::New<double>(n_true_dofs);
|
||||
cR_J = mfem::New<int>(n_true_dofs);
|
||||
for (int i = 0; i < n_true_dofs; i++)
|
||||
{
|
||||
cR_I[i] = i;
|
||||
@@ -774,8 +732,6 @@ void FiniteElementSpace::BuildConformingInterpolation() const
|
||||
MakeVDimMatrix(*cP);
|
||||
MakeVDimMatrix(*cR);
|
||||
}
|
||||
|
||||
if (Device::IsEnabled()) { cP->BuildTranspose(); }
|
||||
}
|
||||
|
||||
void FiniteElementSpace::MakeVDimMatrix(SparseMatrix &mat) const
|
||||
@@ -826,63 +782,6 @@ int FiniteElementSpace::GetNConformingDofs() const
|
||||
return P ? (P->Width() / vdim) : ndofs;
|
||||
}
|
||||
|
||||
const Operator *FiniteElementSpace::GetElementRestriction(
|
||||
ElementDofOrdering e_ordering) const
|
||||
{
|
||||
// Check if we have a discontinuous space using the FE collection:
|
||||
const L2_FECollection *dg_space = dynamic_cast<const L2_FECollection*>(fec);
|
||||
if (dg_space)
|
||||
{
|
||||
if (L2E_nat.Ptr() == NULL)
|
||||
{
|
||||
L2E_nat.Reset(new L2ElementRestriction(*this));
|
||||
}
|
||||
return L2E_nat.Ptr();
|
||||
}
|
||||
if (e_ordering == ElementDofOrdering::LEXICOGRAPHIC)
|
||||
{
|
||||
if (L2E_lex.Ptr() == NULL)
|
||||
{
|
||||
L2E_lex.Reset(new ElementRestriction(*this, e_ordering));
|
||||
}
|
||||
return L2E_lex.Ptr();
|
||||
}
|
||||
// e_ordering == ElementDofOrdering::NATIVE
|
||||
if (L2E_nat.Ptr() == NULL)
|
||||
{
|
||||
L2E_nat.Reset(new ElementRestriction(*this, e_ordering));
|
||||
}
|
||||
return L2E_nat.Ptr();
|
||||
}
|
||||
|
||||
const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
|
||||
const IntegrationRule &ir) const
|
||||
{
|
||||
for (int i = 0; i < E2Q_array.Size(); i++)
|
||||
{
|
||||
const QuadratureInterpolator *qi = E2Q_array[i];
|
||||
if (qi->IntRule == &ir) { return qi; }
|
||||
}
|
||||
|
||||
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, ir);
|
||||
E2Q_array.Append(qi);
|
||||
return qi;
|
||||
}
|
||||
|
||||
const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
|
||||
const QuadratureSpace &qs) const
|
||||
{
|
||||
for (int i = 0; i < E2Q_array.Size(); i++)
|
||||
{
|
||||
const QuadratureInterpolator *qi = E2Q_array[i];
|
||||
if (qi->qspace == &qs) { return qi; }
|
||||
}
|
||||
|
||||
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, qs);
|
||||
E2Q_array.Append(qi);
|
||||
return qi;
|
||||
}
|
||||
|
||||
SparseMatrix *FiniteElementSpace::RefinementMatrix_main(
|
||||
const int coarse_ndofs, const Table &coarse_elem_dof,
|
||||
const DenseTensor localP[]) const
|
||||
@@ -951,7 +850,7 @@ void FiniteElementSpace::GetLocalRefinementMatrices(
|
||||
const FiniteElement *fe = fec->FiniteElementForGeometry(geom);
|
||||
|
||||
const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
|
||||
const DenseTensor &pmats = rtrans.point_matrices[geom];
|
||||
const DenseTensor &pmats = rtrans.GetPointMatrices(geom);
|
||||
|
||||
int nmat = pmats.SizeK();
|
||||
int ldof = fe->GetDof(); // assuming the same FE everywhere
|
||||
@@ -990,9 +889,7 @@ FiniteElementSpace::RefinementOperator::RefinementOperator
|
||||
: fespace(fespace)
|
||||
, old_elem_dof(old_elem_dof)
|
||||
{
|
||||
const Mesh* mesh = fespace->GetMesh();
|
||||
MFEM_VERIFY(mesh->ReduceInt(fespace->GetNDofs()) >=
|
||||
mesh->ReduceInt(old_ndofs),
|
||||
MFEM_VERIFY(fespace->GetNDofs() >= old_ndofs,
|
||||
"Previous space is not coarser.");
|
||||
|
||||
width = old_ndofs * fespace->GetVDim();
|
||||
@@ -1102,7 +999,7 @@ FiniteElementSpace::DerefinementOperator::DerefinementOperator(
|
||||
f_fes->fec->FiniteElementForGeometry(geom);
|
||||
const FiniteElement *coarse_fe =
|
||||
c_fes->fec->FiniteElementForGeometry(geom);
|
||||
const DenseTensor &pmats = rtrans.point_matrices[geom];
|
||||
const DenseTensor &pmats = rtrans.GetPointMatrices(geom);
|
||||
|
||||
lP.SetSize(fine_fe->GetDof(), coarse_fe->GetDof(), pmats.SizeK());
|
||||
lM.SetSize(fine_fe->GetDof(), fine_fe->GetDof(), pmats.SizeK());
|
||||
@@ -1218,7 +1115,7 @@ void FiniteElementSpace::GetLocalDerefinementMatrices(Geometry::Type geom,
|
||||
|
||||
const CoarseFineTransformations &dtrans =
|
||||
mesh->ncmesh->GetDerefinementTransforms();
|
||||
const DenseTensor &pmats = dtrans.point_matrices[geom];
|
||||
const DenseTensor &pmats = dtrans.GetPointMatrices(geom);
|
||||
|
||||
const int nmat = pmats.SizeK();
|
||||
const int ldof = fe->GetDof();
|
||||
@@ -1323,7 +1220,7 @@ void FiniteElementSpace::GetLocalRefinementMatrices(
|
||||
coarse_fes.fec->FiniteElementForGeometry(geom);
|
||||
|
||||
const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
|
||||
const DenseTensor &pmats = rtrans.point_matrices[geom];
|
||||
const DenseTensor &pmats = rtrans.GetPointMatrices(geom);
|
||||
|
||||
int nmat = pmats.SizeK();
|
||||
|
||||
@@ -1416,26 +1313,31 @@ void FiniteElementSpace::UpdateNURBS()
|
||||
void FiniteElementSpace::Construct()
|
||||
{
|
||||
// This method should be used only for non-NURBS spaces.
|
||||
MFEM_VERIFY(!NURBSext, "internal error");
|
||||
MFEM_ASSERT(!NURBSext, "internal error");
|
||||
|
||||
elem_dof = NULL;
|
||||
bdrElem_dof = NULL;
|
||||
|
||||
nvdofs = mesh->GetNV() * fec->DofForGeometry(Geometry::POINT);
|
||||
|
||||
if ( mesh->Dimension() > 1 )
|
||||
{
|
||||
nedofs = mesh->GetNEdges() * fec->DofForGeometry(Geometry::SEGMENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
nedofs = 0;
|
||||
}
|
||||
|
||||
ndofs = 0;
|
||||
nedofs = nfdofs = nbdofs = 0;
|
||||
nfdofs = 0;
|
||||
nbdofs = 0;
|
||||
bdofs = NULL;
|
||||
fdofs = NULL;
|
||||
cP = NULL;
|
||||
cR = NULL;
|
||||
cP_is_set = false;
|
||||
// 'Th' is initialized/destroyed before this method is called.
|
||||
|
||||
nvdofs = mesh->GetNV() * fec->DofForGeometry(Geometry::POINT);
|
||||
|
||||
if (mesh->Dimension() > 1)
|
||||
{
|
||||
nedofs = mesh->GetNEdges() * fec->DofForGeometry(Geometry::SEGMENT);
|
||||
}
|
||||
// Th is initialized/destroyed before this method is called.
|
||||
|
||||
if (mesh->GetNFaces() > 0)
|
||||
{
|
||||
@@ -1467,7 +1369,8 @@ void FiniteElementSpace::Construct()
|
||||
bdofs[0] = 0;
|
||||
for (int i = 0; i < mesh->GetNE(); i++)
|
||||
{
|
||||
nbdofs += fec->DofForGeometry(mesh->GetElementBaseGeometry(i));
|
||||
Geometry::Type geom = mesh->GetElementBaseGeometry(i);
|
||||
nbdofs += fec->DofForGeometry(geom);
|
||||
bdofs[i+1] = nbdofs;
|
||||
}
|
||||
}
|
||||
@@ -1478,7 +1381,7 @@ void FiniteElementSpace::Construct()
|
||||
// later.
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetElementDofs(int i, Array<int> &dofs) const
|
||||
void FiniteElementSpace::GetElementDofs (int i, Array<int> &dofs) const
|
||||
{
|
||||
if (elem_dof)
|
||||
{
|
||||
@@ -1582,10 +1485,6 @@ void FiniteElementSpace::GetElementDofs(int i, Array<int> &dofs) const
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetFE(int i) const
|
||||
{
|
||||
if (i < 0 || !mesh->GetNE()) { return NULL; }
|
||||
MFEM_VERIFY(i < mesh->GetNE(),
|
||||
"Invalid element id " << i << ", maximum allowed " << mesh->GetNE()-1);
|
||||
|
||||
const FiniteElement *FE =
|
||||
fec->FiniteElementForGeometry(mesh->GetElementBaseGeometry(i));
|
||||
|
||||
@@ -1890,13 +1789,6 @@ void FiniteElementSpace::Destroy()
|
||||
delete cR;
|
||||
delete cP;
|
||||
Th.Clear();
|
||||
L2E_nat.Clear();
|
||||
L2E_lex.Clear();
|
||||
for (int i = 0; i < E2Q_array.Size(); i++)
|
||||
{
|
||||
delete E2Q_array[i];
|
||||
}
|
||||
E2Q_array.SetSize(0);
|
||||
|
||||
dof_elem_array.DeleteAll();
|
||||
dof_ldof_array.DeleteAll();
|
||||
@@ -2458,7 +2350,8 @@ const Operator &InterpolationGridTransfer::BackwardOperator()
|
||||
return *B.Ptr();
|
||||
}
|
||||
|
||||
// Construct B, if not set, define a suitable mass_integ
|
||||
// Construct B
|
||||
// If not set, define a suitable mass_integ
|
||||
if (!mass_integ && ran_fes.GetNE() > 0)
|
||||
{
|
||||
const FiniteElement *f_fe_0 = ran_fes.GetFE(0);
|
||||
@@ -2555,7 +2448,7 @@ L2ProjectionGridTransfer::L2Projection::L2Projection(
|
||||
Vector shape_lor(ndof_lor);
|
||||
|
||||
const Geometry::Type geom = fe_ho->GetGeomType();
|
||||
const DenseTensor &pmats = cf_tr.point_matrices[geom];
|
||||
const DenseTensor &pmats = cf_tr.GetPointMatrices(geom);
|
||||
emb_tr.SetIdentityTransformation(geom);
|
||||
|
||||
for (int iho=0; iho<nel_ho; ++iho)
|
||||
@@ -2578,7 +2471,7 @@ L2ProjectionGridTransfer::L2Projection::L2Projection(
|
||||
|
||||
// Create the transformation that embeds the fine low-order element
|
||||
// within the coarse high-order element in reference space
|
||||
emb_tr.GetPointMat() = pmats(cf_tr.embeddings[ilor].matrix);
|
||||
emb_tr.GetPointMat() = pmats(iref);
|
||||
emb_tr.FinalizeTransformation();
|
||||
|
||||
int order = fe_lor->GetOrder() + fe_ho->GetOrder() + el_tr->OrderW();
|
||||
@@ -2621,7 +2514,7 @@ void L2ProjectionGridTransfer::L2Projection::Mult(
|
||||
fes_ho.GetElementVDofs(iho, vdofs);
|
||||
x.GetSubVector(vdofs, xel_mat.GetData());
|
||||
mfem::Mult(R(iho), xel_mat, yel_mat);
|
||||
// Place result correctly into the low-order vector
|
||||
// Place result correctly into low-order vector
|
||||
for (int iref=0; iref<nref; ++iref)
|
||||
{
|
||||
int ilor = ho2lor.GetRow(iho)[iref];
|
||||
@@ -2679,554 +2572,4 @@ const Operator &L2ProjectionGridTransfer::BackwardOperator()
|
||||
return *B;
|
||||
}
|
||||
|
||||
L2ElementRestriction::L2ElementRestriction(const FiniteElementSpace &fes)
|
||||
: ne(fes.GetNE()),
|
||||
vdim(fes.GetVDim()),
|
||||
byvdim(fes.GetOrdering() == Ordering::byVDIM),
|
||||
ndof(ne > 0 ? fes.GetFE(0)->GetDof() : 0)
|
||||
{
|
||||
height = vdim*ne*ndof;
|
||||
width = vdim*ne*ndof;
|
||||
}
|
||||
|
||||
void L2ElementRestriction::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
for (int iel=0; iel<ne; ++iel)
|
||||
{
|
||||
for (int vd=0; vd<vdim; ++vd)
|
||||
{
|
||||
for (int idof=0; idof<ndof; ++idof)
|
||||
{
|
||||
// E-vector dimensions (dofs, vdim, elements)
|
||||
// L-vector dimensions: byVDIM: (vdim, dofs, element)
|
||||
// byNODES: (dofs, elements, vdim)
|
||||
int yidx = iel*vdim*ndof + vd*ndof + idof;
|
||||
int xidx;
|
||||
if (byvdim)
|
||||
{
|
||||
xidx = iel*ndof*vdim + idof*vdim + vd;
|
||||
}
|
||||
else
|
||||
{
|
||||
xidx = vd*ne*ndof + iel*ndof + idof;
|
||||
}
|
||||
y[yidx] = x[xidx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void L2ElementRestriction::MultTranspose(const Vector &x, Vector &y) const
|
||||
{
|
||||
// Since this restriction is a permutation, the transpose is the inverse
|
||||
for (int iel=0; iel<ne; ++iel)
|
||||
{
|
||||
for (int vd=0; vd<vdim; ++vd)
|
||||
{
|
||||
for (int idof=0; idof<ndof; ++idof)
|
||||
{
|
||||
// E-vector dimensions (dofs, vdim, elements)
|
||||
// L-vector dimensions: byVDIM: (vdim, dofs, element)
|
||||
// byNODES: (dofs, elements, vdim)
|
||||
int xidx = iel*vdim*ndof + vd*ndof + idof;
|
||||
int yidx;
|
||||
if (byvdim)
|
||||
{
|
||||
yidx = iel*ndof*vdim + idof*vdim + vd;
|
||||
}
|
||||
else
|
||||
{
|
||||
yidx = vd*ne*ndof + iel*ndof + idof;
|
||||
}
|
||||
y[yidx] = x[xidx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ElementRestriction::ElementRestriction(const FiniteElementSpace &f,
|
||||
ElementDofOrdering e_ordering)
|
||||
: fes(f),
|
||||
ne(fes.GetNE()),
|
||||
vdim(fes.GetVDim()),
|
||||
byvdim(fes.GetOrdering() == Ordering::byVDIM),
|
||||
ndofs(fes.GetNDofs()),
|
||||
dof(ne > 0 ? fes.GetFE(0)->GetDof() : 0),
|
||||
nedofs(ne*dof),
|
||||
offsets(ndofs+1),
|
||||
indices(ne*dof)
|
||||
{
|
||||
// Assuming all finite elements are the same.
|
||||
height = vdim*ne*dof;
|
||||
width = fes.GetVSize();
|
||||
const bool dof_reorder = (e_ordering == ElementDofOrdering::LEXICOGRAPHIC);
|
||||
const int *dof_map = NULL;
|
||||
if (dof_reorder && ne > 0)
|
||||
{
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
const FiniteElement *fe = fes.GetFE(e);
|
||||
const TensorBasisElement* el =
|
||||
dynamic_cast<const TensorBasisElement*>(fe);
|
||||
if (el) { continue; }
|
||||
mfem_error("Finite element not suitable for lexicographic ordering");
|
||||
}
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
const TensorBasisElement* el =
|
||||
dynamic_cast<const TensorBasisElement*>(fe);
|
||||
const Array<int> &fe_dof_map = el->GetDofMap();
|
||||
MFEM_VERIFY(fe_dof_map.Size() > 0, "invalid dof map");
|
||||
dof_map = fe_dof_map.GetData();
|
||||
}
|
||||
const Table& e2dTable = fes.GetElementToDofTable();
|
||||
const int* elementMap = e2dTable.GetJ();
|
||||
// We will be keeping a count of how many local nodes point to its global dof
|
||||
for (int i = 0; i <= ndofs; ++i)
|
||||
{
|
||||
offsets[i] = 0;
|
||||
}
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
for (int d = 0; d < dof; ++d)
|
||||
{
|
||||
const int gid = elementMap[dof*e + d];
|
||||
++offsets[gid + 1];
|
||||
}
|
||||
}
|
||||
// Aggregate to find offsets for each global dof
|
||||
for (int i = 1; i <= ndofs; ++i)
|
||||
{
|
||||
offsets[i] += offsets[i - 1];
|
||||
}
|
||||
// For each global dof, fill in all local nodes that point to it
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
for (int d = 0; d < dof; ++d)
|
||||
{
|
||||
const int did = (!dof_reorder)?d:dof_map[d];
|
||||
const int gid = elementMap[dof*e + did];
|
||||
const int lid = dof*e + d;
|
||||
indices[offsets[gid]++] = lid;
|
||||
}
|
||||
}
|
||||
// We shifted the offsets vector by 1 by using it as a counter.
|
||||
// Now we shift it back.
|
||||
for (int i = ndofs; i > 0; --i)
|
||||
{
|
||||
offsets[i] = offsets[i - 1];
|
||||
}
|
||||
offsets[0] = 0;
|
||||
}
|
||||
|
||||
void ElementRestriction::Mult(const Vector& x, Vector& y) const
|
||||
{
|
||||
// Assumes all elements have the same number of dofs
|
||||
const int nd = dof;
|
||||
const int vd = vdim;
|
||||
const bool t = byvdim;
|
||||
auto d_offsets = offsets.Read();
|
||||
auto d_indices = indices.Read();
|
||||
auto d_x = Reshape(x.Read(), t?vd:ndofs, t?ndofs:vd);
|
||||
auto d_y = Reshape(y.Write(), nd, vd, ne);
|
||||
MFEM_FORALL(i, ndofs,
|
||||
{
|
||||
const int offset = d_offsets[i];
|
||||
const int nextOffset = d_offsets[i+1];
|
||||
for (int c = 0; c < vd; ++c)
|
||||
{
|
||||
const double dofValue = d_x(t?c:i,t?i:c);
|
||||
for (int j = offset; j < nextOffset; ++j)
|
||||
{
|
||||
const int idx_j = d_indices[j];
|
||||
d_y(idx_j % nd, c, idx_j / nd) = dofValue;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ElementRestriction::MultTranspose(const Vector& x, Vector& y) const
|
||||
{
|
||||
// Assumes all elements have the same number of dofs
|
||||
const int nd = dof;
|
||||
const int vd = vdim;
|
||||
const bool t = byvdim;
|
||||
auto d_offsets = offsets.Read();
|
||||
auto d_indices = indices.Read();
|
||||
auto d_x = Reshape(x.Read(), nd, vd, ne);
|
||||
auto d_y = Reshape(y.Write(), t?vd:ndofs, t?ndofs:vd);
|
||||
MFEM_FORALL(i, ndofs,
|
||||
{
|
||||
const int offset = d_offsets[i];
|
||||
const int nextOffset = d_offsets[i + 1];
|
||||
for (int c = 0; c < vd; ++c)
|
||||
{
|
||||
double dofValue = 0;
|
||||
for (int j = offset; j < nextOffset; ++j)
|
||||
{
|
||||
const int idx_j = d_indices[j];
|
||||
dofValue += d_x(idx_j % nd, c, idx_j / nd);
|
||||
}
|
||||
d_y(t?c:i,t?i:c) = dofValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir)
|
||||
{
|
||||
fespace = &fes;
|
||||
qspace = NULL;
|
||||
IntRule = &ir;
|
||||
use_tensor_products = true; // not implemented yet (not used)
|
||||
|
||||
if (fespace->GetNE() == 0) { return; }
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
MFEM_VERIFY(dynamic_cast<const ScalarFiniteElement*>(fe) != NULL,
|
||||
"Only scalar finite elements are supported");
|
||||
}
|
||||
|
||||
QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
|
||||
const QuadratureSpace &qs)
|
||||
{
|
||||
fespace = &fes;
|
||||
qspace = &qs;
|
||||
IntRule = NULL;
|
||||
use_tensor_products = true; // not implemented yet (not used)
|
||||
|
||||
if (fespace->GetNE() == 0) { return; }
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
MFEM_VERIFY(dynamic_cast<const ScalarFiniteElement*>(fe) != NULL,
|
||||
"Only scalar finite elements are supported");
|
||||
}
|
||||
|
||||
template<const int T_VDIM, const int T_ND, const int T_NQ>
|
||||
void QuadratureInterpolator::Eval2D(
|
||||
const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val,
|
||||
Vector &q_der,
|
||||
Vector &q_det,
|
||||
const int eval_flags)
|
||||
{
|
||||
const int nd = maps.ndof;
|
||||
const int nq = maps.nqpt;
|
||||
const int ND = T_ND ? T_ND : nd;
|
||||
const int NQ = T_NQ ? T_NQ : nq;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
MFEM_VERIFY(ND <= MAX_ND2D, "");
|
||||
MFEM_VERIFY(NQ <= MAX_NQ2D, "");
|
||||
MFEM_VERIFY(VDIM == 2 || !(eval_flags & DETERMINANTS), "");
|
||||
auto B = Reshape(maps.B.Read(), NQ, ND);
|
||||
auto G = Reshape(maps.G.Read(), NQ, 2, ND);
|
||||
auto E = Reshape(e_vec.Read(), ND, VDIM, NE);
|
||||
auto val = Reshape(q_val.Write(), NQ, VDIM, NE);
|
||||
auto der = Reshape(q_der.Write(), NQ, VDIM, 2, NE);
|
||||
auto det = Reshape(q_det.Write(), NQ, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
const int ND = T_ND ? T_ND : nd;
|
||||
const int NQ = T_NQ ? T_NQ : nq;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int max_ND = T_ND ? T_ND : MAX_ND2D;
|
||||
constexpr int max_VDIM = T_VDIM ? T_VDIM : MAX_VDIM2D;
|
||||
double s_E[max_VDIM*max_ND];
|
||||
for (int d = 0; d < ND; d++)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
s_E[c+d*VDIM] = E(d,c,e);
|
||||
}
|
||||
}
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
if (eval_flags & VALUES)
|
||||
{
|
||||
double ed[max_VDIM];
|
||||
for (int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
|
||||
for (int d = 0; d < ND; ++d)
|
||||
{
|
||||
const double b = B(q,d);
|
||||
for (int c = 0; c < VDIM; c++) { ed[c] += b*s_E[c+d*VDIM]; }
|
||||
}
|
||||
for (int c = 0; c < VDIM; c++) { val(q,c,e) = ed[c]; }
|
||||
}
|
||||
if ((eval_flags & DERIVATIVES) || (eval_flags & DETERMINANTS))
|
||||
{
|
||||
// use MAX_VDIM2D to avoid "subscript out of range" warnings
|
||||
double D[MAX_VDIM2D*2];
|
||||
for (int i = 0; i < 2*VDIM; i++) { D[i] = 0.0; }
|
||||
for (int d = 0; d < ND; ++d)
|
||||
{
|
||||
const double wx = G(q,0,d);
|
||||
const double wy = G(q,1,d);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
double s_e = s_E[c+d*VDIM];
|
||||
D[c+VDIM*0] += s_e * wx;
|
||||
D[c+VDIM*1] += s_e * wy;
|
||||
}
|
||||
}
|
||||
if (eval_flags & DERIVATIVES)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
der(q,c,0,e) = D[c+VDIM*0];
|
||||
der(q,c,1,e) = D[c+VDIM*1];
|
||||
}
|
||||
}
|
||||
if (VDIM == 2 && (eval_flags & DETERMINANTS))
|
||||
{
|
||||
// The check (VDIM == 2) should eliminate this block when VDIM is
|
||||
// known at compile time and (VDIM != 2).
|
||||
det(q,e) = D[0]*D[3] - D[1]*D[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<const int T_VDIM, const int T_ND, const int T_NQ>
|
||||
void QuadratureInterpolator::Eval3D(
|
||||
const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val,
|
||||
Vector &q_der,
|
||||
Vector &q_det,
|
||||
const int eval_flags)
|
||||
{
|
||||
const int nd = maps.ndof;
|
||||
const int nq = maps.nqpt;
|
||||
const int ND = T_ND ? T_ND : nd;
|
||||
const int NQ = T_NQ ? T_NQ : nq;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
MFEM_VERIFY(ND <= MAX_ND3D, "");
|
||||
MFEM_VERIFY(NQ <= MAX_NQ3D, "");
|
||||
MFEM_VERIFY(VDIM == 3 || !(eval_flags & DETERMINANTS), "");
|
||||
auto B = Reshape(maps.B.Read(), NQ, ND);
|
||||
auto G = Reshape(maps.G.Read(), NQ, 3, ND);
|
||||
auto E = Reshape(e_vec.Read(), ND, VDIM, NE);
|
||||
auto val = Reshape(q_val.Write(), NQ, VDIM, NE);
|
||||
auto der = Reshape(q_der.Write(), NQ, VDIM, 3, NE);
|
||||
auto det = Reshape(q_det.Write(), NQ, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
const int ND = T_ND ? T_ND : nd;
|
||||
const int NQ = T_NQ ? T_NQ : nq;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int max_ND = T_ND ? T_ND : MAX_ND3D;
|
||||
constexpr int max_VDIM = T_VDIM ? T_VDIM : MAX_VDIM3D;
|
||||
double s_E[max_VDIM*max_ND];
|
||||
for (int d = 0; d < ND; d++)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
s_E[c+d*VDIM] = E(d,c,e);
|
||||
}
|
||||
}
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
if (eval_flags & VALUES)
|
||||
{
|
||||
double ed[max_VDIM];
|
||||
for (int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
|
||||
for (int d = 0; d < ND; ++d)
|
||||
{
|
||||
const double b = B(q,d);
|
||||
for (int c = 0; c < VDIM; c++) { ed[c] += b*s_E[c+d*VDIM]; }
|
||||
}
|
||||
for (int c = 0; c < VDIM; c++) { val(q,c,e) = ed[c]; }
|
||||
}
|
||||
if ((eval_flags & DERIVATIVES) || (eval_flags & DETERMINANTS))
|
||||
{
|
||||
// use MAX_VDIM3D to avoid "subscript out of range" warnings
|
||||
double D[MAX_VDIM3D*3];
|
||||
for (int i = 0; i < 3*VDIM; i++) { D[i] = 0.0; }
|
||||
for (int d = 0; d < ND; ++d)
|
||||
{
|
||||
const double wx = G(q,0,d);
|
||||
const double wy = G(q,1,d);
|
||||
const double wz = G(q,2,d);
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
double s_e = s_E[c+d*VDIM];
|
||||
D[c+VDIM*0] += s_e * wx;
|
||||
D[c+VDIM*1] += s_e * wy;
|
||||
D[c+VDIM*2] += s_e * wz;
|
||||
}
|
||||
}
|
||||
if (eval_flags & DERIVATIVES)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
der(q,c,0,e) = D[c+VDIM*0];
|
||||
der(q,c,1,e) = D[c+VDIM*1];
|
||||
der(q,c,2,e) = D[c+VDIM*2];
|
||||
}
|
||||
}
|
||||
if (VDIM == 3 && (eval_flags & DETERMINANTS))
|
||||
{
|
||||
// The check (VDIM == 3) should eliminate this block when VDIM is
|
||||
// known at compile time and (VDIM != 3).
|
||||
det(q,e) = D[0] * (D[4] * D[8] - D[5] * D[7]) +
|
||||
D[3] * (D[2] * D[7] - D[1] * D[8]) +
|
||||
D[6] * (D[1] * D[5] - D[2] * D[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void QuadratureInterpolator::Mult(
|
||||
const Vector &e_vec, unsigned eval_flags,
|
||||
Vector &q_val, Vector &q_der, Vector &q_det) const
|
||||
{
|
||||
const int ne = fespace->GetNE();
|
||||
if (ne == 0) { return; }
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::FULL);
|
||||
const int nd = maps.ndof;
|
||||
const int nq = maps.nqpt;
|
||||
void (*eval_func)(
|
||||
const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val,
|
||||
Vector &q_der,
|
||||
Vector &q_det,
|
||||
const int eval_flags) = NULL;
|
||||
if (vdim == 1)
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (100*nd + nq)
|
||||
{
|
||||
// Q0
|
||||
case 101: eval_func = &Eval2D<1,1,1>; break;
|
||||
case 104: eval_func = &Eval2D<1,1,4>; break;
|
||||
// Q1
|
||||
case 404: eval_func = &Eval2D<1,4,4>; break;
|
||||
case 409: eval_func = &Eval2D<1,4,9>; break;
|
||||
// Q2
|
||||
case 909: eval_func = &Eval2D<1,9,9>; break;
|
||||
case 916: eval_func = &Eval2D<1,9,16>; break;
|
||||
// Q3
|
||||
case 1616: eval_func = &Eval2D<1,16,16>; break;
|
||||
case 1625: eval_func = &Eval2D<1,16,25>; break;
|
||||
case 1636: eval_func = &Eval2D<1,16,36>; break;
|
||||
// Q4
|
||||
case 2525: eval_func = &Eval2D<1,25,25>; break;
|
||||
case 2536: eval_func = &Eval2D<1,25,36>; break;
|
||||
case 2549: eval_func = &Eval2D<1,25,49>; break;
|
||||
case 2564: eval_func = &Eval2D<1,25,64>; break;
|
||||
}
|
||||
if (nq >= 100 || !eval_func)
|
||||
{
|
||||
eval_func = &Eval2D<1>;
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch (1000*nd + nq)
|
||||
{
|
||||
// Q0
|
||||
case 1001: eval_func = &Eval3D<1,1,1>; break;
|
||||
case 1008: eval_func = &Eval3D<1,1,8>; break;
|
||||
// Q1
|
||||
case 8008: eval_func = &Eval3D<1,8,8>; break;
|
||||
case 8027: eval_func = &Eval3D<1,8,27>; break;
|
||||
// Q2
|
||||
case 27027: eval_func = &Eval3D<1,27,27>; break;
|
||||
case 27064: eval_func = &Eval3D<1,27,64>; break;
|
||||
// Q3
|
||||
case 64064: eval_func = &Eval3D<1,64,64>; break;
|
||||
case 64125: eval_func = &Eval3D<1,64,125>; break;
|
||||
case 64216: eval_func = &Eval3D<1,64,216>; break;
|
||||
// Q4
|
||||
case 125125: eval_func = &Eval3D<1,125,125>; break;
|
||||
case 125216: eval_func = &Eval3D<1,125,216>; break;
|
||||
}
|
||||
if (nq >= 1000 || !eval_func)
|
||||
{
|
||||
eval_func = &Eval3D<1>;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (vdim == dim)
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (100*nd + nq)
|
||||
{
|
||||
// Q1
|
||||
case 404: eval_func = &Eval2D<2,4,4>; break;
|
||||
case 409: eval_func = &Eval2D<2,4,9>; break;
|
||||
// Q2
|
||||
case 909: eval_func = &Eval2D<2,9,9>; break;
|
||||
case 916: eval_func = &Eval2D<2,9,16>; break;
|
||||
// Q3
|
||||
case 1616: eval_func = &Eval2D<2,16,16>; break;
|
||||
case 1625: eval_func = &Eval2D<2,16,25>; break;
|
||||
case 1636: eval_func = &Eval2D<2,16,36>; break;
|
||||
// Q4
|
||||
case 2525: eval_func = &Eval2D<2,25,25>; break;
|
||||
case 2536: eval_func = &Eval2D<2,25,36>; break;
|
||||
case 2549: eval_func = &Eval2D<2,25,49>; break;
|
||||
case 2564: eval_func = &Eval2D<2,25,64>; break;
|
||||
}
|
||||
if (nq >= 100 || !eval_func)
|
||||
{
|
||||
eval_func = &Eval2D<2>;
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch (1000*nd + nq)
|
||||
{
|
||||
// Q1
|
||||
case 8008: eval_func = &Eval3D<3,8,8>; break;
|
||||
case 8027: eval_func = &Eval3D<3,8,27>; break;
|
||||
// Q2
|
||||
case 27027: eval_func = &Eval3D<3,27,27>; break;
|
||||
case 27064: eval_func = &Eval3D<3,27,64>; break;
|
||||
// Q3
|
||||
case 64064: eval_func = &Eval3D<3,64,64>; break;
|
||||
case 64125: eval_func = &Eval3D<3,64,125>; break;
|
||||
case 64216: eval_func = &Eval3D<3,64,216>; break;
|
||||
// Q4
|
||||
case 125125: eval_func = &Eval3D<3,125,125>; break;
|
||||
case 125216: eval_func = &Eval3D<3,125,216>; break;
|
||||
}
|
||||
if (nq >= 1000 || !eval_func)
|
||||
{
|
||||
eval_func = &Eval3D<3>;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (eval_func)
|
||||
{
|
||||
eval_func(ne, vdim, maps, e_vec, q_val, q_der, q_det, eval_flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("case not supported yet");
|
||||
}
|
||||
}
|
||||
|
||||
void QuadratureInterpolator::MultTranspose(
|
||||
unsigned eval_flags, const Vector &q_val, const Vector &q_der,
|
||||
Vector &e_vec) const
|
||||
{
|
||||
MFEM_ABORT("this method is not implemented yet");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
-204
@@ -59,25 +59,9 @@ Ordering::Map<Ordering::byVDIM>(int ndofs, int vdim, int dof, int vd)
|
||||
}
|
||||
|
||||
|
||||
/// Constants describing the possible orderings of the DOFs in one element.
|
||||
enum class ElementDofOrdering
|
||||
{
|
||||
/// Native ordering as defined by the FiniteElement.
|
||||
/** This ordering can be used by tensor-product elements when the
|
||||
interpolation from the DOFs to quadrature points does not use the
|
||||
tensor-product structure. */
|
||||
NATIVE,
|
||||
/// Lexicographic ordering for tensor-product FiniteElements.
|
||||
/** This ordering can be used only with tensor-product elements. */
|
||||
LEXICOGRAPHIC
|
||||
};
|
||||
|
||||
|
||||
// Forward declarations
|
||||
class NURBSExtension;
|
||||
class BilinearFormIntegrator;
|
||||
class QuadratureSpace;
|
||||
class QuadratureInterpolator;
|
||||
|
||||
|
||||
/** @brief Class FiniteElementSpace - responsible for providing FEM view of the
|
||||
@@ -126,11 +110,6 @@ protected:
|
||||
/// Transformation to apply to GridFunctions after space Update().
|
||||
OperatorHandle Th;
|
||||
|
||||
/// The element restriction operators, see GetElementRestriction().
|
||||
mutable OperatorHandle L2E_nat, L2E_lex;
|
||||
|
||||
mutable Array<QuadratureInterpolator*> E2Q_array;
|
||||
|
||||
long sequence; // should match Mesh::GetSequence
|
||||
|
||||
void UpdateNURBS();
|
||||
@@ -146,8 +125,6 @@ protected:
|
||||
|
||||
/// Helper to get vertex, edge or face DOFs (entity=0,1,2 resp.).
|
||||
void GetEntityDofs(int entity, int index, Array<int> &dofs) const;
|
||||
// Get degenerate face DOFs: see explanation in method implementation.
|
||||
void GetDegenerateFaceDofs(int index, Array<int> &dofs) const;
|
||||
|
||||
/// Calculate the cP and cR matrices for a nonconforming mesh.
|
||||
void BuildConformingInterpolation() const;
|
||||
@@ -158,7 +135,6 @@ protected:
|
||||
static bool DofFinalizable(int dof, const Array<bool>& finalized,
|
||||
const SparseMatrix& deps);
|
||||
|
||||
/// Replicate 'mat' in the vector dimension, according to vdim ordering mode.
|
||||
void MakeVDimMatrix(SparseMatrix &mat) const;
|
||||
|
||||
/// GridFunction interpolation operator applicable after mesh refinement.
|
||||
@@ -281,61 +257,14 @@ public:
|
||||
bool Conforming() const { return mesh->Conforming(); }
|
||||
bool Nonconforming() const { return mesh->Nonconforming(); }
|
||||
|
||||
/// The returned SparseMatrix is owned by the FiniteElementSpace.
|
||||
const SparseMatrix *GetConformingProlongation() const;
|
||||
|
||||
/// The returned SparseMatrix is owned by the FiniteElementSpace.
|
||||
const SparseMatrix *GetConformingRestriction() const;
|
||||
|
||||
/// The returned Operator is owned by the FiniteElementSpace.
|
||||
virtual const Operator *GetProlongationMatrix() const
|
||||
{ return GetConformingProlongation(); }
|
||||
|
||||
/// The returned SparseMatrix is owned by the FiniteElementSpace.
|
||||
virtual const SparseMatrix *GetRestrictionMatrix() const
|
||||
{ return GetConformingRestriction(); }
|
||||
|
||||
/// Return an Operator that converts L-vectors to E-vectors.
|
||||
/** An L-vector is a vector of size GetVSize() which is the same size as a
|
||||
GridFunction. An E-vector represents the element-wise discontinuous
|
||||
version of the FE space.
|
||||
|
||||
The layout of the E-vector is: ND x VDIM x NE, where ND is the number of
|
||||
degrees of freedom, VDIM is the vector dimension of the FE space, and NE
|
||||
is the number of the mesh elements.
|
||||
|
||||
The parameter @a e_ordering describes how the local DOFs in each element
|
||||
should be ordered, see ElementDofOrdering.
|
||||
|
||||
For discontinuous spaces, the element restriction corresponds to a
|
||||
permutation of the degrees of freedom, implemented by the
|
||||
L2ElementRestriction class.
|
||||
|
||||
The returned Operator is owned by the FiniteElementSpace. */
|
||||
const Operator *GetElementRestriction(ElementDofOrdering e_ordering) const;
|
||||
|
||||
/** @brief Return a QuadratureInterpolator that interpolates E-vectors to
|
||||
quadrature point values and/or derivatives (Q-vectors). */
|
||||
/** An E-vector represents the element-wise discontinuous version of the FE
|
||||
space and can be obtained, for example, from a GridFunction using the
|
||||
Operator returned by GetElementRestriction().
|
||||
|
||||
All elements will use the same IntegrationRule, @a ir as the target
|
||||
quadrature points. */
|
||||
const QuadratureInterpolator *GetQuadratureInterpolator(
|
||||
const IntegrationRule &ir) const;
|
||||
|
||||
/** @brief Return a QuadratureInterpolator that interpolates E-vectors to
|
||||
quadrature point values and/or derivatives (Q-vectors). */
|
||||
/** An E-vector represents the element-wise discontinuous version of the FE
|
||||
space and can be obtained, for example, from a GridFunction using the
|
||||
Operator returned by GetElementRestriction().
|
||||
|
||||
The target quadrature points in the elements are described by the given
|
||||
QuadratureSpace, @a qs. */
|
||||
const QuadratureInterpolator *GetQuadratureInterpolator(
|
||||
const QuadratureSpace &qs) const;
|
||||
|
||||
/// Returns vector dimension.
|
||||
inline int GetVDim() const { return vdim; }
|
||||
|
||||
@@ -877,139 +806,6 @@ public:
|
||||
virtual const Operator &BackwardOperator();
|
||||
};
|
||||
|
||||
|
||||
/// Operator that converts FiniteElementSpace L-vectors to E-vectors.
|
||||
/** Objects of this type are typically created and owned by FiniteElementSpace
|
||||
objects, see FiniteElementSpace::GetElementRestriction(). */
|
||||
class ElementRestriction : public Operator
|
||||
{
|
||||
protected:
|
||||
const FiniteElementSpace &fes;
|
||||
const int ne;
|
||||
const int vdim;
|
||||
const bool byvdim;
|
||||
const int ndofs;
|
||||
const int dof;
|
||||
const int nedofs;
|
||||
Array<int> offsets;
|
||||
Array<int> indices;
|
||||
|
||||
public:
|
||||
ElementRestriction(const FiniteElementSpace&, ElementDofOrdering);
|
||||
void Mult(const Vector &x, Vector &y) const;
|
||||
void MultTranspose(const Vector &x, Vector &y) const;
|
||||
};
|
||||
|
||||
/// Operator that converts L2 FiniteElementSpace L-vectors to E-vectors.
|
||||
/** Objects of this type are typically created and owned by FiniteElementSpace
|
||||
objects, see FiniteElementSpace::GetElementRestriction(). L-vectors
|
||||
corresponding to grid functions in L2 finite element spaces differ from
|
||||
E-vectors only in the ordering of the degrees of freedom. */
|
||||
class L2ElementRestriction : public Operator
|
||||
{
|
||||
const int ne;
|
||||
const int vdim;
|
||||
const bool byvdim;
|
||||
const int ndof;
|
||||
public:
|
||||
L2ElementRestriction(const FiniteElementSpace&);
|
||||
void Mult(const Vector &x, Vector &y) const;
|
||||
void MultTranspose(const Vector &x, Vector &y) const;
|
||||
};
|
||||
|
||||
/** @brief A class that performs interpolation from an E-vector to quadrature
|
||||
point values and/or derivatives (Q-vectors). */
|
||||
/** An E-vector represents the element-wise discontinuous version of the FE
|
||||
space and can be obtained, for example, from a GridFunction using the
|
||||
Operator returned by FiniteElementSpace::GetElementRestriction().
|
||||
|
||||
The target quadrature points in the elements can be described either by an
|
||||
IntegrationRule (all mesh elements must be of the same type in this case) or
|
||||
by a QuadratureSpace. */
|
||||
class QuadratureInterpolator
|
||||
{
|
||||
protected:
|
||||
friend class FiniteElementSpace; // Needs access to qspace and IntRule
|
||||
|
||||
const FiniteElementSpace *fespace; ///< Not owned
|
||||
const QuadratureSpace *qspace; ///< Not owned
|
||||
const IntegrationRule *IntRule; ///< Not owned
|
||||
|
||||
mutable bool use_tensor_products;
|
||||
|
||||
static const int MAX_NQ2D = 100;
|
||||
static const int MAX_ND2D = 100;
|
||||
static const int MAX_VDIM2D = 2;
|
||||
|
||||
static const int MAX_NQ3D = 1000;
|
||||
static const int MAX_ND3D = 1000;
|
||||
static const int MAX_VDIM3D = 3;
|
||||
|
||||
public:
|
||||
enum EvalFlags
|
||||
{
|
||||
VALUES = 1 << 0, ///< Evaluate the values at quadrature points
|
||||
DERIVATIVES = 1 << 1, ///< Evaluate the derivatives at quadrature points
|
||||
/** @brief Assuming the derivative at quadrature points form a matrix,
|
||||
this flag can be used to compute and store their determinants. This
|
||||
flag can only be used in Mult(). */
|
||||
DETERMINANTS = 1 << 2
|
||||
};
|
||||
|
||||
QuadratureInterpolator(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir);
|
||||
|
||||
QuadratureInterpolator(const FiniteElementSpace &fes,
|
||||
const QuadratureSpace &qs);
|
||||
|
||||
/** @brief Disable the use of tensor product evaluations, for tensor-product
|
||||
elements, e.g. quads and hexes. */
|
||||
/** Currently, tensor product evaluations are not implemented and this method
|
||||
has no effect. */
|
||||
void DisableTensorProducts(bool disable = true) const
|
||||
{ use_tensor_products = !disable; }
|
||||
|
||||
/// Interpolate the E-vector @a e_vec to quadrature points.
|
||||
/** The @a eval_flags are a bitwise mask of constants from the EvalFlags
|
||||
enumeration. When the VALUES flag is set, the values at quadrature points
|
||||
are computed and stored in the Vector @a q_val. Similarly, when the flag
|
||||
DERIVATIVES is set, the derivatives are computed and stored in @a q_der.
|
||||
When the DETERMINANTS flags is set, it is assumed that the derivatives
|
||||
form a matrix at each quadrature point (i.e. the associated
|
||||
FiniteElementSpace is a vector space) and their determinants are computed
|
||||
and stored in @a q_det. */
|
||||
void Mult(const Vector &e_vec, unsigned eval_flags,
|
||||
Vector &q_val, Vector &q_der, Vector &q_det) const;
|
||||
|
||||
/// Perform the transpose operation of Mult(). (TODO)
|
||||
void MultTranspose(unsigned eval_flags, const Vector &q_val,
|
||||
const Vector &q_der, Vector &e_vec) const;
|
||||
|
||||
// Compute kernels follow (cannot be private or protected with nvcc)
|
||||
|
||||
/// Template compute kernel for 2D.
|
||||
template<const int T_VDIM = 0, const int T_ND = 0, const int T_NQ = 0>
|
||||
static void Eval2D(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val,
|
||||
Vector &q_der,
|
||||
Vector &q_det,
|
||||
const int eval_flags);
|
||||
|
||||
/// Template compute kernel for 3D.
|
||||
template<const int T_VDIM = 0, const int T_ND = 0, const int T_NQ = 0>
|
||||
static void Eval3D(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val,
|
||||
Vector &q_der,
|
||||
Vector &q_det,
|
||||
const int eval_flags);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+15
-21
@@ -30,9 +30,6 @@ using namespace std;
|
||||
GridFunction::GridFunction(Mesh *m, std::istream &input)
|
||||
: Vector()
|
||||
{
|
||||
// Grid functions are stored on the device
|
||||
UseDevice(true);
|
||||
|
||||
fes = new FiniteElementSpace;
|
||||
fec = fes->Load(m, input);
|
||||
|
||||
@@ -63,8 +60,6 @@ GridFunction::GridFunction(Mesh *m, std::istream &input)
|
||||
|
||||
GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
|
||||
{
|
||||
UseDevice(true);
|
||||
|
||||
// all GridFunctions must have the same FE collection, vdim, ordering
|
||||
int vdim, ordering;
|
||||
|
||||
@@ -168,7 +163,6 @@ void GridFunction::Update()
|
||||
Vector old_data;
|
||||
old_data.Swap(*this);
|
||||
SetSize(T->Height());
|
||||
UseDevice(true);
|
||||
T->Mult(old_data, *this);
|
||||
}
|
||||
else
|
||||
@@ -198,9 +192,7 @@ void GridFunction::MakeRef(FiniteElementSpace *f, Vector &v, int v_offset)
|
||||
MFEM_ASSERT(v.Size() >= v_offset + f->GetVSize(), "");
|
||||
if (f != fes) { Destroy(); }
|
||||
fes = f;
|
||||
v.UseDevice(true);
|
||||
NewMemoryAndSize(Memory<double>(v.GetMemory(), v_offset, fes->GetVSize()),
|
||||
fes->GetVSize(), true);
|
||||
NewDataAndSize((double *)v + v_offset, fes->GetVSize());
|
||||
sequence = fes->GetSequence();
|
||||
}
|
||||
|
||||
@@ -223,16 +215,13 @@ void GridFunction::MakeTRef(FiniteElementSpace *f, Vector &tv, int tv_offset)
|
||||
if (!f->GetProlongationMatrix())
|
||||
{
|
||||
MakeRef(f, tv, tv_offset);
|
||||
t_vec.NewMemoryAndSize(data, size, false);
|
||||
t_vec.NewDataAndSize(data, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ASSERT(tv.Size() >= tv_offset + f->GetTrueVSize(), "");
|
||||
SetSpace(f); // works in parallel
|
||||
tv.UseDevice(true);
|
||||
const int tv_size = f->GetTrueVSize();
|
||||
t_vec.NewMemoryAndSize(Memory<double>(tv.GetMemory(), tv_offset, tv_size),
|
||||
tv_size, true);
|
||||
t_vec.NewDataAndSize(&tv(tv_offset), f->GetTrueVSize());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +302,7 @@ int GridFunction::VectorDim() const
|
||||
{
|
||||
fe = fes->GetFE(0);
|
||||
}
|
||||
if (!fe || fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
if (fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
return fes->GetVDim();
|
||||
}
|
||||
@@ -326,7 +315,7 @@ void GridFunction::GetTrueDofs(Vector &tv) const
|
||||
if (!R)
|
||||
{
|
||||
// R is identity -> make tv a reference to *this
|
||||
tv.NewDataAndSize(const_cast<double*>((const double*)data), size);
|
||||
tv.NewDataAndSize(data, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1378,7 +1367,7 @@ void GridFunction::AccumulateAndCountBdrValues(
|
||||
if (vdofs.Size() == 0) { continue; }
|
||||
|
||||
transf = mesh->GetEdgeTransformation(edge);
|
||||
transf->Attribute = -1; // TODO: set the boundary attribute
|
||||
transf->Attribute = -1; // FIXME: set the boundary attribute
|
||||
fe = fes->GetEdgeElement(edge);
|
||||
if (!vcoeff)
|
||||
{
|
||||
@@ -1482,7 +1471,7 @@ void GridFunction::AccumulateAndCountBdrTangentValues(
|
||||
if (dofs.Size() == 0) { continue; }
|
||||
|
||||
T = mesh->GetEdgeTransformation(edge);
|
||||
T->Attribute = -1; // TODO: set the boundary attribute
|
||||
T->Attribute = -1; // FIXME: set the boundary attribute
|
||||
fe = fes->GetEdgeElement(edge);
|
||||
lvec.SetSize(fe->GetDof());
|
||||
fe->Project(vcoeff, *T, lvec);
|
||||
@@ -1716,7 +1705,6 @@ void GridFunction::ProjectDiscCoefficient(VectorCoefficient &coeff,
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
|
||||
HostWrite();
|
||||
// maximal element attribute for each dof
|
||||
dof_attr.SetSize(fes->GetVSize());
|
||||
dof_attr = -1;
|
||||
@@ -1788,7 +1776,6 @@ void GridFunction::ProjectBdrCoefficient(VectorCoefficient &vcoeff,
|
||||
void GridFunction::ProjectBdrCoefficient(Coefficient *coeff[], Array<int> &attr)
|
||||
{
|
||||
Array<int> values_counter;
|
||||
this->HostReadWrite();
|
||||
AccumulateAndCountBdrValues(coeff, NULL, attr, values_counter);
|
||||
ComputeMeans(ARITHMETIC, values_counter);
|
||||
#ifdef MFEM_DEBUG
|
||||
@@ -2323,7 +2310,14 @@ double GridFunction::ComputeLpError(const double p, Coefficient &exsol,
|
||||
else
|
||||
{
|
||||
int intorder = 2*fe->GetOrder() + 1; // <----------
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
if (fe->Space() == FunctionSpace::SBPk)
|
||||
{
|
||||
ir = &(fe->GetNodes());
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
}
|
||||
GetValues(i, *ir, vals);
|
||||
T = fes->GetElementTransformation(i);
|
||||
|
||||
+7
-14
@@ -68,16 +68,15 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
GridFunction() { fes = NULL; fec = NULL; sequence = 0; UseDevice(true); }
|
||||
GridFunction() { fes = NULL; fec = NULL; sequence = 0; }
|
||||
|
||||
/// Copy constructor. The internal true-dof vector #t_vec is not copied.
|
||||
GridFunction(const GridFunction &orig)
|
||||
: Vector(orig), fes(orig.fes), fec(NULL), sequence(orig.sequence)
|
||||
{ UseDevice(true); }
|
||||
: Vector(orig), fes(orig.fes), fec(NULL), sequence(orig.sequence) { }
|
||||
|
||||
/// Construct a GridFunction associated with the FiniteElementSpace @a *f.
|
||||
GridFunction(FiniteElementSpace *f) : Vector(f->GetVSize())
|
||||
{ fes = f; fec = NULL; sequence = f->GetSequence(); UseDevice(true); }
|
||||
{ fes = f; fec = NULL; sequence = f->GetSequence(); }
|
||||
|
||||
/// Construct a GridFunction using previously allocated array @a data.
|
||||
/** The GridFunction does not assume ownership of @a data which is assumed to
|
||||
@@ -85,9 +84,8 @@ public:
|
||||
for externally allocated array, the pointer @a data can be NULL. The data
|
||||
array can be replaced later using the method SetData().
|
||||
*/
|
||||
GridFunction(FiniteElementSpace *f, double *data)
|
||||
: Vector(data, f->GetVSize())
|
||||
{ fes = f; fec = NULL; sequence = f->GetSequence(); UseDevice(true); }
|
||||
GridFunction(FiniteElementSpace *f, double *data) : Vector(data, f->GetVSize())
|
||||
{ fes = f; fec = NULL; sequence = f->GetSequence(); }
|
||||
|
||||
/// 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
|
||||
@@ -126,7 +124,6 @@ public:
|
||||
|
||||
/// @brief Extract the true-dofs from the GridFunction. If all dofs are true,
|
||||
/// then `tv` will be set to point to the data of `*this`.
|
||||
/** @warning This method breaks const-ness when all dofs are true. */
|
||||
void GetTrueDofs(Vector &tv) const;
|
||||
|
||||
/// Shortcut for calling GetTrueDofs() with GetTrueVector() as argument.
|
||||
@@ -434,8 +431,6 @@ public:
|
||||
/** The GridFunction is resized using the SetSize() method. */
|
||||
virtual void SetSpace(FiniteElementSpace *f);
|
||||
|
||||
using Vector::MakeRef;
|
||||
|
||||
/** @brief Make the GridFunction reference external data on a new
|
||||
FiniteElementSpace. */
|
||||
/** This method changes the FiniteElementSpace associated with the
|
||||
@@ -707,7 +702,7 @@ inline void QuadratureFunction::GetElementValues(int idx, Vector &values) const
|
||||
const int s_offset = qspace->element_offsets[idx];
|
||||
const int sl_size = qspace->element_offsets[idx+1] - s_offset;
|
||||
values.SetSize(vdim*sl_size);
|
||||
const double *q = data + vdim*s_offset;
|
||||
double *q = data + vdim*s_offset;
|
||||
for (int i = 0; i<values.Size(); i++)
|
||||
{
|
||||
values(i) = *(q++);
|
||||
@@ -727,14 +722,12 @@ inline void QuadratureFunction::GetElementValues(int idx,
|
||||
const int s_offset = qspace->element_offsets[idx];
|
||||
const int sl_size = qspace->element_offsets[idx+1] - s_offset;
|
||||
values.SetSize(vdim, sl_size);
|
||||
const double *q = data + vdim*s_offset;
|
||||
double *q = data + vdim*s_offset;
|
||||
for (int j = 0; j<sl_size; j++)
|
||||
{
|
||||
for (int i = 0; i<vdim; i++)
|
||||
{
|
||||
values(i,j) = *(q++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -78,19 +78,6 @@ IntegrationRule::IntegrationRule(IntegrationRule &irx, IntegrationRule &iry,
|
||||
}
|
||||
}
|
||||
|
||||
const Array<double> &IntegrationRule::GetWeights() const
|
||||
{
|
||||
if (weights.Size() != GetNPoints())
|
||||
{
|
||||
weights.SetSize(GetNPoints());
|
||||
for (int i = 0; i < GetNPoints(); i++)
|
||||
{
|
||||
weights[i] = IntPoint(i).weight;
|
||||
}
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
void IntegrationRule::GrundmannMollerSimplexRule(int s, int n)
|
||||
{
|
||||
// for pow on older compilers
|
||||
|
||||
@@ -87,9 +87,6 @@ class IntegrationRule : public Array<IntegrationPoint>
|
||||
private:
|
||||
friend class IntegrationRules;
|
||||
int Order;
|
||||
/** @brief The quadrature weights gathered as a contiguous array. Created
|
||||
by request with the method GetWeights(). */
|
||||
mutable Array<double> weights;
|
||||
|
||||
/// Define n-simplex rule (triangle/tetrahedron for n=2/3) of order (2s+1)
|
||||
void GrundmannMollerSimplexRule(int s, int n = 3);
|
||||
@@ -242,11 +239,6 @@ public:
|
||||
/// Returns a const reference to the i-th integration point
|
||||
const IntegrationPoint &IntPoint(int i) const { return (*this)[i]; }
|
||||
|
||||
/// Return the quadrature weights in a contiguous array.
|
||||
/** If a contiguous array is not required, the weights can be accessed with
|
||||
a call like this: `IntPoint(i).weight`. */
|
||||
const Array<double> &GetWeights() const;
|
||||
|
||||
/// Destroys an IntegrationRule object
|
||||
~IntegrationRule() { }
|
||||
};
|
||||
|
||||
@@ -19,9 +19,6 @@ namespace mfem
|
||||
LinearForm::LinearForm(FiniteElementSpace *f, LinearForm *lf)
|
||||
: Vector(f->GetVSize())
|
||||
{
|
||||
// Linear forms are stored on the device
|
||||
UseDevice(true);
|
||||
|
||||
fes = f;
|
||||
extern_lfs = 1;
|
||||
|
||||
@@ -86,10 +83,6 @@ void LinearForm::Assemble()
|
||||
|
||||
Vector::operator=(0.0);
|
||||
|
||||
// The above operation is executed on device because of UseDevice().
|
||||
// The first use of AddElementVector() below will move it back to host
|
||||
// because both 'vdofs' and 'elemvect' are on host.
|
||||
|
||||
if (dlfi.Size())
|
||||
{
|
||||
for (i = 0; i < fes -> GetNE(); i++)
|
||||
@@ -138,11 +131,7 @@ void LinearForm::Assemble()
|
||||
eltrans = fes -> GetBdrElementTransformation (i);
|
||||
for (int k=0; k < blfi.Size(); k++)
|
||||
{
|
||||
if (blfi_marker[k] &&
|
||||
(*blfi_marker[k])[bdr_attr-1] == 0) { continue; }
|
||||
|
||||
blfi[k]->AssembleRHSElementVect(*fes->GetBE(i), *eltrans, elemvect);
|
||||
|
||||
AddElementVector (vdofs, elemvect);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -64,7 +64,7 @@ public:
|
||||
/// Creates linear form associated with FE space @a *f.
|
||||
/** The pointer @a f is not owned by the newly constructed object. */
|
||||
LinearForm(FiniteElementSpace *f) : Vector(f->GetVSize())
|
||||
{ fes = f; extern_lfs = 0; UseDevice(true); }
|
||||
{ fes = f; extern_lfs = 0; }
|
||||
|
||||
/** @brief Create a LinearForm on the FiniteElementSpace @a f, using the
|
||||
same integrators as the LinearForm @a lf.
|
||||
@@ -79,7 +79,7 @@ public:
|
||||
/** The associated FiniteElementSpace can be set later using one of the
|
||||
methods: Update(FiniteElementSpace *) or
|
||||
Update(FiniteElementSpace *, Vector &, int). */
|
||||
LinearForm() { fes = NULL; extern_lfs = 0; UseDevice(true); }
|
||||
LinearForm() { fes = NULL; extern_lfs = 0; }
|
||||
|
||||
/// Copy assignment. Only the data of the base class Vector is copied.
|
||||
/** It is assumed that this object and @a rhs use FiniteElementSpace%s that
|
||||
|
||||
+19
-18
@@ -36,9 +36,16 @@ void DomainLFIntegrator::AssembleRHSElementVect(const FiniteElement &el,
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
// ir = &IntRules.Get(el.GetGeomType(),
|
||||
// oa * el.GetOrder() + ob + Tr.OrderW());
|
||||
ir = &IntRules.Get(el.GetGeomType(), oa * el.GetOrder() + ob);
|
||||
if (el.Space() == FunctionSpace::SBPk)
|
||||
{
|
||||
ir = &el.GetNodes();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ir = &IntRules.Get(el.GetGeomType(),
|
||||
// oa * el.GetOrder() + ob + Tr.OrderW());
|
||||
ir = &IntRules.Get(el.GetGeomType(), oa * el.GetOrder() + ob);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
@@ -181,7 +188,7 @@ void VectorDomainLFIntegrator::AssembleRHSElementVect(
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2*el.GetOrder();
|
||||
int intorder = el.GetOrder() + 1;
|
||||
ir = &IntRules.Get(el.GetGeomType(), intorder);
|
||||
}
|
||||
|
||||
@@ -240,7 +247,7 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2*el.GetOrder();
|
||||
int intorder = el.GetOrder() + 1;
|
||||
ir = &IntRules.Get(el.GetGeomType(), intorder);
|
||||
}
|
||||
|
||||
@@ -275,7 +282,7 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2*el.GetOrder();
|
||||
int intorder = el.GetOrder() + 1;
|
||||
ir = &IntRules.Get(Tr.FaceGeom, intorder);
|
||||
}
|
||||
|
||||
@@ -350,6 +357,7 @@ void VectorFEDomainLFIntegrator::AssembleDeltaElementVect(
|
||||
vshape.Mult(vec, elvect);
|
||||
}
|
||||
|
||||
|
||||
void VectorBoundaryFluxLFIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
@@ -396,26 +404,19 @@ void VectorFEBoundaryFluxLFIntegrator::AssembleRHSElementVect(
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2*el.GetOrder(); // <----------
|
||||
if (F == NULL)
|
||||
{
|
||||
intorder -= el.GetOrder() + 1;
|
||||
}
|
||||
ir = &IntRules.Get(el.GetGeomType(), intorder);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
Tr.SetIntPoint (&ip);
|
||||
double val = ip.weight*F.Eval(Tr, ip);
|
||||
|
||||
el.CalcShape(ip, shape);
|
||||
|
||||
double val = ip.weight;
|
||||
if (F)
|
||||
{
|
||||
Tr.SetIntPoint (&ip);
|
||||
val *= F->Eval(Tr, ip);
|
||||
}
|
||||
|
||||
elvect.Add(val, shape);
|
||||
add(elvect, val, shape, elvect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -279,12 +279,11 @@ public:
|
||||
class VectorFEBoundaryFluxLFIntegrator : public LinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
Coefficient *F;
|
||||
Coefficient &F;
|
||||
Vector shape;
|
||||
|
||||
public:
|
||||
VectorFEBoundaryFluxLFIntegrator() : F(NULL) { }
|
||||
VectorFEBoundaryFluxLFIntegrator(Coefficient &f) : F(&f) { }
|
||||
VectorFEBoundaryFluxLFIntegrator(Coefficient &f) : F(f) { }
|
||||
|
||||
virtual void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
|
||||
+3
-72
@@ -65,8 +65,6 @@ double NonlinearForm::GetGridFunctionEnergy(const Vector &x) const
|
||||
Vector el_x;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *T;
|
||||
Mesh *mesh = fes->GetMesh();
|
||||
|
||||
double energy = 0.0;
|
||||
|
||||
if (dnfi.Size())
|
||||
@@ -86,81 +84,14 @@ double NonlinearForm::GetGridFunctionEnergy(const Vector &x) const
|
||||
|
||||
if (fnfi.Size())
|
||||
{
|
||||
FaceElementTransformations *tr;
|
||||
const FiniteElement *fe1, *fe2;
|
||||
Array<int> vdofs2;
|
||||
|
||||
for (int i = 0; i < mesh->GetNumFaces(); i++)
|
||||
{
|
||||
tr = mesh->GetInteriorFaceTransformations(i);
|
||||
if (tr != NULL)
|
||||
{
|
||||
fes->GetElementVDofs(tr->Elem1No, vdofs);
|
||||
fes->GetElementVDofs(tr->Elem2No, vdofs2);
|
||||
vdofs.Append (vdofs2);
|
||||
x.GetSubVector(vdofs, el_x);
|
||||
fe1 = fes->GetFE(tr->Elem1No);
|
||||
fe2 = fes->GetFE(tr->Elem2No);
|
||||
for (int k = 0; k < fnfi.Size(); k++)
|
||||
{
|
||||
energy += fnfi[k]->GetFaceEnergy(*fe1, *fe2, *tr, el_x);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("TODO: add energy contribution from interior face terms");
|
||||
}
|
||||
|
||||
if (bfnfi.Size())
|
||||
{
|
||||
FaceElementTransformations *tr;
|
||||
const FiniteElement *fe1, *fe2;
|
||||
|
||||
// Which boundary attributes need to be processed?
|
||||
Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
|
||||
mesh->bdr_attributes.Max() : 0);
|
||||
bdr_attr_marker = 0;
|
||||
for (int k = 0; k < bfnfi.Size(); k++)
|
||||
{
|
||||
if (bfnfi_marker[k] == NULL)
|
||||
{
|
||||
bdr_attr_marker = 1;
|
||||
break;
|
||||
}
|
||||
Array<int> &bdr_marker = *bfnfi_marker[k];
|
||||
MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
|
||||
"invalid boundary marker for boundary face integrator #"
|
||||
<< k << ", counting from zero");
|
||||
for (int i = 0; i < bdr_attr_marker.Size(); i++)
|
||||
{
|
||||
bdr_attr_marker[i] |= bdr_marker[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < fes -> GetNBE(); i++)
|
||||
{
|
||||
const int bdr_attr = mesh->GetBdrAttribute(i);
|
||||
if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
|
||||
|
||||
tr = mesh->GetBdrFaceTransformations (i);
|
||||
if (tr != NULL)
|
||||
{
|
||||
fes->GetElementVDofs(tr->Elem1No, vdofs);
|
||||
x.GetSubVector(vdofs, el_x);
|
||||
|
||||
fe1 = fes->GetFE(tr->Elem1No);
|
||||
// The fe2 object is really a dummy and not used on the boundaries,
|
||||
// but we can't dereference a NULL pointer, and we don't want to
|
||||
// actually make a fake element.
|
||||
fe2 = fe1;
|
||||
for (int k = 0; k < bfnfi.Size(); k++)
|
||||
{
|
||||
if (bfnfi_marker[k] &&
|
||||
(*bfnfi_marker[k])[bdr_attr-1] == 0) { continue; }
|
||||
|
||||
energy += bfnfi[k]->GetFaceEnergy(*fe1, *fe2, *tr, el_x);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("TODO: add energy contribution from boundary face terms");
|
||||
}
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
be fes->GetVSize(). */
|
||||
double GetGridFunctionEnergy(const Vector &x) const;
|
||||
|
||||
/// Compute the energy corresponding to the state @a x.
|
||||
/// Compute the enery corresponding to the state @a x.
|
||||
/** In general, @a x may have non-homogeneous essential boundary values.
|
||||
|
||||
The state @a x must be a true-dof vector. */
|
||||
|
||||
@@ -55,14 +55,6 @@ double NonlinearFormIntegrator::GetElementEnergy(
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double NonlinearFormIntegrator::GetFaceEnergy(
|
||||
const FiniteElement &el1, const FiniteElement &el2,
|
||||
FaceElementTransformations &Tr, const Vector &elfun)
|
||||
{
|
||||
mfem_error("NonlinearFormIntegrator::GetFaceEnergy"
|
||||
" is not overloaded!");
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void BlockNonlinearFormIntegrator::AssembleElementVector(
|
||||
const Array<const FiniteElement *> &el,
|
||||
|
||||
+1
-7
@@ -63,17 +63,11 @@ public:
|
||||
FaceElementTransformations &Tr,
|
||||
const Vector &elfun, DenseMatrix &elmat);
|
||||
|
||||
/// Compute the local energy/functional
|
||||
/// Compute the local energy
|
||||
virtual double GetElementEnergy(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
const Vector &elfun);
|
||||
|
||||
/// Compute the face(s) contribution to the energy/functional
|
||||
virtual double GetFaceEnergy(const FiniteElement &el1,
|
||||
const FiniteElement &el2,
|
||||
FaceElementTransformations &Tr,
|
||||
const Vector &elfun);
|
||||
|
||||
virtual ~NonlinearFormIntegrator() { }
|
||||
};
|
||||
|
||||
|
||||
+42
-49
@@ -35,30 +35,25 @@ typedef double* QLocal2D_t @dim(Q1D, Q1D, NE);
|
||||
typedef double* DLocal3D_t @dim(D1D, D1D, D1D, NE);
|
||||
typedef double* QLocal3D_t @dim(Q1D, Q1D, Q1D, NE);
|
||||
|
||||
typedef double* Jacobian2D_t @dim(Q2D, 2, 2, NE);
|
||||
typedef double* Jacobian3D_t @dim(Q3D, 3, 3, NE);
|
||||
typedef double* Jacobian2D_t @dim(2, 2, Q2D, NE);
|
||||
typedef double* Jacobian3D_t @dim(3, 3, Q3D, NE);
|
||||
|
||||
typedef double* Coeff2D_t @dim(Q2D, NE);
|
||||
typedef double* Coeff3D_t @dim(Q3D, NE);
|
||||
|
||||
typedef double* SymmOperator2D_t @dim(Q2D, 3, NE);
|
||||
typedef double* SymmOperator3D_t @dim(Q3D, 6, NE);
|
||||
typedef double* SymmOperator2D_t @dim(3, Q2D, NE);
|
||||
typedef double* SymmOperator3D_t @dim(6, Q3D, NE);
|
||||
|
||||
@kernel void DiffusionSetup2D(const int NE,
|
||||
@restrict const double *W,
|
||||
@restrict const Jacobian2D_t J,
|
||||
@restrict const Coeff2D_t C,
|
||||
@restrict SymmOperator2D_t op,
|
||||
const bool const_c) {
|
||||
const double COEFF,
|
||||
@restrict SymmOperator2D_t op) {
|
||||
for (int e = 0; e < NE; ++e; @outer) {
|
||||
for (int q = 0; q < Q2D; ++q; @inner) {
|
||||
const double J11 = J(q, 0, 0, e), J12 = J(q, 1, 0, e);
|
||||
const double J21 = J(q, 0, 1, e), J22 = J(q, 1, 1, e);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
const double c_detJ = W[q] * coeff / ((J11 * J22) - (J21 * J12));
|
||||
op(q, 0, e) = c_detJ * (J21*J21 + J22*J22); // (1,1)
|
||||
op(q, 1, e) = -c_detJ * (J21*J11 + J22*J12); // (1,2), (2,1)
|
||||
op(q, 2, e) = c_detJ * (J11*J11 + J12*J12); // (2,2)
|
||||
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e);
|
||||
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e);
|
||||
const double c_detJ = W[q] * COEFF / ((J11 * J22) - (J21 * J12));
|
||||
op(0, q, e) = c_detJ * (J21*J21 + J22*J22); // (1,1)
|
||||
op(1, q, e) = -c_detJ * (J21*J11 + J22*J12); // (1,2), (2,1)
|
||||
op(2, q, e) = c_detJ * (J11*J11 + J12*J12); // (2,2)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,20 +61,18 @@ typedef double* SymmOperator3D_t @dim(Q3D, 6, NE);
|
||||
@kernel void DiffusionSetup3D(const int NE,
|
||||
@restrict const double *W,
|
||||
@restrict const Jacobian3D_t J,
|
||||
@restrict const Coeff3D_t C,
|
||||
@restrict SymmOperator3D_t op,
|
||||
const bool const_c) {
|
||||
const double COEFF,
|
||||
@restrict SymmOperator3D_t op) {
|
||||
for (int e = 0; e < NE; ++e; @outer) {
|
||||
for (int q = 0; q < Q3D; ++q; @inner) {
|
||||
const double J11 = J(q, 0, 0, e), J12 = J(q, 1, 0, e), J13 = J(q, 2, 0, e);
|
||||
const double J21 = J(q, 0, 1, e), J22 = J(q, 1, 1, e), J23 = J(q, 2, 1, e);
|
||||
const double J31 = J(q, 0, 2, e), J32 = J(q, 1, 2, e), J33 = J(q, 2, 2, e);
|
||||
const double J11 = J(0, 0, q, e), J12 = J(1, 0, q, e), J13 = J(2, 0, q, e);
|
||||
const double J21 = J(0, 1, q, e), J22 = J(1, 1, q, e), J23 = J(2, 1, q, e);
|
||||
const double J31 = J(0, 2, q, e), J32 = J(1, 2, q, e), J33 = J(2, 2, q, e);
|
||||
|
||||
const double detJ = ((J11 * J22 * J33) + (J12 * J23 * J31) + (J13 * J21 * J32) -
|
||||
(J13 * J22 * J31) - (J12 * J21 * J33) - (J11 * J23 * J32));
|
||||
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
const double c_detJ = W[q] * coeff / detJ;
|
||||
const double c_detJ = W[q] * COEFF / detJ;
|
||||
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
@@ -95,12 +88,12 @@ typedef double* SymmOperator3D_t @dim(Q3D, 6, NE);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
|
||||
// adj(J)^Tadj(J)
|
||||
op(q, 0, e) = c_detJ * (A11*A11 + A21*A21 + A31*A31); // (1,1)
|
||||
op(q, 1, e) = c_detJ * (A11*A12 + A21*A22 + A31*A32); // (1,2), (2,1)
|
||||
op(q, 2, e) = c_detJ * (A11*A13 + A21*A23 + A31*A33); // (1,3), (3,1)
|
||||
op(q, 3, e) = c_detJ * (A12*A12 + A22*A22 + A32*A32); // (2,2)
|
||||
op(q, 4, e) = c_detJ * (A12*A13 + A22*A23 + A32*A33); // (2,3), (3,2)
|
||||
op(q, 5, e) = c_detJ * (A13*A13 + A23*A23 + A33*A33); // (3,3)
|
||||
op(0, q, e) = c_detJ * (A11*A11 + A21*A21 + A31*A31); // (1,1)
|
||||
op(1, q, e) = c_detJ * (A11*A12 + A21*A22 + A31*A32); // (1,2), (2,1)
|
||||
op(2, q, e) = c_detJ * (A11*A13 + A21*A23 + A31*A33); // (1,3), (3,1)
|
||||
op(3, q, e) = c_detJ * (A12*A12 + A22*A22 + A32*A32); // (2,2)
|
||||
op(4, q, e) = c_detJ * (A12*A13 + A22*A23 + A32*A33); // (2,3), (3,2)
|
||||
op(5, q, e) = c_detJ * (A13*A13 + A23*A23 + A33*A33); // (3,3)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,9 +146,9 @@ typedef double* SymmOperator3D_t @dim(Q3D, 6, NE);
|
||||
for (int qy = 0; qy < Q1D; ++qy) {
|
||||
for (int qx = 0; qx < Q1D; ++qx) {
|
||||
const int q = QUAD_2D_ID(qx, qy);
|
||||
const double O11 = op(q, 0, e);
|
||||
const double O12 = op(q, 1, e);
|
||||
const double O22 = op(q, 2, e);
|
||||
const double O11 = op(0, q, e);
|
||||
const double O12 = op(1, q, e);
|
||||
const double O22 = op(2, q, e);
|
||||
|
||||
const double gradX = grad[qy][qx][0];
|
||||
const double gradY = grad[qy][qx][1];
|
||||
@@ -262,9 +255,9 @@ typedef double* SymmOperator3D_t @dim(Q3D, 6, NE);
|
||||
}
|
||||
|
||||
const int q = QUAD_2D_ID(qx, qy);
|
||||
const double O11 = op(q, 0, e);
|
||||
const double O12 = op(q, 1, e);
|
||||
const double O22 = op(q, 2, e);
|
||||
const double O11 = op(0, q, e);
|
||||
const double O12 = op(1, q, e);
|
||||
const double O22 = op(2, q, e);
|
||||
|
||||
s_grad(0, qx, qy) = (O11 * gradX) + (O12 * gradY);
|
||||
s_grad(1, qx, qy) = (O12 * gradX) + (O22 * gradY);
|
||||
@@ -389,12 +382,12 @@ typedef double* SymmOperator3D_t @dim(Q3D, 6, NE);
|
||||
for (int qy = 0; qy < Q1D; ++qy) {
|
||||
for (int qx = 0; qx < Q1D; ++qx) {
|
||||
const int q = QUAD_3D_ID(qx, qy, qz);
|
||||
const double O11 = op(q, 0, e);
|
||||
const double O12 = op(q, 1, e);
|
||||
const double O13 = op(q, 2, e);
|
||||
const double O22 = op(q, 3, e);
|
||||
const double O23 = op(q, 4, e);
|
||||
const double O33 = op(q, 5, e);
|
||||
const double O11 = op(0, q, e);
|
||||
const double O12 = op(1, q, e);
|
||||
const double O13 = op(2, q, e);
|
||||
const double O22 = op(3, q, e);
|
||||
const double O23 = op(4, q, e);
|
||||
const double O33 = op(5, q, e);
|
||||
|
||||
const double gradX = grad[qz][qy][qx][0];
|
||||
const double gradY = grad[qz][qy][qx][1];
|
||||
@@ -564,12 +557,12 @@ typedef double* SymmOperator3D_t @dim(Q3D, 6, NE);
|
||||
}
|
||||
|
||||
const int q = QUAD_3D_ID(qx, qy, qz);
|
||||
const double O11 = op(q, 0, e);
|
||||
const double O12 = op(q, 1, e);
|
||||
const double O13 = op(q, 2, e);
|
||||
const double O22 = op(q, 3, e);
|
||||
const double O23 = op(q, 4, e);
|
||||
const double O33 = op(q, 5, e);
|
||||
const double O11 = op(0, q, e);
|
||||
const double O12 = op(1, q, e);
|
||||
const double O13 = op(2, q, e);
|
||||
const double O22 = op(3, q, e);
|
||||
const double O23 = op(4, q, e);
|
||||
const double O33 = op(5, q, e);
|
||||
|
||||
const double qDxyz = (O11 * Dxyz) + (O12 * xDyz) + (O13 * xyDz);
|
||||
const double qxDyz = (O12 * Dxyz) + (O22 * xDyz) + (O23 * xyDz);
|
||||
|
||||
@@ -203,14 +203,7 @@ void ParBilinearForm::AssembleSharedFaces(int skip_zeros)
|
||||
vdofs1.Copy(vdofs_all);
|
||||
for (int j = 0; j < vdofs2.Size(); j++)
|
||||
{
|
||||
if (vdofs2[j] >= 0)
|
||||
{
|
||||
vdofs2[j] += height;
|
||||
}
|
||||
else
|
||||
{
|
||||
vdofs2[j] -= height;
|
||||
}
|
||||
vdofs2[j] += height;
|
||||
}
|
||||
vdofs_all.Append(vdofs2);
|
||||
for (int k = 0; k < fbfi.Size(); k++)
|
||||
|
||||
+80
-416
@@ -14,7 +14,6 @@
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
#include "pfespace.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../general/sort_pairs.hpp"
|
||||
#include "../mesh/mesh_headers.hpp"
|
||||
#include "../general/binaryio.hpp"
|
||||
@@ -98,8 +97,6 @@ void ParFiniteElementSpace::ParInit(ParMesh *pm)
|
||||
|
||||
gcomm = NULL;
|
||||
|
||||
gfdofs = NULL;
|
||||
|
||||
P = NULL;
|
||||
Pconf = NULL;
|
||||
R = NULL;
|
||||
@@ -150,37 +147,20 @@ void ParFiniteElementSpace::Construct()
|
||||
// cut space.
|
||||
ConstructTrueDofs();
|
||||
|
||||
ngedofs = ngfdofs = 0;
|
||||
gfdofs = NULL;
|
||||
|
||||
// calculate number of ghost DOFs
|
||||
ngvdofs = pncmesh->GetNGhostVertices()
|
||||
* fec->DofForGeometry(Geometry::POINT);
|
||||
|
||||
ngedofs = ngfdofs = 0;
|
||||
if (pmesh->Dimension() > 1)
|
||||
{
|
||||
ngedofs = pncmesh->GetNGhostEdges()
|
||||
* fec->DofForGeometry(Geometry::SEGMENT);
|
||||
}
|
||||
|
||||
if (pmesh->Dimension() > 2)
|
||||
{
|
||||
if (fdofs != NULL) // have mixed faces
|
||||
{
|
||||
gfdofs = new int[pncmesh->GetNGhostFaces()+1];
|
||||
gfdofs[0] = 0;
|
||||
for (int i = 0; i < pncmesh->GetNGhostFaces(); i++)
|
||||
{
|
||||
int ghost = pncmesh->GetNFaces() + i;
|
||||
ngfdofs += fec->DofForGeometry(pncmesh->GetFaceGeometry(ghost));
|
||||
gfdofs[i+1] = ngfdofs;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ngfdofs = pncmesh->GetNGhostFaces()
|
||||
* fec->DofForGeometry(pncmesh->GetFaceGeometry(0));
|
||||
}
|
||||
ngfdofs = pncmesh->GetNGhostFaces()
|
||||
* fec->DofForGeometry(pncmesh->GetGhostFaceGeometry(0));
|
||||
}
|
||||
|
||||
// total number of ghost DOFs. Ghost DOFs start at index 'ndofs', i.e.,
|
||||
@@ -633,15 +613,15 @@ void ParFiniteElementSpace::Build_Dof_TrueDof_Matrix() const // matrix P
|
||||
int ldof = GetVSize();
|
||||
int ltdof = TrueVSize();
|
||||
|
||||
HYPRE_Int *i_diag = new HYPRE_Int[ldof+1];
|
||||
HYPRE_Int *j_diag = new HYPRE_Int[ltdof];
|
||||
HYPRE_Int *i_diag = mfem::New<HYPRE_Int>(ldof+1);
|
||||
HYPRE_Int *j_diag = mfem::New<HYPRE_Int>(ltdof);
|
||||
int diag_counter;
|
||||
|
||||
HYPRE_Int *i_offd = new HYPRE_Int[ldof+1];
|
||||
HYPRE_Int *j_offd = new HYPRE_Int[ldof-ltdof];
|
||||
HYPRE_Int *i_offd = mfem::New<HYPRE_Int>(ldof+1);
|
||||
HYPRE_Int *j_offd = mfem::New<HYPRE_Int>(ldof-ltdof);
|
||||
int offd_counter;
|
||||
|
||||
HYPRE_Int *cmap = new HYPRE_Int[ldof-ltdof];
|
||||
HYPRE_Int *cmap = mfem::New<HYPRE_Int>(ldof-ltdof);
|
||||
|
||||
HYPRE_Int *col_starts = GetTrueDofOffsets();
|
||||
HYPRE_Int *row_starts = GetDofOffsets();
|
||||
@@ -767,14 +747,12 @@ void ParFiniteElementSpace::GetEssentialTrueDofs(const Array<int>
|
||||
// Verify that in boolean arithmetic: P^T ess_dofs = R ess_dofs.
|
||||
Array<int> true_ess_dofs2(true_ess_dofs.Size());
|
||||
HypreParMatrix *Pt = Dof_TrueDof_Matrix()->Transpose();
|
||||
const int *ess_dofs_data = ess_dofs.HostRead();
|
||||
Pt->BooleanMult(1, ess_dofs_data, 0, true_ess_dofs2);
|
||||
Pt->BooleanMult(1, ess_dofs, 0, true_ess_dofs2);
|
||||
delete Pt;
|
||||
int counter = 0;
|
||||
const int *ted = true_ess_dofs.HostRead();
|
||||
for (int i = 0; i < true_ess_dofs.Size(); i++)
|
||||
{
|
||||
if (bool(ted[i]) != bool(true_ess_dofs2[i])) { counter++; }
|
||||
if (bool(true_ess_dofs[i]) != bool(true_ess_dofs2[i])) { counter++; }
|
||||
}
|
||||
MFEM_VERIFY(counter == 0, "internal MFEM error: counter = " << counter);
|
||||
#endif
|
||||
@@ -876,20 +854,7 @@ const Operator *ParFiniteElementSpace::GetProlongationMatrix() const
|
||||
{
|
||||
if (Conforming())
|
||||
{
|
||||
if (!Pconf)
|
||||
{
|
||||
if (!Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
Pconf = new ConformingProlongationOperator(*this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NRanks > 1)
|
||||
{
|
||||
Pconf = new DeviceConformingProlongationOperator(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Pconf) { Pconf = new ConformingProlongationOperator(*this); }
|
||||
return Pconf;
|
||||
}
|
||||
else
|
||||
@@ -937,15 +902,11 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
|
||||
{
|
||||
GetElementVDofs(my_elems[i], ldofs);
|
||||
for (int j = 0; j < ldofs.Size(); j++)
|
||||
{
|
||||
int ldof = (ldofs[j] >= 0 ? ldofs[j] : -1-ldofs[j]);
|
||||
|
||||
if (ldof_marker[ldof] != fn)
|
||||
if (ldof_marker[ldofs[j]] != fn)
|
||||
{
|
||||
ldof_marker[ldof] = fn;
|
||||
ldof_marker[ldofs[j]] = fn;
|
||||
send_face_nbr_ldof.AddAColumnInRow(fn);
|
||||
}
|
||||
}
|
||||
send_nbr_elem_dof.AddColumnsInRow(send_el_off[fn] + i, ldofs.Size());
|
||||
}
|
||||
|
||||
@@ -999,11 +960,9 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
|
||||
GetElementVDofs(my_elems[i], ldofs);
|
||||
for (int j = 0; j < ldofs.Size(); j++)
|
||||
{
|
||||
int ldof = (ldofs[j] >= 0 ? ldofs[j] : -1-ldofs[j]);
|
||||
|
||||
if (ldof_marker[ldof] != fn)
|
||||
if (ldof_marker[ldofs[j]] != fn)
|
||||
{
|
||||
ldof_marker[ldof] = fn;
|
||||
ldof_marker[ldofs[j]] = fn;
|
||||
send_face_nbr_ldof.AddConnection(fn, ldofs[j]);
|
||||
}
|
||||
}
|
||||
@@ -1024,14 +983,12 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
|
||||
|
||||
for (int i = 0; i < num_ldofs; i++)
|
||||
{
|
||||
int ldof = (ldofs[i] >= 0 ? ldofs[i] : -1-ldofs[i]);
|
||||
ldof_marker[ldof] = i;
|
||||
ldof_marker[ldofs[i]] = i;
|
||||
}
|
||||
|
||||
for ( ; j < j_end; j++)
|
||||
{
|
||||
int ldof = (send_J[j] >= 0 ? send_J[j] : -1-send_J[j]);
|
||||
send_J[j] = (send_J[j] >= 0 ? ldof_marker[ldof] : -1-ldof_marker[ldof]);
|
||||
send_J[j] = ldof_marker[send_J[j]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1066,14 +1023,7 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
|
||||
|
||||
for ( ; j < j_end; j++)
|
||||
{
|
||||
if (recv_J[j] >= 0)
|
||||
{
|
||||
recv_J[j] += shift;
|
||||
}
|
||||
else
|
||||
{
|
||||
recv_J[j] -= shift;
|
||||
}
|
||||
recv_J[j] += shift;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1122,15 +1072,8 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
|
||||
for (int fn = 0, j = 0; fn < num_face_nbrs; fn++)
|
||||
{
|
||||
for (int j_end = face_nbr_ldof.GetI()[fn+1]; j < j_end; j++)
|
||||
{
|
||||
int ldof = face_nbr_ldof.GetJ()[j];
|
||||
if (ldof < 0)
|
||||
{
|
||||
ldof = -1-ldof;
|
||||
}
|
||||
|
||||
face_nbr_glob_dof_map[j] = dof_face_nbr_offsets[fn] + ldof;
|
||||
}
|
||||
face_nbr_glob_dof_map[j] =
|
||||
dof_face_nbr_offsets[fn] + face_nbr_ldof.GetJ()[j];
|
||||
}
|
||||
|
||||
MPI_Waitall(num_face_nbrs, send_requests, statuses);
|
||||
@@ -1343,18 +1286,20 @@ void ParFiniteElementSpace::GetGhostEdgeDofs(const MeshId &edge_id,
|
||||
void ParFiniteElementSpace::GetGhostFaceDofs(const MeshId &face_id,
|
||||
Array<int> &dofs) const
|
||||
{
|
||||
int nfv, V[4], E[4], Eo[4];
|
||||
nfv = pmesh->pncmesh->GetFaceVerticesEdges(face_id, V, E, Eo);
|
||||
const int ghost_face_index = face_id.index - pncmesh->GetNFaces();
|
||||
MFEM_ASSERT(pncmesh->GetGhostFaceGeometry(ghost_face_index)
|
||||
== Geometry::SQUARE, "");
|
||||
|
||||
int nv = fec->DofForGeometry(Geometry::POINT);
|
||||
int ne = fec->DofForGeometry(Geometry::SEGMENT);
|
||||
int nf = fec->DofForGeometry((nfv == 3) ?
|
||||
Geometry::TRIANGLE : Geometry::SQUARE);
|
||||
int nf = fec->DofForGeometry(Geometry::SQUARE);
|
||||
dofs.SetSize(4*nv + 4*ne + nf);
|
||||
|
||||
dofs.SetSize(nfv*(nv + ne) + nf);
|
||||
int V[4], E[4], Eo[4];
|
||||
pmesh->pncmesh->GetFaceVerticesEdges(face_id, V, E, Eo);
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < nfv; i++)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int ghost = pncmesh->GetNVertices();
|
||||
int first = (V[i] < ghost) ? V[i]*nv : (ndofs + (V[i] - ghost)*nv);
|
||||
@@ -1364,7 +1309,7 @@ void ParFiniteElementSpace::GetGhostFaceDofs(const MeshId &face_id,
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < nfv; i++)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int ghost = pncmesh->GetNEdges();
|
||||
int first = (E[i] < ghost) ? nvdofs + E[i]*ne
|
||||
@@ -1377,10 +1322,8 @@ void ParFiniteElementSpace::GetGhostFaceDofs(const MeshId &face_id,
|
||||
}
|
||||
}
|
||||
|
||||
const int ghost_face_index = face_id.index - pncmesh->GetNFaces();
|
||||
int first = ndofs + ngvdofs + ngedofs;
|
||||
first += gfdofs ? gfdofs[ghost_face_index] : nf*ghost_face_index;
|
||||
|
||||
// Assuming all ghost faces have the same number of dofs:
|
||||
int first = ndofs + ngvdofs + ngedofs + ghost_face_index*nf;
|
||||
for (int j = 0; j < nf; j++)
|
||||
{
|
||||
dofs[offset++] = first + j;
|
||||
@@ -1422,19 +1365,12 @@ void ParFiniteElementSpace::GetBareDofs(int entity, int index,
|
||||
break;
|
||||
|
||||
default:
|
||||
ned = fec->DofForGeometry(pncmesh->GetFaceGeometry(index));
|
||||
MFEM_ASSERT(!pmesh->HasGeometry(Geometry::TRIANGLE), "");
|
||||
ned = fec->DofForGeometry(Geometry::SQUARE);
|
||||
ghost = pncmesh->GetNFaces();
|
||||
|
||||
if (index < ghost) // regular face
|
||||
{
|
||||
first = nvdofs + nedofs + (fdofs ? fdofs[index] : index*ned);
|
||||
}
|
||||
else // ghost face
|
||||
{
|
||||
index -= ghost;
|
||||
first = ndofs + ngvdofs + ngedofs +
|
||||
(gfdofs ? gfdofs[index] : index*ned);
|
||||
}
|
||||
first = (index < ghost)
|
||||
? nvdofs + nedofs + index*ned // regular face
|
||||
: ndofs + ngvdofs + ngedofs + (index - ghost)*ned; // ghost
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1470,30 +1406,16 @@ int ParFiniteElementSpace::PackDof(int entity, int index, int edof) const
|
||||
: ndofs + ngvdofs + (index - ghost)*ned + edof; // ghost edge
|
||||
|
||||
default:
|
||||
MFEM_ASSERT(!pmesh->HasGeometry(Geometry::TRIANGLE), "");
|
||||
ghost = pncmesh->GetNFaces();
|
||||
ned = fec->DofForGeometry(pncmesh->GetFaceGeometry(index));
|
||||
ned = fec->DofForGeometry(Geometry::SQUARE);
|
||||
|
||||
if (index < ghost) // regular face
|
||||
{
|
||||
return nvdofs + nedofs + (fdofs ? fdofs[index] : index*ned) + edof;
|
||||
}
|
||||
else // ghost face
|
||||
{
|
||||
index -= ghost;
|
||||
return ndofs + ngvdofs + ngedofs +
|
||||
(gfdofs ? gfdofs[index] : index*ned) + edof;
|
||||
}
|
||||
return (index < ghost)
|
||||
? nvdofs + nedofs + index*ned + edof // regular face
|
||||
: ndofs + ngvdofs + ngedofs + (index - ghost)*ned + edof; //ghost
|
||||
}
|
||||
}
|
||||
|
||||
static int bisect(int* array, int size, int value)
|
||||
{
|
||||
int* end = array + size;
|
||||
int* pos = std::upper_bound(array, end, value);
|
||||
MFEM_VERIFY(pos != end, "value not found");
|
||||
return pos - array;
|
||||
}
|
||||
|
||||
/** Dissect a DOF number to obtain the entity type (0=vertex, 1=edge, 2=face),
|
||||
* entity index and the DOF number within the entity.
|
||||
*/
|
||||
@@ -1519,17 +1441,9 @@ void ParFiniteElementSpace::UnpackDof(int dof,
|
||||
dof -= nedofs;
|
||||
if (dof < nfdofs) // regular face
|
||||
{
|
||||
if (fdofs) // have mixed faces
|
||||
{
|
||||
index = bisect(fdofs+1, mesh->GetNFaces(), dof);
|
||||
edof = dof - fdofs[index];
|
||||
}
|
||||
else // uniform faces
|
||||
{
|
||||
int nf = fec->DofForGeometry(pncmesh->GetFaceGeometry(0));
|
||||
index = dof / nf, edof = dof % nf;
|
||||
}
|
||||
entity = 2;
|
||||
MFEM_ASSERT(!pmesh->HasGeometry(Geometry::TRIANGLE), "");
|
||||
int nf = fec->DofForGeometry(Geometry::SQUARE);
|
||||
entity = 2, index = dof / nf, edof = dof % nf;
|
||||
return;
|
||||
}
|
||||
MFEM_ABORT("Cannot unpack internal DOF");
|
||||
@@ -1553,17 +1467,8 @@ void ParFiniteElementSpace::UnpackDof(int dof,
|
||||
dof -= ngedofs;
|
||||
if (dof < ngfdofs) // ghost face
|
||||
{
|
||||
if (gfdofs) // have mixed faces
|
||||
{
|
||||
index = bisect(gfdofs+1, pncmesh->GetNGhostFaces(), dof);
|
||||
edof = dof - gfdofs[index];
|
||||
}
|
||||
else // uniform faces
|
||||
{
|
||||
int nf = fec->DofForGeometry(pncmesh->GetFaceGeometry(0));
|
||||
index = pncmesh->GetNFaces() + dof / nf, edof = dof % nf;
|
||||
}
|
||||
entity = 2;
|
||||
int nf = fec->DofForGeometry(pncmesh->GetGhostFaceGeometry(0));
|
||||
entity = 2, index = pncmesh->GetNFaces() + dof / nf, edof = dof % nf;
|
||||
return;
|
||||
}
|
||||
MFEM_ABORT("Out of range DOF.");
|
||||
@@ -1746,7 +1651,7 @@ void NeighborRowMessage::Encode(int rank)
|
||||
mfem::out << "Rank " << pncmesh->MyRank << " sending to " << rank
|
||||
<< ": ent " << ri.entity << ", index " << ri.index
|
||||
<< ", edof " << ri.edof << " (id " << id.element << "/"
|
||||
<< int(id.local) << ")" << std::endl;
|
||||
<< id.local << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
// handle orientation and sign change
|
||||
@@ -1789,6 +1694,8 @@ void NeighborRowMessage::Decode(int rank)
|
||||
rows.clear();
|
||||
rows.reserve(nrows);
|
||||
|
||||
Geometry::Type fgeom = pncmesh->GetFaceGeometry();
|
||||
|
||||
// read rows
|
||||
for (int ent = 0, gi = 0; ent < 3; ent++)
|
||||
{
|
||||
@@ -1807,9 +1714,8 @@ void NeighborRowMessage::Decode(int rank)
|
||||
}
|
||||
else if (ent == 2)
|
||||
{
|
||||
Geometry::Type geom = pncmesh->GetFaceGeometry(id.index);
|
||||
int fo = pncmesh->GetFaceOrientation(id.index);
|
||||
ind = fec->DofOrderForOrientation(geom, fo);
|
||||
ind = fec->DofOrderForOrientation(fgeom, fo);
|
||||
}
|
||||
|
||||
double s = 1.0;
|
||||
@@ -1898,7 +1804,7 @@ void ParFiniteElementSpace
|
||||
for (int i = 0; i < dof_group.Size(); i++)
|
||||
{
|
||||
os << i << ": ";
|
||||
if (i < (nvdofs + nedofs + nfdofs) || i >= ndofs)
|
||||
if (i < (nvdofs + nedofs + nfdofs) || i > ndofs)
|
||||
{
|
||||
int ent, idx, edof;
|
||||
UnpackDof(i, ent, idx, edof);
|
||||
@@ -1980,7 +1886,15 @@ int ParFiniteElementSpace
|
||||
if (!list.masters.size()) { continue; }
|
||||
|
||||
IsoparametricTransformation T;
|
||||
DenseMatrix I;
|
||||
if (entity > 1) { T.SetFE(&QuadrilateralFE); }
|
||||
else { T.SetFE(&SegmentFE); }
|
||||
|
||||
Geometry::Type geom = (entity > 1) ?
|
||||
Geometry::SQUARE : Geometry::SEGMENT;
|
||||
const FiniteElement* fe = fec->FiniteElementForGeometry(geom);
|
||||
if (!fe) { continue; }
|
||||
|
||||
DenseMatrix I(fe->GetDof());
|
||||
|
||||
// process masters that we own or that affect our edges/faces
|
||||
for (unsigned mi = 0; mi < list.masters.size(); mi++)
|
||||
@@ -1994,17 +1908,6 @@ int ParFiniteElementSpace
|
||||
|
||||
if (!master_dofs.Size()) { continue; }
|
||||
|
||||
const FiniteElement* fe = fec->FiniteElementForGeometry(mf.Geom());
|
||||
if (!fe) { continue; }
|
||||
|
||||
switch (mf.Geom())
|
||||
{
|
||||
case Geometry::SQUARE: T.SetFE(&QuadrilateralFE); break;
|
||||
case Geometry::TRIANGLE: T.SetFE(&TriangleFE); break;
|
||||
case Geometry::SEGMENT: T.SetFE(&SegmentFE); break;
|
||||
default: MFEM_ABORT("unsupported geometry");
|
||||
}
|
||||
|
||||
// constrain slaves that exist in our mesh
|
||||
for (int si = mf.slaves_begin; si < mf.slaves_end; si++)
|
||||
{
|
||||
@@ -2055,8 +1958,6 @@ int ParFiniteElementSpace
|
||||
(l == 1) ? (const MeshId&) list.masters[i]
|
||||
/* */ : (const MeshId&) list.slaves[i];
|
||||
|
||||
if (id.index < 0) { continue; }
|
||||
|
||||
GroupId owner = pncmesh->GetEntityOwnerId(entity, id.index);
|
||||
GroupId group = pncmesh->GetEntityGroupId(entity, id.index);
|
||||
|
||||
@@ -2348,7 +2249,7 @@ HypreParMatrix* ParFiniteElementSpace
|
||||
}
|
||||
|
||||
// create offd column mapping
|
||||
HYPRE_Int *cmap = new HYPRE_Int[col_map.size()];
|
||||
HYPRE_Int *cmap = mfem::New<HYPRE_Int>(col_map.size());
|
||||
int offd_col = 0;
|
||||
for (std::map<HYPRE_Int, int>::iterator
|
||||
it = col_map.begin(); it != col_map.end(); ++it)
|
||||
@@ -2357,14 +2258,14 @@ HypreParMatrix* ParFiniteElementSpace
|
||||
it->second = offd_col++;
|
||||
}
|
||||
|
||||
HYPRE_Int *I_diag = new HYPRE_Int[vdim*local_rows + 1];
|
||||
HYPRE_Int *I_offd = new HYPRE_Int[vdim*local_rows + 1];
|
||||
HYPRE_Int *I_diag = mfem::New<HYPRE_Int>(vdim*local_rows + 1);
|
||||
HYPRE_Int *I_offd = mfem::New<HYPRE_Int>(vdim*local_rows + 1);
|
||||
|
||||
HYPRE_Int *J_diag = new HYPRE_Int[nnz_diag];
|
||||
HYPRE_Int *J_offd = new HYPRE_Int[nnz_offd];
|
||||
HYPRE_Int *J_diag = mfem::New<HYPRE_Int>(nnz_diag);
|
||||
HYPRE_Int *J_offd = mfem::New<HYPRE_Int>(nnz_offd);
|
||||
|
||||
double *A_diag = new double[nnz_diag];
|
||||
double *A_offd = new double[nnz_offd];
|
||||
double *A_diag = mfem::New<double>(nnz_diag);
|
||||
double *A_offd = mfem::New<double>(nnz_offd);
|
||||
|
||||
int vdim1 = bynodes ? vdim : 1;
|
||||
int vdim2 = bynodes ? 1 : vdim;
|
||||
@@ -2415,7 +2316,7 @@ HypreParMatrix* ParFiniteElementSpace
|
||||
|
||||
static HYPRE_Int* make_i_array(int nrows)
|
||||
{
|
||||
HYPRE_Int *I = new HYPRE_Int[nrows+1];
|
||||
HYPRE_Int *I = mfem::New<HYPRE_Int>(nrows+1);
|
||||
for (int i = 0; i <= nrows; i++) { I[i] = -1; }
|
||||
return I;
|
||||
}
|
||||
@@ -2427,7 +2328,7 @@ static HYPRE_Int* make_j_array(HYPRE_Int* I, int nrows)
|
||||
{
|
||||
if (I[i] >= 0) { nnz++; }
|
||||
}
|
||||
HYPRE_Int *J = new HYPRE_Int[nnz];
|
||||
HYPRE_Int *J = mfem::New<HYPRE_Int>(nnz);
|
||||
|
||||
I[nrows] = -1;
|
||||
for (int i = 0, k = 0; i <= nrows; i++)
|
||||
@@ -2526,7 +2427,7 @@ ParFiniteElementSpace::RebalanceMatrix(int old_ndofs,
|
||||
}
|
||||
SortPairs<HYPRE_Int, int>(cmap_offd, offd_cols);
|
||||
|
||||
HYPRE_Int* cmap = new HYPRE_Int[offd_cols];
|
||||
HYPRE_Int* cmap = mfem::New<HYPRE_Int>(offd_cols);
|
||||
for (int i = 0; i < offd_cols; i++)
|
||||
{
|
||||
cmap[i] = cmap_offd[i].one;
|
||||
@@ -2553,9 +2454,6 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
|
||||
int nrk = HYPRE_AssumedPartitionCheck() ? 2 : NRanks;
|
||||
|
||||
MFEM_VERIFY(Nonconforming(), "Not implemented for conforming meshes.");
|
||||
MFEM_VERIFY(pmesh->GetNumGeometries(pmesh->Dimension()) == 1,
|
||||
"Not implemented for mixed meshes.");
|
||||
|
||||
MFEM_VERIFY(old_dof_offsets[nrk], "Missing previous (finer) space.");
|
||||
MFEM_VERIFY(dof_offsets[nrk] <= old_dof_offsets[nrk],
|
||||
"Previous space is not finer.");
|
||||
@@ -2569,7 +2467,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
|
||||
Vector row;
|
||||
|
||||
ParNCMesh* pncmesh = pmesh->pncmesh;
|
||||
Geometry::Type geom = pncmesh->GetElementGeometry(0); // TODO mixed meshes
|
||||
Geometry::Type geom = pncmesh->GetElementGeometry();
|
||||
int ldof = fec->FiniteElementForGeometry(geom)->GetDof();
|
||||
|
||||
const CoarseFineTransformations &dtrans = pncmesh->GetDerefinementTransforms();
|
||||
@@ -2725,7 +2623,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
|
||||
offd->SetWidth(col_map.size());
|
||||
|
||||
// create offd column mapping for use by hypre
|
||||
HYPRE_Int *cmap = new HYPRE_Int[offd->Width()];
|
||||
HYPRE_Int *cmap = mfem::New<HYPRE_Int>(offd->Width());
|
||||
for (std::map<HYPRE_Int, int>::iterator
|
||||
it = col_map.begin(); it != col_map.end(); ++it)
|
||||
{
|
||||
@@ -2793,8 +2691,6 @@ void ParFiniteElementSpace::Destroy()
|
||||
delete Pconf; Pconf = NULL;
|
||||
delete R; R = NULL;
|
||||
|
||||
delete [] gfdofs; gfdofs = NULL;
|
||||
|
||||
delete gcomm; gcomm = NULL;
|
||||
|
||||
num_face_nbr_dofs = -1;
|
||||
@@ -2967,8 +2863,9 @@ void ConformingProlongationOperator::Mult(const Vector &x, Vector &y) const
|
||||
MFEM_ASSERT(x.Size() == Width(), "");
|
||||
MFEM_ASSERT(y.Size() == Height(), "");
|
||||
|
||||
const double *xdata = x.HostRead();
|
||||
double *ydata = y.HostWrite();
|
||||
const double *xdata = x.GetData();
|
||||
double *ydata = y.GetData();
|
||||
x.Pull();
|
||||
const int m = external_ldofs.Size();
|
||||
|
||||
const int in_layout = 2; // 2 - input is ltdofs array
|
||||
@@ -2985,6 +2882,7 @@ void ConformingProlongationOperator::Mult(const Vector &x, Vector &y) const
|
||||
|
||||
const int out_layout = 0; // 0 - output is ldofs array
|
||||
gc.BcastEnd(ydata, out_layout);
|
||||
y.Push();
|
||||
}
|
||||
|
||||
void ConformingProlongationOperator::MultTranspose(
|
||||
@@ -2993,8 +2891,9 @@ void ConformingProlongationOperator::MultTranspose(
|
||||
MFEM_ASSERT(x.Size() == Height(), "");
|
||||
MFEM_ASSERT(y.Size() == Width(), "");
|
||||
|
||||
const double *xdata = x.HostRead();
|
||||
double *ydata = y.HostWrite();
|
||||
const double *xdata = x.GetData();
|
||||
double *ydata = y.GetData();
|
||||
x.Pull();
|
||||
const int m = external_ldofs.Size();
|
||||
|
||||
gc.ReduceBegin(xdata);
|
||||
@@ -3010,242 +2909,7 @@ void ConformingProlongationOperator::MultTranspose(
|
||||
|
||||
const int out_layout = 2; // 2 - output is an array on all ltdofs
|
||||
gc.ReduceEnd<double>(ydata, out_layout, GroupCommunicator::Sum);
|
||||
}
|
||||
|
||||
DeviceConformingProlongationOperator::DeviceConformingProlongationOperator(
|
||||
const ParFiniteElementSpace &pfes) :
|
||||
ConformingProlongationOperator(pfes),
|
||||
mpi_gpu_aware(Device::GetGPUAwareMPI())
|
||||
{
|
||||
MFEM_ASSERT(pfes.Conforming(), "internal error");
|
||||
const SparseMatrix *R = pfes.GetRestrictionMatrix();
|
||||
MFEM_ASSERT(R->Finalized(), "");
|
||||
const int tdofs = R->Height();
|
||||
MFEM_ASSERT(tdofs == pfes.GetTrueVSize(), "");
|
||||
MFEM_ASSERT(tdofs == R->GetI()[tdofs], "");
|
||||
ltdof_ldof = Array<int>(const_cast<int*>(R->GetJ()), tdofs);
|
||||
ltdof_ldof.UseDevice();
|
||||
{
|
||||
Table nbr_ltdof;
|
||||
gc.GetNeighborLTDofTable(nbr_ltdof);
|
||||
const int nb_connections = nbr_ltdof.Size_of_connections();
|
||||
shr_ltdof.SetSize(nb_connections);
|
||||
shr_ltdof.CopyFrom(nbr_ltdof.GetJ());
|
||||
shr_buf.SetSize(nb_connections);
|
||||
shr_buf.UseDevice(true);
|
||||
shr_buf_offsets = nbr_ltdof.GetI();
|
||||
{
|
||||
Array<int> shr_ltdof(nbr_ltdof.GetJ(), nb_connections);
|
||||
Array<int> unique_ltdof(shr_ltdof);
|
||||
unique_ltdof.Sort();
|
||||
unique_ltdof.Unique();
|
||||
// Note: the next loop modifies the J array of nbr_ltdof
|
||||
for (int i = 0; i < shr_ltdof.Size(); i++)
|
||||
{
|
||||
shr_ltdof[i] = unique_ltdof.FindSorted(shr_ltdof[i]);
|
||||
MFEM_ASSERT(shr_ltdof[i] != -1, "internal error");
|
||||
}
|
||||
Table unique_shr;
|
||||
Transpose(shr_ltdof, unique_shr, unique_ltdof.Size());
|
||||
unq_ltdof = Array<int>(unique_ltdof, unique_ltdof.Size());
|
||||
unq_shr_i = Array<int>(unique_shr.GetI(), unique_shr.Size()+1);
|
||||
unq_shr_j = Array<int>(unique_shr.GetJ(), unique_shr.Size_of_connections());
|
||||
}
|
||||
delete [] nbr_ltdof.GetJ();
|
||||
nbr_ltdof.LoseData();
|
||||
}
|
||||
{
|
||||
Table nbr_ldof;
|
||||
gc.GetNeighborLDofTable(nbr_ldof);
|
||||
const int nb_connections = nbr_ldof.Size_of_connections();
|
||||
ext_ldof.SetSize(nb_connections);
|
||||
ext_ldof.CopyFrom(nbr_ldof.GetJ());
|
||||
ext_buf.SetSize(nb_connections);
|
||||
ext_buf.UseDevice(true);
|
||||
ext_buf_offsets = nbr_ldof.GetI();
|
||||
delete [] nbr_ldof.GetJ();
|
||||
nbr_ldof.LoseData();
|
||||
}
|
||||
const GroupTopology >opo = gc.GetGroupTopology();
|
||||
int req_counter = 0;
|
||||
for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++)
|
||||
{
|
||||
const int send_offset = shr_buf_offsets[nbr];
|
||||
const int send_size = shr_buf_offsets[nbr+1] - send_offset;
|
||||
if (send_size > 0) { req_counter++; }
|
||||
|
||||
const int recv_offset = ext_buf_offsets[nbr];
|
||||
const int recv_size = ext_buf_offsets[nbr+1] - recv_offset;
|
||||
if (recv_size > 0) { req_counter++; }
|
||||
}
|
||||
requests = new MPI_Request[req_counter];
|
||||
}
|
||||
|
||||
static void ExtractSubVector(const int N,
|
||||
const Array<int> &indices,
|
||||
const Vector &in, Vector &out)
|
||||
{
|
||||
auto y = out.Write();
|
||||
const auto x = in.Read();
|
||||
const auto I = indices.Read();
|
||||
MFEM_FORALL(i, N, y[i] = x[I[i]];); // indices can be repeated
|
||||
}
|
||||
|
||||
void DeviceConformingProlongationOperator::BcastBeginCopy(
|
||||
const Vector &x) const
|
||||
{
|
||||
// shr_buf[i] = src[shr_ltdof[i]]
|
||||
if (shr_ltdof.Size() == 0) { return; }
|
||||
ExtractSubVector(shr_ltdof.Size(), shr_ltdof, x, shr_buf);
|
||||
// If the above kernel is executed asynchronously, we should wait for it to
|
||||
// complete
|
||||
if (mpi_gpu_aware) { Device::Synchronize(); }
|
||||
}
|
||||
|
||||
static void SetSubVector(const int N,
|
||||
const Array<int> &indices,
|
||||
const Vector &in, Vector &out)
|
||||
{
|
||||
auto y = out.Write();
|
||||
const auto x = in.Read();
|
||||
const auto I = indices.Read();
|
||||
MFEM_FORALL(i, N, y[I[i]] = x[i];);
|
||||
}
|
||||
|
||||
void DeviceConformingProlongationOperator::BcastLocalCopy(
|
||||
const Vector &x, Vector &y) const
|
||||
{
|
||||
// dst[ltdof_ldof[i]] = src[i]
|
||||
if (ltdof_ldof.Size() == 0) { return; }
|
||||
SetSubVector(ltdof_ldof.Size(), ltdof_ldof, x, y);
|
||||
}
|
||||
|
||||
void DeviceConformingProlongationOperator::BcastEndCopy(
|
||||
Vector &y) const
|
||||
{
|
||||
// dst[ext_ldof[i]] = ext_buf[i]
|
||||
if (ext_ldof.Size() == 0) { return; }
|
||||
SetSubVector(ext_ldof.Size(), ext_ldof, ext_buf, y);
|
||||
}
|
||||
|
||||
void DeviceConformingProlongationOperator::Mult(const Vector &x,
|
||||
Vector &y) const
|
||||
{
|
||||
const GroupTopology >opo = gc.GetGroupTopology();
|
||||
BcastBeginCopy(x); // copy to 'shr_buf'
|
||||
int req_counter = 0;
|
||||
for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++)
|
||||
{
|
||||
const int send_offset = shr_buf_offsets[nbr];
|
||||
const int send_size = shr_buf_offsets[nbr+1] - send_offset;
|
||||
if (send_size > 0)
|
||||
{
|
||||
auto send_buf = mpi_gpu_aware ? shr_buf.Read() : shr_buf.HostRead();
|
||||
MPI_Isend(send_buf + send_offset, send_size, MPI_DOUBLE,
|
||||
gtopo.GetNeighborRank(nbr), 41822,
|
||||
gtopo.GetComm(), &requests[req_counter++]);
|
||||
}
|
||||
const int recv_offset = ext_buf_offsets[nbr];
|
||||
const int recv_size = ext_buf_offsets[nbr+1] - recv_offset;
|
||||
if (recv_size > 0)
|
||||
{
|
||||
auto recv_buf = mpi_gpu_aware ? ext_buf.Write() : ext_buf.HostWrite();
|
||||
MPI_Irecv(recv_buf + recv_offset, recv_size, MPI_DOUBLE,
|
||||
gtopo.GetNeighborRank(nbr), 41822,
|
||||
gtopo.GetComm(), &requests[req_counter++]);
|
||||
}
|
||||
}
|
||||
BcastLocalCopy(x, y);
|
||||
MPI_Waitall(req_counter, requests, MPI_STATUSES_IGNORE);
|
||||
BcastEndCopy(y); // copy from 'ext_buf'
|
||||
}
|
||||
|
||||
DeviceConformingProlongationOperator::~DeviceConformingProlongationOperator()
|
||||
{
|
||||
delete [] requests;
|
||||
delete [] ext_buf_offsets;
|
||||
delete [] shr_buf_offsets;
|
||||
}
|
||||
|
||||
void DeviceConformingProlongationOperator::ReduceBeginCopy(
|
||||
const Vector &x) const
|
||||
{
|
||||
// ext_buf[i] = src[ext_ldof[i]]
|
||||
if (ext_ldof.Size() == 0) { return; }
|
||||
ExtractSubVector(ext_ldof.Size(), ext_ldof, x, ext_buf);
|
||||
// If the above kernel is executed asynchronously, we should wait for it to
|
||||
// complete
|
||||
if (mpi_gpu_aware) { Device::Synchronize(); }
|
||||
}
|
||||
|
||||
void DeviceConformingProlongationOperator::ReduceLocalCopy(
|
||||
const Vector &x, Vector &y) const
|
||||
{
|
||||
// dst[i] = src[ltdof_ldof[i]]
|
||||
if (ltdof_ldof.Size() == 0) { return; }
|
||||
ExtractSubVector(ltdof_ldof.Size(), ltdof_ldof, x, y);
|
||||
}
|
||||
|
||||
static void AddSubVector(const int num_unique_dst_indices,
|
||||
const Array<int> &unique_dst_indices,
|
||||
const Array<int> &unique_to_src_offsets,
|
||||
const Array<int> &unique_to_src_indices,
|
||||
const Vector &src,
|
||||
Vector &dst)
|
||||
{
|
||||
auto y = dst.Write();
|
||||
const auto x = src.Read();
|
||||
const auto DST_I = unique_dst_indices.Read();
|
||||
const auto SRC_O = unique_to_src_offsets.Read();
|
||||
const auto SRC_I = unique_to_src_indices.Read();
|
||||
MFEM_FORALL(i, num_unique_dst_indices,
|
||||
{
|
||||
const int dst_idx = DST_I[i];
|
||||
double sum = y[dst_idx];
|
||||
const int end = SRC_O[i+1];
|
||||
for (int j = SRC_O[i]; j != end; ++j) { sum += x[SRC_I[j]]; }
|
||||
y[dst_idx] = sum;
|
||||
});
|
||||
}
|
||||
|
||||
void DeviceConformingProlongationOperator::ReduceEndAssemble(Vector &y) const
|
||||
{
|
||||
// dst[shr_ltdof[i]] += shr_buf[i]
|
||||
const int unq_ltdof_size = unq_ltdof.Size();
|
||||
if (unq_ltdof_size == 0) { return; }
|
||||
AddSubVector(unq_ltdof_size, unq_ltdof, unq_shr_i, unq_shr_j, shr_buf, y);
|
||||
}
|
||||
|
||||
void DeviceConformingProlongationOperator::MultTranspose(const Vector &x,
|
||||
Vector &y) const
|
||||
{
|
||||
const GroupTopology >opo = gc.GetGroupTopology();
|
||||
ReduceBeginCopy(x); // copy to 'ext_buf'
|
||||
int req_counter = 0;
|
||||
for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++)
|
||||
{
|
||||
const int send_offset = ext_buf_offsets[nbr];
|
||||
const int send_size = ext_buf_offsets[nbr+1] - send_offset;
|
||||
if (send_size > 0)
|
||||
{
|
||||
auto send_buf = mpi_gpu_aware ? ext_buf.Read() : ext_buf.HostRead();
|
||||
MPI_Isend(send_buf + send_offset, send_size, MPI_DOUBLE,
|
||||
gtopo.GetNeighborRank(nbr), 41823,
|
||||
gtopo.GetComm(), &requests[req_counter++]);
|
||||
}
|
||||
const int recv_offset = shr_buf_offsets[nbr];
|
||||
const int recv_size = shr_buf_offsets[nbr+1] - recv_offset;
|
||||
if (recv_size > 0)
|
||||
{
|
||||
auto recv_buf = mpi_gpu_aware ? shr_buf.Write() : shr_buf.HostWrite();
|
||||
MPI_Irecv(recv_buf + recv_offset, recv_size, MPI_DOUBLE,
|
||||
gtopo.GetNeighborRank(nbr), 41823,
|
||||
gtopo.GetComm(), &requests[req_counter++]);
|
||||
}
|
||||
}
|
||||
ReduceLocalCopy(x, y);
|
||||
MPI_Waitall(req_counter, requests, MPI_STATUSES_IGNORE);
|
||||
ReduceEndAssemble(y); // assemble from 'shr_buf'
|
||||
y.Push();
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+1
-48
@@ -46,7 +46,6 @@ private:
|
||||
|
||||
/// Number of vertex/edge/face/total ghost DOFs (nonconforming case).
|
||||
int ngvdofs, ngedofs, ngfdofs, ngdofs;
|
||||
int* gfdofs;
|
||||
|
||||
/// The group of each local dof.
|
||||
Array<int> ldof_group;
|
||||
@@ -114,7 +113,7 @@ private:
|
||||
void GetGhostFaceDofs(const MeshId &face_id, Array<int> &dofs) const;
|
||||
|
||||
void GetGhostDofs(int entity, const MeshId &id, Array<int> &dofs) const;
|
||||
/// Return the dofs associated with the interior of the given mesh entity.
|
||||
// Return the dofs associated with the interior of the given mesh entity.
|
||||
void GetBareDofs(int entity, int index, Array<int> &dofs) const;
|
||||
|
||||
int PackDof(int entity, int index, int edof) const;
|
||||
@@ -388,52 +387,6 @@ public:
|
||||
virtual void MultTranspose(const Vector &x, Vector &y) const;
|
||||
};
|
||||
|
||||
/// Auxiliary device class used by ParFiniteElementSpace.
|
||||
class DeviceConformingProlongationOperator: public
|
||||
ConformingProlongationOperator
|
||||
{
|
||||
protected:
|
||||
bool mpi_gpu_aware;
|
||||
Array<int> shr_ltdof, ext_ldof;
|
||||
mutable Vector shr_buf, ext_buf;
|
||||
int *shr_buf_offsets, *ext_buf_offsets;
|
||||
Array<int> ltdof_ldof, unq_ltdof;
|
||||
Array<int> unq_shr_i, unq_shr_j;
|
||||
MPI_Request *requests;
|
||||
// Kernel: copy ltdofs from 'src' to 'shr_buf' - prepare for send.
|
||||
// shr_buf[i] = src[shr_ltdof[i]]
|
||||
void BcastBeginCopy(const Vector &src) const;
|
||||
|
||||
// Kernel: copy ltdofs from 'src' to ldofs in 'dst'.
|
||||
// dst[ltdof_ldof[i]] = src[i]
|
||||
void BcastLocalCopy(const Vector &src, Vector &dst) const;
|
||||
|
||||
// Kernel: copy ext. dofs from 'ext_buf' to 'dst' - after recv.
|
||||
// dst[ext_ldof[i]] = ext_buf[i]
|
||||
void BcastEndCopy(Vector &dst) const;
|
||||
|
||||
// Kernel: copy ext. dofs from 'src' to 'ext_buf' - prepare for send.
|
||||
// ext_buf[i] = src[ext_ldof[i]]
|
||||
void ReduceBeginCopy(const Vector &src) const;
|
||||
|
||||
// Kernel: copy owned ldofs from 'src' to ltdofs in 'dst'.
|
||||
// dst[i] = src[ltdof_ldof[i]]
|
||||
void ReduceLocalCopy(const Vector &src, Vector &dst) const;
|
||||
|
||||
// Kernel: assemble dofs from 'shr_buf' into to 'dst' - after recv.
|
||||
// dst[shr_ltdof[i]] += shr_buf[i]
|
||||
void ReduceEndAssemble(Vector &dst) const;
|
||||
|
||||
public:
|
||||
DeviceConformingProlongationOperator(const ParFiniteElementSpace &pfes);
|
||||
|
||||
virtual ~DeviceConformingProlongationOperator();
|
||||
|
||||
virtual void Mult(const Vector &x, Vector &y) const;
|
||||
|
||||
virtual void MultTranspose(const Vector &x, Vector &y) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
+16
-19
@@ -225,13 +225,11 @@ void ParGridFunction::ExchangeFaceNbrData()
|
||||
MPI_Request *recv_requests = requests + num_face_nbrs;
|
||||
MPI_Status *statuses = new MPI_Status[num_face_nbrs];
|
||||
|
||||
const double *h_data = this->HostRead();
|
||||
for (int i = 0; i < send_data.Size(); i++)
|
||||
{
|
||||
send_data[i] = h_data[send_ldof[i]];
|
||||
send_data[i] = data[send_ldof[i]];
|
||||
}
|
||||
|
||||
double *h_face_nbr_data = face_nbr_data.HostWrite();
|
||||
for (int fn = 0; fn < num_face_nbrs; fn++)
|
||||
{
|
||||
int nbr_rank = pmesh->GetFaceNbrRank(fn);
|
||||
@@ -241,7 +239,7 @@ void ParGridFunction::ExchangeFaceNbrData()
|
||||
send_offset[fn+1] - send_offset[fn],
|
||||
MPI_DOUBLE, nbr_rank, tag, MyComm, &send_requests[fn]);
|
||||
|
||||
MPI_Irecv(&h_face_nbr_data[recv_offset[fn]],
|
||||
MPI_Irecv(&face_nbr_data(recv_offset[fn]),
|
||||
recv_offset[fn+1] - recv_offset[fn],
|
||||
MPI_DOUBLE, nbr_rank, tag, MyComm, &recv_requests[fn]);
|
||||
}
|
||||
@@ -369,10 +367,10 @@ void ParGridFunction::ProjectDiscCoefficient(Coefficient &coeff, AvgType type)
|
||||
GroupCommunicator &gcomm = pfes->GroupComm();
|
||||
gcomm.Reduce<int>(zones_per_vdof, GroupCommunicator::Sum);
|
||||
gcomm.Bcast(zones_per_vdof);
|
||||
|
||||
// Accumulate for all vdofs.
|
||||
gcomm.Reduce<double>(data, GroupCommunicator::Sum);
|
||||
gcomm.Bcast<double>(data);
|
||||
// Accumulate for all tdofs.
|
||||
HypreParVector *tv = this->ParallelAssemble();
|
||||
this->Distribute(tv);
|
||||
delete tv;
|
||||
|
||||
ComputeMeans(type, zones_per_vdof);
|
||||
}
|
||||
@@ -391,10 +389,10 @@ void ParGridFunction::ProjectDiscCoefficient(VectorCoefficient &vcoeff,
|
||||
GroupCommunicator &gcomm = pfes->GroupComm();
|
||||
gcomm.Reduce<int>(zones_per_vdof, GroupCommunicator::Sum);
|
||||
gcomm.Bcast(zones_per_vdof);
|
||||
|
||||
// Accumulate for all vdofs.
|
||||
gcomm.Reduce<double>(data, GroupCommunicator::Sum);
|
||||
gcomm.Bcast<double>(data);
|
||||
// Accumulate for all tdofs.
|
||||
HypreParVector *tv = this->ParallelAssemble();
|
||||
this->Distribute(tv);
|
||||
delete tv;
|
||||
|
||||
ComputeMeans(type, zones_per_vdof);
|
||||
}
|
||||
@@ -427,8 +425,8 @@ void ParGridFunction::ProjectBdrCoefficient(
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: is this the same as the conforming case (after the merge of
|
||||
// cut-mesh-groups-dev)?
|
||||
// FIXME: same as the conforming case after 'cut-mesh-groups-dev-*' is
|
||||
// merged?
|
||||
ComputeMeans(ARITHMETIC, values_counter);
|
||||
}
|
||||
#ifdef MFEM_DEBUG
|
||||
@@ -471,8 +469,8 @@ void ParGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: is this the same as the conforming case (after the merge of
|
||||
// cut-mesh-groups-dev)?
|
||||
// FIXME: same as the conforming case after 'cut-mesh-groups-dev-*' is
|
||||
// merged?
|
||||
ComputeMeans(ARITHMETIC, values_counter);
|
||||
}
|
||||
#ifdef MFEM_DEBUG
|
||||
@@ -489,17 +487,16 @@ void ParGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
|
||||
|
||||
void ParGridFunction::Save(std::ostream &out) const
|
||||
{
|
||||
double *data_ = const_cast<double*>(HostRead());
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (pfes->GetDofSign(i) < 0) { data_[i] = -data_[i]; }
|
||||
if (pfes->GetDofSign(i) < 0) { data[i] = -data[i]; }
|
||||
}
|
||||
|
||||
GridFunction::Save(out);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (pfes->GetDofSign(i) < 0) { data_[i] = -data_[i]; }
|
||||
if (pfes->GetDofSign(i) < 0) { data[i] = -data[i]; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,8 +112,6 @@ public:
|
||||
/// Associate a new parallel space with the ParGridFunction.
|
||||
void SetSpace(ParFiniteElementSpace *f);
|
||||
|
||||
using GridFunction::MakeRef;
|
||||
|
||||
/** @brief Make the ParGridFunction reference external data on a new
|
||||
FiniteElementSpace. */
|
||||
/** This method changes the FiniteElementSpace associated with the
|
||||
|
||||
@@ -46,7 +46,7 @@ double ParNonlinearForm::GetParGridFunctionEnergy(const Vector &x) const
|
||||
void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
NonlinearForm::Mult(x, y); // x --(P)--> aux1 --(A_local)--> aux2
|
||||
Y.MakeRef(aux2, 0); // aux2 contains A_local.P.x
|
||||
Y.SetData(aux2.GetData()); // aux2 contains A_local.P.x
|
||||
|
||||
if (fnfi.Size())
|
||||
{
|
||||
@@ -58,7 +58,7 @@ void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
Array<int> vdofs1, vdofs2;
|
||||
Vector el_x, el_y;
|
||||
|
||||
X.MakeRef(aux1, 0); // aux1 contains P.x
|
||||
X.SetData(aux1.GetData()); // aux1 contains P.x
|
||||
X.ExchangeFaceNbrData();
|
||||
const int n_shared_faces = pmesh->GetNSharedFaces();
|
||||
for (int i = 0; i < n_shared_faces; i++)
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
#include "fem.hpp"
|
||||
|
||||
#include <axom/sidre.hpp>
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include <sidre/IOManager.hpp>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <iomanip> // for setw, setfill
|
||||
@@ -202,10 +204,10 @@ SidreDataCollection::get_file_path(const std::string &filename) const
|
||||
|
||||
axom::sidre::View *
|
||||
SidreDataCollection::AllocNamedBuffer(const std::string& buffer_name,
|
||||
axom::sidre::IndexType sz,
|
||||
axom::sidre::SidreLength sz,
|
||||
axom::sidre::TypeID type)
|
||||
{
|
||||
sz = std::max(sz, sidre::IndexType(0));
|
||||
sz = std::max(sz, sidre::SidreLength(0));
|
||||
sidre::Group *f = named_buffers_grp();
|
||||
sidre::View *v = NULL;
|
||||
|
||||
@@ -823,7 +825,7 @@ void SidreDataCollection::Save(const std::string& filename,
|
||||
void SidreDataCollection::
|
||||
addScalarBasedGridFunction(const std::string &field_name, GridFunction *gf,
|
||||
const std::string &buffer_name,
|
||||
axom::sidre::IndexType offset)
|
||||
axom::sidre::SidreLength offset)
|
||||
{
|
||||
sidre::Group* grp = m_bp_grp->getGroup("fields/" + field_name);
|
||||
MFEM_ASSERT(grp != NULL, "field " << field_name << " does not exist");
|
||||
@@ -886,7 +888,7 @@ addScalarBasedGridFunction(const std::string &field_name, GridFunction *gf,
|
||||
void SidreDataCollection::
|
||||
addVectorBasedGridFunction(const std::string& field_name, GridFunction *gf,
|
||||
const std::string &buffer_name,
|
||||
axom::sidre::IndexType offset)
|
||||
axom::sidre::SidreLength offset)
|
||||
{
|
||||
sidre::Group* grp = m_bp_grp->getGroup("fields/" + field_name);
|
||||
MFEM_ASSERT(grp != NULL, "field " << field_name << " does not exist");
|
||||
@@ -1011,7 +1013,7 @@ DeregisterFieldInBPIndex(const std::string& field_name)
|
||||
void SidreDataCollection::RegisterField(const std::string &field_name,
|
||||
GridFunction *gf,
|
||||
const std::string &buffer_name,
|
||||
axom::sidre::IndexType offset)
|
||||
axom::sidre::SidreLength offset)
|
||||
{
|
||||
if ( field_name.empty() || buffer_name.empty() ||
|
||||
gf == NULL || gf->FESpace() == NULL )
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
# pragma GCC diagnostic ignored "-Wpedantic"
|
||||
# endif
|
||||
#endif
|
||||
#include <axom/sidre.hpp>
|
||||
#include <sidre/sidre.hpp>
|
||||
#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
@@ -246,7 +246,7 @@ public:
|
||||
*/
|
||||
void RegisterField(const std::string &field_name, GridFunction *gf,
|
||||
const std::string &buffer_name,
|
||||
axom::sidre::IndexType offset);
|
||||
axom::sidre::SidreLength offset);
|
||||
|
||||
/// Registers an attribute field in the Sidre DataStore
|
||||
/** The registration process is similar to that of RegisterField()
|
||||
@@ -385,7 +385,7 @@ public:
|
||||
*/
|
||||
axom::sidre::View *
|
||||
AllocNamedBuffer(const std::string& buffer_name,
|
||||
axom::sidre::IndexType sz,
|
||||
axom::sidre::SidreLength sz,
|
||||
axom::sidre::TypeID type =
|
||||
axom::sidre::DOUBLE_ID);
|
||||
|
||||
@@ -469,7 +469,7 @@ private:
|
||||
void addScalarBasedGridFunction(const std::string& field_name,
|
||||
GridFunction* gf,
|
||||
const std::string &buffer_name,
|
||||
axom::sidre::IndexType offset);
|
||||
axom::sidre::SidreLength offset);
|
||||
|
||||
/**
|
||||
* \brief A private helper function to set up the views associated with the
|
||||
@@ -483,7 +483,7 @@ private:
|
||||
void addVectorBasedGridFunction(const std::string& field_name,
|
||||
GridFunction* gf,
|
||||
const std::string &buffer_name,
|
||||
axom::sidre::IndexType offset);
|
||||
axom::sidre::SidreLength offset);
|
||||
|
||||
/** @brief A private helper function to set up the Views associated with
|
||||
attribute field named @a field_name */
|
||||
|
||||
+19
-196
@@ -12,7 +12,6 @@
|
||||
#include "tmop.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "pgridfunc.hpp"
|
||||
#include "tmop_tools.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -769,7 +768,7 @@ void TMOP_Metric_352::AssembleH(const DenseMatrix &Jpt,
|
||||
void TargetConstructor::ComputeAvgVolume() const
|
||||
{
|
||||
MFEM_VERIFY(nodes, "Nodes are not given!");
|
||||
MFEM_ASSERT(avg_volume == 0.0, "The average volume is already computed!");
|
||||
MFEM_ASSERT(avg_volume == 0.0, "the average volume is already computed!");
|
||||
|
||||
Mesh *mesh = nodes->FESpace()->GetMesh();
|
||||
const int NE = mesh->GetNE();
|
||||
@@ -788,13 +787,9 @@ void TargetConstructor::ComputeAvgVolume() const
|
||||
volume += ip.weight * Tr.Weight();
|
||||
}
|
||||
}
|
||||
|
||||
NCMesh *ncmesh = mesh->ncmesh;
|
||||
if (Parallel() == false)
|
||||
if (!Parallel())
|
||||
{
|
||||
avg_volume = (ncmesh == NULL) ?
|
||||
volume / NE : volume / ncmesh->GetNumRootElements();
|
||||
|
||||
avg_volume = volume / NE;
|
||||
}
|
||||
#ifdef MFEM_USE_MPI
|
||||
else
|
||||
@@ -802,8 +797,7 @@ void TargetConstructor::ComputeAvgVolume() const
|
||||
double area_NE[4];
|
||||
area_NE[0] = volume; area_NE[1] = NE;
|
||||
MPI_Allreduce(area_NE, area_NE + 2, 2, MPI_DOUBLE, MPI_SUM, comm);
|
||||
avg_volume = (ncmesh == NULL) ?
|
||||
area_NE[2] / area_NE[3] : area_NE[2] / ncmesh->GetNumRootElements();
|
||||
avg_volume = area_NE[2] / area_NE[3];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -811,7 +805,6 @@ void TargetConstructor::ComputeAvgVolume() const
|
||||
// virtual method
|
||||
void TargetConstructor::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
const IntegrationRule &ir,
|
||||
const Vector &elfun,
|
||||
DenseTensor &Jtr) const
|
||||
{
|
||||
MFEM_ASSERT(target_type == IDEAL_SHAPE_UNIT_SIZE || nodes != NULL, "");
|
||||
@@ -834,15 +827,7 @@ void TargetConstructor::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
{
|
||||
if (avg_volume == 0.0) { ComputeAvgVolume(); }
|
||||
DenseMatrix W(Wideal.Height());
|
||||
|
||||
NCMesh *ncmesh = nodes->FESpace()->GetMesh()->ncmesh;
|
||||
double el_volume = avg_volume;
|
||||
if (ncmesh)
|
||||
{
|
||||
el_volume = avg_volume / ncmesh->GetElementSizeReduction(e_id);
|
||||
}
|
||||
|
||||
W.Set(std::pow(volume_scale * el_volume / Wideal.Det(),
|
||||
W.Set(std::pow(volume_scale * avg_volume / Wideal.Det(),
|
||||
1./W.Height()), Wideal);
|
||||
for (int i = 0; i < ir.GetNPoints(); i++) { Jtr(i) = W; }
|
||||
break;
|
||||
@@ -868,7 +853,7 @@ void TargetConstructor::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
if (target_type == IDEAL_SHAPE_GIVEN_SIZE)
|
||||
{
|
||||
const double det = Jtr(i).Det();
|
||||
MFEM_VERIFY(det > 0.0, "The given mesh is inverted!");
|
||||
MFEM_VERIFY(det > 0.0, "Initial mesh is inverted!");
|
||||
Jtr(i).Set(std::pow(det / detW, 1./dim), Wideal);
|
||||
}
|
||||
}
|
||||
@@ -879,162 +864,6 @@ void TargetConstructor::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
}
|
||||
}
|
||||
|
||||
void AnalyticAdaptTC::SetAnalyticTargetSpec(Coefficient *sspec,
|
||||
VectorCoefficient *vspec,
|
||||
MatrixCoefficient *mspec)
|
||||
{
|
||||
scalar_tspec = sspec;
|
||||
vector_tspec = vspec;
|
||||
matrix_tspec = mspec;
|
||||
}
|
||||
|
||||
void AnalyticAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
const IntegrationRule &ir,
|
||||
const Vector &elfun,
|
||||
DenseTensor &Jtr) const
|
||||
{
|
||||
DenseMatrix point_mat;
|
||||
point_mat.UseExternalData(elfun.GetData(), fe.GetDof(), fe.GetDim());
|
||||
|
||||
switch (target_type)
|
||||
{
|
||||
case GIVEN_FULL:
|
||||
{
|
||||
MFEM_VERIFY(matrix_tspec != NULL,
|
||||
"Target type GIVEN_FULL requires a MatrixCoefficient.");
|
||||
|
||||
IsoparametricTransformation Tpr;
|
||||
Tpr.SetFE(&fe);
|
||||
Tpr.ElementNo = e_id;
|
||||
Tpr.GetPointMat().Transpose(point_mat);
|
||||
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
Tpr.SetIntPoint(&ip);
|
||||
matrix_tspec->Eval(Jtr(i), Tpr, ip);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MFEM_ABORT("Incompatible target type for analytic adaptation!");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
void DiscreteAdaptTC::SetParDiscreteTargetSpec(ParGridFunction &tspec)
|
||||
{
|
||||
target_spec.SetSize(tspec.Size());
|
||||
target_spec = tspec;
|
||||
tspec_fes = tspec.FESpace();
|
||||
|
||||
// Default evaluator is based on CG advection.
|
||||
if (adapt_eval == NULL) { adapt_eval = new AdvectorCG; }
|
||||
|
||||
adapt_eval->SetParMetaInfo(*tspec.ParFESpace()->GetParMesh(),
|
||||
*tspec.FESpace()->FEColl(),
|
||||
tspec.FESpace()->GetVDim());
|
||||
|
||||
adapt_eval->SetInitialField
|
||||
(*tspec.FESpace()->GetMesh()->GetNodes(), target_spec);
|
||||
}
|
||||
#endif
|
||||
|
||||
void DiscreteAdaptTC::SetSerialDiscreteTargetSpec(GridFunction &tspec)
|
||||
{
|
||||
target_spec.SetSize(tspec.Size());
|
||||
target_spec = tspec;
|
||||
tspec_fes = tspec.FESpace();
|
||||
|
||||
// Default evaluator is based on CG advection.
|
||||
if (adapt_eval == NULL) { adapt_eval = new AdvectorCG; }
|
||||
|
||||
adapt_eval->SetSerialMetaInfo(*tspec.FESpace()->GetMesh(),
|
||||
*tspec.FESpace()->FEColl(),
|
||||
tspec.FESpace()->GetVDim());
|
||||
|
||||
adapt_eval->SetInitialField
|
||||
(*tspec.FESpace()->GetMesh()->GetNodes(), target_spec);
|
||||
}
|
||||
|
||||
void DiscreteAdaptTC::UpdateTargetSpecification(const Vector &new_x)
|
||||
{
|
||||
MFEM_VERIFY(target_spec.Size() > 0, "Target specification is not set!");
|
||||
|
||||
adapt_eval->ComputeAtNewPosition(new_x, target_spec);
|
||||
}
|
||||
|
||||
void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
const IntegrationRule &ir,
|
||||
const Vector &elfun,
|
||||
DenseTensor &Jtr) const
|
||||
{
|
||||
MFEM_VERIFY(tspec_fes, "A call to SetDiscreteTargerSpec() is needed.");
|
||||
|
||||
switch (target_type)
|
||||
{
|
||||
case IDEAL_SHAPE_GIVEN_SIZE:
|
||||
{
|
||||
const DenseMatrix &Wideal =
|
||||
Geometries.GetGeomToPerfGeomJac(fe.GetGeomType());
|
||||
const int dim = Wideal.Height(),
|
||||
ntspec_dofs = tspec_fes->GetFE(0)->GetDof();
|
||||
|
||||
Vector shape(ntspec_dofs), tspec_vals(ntspec_dofs);
|
||||
Array<int> dofs;
|
||||
tspec_fes->GetElementDofs(e_id, dofs);
|
||||
target_spec.GetSubVector(dofs, tspec_vals);
|
||||
|
||||
const double min_size = tspec_vals.Min();
|
||||
MFEM_ASSERT(min_size > 0.0,
|
||||
"Non-positive size propagated in the target definition.");
|
||||
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
tspec_fes->GetFE(e_id)->CalcShape(ip, shape);
|
||||
const double size = std::max(shape * tspec_vals, min_size);
|
||||
Jtr(i).Set(std::pow(size / Wideal.Det(), 1.0/dim), Wideal);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MFEM_ABORT("Incompatible target type for analytic adaptation!");
|
||||
}
|
||||
}
|
||||
|
||||
void AdaptivityEvaluator::SetSerialMetaInfo(const Mesh &m,
|
||||
const FiniteElementCollection &fec,
|
||||
int num_comp)
|
||||
{
|
||||
delete fes;
|
||||
delete mesh;
|
||||
mesh = new Mesh(m, true);
|
||||
fes = new FiniteElementSpace(mesh, &fec, num_comp);
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
void AdaptivityEvaluator::SetParMetaInfo(const ParMesh &m,
|
||||
const FiniteElementCollection &fec,
|
||||
int num_comp)
|
||||
{
|
||||
delete pfes;
|
||||
delete pmesh;
|
||||
pmesh = new ParMesh(m, true);
|
||||
pfes = new ParFiniteElementSpace(pmesh, &fec, num_comp);
|
||||
}
|
||||
#endif
|
||||
|
||||
AdaptivityEvaluator::~AdaptivityEvaluator()
|
||||
{
|
||||
delete fes;
|
||||
delete mesh;
|
||||
#ifdef MFEM_USE_MPI
|
||||
delete pfes;
|
||||
delete pmesh;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TMOP_Integrator::EnableLimiting(const GridFunction &n0,
|
||||
const GridFunction &dist, Coefficient &w0,
|
||||
TMOP_LimiterFunction *lfunc)
|
||||
@@ -1092,7 +921,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
|
||||
energy = 0.0;
|
||||
DenseTensor Jtr(dim, dim, ir->GetNPoints());
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, Jtr);
|
||||
|
||||
// Limited case.
|
||||
Vector shape, p, p0, d_vals;
|
||||
@@ -1127,13 +956,13 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
Tpr->Attribute = T.Attribute;
|
||||
Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
|
||||
}
|
||||
// TODO: computing the coefficients 'coeff1' and 'coeff0' in physical
|
||||
// coordinates means that, generally, the gradient and Hessian of the
|
||||
// TMOP_Integrator will depend on the derivatives of the coefficients.
|
||||
// FIXME: computing the coefficients 'coeff1' and 'coeff0' in physical
|
||||
// coordinates means that, generally, the gradient and Hessian of the
|
||||
// TMOP_Integrator will depend on the derivatives of the coefficients.
|
||||
//
|
||||
// In some cases the coefficients are independent of any movement of
|
||||
// the physical coordinates (i.e. changes in 'elfun'), e.g. when the
|
||||
// coefficient is a ConstantCoefficient or a GridFunctionCoefficient.
|
||||
// In some cases the coefficients are independent of any movement of
|
||||
// the physical coordinates (i.e. changes in 'elfun'), e.g. when the
|
||||
// coefficient is a ConstantCoefficient or a GridFunctionCoefficient.
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
@@ -1161,7 +990,6 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
energy += weight * val;
|
||||
}
|
||||
delete Tpr;
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
@@ -1188,7 +1016,7 @@ void TMOP_Integrator::AssembleElementVector(const FiniteElement &el,
|
||||
|
||||
elvect = 0.0;
|
||||
DenseTensor Jtr(dim, dim, ir->GetNPoints());
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, Jtr);
|
||||
|
||||
// Limited case.
|
||||
DenseMatrix pos0;
|
||||
@@ -1244,8 +1072,6 @@ void TMOP_Integrator::AssembleElementVector(const FiniteElement &el,
|
||||
P *= weight_m;
|
||||
AddMultABt(DS, P, PMatO);
|
||||
|
||||
// TODO: derivatives of adaptivity-based targets.
|
||||
|
||||
if (coeff0)
|
||||
{
|
||||
el.CalcShape(ip, shape);
|
||||
@@ -1281,7 +1107,7 @@ void TMOP_Integrator::AssembleElementGrad(const FiniteElement &el,
|
||||
|
||||
elmat = 0.0;
|
||||
DenseTensor Jtr(dim, dim, ir->GetNPoints());
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, Jtr);
|
||||
|
||||
// Limited case.
|
||||
DenseMatrix pos0, grad_grad;
|
||||
@@ -1334,8 +1160,6 @@ void TMOP_Integrator::AssembleElementGrad(const FiniteElement &el,
|
||||
|
||||
metric->AssembleH(Jpt, DS, weight_m, elmat);
|
||||
|
||||
// TODO: derivatives of adaptivity-based targets.
|
||||
|
||||
if (coeff0)
|
||||
{
|
||||
el.CalcShape(ip, shape);
|
||||
@@ -1410,12 +1234,11 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x,
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
fe = fes->GetFE(i);
|
||||
targetC->ComputeElementTargets(i, *fe, *ir, Jtr);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
x.GetSubVector(vdofs, x_vals);
|
||||
PMatI.UseExternalData(x_vals.GetData(), dof, dim);
|
||||
|
||||
targetC->ComputeElementTargets(i, *fe, *ir, x_vals, Jtr);
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
@@ -1451,6 +1274,9 @@ void InterpolateTMOP_QualityMetric(TMOP_QualityMetric &metric,
|
||||
const IntegrationRule &ir = metric_gf.FESpace()->GetFE(i)->GetNodes();
|
||||
const int nsp = ir.GetNPoints(), dof = fe_pos.GetDof();
|
||||
|
||||
W.SetSize(dim, dim, nsp);
|
||||
tc.ComputeElementTargets(i, fe_pos, ir, W);
|
||||
|
||||
dshape.SetSize(dof, dim);
|
||||
pos.SetSize(dof, dim);
|
||||
posV.SetDataAndSize(pos.Data(), dof * dim);
|
||||
@@ -1459,9 +1285,6 @@ void InterpolateTMOP_QualityMetric(TMOP_QualityMetric &metric,
|
||||
nodes.FESpace()->GetElementVDofs(i, pos_dofs);
|
||||
nodes.GetSubVector(pos_dofs, posV);
|
||||
|
||||
W.SetSize(dim, dim, nsp);
|
||||
tc.ComputeElementTargets(i, fe_pos, ir, posV, W);
|
||||
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
const DenseMatrix &Wj = W(j);
|
||||
|
||||
+3
-124
@@ -12,6 +12,7 @@
|
||||
#ifndef MFEM_TMOP_HPP
|
||||
#define MFEM_TMOP_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "../linalg/invariants.hpp"
|
||||
#include "nonlininteg.hpp"
|
||||
|
||||
@@ -513,51 +514,6 @@ public:
|
||||
virtual ~TMOP_QuadraticLimiter() { }
|
||||
};
|
||||
|
||||
class FiniteElementCollection;
|
||||
class FiniteElementSpace;
|
||||
class ParFiniteElementSpace;
|
||||
|
||||
class AdaptivityEvaluator
|
||||
{
|
||||
protected:
|
||||
// Owned.
|
||||
Mesh *mesh;
|
||||
FiniteElementSpace *fes;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
// Owned.
|
||||
ParMesh *pmesh;
|
||||
ParFiniteElementSpace *pfes;
|
||||
#endif
|
||||
|
||||
public:
|
||||
AdaptivityEvaluator() : mesh(NULL), fes(NULL)
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
pmesh = NULL;
|
||||
pfes = NULL;
|
||||
#endif
|
||||
}
|
||||
virtual ~AdaptivityEvaluator();
|
||||
|
||||
/** Specifies the Mesh and FiniteElementCollection of the solution that will
|
||||
be evaluated. The given mesh will be copied into the internal object. */
|
||||
void SetSerialMetaInfo(const Mesh &m,
|
||||
const FiniteElementCollection &fec, int num_comp);
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
/// Parallel version of SetSerialMetaInfo.
|
||||
void SetParMetaInfo(const ParMesh &m,
|
||||
const FiniteElementCollection &fec, int num_comp);
|
||||
#endif
|
||||
|
||||
// TODO use GridFunctions to make clear it's on the ldofs?
|
||||
virtual void SetInitialField(const Vector &init_nodes,
|
||||
const Vector &init_field) = 0;
|
||||
|
||||
virtual void ComputeAtNewPosition(const Vector &new_nodes,
|
||||
Vector &new_field) = 0;
|
||||
};
|
||||
|
||||
/** @brief Base class representing target-matrix construction algorithms for
|
||||
mesh optimization via the target-matrix optimization paradigm (TMOP). */
|
||||
@@ -582,11 +538,9 @@ public:
|
||||
IDEAL_SHAPE_GIVEN_SIZE, /**<
|
||||
Ideal shape, given size/volume; the given nodes define the target
|
||||
volume at all quadrature points. */
|
||||
GIVEN_SHAPE_AND_SIZE, /**<
|
||||
GIVEN_SHAPE_AND_SIZE /**<
|
||||
Given shape, given size/volume; the given nodes define the exact target
|
||||
Jacobian matrix at all quadrature points. */
|
||||
GIVEN_FULL /**<
|
||||
Full target tensor is specified at every quadrature point. */
|
||||
};
|
||||
|
||||
protected:
|
||||
@@ -635,89 +589,14 @@ public:
|
||||
void SetVolumeScale(double vol_scale) { volume_scale = vol_scale; }
|
||||
|
||||
/** @brief Given an element and quadrature rule, computes ref->target
|
||||
transformation Jacobians for each quadrature point in the element.
|
||||
The physical positions of the element's nodes are given by @a elfun. */
|
||||
transformation Jacobians for each quadrature point in the element. */
|
||||
virtual void ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
const IntegrationRule &ir,
|
||||
const Vector &elfun,
|
||||
DenseTensor &Jtr) const;
|
||||
};
|
||||
|
||||
class AnalyticAdaptTC : public TargetConstructor
|
||||
{
|
||||
protected:
|
||||
// Analytic target specification.
|
||||
Coefficient *scalar_tspec;
|
||||
VectorCoefficient *vector_tspec;
|
||||
MatrixCoefficient *matrix_tspec;
|
||||
|
||||
public:
|
||||
AnalyticAdaptTC(TargetType ttype)
|
||||
: TargetConstructor(ttype),
|
||||
scalar_tspec(NULL), vector_tspec(NULL), matrix_tspec(NULL) { }
|
||||
|
||||
virtual void SetAnalyticTargetSpec(Coefficient *sspec,
|
||||
VectorCoefficient *vspec,
|
||||
MatrixCoefficient *mspec);
|
||||
|
||||
/** @brief Given an element and quadrature rule, computes ref->target
|
||||
transformation Jacobians for each quadrature point in the element.
|
||||
The physical positions of the element's nodes are given by @a elfun. */
|
||||
virtual void ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
const IntegrationRule &ir,
|
||||
const Vector &elfun,
|
||||
DenseTensor &Jtr) const;
|
||||
};
|
||||
|
||||
class ParGridFunction;
|
||||
|
||||
class DiscreteAdaptTC : public TargetConstructor
|
||||
{
|
||||
protected:
|
||||
// Discrete target specification.
|
||||
// Data is owned, updated by UpdateTargetSpecification.
|
||||
Vector target_spec;
|
||||
// Note: do not use the Nodes of this space as they may not be on the
|
||||
// positions corresponding to the values of tspec.
|
||||
const FiniteElementSpace *tspec_fes;
|
||||
|
||||
// Evaluation of the discrete target specification on different meshes.
|
||||
// Owned.
|
||||
AdaptivityEvaluator *adapt_eval;
|
||||
|
||||
public:
|
||||
DiscreteAdaptTC(TargetType ttype)
|
||||
: TargetConstructor(ttype),
|
||||
target_spec(), tspec_fes(NULL), adapt_eval(NULL) { }
|
||||
|
||||
virtual ~DiscreteAdaptTC() { delete adapt_eval; }
|
||||
|
||||
virtual void SetSerialDiscreteTargetSpec(GridFunction &tspec);
|
||||
#ifdef MFEM_USE_MPI
|
||||
virtual void SetParDiscreteTargetSpec(ParGridFunction &tspec);
|
||||
#endif
|
||||
|
||||
/** Used to update the target specification after the mesh has changed. The
|
||||
new mesh positions are given by new_x. */
|
||||
void UpdateTargetSpecification(const Vector &new_x);
|
||||
|
||||
void SetAdaptivityEvaluator(AdaptivityEvaluator *ae)
|
||||
{
|
||||
if (adapt_eval) { delete adapt_eval; }
|
||||
adapt_eval = ae;
|
||||
}
|
||||
|
||||
/** @brief Given an element and quadrature rule, computes ref->target
|
||||
transformation Jacobians for each quadrature point in the element.
|
||||
The physical positions of the element's nodes are given by @a elfun.
|
||||
Note that this function assumes that UpdateTargetSpecification() has
|
||||
been called with the position vector corresponding to @a elfun. */
|
||||
virtual void ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
const IntegrationRule &ir,
|
||||
const Vector &elfun,
|
||||
DenseTensor &Jtr) const;
|
||||
};
|
||||
|
||||
/** @brief A TMOP integrator class based on any given TMOP_QualityMetric and
|
||||
TargetConstructor.
|
||||
|
||||
|
||||
@@ -1,518 +0,0 @@
|
||||
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
||||
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
||||
// reserved. See file COPYRIGHT for details.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability see http://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU Lesser General Public License (as published by the Free
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
#include "tmop_tools.hpp"
|
||||
#include "nonlinearform.hpp"
|
||||
#include "pnonlinearform.hpp"
|
||||
#include "../general/osockstream.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
void AdvectorCG::SetInitialField(const Vector &init_nodes,
|
||||
const Vector &init_field)
|
||||
{
|
||||
nodes0 = init_nodes;
|
||||
field0 = init_field;
|
||||
}
|
||||
|
||||
void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes,
|
||||
Vector &new_field)
|
||||
{
|
||||
int myid = 0;
|
||||
Mesh *m = mesh;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (pfes) { MPI_Comm_rank(pfes->GetComm(), &myid); }
|
||||
if (pmesh) { m = pmesh; }
|
||||
#endif
|
||||
|
||||
MFEM_VERIFY(m != NULL, "No mesh has been given to the AdaptivityEvaluator.");
|
||||
|
||||
// This will be used to move the positions.
|
||||
GridFunction *mesh_nodes = m->GetNodes();
|
||||
*mesh_nodes = nodes0;
|
||||
new_field = field0;
|
||||
|
||||
// Velocity of the positions.
|
||||
GridFunction u(mesh_nodes->FESpace());
|
||||
subtract(new_nodes, nodes0, u);
|
||||
|
||||
TimeDependentOperator *oper = NULL;
|
||||
// This must be the fes of the ind, associated with the object's mesh.
|
||||
if (fes) { oper = new SerialAdvectorCGOper(nodes0, u, *fes); }
|
||||
#ifdef MFEM_USE_MPI
|
||||
else if (pfes) { oper = new ParAdvectorCGOper(nodes0, u, *pfes); }
|
||||
#endif
|
||||
MFEM_VERIFY(oper != NULL,
|
||||
"No FE space has been given to the AdaptivityEvaluator.");
|
||||
ode_solver.Init(*oper);
|
||||
|
||||
// Compute some time step [mesh_size / speed].
|
||||
double min_h = std::numeric_limits<double>::infinity();
|
||||
for (int i = 0; i < m->GetNE(); i++)
|
||||
{
|
||||
min_h = std::min(min_h, m->GetElementSize(i));
|
||||
}
|
||||
double v_max = 0.0;
|
||||
const int s = u.FESpace()->GetVSize() / 2;
|
||||
for (int i = 0; i < s; i++)
|
||||
{
|
||||
const double vel = u(i) * u(i) + u(i+s) * u(i+s);
|
||||
v_max = std::max(v_max, vel);
|
||||
}
|
||||
if (v_max == 0.0)
|
||||
{
|
||||
// No need to change the field.
|
||||
return;
|
||||
}
|
||||
v_max = std::sqrt(v_max);
|
||||
double dt = 0.5 * min_h / v_max;
|
||||
double glob_dt = dt;
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (pfes)
|
||||
{
|
||||
MPI_Allreduce(&dt, &glob_dt, 1, MPI_DOUBLE, MPI_MIN, pfes->GetComm());
|
||||
}
|
||||
#endif
|
||||
|
||||
double t = 0.0;
|
||||
bool last_step = false;
|
||||
for (int ti = 1; !last_step; ti++)
|
||||
{
|
||||
if (t + glob_dt >= 1.0)
|
||||
{
|
||||
#ifdef MFEM_DEBUG
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "Remap took " << ti << " steps." << std::endl;
|
||||
}
|
||||
#endif
|
||||
glob_dt = 1.0 - t;
|
||||
last_step = true;
|
||||
}
|
||||
ode_solver.Step(new_field, t, glob_dt);
|
||||
}
|
||||
|
||||
// Trim the overshoots and undershoots.
|
||||
const double minv = field0.Min(), maxv = field0.Max();
|
||||
for (int i = 0; i < new_field.Size(); i++)
|
||||
{
|
||||
if (new_field(i) < minv) { new_field(i) = minv; }
|
||||
if (new_field(i) > maxv) { new_field(i) = maxv; }
|
||||
}
|
||||
|
||||
nodes0 = new_nodes;
|
||||
field0 = new_field;
|
||||
|
||||
delete oper;
|
||||
}
|
||||
|
||||
SerialAdvectorCGOper::SerialAdvectorCGOper(const Vector &x_start,
|
||||
GridFunction &vel,
|
||||
FiniteElementSpace &fes)
|
||||
: TimeDependentOperator(fes.GetVSize()),
|
||||
x0(x_start), x_now(*fes.GetMesh()->GetNodes()),
|
||||
u(vel), u_coeff(&u), M(&fes), K(&fes)
|
||||
{
|
||||
ConvectionIntegrator *Kinteg = new ConvectionIntegrator(u_coeff);
|
||||
K.AddDomainIntegrator(Kinteg);
|
||||
K.Assemble(0);
|
||||
K.Finalize(0);
|
||||
|
||||
MassIntegrator *Minteg = new MassIntegrator;
|
||||
M.AddDomainIntegrator(Minteg);
|
||||
M.Assemble();
|
||||
M.Finalize();
|
||||
}
|
||||
|
||||
void SerialAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
|
||||
{
|
||||
// Move the mesh.
|
||||
const double t = GetTime();
|
||||
add(x0, t, u, x_now);
|
||||
|
||||
// Assemble on the new mesh.
|
||||
K.BilinearForm::operator=(0.0);
|
||||
K.Assemble();
|
||||
Vector rhs(K.Size());
|
||||
K.Mult(ind, rhs);
|
||||
M.BilinearForm::operator=(0.0);
|
||||
M.Assemble();
|
||||
|
||||
di_dt = 0.0;
|
||||
CGSolver lin_solver;
|
||||
DSmoother prec;
|
||||
lin_solver.SetPreconditioner(prec);
|
||||
lin_solver.SetOperator(M.SpMat());
|
||||
lin_solver.SetRelTol(1e-12); lin_solver.SetAbsTol(0.0);
|
||||
lin_solver.SetMaxIter(100);
|
||||
lin_solver.SetPrintLevel(0);
|
||||
lin_solver.Mult(rhs, di_dt);
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParAdvectorCGOper::ParAdvectorCGOper(const Vector &x_start,
|
||||
GridFunction &vel,
|
||||
ParFiniteElementSpace &pfes)
|
||||
: TimeDependentOperator(pfes.GetVSize()),
|
||||
x0(x_start), x_now(*pfes.GetMesh()->GetNodes()),
|
||||
u(vel), u_coeff(&u), M(&pfes), K(&pfes)
|
||||
{
|
||||
ConvectionIntegrator *Kinteg = new ConvectionIntegrator(u_coeff);
|
||||
K.AddDomainIntegrator(Kinteg);
|
||||
K.Assemble(0);
|
||||
K.Finalize(0);
|
||||
|
||||
MassIntegrator *Minteg = new MassIntegrator;
|
||||
M.AddDomainIntegrator(Minteg);
|
||||
M.Assemble();
|
||||
M.Finalize();
|
||||
}
|
||||
|
||||
void ParAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
|
||||
{
|
||||
// Move the mesh.
|
||||
const double t = GetTime();
|
||||
add(x0, t, u, x_now);
|
||||
|
||||
// Assemble on the new mesh.
|
||||
K.BilinearForm::operator=(0.0);
|
||||
K.Assemble();
|
||||
ParGridFunction rhs(K.ParFESpace());
|
||||
K.Mult(ind, rhs);
|
||||
M.BilinearForm::operator=(0.0);
|
||||
M.Assemble();
|
||||
|
||||
HypreParVector *RHS = rhs.ParallelAssemble();
|
||||
HypreParVector X(K.ParFESpace());
|
||||
X = 0.0;
|
||||
HypreParMatrix *Mh = M.ParallelAssemble();
|
||||
|
||||
CGSolver lin_solver(M.ParFESpace()->GetParMesh()->GetComm());
|
||||
HypreSmoother prec;
|
||||
prec.SetType(HypreSmoother::Jacobi, 1);
|
||||
lin_solver.SetPreconditioner(prec);
|
||||
lin_solver.SetOperator(*Mh);
|
||||
lin_solver.SetRelTol(1e-8);
|
||||
lin_solver.SetAbsTol(0.0);
|
||||
lin_solver.SetMaxIter(100);
|
||||
lin_solver.SetPrintLevel(0);
|
||||
lin_solver.Mult(*RHS, X);
|
||||
K.ParFESpace()->GetProlongationMatrix()->Mult(X, di_dt);
|
||||
|
||||
delete Mh;
|
||||
delete RHS;
|
||||
}
|
||||
#endif
|
||||
|
||||
double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
const Vector &b) const
|
||||
{
|
||||
const FiniteElementSpace *fes = NULL;
|
||||
double energy_in = 0.0;
|
||||
#ifdef MFEM_USE_MPI
|
||||
const ParNonlinearForm *p_nlf = dynamic_cast<const ParNonlinearForm *>(oper);
|
||||
MFEM_VERIFY(!(parallel && p_nlf == NULL), "Invalid Operator subclass.");
|
||||
if (parallel)
|
||||
{
|
||||
fes = p_nlf->FESpace();
|
||||
energy_in = p_nlf->GetEnergy(x);
|
||||
}
|
||||
#endif
|
||||
const bool serial = !parallel;
|
||||
const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
|
||||
MFEM_VERIFY(!(serial && nlf == NULL), "Invalid Operator subclass.");
|
||||
if (serial)
|
||||
{
|
||||
fes = nlf->FESpace();
|
||||
energy_in = nlf->GetEnergy(x);
|
||||
}
|
||||
|
||||
const bool have_b = (b.Size() == Height());
|
||||
|
||||
const int NE = fes->GetMesh()->GetNE(), dim = fes->GetFE(0)->GetDim(),
|
||||
dof = fes->GetFE(0)->GetDof(), nsp = ir.GetNPoints();
|
||||
Array<int> xdofs(dof * dim);
|
||||
DenseMatrix Jpr(dim), dshape(dof, dim), pos(dof, dim);
|
||||
Vector posV(pos.Data(), dof * dim);
|
||||
|
||||
Vector x_out(x.Size()), x_out_loc(fes->GetVSize());
|
||||
bool x_out_ok = false;
|
||||
double scale = 1.0, energy_out;
|
||||
double norm0 = Norm(r);
|
||||
|
||||
// Decreases the scaling of the update until the new mesh is valid.
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
add(x, -scale, c, x_out);
|
||||
|
||||
if (serial)
|
||||
{
|
||||
const SparseMatrix *cP = fes->GetConformingProlongation();
|
||||
if (!cP) {x_out_loc.SetData(x_out.GetData());}
|
||||
else {cP->Mult(x_out,x_out_loc);}
|
||||
energy_out = nlf->GetGridFunctionEnergy(x_out_loc);
|
||||
}
|
||||
#ifdef MFEM_USE_MPI
|
||||
else
|
||||
{
|
||||
fes->GetProlongationMatrix()->Mult(x_out, x_out_loc);
|
||||
energy_out = p_nlf->GetParGridFunctionEnergy(x_out_loc);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (energy_out > 1.2*energy_in || std::isnan(energy_out) != 0)
|
||||
{
|
||||
if (print_level >= 0)
|
||||
{ mfem::out << "Scale = " << scale << " Increasing energy.\n"; }
|
||||
scale *= 0.5; continue;
|
||||
}
|
||||
|
||||
int jac_ok = 1;
|
||||
for (int i = 0; i < NE; i++)
|
||||
{
|
||||
fes->GetElementVDofs(i, xdofs);
|
||||
x_out_loc.GetSubVector(xdofs, posV);
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
|
||||
MultAtB(pos, dshape, Jpr);
|
||||
if (Jpr.Det() <= 0.0) { jac_ok = 0; goto break2; }
|
||||
}
|
||||
}
|
||||
break2:
|
||||
int jac_ok_all = jac_ok;
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
MPI_Allreduce(&jac_ok, &jac_ok_all, 1, MPI_INT, MPI_LAND,
|
||||
p_nlf->ParFESpace()->GetComm());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (jac_ok_all == 0)
|
||||
{
|
||||
if (print_level >= 0)
|
||||
{ mfem::out << "Scale = " << scale << " Neg det(J) found.\n"; }
|
||||
scale *= 0.5; continue;
|
||||
}
|
||||
|
||||
oper->Mult(x_out, r);
|
||||
if (have_b) { r -= b; }
|
||||
double norm = Norm(r);
|
||||
|
||||
if (norm > 1.2*norm0)
|
||||
{
|
||||
if (print_level >= 0)
|
||||
{ mfem::out << "Scale = " << scale << " Norm increased.\n"; }
|
||||
scale *= 0.5; continue;
|
||||
}
|
||||
else { x_out_ok = true; break; }
|
||||
}
|
||||
|
||||
if (print_level >= 0)
|
||||
{
|
||||
mfem::out << "Energy decrease: "
|
||||
<< (energy_in - energy_out) / energy_in * 100.0
|
||||
<< "% with " << scale << " scaling.\n";
|
||||
}
|
||||
|
||||
if (x_out_ok == false) { scale = 0.0; }
|
||||
return scale;
|
||||
}
|
||||
|
||||
void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
|
||||
{
|
||||
if (discr_tc)
|
||||
{
|
||||
if (parallel)
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
const ParNonlinearForm *nlf =
|
||||
dynamic_cast<const ParNonlinearForm *>(oper);
|
||||
Vector x_loc(nlf->ParFESpace()->GetVSize());
|
||||
nlf->ParFESpace()->GetProlongationMatrix()->Mult(x, x_loc);
|
||||
discr_tc->UpdateTargetSpecification(x_loc);
|
||||
#endif
|
||||
}
|
||||
else { discr_tc->UpdateTargetSpecification(x); }
|
||||
}
|
||||
}
|
||||
|
||||
double TMOPDescentNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
const Vector &b) const
|
||||
{
|
||||
const FiniteElementSpace *fes = NULL;
|
||||
double energy_in = 0.0;
|
||||
#ifdef MFEM_USE_MPI
|
||||
const ParNonlinearForm *p_nlf = dynamic_cast<const ParNonlinearForm *>(oper);
|
||||
MFEM_VERIFY(!(parallel && p_nlf == NULL), "Invalid Operator subclass.");
|
||||
if (parallel)
|
||||
{
|
||||
fes = p_nlf->FESpace();
|
||||
energy_in = p_nlf->GetEnergy(x);
|
||||
}
|
||||
#endif
|
||||
const bool serial = !parallel;
|
||||
const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
|
||||
MFEM_VERIFY(!(serial && nlf == NULL), "Invalid Operator subclass.");
|
||||
if (serial)
|
||||
{
|
||||
fes = nlf->FESpace();
|
||||
energy_in = nlf->GetEnergy(x);
|
||||
}
|
||||
|
||||
const int NE = fes->GetMesh()->GetNE(), dim = fes->GetFE(0)->GetDim(),
|
||||
dof = fes->GetFE(0)->GetDof(), nsp = ir.GetNPoints();
|
||||
Array<int> xdofs(dof * dim);
|
||||
DenseMatrix Jpr(dim), dshape(dof, dim), pos(dof, dim);
|
||||
Vector posV(pos.Data(), dof * dim);
|
||||
Vector x_loc(fes->GetVSize());
|
||||
|
||||
double min_detJ = infinity();
|
||||
for (int i = 0; i < NE; i++)
|
||||
{
|
||||
fes->GetElementVDofs(i, xdofs);
|
||||
x_loc.GetSubVector(xdofs, posV);
|
||||
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
|
||||
MultAtB(pos, dshape, Jpr);
|
||||
min_detJ = std::min(min_detJ, Jpr.Det());
|
||||
}
|
||||
}
|
||||
double min_detJ_all = min_detJ;
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
{
|
||||
MPI_Allreduce(&min_detJ, &min_detJ_all, 1, MPI_DOUBLE, MPI_MIN,
|
||||
p_nlf->ParFESpace()->GetComm());
|
||||
}
|
||||
#endif
|
||||
if (print_level >= 0)
|
||||
{
|
||||
mfem::out << "Minimum det(J) = " << min_detJ_all << '\n';
|
||||
}
|
||||
|
||||
Vector x_out(x.Size());
|
||||
bool x_out_ok = false;
|
||||
double scale = 1.0, energy_out;
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
add(x, -scale, c, x_out);
|
||||
if (serial)
|
||||
{
|
||||
const SparseMatrix *cP = fes->GetConformingProlongation();
|
||||
if (!cP) {x_loc.SetData(x_out.GetData());}
|
||||
else {cP->Mult(x_out,x_loc);}
|
||||
energy_out = nlf->GetGridFunctionEnergy(x_loc);
|
||||
}
|
||||
#ifdef MFEM_USE_MPI
|
||||
else
|
||||
{
|
||||
fes->GetProlongationMatrix()->Mult(x_out, x_loc);
|
||||
energy_out = p_nlf->GetParGridFunctionEnergy(x_loc);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (energy_out > energy_in || std::isnan(energy_out) != 0)
|
||||
{
|
||||
scale *= 0.5;
|
||||
}
|
||||
else { x_out_ok = true; break; }
|
||||
}
|
||||
|
||||
if (print_level >= 0)
|
||||
{
|
||||
mfem::out << "Energy decrease: "
|
||||
<< (energy_in - energy_out) / energy_in * 100.0
|
||||
<< "% with " << scale << " scaling.\n";
|
||||
}
|
||||
|
||||
if (x_out_ok == false) { return 0.0; }
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
void TMOPDescentNewtonSolver::ProcessNewState(const Vector &x) const
|
||||
{
|
||||
if (discr_tc)
|
||||
{
|
||||
if (parallel)
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
const ParNonlinearForm *nlf =
|
||||
dynamic_cast<const ParNonlinearForm *>(oper);
|
||||
Vector x_loc(nlf->ParFESpace()->GetVSize());
|
||||
nlf->ParFESpace()->GetProlongationMatrix()->Mult(x, x_loc);
|
||||
discr_tc->UpdateTargetSpecification(x_loc);
|
||||
#endif
|
||||
}
|
||||
else { discr_tc->UpdateTargetSpecification(x); }
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
// Metric values are visualized by creating an L2 finite element functions and
|
||||
// computing the metric values at the nodes.
|
||||
void vis_tmop_metric_p(int order, TMOP_QualityMetric &qm,
|
||||
const TargetConstructor &tc, ParMesh &pmesh,
|
||||
char *title, int position)
|
||||
{
|
||||
L2_FECollection fec(order, pmesh.Dimension(), BasisType::GaussLobatto);
|
||||
ParFiniteElementSpace fes(&pmesh, &fec, 1);
|
||||
ParGridFunction metric(&fes);
|
||||
InterpolateTMOP_QualityMetric(qm, tc, pmesh, metric);
|
||||
socketstream sock;
|
||||
if (pmesh.GetMyRank() == 0)
|
||||
{
|
||||
sock.open("localhost", 19916);
|
||||
sock << "solution\n";
|
||||
}
|
||||
pmesh.PrintAsOne(sock);
|
||||
metric.SaveAsOne(sock);
|
||||
if (pmesh.GetMyRank() == 0)
|
||||
{
|
||||
sock << "window_title '"<< title << "'\n"
|
||||
<< "window_geometry "
|
||||
<< position << " " << 0 << " " << 600 << " " << 600 << "\n"
|
||||
<< "keys jRmclA\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Metric values are visualized by creating an L2 finite element functions and
|
||||
// computing the metric values at the nodes.
|
||||
void vis_tmop_metric_s(int order, TMOP_QualityMetric &qm,
|
||||
const TargetConstructor &tc, Mesh &mesh,
|
||||
char *title, int position)
|
||||
{
|
||||
L2_FECollection fec(order, mesh.Dimension(), BasisType::GaussLobatto);
|
||||
FiniteElementSpace fes(&mesh, &fec, 1);
|
||||
GridFunction metric(&fes);
|
||||
InterpolateTMOP_QualityMetric(qm, tc, mesh, metric);
|
||||
osockstream sock(19916, "localhost");
|
||||
sock << "solution\n";
|
||||
mesh.Print(sock);
|
||||
metric.Save(sock);
|
||||
sock.send();
|
||||
sock << "window_title '"<< title << "'\n"
|
||||
<< "window_geometry "
|
||||
<< position << " " << 0 << " " << 600 << " " << 600 << "\n"
|
||||
<< "keys jRmclA\n";
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user