Compare commits
87
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bcd14bcfb | ||
|
|
04029239d4 | ||
|
|
331b15563d | ||
|
|
13a48c2058 | ||
|
|
95a0d63574 | ||
|
|
75a1fd2388 | ||
|
|
d47185fdd3 | ||
|
|
55951f3778 | ||
|
|
6d2e45576d | ||
|
|
f61773132d | ||
|
|
cda16bf147 | ||
|
|
298417664b | ||
|
|
d386bdd4b4 | ||
|
|
4798173ecf | ||
|
|
0aed9d2752 | ||
|
|
ed3df1c25a | ||
|
|
9898923e66 | ||
|
|
21cdc4d8a3 | ||
|
|
b12684d9c6 | ||
|
|
675b137cbe | ||
|
|
83db3da392 | ||
|
|
c097bda546 | ||
|
|
56608342e8 | ||
|
|
a1c1da8e9c | ||
|
|
72968077c6 | ||
|
|
9cebf45288 | ||
|
|
ffc2dfc70b | ||
|
|
d996ee2d39 | ||
|
|
49c25eec31 | ||
|
|
27f8d46aae | ||
|
|
4a64afedc2 | ||
|
|
03d36aa518 | ||
|
|
b2f154112c | ||
|
|
247f9c7445 | ||
|
|
2baece3ab1 | ||
|
|
5b5769dea3 | ||
|
|
f617acf414 | ||
|
|
68fbe31aa1 | ||
|
|
8142e822d8 | ||
|
|
a7303349e0 | ||
|
|
10b3988449 | ||
|
|
bc876e1c64 | ||
|
|
1a8c36e92f | ||
|
|
aa027c2b8d | ||
|
|
8a8d9419d1 | ||
|
|
6e82bd6ada | ||
|
|
c9d80fc64f | ||
|
|
c9762fe73e | ||
|
|
41f45474b2 | ||
|
|
4313a7b00f | ||
|
|
3e4301a4cb | ||
|
|
6991239cc0 | ||
|
|
9655ceaaef | ||
|
|
b92b3acc1a | ||
|
|
226ccf8db7 | ||
|
|
4ffe4a4beb | ||
|
|
dbaa40a116 | ||
|
|
8ad78ae156 | ||
|
|
118a4dcde4 | ||
|
|
3e34d4b99a | ||
|
|
06ee78f67c | ||
|
|
be8eac8997 | ||
|
|
890579e228 | ||
|
|
ceb8bb1417 | ||
|
|
a06fe30a73 | ||
|
|
2bb423434c | ||
|
|
1bf5b9098f | ||
|
|
ed431414c2 | ||
|
|
0bbe93c26f | ||
|
|
d41d992798 | ||
|
|
881cc50cfd | ||
|
|
fb7be12a77 | ||
|
|
4e48ebc0cf | ||
|
|
ac12259cba | ||
|
|
99fbdcdf73 | ||
|
|
aaead6c866 | ||
|
|
d3a1685cb6 | ||
|
|
16ca9883eb | ||
|
|
2a0c8f25d3 | ||
|
|
e9691ba40e | ||
|
|
21edf56417 | ||
|
|
80a7cbaafe | ||
|
|
90b5e07681 | ||
|
|
e9de1fcf7b | ||
|
|
99759b6e7c | ||
|
|
a63cbf6841 | ||
|
|
311f538fd5 |
+3
-1
@@ -43,7 +43,9 @@ before_build:
|
||||
build_script:
|
||||
- cmake --build build_parallel
|
||||
- cmake --build build_serial
|
||||
- cmake --build build_serial --target exec
|
||||
|
||||
after_build:
|
||||
# - cmake --build build_parallel --target check
|
||||
- cmake --build build_serial --target check
|
||||
- cmake --build build_serial --target RUN_TESTS
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@ doc/CodeDocumentation
|
||||
*.dSYM
|
||||
.DS_Store
|
||||
|
||||
# Editor files
|
||||
.vscode
|
||||
|
||||
# Example and miniapp binaries and outputs
|
||||
|
||||
examples/ex[1-9]
|
||||
@@ -85,6 +88,7 @@ examples/gnuplot_ex20p.inp
|
||||
examples/ex22*.mesh
|
||||
examples/ex22*.sol
|
||||
examples/ex22p_*.*
|
||||
examples/exSBP*
|
||||
|
||||
examples/sundials/ex9
|
||||
examples/sundials/ex1[06]
|
||||
|
||||
@@ -205,6 +205,7 @@ install:
|
||||
else
|
||||
echo "Reusing cached hypre-2.10.0b/";
|
||||
fi;
|
||||
ln -s hypre-2.10.0b hypre;
|
||||
else
|
||||
echo "Serial build, not using hypre";
|
||||
fi
|
||||
|
||||
@@ -8,22 +8,21 @@
|
||||
http://mfem.org
|
||||
|
||||
|
||||
Version 4.0-RC1, Apr 11, 2019
|
||||
Version 4.0-RC2, Apr 24, 2019
|
||||
=============================
|
||||
|
||||
Requirements and Limitations
|
||||
----------------------------
|
||||
- This is a release candidate for mfem-4.0.
|
||||
- Use at your own risk -- not everything will work, the API may change.
|
||||
- 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.
|
||||
|
||||
- GPU-related limitations:
|
||||
* NVCC is not supported in the CMake build system yet.
|
||||
* Element batching is currently ignored.
|
||||
* 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.
|
||||
* FunctionCoefficients do not currently work on GPUs.
|
||||
are not supported yet. Element batching is currently ignored.
|
||||
* Partial assembly kernels are not implemented yet for simplices.
|
||||
|
||||
GPU support
|
||||
@@ -145,6 +144,10 @@ New and improved solvers and preconditioners
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- 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
|
||||
|
||||
+55
-3
@@ -86,6 +86,13 @@ include("${CMAKE_CURRENT_SOURCE_DIR}/config/XSDKDefaults.cmake")
|
||||
|
||||
# Enable languages.
|
||||
enable_language(CXX)
|
||||
if (MFEM_USE_CUDA)
|
||||
# MFEM_USE_CUDA requires CMake 3.8 or newer (for direct CUDA support)
|
||||
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||
enable_language(CUDA)
|
||||
message(STATUS "Using CUDA architecture: ${CUDA_ARCH}")
|
||||
endif()
|
||||
|
||||
if (XSDK_ENABLE_C)
|
||||
enable_language(C)
|
||||
endif()
|
||||
@@ -266,6 +273,32 @@ if (MFEM_USE_PUMI)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# CUDA
|
||||
if (MFEM_USE_CUDA)
|
||||
set(CMAKE_CUDA_STANDARD 11)
|
||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CUDA_EXTENSIONS OFF)
|
||||
set(CMAKE_CUDA_FLAGS "-arch=${CUDA_ARCH} --expt-extended-lambda"
|
||||
CACHE STRING "CUDA flags set for MFEM" FORCE)
|
||||
if (MFEM_USE_MPI)
|
||||
set(CUDA_CCBIN_COMPILER ${MPI_CXX_COMPILER})
|
||||
else()
|
||||
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
|
||||
if (MFEM_USE_OCCA)
|
||||
find_package(OCCA REQUIRED)
|
||||
endif()
|
||||
|
||||
# RAJA
|
||||
if (MFEM_USE_RAJA)
|
||||
find_package(RAJA REQUIRED)
|
||||
endif()
|
||||
|
||||
# MFEM_TIMER_TYPE
|
||||
if (NOT DEFINED MFEM_TIMER_TYPE)
|
||||
if (APPLE)
|
||||
@@ -291,7 +324,7 @@ endif()
|
||||
# be before SuiteSparse.
|
||||
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
|
||||
MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT GECKO GNUTLS NETCDF MPFR PUMI
|
||||
POSIXCLOCKS MFEMBacktrace ZLIB)
|
||||
POSIXCLOCKS MFEMBacktrace ZLIB OCCA RAJA)
|
||||
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
|
||||
set(TPL_LIBRARIES "")
|
||||
set(TPL_INCLUDE_DIRS "")
|
||||
@@ -327,6 +360,13 @@ set(MFEM_SOURCE_DIRS general linalg mesh fem)
|
||||
foreach(DIR IN LISTS MFEM_SOURCE_DIRS)
|
||||
add_subdirectory(${DIR})
|
||||
endforeach()
|
||||
|
||||
if (MFEM_USE_CUDA)
|
||||
foreach(file IN LISTS SOURCES)
|
||||
set_property(SOURCE ${file} PROPERTY LANGUAGE CUDA)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
add_subdirectory(config)
|
||||
set(MASTER_HEADERS
|
||||
${PROJECT_SOURCE_DIR}/mfem.hpp
|
||||
@@ -337,6 +377,11 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON CACHE BOOL "")
|
||||
set(CMAKE_INSTALL_RPATH "${_lib_path}" CACHE PATH "")
|
||||
set(CMAKE_INSTALL_NAME_DIR "${_lib_path}" CACHE PATH "")
|
||||
|
||||
set(MFEM_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
|
||||
"The MFEM source directory" FORCE)
|
||||
set(MFEM_INSTALL_DIR ${CMAKE_INSTALL_PREFIX} CACHE PATH
|
||||
"The MFEM install directory" FORCE)
|
||||
|
||||
# Declaring the library
|
||||
add_library(mfem ${SOURCES} ${HEADERS} ${MASTER_HEADERS})
|
||||
# message(STATUS "TPL_LIBRARIES = ${TPL_LIBRARIES}")
|
||||
@@ -434,12 +479,12 @@ endif()
|
||||
# Add 'check' target - quick test
|
||||
if (NOT MFEM_USE_MPI)
|
||||
add_custom_target(check
|
||||
${CMAKE_CTEST_COMMAND} -R '^ex1_ser' -C ${CMAKE_CFG_INTDIR}
|
||||
${CMAKE_CTEST_COMMAND} -R \"^ex1_ser\" -C ${CMAKE_CFG_INTDIR}
|
||||
USES_TERMINAL)
|
||||
add_dependencies(check ex1)
|
||||
else()
|
||||
add_custom_target(check
|
||||
${CMAKE_CTEST_COMMAND} -R '^ex1p' -C ${CMAKE_CFG_INTDIR}
|
||||
${CMAKE_CTEST_COMMAND} -R \"^ex1p\" -C ${CMAKE_CFG_INTDIR}
|
||||
USES_TERMINAL)
|
||||
add_dependencies(check ex1p)
|
||||
endif()
|
||||
@@ -484,6 +529,13 @@ install(DIRECTORY ${MFEM_SOURCE_DIRS}
|
||||
DESTINATION ${INSTALL_INCLUDE_DIR}/mfem
|
||||
FILES_MATCHING PATTERN "*.hpp")
|
||||
|
||||
# Install the okl files
|
||||
if (MFEM_USE_OCCA)
|
||||
install(DIRECTORY ${MFEM_SOURCE_DIRS}
|
||||
DESTINATION ${INSTALL_INCLUDE_DIR}/mfem
|
||||
FILES_MATCHING PATTERN "*.okl")
|
||||
endif()
|
||||
|
||||
# Install ${HEADERS}
|
||||
# ---
|
||||
# foreach (HDR ${HEADERS})
|
||||
|
||||
@@ -142,6 +142,16 @@ Origin](#developers-certificate-of-origin-11) at the end of this file.*
|
||||
+ [`HypreParMatrix`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreParMatrix.html) and [`HypreParVector`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreParVector.html)
|
||||
+ [`HypreSolver`](http://mfem.github.io/doxygen/html/classmfem_1_1HypreSolver.html) and other [hypre classes](http://mfem.github.io/doxygen/html/hypre_8hpp.html)
|
||||
|
||||
- GPU and multi-core CPU support is based on device kernels supporting different
|
||||
backends (CUDA, OCCA, RAJA, OpenMP, etc.) and an internal lightweight
|
||||
device/host memory manager.
|
||||
|
||||
- The main device-relevant classes and sources are:
|
||||
+ [`Device`](http://mfem.github.io/doxygen/html/device_8hpp.html)
|
||||
+ [`MemoryManager`](http://mfem.github.io/doxygen/html/mem_manager_8hpp.html)
|
||||
+ the [`MFEM_FORALL`](http://mfem.github.io/doxygen/html/forall_8hpp.html) macro
|
||||
+ the [`cuda.hpp`](http://mfem.github.io/doxygen/html/cuda_8hpp.html) and [`occa.hpp`](http://mfem.github.io/doxygen/html/occa_8hpp.html) files
|
||||
|
||||
- The `general/` directory contains C++ classes that serve as utilities for
|
||||
communication, error handling, arrays, (Boolean) tables, timing, etc.
|
||||
|
||||
|
||||
@@ -13,11 +13,17 @@ of MFEM is a (modern) C++ compiler, such as g++. The parallel version of MFEM
|
||||
requires an MPI C++ compiler, as well as the following external libraries:
|
||||
|
||||
- hypre (a library of high-performance preconditioners)
|
||||
http://www.llnl.gov/CASC/hypre
|
||||
https://github.com/hypre-space/hypre
|
||||
|
||||
- METIS (a family of multilevel partitioning algorithms)
|
||||
http://glaros.dtc.umn.edu/gkhome/metis/metis/overview
|
||||
|
||||
The hypre dependency can be downloaded as a tarball from GitHub or from the
|
||||
project webpage https://www.llnl.gov/casc/hypre. For example, the 2.16.0 release
|
||||
of hypre is available at
|
||||
|
||||
https://github.com/hypre-space/hypre/archive/v2.16.0.tar.gz
|
||||
|
||||
The METIS dependency can be disabled but that is not generally recommended, see
|
||||
the option MFEM_USE_METIS.
|
||||
|
||||
@@ -48,7 +54,7 @@ following package managers:
|
||||
|
||||
- Spack, https://github.com/spack/spack
|
||||
- OpenHPC, http://openhpc.community
|
||||
- Homebrew/Science, https://github.com/Homebrew/homebrew-science
|
||||
- Homebrew/Science, https://github.com/Homebrew/homebrew-science (deprecated)
|
||||
|
||||
We also recommend downloading and building the MFEM-based GLVis visualization
|
||||
tool which can be used to visualize the meshes and solution in MFEM's examples
|
||||
@@ -60,9 +66,9 @@ Serial build:
|
||||
make serial -j 4
|
||||
|
||||
Parallel build:
|
||||
(download hypre 2.10.0b and METIS 4 from above URLs)
|
||||
(download hypre and METIS 4 from above URLs)
|
||||
(build METIS 4 in ../metis-4.0 relative to mfem/)
|
||||
(build hypre 2.10.0b in ../hypre-2.10.0b relative to mfem/)
|
||||
(build hypre in ../hypre relative to mfem/)
|
||||
make parallel -j 4
|
||||
|
||||
CUDA build:
|
||||
@@ -87,13 +93,19 @@ Serial build:
|
||||
make -j 4 (assuming "UNIX Makefiles" generator)
|
||||
|
||||
Parallel build:
|
||||
(download hypre 2.10.0b and METIS 4 from above URLs)
|
||||
(download hypre and METIS 4 from above URLs)
|
||||
(build METIS 4 in ../metis-4.0 relative to mfem/)
|
||||
(build hypre 2.10.0b in ../hypre-2.10.0b relative to mfem/)
|
||||
(build hypre in ../hypre relative to mfem/)
|
||||
mkdir <mfem-build-dir> ; cd <mfem-build-dir>
|
||||
cmake <mfem-source-dir> -DMFEM_USE_MPI=YES
|
||||
make -j 4
|
||||
|
||||
CUDA build:
|
||||
(this build requires CMake 3.8 or newer)
|
||||
mkdir <mfem-build-dir> ; cd <mfem-build-dir>
|
||||
cmake <mfem-source-dir> -DMFEM_USE_CUDA=YES
|
||||
make -j 4
|
||||
|
||||
Example codes (serial/parallel, depending on the build):
|
||||
make examples -j 4
|
||||
|
||||
@@ -278,6 +290,7 @@ MFEM_THREAD_SAFE = YES/NO
|
||||
|
||||
MFEM_USE_LEGACY_OPENMP = YES/NO
|
||||
Enable (basic) experimental OpenMP support. Requires MFEM_THREAD_SAFE.
|
||||
This option is deprecated.
|
||||
|
||||
MFEM_USE_OPENMP = YES/NO
|
||||
Enable the OpenMP backend.
|
||||
@@ -393,7 +406,8 @@ MFEM_USE_PUMI = YES/NO
|
||||
|
||||
MFEM_USE_MM = YES/NO
|
||||
Enables support for the MFEM's memory manager (MM), which is required to
|
||||
support devices with different memory spaces.
|
||||
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
|
||||
@@ -406,13 +420,15 @@ MFEM_USE_CUDA = YES/NO
|
||||
MFEM_USE_RAJA = YES/NO
|
||||
Enable support for the RAJA performance portability layer in MFEM. RAJA
|
||||
provides a portable abstraction for loops, supporting different programming
|
||||
model backends. When using the RAJA CUDA backend, MFEM_USE_MM is required.
|
||||
model backends. When using RAJA built with CUDA support, CUDA support must be
|
||||
also enabled in MFEM, i.e. MFEM_USE_CUDA=YES must be set.
|
||||
|
||||
MFEM_USE_OCCA = YES/NO
|
||||
Enables support for the OCCA library in MFEM. OCCA is an open-source library
|
||||
which aims to make it easy to program different types of devices (e.g. CPU,
|
||||
GPU, FPGA) by providing an unified API for interacting with JIT-compiled
|
||||
backends. When using the OCCA CUDA backend, MFEM_USE_MM is required.
|
||||
backends. In order to use the OCCA CUDA backend, CUDA support must be enabled
|
||||
in MFEM as well, i.e. MFEM_USE_CUDA=YES must be set.
|
||||
|
||||
MFEM_BUILD_TAG = (any value)
|
||||
An optional tag to characterize the build. Exported to config/config.mk.
|
||||
@@ -435,7 +451,7 @@ directory and use the string @MFEM_DIR@, e.g. HYPRE_OPT = -I@MFEM_DIR@/../hypre.
|
||||
The specific libraries and their options are:
|
||||
|
||||
- HYPRE, required for the parallel build, i.e. when MFEM_USE_MPI = YES.
|
||||
URL: http://www.llnl.gov/CASC/hypre
|
||||
URL: https://github.com/hypre-space/hypre and https://www.llnl.gov/casc/hypre
|
||||
Options: HYPRE_OPT, HYPRE_LIB.
|
||||
|
||||
- METIS, used when MFEM_USE_METIS = YES. If using METIS 5, set
|
||||
@@ -645,6 +661,8 @@ Configuration variables (CMake)
|
||||
===============================
|
||||
See the configuration file config/defaults.cmake for the default settings.
|
||||
|
||||
Note: the option MFEM_USE_CUDA requires CMake version 3.8 or newer!
|
||||
|
||||
Non-standard CMake variables for compilers:
|
||||
CXX - If set, overwrite the auto-detected C++ compiler, serial build
|
||||
MPICXX - If set, overwrite the auto-detected MPI C++ compiler, parallel build
|
||||
@@ -675,9 +693,6 @@ MFEM_USE_NETCDF
|
||||
MFEM_USE_MPFR
|
||||
MFEM_USE_GZSTREAM
|
||||
MFEM_USE_PUMI
|
||||
|
||||
The following GNU make options are not supported with CMake yet:
|
||||
|
||||
MFEM_USE_CUDA
|
||||
MFEM_USE_OCCA
|
||||
MFEM_USE_RAJA
|
||||
@@ -728,6 +743,8 @@ The CMake build system adds auto-detection for the following packages/libraries:
|
||||
- LIBUNWIND
|
||||
- POSIXCLOCKS
|
||||
- PUMI
|
||||
- OCCA
|
||||
- RAJA
|
||||
|
||||
The following built-in CMake packages are also used:
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
http://mfem.org
|
||||
|
||||
MFEM is a modular parallel C++ library for finite element methods. Its goal is
|
||||
to enable the research and development of scalable finite element discretization
|
||||
and solver algorithms through general finite element abstractions, accurate and
|
||||
flexible visualization, and tight integration with the hypre library.
|
||||
to enable high-performance scalable finite element discretization research and
|
||||
application development on a wide variety of platforms, ranging from laptops to
|
||||
supercomputers.
|
||||
|
||||
* For building instructions, see the file INSTALL, or type "make help".
|
||||
|
||||
@@ -39,23 +39,24 @@ conforming and non-conforming (AMR) adaptive refinement. Arbitrary element
|
||||
transformations, allowing for high-order mesh elements with curved boundaries,
|
||||
are also supported.
|
||||
|
||||
MFEM is commonly used as a "finite element to linear algebra translator", since
|
||||
it can take a problem described in terms of finite element-type objects, and
|
||||
produce the corresponding linear algebra vectors and sparse matrices. In order
|
||||
to facilitate this, MFEM uses compressed sparse row (CSR) sparse matrix storage
|
||||
and includes simple smoothers and Krylov solvers, such as PCG, MINRES and GMRES,
|
||||
as well as support for sequential sparse direct solvers from the SuiteSparse
|
||||
When used as a "finite element to linear algebra translator", MFEM can take a
|
||||
problem described in terms of finite element-type objects, and produce the
|
||||
corresponding linear algebra vectors and fully or partially assembled operators,
|
||||
e.g. in the form of global sparse matrices or matrix-free operators. The library
|
||||
includes simple smoothers and Krylov solvers, such as PCG, MINRES and GMRES, as
|
||||
well as support for sequential sparse direct solvers from the SuiteSparse
|
||||
library. Nonlinear solvers (the Newton method), eigensolvers (LOBPCG), and
|
||||
several explicit and implicit Runge-Kutta time integrators are also available.
|
||||
|
||||
MFEM supports MPI-based parallelism throughout the library, and can readily be
|
||||
used as a scalable unstructured finite element problem generator. MFEM-based
|
||||
applications require minimal changes to transition from a serial to a
|
||||
high-performing parallel version of the code, where they can take advantage of
|
||||
the integrated scalable linear solvers from the hypre library. Comprehensive
|
||||
support for other external packages, e.g. PETSc and SUNDIALS is also included,
|
||||
giving access to many additional linear and nonlinear solvers, preconditioners,
|
||||
time integrators, etc.
|
||||
used as a scalable unstructured finite element problem generator. As of version
|
||||
4.0, MFEM offers initial support for GPU acceleration, and programming models,
|
||||
such as CUDA, OCCA, RAJA and OpenMP. MFEM-based applications require minimal
|
||||
changes to switch from a serial to a high-performing MPI-parallel version of the
|
||||
code, where they can take advantage of the integrated linear solvers from the
|
||||
hypre library. Comprehensive support for other external packages, e.g. PETSc
|
||||
and SUNDIALS is also included, giving access to many additional linear and
|
||||
nonlinear solvers, preconditioners, time integrators, etc.
|
||||
|
||||
For examples of using MFEM, see the examples/ and miniapps/ directories, as well
|
||||
as the OpenGL visualization tool GLVis which is available at http://glvis.org.
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
IF (NOT COMMAND PRINT_VAR)
|
||||
FUNCTION(PRINT_VAR VAR_NAME)
|
||||
MESSAGE("-- " "${VAR_NAME} = '${${VAR_NAME}}'")
|
||||
MESSAGE(STATUS "${VAR_NAME} = '${${VAR_NAME}}'")
|
||||
ENDFUNCTION()
|
||||
ENDIF()
|
||||
|
||||
@@ -166,14 +166,14 @@ IF (USE_XSDK_DEFAULTS)
|
||||
ENDIF()
|
||||
XSDK_HANDLE_LANG_DEFAULTS(Fortran FC "FFLAGS;FCFLAGS")
|
||||
ENDIF()
|
||||
|
||||
|
||||
# Set XSDK defaults for other CMake variables
|
||||
|
||||
|
||||
IF ("${BUILD_SHARED_LIBS}" STREQUAL "")
|
||||
MESSAGE("-- " "XSDK: Setting default BUILD_SHARED_LIBS=TRUE")
|
||||
SET(BUILD_SHARED_LIBS TRUE CACHE BOOL "Set by default in XSDK mode")
|
||||
ENDIF()
|
||||
|
||||
|
||||
IF ("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
MESSAGE("-- " "XSDK: Setting default CMAKE_BUILD_TYPE=DEBUG")
|
||||
SET(CMAKE_BUILD_TYPE DEBUG CACHE STRING "Set by default in XSDK mode")
|
||||
@@ -181,6 +181,13 @@ IF (USE_XSDK_DEFAULTS)
|
||||
|
||||
ENDIF()
|
||||
|
||||
|
||||
##################################################################################
|
||||
#
|
||||
# MFEM-specific additions: set TPL MFEM_USE_* defaults
|
||||
#
|
||||
##################################################################################
|
||||
|
||||
IF (DEFINED TPL_ENABLE_MPI)
|
||||
SET(MFEM_USE_MPI ${TPL_ENABLE_MPI} CACHE BOOL "Enable MPI parallel build" FORCE)
|
||||
ENDIF()
|
||||
@@ -252,3 +259,15 @@ ENDIF()
|
||||
IF (DEFINED TPL_ENABLE_PUMI)
|
||||
SET(MFEM_USE_PUMI ${TPL_ENABLE_PUMI} CACHE BOOL "Enable PUMI" FORCE)
|
||||
ENDIF()
|
||||
|
||||
IF (DEFINED TPL_ENABLE_CUDA)
|
||||
SET(MFEM_USE_CUDA ${TPL_ENABLE_CUDA} CACHE BOOL "Enable CUDA" FORCE)
|
||||
ENDIF()
|
||||
|
||||
IF (DEFINED TPL_ENABLE_OCCA)
|
||||
SET(MFEM_USE_OCCA ${TPL_ENABLE_OCCA} CACHE BOOL "Enable OCCA" FORCE)
|
||||
ENDIF()
|
||||
|
||||
IF (DEFINED TPL_ENABLE_RAJA)
|
||||
SET(MFEM_USE_RAJA ${TPL_ENABLE_RAJA} CACHE BOOL "Enable RAJA" FORCE)
|
||||
ENDIF()
|
||||
|
||||
@@ -41,6 +41,10 @@ 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@)
|
||||
|
||||
set(MFEM_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
|
||||
set(MFEM_CXX_FLAGS "@CMAKE_CXX_FLAGS@")
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
#define MFEM_VERSION_MINOR (((MFEM_VERSION)/100)%100)
|
||||
#define MFEM_VERSION_PATCH ((MFEM_VERSION)%100)
|
||||
|
||||
// MFEM source directory.
|
||||
#define MFEM_SOURCE_DIR "@MFEM_SOURCE_DIR@"
|
||||
|
||||
// MFEM install directory.
|
||||
#define MFEM_INSTALL_DIR "@MFEM_INSTALL_DIR@"
|
||||
|
||||
// Description of the git commit used to build MFEM.
|
||||
#cmakedefine MFEM_GIT_STRING "@MFEM_GIT_STRING@"
|
||||
|
||||
@@ -104,6 +110,19 @@
|
||||
// Enable MFEM functionality based on the PUMI library
|
||||
#cmakedefine MFEM_USE_PUMI
|
||||
|
||||
// Build the GPU/CUDA-enabled version of the MFEM library.
|
||||
// Requires a CUDA compiler (nvcc).
|
||||
#cmakedefine MFEM_USE_CUDA
|
||||
|
||||
// Enable MFEM functionality based on the RAJA library
|
||||
#cmakedefine MFEM_USE_RAJA
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# 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.
|
||||
|
||||
# Defines the following variables:
|
||||
# - OCCA_FOUND
|
||||
# - OCCA_LIBRARIES
|
||||
# - OCCA_INCLUDE_DIRS
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(OCCA OCCA OCCA_DIR "include" "occa.hpp" "lib" "occa"
|
||||
"Paths to headers required by OCCA." "Libraries required by OCCA.")
|
||||
@@ -0,0 +1,30 @@
|
||||
# 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.
|
||||
|
||||
# Defines the following variables:
|
||||
# - RAJA_FOUND
|
||||
# - RAJA_LIBRARIES
|
||||
# - RAJA_INCLUDE_DIRS
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(RAJA RAJA RAJA_DIR "include" "RAJA/RAJA.hpp" "lib" "RAJA"
|
||||
"Paths to headers required by RAJA." "Libraries required by RAJA.")
|
||||
|
||||
if (NOT RAJA_CONFIG_CMAKE)
|
||||
set(RAJA_CONFIG_CMAKE "${RAJA_DIR}/share/raja/cmake/raja-config.cmake")
|
||||
endif()
|
||||
if (EXISTS "${RAJA_CONFIG_CMAKE}")
|
||||
include("${RAJA_CONFIG_CMAKE}")
|
||||
if (ENABLE_CUDA AND NOT MFEM_USE_CUDA)
|
||||
message(FATAL_ERROR
|
||||
"RAJA is built with CUDA: MFEM_USE_CUDA=YES is required")
|
||||
endif()
|
||||
endif()
|
||||
@@ -232,10 +232,12 @@ function(mfem_find_package Name Prefix DirVar IncSuffixes Header LibSuffixes
|
||||
# If we have the TPL_ versions of _INCLUDE_DIRS and _LIBRARIES then set the
|
||||
# standard ${Prefix} versions
|
||||
if (TPL_${Prefix}_INCLUDE_DIRS)
|
||||
set(${Prefix}_INCLUDE_DIRS ${TPL_${Prefix}_INCLUDE_DIRS} CACHE STRING "TPL_${Prefix}_INCLUDE_DIRS was found." FORCE)
|
||||
set(${Prefix}_INCLUDE_DIRS ${TPL_${Prefix}_INCLUDE_DIRS} CACHE STRING
|
||||
"TPL_${Prefix}_INCLUDE_DIRS was found." FORCE)
|
||||
endif()
|
||||
if (TPL_${Prefix}_LIBRARIES)
|
||||
set(${Prefix}_LIBRARIES ${TPL_${Prefix}_LIBRARIES} CACHE STRING "TPL_${Prefix}_LIBRARIES was found." FORCE)
|
||||
set(${Prefix}_LIBRARIES ${TPL_${Prefix}_LIBRARIES} CACHE STRING
|
||||
"TPL_${Prefix}_LIBRARIES was found." FORCE)
|
||||
endif()
|
||||
|
||||
# Quick return
|
||||
@@ -718,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_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)
|
||||
@@ -726,6 +729,7 @@ function(mfem_export_mk_files)
|
||||
set(${var} NO)
|
||||
endif()
|
||||
endforeach()
|
||||
# TODO: Add support for MFEM_USE_CUDA=YES
|
||||
set(MFEM_CXX ${CMAKE_CXX_COMPILER})
|
||||
set(MFEM_CPPFLAGS "")
|
||||
string(STRIP "${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}"
|
||||
|
||||
@@ -56,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
|
||||
|
||||
+11
-1
@@ -42,6 +42,10 @@ 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)
|
||||
|
||||
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
|
||||
|
||||
@@ -59,13 +63,16 @@ option(MFEM_ENABLE_MINIAPPS "Build all of the miniapps" OFF)
|
||||
# set(CXX g++)
|
||||
# set(MPICXX mpicxx)
|
||||
|
||||
# Set the target CUDA architecture
|
||||
set(CUDA_ARCH "sm_60" CACHE STRING "Target CUDA architecture.")
|
||||
|
||||
set(MFEM_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
# The *_DIR paths below will be the first place searched for the corresponding
|
||||
# headers and library. If these fail, then standard cmake search is performed.
|
||||
# Note: if the variables are already in the cache, they are not overwritten.
|
||||
|
||||
set(HYPRE_DIR "${MFEM_DIR}/../hypre-2.10.0b/src/hypre" CACHE PATH
|
||||
set(HYPRE_DIR "${MFEM_DIR}/../hypre/src/hypre" CACHE PATH
|
||||
"Path to the hypre library.")
|
||||
# If hypre was compiled to depend on BLAS and LAPACK:
|
||||
# set(HYPRE_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
|
||||
@@ -154,6 +161,9 @@ set(Axom_REQUIRED_PACKAGES "Conduit/relay" CACHE STRING
|
||||
set(PUMI_DIR "${MFEM_DIR}/../pumi-2.1.0" CACHE STRING
|
||||
"Directory where PUMI is installed")
|
||||
|
||||
set(OCCA_DIR "${MFEM_DIR}/../occa" CACHE PATH "Path to OCCA")
|
||||
set(RAJA_DIR "${MFEM_DIR}/../raja" CACHE PATH "Path to RAJA")
|
||||
|
||||
set(BLAS_INCLUDE_DIRS "" CACHE STRING "Path to BLAS headers.")
|
||||
set(BLAS_LIBRARIES "" CACHE STRING "The BLAS library.")
|
||||
set(LAPACK_INCLUDE_DIRS "" CACHE STRING "Path to LAPACK headers.")
|
||||
|
||||
+5
-7
@@ -136,7 +136,7 @@ LIBUNWIND_OPT = -g
|
||||
LIBUNWIND_LIB = $(if $(NOTMAC),-lunwind -ldl,)
|
||||
|
||||
# HYPRE library configuration (needed to build the parallel version)
|
||||
HYPRE_DIR = @MFEM_DIR@/../hypre-2.10.0b/src/hypre
|
||||
HYPRE_DIR = @MFEM_DIR@/../hypre/src/hypre
|
||||
HYPRE_OPT = -I$(HYPRE_DIR)/include
|
||||
HYPRE_LIB = -L$(HYPRE_DIR)/lib -lHYPRE
|
||||
|
||||
@@ -300,19 +300,17 @@ PUMI_OPT = -I$(PUMI_DIR)/include
|
||||
PUMI_LIB = -L$(PUMI_DIR)/lib -lpumi -lcrv -lma -lmds -lapf -lpcu -lgmi -lparma\
|
||||
-llion -lmth -lapf_zoltan -lspr
|
||||
|
||||
# CUDA library configuration. Since we compile and link with nvcc (when CUDA is
|
||||
# enabled) we only need to explicitly link with the CUDA driver, libcuda.*,
|
||||
# which is usually in a system path.
|
||||
# CUDA library configuration (currently not needed)
|
||||
CUDA_OPT =
|
||||
CUDA_LIB = $(if $(NOTMAC),,-L/usr/local/cuda/lib) -lcuda
|
||||
CUDA_LIB =
|
||||
|
||||
# OCCA library configuration
|
||||
OCCA_DIR ?= @MFEM_DIR@/../occa
|
||||
OCCA_DIR = @MFEM_DIR@/../occa
|
||||
OCCA_OPT = -I$(OCCA_DIR)/include
|
||||
OCCA_LIB = $(XLINKER)-rpath,$(OCCA_DIR)/lib -L$(OCCA_DIR)/lib -locca
|
||||
|
||||
# RAJA library configuration
|
||||
RAJA_DIR ?= @MFEM_DIR@/../raja
|
||||
RAJA_DIR = @MFEM_DIR@/../raja
|
||||
RAJA_OPT = -I$(RAJA_DIR)/include
|
||||
ifdef CUB_DIR
|
||||
RAJA_OPT += -I$(CUB_DIR)
|
||||
|
||||
+20
-1
@@ -18,6 +18,8 @@ run_prefix=""
|
||||
run_vg="valgrind --leak-check=full --show-reachable=yes --track-origins=yes"
|
||||
run_suffix="-no-vis"
|
||||
skip_gen_meshes="yes"
|
||||
# filter-out device runs ("no") or non-device runs ("yes"):
|
||||
device_runs="no"
|
||||
cur_dir="${PWD}"
|
||||
mfem_dir="$(cd "$(dirname "$0")"/.. && pwd)"
|
||||
mfem_build_dir=""
|
||||
@@ -148,6 +150,11 @@ function extract_sample_runs()
|
||||
if [ "$skip_gen_meshes" == "yes" ]; then
|
||||
runs=`printf "%s" "$runs" | grep -v ".* -m .*\.gen"`
|
||||
fi
|
||||
if [ "$device_runs" == "yes" ]; then
|
||||
runs=`printf "%s" "$runs" | grep ".* -d .*"`
|
||||
else
|
||||
runs=`printf "%s" "$runs" | grep -v ".* -d .*"`
|
||||
fi
|
||||
IFS=$'\n'
|
||||
runs=(${runs})
|
||||
IFS="${old_IFS}"
|
||||
@@ -169,6 +176,9 @@ function help_message()
|
||||
-g <dir> <pattern>
|
||||
Specify explicitly a group (dir + file pattern) to run; This
|
||||
option can be used multiple times to define multiple groups
|
||||
-dev configure only sample runs using devices.
|
||||
To test with a parallel build, the parallel (-p|-par) option
|
||||
should be set first on the command line.
|
||||
-v Enable valgrind
|
||||
-o <dir> [${output_dir:-"<empty>: output goes to stdout"}]
|
||||
If not empty, save output to files inside <dir>
|
||||
@@ -253,7 +263,7 @@ case "$1" in
|
||||
-h|-help)
|
||||
opt_help="yes"
|
||||
;;
|
||||
-p|-parallel)
|
||||
-p|-par)
|
||||
mfem_config="MFEM_USE_MPI=YES MFEM_DEBUG=NO"
|
||||
;;
|
||||
-g)
|
||||
@@ -264,6 +274,11 @@ case "$1" in
|
||||
groups=("${groups[@]}" "${test_group}")
|
||||
shift 2
|
||||
;;
|
||||
-dev)
|
||||
device_runs="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"
|
||||
;;
|
||||
@@ -294,6 +309,10 @@ case "$1" in
|
||||
-n)
|
||||
run_prefix="echo"
|
||||
;;
|
||||
-*)
|
||||
echo "unknown option: '$1'"
|
||||
exit 1
|
||||
;;
|
||||
*=*)
|
||||
eval $1
|
||||
;;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,10 @@ namespace mfem {
|
||||
* - HypreParMatrix and HypreParVector
|
||||
* - HypreSolver and other \link hypre.hpp hypre classes\endlink
|
||||
*
|
||||
* <H3>Main GPU classes</H3>
|
||||
* - Device
|
||||
* - MemoryManager
|
||||
*
|
||||
* <H3>Example codes</H3>
|
||||
* - <a class="el" href="examples_2ex1_8cpp_source.html">Example 1</a>: nodal H1 FEM for the Laplace problem
|
||||
* - <a class="el" href="examples_2ex1p_8cpp_source.html">Example 1p</a>: parallel nodal H1 FEM for the Laplace problem
|
||||
|
||||
@@ -27,7 +27,6 @@ list(APPEND ALL_EXE_SRCS
|
||||
ex18.cpp
|
||||
ex19.cpp
|
||||
ex20.cpp
|
||||
ex21.cpp
|
||||
ex22.cpp
|
||||
)
|
||||
|
||||
@@ -53,7 +52,6 @@ if (MFEM_USE_MPI)
|
||||
ex18p.cpp
|
||||
ex19p.cpp
|
||||
ex20p.cpp
|
||||
ex21p.cpp
|
||||
ex22p.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
+6
-6
@@ -26,12 +26,12 @@
|
||||
// ex1 -m ../data/mobius-strip.mesh -o -1 -sc
|
||||
//
|
||||
// Device sample runs:
|
||||
// > ex1 -pa -d cuda
|
||||
// > ex1 -pa -d raja-cuda
|
||||
// > ex1 -pa -d occa-cuda
|
||||
// > ex1 -pa -d raja-omp
|
||||
// > ex1 -pa -d occa-omp
|
||||
// > ex1 -m ../data/beam-hex.mesh -pa -d cuda
|
||||
// ex1 -pa -d cuda
|
||||
// ex1 -pa -d raja-cuda
|
||||
// ex1 -pa -d occa-cuda
|
||||
// ex1 -pa -d raja-omp
|
||||
// ex1 -pa -d occa-omp
|
||||
// ex1 -m ../data/beam-hex.mesh -pa -d cuda
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define a
|
||||
// simple finite element discretization of the Laplace problem
|
||||
|
||||
+3
-3
@@ -26,9 +26,9 @@
|
||||
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh -o -1 -sc
|
||||
//
|
||||
// Device sample runs:
|
||||
// > mpirun -np 4 ex1p -pa -d cuda
|
||||
// > mpirun -np 4 ex1p -pa -d occa-cuda
|
||||
// > mpirun -np 4 ex1p -pa -d raja-omp
|
||||
// mpirun -np 4 ex1p -pa -d cuda
|
||||
// mpirun -np 4 ex1p -pa -d occa-cuda
|
||||
// mpirun -np 4 ex1p -pa -d raja-omp
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define a
|
||||
// simple finite element discretization of the Laplace problem
|
||||
|
||||
@@ -1,477 +0,0 @@
|
||||
// MFEM Example 21
|
||||
//
|
||||
// Compile with: make ex21
|
||||
//
|
||||
// Sample runs: ex21 -m ../data/inline-segment.mesh -o 3
|
||||
// ex21 -m ../data/inline-tri.mesh -o 3
|
||||
// ex21 -m ../data/inline-quad.mesh -o 3
|
||||
// ex21 -m ../data/inline-quad.mesh -o 3 -p 1
|
||||
// ex21 -m ../data/inline-quad.mesh -o 3 -p 2
|
||||
// ex21 -m ../data/inline-tet.mesh -o 2
|
||||
// ex21 -m ../data/inline-hex.mesh -o 2
|
||||
// ex21 -m ../data/inline-hex.mesh -o 2 -p 1
|
||||
// ex21 -m ../data/inline-hex.mesh -o 2 -p 2
|
||||
// ex21 -m ../data/star.mesh -o 2 -sigma 10.0
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define and
|
||||
// solve simple complex-valued linear systems. We implement three
|
||||
// variants of a damped harmonic oscillator:
|
||||
//
|
||||
// 1) A scalar H1 field
|
||||
// -Div(a Grad u) - omega^2 b u + i omega c u = 0
|
||||
//
|
||||
// 2) A vector H(Curl) field
|
||||
// Curl(a Curl u) - omega^2 b u + i omega c u = 0
|
||||
//
|
||||
// 3) A vector H(Div) field
|
||||
// -Grad(a Div u) - omega^2 b u + i omega c u = 0
|
||||
//
|
||||
// In each case the field is driven by a forced oscillation, with
|
||||
// angular frequency omega, imposed at the boundary or a portion
|
||||
// of the boundary.
|
||||
//
|
||||
// In electromagnetics the coefficients are typically named the
|
||||
// permeability, mu = 1/a, permittivity, epsilon = b, and
|
||||
// conductivity, sigma = c. The user can specify these constants
|
||||
// using either set of names.
|
||||
//
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
static double mu_ = 1.0;
|
||||
static double epsilon_ = 1.0;
|
||||
static double sigma_ = 20.0;
|
||||
static double omega_ = 10.0;
|
||||
|
||||
double u0_real_exact(const Vector &);
|
||||
double u0_imag_exact(const Vector &);
|
||||
|
||||
void u1_real_exact(const Vector &, Vector &);
|
||||
void u1_imag_exact(const Vector &, Vector &);
|
||||
|
||||
void u2_real_exact(const Vector &, Vector &);
|
||||
void u2_imag_exact(const Vector &, Vector &);
|
||||
|
||||
bool check_for_inline_mesh(const char * mesh_file);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../data/inline-quad.mesh";
|
||||
int ref_levels = 0;
|
||||
int order = 1;
|
||||
int prob = 0;
|
||||
double freq = -1.0;
|
||||
double a_coef = 0.0;
|
||||
bool visualization = 1;
|
||||
bool herm_conv = true;
|
||||
bool exact_sol = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&prob, "-p", "--problem-type",
|
||||
"Choose from 0: H_1, 1: H(Curl), or 2: H(Div) "
|
||||
"damped harmonic oscillator.");
|
||||
args.AddOption(&a_coef, "-a", "--stiffness-coef",
|
||||
"Stiffness coefficient (spring constant or 1/mu).");
|
||||
args.AddOption(&epsilon_, "-b", "--mass-coef",
|
||||
"Mass coefficient (or epsilon).");
|
||||
args.AddOption(&sigma_, "-c", "--damping-coef",
|
||||
"Damping coefficient (or sigma).");
|
||||
args.AddOption(&mu_, "-mu", "--permeability",
|
||||
"Permeability of free space (or 1/(spring constant)).");
|
||||
args.AddOption(&epsilon_, "-eps", "--permittivity",
|
||||
"Permittivity of free space (or mass constant).");
|
||||
args.AddOption(&sigma_, "-sigma", "--conductivity",
|
||||
"Conductivity (or damping constant).");
|
||||
args.AddOption(&freq, "-f", "--frequency",
|
||||
"Frequency (in Hz).");
|
||||
args.AddOption(&herm_conv, "-herm", "--hermitian", "-no-herm",
|
||||
"--no-hermitian", "Use convention for Hermitian operators.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
if ( a_coef != 0.0 )
|
||||
{
|
||||
mu_ = 1.0 / a_coef;
|
||||
}
|
||||
if ( freq > 0.0 )
|
||||
{
|
||||
omega_ = 2.0 * M_PI * freq;
|
||||
}
|
||||
|
||||
exact_sol = check_for_inline_mesh(mesh_file);
|
||||
if (exact_sol)
|
||||
{
|
||||
cout << "Identified an 'inline' mesh" << endl;
|
||||
}
|
||||
|
||||
ComplexOperator::Convention conv =
|
||||
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
|
||||
|
||||
// 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 resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement where the user specifies
|
||||
// the number of levels with the '-r' option.
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 4. Define a finite element space on the mesh. Here we use continuous
|
||||
// Lagrange, Nedelec, or Raviart-Thomas finite elements of the specified
|
||||
// order.
|
||||
if (dim == 1 && prob != 0 )
|
||||
{
|
||||
cout << "Switching to problem type 0, H1 basis functions, "
|
||||
<< "for 1 dimensional mesh." << endl;
|
||||
prob = 0;
|
||||
}
|
||||
|
||||
FiniteElementCollection *fec;
|
||||
switch (prob)
|
||||
{
|
||||
case 0: fec = new H1_FECollection(order, dim); break;
|
||||
case 1: fec = new ND_FECollection(order, dim); break;
|
||||
case 2: fec = new RT_FECollection(order - 1, dim); break;
|
||||
}
|
||||
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
|
||||
cout << "Number of finite element unknowns: " << fespace->GetTrueVSize()
|
||||
<< endl;
|
||||
|
||||
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined based on the type
|
||||
// of mesh and the problem type.
|
||||
Array<int> ess_tdof_list;
|
||||
Array<int> ess_bdr;
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
if (exact_sol)
|
||||
{
|
||||
switch (prob)
|
||||
{
|
||||
case 0: ess_bdr = 0; ess_bdr[0] = 1; break;
|
||||
default: ess_bdr = 1; ess_bdr[2] = 0; break;
|
||||
}
|
||||
}
|
||||
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.
|
||||
ComplexLinearForm b(fespace, conv);
|
||||
b.Vector::operator=(0.0);
|
||||
|
||||
// 7. Define the solution vector u as a finite element grid function
|
||||
// corresponding to fespace. Initialize u with initial guess of 1+0i
|
||||
// or the exact solution if it is known.
|
||||
ComplexGridFunction u(fespace);
|
||||
ComplexGridFunction * u_exact = NULL;
|
||||
if (exact_sol) { u_exact = new ComplexGridFunction(fespace); }
|
||||
|
||||
FunctionCoefficient u0_r(u0_real_exact);
|
||||
FunctionCoefficient u0_i(u0_imag_exact);
|
||||
VectorFunctionCoefficient u1_r(dim, u1_real_exact);
|
||||
VectorFunctionCoefficient u1_i(dim, u1_imag_exact);
|
||||
VectorFunctionCoefficient u2_r(dim, u2_real_exact);
|
||||
VectorFunctionCoefficient u2_i(dim, u2_imag_exact);
|
||||
|
||||
ConstantCoefficient zeroCoef(0.0);
|
||||
ConstantCoefficient oneCoef(1.0);
|
||||
|
||||
Vector zeroVec(dim); zeroVec = 0.0;
|
||||
Vector oneVec(dim); oneVec = 0.0; oneVec[(prob==2)?(dim-1):0] = 1.0;
|
||||
VectorConstantCoefficient zeroVecCoef(zeroVec);
|
||||
VectorConstantCoefficient oneVecCoef(oneVec);
|
||||
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
u.ProjectBdrCoefficient(oneCoef, zeroCoef, ess_bdr);
|
||||
if (exact_sol) { u_exact->ProjectCoefficient(u0_r, u0_i); }
|
||||
break;
|
||||
case 1:
|
||||
u.ProjectBdrCoefficientTangent(oneVecCoef, zeroVecCoef, ess_bdr);
|
||||
if (exact_sol) { u_exact->ProjectCoefficient(u1_r, u1_i); }
|
||||
break;
|
||||
case 2:
|
||||
u.ProjectBdrCoefficientNormal(oneVecCoef, zeroVecCoef, ess_bdr);
|
||||
if (exact_sol) { u_exact->ProjectCoefficient(u2_r, u2_i); }
|
||||
break;
|
||||
}
|
||||
|
||||
if (visualization && exact_sol)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock_r(vishost, visport);
|
||||
socketstream sol_sock_i(vishost, visport);
|
||||
sol_sock_r.precision(8);
|
||||
sol_sock_i.precision(8);
|
||||
sol_sock_r << "solution\n" << *mesh << u_exact->real()
|
||||
<< "window_title 'Exact Real Part'" << flush;
|
||||
sol_sock_i << "solution\n" << *mesh << u_exact->imag()
|
||||
<< "window_title 'Exact Imaginary Part'" << flush;
|
||||
}
|
||||
|
||||
// 8. Set up the sesquilinear form a(.,.) on the finite element
|
||||
// space corresponding to the damped harmonic oscillator operator
|
||||
// of the appropriate type:
|
||||
//
|
||||
// 0) A scalar H1 field
|
||||
// -Div(a Grad) - omega^2 b + i omega c
|
||||
//
|
||||
// 1) A vector H(Curl) field
|
||||
// Curl(a Curl) - omega^2 b + i omega c
|
||||
//
|
||||
// 2) A vector H(Div) field
|
||||
// -Grad(a Div) - omega^2 b + i omega c
|
||||
//
|
||||
ConstantCoefficient stiffnessCoef(1.0/mu_);
|
||||
ConstantCoefficient massCoef(-omega_ * omega_ * epsilon_);
|
||||
ConstantCoefficient lossCoef(omega_ * sigma_);
|
||||
ConstantCoefficient negMassCoef(omega_ * omega_ * epsilon_);
|
||||
|
||||
SesquilinearForm *a = new SesquilinearForm(fespace, conv);
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator(stiffnessCoef),
|
||||
NULL);
|
||||
a->AddDomainIntegrator(new MassIntegrator(massCoef),
|
||||
new MassIntegrator(lossCoef));
|
||||
break;
|
||||
case 1:
|
||||
a->AddDomainIntegrator(new CurlCurlIntegrator(stiffnessCoef),
|
||||
NULL);
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator(massCoef),
|
||||
new VectorFEMassIntegrator(lossCoef));
|
||||
break;
|
||||
case 2:
|
||||
a->AddDomainIntegrator(new DivDivIntegrator(stiffnessCoef),
|
||||
NULL);
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator(massCoef),
|
||||
new VectorFEMassIntegrator(lossCoef));
|
||||
break;
|
||||
}
|
||||
|
||||
// 9. Assemble the bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as:
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, etc.
|
||||
a->Assemble();
|
||||
|
||||
OperatorHandle A;
|
||||
Vector B, U;
|
||||
|
||||
a->FormLinearSystem(ess_tdof_list, u, b, A, U, B);
|
||||
u = 0.0;
|
||||
U = 0.0;
|
||||
|
||||
{
|
||||
ComplexSparseMatrix * Asp =
|
||||
dynamic_cast<ComplexSparseMatrix*>(A.Ptr());
|
||||
|
||||
cout << "Size of linear system: "
|
||||
<< 2 * Asp->real().Width() << endl << endl;
|
||||
}
|
||||
|
||||
// 10. Define and apply a GMRES solver for AU=B.
|
||||
{
|
||||
GMRESSolver gmres;
|
||||
gmres.SetOperator(*A.Ptr());
|
||||
gmres.SetRelTol(1e-12);
|
||||
gmres.SetMaxIter(1000);
|
||||
gmres.SetPrintLevel(1);
|
||||
gmres.Mult(B, U);
|
||||
}
|
||||
|
||||
// 11. Recover the solution as a finite element grid function and
|
||||
// compute the errors if the exact solution is known.
|
||||
a->RecoverFEMSolution(U, b, u);
|
||||
|
||||
if (exact_sol)
|
||||
{
|
||||
double err_r = -1.0;
|
||||
double err_i = -1.0;
|
||||
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
err_r = u.real().ComputeL2Error(u0_r);
|
||||
err_i = u.imag().ComputeL2Error(u0_i);
|
||||
break;
|
||||
case 1:
|
||||
err_r = u.real().ComputeL2Error(u1_r);
|
||||
err_i = u.imag().ComputeL2Error(u1_i);
|
||||
break;
|
||||
case 2:
|
||||
err_r = u.real().ComputeL2Error(u2_r);
|
||||
err_i = u.imag().ComputeL2Error(u2_i);
|
||||
break;
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
cout << "|| Re (u_h - u) ||_{L^2} = " << err_r << endl;
|
||||
cout << "|| Im (u_h - u) ||_{L^2} = " << err_i << endl;
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
// 12. Save the refined mesh and the solution. This output can be
|
||||
// viewed later using GLVis: "glvis -m mesh -g sol".
|
||||
{
|
||||
ofstream mesh_ofs("refined.mesh");
|
||||
mesh_ofs.precision(8);
|
||||
mesh->Print(mesh_ofs);
|
||||
|
||||
ofstream sol_r_ofs("sol_r.gf");
|
||||
ofstream sol_i_ofs("sol_i.gf");
|
||||
sol_r_ofs.precision(8);
|
||||
sol_i_ofs.precision(8);
|
||||
u.real().Save(sol_r_ofs);
|
||||
u.imag().Save(sol_i_ofs);
|
||||
}
|
||||
|
||||
// 13. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock_r(vishost, visport);
|
||||
socketstream sol_sock_i(vishost, visport);
|
||||
sol_sock_r.precision(8);
|
||||
sol_sock_i.precision(8);
|
||||
sol_sock_r << "solution\n" << *mesh << u.real()
|
||||
<< "window_title 'Comp Real Part'" << flush;
|
||||
sol_sock_i << "solution\n" << *mesh << u.imag()
|
||||
<< "window_title 'Comp Imaginary Part'" << flush;
|
||||
}
|
||||
if (visualization && exact_sol)
|
||||
{
|
||||
*u_exact -= u;
|
||||
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock_r(vishost, visport);
|
||||
socketstream sol_sock_i(vishost, visport);
|
||||
sol_sock_r.precision(8);
|
||||
sol_sock_i.precision(8);
|
||||
sol_sock_r << "solution\n" << *mesh << u_exact->real()
|
||||
<< "window_title 'Exact-Comp Real Part'" << flush;
|
||||
sol_sock_i << "solution\n" << *mesh << u_exact->imag()
|
||||
<< "window_title 'Exact-Comp Imaginary Part'" << flush;
|
||||
}
|
||||
if (visualization)
|
||||
{
|
||||
GridFunction u_t(fespace);
|
||||
u_t = u.real();
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *mesh << u_t
|
||||
<< "window_title 'Harmonic Solution (t = 0.0 T)'"
|
||||
<< "pause\n" << flush;
|
||||
|
||||
cout << "GLVis visualization paused."
|
||||
<< " Press space (in the GLVis window) to resume it.\n";
|
||||
int num_frames = 32;
|
||||
int i = 0;
|
||||
while (sol_sock)
|
||||
{
|
||||
double t = (double)(i % num_frames) / num_frames;
|
||||
ostringstream oss;
|
||||
oss << "Harmonic Solution (t = " << t << " T)";
|
||||
|
||||
add(cos( 2.0 * M_PI * t), u.real(),
|
||||
sin(-2.0 * M_PI * t), u.imag(), u_t);
|
||||
sol_sock << "solution\n" << *mesh << u_t
|
||||
<< "window_title '" << oss.str() << "'" << flush;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// 14. Free the used memory.
|
||||
delete a;
|
||||
delete u_exact;
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool check_for_inline_mesh(const char * mesh_file)
|
||||
{
|
||||
string file(mesh_file);
|
||||
size_t p0 = file.find_last_of("/");
|
||||
string s0 = file.substr((p0==string::npos)?0:(p0+1),7);
|
||||
return s0 == "inline-";
|
||||
}
|
||||
|
||||
complex<double> u0_exact(const Vector &x)
|
||||
{
|
||||
int dim = x.Size();
|
||||
complex<double> i(0.0, 1.0);
|
||||
complex<double> alpha = (epsilon_ * omega_ - i * sigma_);
|
||||
complex<double> kappa = std::sqrt(mu_ * omega_* alpha);
|
||||
return std::exp(-i * kappa * x[dim - 1]);
|
||||
}
|
||||
|
||||
double u0_real_exact(const Vector &x)
|
||||
{
|
||||
return u0_exact(x).real();
|
||||
}
|
||||
|
||||
double u0_imag_exact(const Vector &x)
|
||||
{
|
||||
return u0_exact(x).imag();
|
||||
}
|
||||
|
||||
void u1_real_exact(const Vector &x, Vector &v)
|
||||
{
|
||||
int dim = x.Size();
|
||||
v.SetSize(dim); v = 0.0; v[0] = u0_real_exact(x);
|
||||
}
|
||||
|
||||
void u1_imag_exact(const Vector &x, Vector &v)
|
||||
{
|
||||
int dim = x.Size();
|
||||
v.SetSize(dim); v = 0.0; v[0] = u0_imag_exact(x);
|
||||
}
|
||||
|
||||
void u2_real_exact(const Vector &x, Vector &v)
|
||||
{
|
||||
int dim = x.Size();
|
||||
v.SetSize(dim); v = 0.0; v[dim-1] = u0_real_exact(x);
|
||||
}
|
||||
|
||||
void u2_imag_exact(const Vector &x, Vector &v)
|
||||
{
|
||||
int dim = x.Size();
|
||||
v.SetSize(dim); v = 0.0; v[dim-1] = u0_imag_exact(x);
|
||||
}
|
||||
@@ -1,658 +0,0 @@
|
||||
// MFEM Example 21 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex21p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex21p -m ../data/inline-segment.mesh -o 3
|
||||
// mpirun -np 4 ex21p -m ../data/inline-tri.mesh -o 3
|
||||
// mpirun -np 4 ex21p -m ../data/inline-quad.mesh -o 3
|
||||
// mpirun -np 4 ex21p -m ../data/inline-quad.mesh -o 3 -p 1
|
||||
// mpirun -np 4 ex21p -m ../data/inline-quad.mesh -o 3 -p 2
|
||||
// mpirun -np 4 ex21p -m ../data/inline-tet.mesh -o 2
|
||||
// mpirun -np 4 ex21p -m ../data/inline-hex.mesh -o 2
|
||||
// mpirun -np 4 ex21p -m ../data/inline-hex.mesh -o 2 -p 1
|
||||
// mpirun -np 4 ex21p -m ../data/inline-hex.mesh -o 2 -p 2
|
||||
// mpirun -np 4 ex21p -m ../data/star.mesh -o 2 -sigma 10.0
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define and
|
||||
// solve simple complex-valued linear systems. We implement three
|
||||
// variants of a damped harmonic oscillator:
|
||||
//
|
||||
// 1) A scalar H1 field
|
||||
// -Div(a Grad u) - omega^2 b u + i omega c u = 0
|
||||
//
|
||||
// 2) A vector H(Curl) field
|
||||
// Curl(a Curl u) - omega^2 b u + i omega c u = 0
|
||||
//
|
||||
// 3) A vector H(Div) field
|
||||
// -Grad(a Div u) - omega^2 b u + i omega c u = 0
|
||||
//
|
||||
// In each case the field is driven by a forced oscillation, with
|
||||
// angular frequency omega, imposed at the boundary or a portion
|
||||
// of the boundary.
|
||||
//
|
||||
// In electromagnetics the coefficients are typically named the
|
||||
// permeability, mu = 1/a, permittivity, epsilon = b, and
|
||||
// conductivity, sigma = c. The user can specify these constants
|
||||
// using either set of names.
|
||||
//
|
||||
//#define MFEM_STRUMPACK_SRC
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "mfem.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
static double mu_ = 1.0;
|
||||
static double epsilon_ = 1.0;
|
||||
static double sigma_ = 20.0;
|
||||
static double omega_ = 10.0;
|
||||
|
||||
double u0_real_exact(const Vector &);
|
||||
double u0_imag_exact(const Vector &);
|
||||
|
||||
void u1_real_exact(const Vector &, Vector &);
|
||||
void u1_imag_exact(const Vector &, Vector &);
|
||||
|
||||
void u2_real_exact(const Vector &, Vector &);
|
||||
void u2_imag_exact(const Vector &, Vector &);
|
||||
|
||||
bool check_for_inline_mesh(const char * mesh_file);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm comm = MPI_COMM_WORLD;
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/inline-quad.mesh";
|
||||
int ser_ref_levels = 1;
|
||||
int par_ref_levels = 1;
|
||||
int order = 1;
|
||||
int prob = 0;
|
||||
double freq = -1.0;
|
||||
double a_coef = 0.0;
|
||||
bool visualization = 1;
|
||||
bool herm_conv = true;
|
||||
bool exact_sol = true;
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
bool strumpack = false;
|
||||
#endif
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
|
||||
"Number of times to refine the mesh uniformly in serial.");
|
||||
args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
|
||||
"Number of times to refine the mesh uniformly in parallel.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&prob, "-p", "--problem-type",
|
||||
"Choose from 0: H_1, 1: H(Curl), or 2: H(Div) "
|
||||
"damped harmonic oscillator.");
|
||||
args.AddOption(&a_coef, "-a", "--stiffness-coef",
|
||||
"Stiffness coefficient (spring constant or 1/mu).");
|
||||
args.AddOption(&epsilon_, "-b", "--mass-coef",
|
||||
"Mass coefficient (or epsilon).");
|
||||
args.AddOption(&sigma_, "-c", "--damping-coef",
|
||||
"Damping coefficient (or sigma).");
|
||||
args.AddOption(&mu_, "-mu", "--permeability",
|
||||
"Permeability of free space (or 1/(spring constant)).");
|
||||
args.AddOption(&epsilon_, "-eps", "--permittivity",
|
||||
"Permittivity of free space (or mass constant).");
|
||||
args.AddOption(&sigma_, "-sigma", "--conductivity",
|
||||
"Conductivity (or damping constant).");
|
||||
args.AddOption(&freq, "-f", "--frequency",
|
||||
"Frequency (in Hz).");
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
args.AddOption(&strumpack, "-strumpack", "--strumpack-solver",
|
||||
"-no-strumpack", "--no-strumpack-solver",
|
||||
"Use STRUMPACK's double complex linear solver.");
|
||||
#endif
|
||||
args.AddOption(&herm_conv, "-herm", "--hermitian", "-no-herm",
|
||||
"--no-hermitian", "Use convention for Hermitian operators.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
MPI_Finalize();
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
if ( a_coef != 0.0 )
|
||||
{
|
||||
mu_ = 1.0 / a_coef;
|
||||
}
|
||||
if ( freq > 0.0 )
|
||||
{
|
||||
omega_ = 2.0 * M_PI * freq;
|
||||
}
|
||||
|
||||
exact_sol = check_for_inline_mesh(mesh_file);
|
||||
if (myid == 0 && exact_sol)
|
||||
{
|
||||
cout << "Identified an 'inline' mesh" << endl;
|
||||
}
|
||||
|
||||
ComplexOperator::Convention conv =
|
||||
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
|
||||
|
||||
// 3. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 4. Refine the serial mesh on all processors to increase the resolution.
|
||||
for (int l = 0; l < ser_ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
for (int l = 0; l < par_ref_levels; l++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel
|
||||
// mesh. Here we use continuous Lagrange, Nedelec, or
|
||||
// Raviart-Thomas finite elements of the specified order.
|
||||
if (dim == 1 && prob != 0 )
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Switching to problem type 0, H1 basis functions, "
|
||||
<< "for 1 dimensional mesh." << endl;
|
||||
}
|
||||
prob = 0;
|
||||
}
|
||||
|
||||
FiniteElementCollection *fec;
|
||||
switch (prob)
|
||||
{
|
||||
case 0: fec = new H1_FECollection(order, dim); break;
|
||||
case 1: fec = new ND_FECollection(order, dim); break;
|
||||
case 2: fec = new RT_FECollection(order - 1, dim); break;
|
||||
}
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// based on the type of mesh and the problem type.
|
||||
Array<int> ess_tdof_list;
|
||||
Array<int> ess_bdr;
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
if (exact_sol)
|
||||
{
|
||||
switch (prob)
|
||||
{
|
||||
case 0: ess_bdr = 0; ess_bdr[0] = 1; break;
|
||||
default: ess_bdr = 1; ess_bdr[2] = 0; break;
|
||||
}
|
||||
}
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 8. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system.
|
||||
ParComplexLinearForm b(fespace, conv);
|
||||
b.Vector::operator=(0.0);
|
||||
|
||||
// 9. Define the solution vector u as a parallel finite element
|
||||
// grid function corresponding to fespace. Initialize u with
|
||||
// initial guess of 1+0i or the exact solution if it is known.
|
||||
ParComplexGridFunction u(fespace);
|
||||
ParComplexGridFunction * u_exact = NULL;
|
||||
if (exact_sol) { u_exact = new ParComplexGridFunction(fespace); }
|
||||
|
||||
FunctionCoefficient u0_r(u0_real_exact);
|
||||
FunctionCoefficient u0_i(u0_imag_exact);
|
||||
VectorFunctionCoefficient u1_r(dim, u1_real_exact);
|
||||
VectorFunctionCoefficient u1_i(dim, u1_imag_exact);
|
||||
VectorFunctionCoefficient u2_r(dim, u2_real_exact);
|
||||
VectorFunctionCoefficient u2_i(dim, u2_imag_exact);
|
||||
|
||||
ConstantCoefficient zeroCoef(0.0);
|
||||
ConstantCoefficient oneCoef(1.0);
|
||||
|
||||
Vector zeroVec(dim); zeroVec = 0.0;
|
||||
Vector oneVec(dim); oneVec = 0.0; oneVec[(prob==2)?(dim-1):0] = 1.0;
|
||||
VectorConstantCoefficient zeroVecCoef(zeroVec);
|
||||
VectorConstantCoefficient oneVecCoef(oneVec);
|
||||
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
u.ProjectBdrCoefficient(oneCoef, zeroCoef, ess_bdr);
|
||||
if (exact_sol) { u_exact->ProjectCoefficient(u0_r, u0_i); }
|
||||
break;
|
||||
case 1:
|
||||
u.ProjectBdrCoefficientTangent(oneVecCoef, zeroVecCoef, ess_bdr);
|
||||
if (exact_sol) { u_exact->ProjectCoefficient(u1_r, u1_i); }
|
||||
break;
|
||||
case 2:
|
||||
u.ProjectBdrCoefficientNormal(oneVecCoef, zeroVecCoef, ess_bdr);
|
||||
if (exact_sol) { u_exact->ProjectCoefficient(u2_r, u2_i); }
|
||||
break;
|
||||
}
|
||||
|
||||
if (visualization && exact_sol)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock_r(vishost, visport);
|
||||
socketstream sol_sock_i(vishost, visport);
|
||||
sol_sock_r << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock_r.precision(8);
|
||||
sol_sock_i.precision(8);
|
||||
sol_sock_r << "solution\n" << *pmesh << u_exact->real()
|
||||
<< "window_title 'Exact Real Part'" << flush;
|
||||
sol_sock_i << "solution\n" << *pmesh << u_exact->imag()
|
||||
<< "window_title 'Exact Imaginary Part'" << flush;
|
||||
}
|
||||
|
||||
// 10. Set up the parallel sesquilinear form a(.,.) on the finite element
|
||||
// space corresponding to the damped harmonic oscillator operator
|
||||
// of the appropriate type:
|
||||
//
|
||||
// 0) A scalar H1 field
|
||||
// -Div(a Grad) - omega^2 b + i omega c
|
||||
//
|
||||
// 1) A vector H(Curl) field
|
||||
// Curl(a Curl) - omega^2 b + i omega c
|
||||
//
|
||||
// 2) A vector H(Div) field
|
||||
// -Grad(a Div) - omega^2 b + i omega c
|
||||
//
|
||||
ConstantCoefficient stiffnessCoef(1.0/mu_);
|
||||
ConstantCoefficient massCoef(-omega_ * omega_ * epsilon_);
|
||||
ConstantCoefficient lossCoef(omega_ * sigma_);
|
||||
ConstantCoefficient negMassCoef(omega_ * omega_ * epsilon_);
|
||||
|
||||
ParSesquilinearForm *a = new ParSesquilinearForm(fespace, conv);
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator(stiffnessCoef),
|
||||
NULL);
|
||||
a->AddDomainIntegrator(new MassIntegrator(massCoef),
|
||||
new MassIntegrator(lossCoef));
|
||||
break;
|
||||
case 1:
|
||||
a->AddDomainIntegrator(new CurlCurlIntegrator(stiffnessCoef),
|
||||
NULL);
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator(massCoef),
|
||||
new VectorFEMassIntegrator(lossCoef));
|
||||
break;
|
||||
case 2:
|
||||
a->AddDomainIntegrator(new DivDivIntegrator(stiffnessCoef),
|
||||
NULL);
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator(massCoef),
|
||||
new VectorFEMassIntegrator(lossCoef));
|
||||
break;
|
||||
}
|
||||
|
||||
// 10a. Set up the parallel bilinear form for the preconditioner
|
||||
// corresponding to the appropriate operator if the STRUMPACK solver
|
||||
// has not been selected.
|
||||
//
|
||||
// 0) A scalar H1 field
|
||||
// -Div(a Grad) - omega^2 b + omega c
|
||||
//
|
||||
// 1) A vector H(Curl) field
|
||||
// Curl(a Curl) + omega^2 b + omega c
|
||||
//
|
||||
// 2) A vector H(Div) field
|
||||
// -Grad(a Div) - omega^2 b + omega c
|
||||
//
|
||||
ParBilinearForm *pcOp = NULL;
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
if (!strumpack)
|
||||
#endif
|
||||
{
|
||||
pcOp = new ParBilinearForm(fespace);
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
pcOp->AddDomainIntegrator(new DiffusionIntegrator(stiffnessCoef));
|
||||
pcOp->AddDomainIntegrator(new MassIntegrator(massCoef));
|
||||
pcOp->AddDomainIntegrator(new MassIntegrator(lossCoef));
|
||||
break;
|
||||
case 1:
|
||||
pcOp->AddDomainIntegrator(new CurlCurlIntegrator(stiffnessCoef));
|
||||
pcOp->AddDomainIntegrator(new VectorFEMassIntegrator(negMassCoef));
|
||||
pcOp->AddDomainIntegrator(new VectorFEMassIntegrator(lossCoef));
|
||||
break;
|
||||
case 2:
|
||||
pcOp->AddDomainIntegrator(new DivDivIntegrator(stiffnessCoef));
|
||||
pcOp->AddDomainIntegrator(new VectorFEMassIntegrator(massCoef));
|
||||
pcOp->AddDomainIntegrator(new VectorFEMassIntegrator(lossCoef));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, etc.
|
||||
a->Assemble();
|
||||
if (pcOp) { pcOp->Assemble(); }
|
||||
|
||||
OperatorHandle A;
|
||||
Vector B, U;
|
||||
|
||||
a->FormLinearSystem(ess_tdof_list, u, b, A, U, B);
|
||||
u = 0.0;
|
||||
U = 0.0;
|
||||
|
||||
OperatorHandle PCOp;
|
||||
if (pcOp) { pcOp->FormSystemMatrix(ess_tdof_list, PCOp); }
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
ComplexHypreParMatrix * Ahyp =
|
||||
dynamic_cast<ComplexHypreParMatrix*>(A.Ptr());
|
||||
|
||||
cout << "Size of linear system: "
|
||||
<< 2 * Ahyp->real().GetGlobalNumRows() << endl << endl;
|
||||
}
|
||||
|
||||
// 12. Define and apply a parallel FGMRES solver for AU=B with a
|
||||
// block diagonal preconditioner based on the appropriate multigrid
|
||||
// preconditioner from hypre or simply use STRUMPACK.
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
if (!strumpack)
|
||||
#endif
|
||||
{
|
||||
Array<HYPRE_Int> blockTrueOffsets;
|
||||
blockTrueOffsets.SetSize(3);
|
||||
blockTrueOffsets[0] = 0;
|
||||
blockTrueOffsets[1] = PCOp.Ptr()->Height();
|
||||
blockTrueOffsets[2] = PCOp.Ptr()->Height();
|
||||
blockTrueOffsets.PartialSum();
|
||||
|
||||
BlockDiagonalPreconditioner BDP(blockTrueOffsets);
|
||||
|
||||
Operator * pc_r = NULL;
|
||||
Operator * pc_i = NULL;
|
||||
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
pc_r =
|
||||
new HypreBoomerAMG(dynamic_cast<HypreParMatrix&>(*PCOp.Ptr()));
|
||||
pc_i = new ScaledOperator(pc_r,
|
||||
(conv == ComplexOperator::HERMITIAN) ?
|
||||
1.0:-1.0);
|
||||
break;
|
||||
case 1:
|
||||
pc_r = new HypreAMS(dynamic_cast<HypreParMatrix&>(*PCOp.Ptr()),
|
||||
fespace);
|
||||
pc_i = new ScaledOperator(pc_r,
|
||||
(conv == ComplexOperator::HERMITIAN) ?
|
||||
1.0:-1.0);
|
||||
break;
|
||||
case 2:
|
||||
if (dim == 2 )
|
||||
{
|
||||
pc_r = new HypreAMS(dynamic_cast<HypreParMatrix&>(*PCOp.Ptr()),
|
||||
fespace);
|
||||
}
|
||||
else
|
||||
{
|
||||
pc_r = new HypreADS(dynamic_cast<HypreParMatrix&>(*PCOp.Ptr()),
|
||||
fespace);
|
||||
}
|
||||
pc_i = new ScaledOperator(pc_r,
|
||||
(conv == ComplexOperator::HERMITIAN) ?
|
||||
1.0:-1.0);
|
||||
break;
|
||||
}
|
||||
BDP.SetDiagonalBlock(0, pc_r);
|
||||
BDP.SetDiagonalBlock(1, pc_i);
|
||||
BDP.owns_blocks = 0;
|
||||
|
||||
FGMRESSolver fgmres(MPI_COMM_WORLD);
|
||||
fgmres.SetPreconditioner(BDP);
|
||||
fgmres.SetOperator(*A.Ptr());
|
||||
fgmres.SetRelTol(1e-12);
|
||||
fgmres.SetMaxIter(1000);
|
||||
fgmres.SetPrintLevel(1);
|
||||
fgmres.Mult(B, U);
|
||||
}
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
else
|
||||
{
|
||||
ComplexHypreParMatrix * Ahyp =
|
||||
dynamic_cast<ComplexHypreParMatrix*>(A.Ptr());
|
||||
|
||||
STRUMPACKRowLocCmplxMatrix A_strmp(Ahyp->real(), Ahyp->imag());
|
||||
|
||||
STRUMPACKCmplxSolver strmp(argc, argv, comm);
|
||||
|
||||
strmp.SetPrintFactorStatistics(true);
|
||||
strmp.SetPrintSolveStatistics(true);
|
||||
// strmp.SetKrylovSolver(strumpack::KrylovSolver::AUTO); // core dump
|
||||
strmp.SetKrylovSolver(strumpack::KrylovSolver::DIRECT); // core dump
|
||||
// strmp.SetKrylovSolver(strumpack::KrylovSolver::REFINE); // core dump
|
||||
// strmp.SetKrylovSolver(strumpack::KrylovSolver::PREC_GMRES); // index out of range asserts from strumpack::DenseMatrix
|
||||
// strmp.SetKrylovSolver(strumpack::KrylovSolver::GMRES); // WORKS
|
||||
strmp.SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
|
||||
strmp.SetOperator(A_strmp);
|
||||
strmp.SetFromCommandLine();
|
||||
strmp.Mult(B, U);
|
||||
}
|
||||
#endif
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to U. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(U, b, u);
|
||||
|
||||
if (exact_sol)
|
||||
{
|
||||
double err_r = -1.0;
|
||||
double err_i = -1.0;
|
||||
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
err_r = u.real().ComputeL2Error(u0_r);
|
||||
err_i = u.imag().ComputeL2Error(u0_i);
|
||||
break;
|
||||
case 1:
|
||||
err_r = u.real().ComputeL2Error(u1_r);
|
||||
err_i = u.imag().ComputeL2Error(u1_i);
|
||||
break;
|
||||
case 2:
|
||||
err_r = u.real().ComputeL2Error(u2_r);
|
||||
err_i = u.imag().ComputeL2Error(u2_i);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( myid == 0 )
|
||||
{
|
||||
cout << endl;
|
||||
cout << "|| Re (u_h - u) ||_{L^2} = " << err_r << endl;
|
||||
cout << "|| Im (u_h - u) ||_{L^2} = " << err_i << endl;
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 14. Save the refined mesh and the solution in parallel. This output can be
|
||||
// viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
{
|
||||
ostringstream mesh_name, sol_r_name, sol_i_name;
|
||||
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
|
||||
sol_r_name << "sol_r." << setfill('0') << setw(6) << myid;
|
||||
sol_i_name << "sol_i." << setfill('0') << setw(6) << myid;
|
||||
|
||||
ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
mesh_ofs.precision(8);
|
||||
pmesh->Print(mesh_ofs);
|
||||
|
||||
ofstream sol_r_ofs(sol_r_name.str().c_str());
|
||||
ofstream sol_i_ofs(sol_i_name.str().c_str());
|
||||
sol_r_ofs.precision(8);
|
||||
sol_i_ofs.precision(8);
|
||||
u.real().Save(sol_r_ofs);
|
||||
u.imag().Save(sol_i_ofs);
|
||||
}
|
||||
|
||||
// 15. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock_r(vishost, visport);
|
||||
socketstream sol_sock_i(vishost, visport);
|
||||
sol_sock_r << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock_r.precision(8);
|
||||
sol_sock_i.precision(8);
|
||||
sol_sock_r << "solution\n" << *pmesh << u.real()
|
||||
<< "window_title 'Comp Real Part'" << flush;
|
||||
sol_sock_i << "solution\n" << *pmesh << u.imag()
|
||||
<< "window_title 'Comp Imaginary Part'" << flush;
|
||||
}
|
||||
if (visualization && exact_sol)
|
||||
{
|
||||
*u_exact -= u;
|
||||
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock_r(vishost, visport);
|
||||
socketstream sol_sock_i(vishost, visport);
|
||||
sol_sock_r << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock_r.precision(8);
|
||||
sol_sock_i.precision(8);
|
||||
sol_sock_r << "solution\n" << *pmesh << u_exact->real()
|
||||
<< "window_title 'Exact-Comp Real Part'" << flush;
|
||||
sol_sock_i << "solution\n" << *pmesh << u_exact->imag()
|
||||
<< "window_title 'Exact-Comp Imaginary Part'" << flush;
|
||||
}
|
||||
if (visualization)
|
||||
{
|
||||
ParGridFunction u_t(fespace);
|
||||
u_t = u.real();
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *pmesh << u_t
|
||||
<< "window_title 'Harmonic Solution (t = 0.0 T)'"
|
||||
<< "pause\n" << flush;
|
||||
if (myid == 0)
|
||||
cout << "GLVis visualization paused."
|
||||
<< " Press space (in the GLVis window) to resume it.\n";
|
||||
int num_frames = 32;
|
||||
int i = 0;
|
||||
while (sol_sock)
|
||||
{
|
||||
double t = (double)(i % num_frames) / num_frames;
|
||||
ostringstream oss;
|
||||
oss << "Harmonic Solution (t = " << t << " T)";
|
||||
|
||||
add(cos( 2.0 * M_PI * t), u.real(),
|
||||
sin(-2.0 * M_PI * t), u.imag(), u_t);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock << "solution\n" << *pmesh << u_t
|
||||
<< "window_title '" << oss.str() << "'" << flush;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// 16. Free the used memory.
|
||||
delete a;
|
||||
delete u_exact;
|
||||
delete pcOp;
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete pmesh;
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool check_for_inline_mesh(const char * mesh_file)
|
||||
{
|
||||
string file(mesh_file);
|
||||
size_t p0 = file.find_last_of("/");
|
||||
string s0 = file.substr((p0==string::npos)?0:(p0+1),7);
|
||||
return s0 == "inline-";
|
||||
}
|
||||
|
||||
complex<double> u0_exact(const Vector &x)
|
||||
{
|
||||
int dim = x.Size();
|
||||
complex<double> i(0.0, 1.0);
|
||||
complex<double> alpha = (epsilon_ * omega_ - i * sigma_);
|
||||
complex<double> kappa = std::sqrt(mu_ * omega_* alpha);
|
||||
return std::exp(-i * kappa * x[dim - 1]);
|
||||
}
|
||||
|
||||
double u0_real_exact(const Vector &x)
|
||||
{
|
||||
return u0_exact(x).real();
|
||||
}
|
||||
|
||||
double u0_imag_exact(const Vector &x)
|
||||
{
|
||||
return u0_exact(x).imag();
|
||||
}
|
||||
|
||||
void u1_real_exact(const Vector &x, Vector &v)
|
||||
{
|
||||
int dim = x.Size();
|
||||
v.SetSize(dim); v = 0.0; v[0] = u0_real_exact(x);
|
||||
}
|
||||
|
||||
void u1_imag_exact(const Vector &x, Vector &v)
|
||||
{
|
||||
int dim = x.Size();
|
||||
v.SetSize(dim); v = 0.0; v[0] = u0_imag_exact(x);
|
||||
}
|
||||
|
||||
void u2_real_exact(const Vector &x, Vector &v)
|
||||
{
|
||||
int dim = x.Size();
|
||||
v.SetSize(dim); v = 0.0; v[dim-1] = u0_real_exact(x);
|
||||
}
|
||||
|
||||
void u2_imag_exact(const Vector &x, Vector &v)
|
||||
{
|
||||
int dim = x.Size();
|
||||
v.SetSize(dim); v = 0.0; v[dim-1] = u0_imag_exact(x);
|
||||
}
|
||||
@@ -1,334 +0,0 @@
|
||||
// MFEM Example 3 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex3p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/escher.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/escher.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/fichera.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
|
||||
// mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
|
||||
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
|
||||
//
|
||||
// Description: This example code solves a simple electromagnetic diffusion
|
||||
// problem corresponding to the second order definite Maxwell
|
||||
// equation curl curl E + E = f with boundary condition
|
||||
// E x n = <given tangential field>. Here, we use a given exact
|
||||
// solution E and compute the corresponding r.h.s. f.
|
||||
// We discretize with Nedelec finite elements in 2D or 3D.
|
||||
//
|
||||
// The example demonstrates the use of H(curl) finite element
|
||||
// spaces with the curl-curl and the (vector finite element) mass
|
||||
// bilinear form, as well as the computation of discretization
|
||||
// error when the exact solution is known. Static condensation is
|
||||
// also illustrated.
|
||||
//
|
||||
// We recommend viewing examples 1-2 before viewing this example.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
// Exact solution, E, and r.h.s., f. See below for implementation.
|
||||
void E_exact(const Vector &, Vector &);
|
||||
void f_exact(const Vector &, Vector &);
|
||||
double freq = 1.0, kappa;
|
||||
int dim;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/beam-tet.mesh";
|
||||
int order = 1;
|
||||
bool static_cond = false;
|
||||
bool visualization = 1;
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
bool use_strumpack = false;
|
||||
#endif
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
|
||||
" solution.");
|
||||
args.AddOption(&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.");
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
args.AddOption(&use_strumpack, "-strumpack", "--strumpack-solver",
|
||||
"-no-strumpack", "--no-strumpack-solver",
|
||||
"Use STRUMPACK's double complex linear solver.");
|
||||
#endif
|
||||
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
MPI_Finalize();
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
kappa = freq * M_PI;
|
||||
|
||||
// 3. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
// 4. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement. We choose
|
||||
// 'ref_levels' to be the largest number that gives a final mesh with no
|
||||
// more than 1,000 elements.
|
||||
{
|
||||
int ref_levels =
|
||||
(int)floor(log(100000./mesh->GetNE())/log(2.)/dim);
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
|
||||
// meshes need to be reoriented before we can define high-order Nedelec
|
||||
// spaces on them.
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
{
|
||||
int par_ref_levels = 2;
|
||||
for (int l = 0; l < par_ref_levels; l++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Nedelec finite elements of the specified order.
|
||||
FiniteElementCollection *fec = new ND_FECollection(order, dim);
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes from the mesh as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 8. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system, which in this case is
|
||||
// (f,phi_i) where f is given by the function f_exact and phi_i are the
|
||||
// basis functions in the finite element fespace.
|
||||
VectorFunctionCoefficient f(sdim, f_exact);
|
||||
ParLinearForm *b = new ParLinearForm(fespace);
|
||||
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
|
||||
b->Assemble();
|
||||
|
||||
// 9. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x by projecting the exact
|
||||
// solution. Note that only values from the boundary edges will be used
|
||||
// when eliminating the non-homogeneous boundary condition to modify the
|
||||
// r.h.s. vector b.
|
||||
ParGridFunction x(fespace);
|
||||
VectorFunctionCoefficient E(sdim, E_exact);
|
||||
x.ProjectCoefficient(E);
|
||||
|
||||
// 10. Set up the parallel bilinear form corresponding to the EM diffusion
|
||||
// operator curl muinv curl + sigma I, by adding the curl-curl and the
|
||||
// mass domain integrators.
|
||||
Coefficient *muinv = new ConstantCoefficient(1.0);
|
||||
Coefficient *sigma = new ConstantCoefficient(-1.0);
|
||||
ParBilinearForm *a = new ParBilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
|
||||
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, static condensation, etc.
|
||||
if (static_cond) { a->EnableStaticCondensation(); }
|
||||
a->Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
|
||||
}
|
||||
|
||||
StopWatch chrono;
|
||||
chrono.Clear();
|
||||
chrono.Start();
|
||||
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
if (use_strumpack)
|
||||
{
|
||||
Operator * Arow = new STRUMPACKRowLocMatrix(A);
|
||||
|
||||
STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv, MPI_COMM_WORLD);
|
||||
strumpack->SetPrintFactorStatistics(true);
|
||||
strumpack->SetPrintSolveStatistics(false);
|
||||
strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
|
||||
strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
|
||||
// strumpack->SetMC64Job(strumpack::MC64Job::NONE);
|
||||
// strumpack->SetSymmetricPattern(true);
|
||||
strumpack->SetOperator(*Arow);
|
||||
strumpack->SetFromCommandLine();
|
||||
//Solver * precond = strumpack;
|
||||
|
||||
strumpack->Mult(B, X);
|
||||
|
||||
delete strumpack;
|
||||
delete Arow;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// 12. Define and apply a parallel PCG solver for AX=B with the AMS
|
||||
// preconditioner from hypre.
|
||||
ParFiniteElementSpace *prec_fespace =
|
||||
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
|
||||
HypreSolver *ams = new HypreAMS(A, prec_fespace);
|
||||
HyprePCG *pcg = new HyprePCG(A);
|
||||
pcg->SetTol(1e-12);
|
||||
pcg->SetMaxIter(500);
|
||||
pcg->SetPrintLevel(2);
|
||||
pcg->SetPreconditioner(*ams);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
delete pcg;
|
||||
delete ams;
|
||||
}
|
||||
|
||||
chrono.Stop();
|
||||
cout << "Solver time " << chrono.RealTime() << endl;
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 14. Compute and print the L^2 norm of the error.
|
||||
{
|
||||
double err = x.ComputeL2Error(E);
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "\n|| E_h - E ||_{L^2} = " << err << '\n' << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 15. Save the refined mesh and the solution in parallel. This output can
|
||||
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
{
|
||||
ostringstream mesh_name, sol_name;
|
||||
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
|
||||
sol_name << "sol." << setfill('0') << setw(6) << myid;
|
||||
|
||||
ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
mesh_ofs.precision(8);
|
||||
pmesh->Print(mesh_ofs);
|
||||
|
||||
ofstream sol_ofs(sol_name.str().c_str());
|
||||
sol_ofs.precision(8);
|
||||
x.Save(sol_ofs);
|
||||
}
|
||||
|
||||
// 16. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *pmesh << x << flush;
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
delete a;
|
||||
delete sigma;
|
||||
delete muinv;
|
||||
delete b;
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete pmesh;
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void E_exact(const Vector &x, Vector &E)
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
E(0) = sin(kappa * x(1));
|
||||
E(1) = sin(kappa * x(2));
|
||||
E(2) = sin(kappa * x(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
E(0) = sin(kappa * x(1));
|
||||
E(1) = sin(kappa * x(0));
|
||||
if (x.Size() == 3) { E(2) = 0.0; }
|
||||
}
|
||||
}
|
||||
|
||||
void f_exact(const Vector &x, Vector &f)
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
|
||||
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
|
||||
f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
|
||||
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
|
||||
if (x.Size() == 3) { f(2) = 0.0; }
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -16,9 +16,9 @@
|
||||
// ex6 -m ../data/amr-quad.mesh
|
||||
//
|
||||
// Device sample runs:
|
||||
// > ex6 -pa -d cuda
|
||||
// > ex6 -pa -d occa-cuda
|
||||
// > ex6 -pa -d raja-omp
|
||||
// ex6 -pa -d cuda
|
||||
// ex6 -pa -d occa-cuda
|
||||
// ex6 -pa -d raja-omp
|
||||
//
|
||||
// Description: This is a version of Example 1 with a simple adaptive mesh
|
||||
// refinement loop. The problem being solved is again the Laplace
|
||||
|
||||
+3
-3
@@ -16,9 +16,9 @@
|
||||
// mpirun -np 4 ex6p -m ../data/amr-quad.mesh
|
||||
//
|
||||
// Device sample runs:
|
||||
// > mpirun -np 4 ex6p -pa -d cuda
|
||||
// > mpirun -np 4 ex6p -pa -d occa-cuda
|
||||
// > mpirun -np 4 ex6p -pa -d raja-omp
|
||||
// mpirun -np 4 ex6p -pa -d cuda
|
||||
// mpirun -np 4 ex6p -pa -d occa-cuda
|
||||
// mpirun -np 4 ex6p -pa -d raja-omp
|
||||
//
|
||||
// Description: This is a version of Example 1 with a simple adaptive mesh
|
||||
// refinement loop. The problem being solved is again the Laplace
|
||||
|
||||
@@ -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 ex22
|
||||
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 ex22p
|
||||
ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex22p
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
EXAMPLES = $(SEQ_EXAMPLES)
|
||||
@@ -118,7 +118,7 @@ clean-build:
|
||||
clean-exec:
|
||||
@rm -f refined.mesh displaced.mesh mesh.* ex5.mesh
|
||||
@rm -rf Example5* Example9* Example15* Example16*
|
||||
@rm -f sphere_refined.* sol.* sol_u.* sol_p.* sol_r.* sol_i.*
|
||||
@rm -f sphere_refined.* sol.* sol_u.* sol_p.*
|
||||
@rm -f ex9.mesh ex9-mesh.* ex9-init.* ex9-final.*
|
||||
@rm -f deformed.* velocity.* elastic_energy.* mode_*
|
||||
@rm -f ex16.mesh ex16-mesh.* ex16-init.* ex16-final.*
|
||||
|
||||
@@ -588,14 +588,18 @@ void BilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x,
|
||||
Vector &b, OperatorHandle &A, Vector &X,
|
||||
Vector &B, int copy_interior)
|
||||
{
|
||||
const SparseMatrix *P = fes->GetConformingProlongation();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const SparseMatrix *P = fes->GetConformingProlongation();
|
||||
|
||||
FormSystemMatrix(ess_tdof_list, A);
|
||||
|
||||
// Transform the system and perform the elimination in B, based on the
|
||||
|
||||
@@ -415,6 +415,13 @@ void DiffusionIntegrator::AssembleElementMatrix
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -1,784 +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 "complex_fem.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
ComplexGridFunction::ComplexGridFunction(FiniteElementSpace *fes)
|
||||
: Vector(2*(fes->GetVSize()))
|
||||
{
|
||||
gfr_ = new GridFunction(fes, &data[0]);
|
||||
gfi_ = new GridFunction(fes, &data[fes->GetVSize()]);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexGridFunction::Update()
|
||||
{
|
||||
FiniteElementSpace * fes = gfr_->FESpace();
|
||||
|
||||
int vsize = fes->GetVSize();
|
||||
|
||||
const Operator *T = fes->GetUpdateOperator();
|
||||
if (T)
|
||||
{
|
||||
// Update the individual GridFunction objects. This will allocate
|
||||
// new data arrays for each GridFunction.
|
||||
gfr_->Update();
|
||||
gfi_->Update();
|
||||
|
||||
// Our data array now contains old data as well as being the wrong size
|
||||
// so reallocate it.
|
||||
this->SetSize(2 * vsize);
|
||||
|
||||
// Create temporary vectors which point to the new data array
|
||||
Vector gf_r(&data[0], vsize);
|
||||
Vector gf_i(&data[vsize], vsize);
|
||||
|
||||
// Copy the updated GridFunctions into the new data array
|
||||
gf_r = *gfr_;
|
||||
gf_i = *gfi_;
|
||||
|
||||
// Replace the individual data arrays with pointers into the new data array
|
||||
gfr_->NewDataAndSize(&data[0], vsize);
|
||||
gfi_->NewDataAndSize(&data[vsize], vsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The existing data will not be transferred to the new GridFunctions
|
||||
// so delete it a allocate a new array
|
||||
this->SetSize(2 * vsize);
|
||||
|
||||
// Point the individual GridFunctions to the new data array
|
||||
gfr_->NewDataAndSize(&data[0], vsize);
|
||||
gfi_->NewDataAndSize(&data[vsize], vsize);
|
||||
|
||||
// These updates will only set the proper 'sequence' value within
|
||||
// the individual GridFunction objects because their sizes are
|
||||
// already correct
|
||||
gfr_->Update();
|
||||
gfi_->Update();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ComplexGridFunction::ProjectCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff)
|
||||
{
|
||||
gfr_->ProjectCoefficient(real_coeff);
|
||||
gfi_->ProjectCoefficient(imag_coeff);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexGridFunction::ProjectCoefficient(VectorCoefficient &real_vcoeff,
|
||||
VectorCoefficient &imag_vcoeff)
|
||||
{
|
||||
gfr_->ProjectCoefficient(real_vcoeff);
|
||||
gfi_->ProjectCoefficient(imag_vcoeff);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexGridFunction::ProjectBdrCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
gfr_->ProjectBdrCoefficient(real_coeff, attr);
|
||||
gfi_->ProjectBdrCoefficient(imag_coeff, attr);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexGridFunction::ProjectBdrCoefficientNormal(VectorCoefficient &real_vcoeff,
|
||||
VectorCoefficient &imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
gfr_->ProjectBdrCoefficientNormal(real_vcoeff, attr);
|
||||
gfi_->ProjectBdrCoefficientNormal(imag_vcoeff, attr);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient
|
||||
&real_vcoeff,
|
||||
VectorCoefficient
|
||||
&imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
gfr_->ProjectBdrCoefficientTangent(real_vcoeff, attr);
|
||||
gfi_->ProjectBdrCoefficientTangent(imag_vcoeff, attr);
|
||||
}
|
||||
|
||||
|
||||
ComplexLinearForm::ComplexLinearForm(FiniteElementSpace *f,
|
||||
ComplexOperator::Convention convention)
|
||||
: Vector(2*(f->GetVSize())),
|
||||
conv_(convention)
|
||||
{
|
||||
lfr_ = new LinearForm(f, &data[0]);
|
||||
lfi_ = new LinearForm(f, &data[f->GetVSize()]);
|
||||
}
|
||||
|
||||
ComplexLinearForm::~ComplexLinearForm()
|
||||
{
|
||||
delete lfr_;
|
||||
delete lfi_;
|
||||
}
|
||||
|
||||
void
|
||||
ComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
|
||||
LinearFormIntegrator *lfi_imag)
|
||||
{
|
||||
if ( lfi_real ) { lfr_->AddDomainIntegrator(lfi_real); }
|
||||
if ( lfi_imag ) { lfi_->AddDomainIntegrator(lfi_imag); }
|
||||
}
|
||||
|
||||
void
|
||||
ComplexLinearForm::Update()
|
||||
{
|
||||
FiniteElementSpace *fes = lfr_->FESpace();
|
||||
|
||||
this->Update(fes);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexLinearForm::Update(FiniteElementSpace *fes)
|
||||
{
|
||||
int vsize = fes->GetVSize();
|
||||
SetSize(2 * vsize);
|
||||
|
||||
Vector lfr(&data[0], vsize);
|
||||
Vector lfi(&data[vsize], vsize);
|
||||
|
||||
lfr_->Update(fes, lfr, 0);
|
||||
lfi_->Update(fes, lfi, 0);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexLinearForm::Assemble()
|
||||
{
|
||||
lfr_->Assemble();
|
||||
lfi_->Assemble();
|
||||
if (conv_ == ComplexOperator::BLOCK_SYMMETRIC)
|
||||
{
|
||||
*lfi_ *= -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
complex<double>
|
||||
ComplexLinearForm::operator()(const ComplexGridFunction &gf) const
|
||||
{
|
||||
double s = (conv_ == ComplexOperator::HERMITIAN)?1.0:-1.0;
|
||||
return complex<double>((*lfr_)(gf.real()) - s * (*lfi_)(gf.imag()),
|
||||
(*lfr_)(gf.imag()) + s * (*lfi_)(gf.real()));
|
||||
}
|
||||
|
||||
|
||||
SesquilinearForm::SesquilinearForm(FiniteElementSpace *f,
|
||||
ComplexOperator::Convention convention)
|
||||
: conv_(convention),
|
||||
blfr_(new BilinearForm(f)),
|
||||
blfi_(new BilinearForm(f))
|
||||
{}
|
||||
|
||||
SesquilinearForm::~SesquilinearForm()
|
||||
{
|
||||
delete blfr_;
|
||||
delete blfi_;
|
||||
}
|
||||
|
||||
void SesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag)
|
||||
{
|
||||
if (bfi_real) { blfr_->AddDomainIntegrator(bfi_real); }
|
||||
if (bfi_imag) { blfi_->AddDomainIntegrator(bfi_imag); }
|
||||
}
|
||||
|
||||
void
|
||||
SesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag)
|
||||
{
|
||||
if (bfi_real) { blfr_->AddBoundaryIntegrator(bfi_real); }
|
||||
if (bfi_imag) { blfi_->AddBoundaryIntegrator(bfi_imag); }
|
||||
}
|
||||
|
||||
void
|
||||
SesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag,
|
||||
Array<int> & bdr_marker)
|
||||
{
|
||||
if (bfi_real) { blfr_->AddBoundaryIntegrator(bfi_real, bdr_marker); }
|
||||
if (bfi_imag) { blfi_->AddBoundaryIntegrator(bfi_imag, bdr_marker); }
|
||||
}
|
||||
|
||||
void
|
||||
SesquilinearForm::Assemble(int skip_zeros)
|
||||
{
|
||||
blfr_->Assemble(skip_zeros);
|
||||
blfi_->Assemble(skip_zeros);
|
||||
}
|
||||
|
||||
void
|
||||
SesquilinearForm::Finalize(int skip_zeros)
|
||||
{
|
||||
blfr_->Finalize(skip_zeros);
|
||||
blfi_->Finalize(skip_zeros);
|
||||
}
|
||||
|
||||
ComplexSparseMatrix *
|
||||
SesquilinearForm::AssembleCompSpMat()
|
||||
{
|
||||
return new ComplexSparseMatrix(&blfr_->SpMat(),
|
||||
&blfi_->SpMat(),
|
||||
false, false, conv_);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
Vector &x, Vector &b,
|
||||
OperatorHandle &A,
|
||||
Vector &X, Vector &B,
|
||||
int ci)
|
||||
{
|
||||
FiniteElementSpace * fes = blfr_->FESpace();
|
||||
|
||||
int vsize = fes->GetVSize();
|
||||
// int tvsize = pfes->GetTrueVSize();
|
||||
|
||||
double s = (conv_ == ComplexOperator::HERMITIAN)?1.0:-1.0;
|
||||
|
||||
// Allocate temporary vectors
|
||||
Vector b_0(vsize); b_0 = 0.0;
|
||||
// Vector B_0(tvsize); B_0 = 0.0;
|
||||
|
||||
// Extract the real and imaginary parts of the input vectors
|
||||
MFEM_ASSERT(x.Size() == 2 * vsize, "Input GridFunction of incorrect size!");
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
MFEM_ASSERT(b.Size() == 2 * vsize, "Input LinearForm of incorrect size!");
|
||||
Vector b_r(b.GetData(), vsize);
|
||||
Vector b_i(&(b.GetData())[vsize], vsize);
|
||||
b_i *= s;
|
||||
/*
|
||||
X.SetSize(2 * tvsize);
|
||||
Vector X_r(X.GetData(), tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
|
||||
B.SetSize(2 * tvsize);
|
||||
Vector B_r(B.GetData(), tvsize);
|
||||
Vector B_i(&(B.GetData())[tvsize], tvsize);
|
||||
*/
|
||||
SparseMatrix * A_r = new SparseMatrix;
|
||||
SparseMatrix * A_i = new SparseMatrix;
|
||||
Vector X_0, B_0;
|
||||
|
||||
b_0 = b_r;
|
||||
blfr_->FormLinearSystem(ess_tdof_list, x_r, b_r, *A_r, X_0, B_0, ci);
|
||||
|
||||
int tvsize = B_0.Size();
|
||||
X.SetSize(2 * tvsize);
|
||||
B.SetSize(2 * tvsize);
|
||||
Vector X_r(X.GetData(), tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
Vector B_r(B.GetData(), tvsize);
|
||||
Vector B_i(&(B.GetData())[tvsize], tvsize);
|
||||
X_r = X_0; B_r = B_0;
|
||||
|
||||
b_0 = 0.0;
|
||||
blfi_->FormLinearSystem(ess_tdof_list, x_i, b_0, *A_i, X_0, B_0, false);
|
||||
B_r -= B_0;
|
||||
|
||||
b_0 = b_i;
|
||||
blfr_->FormLinearSystem(ess_tdof_list, x_i, b_0, *A_r, X_0, B_0, ci);
|
||||
X_i = X_0; B_i = B_0;
|
||||
|
||||
b_0 = 0.0;
|
||||
blfi_->FormLinearSystem(ess_tdof_list, x_r, b_0, *A_i, X_0, B_0, false);
|
||||
B_i += B_0;
|
||||
|
||||
B_i *= s;
|
||||
b_i *= s;
|
||||
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
ComplexSparseMatrix * A_sp =
|
||||
new ComplexSparseMatrix(A_r, A_i, true, true, conv_);
|
||||
A.Reset<ComplexSparseMatrix>(A_sp, true);
|
||||
}
|
||||
|
||||
void
|
||||
SesquilinearForm::RecoverFEMSolution(const Vector &X, const Vector &b,
|
||||
Vector &x)
|
||||
{
|
||||
FiniteElementSpace * fes = blfr_->FESpace();
|
||||
|
||||
const SparseMatrix *P = fes->GetConformingProlongation();
|
||||
|
||||
int vsize = fes->GetVSize();
|
||||
int tvsize = X.Size() / 2;
|
||||
|
||||
Vector X_r(X.GetData(), tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
if (!P)
|
||||
{
|
||||
x = X;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Apply conforming prolongation
|
||||
P->Mult(X_r, x_r);
|
||||
P->Mult(X_i, x_i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SesquilinearForm::Update(FiniteElementSpace *nfes)
|
||||
{
|
||||
if ( blfr_ ) { blfr_->Update(nfes); }
|
||||
if ( blfi_ ) { blfi_->Update(nfes); }
|
||||
}
|
||||
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
ParComplexGridFunction::ParComplexGridFunction(ParFiniteElementSpace *pfes)
|
||||
: Vector(2*(pfes->GetVSize()))
|
||||
{
|
||||
pgfr_ = new ParGridFunction(pfes, &data[0]);
|
||||
pgfi_ = new ParGridFunction(pfes, &data[pfes->GetVSize()]);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::Update()
|
||||
{
|
||||
ParFiniteElementSpace * pfes = pgfr_->ParFESpace();
|
||||
|
||||
int vsize = pfes->GetVSize();
|
||||
|
||||
const Operator *T = pfes->GetUpdateOperator();
|
||||
if (T)
|
||||
{
|
||||
// Update the individual GridFunction objects. This will allocate
|
||||
// new data arrays for each GridFunction.
|
||||
pgfr_->Update();
|
||||
pgfi_->Update();
|
||||
|
||||
// Our data array now contains old data as well as being the wrong size
|
||||
// so reallocate it.
|
||||
this->SetSize(2 * vsize);
|
||||
|
||||
// Create temporary vectors which point to the new data array
|
||||
Vector gf_r(&data[0], vsize);
|
||||
Vector gf_i(&data[vsize], vsize);
|
||||
|
||||
// Copy the updated GridFunctions into the new data array
|
||||
gf_r = *pgfr_;
|
||||
gf_i = *pgfi_;
|
||||
|
||||
// Replace the individual data arrays with pointers into the new data array
|
||||
pgfr_->NewDataAndSize(&data[0], vsize);
|
||||
pgfi_->NewDataAndSize(&data[vsize], vsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The existing data will not be transferred to the new GridFunctions
|
||||
// so delete it a allocate a new array
|
||||
this->SetSize(2 * vsize);
|
||||
|
||||
// Point the individual GridFunctions to the new data array
|
||||
pgfr_->NewDataAndSize(&data[0], vsize);
|
||||
pgfi_->NewDataAndSize(&data[vsize], vsize);
|
||||
|
||||
// These updates will only set the proper 'sequence' value within
|
||||
// the individual GridFunction objects because their sizes are
|
||||
// already correct
|
||||
pgfr_->Update();
|
||||
pgfi_->Update();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::ProjectCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff)
|
||||
{
|
||||
pgfr_->ProjectCoefficient(real_coeff);
|
||||
pgfi_->ProjectCoefficient(imag_coeff);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::ProjectCoefficient(VectorCoefficient &real_vcoeff,
|
||||
VectorCoefficient &imag_vcoeff)
|
||||
{
|
||||
pgfr_->ProjectCoefficient(real_vcoeff);
|
||||
pgfi_->ProjectCoefficient(imag_vcoeff);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::ProjectBdrCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
pgfr_->ProjectBdrCoefficient(real_coeff, attr);
|
||||
pgfi_->ProjectBdrCoefficient(imag_coeff, attr);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::ProjectBdrCoefficientNormal(VectorCoefficient
|
||||
&real_vcoeff,
|
||||
VectorCoefficient
|
||||
&imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
pgfr_->ProjectBdrCoefficientNormal(real_vcoeff, attr);
|
||||
pgfi_->ProjectBdrCoefficientNormal(imag_vcoeff, attr);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient
|
||||
&real_vcoeff,
|
||||
VectorCoefficient
|
||||
&imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
pgfr_->ProjectBdrCoefficientTangent(real_vcoeff, attr);
|
||||
pgfi_->ProjectBdrCoefficientTangent(imag_vcoeff, attr);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::Distribute(const Vector *tv)
|
||||
{
|
||||
ParFiniteElementSpace * pfes = pgfr_->ParFESpace();
|
||||
HYPRE_Int size = pfes->GetTrueVSize();
|
||||
|
||||
double * tvd = tv->GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi(&tvd[size], size);
|
||||
|
||||
pgfr_->Distribute(tvr);
|
||||
pgfi_->Distribute(tvi);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::ParallelProject(Vector &tv) const
|
||||
{
|
||||
ParFiniteElementSpace * pfes = pgfr_->ParFESpace();
|
||||
HYPRE_Int size = pfes->GetTrueVSize();
|
||||
|
||||
double * tvd = tv.GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi(&tvd[size], size);
|
||||
|
||||
pgfr_->ParallelProject(tvr);
|
||||
pgfi_->ParallelProject(tvi);
|
||||
}
|
||||
|
||||
|
||||
ParComplexLinearForm::ParComplexLinearForm(ParFiniteElementSpace *pfes,
|
||||
ComplexOperator::Convention
|
||||
convention)
|
||||
: Vector(2*(pfes->GetVSize())),
|
||||
conv_(convention)
|
||||
{
|
||||
plfr_ = new ParLinearForm(pfes, &data[0]);
|
||||
plfi_ = new ParLinearForm(pfes, &data[pfes->GetVSize()]);
|
||||
|
||||
HYPRE_Int * tdof_offsets = pfes->GetTrueDofOffsets();
|
||||
|
||||
int n = (HYPRE_AssumedPartitionCheck()) ? 2 : pfes->GetNRanks();
|
||||
tdof_offsets_ = new HYPRE_Int[n+1];
|
||||
|
||||
for (int i=0; i<=n; i++)
|
||||
{
|
||||
tdof_offsets_[i] = 2 * tdof_offsets[i];
|
||||
}
|
||||
}
|
||||
|
||||
ParComplexLinearForm::~ParComplexLinearForm()
|
||||
{
|
||||
delete plfr_;
|
||||
delete plfi_;
|
||||
delete [] tdof_offsets_;
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
|
||||
LinearFormIntegrator *lfi_imag)
|
||||
{
|
||||
if ( lfi_real ) { plfr_->AddDomainIntegrator(lfi_real); }
|
||||
if ( lfi_imag ) { plfi_->AddDomainIntegrator(lfi_imag); }
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexLinearForm::Update(ParFiniteElementSpace *pf)
|
||||
{
|
||||
ParFiniteElementSpace *pfes = (pf!=NULL)?pf:plfr_->ParFESpace();
|
||||
int vsize = pfes->GetVSize();
|
||||
SetSize(2 * vsize);
|
||||
|
||||
Vector plfr(&data[0], vsize);
|
||||
Vector plfi(&data[vsize], vsize);
|
||||
|
||||
plfr_->Update(pfes, plfr, 0);
|
||||
plfi_->Update(pfes, plfi, 0);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexLinearForm::Assemble()
|
||||
{
|
||||
plfr_->Assemble();
|
||||
plfi_->Assemble();
|
||||
if (conv_ == ComplexOperator::BLOCK_SYMMETRIC)
|
||||
{
|
||||
*plfi_ *= -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexLinearForm::ParallelAssemble(Vector &tv)
|
||||
{
|
||||
HYPRE_Int size = plfr_->ParFESpace()->GetTrueVSize();
|
||||
|
||||
double * tvd = tv.GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi(&tvd[size], size);
|
||||
|
||||
plfr_->ParallelAssemble(tvr);
|
||||
plfi_->ParallelAssemble(tvi);
|
||||
}
|
||||
|
||||
HypreParVector *
|
||||
ParComplexLinearForm::ParallelAssemble()
|
||||
{
|
||||
const ParFiniteElementSpace * pfes = plfr_->ParFESpace();
|
||||
|
||||
HypreParVector * tv = new HypreParVector(pfes->GetComm(),
|
||||
2*(pfes->GlobalTrueVSize()),
|
||||
tdof_offsets_);
|
||||
|
||||
HYPRE_Int size = pfes->GetTrueVSize();
|
||||
|
||||
double * tvd = tv->GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi(&tvd[size], size);
|
||||
|
||||
plfr_->ParallelAssemble(tvr);
|
||||
plfi_->ParallelAssemble(tvi);
|
||||
|
||||
return tv;
|
||||
}
|
||||
|
||||
complex<double>
|
||||
ParComplexLinearForm::operator()(const ParComplexGridFunction &gf) const
|
||||
{
|
||||
double s = (conv_ == ComplexOperator::HERMITIAN)?1.0:-1.0;
|
||||
return complex<double>((*plfr_)(gf.real()) - s * (*plfi_)(gf.imag()),
|
||||
(*plfr_)(gf.imag()) + s * (*plfi_)(gf.real()));
|
||||
}
|
||||
|
||||
|
||||
ParSesquilinearForm::ParSesquilinearForm(ParFiniteElementSpace *pf,
|
||||
ComplexOperator::Convention
|
||||
convention)
|
||||
: conv_(convention),
|
||||
pblfr_(new ParBilinearForm(pf)),
|
||||
pblfi_(new ParBilinearForm(pf))
|
||||
{}
|
||||
|
||||
ParSesquilinearForm::~ParSesquilinearForm()
|
||||
{
|
||||
delete pblfr_;
|
||||
delete pblfi_;
|
||||
}
|
||||
|
||||
void ParSesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag)
|
||||
{
|
||||
if (bfi_real) { pblfr_->AddDomainIntegrator(bfi_real); }
|
||||
if (bfi_imag) { pblfi_->AddDomainIntegrator(bfi_imag); }
|
||||
}
|
||||
|
||||
void
|
||||
ParSesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag)
|
||||
{
|
||||
if (bfi_real) { pblfr_->AddBoundaryIntegrator(bfi_real); }
|
||||
if (bfi_imag) { pblfi_->AddBoundaryIntegrator(bfi_imag); }
|
||||
}
|
||||
|
||||
void
|
||||
ParSesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag,
|
||||
Array<int> & bdr_marker)
|
||||
{
|
||||
if (bfi_real) { pblfr_->AddBoundaryIntegrator(bfi_real, bdr_marker); }
|
||||
if (bfi_imag) { pblfi_->AddBoundaryIntegrator(bfi_imag, bdr_marker); }
|
||||
}
|
||||
|
||||
void
|
||||
ParSesquilinearForm::Assemble(int skip_zeros)
|
||||
{
|
||||
pblfr_->Assemble(skip_zeros);
|
||||
pblfi_->Assemble(skip_zeros);
|
||||
}
|
||||
|
||||
void
|
||||
ParSesquilinearForm::Finalize(int skip_zeros)
|
||||
{
|
||||
pblfr_->Finalize(skip_zeros);
|
||||
pblfi_->Finalize(skip_zeros);
|
||||
}
|
||||
|
||||
ComplexHypreParMatrix *
|
||||
ParSesquilinearForm::ParallelAssemble()
|
||||
{
|
||||
return new ComplexHypreParMatrix(pblfr_->ParallelAssemble(),
|
||||
pblfi_->ParallelAssemble(),
|
||||
true, true, conv_);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
Vector &x, Vector &b,
|
||||
OperatorHandle &A,
|
||||
Vector &X, Vector &B,
|
||||
int ci)
|
||||
{
|
||||
ParFiniteElementSpace * pfes = pblfr_->ParFESpace();
|
||||
|
||||
int tvs = pfes->TrueVSize();
|
||||
cout << "TrueVSize returns " << tvs << endl;
|
||||
cout << "GetVSize returns " << pfes->GetVSize() << endl;
|
||||
|
||||
int vsize = x.Size() / 2;
|
||||
// int vsize = pfes->GetVSize();
|
||||
// int tvsize = pfes->GetTrueVSize();
|
||||
|
||||
cout << "x.Size/2 returns " << vsize << endl;
|
||||
|
||||
double s = (conv_ == ComplexOperator::HERMITIAN)?1.0:-1.0;
|
||||
|
||||
// Allocate temporary vectors
|
||||
Vector b_0(vsize); b_0 = 0.0;
|
||||
// Vector B_0(tvsize); B_0 = 0.0;
|
||||
|
||||
// Extract the real and imaginary parts of the input vectors
|
||||
// MFEM_ASSERT(x.Size() == 2 * vsize, "Input GridFunction of incorrect size!");
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
MFEM_ASSERT(b.Size() == 2 * vsize, "Input LinearForm of incorrect size!");
|
||||
Vector b_r(b.GetData(), vsize);
|
||||
Vector b_i(&(b.GetData())[vsize], vsize);
|
||||
b_i *= s;
|
||||
/*
|
||||
X.SetSize(2 * tvsize);
|
||||
Vector X_r(X.GetData(), tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
|
||||
B.SetSize(2 * tvsize);
|
||||
Vector B_r(B.GetData(), tvsize);
|
||||
Vector B_i(&(B.GetData())[tvsize], tvsize);
|
||||
*/
|
||||
OperatorHandle A_r, A_i;
|
||||
Vector X_0, B_0;
|
||||
cout << "pblfr fls 1" << endl << flush;
|
||||
b_0 = b_r;
|
||||
pblfr_->FormLinearSystem(ess_tdof_list, x_r, b_0, A_r, X_0, B_0, ci);
|
||||
|
||||
int tvsize = B_0.Size();
|
||||
X.SetSize(2 * tvsize);
|
||||
B.SetSize(2 * tvsize);
|
||||
Vector X_r(X.GetData(), tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
Vector B_r(B.GetData(), tvsize);
|
||||
Vector B_i(&(B.GetData())[tvsize], tvsize);
|
||||
X_r = X_0; B_r = B_0;
|
||||
cout << "pblfi fls 1" << endl << flush;
|
||||
b_0 = 0.0;
|
||||
pblfi_->FormLinearSystem(ess_tdof_list, x_i, b_0, A_i, X_0, B_0, false);
|
||||
B_r -= B_0;
|
||||
cout << "pblfr fls 2" << endl << flush;
|
||||
b_0 = b_i;
|
||||
pblfr_->FormLinearSystem(ess_tdof_list, x_i, b_0, A_r, X_0, B_0, ci);
|
||||
X_i = X_0; B_i = B_0;
|
||||
cout << "pblfi fls 2" << endl << flush;
|
||||
b_0 = 0.0;
|
||||
pblfi_->FormLinearSystem(ess_tdof_list, x_r, b_0, A_i, X_0, B_0, false);
|
||||
B_i += B_0;
|
||||
|
||||
B_i *= s;
|
||||
b_i *= s;
|
||||
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
if ( A_r.Type() == Operator::Hypre_ParCSR &&
|
||||
A_i.Type() == Operator::Hypre_ParCSR )
|
||||
{
|
||||
ComplexHypreParMatrix * A_hyp =
|
||||
new ComplexHypreParMatrix(A_r.As<HypreParMatrix>(),
|
||||
A_i.As<HypreParMatrix>(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv_);
|
||||
A.Reset<ComplexHypreParMatrix>(A_hyp, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ComplexOperator * A_op =
|
||||
new ComplexOperator(A_r.As<Operator>(),
|
||||
A_i.As<Operator>(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv_);
|
||||
A.Reset<ComplexOperator>(A_op, true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParSesquilinearForm::RecoverFEMSolution(const Vector &X, const Vector &b,
|
||||
Vector &x)
|
||||
{
|
||||
ParFiniteElementSpace * pfes = pblfr_->ParFESpace();
|
||||
|
||||
const Operator &P = *pfes->GetProlongationMatrix();
|
||||
|
||||
int vsize = pfes->GetVSize();
|
||||
int tvsize = X.Size() / 2;
|
||||
|
||||
Vector X_r(X.GetData(), tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
// Apply conforming prolongation
|
||||
P.Mult(X_r, x_r);
|
||||
P.Mult(X_i, x_i);
|
||||
}
|
||||
|
||||
void
|
||||
ParSesquilinearForm::Update(FiniteElementSpace *nfes)
|
||||
{
|
||||
if ( pblfr_ ) { pblfr_->Update(nfes); }
|
||||
if ( pblfi_ ) { pblfi_->Update(nfes); }
|
||||
}
|
||||
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
}
|
||||
@@ -1,356 +0,0 @@
|
||||
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
||||
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
||||
// reserved. See file COPYRIGHT for details.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability see http://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU Lesser General Public License (as published by the Free
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
#ifndef MFEM_COMPLEX_FEM
|
||||
#define MFEM_COMPLEX_FEM
|
||||
|
||||
#include "../linalg/complex_operator.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "bilinearform.hpp"
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include "pgridfunc.hpp"
|
||||
#include "plinearform.hpp"
|
||||
#include "pbilinearform.hpp"
|
||||
#endif
|
||||
#include <complex>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Class for complex-valued grid function - Vector with associated FE space.
|
||||
class ComplexGridFunction : public Vector
|
||||
{
|
||||
private:
|
||||
|
||||
GridFunction * gfr_;
|
||||
GridFunction * gfi_;
|
||||
|
||||
protected:
|
||||
void Destroy() { delete gfr_; delete gfi_; }
|
||||
|
||||
public:
|
||||
|
||||
/* @brief Construct a ComplexGridFunction associated with the
|
||||
FiniteElementSpace @a *f. */
|
||||
ComplexGridFunction(FiniteElementSpace *f);
|
||||
|
||||
void Update();
|
||||
|
||||
/// Assign constant values to the ComplexGridFunction data.
|
||||
ComplexGridFunction &operator=(const std::complex<double> & value)
|
||||
{ *gfr_ = value.real(); *gfi_ = value.imag(); return *this; }
|
||||
|
||||
virtual void ProjectCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff);
|
||||
virtual void ProjectCoefficient(VectorCoefficient &real_vcoeff,
|
||||
VectorCoefficient &imag_vcoeff);
|
||||
|
||||
virtual void ProjectBdrCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff,
|
||||
Array<int> &attr);
|
||||
virtual void ProjectBdrCoefficientNormal(VectorCoefficient &real_coeff,
|
||||
VectorCoefficient &imag_coeff,
|
||||
Array<int> &attr);
|
||||
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &real_coeff,
|
||||
VectorCoefficient &imag_coeff,
|
||||
Array<int> &attr);
|
||||
|
||||
FiniteElementSpace *FESpace() { return gfr_->FESpace(); }
|
||||
const FiniteElementSpace *FESpace() const { return gfr_->FESpace(); }
|
||||
|
||||
GridFunction & real() { return *gfr_; }
|
||||
GridFunction & imag() { return *gfi_; }
|
||||
const GridFunction & real() const { return *gfr_; }
|
||||
const GridFunction & imag() const { return *gfi_; }
|
||||
|
||||
/// Destroys grid function.
|
||||
virtual ~ComplexGridFunction() { Destroy(); }
|
||||
|
||||
};
|
||||
|
||||
class ComplexLinearForm : public Vector
|
||||
{
|
||||
private:
|
||||
ComplexOperator::Convention conv_;
|
||||
|
||||
protected:
|
||||
LinearForm * lfr_;
|
||||
LinearForm * lfi_;
|
||||
|
||||
// HYPRE_Int * tdof_offsets_;
|
||||
|
||||
public:
|
||||
|
||||
ComplexLinearForm(FiniteElementSpace *fes,
|
||||
ComplexOperator::Convention
|
||||
convention = ComplexOperator::HERMITIAN);
|
||||
|
||||
virtual ~ComplexLinearForm();
|
||||
|
||||
/// Adds new Domain Integrator.
|
||||
void AddDomainIntegrator(LinearFormIntegrator *lfi_real,
|
||||
LinearFormIntegrator *lfi_imag);
|
||||
|
||||
FiniteElementSpace *FESpace() const { return lfr_->FESpace(); }
|
||||
|
||||
LinearForm & real() { return *lfr_; }
|
||||
LinearForm & imag() { return *lfi_; }
|
||||
const LinearForm & real() const { return *lfr_; }
|
||||
const LinearForm & imag() const { return *lfi_; }
|
||||
|
||||
void Update();
|
||||
void Update(FiniteElementSpace *f);
|
||||
|
||||
/// Assembles the linear form i.e. sums over all domain/bdr integrators.
|
||||
void Assemble();
|
||||
|
||||
std::complex<double> operator()(const ComplexGridFunction &gf) const;
|
||||
|
||||
};
|
||||
|
||||
// Class for sesquilinear form
|
||||
class SesquilinearForm
|
||||
{
|
||||
private:
|
||||
ComplexOperator::Convention conv_;
|
||||
|
||||
//protected:
|
||||
BilinearForm *blfr_;
|
||||
BilinearForm *blfi_;
|
||||
|
||||
public:
|
||||
SesquilinearForm(FiniteElementSpace *fes,
|
||||
ComplexOperator::Convention
|
||||
convention = ComplexOperator::HERMITIAN);
|
||||
|
||||
ComplexOperator::Convention GetConvention() const { return conv_; }
|
||||
void SetConvention(const ComplexOperator::Convention &
|
||||
convention) { conv_ = convention; }
|
||||
|
||||
BilinearForm & real() { return *blfr_; }
|
||||
BilinearForm & imag() { return *blfi_; }
|
||||
const BilinearForm & real() const { return *blfr_; }
|
||||
const BilinearForm & imag() const { return *blfi_; }
|
||||
|
||||
/// Adds new Domain Integrator.
|
||||
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag);
|
||||
|
||||
/// Adds new Boundary Integrator.
|
||||
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag);
|
||||
|
||||
/// Adds new Boundary Integrator, restricted to specific boundary attributes.
|
||||
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag,
|
||||
Array<int> &bdr_marker);
|
||||
|
||||
/// Assemble the local matrix
|
||||
void Assemble(int skip_zeros = 1);
|
||||
|
||||
/// Finalizes the matrix initialization.
|
||||
void Finalize(int skip_zeros = 1);
|
||||
|
||||
/// Returns the matrix assembled on the true dofs, i.e. P^t A P.
|
||||
/** The returned matrix has to be deleted by the caller. */
|
||||
ComplexSparseMatrix *AssembleCompSpMat();
|
||||
|
||||
/// Return the parallel FE space associated with the ParBilinearForm.
|
||||
FiniteElementSpace *FESpace() const { return blfr_->FESpace(); }
|
||||
|
||||
void FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x, Vector &b,
|
||||
OperatorHandle &A, Vector &X, Vector &B,
|
||||
int copy_interior = 0);
|
||||
|
||||
/** Call this method after solving a linear system constructed using the
|
||||
FormLinearSystem method to recover the solution as a ParGridFunction-size
|
||||
vector in x. Use the same arguments as in the FormLinearSystem call. */
|
||||
virtual void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x);
|
||||
|
||||
virtual void Update(FiniteElementSpace *nfes = NULL);
|
||||
|
||||
virtual ~SesquilinearForm();
|
||||
};
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
/// Class for complex-valued grid function - Vector with associated FE space.
|
||||
class ParComplexGridFunction : public Vector
|
||||
{
|
||||
private:
|
||||
|
||||
ParGridFunction * pgfr_;
|
||||
ParGridFunction * pgfi_;
|
||||
|
||||
protected:
|
||||
void Destroy() { delete pgfr_; delete pgfi_; }
|
||||
|
||||
public:
|
||||
|
||||
/* @brief Construct a ParComplexGridFunction associated with the
|
||||
ParFiniteElementSpace @a *f. */
|
||||
ParComplexGridFunction(ParFiniteElementSpace *pf);
|
||||
|
||||
void Update();
|
||||
|
||||
/// Assign constant values to the ParComplexGridFunction data.
|
||||
ParComplexGridFunction &operator=(const std::complex<double> & value)
|
||||
{ *pgfr_ = value.real(); *pgfi_ = value.imag(); return *this; }
|
||||
|
||||
virtual void ProjectCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff);
|
||||
virtual void ProjectCoefficient(VectorCoefficient &real_vcoeff,
|
||||
VectorCoefficient &imag_vcoeff);
|
||||
|
||||
virtual void ProjectBdrCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff,
|
||||
Array<int> &attr);
|
||||
virtual void ProjectBdrCoefficientNormal(VectorCoefficient &real_coeff,
|
||||
VectorCoefficient &imag_coeff,
|
||||
Array<int> &attr);
|
||||
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &real_coeff,
|
||||
VectorCoefficient &imag_coeff,
|
||||
Array<int> &attr);
|
||||
|
||||
void Distribute(const Vector *tv);
|
||||
void Distribute(const Vector &tv) { Distribute(&tv); }
|
||||
|
||||
/// Returns the vector restricted to the true dofs.
|
||||
void ParallelProject(Vector &tv) const;
|
||||
|
||||
FiniteElementSpace *FESpace() { return pgfr_->FESpace(); }
|
||||
const FiniteElementSpace *FESpace() const { return pgfr_->FESpace(); }
|
||||
|
||||
ParGridFunction & real() { return *pgfr_; }
|
||||
ParGridFunction & imag() { return *pgfi_; }
|
||||
const ParGridFunction & real() const { return *pgfr_; }
|
||||
const ParGridFunction & imag() const { return *pgfi_; }
|
||||
|
||||
/// Destroys grid function.
|
||||
virtual ~ParComplexGridFunction() { Destroy(); }
|
||||
|
||||
};
|
||||
|
||||
class ParComplexLinearForm : public Vector
|
||||
{
|
||||
private:
|
||||
ComplexOperator::Convention conv_;
|
||||
|
||||
protected:
|
||||
ParLinearForm * plfr_;
|
||||
ParLinearForm * plfi_;
|
||||
|
||||
HYPRE_Int * tdof_offsets_;
|
||||
|
||||
public:
|
||||
|
||||
ParComplexLinearForm(ParFiniteElementSpace *pf,
|
||||
ComplexOperator::Convention
|
||||
convention = ComplexOperator::HERMITIAN);
|
||||
|
||||
virtual ~ParComplexLinearForm();
|
||||
|
||||
/// Adds new Domain Integrator.
|
||||
void AddDomainIntegrator(LinearFormIntegrator *lfi_real,
|
||||
LinearFormIntegrator *lfi_imag);
|
||||
|
||||
ParFiniteElementSpace *ParFESpace() const { return plfr_->ParFESpace(); }
|
||||
|
||||
ParLinearForm & real() { return *plfr_; }
|
||||
ParLinearForm & imag() { return *plfi_; }
|
||||
const ParLinearForm & real() const { return *plfr_; }
|
||||
const ParLinearForm & imag() const { return *plfi_; }
|
||||
|
||||
void Update(ParFiniteElementSpace *pf = NULL);
|
||||
|
||||
/// Assembles the linear form i.e. sums over all domain/bdr integrators.
|
||||
void Assemble();
|
||||
|
||||
/// Assemble the vector on the true dofs, i.e. P^t v.
|
||||
void ParallelAssemble(Vector &tv);
|
||||
|
||||
/// Returns the vector assembled on the true dofs, i.e. P^t v.
|
||||
HypreParVector *ParallelAssemble();
|
||||
|
||||
std::complex<double> operator()(const ParComplexGridFunction &gf) const;
|
||||
|
||||
};
|
||||
|
||||
// Class for parallel sesquilinear form
|
||||
class ParSesquilinearForm
|
||||
{
|
||||
private:
|
||||
ComplexOperator::Convention conv_;
|
||||
|
||||
//protected:
|
||||
ParBilinearForm *pblfr_;
|
||||
ParBilinearForm *pblfi_;
|
||||
|
||||
public:
|
||||
ParSesquilinearForm(ParFiniteElementSpace *pf,
|
||||
ComplexOperator::Convention
|
||||
convention = ComplexOperator::HERMITIAN);
|
||||
|
||||
ComplexOperator::Convention GetConvention() const { return conv_; }
|
||||
void SetConvention(const ComplexOperator::Convention &
|
||||
convention) { conv_ = convention; }
|
||||
|
||||
ParBilinearForm & real() { return *pblfr_; }
|
||||
ParBilinearForm & imag() { return *pblfi_; }
|
||||
const ParBilinearForm & real() const { return *pblfr_; }
|
||||
const ParBilinearForm & imag() const { return *pblfi_; }
|
||||
|
||||
/// Adds new Domain Integrator.
|
||||
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag);
|
||||
|
||||
/// Adds new Boundary Integrator.
|
||||
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag);
|
||||
|
||||
/// Adds new Boundary Integrator, restricted to specific boundary attributes.
|
||||
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
|
||||
BilinearFormIntegrator *bfi_imag,
|
||||
Array<int> &bdr_marker);
|
||||
|
||||
/// Assemble the local matrix
|
||||
void Assemble(int skip_zeros = 1);
|
||||
|
||||
/// Finalizes the matrix initialization.
|
||||
void Finalize(int skip_zeros = 1);
|
||||
|
||||
/// Returns the matrix assembled on the true dofs, i.e. P^t A P.
|
||||
/** The returned matrix has to be deleted by the caller. */
|
||||
ComplexHypreParMatrix *ParallelAssemble();
|
||||
|
||||
/// Return the parallel FE space associated with the ParBilinearForm.
|
||||
ParFiniteElementSpace *ParFESpace() const { return pblfr_->ParFESpace(); }
|
||||
|
||||
void FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x, Vector &b,
|
||||
OperatorHandle &A, Vector &X, Vector &B,
|
||||
int copy_interior = 0);
|
||||
|
||||
/** Call this method after solving a linear system constructed using the
|
||||
FormLinearSystem method to recover the solution as a ParGridFunction-size
|
||||
vector in x. Use the same arguments as in the FormLinearSystem call. */
|
||||
virtual void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x);
|
||||
|
||||
virtual void Update(FiniteElementSpace *nfes = NULL);
|
||||
|
||||
virtual ~ParSesquilinearForm();
|
||||
};
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
}
|
||||
|
||||
#endif // MFEM_COMPLEX_FEM
|
||||
+370
@@ -11845,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
|
||||
|
||||
|
||||
+41
-1
@@ -19,6 +19,7 @@
|
||||
#include "geom.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -126,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
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2819,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};
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "fe_coll.hpp"
|
||||
#include "eltrans.hpp"
|
||||
#include "coefficient.hpp"
|
||||
#include "complex_fem.hpp"
|
||||
#include "lininteg.hpp"
|
||||
#include "nonlininteg.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
|
||||
+8
-1
@@ -2310,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);
|
||||
|
||||
@@ -81,15 +81,6 @@ public:
|
||||
Update(FiniteElementSpace *, Vector &, int). */
|
||||
LinearForm() { fes = NULL; extern_lfs = 0; }
|
||||
|
||||
/// Construct a LinearForm using previously allocated array @a data.
|
||||
/** The LinearForm does not assume ownership of @a data which is assumed to
|
||||
be of size at least `f->GetVSize()`. Similar to the Vector constructor
|
||||
for externally allocated array, the pointer @a data can be NULL. The data
|
||||
array can be replaced later using the method SetData().
|
||||
*/
|
||||
LinearForm(FiniteElementSpace *f, double *data) : Vector(data, f->GetVSize())
|
||||
{ fes = f; }
|
||||
|
||||
/// 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
|
||||
have the same size.
|
||||
|
||||
+10
-3
@@ -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++)
|
||||
|
||||
@@ -45,16 +45,6 @@ public:
|
||||
/** The pointer @a pf is not owned by the newly constructed object. */
|
||||
ParLinearForm(ParFiniteElementSpace *pf) : LinearForm(pf) { pfes = pf; }
|
||||
|
||||
/// Construct a ParLinearForm using previously allocated array @a data.
|
||||
/** The ParLinearForm does not assume ownership of @a data which is assumed
|
||||
to be of size at least `pf->GetVSize()`. Similar to the LinearForm and
|
||||
Vector constructors for externally allocated array, the pointer @a data
|
||||
can be NULL. The data array can be replaced later using the method
|
||||
SetData().
|
||||
*/
|
||||
ParLinearForm(ParFiniteElementSpace *pf, double *data) :
|
||||
LinearForm(pf, data), pfes(pf) { }
|
||||
|
||||
/** @brief Create a ParLinearForm on the ParFiniteElementSpace @a *pf, using
|
||||
the same integrators as the ParLinearForm @a *plf.
|
||||
|
||||
|
||||
+23
-39
@@ -10,17 +10,27 @@
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
#include "cuda.hpp"
|
||||
#include "globals.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
#ifdef MFEM_USE_CUDA
|
||||
void mfem_cuda_error(cudaError_t err, const char *expr, const char *func,
|
||||
const char *file, int line)
|
||||
{
|
||||
mfem::err << "CUDA error: (" << expr << ") failed with error:\n --> "
|
||||
<< cudaGetErrorString(err)
|
||||
<< "\n ... in function: " << func
|
||||
<< "\n ... in file: " << file << ':' << line << '\n';
|
||||
mfem_error();
|
||||
}
|
||||
#endif
|
||||
|
||||
void* CuMemAlloc(void** dptr, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (CUDA_SUCCESS != ::cuMemAlloc((CUdeviceptr*)dptr, bytes))
|
||||
{
|
||||
mfem_error("Error in CuMemAlloc");
|
||||
}
|
||||
MFEM_CUDA_CHECK(cudaMalloc(dptr, bytes));
|
||||
#endif
|
||||
return *dptr;
|
||||
}
|
||||
@@ -28,10 +38,7 @@ void* CuMemAlloc(void** dptr, size_t bytes)
|
||||
void* CuMemFree(void *dptr)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (CUDA_SUCCESS != ::cuMemFree((CUdeviceptr)dptr))
|
||||
{
|
||||
mfem_error("Error in CuMemFree");
|
||||
}
|
||||
MFEM_CUDA_CHECK(cudaFree(dptr));
|
||||
#endif
|
||||
return dptr;
|
||||
}
|
||||
@@ -39,22 +46,15 @@ void* CuMemFree(void *dptr)
|
||||
void* CuMemcpyHtoD(void* dst, const void* src, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (CUDA_SUCCESS != ::cuMemcpyHtoD((CUdeviceptr)dst, src, bytes))
|
||||
{
|
||||
mfem_error("Error in CuMemcpyHtoD");
|
||||
}
|
||||
MFEM_CUDA_CHECK(cudaMemcpy(dst, src, bytes, cudaMemcpyHostToDevice));
|
||||
#endif
|
||||
return dst;
|
||||
}
|
||||
|
||||
void* CuMemcpyHtoDAsync(void* dst, const void* src, size_t bytes, void *s)
|
||||
void* CuMemcpyHtoDAsync(void* dst, const void* src, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (CUDA_SUCCESS !=
|
||||
::cuMemcpyHtoDAsync((CUdeviceptr)dst, src, bytes, (CUstream)s))
|
||||
{
|
||||
mfem_error("Error in CuMemcpyHtoDAsync");
|
||||
}
|
||||
MFEM_CUDA_CHECK(cudaMemcpyAsync(dst, src, bytes, cudaMemcpyHostToDevice));
|
||||
#endif
|
||||
return dst;
|
||||
}
|
||||
@@ -62,24 +62,15 @@ void* CuMemcpyHtoDAsync(void* dst, const void* src, size_t bytes, void *s)
|
||||
void* CuMemcpyDtoD(void* dst, void* src, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (CUDA_SUCCESS !=
|
||||
::cuMemcpyDtoD((CUdeviceptr)dst, (CUdeviceptr)src, bytes))
|
||||
{
|
||||
mfem_error("Error in CuMemcpyDtoD");
|
||||
}
|
||||
MFEM_CUDA_CHECK(cudaMemcpy(dst, src, bytes, cudaMemcpyDeviceToDevice));
|
||||
#endif
|
||||
return dst;
|
||||
}
|
||||
|
||||
void* CuMemcpyDtoDAsync(void* dst, void* src, size_t bytes, void *s)
|
||||
void* CuMemcpyDtoDAsync(void* dst, void* src, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (CUDA_SUCCESS !=
|
||||
::cuMemcpyDtoDAsync((CUdeviceptr)dst, (CUdeviceptr)src,
|
||||
bytes, (CUstream)s))
|
||||
{
|
||||
mfem_error("Error in CuMemcpyDtoDAsync");
|
||||
}
|
||||
MFEM_CUDA_CHECK(cudaMemcpyAsync(dst, src, bytes, cudaMemcpyDeviceToDevice));
|
||||
#endif
|
||||
return dst;
|
||||
}
|
||||
@@ -87,10 +78,7 @@ void* CuMemcpyDtoDAsync(void* dst, void* src, size_t bytes, void *s)
|
||||
void* CuMemcpyDtoH(void *dst, void *src, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (CUDA_SUCCESS != ::cuMemcpyDtoH(dst, (CUdeviceptr)src, bytes))
|
||||
{
|
||||
mfem_error("Error in CuMemcpyDtoH");
|
||||
}
|
||||
MFEM_CUDA_CHECK(cudaMemcpy(dst, src, bytes, cudaMemcpyDeviceToHost));
|
||||
#endif
|
||||
return dst;
|
||||
}
|
||||
@@ -98,11 +86,7 @@ void* CuMemcpyDtoH(void *dst, void *src, size_t bytes)
|
||||
void* CuMemcpyDtoHAsync(void* dst, void* src, size_t bytes, void *s)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (CUDA_SUCCESS !=
|
||||
::cuMemcpyDtoHAsync(dst, (CUdeviceptr)src, bytes, (CUstream)s))
|
||||
{
|
||||
mfem_error("Error in CuMemcpyDtoHAsync");
|
||||
}
|
||||
MFEM_CUDA_CHECK(cudaMemcpyAsync(dst, src, bytes, cudaMemcpyDeviceToHost));
|
||||
#endif
|
||||
return dst;
|
||||
}
|
||||
|
||||
+12
-69
@@ -26,89 +26,33 @@
|
||||
#ifdef MFEM_USE_CUDA
|
||||
#define MFEM_ATTR_DEVICE __device__
|
||||
#define MFEM_ATTR_HOST_DEVICE __host__ __device__
|
||||
// Define the CUDA debug macros:
|
||||
// - MFEM_CUDA_CHECK_DRV(x) where 'x' returns/is type 'CUresult'
|
||||
// - MFEM_CUDA_CHECK_RT(x) where 'x' returns/is type 'cudaError_t'
|
||||
#ifdef MFEM_DEBUG
|
||||
#define MFEM_CUDA_CHECK_DRV(x) \
|
||||
do \
|
||||
{ \
|
||||
CUresult err = (x); \
|
||||
if (err != CUDA_SUCCESS) \
|
||||
{ \
|
||||
const char *error_string; \
|
||||
cuGetErrorString(err, &error_string); \
|
||||
_MFEM_MESSAGE("CUDA error: (" << #x \
|
||||
<< ") failed with error:\n --> " \
|
||||
<< error_string, 0); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#define MFEM_CUDA_CHECK_RT(x) \
|
||||
// Define a CUDA error check macro, MFEM_CUDA_CHECK(x), where x returns/is of
|
||||
// type 'cudaError_t'. This macro evaluates 'x' and raises an error if the
|
||||
// result is not cudaSuccess.
|
||||
#define MFEM_CUDA_CHECK(x) \
|
||||
do \
|
||||
{ \
|
||||
cudaError_t err = (x); \
|
||||
if (err != cudaSuccess) \
|
||||
{ \
|
||||
_MFEM_MESSAGE("CUDA error: (" << #x \
|
||||
<< ") failed with error:\n --> " \
|
||||
<< cudaGetErrorString(err), 0); \
|
||||
mfem_cuda_error(err, #x, _MFEM_FUNC_NAME, __FILE__, __LINE__); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
#define MFEM_CUDA_CHECK_DRV(x) x
|
||||
#define MFEM_CUDA_CHECK_RT(x) x
|
||||
#endif
|
||||
#else // MFEM_USE_CUDA
|
||||
#define MFEM_ATTR_DEVICE
|
||||
#define MFEM_ATTR_HOST_DEVICE
|
||||
typedef int CUdevice;
|
||||
typedef int CUcontext;
|
||||
typedef void* CUstream;
|
||||
#endif // MFEM_USE_CUDA
|
||||
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// Define 'atomicAdd' function.
|
||||
#ifdef __CUDA_ARCH__
|
||||
#if __CUDA_ARCH__ < 600
|
||||
static __device__ inline double atomicAdd(double* address, double val)
|
||||
{
|
||||
unsigned long long int* address_as_ull = (unsigned long long int*)address;
|
||||
unsigned long long int old = *address_as_ull, assumed;
|
||||
do
|
||||
{
|
||||
assumed = old;
|
||||
old =
|
||||
atomicCAS(address_as_ull, assumed,
|
||||
__double_as_longlong(val +
|
||||
__longlong_as_double(assumed)));
|
||||
// Note: uses integer comparison to avoid hang in case of NaN
|
||||
// (since NaN != NaN)
|
||||
}
|
||||
while (assumed != old);
|
||||
return __longlong_as_double(old);
|
||||
}
|
||||
#endif // __CUDA_ARCH__ < 600
|
||||
template<typename T> MFEM_ATTR_DEVICE
|
||||
inline T AtomicAdd(T volatile *address, T val)
|
||||
{
|
||||
return atomicAdd((T *)address, val);
|
||||
}
|
||||
#else // __CUDA_ARCH__
|
||||
template<typename T> inline T AtomicAdd(T volatile *address, T val)
|
||||
{
|
||||
#ifdef MFEM_USE_OPENMP
|
||||
#pragma omp atomic
|
||||
#ifdef MFEM_USE_CUDA
|
||||
// Function used by the macro MFEM_CUDA_CHECK.
|
||||
void mfem_cuda_error(cudaError_t err, const char *expr, const char *func,
|
||||
const char *file, int line);
|
||||
#endif
|
||||
*address += val;
|
||||
return *address;
|
||||
}
|
||||
#endif // __CUDA_ARCH__
|
||||
|
||||
|
||||
/// Allocates device memory
|
||||
void* CuMemAlloc(void **d_ptr, size_t bytes);
|
||||
@@ -120,20 +64,19 @@ void* CuMemFree(void *d_ptr);
|
||||
void* CuMemcpyHtoD(void *d_dst, const void *h_src, size_t bytes);
|
||||
|
||||
/// Copies memory from Host to Device
|
||||
void* CuMemcpyHtoDAsync(void *d_dst, const void *h_src,
|
||||
size_t bytes, void *stream);
|
||||
void* CuMemcpyHtoDAsync(void *d_dst, const void *h_src, size_t bytes);
|
||||
|
||||
/// Copies memory from Device to Device
|
||||
void* CuMemcpyDtoD(void *d_dst, void *d_src, size_t bytes);
|
||||
|
||||
/// Copies memory from Device to Device
|
||||
void* CuMemcpyDtoDAsync(void *d_dst, void *d_src, size_t bytes, void *stream);
|
||||
void* CuMemcpyDtoDAsync(void *d_dst, void *d_src, size_t bytes);
|
||||
|
||||
/// Copies memory from Device to Host
|
||||
void* CuMemcpyDtoH(void *h_dst, void *d_src, size_t bytes);
|
||||
|
||||
/// Copies memory from Device to Host
|
||||
void* CuMemcpyDtoHAsync(void *h_dst, void *d_src, size_t bytes, void *stream);
|
||||
void* CuMemcpyDtoHAsync(void *h_dst, void *d_src, size_t bytes);
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
|
||||
+8
-27
@@ -24,9 +24,6 @@ namespace mfem
|
||||
namespace internal
|
||||
{
|
||||
|
||||
CUstream *cuStream = NULL;
|
||||
static CUdevice cuDevice;
|
||||
static CUcontext cuContext;
|
||||
OccaDevice occaDevice;
|
||||
|
||||
// Backends listed by priority, high to low:
|
||||
@@ -100,14 +97,9 @@ void Device::Print(std::ostream &out)
|
||||
#ifdef MFEM_USE_CUDA
|
||||
static void DeviceSetup(const int dev, int &ngpu)
|
||||
{
|
||||
cudaGetDeviceCount(&ngpu);
|
||||
MFEM_VERIFY(ngpu>0, "No CUDA device found!");
|
||||
cuInit(0);
|
||||
cuDeviceGet(&internal::cuDevice, dev);
|
||||
cuCtxCreate(&internal::cuContext, CU_CTX_SCHED_AUTO, internal::cuDevice);
|
||||
internal::cuStream = new CUstream;
|
||||
MFEM_VERIFY(internal::cuStream, "CUDA stream could not be created!");
|
||||
cuStreamCreate(internal::cuStream, CU_STREAM_DEFAULT);
|
||||
MFEM_CUDA_CHECK(cudaGetDeviceCount(&ngpu));
|
||||
MFEM_VERIFY(ngpu > 0, "No CUDA device found!");
|
||||
MFEM_CUDA_CHECK(cudaSetDevice(dev));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -125,7 +117,7 @@ static void RajaDeviceSetup(const int dev, int &ngpu)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void OccaDeviceSetup(CUdevice cu_dev, CUcontext cu_ctx)
|
||||
static void OccaDeviceSetup(const int dev)
|
||||
{
|
||||
#ifdef MFEM_USE_OCCA
|
||||
const int cpu = Device::Allows(Backend::OCCA_CPU);
|
||||
@@ -138,7 +130,8 @@ static void OccaDeviceSetup(CUdevice cu_dev, CUcontext cu_ctx)
|
||||
if (cuda)
|
||||
{
|
||||
#if OCCA_CUDA_ENABLED
|
||||
internal::occaDevice = occa::cuda::wrapDevice(cu_dev, cu_ctx);
|
||||
std::string mode("mode: 'CUDA', device_id : ");
|
||||
internal::occaDevice.setup(mode.append(1,'0'+dev));
|
||||
#else
|
||||
MFEM_ABORT("the OCCA CUDA backend requires OCCA built with CUDA!");
|
||||
#endif
|
||||
@@ -197,22 +190,10 @@ void Device::Setup(const int device)
|
||||
"the OpenMP and RAJA OpenMP backends require MFEM built with"
|
||||
" MFEM_USE_OPENMP=YES");
|
||||
#endif
|
||||
// The check for MFEM_USE_OCCA is in the function OccaDeviceSetup().
|
||||
|
||||
// We initialize CUDA and/or RAJA_CUDA first so OccaDeviceSetup() can reuse
|
||||
// the same initialized cuDevice and cuContext objects when OCCA_CUDA is
|
||||
// enabled.
|
||||
if (Allows(Backend::CUDA)) { CudaDeviceSetup(dev, ngpu); }
|
||||
if (Allows(Backend::RAJA_CUDA)) { RajaDeviceSetup(dev, ngpu); }
|
||||
if (Allows(Backend::OCCA_MASK))
|
||||
{
|
||||
OccaDeviceSetup(internal::cuDevice, internal::cuContext);
|
||||
}
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
delete internal::cuStream;
|
||||
// The check for MFEM_USE_OCCA is in the function OccaDeviceSetup().
|
||||
if (Allows(Backend::OCCA_MASK)) { OccaDeviceSetup(dev); }
|
||||
}
|
||||
|
||||
} // mfem
|
||||
|
||||
@@ -181,8 +181,6 @@ public:
|
||||
Backend::*_MASK, or combinations of those. */
|
||||
static inline bool Allows(unsigned long b_mask)
|
||||
{ return Get().allowed_backends & b_mask; }
|
||||
|
||||
~Device();
|
||||
};
|
||||
|
||||
} // mfem
|
||||
|
||||
+4
-2
@@ -22,6 +22,9 @@
|
||||
|
||||
#ifdef MFEM_USE_RAJA
|
||||
#include "RAJA/RAJA.hpp"
|
||||
#if defined(RAJA_ENABLE_CUDA) && !defined(MFEM_USE_CUDA)
|
||||
#error When RAJA is built with CUDA, MFEM_USE_CUDA=YES is required
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace mfem
|
||||
@@ -106,8 +109,7 @@ void CuWrap(const int N, DBODY &&d_body)
|
||||
if (N==0) { return; }
|
||||
const int GRID = (N+BLOCKS-1)/BLOCKS;
|
||||
CuKernel<<<GRID,BLOCKS>>>(N,d_body);
|
||||
const cudaError_t last = cudaGetLastError();
|
||||
MFEM_VERIFY(last == cudaSuccess, cudaGetErrorString(last));
|
||||
MFEM_CUDA_CHECK(cudaGetLastError());
|
||||
}
|
||||
|
||||
#else // MFEM_USE_CUDA
|
||||
|
||||
@@ -312,7 +312,6 @@ void MemoryManager::Pull(const void *ptr, const std::size_t bytes)
|
||||
{ mfem_error("Unknown pointer to pull from!"); }
|
||||
}
|
||||
|
||||
namespace internal { extern CUstream *cuStream; }
|
||||
void* MemoryManager::Memcpy(void *dst, const void *src,
|
||||
const std::size_t bytes, const bool async)
|
||||
{
|
||||
@@ -322,7 +321,7 @@ void* MemoryManager::Memcpy(void *dst, const void *src,
|
||||
const bool run_on_host = !Device::Allows(Backend::DEVICE_MASK);
|
||||
if (run_on_host) { return std::memcpy(dst, src, bytes); }
|
||||
if (!async) { return CuMemcpyDtoD(d_dst, d_src, bytes); }
|
||||
return CuMemcpyDtoDAsync(d_dst, d_src, bytes, internal::cuStream);
|
||||
return CuMemcpyDtoDAsync(d_dst, d_src, bytes);
|
||||
}
|
||||
|
||||
void MemoryManager::RegisterCheck(void *ptr)
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#define MFEM_OCCA_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "cuda.hpp" // for CUdevice, CUcontext
|
||||
|
||||
#ifdef MFEM_USE_OCCA
|
||||
#include <occa.hpp>
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
#include "complex_operator.hpp"
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -41,30 +39,6 @@ ComplexOperator::~ComplexOperator()
|
||||
delete v_;
|
||||
}
|
||||
|
||||
Operator & ComplexOperator::real()
|
||||
{
|
||||
MFEM_ASSERT(Op_Real_, "ComplexOperator has no real part!");
|
||||
return *Op_Real_;
|
||||
}
|
||||
|
||||
Operator & ComplexOperator::imag()
|
||||
{
|
||||
MFEM_ASSERT(Op_Imag_, "ComplexOperator has no imaginary part!");
|
||||
return *Op_Imag_;
|
||||
}
|
||||
|
||||
const Operator & ComplexOperator::real() const
|
||||
{
|
||||
MFEM_ASSERT(Op_Real_, "ComplexOperator has no real part!");
|
||||
return *Op_Real_;
|
||||
}
|
||||
|
||||
const Operator & ComplexOperator::imag() const
|
||||
{
|
||||
MFEM_ASSERT(Op_Imag_, "ComplexOperator has no imaginary part!");
|
||||
return *Op_Imag_;
|
||||
}
|
||||
|
||||
void ComplexOperator::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
double * x_data = x.GetData();
|
||||
@@ -146,30 +120,6 @@ void ComplexOperator::MultTranspose(const Vector &x_r, const Vector &x_i,
|
||||
}
|
||||
|
||||
|
||||
SparseMatrix & ComplexSparseMatrix::real()
|
||||
{
|
||||
MFEM_ASSERT(Op_Real_, "ComplexSparseMatrix has no real part!");
|
||||
return dynamic_cast<SparseMatrix &>(*Op_Real_);
|
||||
}
|
||||
|
||||
SparseMatrix & ComplexSparseMatrix::imag()
|
||||
{
|
||||
MFEM_ASSERT(Op_Imag_, "ComplexSparseMatrix has no imaginary part!");
|
||||
return dynamic_cast<SparseMatrix &>(*Op_Imag_);
|
||||
}
|
||||
|
||||
const SparseMatrix & ComplexSparseMatrix::real() const
|
||||
{
|
||||
MFEM_ASSERT(Op_Real_, "ComplexSparseMatrix has no real part!");
|
||||
return dynamic_cast<const SparseMatrix &>(*Op_Real_);
|
||||
}
|
||||
|
||||
const SparseMatrix & ComplexSparseMatrix::imag() const
|
||||
{
|
||||
MFEM_ASSERT(Op_Imag_, "ComplexSparseMatrix has no imaginary part!");
|
||||
return dynamic_cast<const SparseMatrix &>(*Op_Imag_);
|
||||
}
|
||||
|
||||
SparseMatrix * ComplexSparseMatrix::GetSystemMatrix() const
|
||||
{
|
||||
SparseMatrix * A_r = dynamic_cast<SparseMatrix*>(Op_Real_);
|
||||
@@ -234,358 +184,4 @@ SparseMatrix * ComplexSparseMatrix::GetSystemMatrix() const
|
||||
return new SparseMatrix(I, J, D, this->Height(), this->Width());
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
ComplexHypreParMatrix::ComplexHypreParMatrix(HypreParMatrix * A_Real,
|
||||
HypreParMatrix * A_Imag,
|
||||
bool ownReal, bool ownImag,
|
||||
Convention convention)
|
||||
: ComplexOperator(A_Real, A_Imag, ownReal, ownImag, convention)
|
||||
{
|
||||
comm_ = (A_Real) ? A_Real->GetComm() :
|
||||
((A_Imag) ? A_Imag->GetComm() : MPI_COMM_WORLD);
|
||||
|
||||
MPI_Comm_rank(comm_, &myid_);
|
||||
MPI_Comm_size(comm_, &nranks_);
|
||||
}
|
||||
|
||||
HypreParMatrix & ComplexHypreParMatrix::real()
|
||||
{
|
||||
MFEM_ASSERT(Op_Real_, "ComplexHypreParMatrix has no real part!");
|
||||
return dynamic_cast<HypreParMatrix &>(*Op_Real_);
|
||||
}
|
||||
|
||||
HypreParMatrix & ComplexHypreParMatrix::imag()
|
||||
{
|
||||
MFEM_ASSERT(Op_Imag_, "ComplexHypreParMatrix has no imaginary part!");
|
||||
return dynamic_cast<HypreParMatrix &>(*Op_Imag_);
|
||||
}
|
||||
|
||||
const HypreParMatrix & ComplexHypreParMatrix::real() const
|
||||
{
|
||||
MFEM_ASSERT(Op_Real_, "ComplexHypreParMatrix has no real part!");
|
||||
return dynamic_cast<const HypreParMatrix &>(*Op_Real_);
|
||||
}
|
||||
|
||||
const HypreParMatrix & ComplexHypreParMatrix::imag() const
|
||||
{
|
||||
MFEM_ASSERT(Op_Imag_, "ComplexHypreParMatrix has no imaginary part!");
|
||||
return dynamic_cast<const HypreParMatrix &>(*Op_Imag_);
|
||||
}
|
||||
|
||||
HypreParMatrix * ComplexHypreParMatrix::GetSystemMatrix() const
|
||||
{
|
||||
HypreParMatrix * A_r = dynamic_cast<HypreParMatrix*>(Op_Real_);
|
||||
HypreParMatrix * A_i = dynamic_cast<HypreParMatrix*>(Op_Imag_);
|
||||
|
||||
if ( A_r == NULL && A_i == NULL ) { return NULL; }
|
||||
|
||||
HYPRE_Int global_num_rows_r = (A_r) ? A_r->GetGlobalNumRows() : 0;
|
||||
HYPRE_Int global_num_rows_i = (A_i) ? A_i->GetGlobalNumRows() : 0;
|
||||
HYPRE_Int global_num_rows = std::max(global_num_rows_r, global_num_rows_i);
|
||||
|
||||
HYPRE_Int global_num_cols_r = (A_r) ? A_r->GetGlobalNumCols() : 0;
|
||||
HYPRE_Int global_num_cols_i = (A_i) ? A_i->GetGlobalNumCols() : 0;
|
||||
HYPRE_Int global_num_cols = std::max(global_num_cols_r, global_num_cols_i);
|
||||
|
||||
int row_starts_size = (HYPRE_AssumedPartitionCheck()) ? 2 : nranks_ + 1;
|
||||
HYPRE_Int * row_starts = hypre_CTAlloc(HYPRE_Int, row_starts_size);
|
||||
HYPRE_Int * col_starts = hypre_CTAlloc(HYPRE_Int, row_starts_size);
|
||||
|
||||
const HYPRE_Int * row_starts_z = (A_r) ? A_r->RowPart() :
|
||||
((A_i) ? A_i->RowPart() : NULL);
|
||||
const HYPRE_Int * col_starts_z = (A_r) ? A_r->ColPart() :
|
||||
((A_i) ? A_i->ColPart() : NULL);
|
||||
|
||||
for (int i = 0; i < row_starts_size; i++)
|
||||
{
|
||||
row_starts[i] = 2 * row_starts_z[i];
|
||||
col_starts[i] = 2 * col_starts_z[i];
|
||||
}
|
||||
|
||||
SparseMatrix diag_r, diag_i, offd_r, offd_i;
|
||||
HYPRE_Int * cmap_r, * cmap_i;
|
||||
|
||||
int nrows_r = 0, nrows_i = 0, ncols_r = 0, ncols_i = 0;
|
||||
int ncols_offd_r = 0, ncols_offd_i = 0;
|
||||
if (A_r)
|
||||
{
|
||||
A_r->GetDiag(diag_r);
|
||||
A_r->GetOffd(offd_r, cmap_r);
|
||||
nrows_r = diag_r.Height();
|
||||
ncols_r = diag_r.Width();
|
||||
ncols_offd_r = offd_r.Width();
|
||||
}
|
||||
if (A_i)
|
||||
{
|
||||
A_i->GetDiag(diag_i);
|
||||
A_i->GetOffd(offd_i, cmap_i);
|
||||
nrows_i = diag_i.Height();
|
||||
ncols_i = diag_i.Width();
|
||||
ncols_offd_i = offd_i.Width();
|
||||
}
|
||||
int nrows = std::max(nrows_r, nrows_i);
|
||||
int ncols = std::max(ncols_r, ncols_i);
|
||||
|
||||
// Determine the unique set of off-diagonal columns global indices
|
||||
std::set<int> cset;
|
||||
for (int i=0; i<ncols_offd_r; i++)
|
||||
{
|
||||
cset.insert(cmap_r[i]);
|
||||
}
|
||||
for (int i=0; i<ncols_offd_i; i++)
|
||||
{
|
||||
cset.insert(cmap_i[i]);
|
||||
}
|
||||
int num_cols_offd = (int)cset.size();
|
||||
|
||||
// Exatract pointers to the various CSR arrays of the diagonal blocks
|
||||
const int * diag_r_I = (A_r) ? diag_r.GetI() : NULL;
|
||||
const int * diag_i_I = (A_i) ? diag_i.GetI() : NULL;
|
||||
|
||||
const int * diag_r_J = (A_r) ? diag_r.GetJ() : NULL;
|
||||
const int * diag_i_J = (A_i) ? diag_i.GetJ() : NULL;
|
||||
|
||||
const double * diag_r_D = (A_r) ? diag_r.GetData() : NULL;
|
||||
const double * diag_i_D = (A_i) ? diag_i.GetData() : NULL;
|
||||
|
||||
int diag_r_nnz = (diag_r_I) ? diag_r_I[nrows] : 0;
|
||||
int diag_i_nnz = (diag_i_I) ? diag_i_I[nrows] : 0;
|
||||
int diag_nnz = 2 * (diag_r_nnz + diag_i_nnz);
|
||||
|
||||
// Exatract pointers to the various CSR arrays of the off-diagonal blocks
|
||||
const int * offd_r_I = (A_r) ? offd_r.GetI() : NULL;
|
||||
const int * offd_i_I = (A_i) ? offd_i.GetI() : NULL;
|
||||
|
||||
const int * offd_r_J = (A_r) ? offd_r.GetJ() : NULL;
|
||||
const int * offd_i_J = (A_i) ? offd_i.GetJ() : NULL;
|
||||
|
||||
const double * offd_r_D = (A_r) ? offd_r.GetData() : NULL;
|
||||
const double * offd_i_D = (A_i) ? offd_i.GetData() : NULL;
|
||||
|
||||
int offd_r_nnz = (offd_r_I) ? offd_r_I[nrows] : 0;
|
||||
int offd_i_nnz = (offd_i_I) ? offd_i_I[nrows] : 0;
|
||||
int offd_nnz = 2 * (offd_r_nnz + offd_i_nnz);
|
||||
|
||||
// Allocate CSR arrays for the combined matrix
|
||||
HYPRE_Int * diag_I = hypre_CTAlloc(HYPRE_Int, 2 * nrows + 1);
|
||||
HYPRE_Int * diag_J = hypre_CTAlloc(HYPRE_Int, diag_nnz);
|
||||
double * diag_D = hypre_CTAlloc(double, diag_nnz);
|
||||
|
||||
HYPRE_Int * offd_I = hypre_CTAlloc(HYPRE_Int, 2 * nrows + 1);
|
||||
HYPRE_Int * offd_J = hypre_CTAlloc(HYPRE_Int, offd_nnz);
|
||||
double * offd_D = hypre_CTAlloc(double, offd_nnz);
|
||||
HYPRE_Int * cmap = hypre_CTAlloc(HYPRE_Int, 2 * num_cols_offd);
|
||||
|
||||
// Fill the CSR arrays for the diagonal portion of the matrix
|
||||
const double factor = (convention_ == HERMITIAN) ? 1.0 : -1.0;
|
||||
|
||||
diag_I[0] = 0;
|
||||
diag_I[nrows] = diag_r_nnz + diag_i_nnz;
|
||||
for (int i=0; i<nrows; i++)
|
||||
{
|
||||
diag_I[i + 1] = ((diag_r_I)?diag_r_I[i+1]:0) +
|
||||
((diag_i_I)?diag_i_I[i+1]:0);
|
||||
diag_I[i + nrows + 1] = diag_I[i+1] + diag_r_nnz + diag_i_nnz;
|
||||
|
||||
if (diag_r_I)
|
||||
{
|
||||
for (int j=0; j<diag_r_I[i+1] - diag_r_I[i]; j++)
|
||||
{
|
||||
diag_J[diag_I[i] + j] = diag_r_J[diag_r_I[i] + j];
|
||||
diag_D[diag_I[i] + j] = diag_r_D[diag_r_I[i] + j];
|
||||
|
||||
diag_J[diag_I[i+nrows] + j] =
|
||||
diag_r_J[diag_r_I[i] + j] + ncols;
|
||||
diag_D[diag_I[i+nrows] + j] =
|
||||
factor * diag_r_D[diag_r_I[i] + j];
|
||||
}
|
||||
}
|
||||
if (diag_i_I)
|
||||
{
|
||||
const int off_r = (diag_r_I)?(diag_r_I[i+1] - diag_r_I[i]):0;
|
||||
for (int j=0; j<diag_i_I[i+1] - diag_i_I[i]; j++)
|
||||
{
|
||||
diag_J[diag_I[i] + off_r + j] = diag_i_J[diag_i_I[i] + j] + ncols;
|
||||
diag_D[diag_I[i] + off_r + j] = -diag_i_D[diag_i_I[i] + j];
|
||||
|
||||
diag_J[diag_I[i+nrows] + off_r + j] = diag_i_J[diag_i_I[i] + j];
|
||||
diag_D[diag_I[i+nrows] + off_r + j] =
|
||||
factor * diag_i_D[diag_i_I[i] + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the mappings describing the layout of off-diagonal columns
|
||||
int num_recv_procs = 0;
|
||||
HYPRE_Int * offd_col_start_stop = NULL;
|
||||
this->getColStartStop(A_r, A_i, num_recv_procs, offd_col_start_stop);
|
||||
|
||||
std::set<int>::iterator sit;
|
||||
std::map<int,int> cmapa, cmapb, cinvmap;
|
||||
for (sit=cset.begin(); sit!=cset.end(); sit++)
|
||||
{
|
||||
int col_orig = *sit;
|
||||
int col_2x2 = -1;
|
||||
int col_size = 0;
|
||||
for (int i=0; i<num_recv_procs; i++)
|
||||
{
|
||||
if (offd_col_start_stop[2*i] <= col_orig &&
|
||||
col_orig < offd_col_start_stop[2*i+1])
|
||||
{
|
||||
col_2x2 = offd_col_start_stop[2*i] + col_orig;
|
||||
col_size = offd_col_start_stop[2*i+1] - offd_col_start_stop[2*i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
cmapa[*sit] = col_2x2;
|
||||
cmapb[*sit] = col_2x2 + col_size;
|
||||
cinvmap[col_2x2] = -1;
|
||||
cinvmap[col_2x2 + col_size] = -1;
|
||||
}
|
||||
delete [] offd_col_start_stop;
|
||||
|
||||
std::map<int, int>::iterator mit;
|
||||
int i = 0;
|
||||
for (mit=cinvmap.begin(); mit!=cinvmap.end(); mit++, i++)
|
||||
{
|
||||
mit->second = i;
|
||||
cmap[i] = mit->first;
|
||||
}
|
||||
|
||||
// Fill the CSR arrays for the off-diagonal portion of the matrix
|
||||
offd_I[0] = 0;
|
||||
offd_I[nrows] = offd_r_nnz + offd_i_nnz;
|
||||
for (int i=0; i<nrows; i++)
|
||||
{
|
||||
offd_I[i + 1] = ((offd_r_I)?offd_r_I[i+1]:0) +
|
||||
((offd_i_I)?offd_i_I[i+1]:0);
|
||||
offd_I[i + nrows + 1] = offd_I[i+1] + offd_r_nnz + offd_i_nnz;
|
||||
|
||||
if (offd_r_I)
|
||||
{
|
||||
const int off_i = (offd_i_I)?(offd_i_I[i+1] - offd_i_I[i]):0;
|
||||
for (int j=0; j<offd_r_I[i+1] - offd_r_I[i]; j++)
|
||||
{
|
||||
offd_J[offd_I[i] + j] =
|
||||
cinvmap[cmapa[cmap_r[offd_r_J[offd_r_I[i] + j]]]];
|
||||
offd_D[offd_I[i] + j] = offd_r_D[offd_r_I[i] + j];
|
||||
|
||||
offd_J[offd_I[i+nrows] + off_i + j] =
|
||||
cinvmap[cmapb[cmap_r[offd_r_J[offd_r_I[i] + j]]]];
|
||||
offd_D[offd_I[i+nrows] + off_i + j] =
|
||||
factor * offd_r_D[offd_r_I[i] + j];
|
||||
}
|
||||
}
|
||||
if (offd_i_I)
|
||||
{
|
||||
const int off_r = (offd_r_I)?(offd_r_I[i+1] - offd_r_I[i]):0;
|
||||
for (int j=0; j<offd_i_I[i+1] - offd_i_I[i]; j++)
|
||||
{
|
||||
offd_J[offd_I[i] + off_r + j] =
|
||||
cinvmap[cmapb[cmap_i[offd_i_J[offd_i_I[i] + j]]]];
|
||||
offd_D[offd_I[i] + off_r + j] = -offd_i_D[offd_i_I[i] + j];
|
||||
|
||||
offd_J[offd_I[i+nrows] + j] =
|
||||
cinvmap[cmapa[cmap_i[offd_i_J[offd_i_I[i] + j]]]];
|
||||
offd_D[offd_I[i+nrows] + j] = factor * offd_i_D[offd_i_I[i] + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the combined matrix
|
||||
HypreParMatrix * A = new HypreParMatrix(comm_,
|
||||
2 * global_num_rows,
|
||||
2 * global_num_cols,
|
||||
row_starts, col_starts,
|
||||
diag_I, diag_J, diag_D,
|
||||
offd_I, offd_J, offd_D,
|
||||
2 * num_cols_offd, cmap);
|
||||
|
||||
// Give the new matrix ownership of its interanl arrays
|
||||
A->SetOwnerFlags(-1,-1,-1);
|
||||
hypre_CSRMatrixSetDataOwner(((hypre_ParCSRMatrix*)(*A))->diag,1);
|
||||
hypre_CSRMatrixSetDataOwner(((hypre_ParCSRMatrix*)(*A))->offd,1);
|
||||
hypre_ParCSRMatrixSetRowStartsOwner((hypre_ParCSRMatrix*)(*A),1);
|
||||
hypre_ParCSRMatrixSetColStartsOwner((hypre_ParCSRMatrix*)(*A),1);
|
||||
|
||||
return A;
|
||||
}
|
||||
|
||||
void
|
||||
ComplexHypreParMatrix::getColStartStop(const HypreParMatrix * A_r,
|
||||
const HypreParMatrix * A_i,
|
||||
int & num_recv_procs,
|
||||
HYPRE_Int *& offd_col_start_stop) const
|
||||
{
|
||||
hypre_ParCSRCommPkg * comm_pkg_r =
|
||||
(A_r) ? hypre_ParCSRMatrixCommPkg((hypre_ParCSRMatrix*)(*A_r)) : NULL;
|
||||
hypre_ParCSRCommPkg * comm_pkg_i =
|
||||
(A_i) ? hypre_ParCSRMatrixCommPkg((hypre_ParCSRMatrix*)(*A_i)) : NULL;
|
||||
|
||||
std::set<HYPRE_Int> send_procs, recv_procs;
|
||||
if ( comm_pkg_r )
|
||||
{
|
||||
for (HYPRE_Int i=0; i<comm_pkg_r->num_sends; i++)
|
||||
{
|
||||
send_procs.insert(comm_pkg_r->send_procs[i]);
|
||||
}
|
||||
for (HYPRE_Int i=0; i<comm_pkg_r->num_recvs; i++)
|
||||
{
|
||||
recv_procs.insert(comm_pkg_r->recv_procs[i]);
|
||||
}
|
||||
}
|
||||
if ( comm_pkg_i )
|
||||
{
|
||||
for (HYPRE_Int i=0; i<comm_pkg_i->num_sends; i++)
|
||||
{
|
||||
send_procs.insert(comm_pkg_i->send_procs[i]);
|
||||
}
|
||||
for (HYPRE_Int i=0; i<comm_pkg_i->num_recvs; i++)
|
||||
{
|
||||
recv_procs.insert(comm_pkg_i->recv_procs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
num_recv_procs = (int)recv_procs.size();
|
||||
|
||||
HYPRE_Int loc_start_stop[2];
|
||||
offd_col_start_stop = new HYPRE_Int[2 * num_recv_procs];
|
||||
|
||||
const HYPRE_Int * row_part = (A_r) ? A_r->RowPart() :
|
||||
((A_i) ? A_i->RowPart() : NULL);
|
||||
|
||||
int row_part_ind = (HYPRE_AssumedPartitionCheck()) ? 0 : myid_;
|
||||
loc_start_stop[0] = row_part[row_part_ind];
|
||||
loc_start_stop[1] = row_part[row_part_ind+1];
|
||||
|
||||
MPI_Request * req = new MPI_Request[send_procs.size()+recv_procs.size()];
|
||||
MPI_Status * stat = new MPI_Status[send_procs.size()+recv_procs.size()];
|
||||
int send_count = 0;
|
||||
int recv_count = 0;
|
||||
int tag = 0;
|
||||
|
||||
std::set<HYPRE_Int>::iterator sit;
|
||||
for (sit=send_procs.begin(); sit!=send_procs.end(); sit++)
|
||||
{
|
||||
MPI_Isend(loc_start_stop, 2, HYPRE_MPI_INT,
|
||||
*sit, tag, comm_, &req[send_count]);
|
||||
send_count++;
|
||||
}
|
||||
for (sit=recv_procs.begin(); sit!=recv_procs.end(); sit++)
|
||||
{
|
||||
MPI_Irecv(&offd_col_start_stop[2*recv_count], 2, HYPRE_MPI_INT,
|
||||
*sit, tag, comm_, &req[send_count+recv_count]);
|
||||
recv_count++;
|
||||
}
|
||||
|
||||
MPI_Waitall(send_count+recv_count, req, stat);
|
||||
|
||||
delete [] req;
|
||||
delete [] stat;
|
||||
}
|
||||
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
}
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
|
||||
#include "operator.hpp"
|
||||
#include "sparsemat.hpp"
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include "hypre.hpp"
|
||||
#endif
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -30,8 +27,7 @@ namespace mfem
|
||||
ComplexOperator allows one to choose a convention upon construction, which
|
||||
facilitates symmetry.
|
||||
|
||||
If we let (y_r + i y_i) = (Op_r + i Op_i)(x_r + i x_i) then Matrix-vector
|
||||
products are then computed as:
|
||||
Matrix-vector products are then computed as:
|
||||
|
||||
1. When Convention::HERMITIAN is used (default)
|
||||
/ y_r \ / Op_r -Op_i \ / x_r \
|
||||
@@ -42,8 +38,6 @@ namespace mfem
|
||||
/ y_r \ / Op_r -Op_i \ / x_r \
|
||||
| | = | | | |
|
||||
\-y_i / \-Op_i -Op_r / \ x_i /
|
||||
In other words, Matrix-vector products with Convention::BLOCK_SYMMETRIC
|
||||
compute the complex conjugate of Op*x.
|
||||
|
||||
Either convention can be used with a given complex operator,
|
||||
however, each of them is best suited for certain classes of
|
||||
@@ -88,30 +82,9 @@ public:
|
||||
|
||||
virtual ~ComplexOperator();
|
||||
|
||||
/** @brief Check for existence of real or imaginary part of the operator
|
||||
|
||||
These methods do not check that the operators are non-zero but
|
||||
only that the operators have been set.
|
||||
*/
|
||||
bool hasRealPart() const { return Op_Real_ != NULL; }
|
||||
bool hasImagPart() const { return Op_Imag_ != NULL; }
|
||||
|
||||
/** @brief Real or imaginary part accessor methods
|
||||
|
||||
The following accessor methods should only be called if the
|
||||
requested part of the opertor is known to exist. This
|
||||
can be checked with hasRealPart() or hasImagPart().
|
||||
*/
|
||||
virtual Operator & real();
|
||||
virtual Operator & imag();
|
||||
virtual const Operator & real() const;
|
||||
virtual const Operator & imag() const;
|
||||
|
||||
virtual void Mult(const Vector &x, Vector &y) const;
|
||||
virtual void MultTranspose(const Vector &x, Vector &y) const;
|
||||
|
||||
virtual Type GetType() const { return Complex_Operator; }
|
||||
|
||||
protected:
|
||||
// Let this be hidden from the public interface since the implementation
|
||||
// depends on internal members
|
||||
@@ -154,74 +127,9 @@ public:
|
||||
: ComplexOperator(A_Real, A_Imag, ownReal, ownImag, convention)
|
||||
{}
|
||||
|
||||
virtual SparseMatrix & real();
|
||||
virtual SparseMatrix & imag();
|
||||
|
||||
virtual const SparseMatrix & real() const;
|
||||
virtual const SparseMatrix & imag() const;
|
||||
|
||||
/** Combine the blocks making up this complex operator into a
|
||||
single SparseMatrix. The resulting matrix can be passed to
|
||||
solvers which require access to the matrix entries themselves,
|
||||
such as sparse direct solvers, rather than simply the action of
|
||||
the opertor. Note that this combined operator requires roughly
|
||||
twice the memory of the block structured operator. */
|
||||
SparseMatrix * GetSystemMatrix() const;
|
||||
|
||||
virtual Type GetType() const { return MFEM_ComplexSparseMat; }
|
||||
};
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
/** @brief Specialization of the ComplexOperator built from a pair of
|
||||
HypreParMatrices.
|
||||
|
||||
The purpose of this specialization is to construct a single
|
||||
HypreParMatrix object which is equivalent to the 2x2 block system
|
||||
that the ComplexOperator mimics. The resulting HypreParMatrix can
|
||||
then be passed along to solvers which require access to the CSR
|
||||
matrix data such as SuperLU, STRUMPACK, or similar sparse linear
|
||||
solvers.
|
||||
|
||||
See ComplexOperator documentation in operator.hpp for more information.
|
||||
*/
|
||||
class ComplexHypreParMatrix : public ComplexOperator
|
||||
{
|
||||
public:
|
||||
ComplexHypreParMatrix(HypreParMatrix * A_Real, HypreParMatrix * A_Imag,
|
||||
bool ownReal, bool ownImag,
|
||||
Convention convention = HERMITIAN);
|
||||
|
||||
virtual HypreParMatrix & real();
|
||||
virtual HypreParMatrix & imag();
|
||||
|
||||
virtual const HypreParMatrix & real() const;
|
||||
virtual const HypreParMatrix & imag() const;
|
||||
|
||||
/** Combine the blocks making up this complex operator into a
|
||||
single HypreParMatrix. The resulting matrix can be passed to
|
||||
solvers which require access to the matrix entries themselves,
|
||||
such as sparse direct solvers or Hypre preconditioners, rather
|
||||
than simply the action of the opertor. Note that this combined
|
||||
operator requires roughly twice the memory of the block
|
||||
structured operator. */
|
||||
HypreParMatrix * GetSystemMatrix() const;
|
||||
|
||||
virtual Type GetType() const { return Complex_Hypre_ParCSR; }
|
||||
|
||||
private:
|
||||
void getColStartStop(const HypreParMatrix * A_r,
|
||||
const HypreParMatrix * A_i,
|
||||
int & num_recv_procs,
|
||||
HYPRE_Int *& offd_col_start_stop) const;
|
||||
|
||||
MPI_Comm comm_;
|
||||
int myid_;
|
||||
int nranks_;
|
||||
};
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
}
|
||||
|
||||
#endif // MFEM_COMPLEX_OPERATOR
|
||||
#endif
|
||||
|
||||
+7
-4
@@ -468,13 +468,16 @@ public:
|
||||
{ internal::hypre_ParCSRMatrixSetConstantValues(A, value); return *this; }
|
||||
|
||||
/** Perform the operation `*this += B`, assuming that both matrices use the
|
||||
same row and column partitions and the same col_map_offd arrays. We also
|
||||
assume that the sparsity pattern of `*this` contains that of `B`. */
|
||||
same row and column partitions and the same col_map_offd arrays, or B has
|
||||
an empty off-diagonal block. We also assume that the sparsity pattern of
|
||||
`*this` contains that of `B`. */
|
||||
HypreParMatrix &operator+=(const HypreParMatrix &B) { return Add(1.0, B); }
|
||||
|
||||
/** Perform the operation `*this += beta*B`, assuming that both matrices use
|
||||
the same row and column partitions and the same col_map_offd arrays. We
|
||||
also assume that the sparsity pattern of `*this` contains that of `B`. */
|
||||
the same row and column partitions and the same col_map_offd arrays, or
|
||||
B has an empty off-diagonal block. We also assume that the sparsity
|
||||
pattern of `*this` contains that of `B`. For a more general case consider
|
||||
the stand-alone function ParAdd described below. */
|
||||
HypreParMatrix &Add(const double beta, const HypreParMatrix &B)
|
||||
{
|
||||
MFEM_VERIFY(internal::hypre_ParCSRMatrixSum(A, beta, B.A) == 0,
|
||||
|
||||
@@ -1520,10 +1520,14 @@ hypre_ParCSRMatrixSum(hypre_ParCSRMatrix *A,
|
||||
hypre_CSRMatrix *A_offd = hypre_ParCSRMatrixOffd(A);
|
||||
hypre_CSRMatrix *B_diag = hypre_ParCSRMatrixDiag(B);
|
||||
hypre_CSRMatrix *B_offd = hypre_ParCSRMatrixOffd(B);
|
||||
HYPRE_Int ncols_B_offd = hypre_CSRMatrixNumCols(B_offd);
|
||||
HYPRE_Int error;
|
||||
|
||||
error = hypre_CSRMatrixSum(A_diag, beta, B_diag);
|
||||
error = error ? error : hypre_CSRMatrixSum(A_offd, beta, B_offd);
|
||||
if (ncols_B_offd > 0) /* treat B_offd as zero if it has no columns */
|
||||
{
|
||||
error = error ? error : hypre_CSRMatrixSum(A_offd, beta, B_offd);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -115,8 +115,9 @@ hypre_ParCSRMatrixAdd(hypre_ParCSRMatrix *A,
|
||||
hypre_ParCSRMatrix *B);
|
||||
|
||||
/** Perform the operation A += beta*B, assuming that both matrices use the same
|
||||
row and column partitions and the same col_map_offd arrays. We also assume
|
||||
that the sparsity pattern of A contains that of B. */
|
||||
row and column partitions and the same col_map_offd arrays, or B has an empty
|
||||
off-diagonal block. We also assume that the sparsity pattern of A contains
|
||||
that of B. */
|
||||
HYPRE_Int
|
||||
hypre_ParCSRMatrixSum(hypre_ParCSRMatrix *A,
|
||||
HYPRE_Complex beta,
|
||||
|
||||
+2
-23
@@ -124,17 +124,14 @@ public:
|
||||
enum Type
|
||||
{
|
||||
ANY_TYPE, ///< ID for the base class Operator, i.e. any type.
|
||||
MFEM_SPARSEMAT, ///< ID for class SparseMatrix.
|
||||
MFEM_SPARSEMAT, ///< ID for class SparseMatrix
|
||||
Hypre_ParCSR, ///< ID for class HypreParMatrix.
|
||||
PETSC_MATAIJ, ///< ID for class PetscParMatrix, MATAIJ format.
|
||||
PETSC_MATIS, ///< ID for class PetscParMatrix, MATIS format.
|
||||
PETSC_MATSHELL, ///< ID for class PetscParMatrix, MATSHELL format.
|
||||
PETSC_MATNEST, ///< ID for class PetscParMatrix, MATNEST format.
|
||||
PETSC_MATHYPRE, ///< ID for class PetscParMatrix, MATHYPRE format.
|
||||
PETSC_MATGENERIC, ///< ID for class PetscParMatrix, unspecified format.
|
||||
Complex_Operator, ///< ID for class ComplexOperator.
|
||||
MFEM_ComplexSparseMat, ///< ID for class ComplexSparseMatrix.
|
||||
Complex_Hypre_ParCSR ///< ID for class ComplexHypreParMatrix.
|
||||
PETSC_MATGENERIC ///< ID for class PetscParMatrix, unspecified format.
|
||||
};
|
||||
|
||||
/// Return the type ID of the Operator class.
|
||||
@@ -305,24 +302,6 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/// Scaled Operator B: x -> a A(x).
|
||||
class ScaledOperator : public Operator
|
||||
{
|
||||
private:
|
||||
const Operator &A_;
|
||||
double a_;
|
||||
|
||||
public:
|
||||
/// Create a scalar product operator related to A.
|
||||
explicit ScaledOperator(const Operator *A, double a)
|
||||
: Operator(A->Width(), A->Height()), A_(*A), a_(a) { }
|
||||
|
||||
/// Operator application
|
||||
virtual void Mult(const Vector &x, Vector &y) const
|
||||
{ A_.Mult(x, y); y *= a_; }
|
||||
};
|
||||
|
||||
|
||||
/** @brief The transpose of a given operator. Switches the roles of the methods
|
||||
Mult() and MultTranspose(). */
|
||||
class TransposeOperator : public Operator
|
||||
|
||||
+78
-52
@@ -38,6 +38,7 @@ SparseMatrix::SparseMatrix(int nrows, int ncols)
|
||||
current_row(-1),
|
||||
ColPtrJ(NULL),
|
||||
ColPtrNode(NULL),
|
||||
At(NULL),
|
||||
ownGraph(true),
|
||||
ownData(true),
|
||||
isSorted(false)
|
||||
@@ -60,6 +61,7 @@ SparseMatrix::SparseMatrix(int *i, int *j, double *data, int m, int n)
|
||||
Rows(NULL),
|
||||
ColPtrJ(NULL),
|
||||
ColPtrNode(NULL),
|
||||
At(NULL),
|
||||
ownGraph(true),
|
||||
ownData(true),
|
||||
isSorted(false)
|
||||
@@ -78,6 +80,7 @@ SparseMatrix::SparseMatrix(int *i, int *j, double *data, int m, int n,
|
||||
Rows(NULL),
|
||||
ColPtrJ(NULL),
|
||||
ColPtrNode(NULL),
|
||||
At(NULL),
|
||||
ownGraph(ownij),
|
||||
ownData(owna),
|
||||
isSorted(issorted)
|
||||
@@ -103,6 +106,7 @@ SparseMatrix::SparseMatrix(int nrows, int ncols, int rowsize)
|
||||
, Rows(NULL)
|
||||
, ColPtrJ(NULL)
|
||||
, ColPtrNode(NULL)
|
||||
, At(NULL)
|
||||
, ownGraph(true)
|
||||
, ownData(true)
|
||||
, isSorted(false)
|
||||
@@ -183,6 +187,7 @@ SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph)
|
||||
current_row = -1;
|
||||
ColPtrJ = NULL;
|
||||
ColPtrNode = NULL;
|
||||
At = NULL;
|
||||
isSorted = mat.isSorted;
|
||||
}
|
||||
|
||||
@@ -191,6 +196,7 @@ SparseMatrix::SparseMatrix(const Vector &v)
|
||||
, Rows(NULL)
|
||||
, ColPtrJ(NULL)
|
||||
, ColPtrNode(NULL)
|
||||
, At(NULL)
|
||||
, ownGraph(true)
|
||||
, ownData(true)
|
||||
, isSorted(true)
|
||||
@@ -245,6 +251,7 @@ void SparseMatrix::SetEmpty()
|
||||
current_row = -1;
|
||||
ColPtrJ = NULL;
|
||||
ColPtrNode = NULL;
|
||||
At = NULL;
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
NodesMem = NULL;
|
||||
#endif
|
||||
@@ -333,7 +340,7 @@ void SparseMatrix::SetWidth(int newWidth)
|
||||
// Nothing to be done here
|
||||
return;
|
||||
}
|
||||
else if ( newWidth == -1)
|
||||
else if (newWidth == -1)
|
||||
{
|
||||
// Compute the actual width
|
||||
width = ActualWidth();
|
||||
@@ -552,12 +559,10 @@ void SparseMatrix::Mult(const Vector &x, Vector &y) const
|
||||
|
||||
void SparseMatrix::AddMult(const Vector &x, Vector &y, const double a) const
|
||||
{
|
||||
MFEM_ASSERT(width == x.Size(),
|
||||
"Input vector size (" << x.Size() << ") must match matrix width (" << width
|
||||
<< ")");
|
||||
MFEM_ASSERT(height == y.Size(),
|
||||
"Output vector size (" << y.Size() << ") must match matrix height (" << height
|
||||
<< ")");
|
||||
MFEM_ASSERT(width == x.Size(), "Input vector size (" << x.Size()
|
||||
<< ") must match matrix width (" << width << ")");
|
||||
MFEM_ASSERT(height == y.Size(), "Output vector size (" << y.Size()
|
||||
<< ") must match matrix height (" << height << ")");
|
||||
|
||||
int i, j, end;
|
||||
double *Ap = A, *yp = y.GetData();
|
||||
@@ -636,12 +641,10 @@ void SparseMatrix::MultTranspose(const Vector &x, Vector &y) const
|
||||
void SparseMatrix::AddMultTranspose(const Vector &x, Vector &y,
|
||||
const double a) const
|
||||
{
|
||||
MFEM_ASSERT(height == x.Size(),
|
||||
"Input vector size (" << x.Size() << ") must match matrix height (" << height
|
||||
<< ")");
|
||||
MFEM_ASSERT(width == y.Size(),
|
||||
"Output vector size (" << y.Size() << ") must match matrix width (" << width
|
||||
<< ")");
|
||||
MFEM_ASSERT(height == x.Size(), "Input vector size (" << x.Size()
|
||||
<< ") must match matrix height (" << height << ")");
|
||||
MFEM_ASSERT(width == y.Size(), "Output vector size (" << y.Size()
|
||||
<< ") must match matrix width (" << width << ")");
|
||||
|
||||
if (A == NULL)
|
||||
{
|
||||
@@ -658,23 +661,40 @@ void SparseMatrix::AddMultTranspose(const Vector &x, Vector &y,
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Prepare the lambda capture and get our pointers from the memory manager
|
||||
const int d_height = height;
|
||||
const DeviceArray d_I(I);
|
||||
const DeviceArray d_J(J);
|
||||
const DeviceVector d_A(A);
|
||||
const DeviceVector d_x(x, x.Size());
|
||||
DeviceVector d_y(y, y.Size());
|
||||
MFEM_FORALL(i, d_height,
|
||||
|
||||
if (At)
|
||||
{
|
||||
const double xi = a * d_x[i];
|
||||
const int end = d_I[i+1];
|
||||
for (int j = d_I[i]; j < end; j++)
|
||||
At->AddMult(x, y, a);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_VERIFY(Device::IsDisabled(), "transpose action on device is not "
|
||||
"enabled; see BuildTranspose() for details.");
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
const int Jj = d_J[j];
|
||||
AtomicAdd(&d_y[Jj], d_A[j] * xi);
|
||||
const double xi = a * x[i];
|
||||
const int end = I[i+1];
|
||||
for (int j = I[i]; j < end; j++)
|
||||
{
|
||||
const int Jj = J[j];
|
||||
y[Jj] += A[j] * xi;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void SparseMatrix::BuildTranspose() const
|
||||
{
|
||||
if (At == NULL)
|
||||
{
|
||||
At = Transpose(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void SparseMatrix::ResetTranspose() const
|
||||
{
|
||||
delete At;
|
||||
At = NULL;
|
||||
}
|
||||
|
||||
void SparseMatrix::PartMult(
|
||||
@@ -2101,12 +2121,12 @@ void SparseMatrix::Set(const int i, const int j, const double A)
|
||||
if ((gi=i) < 0) { gi = -1-gi, s = -1; }
|
||||
else { s = 1; }
|
||||
MFEM_ASSERT(gi < height,
|
||||
"Trying to insert a row " << gi << " outside the matrix height "
|
||||
"Trying to set a row " << gi << " outside the matrix height "
|
||||
<< height);
|
||||
if ((gj=j) < 0) { gj = -1-gj, t = -s; }
|
||||
else { t = s; }
|
||||
MFEM_ASSERT(gj < width,
|
||||
"Trying to insert a column " << gj << " outside the matrix width "
|
||||
"Trying to set a column " << gj << " outside the matrix width "
|
||||
<< width);
|
||||
if (t < 0) { a = -a; }
|
||||
_Set_(gi, gj, a);
|
||||
@@ -2142,7 +2162,7 @@ void SparseMatrix::SetSubMatrix(const Array<int> &rows, const Array<int> &cols,
|
||||
if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
|
||||
else { s = 1; }
|
||||
MFEM_ASSERT(gi < height,
|
||||
"Trying to insert a row " << gi << " outside the matrix height "
|
||||
"Trying to set a row " << gi << " outside the matrix height "
|
||||
<< height);
|
||||
SetColPtr(gi);
|
||||
for (j = 0; j < cols.Size(); j++)
|
||||
@@ -2155,7 +2175,7 @@ void SparseMatrix::SetSubMatrix(const Array<int> &rows, const Array<int> &cols,
|
||||
if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
|
||||
else { t = s; }
|
||||
MFEM_ASSERT(gj < width,
|
||||
"Trying to insert a column " << gj << " outside the matrix width "
|
||||
"Trying to set a column " << gj << " outside the matrix width "
|
||||
<< width);
|
||||
if (t < 0) { a = -a; }
|
||||
_Set_(gj, a);
|
||||
@@ -2177,7 +2197,7 @@ void SparseMatrix::SetSubMatrixTranspose(const Array<int> &rows,
|
||||
if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
|
||||
else { s = 1; }
|
||||
MFEM_ASSERT(gi < height,
|
||||
"Trying to insert a row " << gi << " outside the matrix height "
|
||||
"Trying to set a row " << gi << " outside the matrix height "
|
||||
<< height);
|
||||
SetColPtr(gi);
|
||||
for (j = 0; j < cols.Size(); j++)
|
||||
@@ -2190,7 +2210,7 @@ void SparseMatrix::SetSubMatrixTranspose(const Array<int> &rows,
|
||||
if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
|
||||
else { t = s; }
|
||||
MFEM_ASSERT(gj < width,
|
||||
"Trying to insert a column " << gj << " outside the matrix width "
|
||||
"Trying to set a column " << gj << " outside the matrix width "
|
||||
<< width);
|
||||
if (t < 0) { a = -a; }
|
||||
_Set_(gj, a);
|
||||
@@ -2210,7 +2230,7 @@ void SparseMatrix::GetSubMatrix(const Array<int> &rows, const Array<int> &cols,
|
||||
if ((gi=rows[i]) < 0) { gi = -1-gi, s = -1; }
|
||||
else { s = 1; }
|
||||
MFEM_ASSERT(gi < height,
|
||||
"Trying to insert a row " << gi << " outside the matrix height "
|
||||
"Trying to read a row " << gi << " outside the matrix height "
|
||||
<< height);
|
||||
SetColPtr(gi);
|
||||
for (j = 0; j < cols.Size(); j++)
|
||||
@@ -2218,7 +2238,7 @@ void SparseMatrix::GetSubMatrix(const Array<int> &rows, const Array<int> &cols,
|
||||
if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
|
||||
else { t = s; }
|
||||
MFEM_ASSERT(gj < width,
|
||||
"Trying to insert a column " << gj << " outside the matrix width "
|
||||
"Trying to read a column " << gj << " outside the matrix width "
|
||||
<< width);
|
||||
a = _Get_(gj);
|
||||
subm(i, j) = (t < 0) ? (-a) : (a);
|
||||
@@ -2236,7 +2256,7 @@ bool SparseMatrix::RowIsEmpty(const int row) const
|
||||
gi = -1-gi;
|
||||
}
|
||||
MFEM_ASSERT(gi < height,
|
||||
"Trying to insert a row " << gi << " outside the matrix height "
|
||||
"Trying to query a row " << gi << " outside the matrix height "
|
||||
<< height);
|
||||
if (Rows)
|
||||
{
|
||||
@@ -2255,7 +2275,7 @@ int SparseMatrix::GetRow(const int row, Array<int> &cols, Vector &srow) const
|
||||
|
||||
if ((gi=row) < 0) { gi = -1-gi; }
|
||||
MFEM_ASSERT(gi < height,
|
||||
"Trying to insert a row " << gi << " outside the matrix height "
|
||||
"Trying to read a row " << gi << " outside the matrix height "
|
||||
<< height);
|
||||
if (Rows)
|
||||
{
|
||||
@@ -2282,7 +2302,7 @@ int SparseMatrix::GetRow(const int row, Array<int> &cols, Vector &srow) const
|
||||
j = I[gi];
|
||||
cols.MakeRef(J + j, I[gi+1]-j);
|
||||
srow.NewDataAndSize(A + j, cols.Size());
|
||||
MFEM_ASSERT(row >= 0, "Row not valid: " << row );
|
||||
MFEM_ASSERT(row >= 0, "Row not valid: " << row << ", height: " << height);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -2296,7 +2316,7 @@ void SparseMatrix::SetRow(const int row, const Array<int> &cols,
|
||||
if ((gi=row) < 0) { gi = -1-gi, s = -1; }
|
||||
else { s = 1; }
|
||||
MFEM_ASSERT(gi < height,
|
||||
"Trying to insert a row " << gi << " outside the matrix height "
|
||||
"Trying to set a row " << gi << " outside the matrix height "
|
||||
<< height);
|
||||
|
||||
if (!Finalized())
|
||||
@@ -2307,7 +2327,7 @@ void SparseMatrix::SetRow(const int row, const Array<int> &cols,
|
||||
if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
|
||||
else { t = s; }
|
||||
MFEM_ASSERT(gj < width,
|
||||
"Trying to insert a column " << gj << " outside the matrix"
|
||||
"Trying to set a column " << gj << " outside the matrix"
|
||||
" width " << width);
|
||||
a = srow(j);
|
||||
if (t < 0) { a = -a; }
|
||||
@@ -2325,7 +2345,7 @@ void SparseMatrix::SetRow(const int row, const Array<int> &cols,
|
||||
if ((gj=cols[j]) < 0) { gj = -1-gj, t = -s; }
|
||||
else { t = s; }
|
||||
MFEM_ASSERT(gj < width,
|
||||
"Trying to insert a column " << gj << " outside the matrix"
|
||||
"Trying to set a column " << gj << " outside the matrix"
|
||||
" width " << width);
|
||||
|
||||
J[i] = gj;
|
||||
@@ -2771,9 +2791,10 @@ void SparseMatrix::Destroy()
|
||||
delete NodesMem;
|
||||
}
|
||||
#endif
|
||||
delete At;
|
||||
}
|
||||
|
||||
int SparseMatrix::ActualWidth()
|
||||
int SparseMatrix::ActualWidth() const
|
||||
{
|
||||
int awidth = 0;
|
||||
if (A)
|
||||
@@ -2817,8 +2838,10 @@ SparseMatrix *Transpose (const SparseMatrix &A)
|
||||
"Finalize must be called before Transpose. Use TransposeRowMatrix instead");
|
||||
|
||||
int i, j, end;
|
||||
int m, n, nnz, *A_i, *A_j, *At_i, *At_j;
|
||||
double *A_data, *At_data;
|
||||
const int *A_i, *A_j;
|
||||
int m, n, nnz, *At_i, *At_j;
|
||||
const double *A_data;
|
||||
double *At_data;
|
||||
|
||||
m = A.Height(); // number of rows of A
|
||||
n = A.Width(); // number of columns of A
|
||||
@@ -2945,8 +2968,10 @@ SparseMatrix *Mult (const SparseMatrix &A, const SparseMatrix &B,
|
||||
SparseMatrix *OAB)
|
||||
{
|
||||
int nrowsA, ncolsA, nrowsB, ncolsB;
|
||||
int *A_i, *A_j, *B_i, *B_j, *C_i, *C_j, *B_marker;
|
||||
double *A_data, *B_data, *C_data;
|
||||
const int *A_i, *A_j, *B_i, *B_j;
|
||||
int *C_i, *C_j, *B_marker;
|
||||
const double *A_data, *B_data;
|
||||
double *C_data;
|
||||
int ia, ib, ic, ja, jb, num_nonzeros;
|
||||
int row_start, counter;
|
||||
double a_entry, b_entry;
|
||||
@@ -3259,13 +3284,13 @@ SparseMatrix * Add(double a, const SparseMatrix & A, double b,
|
||||
int * C_j;
|
||||
double * C_data;
|
||||
|
||||
int * A_i = A.GetI();
|
||||
int * A_j = A.GetJ();
|
||||
double * A_data = A.GetData();
|
||||
const int *A_i = A.GetI();
|
||||
const int *A_j = A.GetJ();
|
||||
const double *A_data = A.GetData();
|
||||
|
||||
int * B_i = B.GetI();
|
||||
int * B_j = B.GetJ();
|
||||
double * B_data = B.GetData();
|
||||
const int *B_i = B.GetI();
|
||||
const int *B_j = B.GetJ();
|
||||
const double *B_data = B.GetData();
|
||||
|
||||
int * marker = new int[ncols];
|
||||
std::fill(marker, marker+ncols, -1);
|
||||
@@ -3493,6 +3518,7 @@ void SparseMatrix::Swap(SparseMatrix &other)
|
||||
mfem::Swap(current_row, other.current_row);
|
||||
mfem::Swap(ColPtrJ, other.ColPtrJ);
|
||||
mfem::Swap(ColPtrNode, other.ColPtrNode);
|
||||
mfem::Swap(At, other.At);
|
||||
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
mfem::Swap(NodesMem, other.NodesMem);
|
||||
|
||||
+74
-18
@@ -64,6 +64,9 @@ protected:
|
||||
mutable int* ColPtrJ;
|
||||
mutable RowNode ** ColPtrNode;
|
||||
|
||||
/// Transpose of A. Owned. Used to perform MultTranspose() on devices.
|
||||
mutable SparseMatrix *At;
|
||||
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
typedef MemAlloc <RowNode, 1024> RowNodeAlloc;
|
||||
RowNodeAlloc * NodesMem;
|
||||
@@ -97,6 +100,9 @@ public:
|
||||
|
||||
/** @brief Create a sparse matrix in CSR format. Ownership of @a i, @a j, and
|
||||
@a data is optionally transferred to the SparseMatrix. */
|
||||
/** If the parameter @a data is NULL, then the internal #A array is allocated
|
||||
by this constructor (initializing it with zeros and taking ownership,
|
||||
regardless of the parameter @a owna). */
|
||||
SparseMatrix(int *i, int *j, double *data, int m, int n, bool ownij,
|
||||
bool owna, bool issorted);
|
||||
|
||||
@@ -112,7 +118,7 @@ public:
|
||||
ownership. */
|
||||
SparseMatrix(const SparseMatrix &mat, bool copy_graph = true);
|
||||
|
||||
/// Create a SparseMatrix with diagonal v, i.e. A = Diag(v)
|
||||
/// Create a SparseMatrix with diagonal @a v, i.e. A = Diag(v)
|
||||
SparseMatrix(const Vector & v);
|
||||
|
||||
|
||||
@@ -134,21 +140,35 @@ public:
|
||||
/// Check if the SparseMatrix is empty.
|
||||
bool Empty() const { return (A == NULL) && (Rows == NULL); }
|
||||
|
||||
/// Return the array #I
|
||||
inline int *GetI() const { return I; }
|
||||
/// Return the array #J
|
||||
inline int *GetJ() const { return J; }
|
||||
/// Return element data, i.e. array #A
|
||||
inline double *GetData() const { return A; }
|
||||
/// Returns the number of elements in row @a i
|
||||
/// Return the array #I.
|
||||
inline int *GetI() { return I; }
|
||||
/// Return the array #I, const version.
|
||||
inline const int *GetI() const { return I; }
|
||||
|
||||
/// Return the array #J.
|
||||
inline int *GetJ() { return J; }
|
||||
/// Return the array #J, const version.
|
||||
inline const int *GetJ() const { return J; }
|
||||
|
||||
/// Return the element data, i.e. the array #A.
|
||||
inline double *GetData() { return A; }
|
||||
/// Return the element data, i.e. the array #A, const version.
|
||||
inline const double *GetData() const { return A; }
|
||||
|
||||
/// Returns the number of elements in row @a i.
|
||||
int RowSize(const int i) const;
|
||||
/// Returns the maximum number of elements among all rows
|
||||
|
||||
/// Returns the maximum number of elements among all rows.
|
||||
int MaxRowSize() const;
|
||||
/// Return a pointer to the column indices in a row
|
||||
|
||||
/// Return a pointer to the column indices in a row.
|
||||
int *GetRowColumns(const int row);
|
||||
/// Return a pointer to the column indices in a row, const version.
|
||||
const int *GetRowColumns(const int row) const;
|
||||
/// Return a pointer to the entries in a row
|
||||
|
||||
/// Return a pointer to the entries in a row.
|
||||
double *GetRowEntries(const int row);
|
||||
/// Return a pointer to the entries in a row, const version.
|
||||
const double *GetRowEntries(const int row) const;
|
||||
|
||||
/// Change the width of a SparseMatrix.
|
||||
@@ -163,7 +183,7 @@ public:
|
||||
|
||||
/// Returns the actual Width of the matrix.
|
||||
/*! This method can be called for matrices finalized or not. */
|
||||
int ActualWidth();
|
||||
int ActualWidth() const;
|
||||
|
||||
/// Sort the column indices corresponding to each row.
|
||||
void SortColumnIndices();
|
||||
@@ -206,13 +226,45 @@ public:
|
||||
void AddMultTranspose(const Vector &x, Vector &y,
|
||||
const double a = 1.0) const;
|
||||
|
||||
/** @brief Build and store internally the transpose of this matrix which will
|
||||
be used in the methods AddMultTranspose() and MultTranspose(). */
|
||||
/** If this method has been called, the internal transpose matrix will be
|
||||
used to perform the action of the transpose matrix in AddMultTranspose(),
|
||||
and MultTranspose().
|
||||
|
||||
Warning: any changes in this matrix will invalidate the internal
|
||||
transpose. To rebuild the transpose, call ResetTranspose() followed by a
|
||||
call to this method. If the internal transpose is already built, this
|
||||
method has no effect.
|
||||
|
||||
When any non-default backend is enabled, i.e. Device::IsEnabled() is
|
||||
true, the methods AddMultTranspose(), and MultTranspose(), require the
|
||||
internal transpose to be built. If that is not the case (i.e. the
|
||||
internal transpose is not built), these methods will raise an error with
|
||||
an appropriate message pointing to this method. When using the default
|
||||
backend, calling this method is optional.
|
||||
|
||||
This method can only be used when the sparse matrix is finalized. */
|
||||
void BuildTranspose() const;
|
||||
|
||||
/** Reset (destroy) the internal transpose matrix. See BuildTranspose() for
|
||||
more details. */
|
||||
void ResetTranspose() const;
|
||||
|
||||
void PartMult(const Array<int> &rows, const Vector &x, Vector &y) const;
|
||||
void PartAddMult(const Array<int> &rows, const Vector &x, Vector &y,
|
||||
const double a=1.0) const;
|
||||
|
||||
/// y = A * x, but treat all elements as booleans (zero=false, nonzero=true).
|
||||
/// y = A * x, treating all entries as booleans (zero=false, nonzero=true).
|
||||
/** The actual values stored in the data array, #A, are not used - this means
|
||||
and that all entries in the sparsity pattern are considered to be true by
|
||||
this method. */
|
||||
void BooleanMult(const Array<int> &x, Array<int> &y) const;
|
||||
/// y = At * x, but treat all elements as booleans (zero=false, nonzero=true).
|
||||
|
||||
/// y = At * x, treating all entries as booleans (zero=false, nonzero=true).
|
||||
/** The actual values stored in the data array, #A, are not used - this means
|
||||
and that all entries in the sparsity pattern are considered to be true by
|
||||
this method. */
|
||||
void BooleanMultTranspose(const Array<int> &x, Array<int> &y) const;
|
||||
|
||||
/// Compute y^t A x
|
||||
@@ -452,11 +504,11 @@ SparseMatrix *Transpose(const SparseMatrix &A);
|
||||
SparseMatrix *TransposeAbstractSparseMatrix (const AbstractSparseMatrix &A,
|
||||
int useActualWidth);
|
||||
|
||||
/** Matrix product A.B.
|
||||
If OAB is not NULL, we assume it has the structure
|
||||
of A.B and store the result in OAB.
|
||||
If OAB is NULL, we create a new SparseMatrix to store
|
||||
/// Matrix product A.B.
|
||||
/** If @a OAB is not NULL, we assume it has the structure of A.B and store the
|
||||
result in @a OAB. If @a OAB is NULL, we create a new SparseMatrix to store
|
||||
the result and return a pointer to it.
|
||||
|
||||
All matrices must be finalized. */
|
||||
SparseMatrix *Mult(const SparseMatrix &A, const SparseMatrix &B,
|
||||
SparseMatrix *OAB = NULL);
|
||||
@@ -555,16 +607,20 @@ inline void SparseMatrix::SetColPtr(const int row) const
|
||||
inline void SparseMatrix::ClearColPtr() const
|
||||
{
|
||||
if (Rows)
|
||||
{
|
||||
for (RowNode *node_p = Rows[current_row]; node_p != NULL;
|
||||
node_p = node_p->Prev)
|
||||
{
|
||||
ColPtrNode[node_p->Column] = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = I[current_row], end = I[current_row+1]; j < end; j++)
|
||||
{
|
||||
ColPtrJ[J[j]] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline double &SparseMatrix::SearchRow(const int col)
|
||||
|
||||
+9
-9
@@ -857,11 +857,11 @@ static double cuVectorMin(const int N, const double *X)
|
||||
const int bytes = min_sz*sizeof(double);
|
||||
static double *h_min = NULL;
|
||||
if (!h_min) { h_min = (double*)calloc(min_sz,sizeof(double)); }
|
||||
static CUdeviceptr gdsr = (CUdeviceptr) NULL;
|
||||
if (!gdsr) { ::cuMemAlloc(&gdsr,bytes); }
|
||||
static void *gdsr = NULL;
|
||||
if (!gdsr) { MFEM_CUDA_CHECK(cudaMalloc(&gdsr, bytes)); }
|
||||
cuKernelMin<<<gridSize,blockSize>>>(N, (double*)gdsr, x);
|
||||
MFEM_CUDA_CHECK_RT(cudaGetLastError());
|
||||
::cuMemcpy((CUdeviceptr)h_min,(CUdeviceptr)gdsr,bytes);
|
||||
MFEM_CUDA_CHECK(cudaGetLastError());
|
||||
MFEM_CUDA_CHECK(cudaMemcpy(h_min, gdsr, bytes, cudaMemcpyDeviceToHost));
|
||||
double min = std::numeric_limits<double>::infinity();
|
||||
for (int i = 0; i < min_sz; i++) { min = fmin(min, h_min[i]); }
|
||||
return min;
|
||||
@@ -909,19 +909,19 @@ static double cuVectorDot(const int N, const double *X, const double *Y)
|
||||
if (h_dot) { free(h_dot); }
|
||||
h_dot = (double*)calloc(dot_sz,sizeof(double));
|
||||
}
|
||||
static CUdeviceptr gdsr = (CUdeviceptr) NULL;
|
||||
static void *gdsr = NULL;
|
||||
if (!gdsr or dot_block_sz!=dot_sz)
|
||||
{
|
||||
if (gdsr) { MFEM_CUDA_CHECK_DRV(::cuMemFree(gdsr)); }
|
||||
MFEM_CUDA_CHECK_DRV(::cuMemAlloc(&gdsr,bytes));
|
||||
if (gdsr) { MFEM_CUDA_CHECK(cudaFree(gdsr)); }
|
||||
MFEM_CUDA_CHECK(cudaMalloc(&gdsr,bytes));
|
||||
}
|
||||
if (dot_block_sz!=dot_sz)
|
||||
{
|
||||
dot_block_sz = dot_sz;
|
||||
}
|
||||
cuKernelDot<<<gridSize,blockSize>>>(N, (double*)gdsr, x, y);
|
||||
MFEM_CUDA_CHECK_RT(cudaGetLastError());
|
||||
MFEM_CUDA_CHECK_DRV(::cuMemcpy((CUdeviceptr)h_dot,(CUdeviceptr)gdsr,bytes));
|
||||
MFEM_CUDA_CHECK(cudaGetLastError());
|
||||
MFEM_CUDA_CHECK(cudaMemcpy(h_dot, gdsr, bytes, cudaMemcpyDeviceToHost));
|
||||
double dot = 0.0;
|
||||
for (int i = 0; i < dot_sz; i++) { dot += h_dot[i]; }
|
||||
return dot;
|
||||
|
||||
@@ -211,6 +211,9 @@ ifneq ($(MFEM_USE_CUDA),YES)
|
||||
XCOMPILER = $(CXX_XCOMPILER)
|
||||
XLINKER = $(CXX_XLINKER)
|
||||
else
|
||||
ifneq ($(MFEM_USE_MM),YES)
|
||||
$(error MFEM_USE_CUDA=YES requires MFEM_USE_MM=YES)
|
||||
endif
|
||||
MFEM_CXX ?= $(CUDA_CXX)
|
||||
CXXFLAGS += $(CUDA_FLAGS) -ccbin $(CXX_OR_MPICXX)
|
||||
XCOMPILER = $(CUDA_XCOMPILER)
|
||||
@@ -230,7 +233,7 @@ endif
|
||||
|
||||
# List of MFEM dependencies, that require the *_LIB variable to be non-empty
|
||||
MFEM_REQ_LIB_DEPS = SUPERLU METIS CONDUIT SIDRE LAPACK SUNDIALS MESQUITE\
|
||||
SUITESPARSE STRUMPACK GECKO GNUTLS NETCDF PETSC MPFR PUMI CUDA OCCA RAJA
|
||||
SUITESPARSE STRUMPACK GECKO GNUTLS NETCDF PETSC MPFR PUMI OCCA RAJA
|
||||
PETSC_ERROR_MSG = $(if $(PETSC_FOUND),,. PETSC config not found: $(PETSC_VARS))
|
||||
|
||||
define mfem_check_dependency
|
||||
@@ -246,7 +249,7 @@ ifeq ($(MAKECMDGOALS),config)
|
||||
endif
|
||||
|
||||
# List of MFEM dependencies, processed below
|
||||
MFEM_DEPENDENCIES = $(MFEM_REQ_LIB_DEPS) LIBUNWIND OPENMP
|
||||
MFEM_DEPENDENCIES = $(MFEM_REQ_LIB_DEPS) LIBUNWIND OPENMP CUDA
|
||||
|
||||
# List of deprecated MFEM dependencies, processed below
|
||||
MFEM_LEGACY_DEPENDENCIES = OPENMP
|
||||
@@ -319,8 +322,8 @@ MFEM_TEST_MK ?= @MFEM_DIR@/config/test.mk
|
||||
# Use "\n" (interpreted by sed) to add a newline.
|
||||
MFEM_CONFIG_EXTRA ?= $(if $(BUILD_DIR_DEF),MFEM_BUILD_DIR ?= @MFEM_DIR@,)
|
||||
|
||||
MFEM_SOURCE_DIR := $(MFEM_REAL_DIR)
|
||||
MFEM_INSTALL_DIR := $(BUILD_REAL_DIR)
|
||||
MFEM_SOURCE_DIR = $(MFEM_REAL_DIR)
|
||||
MFEM_INSTALL_DIR = $(abspath $(MFEM_PREFIX))
|
||||
|
||||
# If we have 'config' target, export variables used by config/makefile
|
||||
ifneq (,$(filter config,$(MAKECMDGOALS)))
|
||||
@@ -344,6 +347,11 @@ ifneq (,$(filter install,$(MAKECMDGOALS)))
|
||||
MFEM_LIBS = $(if $(shared),$(INSTALL_RPATH)) -L@MFEM_LIB_DIR@ -lmfem\
|
||||
@MFEM_EXT_LIBS@
|
||||
MFEM_LIB_FILE = @MFEM_LIB_DIR@/libmfem.$(if $(shared),$(SO_VER),a)
|
||||
ifeq ($(MFEM_USE_OCCA),YES)
|
||||
ifneq ($(MFEM_INSTALL_DIR),$(abspath $(PREFIX))
|
||||
$(error OCCA is enabled: PREFIX must be set during configuration!)
|
||||
endif
|
||||
endif
|
||||
MFEM_PREFIX := $(abspath $(PREFIX))
|
||||
MFEM_INC_DIR = $(abspath $(PREFIX_INC))
|
||||
MFEM_LIB_DIR = $(abspath $(PREFIX_LIB))
|
||||
@@ -358,6 +366,7 @@ DIRS = general linalg mesh fem
|
||||
SOURCE_FILES = $(foreach dir,$(DIRS),$(wildcard $(SRC)$(dir)/*.cpp))
|
||||
RELSRC_FILES = $(patsubst $(SRC)%,%,$(SOURCE_FILES))
|
||||
OBJECT_FILES = $(patsubst $(SRC)%,$(BLD)%,$(SOURCE_FILES:.cpp=.o))
|
||||
OKL_DIRS = fem
|
||||
|
||||
.PHONY: lib all clean distclean install config status info deps serial parallel\
|
||||
debug pdebug cuda pcuda cudebug pcudebug style check test unittest\
|
||||
@@ -498,7 +507,12 @@ install: $(if $(static),$(BLD)libmfem.a) $(if $(shared),$(BLD)libmfem.$(SO_EXT))
|
||||
# install remaining includes in each subdirectory
|
||||
for dir in $(DIRS); do \
|
||||
mkdir -p $(PREFIX_INC)/mfem/$$dir && \
|
||||
$(INSTALL) -m 640 $(SRC)$$dir/*.hpp $(SRC)$$dir/*.okl $(PREFIX_INC)/mfem/$$dir; \
|
||||
$(INSTALL) -m 640 $(SRC)$$dir/*.hpp $(PREFIX_INC)/mfem/$$dir; \
|
||||
done
|
||||
# install *.okl files
|
||||
for dir in $(OKL_DIRS); do \
|
||||
mkdir -p $(PREFIX_INC)/mfem/$$dir && \
|
||||
$(INSTALL) -m 640 $(SRC)$$dir/*.okl $(PREFIX_INC)/mfem/$$dir; \
|
||||
done
|
||||
# install config.mk in $(PREFIX_SHARE)
|
||||
mkdir -p $(PREFIX_SHARE)
|
||||
|
||||
+17
-16
@@ -3090,6 +3090,23 @@ void ParMesh::Rebalance()
|
||||
" meshes.");
|
||||
}
|
||||
|
||||
// Make sure the Nodes use a ParFiniteElementSpace
|
||||
if (Nodes && dynamic_cast<ParFiniteElementSpace*>(Nodes->FESpace()) == NULL)
|
||||
{
|
||||
ParFiniteElementSpace *pfes =
|
||||
new ParFiniteElementSpace(*Nodes->FESpace(), *this);
|
||||
ParGridFunction *new_nodes = new ParGridFunction(pfes);
|
||||
*new_nodes = *Nodes;
|
||||
if (Nodes->OwnFEC())
|
||||
{
|
||||
new_nodes->MakeOwner(Nodes->OwnFEC());
|
||||
Nodes->MakeOwner(NULL); // takes away ownership of 'fec' and 'fes'
|
||||
delete Nodes->FESpace();
|
||||
}
|
||||
delete Nodes;
|
||||
Nodes = new_nodes;
|
||||
}
|
||||
|
||||
DeleteFaceNbrData();
|
||||
|
||||
pncmesh->Rebalance();
|
||||
@@ -3110,22 +3127,6 @@ void ParMesh::Rebalance()
|
||||
last_operation = Mesh::REBALANCE;
|
||||
sequence++;
|
||||
|
||||
// Make sure the Nodes use a ParFiniteElementSpace
|
||||
if (Nodes && dynamic_cast<ParFiniteElementSpace*>(Nodes->FESpace()) == NULL)
|
||||
{
|
||||
ParFiniteElementSpace *pfes =
|
||||
new ParFiniteElementSpace(*Nodes->FESpace(), *this);
|
||||
ParGridFunction *new_nodes = new ParGridFunction(pfes);
|
||||
*new_nodes = *Nodes;
|
||||
if (Nodes->OwnFEC())
|
||||
{
|
||||
new_nodes->MakeOwner(Nodes->OwnFEC());
|
||||
Nodes->MakeOwner(NULL); // takes away ownership of 'fec' and 'fes'
|
||||
delete Nodes->FESpace();
|
||||
}
|
||||
delete Nodes;
|
||||
Nodes = new_nodes;
|
||||
}
|
||||
UpdateNodes();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
# terms of the GNU Lesser General Public License (as published by the Free
|
||||
# Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
# Include the build directory where mfem.hpp and mfem-performance.hpp are.
|
||||
include_directories(BEFORE ${PROJECT_BINARY_DIR})
|
||||
# Include the top mfem source directory - needed by some tests, e.g. to
|
||||
# #include "general/text.hpp".
|
||||
include_directories(BEFORE ${PROJECT_SOURCE_DIR})
|
||||
# Include the build directory where mfem.hpp and mfem-performance.hpp are.
|
||||
include_directories(BEFORE ${PROJECT_BINARY_DIR})
|
||||
# Include the source directory for the unit tests - catch.hpp is there.
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
|
||||
@@ -12,7 +12,13 @@
|
||||
#include "mfem.hpp"
|
||||
#include "catch.hpp"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h> // rmdir
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h> // rmdir
|
||||
#else
|
||||
#include <direct.h> // _rmdir
|
||||
#define rmdir(dir) _rmdir(dir)
|
||||
#endif
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ TEST_CASE("InverseElementTransformation",
|
||||
REQUIRE( mesh_file.good() );
|
||||
|
||||
const int npts = 100; // number of random points to test
|
||||
const int min_found_pts = 94;
|
||||
const int min_found_pts = 93;
|
||||
const int rand_seed = 189548;
|
||||
srand(rand_seed);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user