Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c95789ba3c |
+1
-8
@@ -128,13 +128,6 @@ examples/amgx/sol.gf
|
||||
examples/amgx/mesh.*
|
||||
examples/amgx/sol.*
|
||||
|
||||
examples/caliper/ex1
|
||||
examples/caliper/ex1p
|
||||
examples/caliper/refined.mesh
|
||||
examples/caliper/sol.gf
|
||||
examples/caliper/mesh.*
|
||||
examples/caliper/sol.*
|
||||
|
||||
examples/ginkgo/ex1
|
||||
examples/ginkgo/refined.mesh
|
||||
examples/ginkgo/sol.gf
|
||||
@@ -307,7 +300,7 @@ miniapps/tools/convert-dc
|
||||
miniapps/tools/lor-transfer
|
||||
miniapps/tools/plor-transfer
|
||||
miniapps/tools/get-values
|
||||
miniapps/tools/tmop-check-metric
|
||||
miniapps/tools/check-tmop-metric
|
||||
miniapps/tools/tmop-metric-magnitude
|
||||
miniapps/tools/nodal-transfer
|
||||
miniapps/tools/ParaView
|
||||
|
||||
@@ -16,18 +16,10 @@ Discretization improvements
|
||||
- Introduced support for higher order non conformal Nedelec elements on
|
||||
simplices in ParMesh.
|
||||
|
||||
- Added functionality for construction of cut-surface and cut-volume
|
||||
IntegrationRules through a moment-fitting approach. The cut is specified by
|
||||
the zero level set of a Coefficient. See fem/intrules_cut.hpp and Example 38.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- The ReadCubit Genesis mesh importer has been rewritten to improve readability.
|
||||
|
||||
- Improved thread safety for global variables in the library, for example
|
||||
IntegrationRules IntRules, RefinedIntRules, GeometryRefiner
|
||||
GlobGeometryRefiner, and FiniteElement::dof2quad_array.
|
||||
|
||||
|
||||
Version 4.6, released on September 27, 2023
|
||||
===========================================
|
||||
@@ -95,8 +87,6 @@ Linear and nonlinear solvers
|
||||
|
||||
- Added HIP support to the PETSc and SUNDIALS interfaces.
|
||||
|
||||
- Efficient GPU-accelerated LOR assembly now supports surface meshes.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- Added a new H(div) solver miniapp demonstrating the use of a matrix-free
|
||||
|
||||
+6
-23
@@ -139,9 +139,10 @@ if (MFEM_USE_CUDA)
|
||||
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} ${CUDA_FLAGS}")
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
set(CUSPARSE_FOUND TRUE)
|
||||
get_target_property(CUSPARSE_LIBRARIES CUDA::cusparse LOCATION)
|
||||
set(CUSPARSE_LIBRARIES "cusparse")
|
||||
set(CUBLAS_FOUND TRUE)
|
||||
set(CUBLAS_LIBRARIES "cublas")
|
||||
endif()
|
||||
|
||||
if (XSDK_ENABLE_C)
|
||||
@@ -530,7 +531,7 @@ find_package(Threads REQUIRED)
|
||||
set(MFEM_TPLS OPENMP HYPRE LAPACK BLAS SuperLUDist STRUMPACK METIS SuiteSparse
|
||||
SUNDIALS PETSC SLEPC MUMPS AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB
|
||||
NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
|
||||
ADIOS2 CUSPARSE MKL_CPARDISO MKL_PARDISO AMGX CALIPER CODIPACK
|
||||
ADIOS2 CUBLAS CUSPARSE MKL_CPARDISO MKL_PARDISO AMGX CALIPER CODIPACK
|
||||
BENCHMARK PARELAG MPI_CXX HIP HIPSPARSE MOONOLITH BLITZ ALGOIM ENZYME)
|
||||
|
||||
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
|
||||
@@ -640,34 +641,16 @@ if (NOT ("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}"))
|
||||
foreach(Header mfem.hpp mfem-performance.hpp)
|
||||
message(STATUS
|
||||
"Writing substitute header --> \"${Header}\"")
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/${Header}.tmp"
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/${Header}"
|
||||
"// Auto-generated file.
|
||||
#define MFEM_CONFIG_FILE \"${PROJECT_BINARY_DIR}/config/_config.hpp\"
|
||||
#include \"${PROJECT_SOURCE_DIR}/${Header}\"
|
||||
")
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${PROJECT_BINARY_DIR}/${Header}.tmp"
|
||||
"${PROJECT_BINARY_DIR}/${Header}"
|
||||
)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E remove
|
||||
"${PROJECT_BINARY_DIR}/${Header}.tmp"
|
||||
)
|
||||
|
||||
# This version will be installed in the top include directory:
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/InstallHeaders/${Header}.tmp"
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/InstallHeaders/${Header}"
|
||||
"// Auto-generated file.
|
||||
#include \"mfem/${Header}\"
|
||||
")
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${PROJECT_BINARY_DIR}/InstallHeaders/${Header}.tmp"
|
||||
"${PROJECT_BINARY_DIR}/InstallHeaders/${Header}"
|
||||
)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E remove
|
||||
"${PROJECT_BINARY_DIR}/InstallHeaders/${Header}.tmp"
|
||||
)
|
||||
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -659,7 +659,8 @@ The specific libraries and their options are:
|
||||
requires the PT-Scotch and Scalapack libraries as well as ParMETIS, which
|
||||
includes METIS 5 in its distribution. Starting with STRUMPACK v2.2.0, ParMETIS
|
||||
and PT-Scotch are optional dependencies.
|
||||
The support for STRUMPACK was added in MFEM v3.3.2.
|
||||
The support for STRUMPACK was added in MFEM v3.3.2 and it requires STRUMPACK
|
||||
2.0.0 or later.
|
||||
URL: http://portal.nersc.gov/project/sparse/strumpack
|
||||
Options: STRUMPACK_OPT, STRUMPACK_LIB.
|
||||
Versions: STRUMPACK >= 3.0.0.
|
||||
|
||||
@@ -14,13 +14,9 @@
|
||||
# - HYPRE_LIBRARIES
|
||||
# - HYPRE_INCLUDE_DIRS
|
||||
# - HYPRE_VERSION
|
||||
# - HYPRE_USING_CUDA (internal)
|
||||
# - HYPRE_USING_HIP (internal)
|
||||
|
||||
if (HYPRE_FOUND)
|
||||
if (HYPRE_USING_CUDA)
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
endif()
|
||||
if (HYPRE_USING_HIP)
|
||||
find_package(rocsparse REQUIRED)
|
||||
find_package(rocrand REQUIRED)
|
||||
@@ -31,20 +27,6 @@ endif()
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(HYPRE HYPRE HYPRE_DIR "include" "HYPRE.h" "lib" "HYPRE"
|
||||
"Paths to headers required by HYPRE." "Libraries required by HYPRE."
|
||||
CHECK_BUILD HYPRE_USING_CUDA FALSE
|
||||
"
|
||||
#undef HYPRE_USING_CUDA
|
||||
#include <HYPRE_config.h>
|
||||
|
||||
#ifndef HYPRE_USING_CUDA
|
||||
#error HYPRE is built without CUDA.
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
"
|
||||
CHECK_BUILD HYPRE_USING_HIP FALSE
|
||||
"
|
||||
#undef HYPRE_USING_HIP
|
||||
@@ -75,16 +57,6 @@ if (HYPRE_FOUND AND (NOT HYPRE_VERSION))
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (HYPRE_FOUND AND HYPRE_USING_CUDA)
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
get_target_property(CUSPARSE_LIBRARIES CUDA::cusparse LOCATION)
|
||||
get_target_property(CURAND_LIBRARIES CUDA::curand LOCATION)
|
||||
list(APPEND HYPRE_LIBRARIES ${CUSPARSE_LIBRARIES} ${CURAND_LIBRARIES})
|
||||
set(HYPRE_LIBRARIES ${HYPRE_LIBRARIES} CACHE STRING
|
||||
"HYPRE libraries + dependencies." FORCE)
|
||||
message(STATUS "Updated HYPRE_LIBRARIES: ${HYPRE_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
if (HYPRE_FOUND AND HYPRE_USING_HIP)
|
||||
find_package(rocsparse REQUIRED)
|
||||
find_package(rocrand REQUIRED)
|
||||
|
||||
@@ -106,7 +106,12 @@ set(HYPRE_DIR "${MFEM_DIR}/../hypre/src/hypre" CACHE PATH
|
||||
# If hypre was compiled to depend on BLAS and LAPACK:
|
||||
# set(HYPRE_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
|
||||
# "Packages that HYPRE depends on.")
|
||||
# CUDA and HIP dependencies for HYPRE are handled in FindHYPRE.cmake.
|
||||
if (MFEM_USE_CUDA)
|
||||
# This is only necessary when hypre is built with cuda:
|
||||
set(HYPRE_REQUIRED_LIBRARIES "-lcusparse" "-lcurand" CACHE STRING
|
||||
"Libraries that HYPRE depends on.")
|
||||
endif()
|
||||
# HIP dependency for HYPRE is handled in FindHYPRE.cmake.
|
||||
|
||||
set(METIS_DIR "${MFEM_DIR}/../metis-4.0" CACHE PATH "Path to the METIS library.")
|
||||
|
||||
@@ -152,8 +157,7 @@ set(STRUMPACK_DIR "${MFEM_DIR}/../STRUMPACK-build" CACHE PATH
|
||||
# STRUMPACK may also depend on "OpenMP", depending on how it was compiled.
|
||||
# Starting with v2.2.0 of STRUMPACK, ParMETIS and Scotch are optional.
|
||||
set(STRUMPACK_REQUIRED_PACKAGES "MPI" "MPI_Fortran" "ParMETIS" "METIS"
|
||||
"Scotch/ptscotch/ptscotcherr/scotch/scotcherr"
|
||||
"ScaLAPACK" "LAPACK" "BLAS" CACHE STRING
|
||||
"ScaLAPACK" "Scotch/ptscotch/ptscotcherr/scotch/scotcherr" CACHE STRING
|
||||
"Additional packages required by STRUMPACK.")
|
||||
# If the MPI package does not find all required Fortran libraries:
|
||||
# set(STRUMPACK_REQUIRED_LIBRARIES "gfortran" "mpi_mpifh" CACHE STRING
|
||||
|
||||
+2
-3
@@ -38,14 +38,14 @@ all: header config-mk
|
||||
MPI = $(MFEM_USE_MPI:NO=)
|
||||
GHV_CXX ?= $(MFEM_CXX)
|
||||
GHV = get_hypre_version
|
||||
GHV_FLAGS = $(MFEM_CXXFLAGS) $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(HYPRE_OPT))
|
||||
GHV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(HYPRE_OPT))
|
||||
SMX = $(if $(MFEM_USE_PUMI:NO=),MFEM_USE_SIMMETRIX)
|
||||
SMX_PATH = $(PUMI_DIR)/include/gmi_sim.h
|
||||
SMX_FILE = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(SMX_PATH))
|
||||
MUMPS = $(MFEM_USE_MUMPS:NO=)
|
||||
GMV_CXX ?= $(MFEM_CXX)
|
||||
GMV = get_mumps_version
|
||||
GMV_FLAGS = $(MFEM_CXXFLAGS) $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(MUMPS_OPT))
|
||||
GMV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(MUMPS_OPT))
|
||||
|
||||
$(GHV): $(SRC)$(GHV).cpp
|
||||
$(call mfem-info, Determining HYPRE version ...)
|
||||
@@ -110,4 +110,3 @@ config-mk:
|
||||
|
||||
clean:
|
||||
rm -f $(CONFIG_HPP) $(CONFIG_MK) sample-runs-build.log
|
||||
rm -f $(GHV) $(GHV).out $(GMV) $(GMV).out
|
||||
|
||||
@@ -315,7 +315,7 @@ function extract_sample_runs()
|
||||
sruns=`grep -v "^//.* mpirun .* ${app}" "${src}" |
|
||||
grep "^//.* ${app}" |
|
||||
sed -e "s/.* ${app}/${vg_app}/g"`
|
||||
runs="${sruns}"$'\n'"${pruns}"
|
||||
runs="${sruns}${pruns}"
|
||||
if [ "$skip_gen_meshes" == "yes" ]; then
|
||||
runs=`printf "%s" "$runs" | grep -v ".* -m .*\.gen"`
|
||||
fi
|
||||
|
||||
@@ -112,7 +112,6 @@ namespace mfem {
|
||||
* - <a class="el" href="ex36p_8cpp_source.html">Example 36p</a>: parallel Proximal Galerkin FEM for the obstacle problem
|
||||
* - <a class="el" href="ex37_8cpp_source.html">Example 37</a>: Topology optimization
|
||||
* - <a class="el" href="ex37p_8cpp_source.html">Example 37p</a>: parallel topology optimization
|
||||
* - <a class="el" href="ex38_8cpp_source.html">Example 38</a>: cut-surface and cut-volume integration
|
||||
*
|
||||
* <H4>AmgX Examples</H4>
|
||||
* - Variants of Examples
|
||||
|
||||
@@ -45,12 +45,6 @@ list(APPEND ALL_EXE_SRCS
|
||||
ex37.cpp
|
||||
)
|
||||
|
||||
if(MFEM_USE_LAPACK)
|
||||
list(APPEND ALL_EXE_SRCS
|
||||
ex38.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
list(APPEND ALL_EXE_SRCS
|
||||
ex0p.cpp
|
||||
|
||||
+2
-3
@@ -262,13 +262,12 @@ int main(int argc, char *argv[])
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
if (sp_solver)
|
||||
{
|
||||
STRUMPACKSolver * strumpack = new STRUMPACKSolver(MPI_COMM_WORLD, argc, argv);
|
||||
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->SetMatching(strumpack::MatchingJob::NONE);
|
||||
strumpack->SetCompression(strumpack::CompressionType::NONE);
|
||||
strumpack->DisableMatching();
|
||||
strumpack->SetOperator(*Arow);
|
||||
strumpack->SetFromCommandLine();
|
||||
precond = strumpack;
|
||||
|
||||
+6
-5
@@ -26,12 +26,13 @@
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
/** After spatial discretization, the wave model can be written as:
|
||||
/** After spatial discretization, the conduction model can be written as:
|
||||
*
|
||||
* d^2u/dt^2 = M^{-1}(-Ku)
|
||||
*
|
||||
* where u is the vector representing the temperature, M is the mass,
|
||||
* and K is the stiffness matrix.
|
||||
* where u is the vector representing the temperature, M is the mass matrix,
|
||||
* and K is the diffusion operator with diffusivity depending on u:
|
||||
* (\kappa + \alpha u).
|
||||
*
|
||||
* Class WaveOperator represents the right-hand side of the above ODE.
|
||||
*/
|
||||
@@ -300,7 +301,7 @@ int main(int argc, char *argv[])
|
||||
Vector dudt;
|
||||
dudt_gf.GetTrueDofs(dudt);
|
||||
|
||||
// 7. Initialize the wave operator and the visualization.
|
||||
// 7. Initialize the conduction operator and the visualization.
|
||||
Array<int> ess_bdr;
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
@@ -355,7 +356,7 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
{
|
||||
sout.precision(precision);
|
||||
sout << "solution\n" << *mesh << u_gf;
|
||||
sout << "solution\n" << *mesh << dudt_gf;
|
||||
sout << "pause\n";
|
||||
sout << flush;
|
||||
cout << "GLVis visualization paused."
|
||||
|
||||
+4
-29
@@ -170,7 +170,6 @@ int main(int argc, char *argv[])
|
||||
bool herm_conv = true;
|
||||
bool slu_solver = false;
|
||||
bool mumps_solver = false;
|
||||
bool strumpack_solver = false;
|
||||
bool visualization = 1;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
@@ -201,11 +200,6 @@ int main(int argc, char *argv[])
|
||||
#ifdef MFEM_USE_MUMPS
|
||||
args.AddOption(&mumps_solver, "-mumps", "--mumps-solver", "-no-mumps",
|
||||
"--no-mumps-solver", "Use the MUMPS Solver.");
|
||||
#endif
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
args.AddOption(&strumpack_solver, "-strumpack", "--strumpack-solver",
|
||||
"-no-strumpack", "--no-strumpack-solver",
|
||||
"Use the STRUMPACK Solver.");
|
||||
#endif
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
@@ -215,14 +209,13 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.Parse();
|
||||
if (slu_solver + mumps_solver + strumpack_solver > 1)
|
||||
if (slu_solver && mumps_solver)
|
||||
{
|
||||
if (myid == 0)
|
||||
cout << "WARNING: More than one of SuperLU, MUMPS, and STRUMPACK have"
|
||||
<< " been selected, please choose only one." << endl
|
||||
cout << "WARNING: Both SuperLU and MUMPS have been selected,"
|
||||
<< " please choose either one." << endl
|
||||
<< " Defaulting to SuperLU." << endl;
|
||||
mumps_solver = false;
|
||||
strumpack_solver = false;
|
||||
}
|
||||
|
||||
if (iprob > 4) { iprob = 4; }
|
||||
@@ -481,24 +474,6 @@ int main(int argc, char *argv[])
|
||||
delete A;
|
||||
}
|
||||
#endif
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
if (!pa && strumpack_solver)
|
||||
{
|
||||
HypreParMatrix *A = Ah.As<ComplexHypreParMatrix>()->GetSystemMatrix();
|
||||
STRUMPACKRowLocMatrix SA(*A);
|
||||
STRUMPACKSolver strumpack(MPI_COMM_WORLD, argc, argv);
|
||||
strumpack.SetPrintFactorStatistics(false);
|
||||
strumpack.SetPrintSolveStatistics(false);
|
||||
strumpack.SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
|
||||
strumpack.SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
|
||||
strumpack.SetMatching(strumpack::MatchingJob::NONE);
|
||||
strumpack.SetCompression(strumpack::CompressionType::NONE);
|
||||
strumpack.SetFromCommandLine();
|
||||
strumpack.SetOperator(SA);
|
||||
strumpack.Mult(B, X);
|
||||
delete A;
|
||||
}
|
||||
#endif
|
||||
#ifdef MFEM_USE_MUMPS
|
||||
if (!pa && mumps_solver)
|
||||
{
|
||||
@@ -518,7 +493,7 @@ int main(int argc, char *argv[])
|
||||
//
|
||||
// In PML: 1/mu (abs(1/det(J) J^T J) Curl E, Curl F)
|
||||
// + omega^2 * epsilon (abs(det(J) * (J^T J)^-1) * E, F)
|
||||
if (pa || (!slu_solver && !mumps_solver && !strumpack_solver))
|
||||
if (pa || (!slu_solver && !mumps_solver))
|
||||
{
|
||||
ConstantCoefficient absomeg(pow(omega, 2) * epsilon);
|
||||
RestrictedCoefficient restr_absomeg(absomeg,attr);
|
||||
|
||||
@@ -1,696 +0,0 @@
|
||||
// MFEM Example 38
|
||||
//
|
||||
// Compile with: make ex38
|
||||
//
|
||||
// Sample runs:
|
||||
// (since all sample runs require LAPACK, the * symbol is used to exclude them
|
||||
// from the automatically generated internal MFEM tests).
|
||||
// * ex38
|
||||
// * ex38 -i volumetric1d
|
||||
// * ex38 -i surface2d
|
||||
// * ex38 -i surface2d -o 4 -r 5
|
||||
// * ex38 -i volumetric2d
|
||||
// * ex38 -i volumetric2d -o 4 -r 5
|
||||
// * ex38 -i surface3d
|
||||
// * ex38 -i surface3d -o 4 -r 5
|
||||
// * ex38 -i volumetric3d
|
||||
// * ex38 -i volumetric3d -o 4 -r 5
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to integrate
|
||||
// functions over implicit interfaces and subdomains bounded by
|
||||
// implicit interfaces.
|
||||
//
|
||||
// The quadrature rules are constructed by means of moment-fitting.
|
||||
// The interface is given by the zero isoline of a level-set
|
||||
// function ϕ and the subdomain is given as the domain where ϕ>0
|
||||
// holds. The algorithm for construction of the quadrature rules
|
||||
// was introduced by Mueller, Kummer and Oberlack [1].
|
||||
//
|
||||
// This example also showcases how to set up integrators using the
|
||||
// integration rules on implicit surfaces and subdomains.
|
||||
//
|
||||
// [1] Mueller, B., Kummer, F. and Oberlack, M. (2013) Highly accurate surface
|
||||
// and volume integration on implicit domains by means of moment-fitting.
|
||||
// Int. J. Numer. Meth. Engr. (96) 512-528. DOI:10.1002/nme.4569
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
/// @brief Integration rule the example should demonstrate
|
||||
enum class IntegrationType { Volumetric1D, Surface2D, Volumetric2D,
|
||||
Surface3D, Volumetric3D
|
||||
};
|
||||
IntegrationType itype;
|
||||
|
||||
/// @brief Level-set function defining the implicit interface
|
||||
double lvlset(const Vector& X)
|
||||
{
|
||||
switch (itype)
|
||||
{
|
||||
case IntegrationType::Volumetric1D:
|
||||
return .55 - X(0);
|
||||
case IntegrationType::Surface2D:
|
||||
return 1. - (pow(X(0), 2.) + pow(X(1), 2.));
|
||||
case IntegrationType::Volumetric2D:
|
||||
return 1. - (pow(X(0) / 1.5, 2.) + pow(X(1) / .75, 2.));
|
||||
case IntegrationType::Surface3D:
|
||||
return 1. - (pow(X(0), 2.) + pow(X(1), 2.) + pow(X(2), 2.));
|
||||
case IntegrationType::Volumetric3D:
|
||||
return 1. - (pow(X(0) / 1.5, 2.) + pow(X(1) / .75, 2.) + pow(X(2) / .5, 2.));
|
||||
default:
|
||||
return 1.;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Function that should be integrated
|
||||
double integrand(const Vector& X)
|
||||
{
|
||||
switch (itype)
|
||||
{
|
||||
case IntegrationType::Volumetric1D:
|
||||
return 1.;
|
||||
case IntegrationType::Surface2D:
|
||||
return 3. * pow(X(0), 2.) - pow(X(1), 2.);
|
||||
case IntegrationType::Volumetric2D:
|
||||
return 1.;
|
||||
case IntegrationType::Surface3D:
|
||||
return 4. - 3. * pow(X(0), 2.) + 2. * pow(X(1), 2.) - pow(X(2), 2.);
|
||||
case IntegrationType::Volumetric3D:
|
||||
return 1.;
|
||||
default:
|
||||
return 0.;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Analytic surface integral
|
||||
double Surface()
|
||||
{
|
||||
switch (itype)
|
||||
{
|
||||
case IntegrationType::Volumetric1D:
|
||||
return 1.;
|
||||
case IntegrationType::Surface2D:
|
||||
return 2. * M_PI;
|
||||
case IntegrationType::Volumetric2D:
|
||||
return 7.26633616541076;
|
||||
case IntegrationType::Surface3D:
|
||||
return 40. / 3. * M_PI;
|
||||
case IntegrationType::Volumetric3D:
|
||||
return 9.90182151329315;
|
||||
default:
|
||||
return 0.;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Analytic volume integral over subdomain with positive level-set
|
||||
double Volume()
|
||||
{
|
||||
switch (itype)
|
||||
{
|
||||
case IntegrationType::Volumetric1D:
|
||||
return .55;
|
||||
case IntegrationType::Surface2D:
|
||||
return NAN;
|
||||
case IntegrationType::Volumetric2D:
|
||||
return 9. / 8. * M_PI;
|
||||
case IntegrationType::Surface3D:
|
||||
return NAN;
|
||||
case IntegrationType::Volumetric3D:
|
||||
return 3. / 4. * M_PI;
|
||||
default:
|
||||
return 0.;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
/**
|
||||
@brief Class for surface IntegrationRule
|
||||
|
||||
This class demonstrates how IntegrationRules computed as CutIntegrationRules
|
||||
can be saved to reduce the impact by computing them from scratch each time.
|
||||
*/
|
||||
class SIntegrationRule : public IntegrationRule
|
||||
{
|
||||
protected:
|
||||
/// @brief Space Dimension of the IntegrationRule
|
||||
int dim;
|
||||
/// @brief Column-wise matrix of the quadtrature weights
|
||||
DenseMatrix Weights;
|
||||
/// @brief Column-wise matrix of the transformation weights of the normal
|
||||
DenseMatrix SurfaceWeights;
|
||||
|
||||
public:
|
||||
/**
|
||||
@brief Constructor of SIntegrationRule
|
||||
|
||||
The surface integrationRules are computed and saved in the constructor.
|
||||
|
||||
@param [in] Order Order of the IntegrationRule
|
||||
@param [in] LvlSet Level-set defining the implicit interface
|
||||
@param [in] lsOrder Polynomial degree for approx of level-set function
|
||||
@param [in] mesh Pointer to the mesh that is used
|
||||
*/
|
||||
SIntegrationRule(int Order, Coefficient& LvlSet, int lsOrder, Mesh* mesh)
|
||||
{
|
||||
dim = mesh->Dimension();
|
||||
|
||||
IsoparametricTransformation Tr;
|
||||
MomentFittingIntRules MFIRs(Order, LvlSet, lsOrder);
|
||||
mesh->GetElementTransformation(0, &Tr);
|
||||
IntegrationRule ir;
|
||||
MFIRs.GetSurfaceIntegrationRule(Tr, ir);
|
||||
if (dim >1)
|
||||
{
|
||||
Weights.SetSize(ir.GetNPoints(), mesh->GetNE());
|
||||
}
|
||||
else
|
||||
{
|
||||
Weights.SetSize(2, mesh->GetNE());
|
||||
}
|
||||
SurfaceWeights.SetSize(ir.GetNPoints(), mesh->GetNE());
|
||||
Vector w;
|
||||
MFIRs.GetSurfaceWeights(Tr, ir, w);
|
||||
SurfaceWeights.SetCol(0, w);
|
||||
SetSize(ir.GetNPoints());
|
||||
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
IntPoint(ip).index = ip;
|
||||
IntegrationPoint &intp = IntPoint(ip);
|
||||
intp.x = ir.IntPoint(ip).x;
|
||||
intp.y = ir.IntPoint(ip).y;
|
||||
intp.z = ir.IntPoint(ip).z;
|
||||
if (dim > 1)
|
||||
{
|
||||
Weights(ip, 0) = ir.IntPoint(ip).weight;
|
||||
}
|
||||
else
|
||||
{
|
||||
Weights(0, 0) = ir.IntPoint(ip).x;
|
||||
Weights(1, 0) = ir.IntPoint(ip).weight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int elem = 1; elem < mesh->GetNE(); elem++)
|
||||
{
|
||||
mesh->GetElementTransformation(elem, &Tr);
|
||||
MFIRs.GetSurfaceIntegrationRule(Tr, ir);
|
||||
Vector w;
|
||||
MFIRs.GetSurfaceWeights(Tr, ir, w);
|
||||
SurfaceWeights.SetCol(elem, w);
|
||||
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
if (dim > 1)
|
||||
{
|
||||
Weights(ip, elem) = ir.IntPoint(ip).weight;
|
||||
}
|
||||
else
|
||||
{
|
||||
Weights(0, elem) = ir.IntPoint(ip).x;
|
||||
Weights(1, elem) = ir.IntPoint(ip).weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Set the weights for the given element and multiply them with the
|
||||
transformation of the interface
|
||||
*/
|
||||
void SetElementinclSurfaceWeight(int Element)
|
||||
{
|
||||
if (dim == 1)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(0);
|
||||
intp.x = Weights(0, Element);
|
||||
intp.weight = Weights(1, Element);
|
||||
cout << intp.x << " " << Element << endl;
|
||||
}
|
||||
else
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(ip);
|
||||
intp.weight = Weights(ip, Element) * SurfaceWeights(ip, Element);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Set the weights for the given element
|
||||
void SetElement(int Element)
|
||||
{
|
||||
if (dim == 1)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(0);
|
||||
intp.x = Weights(0, Element);
|
||||
intp.weight = Weights(1, Element);
|
||||
}
|
||||
else
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(ip);
|
||||
intp.weight = Weights(ip, Element);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Destructor of SIntegrationRule
|
||||
~SIntegrationRule() {}
|
||||
};
|
||||
|
||||
/**
|
||||
@brief Class for volume IntegrationRule
|
||||
|
||||
This class demonstrates how IntegrationRules computed as CutIntegrationRules
|
||||
can be saved to reduce the impact by computing them from scratch each time.
|
||||
*/
|
||||
class CIntegrationRule : public IntegrationRule
|
||||
{
|
||||
protected:
|
||||
/// @brief Space Dimension of the IntegrationRule
|
||||
int dim;
|
||||
/// @brief Column-wise matrix of the quadtrature weights
|
||||
DenseMatrix Weights;
|
||||
|
||||
public:
|
||||
/**
|
||||
@brief Constructor of CIntegrationRule
|
||||
|
||||
The volume integrationRules are computed and saved in the constructor.
|
||||
|
||||
@param [in] Order Order of the IntegrationRule
|
||||
@param [in] LvlSet Level-set defining the implicit interface
|
||||
@param [in] lsOrder Polynomial degree for approx of level-set function
|
||||
@param [in] mesh Pointer to the mesh that is used
|
||||
*/
|
||||
CIntegrationRule(int Order, Coefficient& LvlSet, int lsOrder, Mesh* mesh)
|
||||
{
|
||||
dim = mesh->Dimension();
|
||||
|
||||
IsoparametricTransformation Tr;
|
||||
MomentFittingIntRules MFIRs(Order, LvlSet, lsOrder);
|
||||
mesh->GetElementTransformation(0, &Tr);
|
||||
IntegrationRule ir;
|
||||
MFIRs.GetVolumeIntegrationRule(Tr, ir);
|
||||
if (dim > 1)
|
||||
{
|
||||
Weights.SetSize(ir.GetNPoints(), mesh->GetNE());
|
||||
}
|
||||
else
|
||||
{
|
||||
Weights.SetSize(2 * ir.GetNPoints(), mesh->GetNE());
|
||||
}
|
||||
|
||||
SetSize(ir.GetNPoints());
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
IntPoint(ip).index = ip;
|
||||
IntegrationPoint &intp = IntPoint(ip);
|
||||
intp.x = ir.IntPoint(ip).x;
|
||||
intp.y = ir.IntPoint(ip).y;
|
||||
intp.z = ir.IntPoint(ip).z;
|
||||
if (dim > 1)
|
||||
{
|
||||
Weights(ip, 0) = ir.IntPoint(ip).weight;
|
||||
}
|
||||
else
|
||||
{
|
||||
Weights(2 * ip, 0) = ir.IntPoint(ip).x;
|
||||
Weights(2 * ip + 1, 0) = ir.IntPoint(ip).weight;
|
||||
}
|
||||
}
|
||||
|
||||
for (int elem = 1; elem < mesh->GetNE(); elem++)
|
||||
{
|
||||
mesh->GetElementTransformation(elem, &Tr);
|
||||
MFIRs.GetVolumeIntegrationRule(Tr, ir);
|
||||
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
if (dim > 1)
|
||||
{
|
||||
Weights(ip, elem) = ir.IntPoint(ip).weight;
|
||||
}
|
||||
else
|
||||
{
|
||||
Weights(2 * ip, elem) = ir.IntPoint(ip).x;
|
||||
Weights(2 * ip + 1, elem) = ir.IntPoint(ip).weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Set the weights for the given element
|
||||
void SetElement(int Element)
|
||||
{
|
||||
if (dim == 1)
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(ip);
|
||||
intp.x = Weights(2 * ip, Element);
|
||||
intp.weight = Weights(2 * ip + 1, Element);
|
||||
}
|
||||
else
|
||||
for (int ip = 0; ip < GetNPoints(); ip++)
|
||||
{
|
||||
IntegrationPoint &intp = IntPoint(ip);
|
||||
intp.weight = Weights(ip, Element);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Destructor of CIntegrationRule
|
||||
~CIntegrationRule() {}
|
||||
};
|
||||
/**
|
||||
@brief Class for surface linearform integrator
|
||||
|
||||
Integrator to demonstrate the use of the surface integration rule on an
|
||||
implicit surface defined by a level-set.
|
||||
*/
|
||||
class SurfaceLFIntegrator : public LinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
/// @brief vector to evaluate the basis functions
|
||||
Vector shape;
|
||||
|
||||
/// @brief surface integration rule
|
||||
SIntegrationRule* SIntRule;
|
||||
|
||||
/// @brief coefficient representing the level-set defining the interface
|
||||
Coefficient &LevelSet;
|
||||
|
||||
/// @brief coefficient representing the integrand
|
||||
Coefficient &Q;
|
||||
|
||||
public:
|
||||
/**
|
||||
@brief Constructor for the surface linear form integrator
|
||||
|
||||
Constructor for the surface linear form integrator to demonstrate the use
|
||||
of the surface integration rule by means of moment-fitting.
|
||||
|
||||
@param [in] q coefficient representing the inegrand
|
||||
@param [in] levelset level-set defining the implicit interfac
|
||||
@param [in] ir surface integrtion rule to be used
|
||||
*/
|
||||
SurfaceLFIntegrator(Coefficient &q, Coefficient &levelset,
|
||||
SIntegrationRule* ir)
|
||||
: LinearFormIntegrator(), SIntRule(ir), LevelSet(levelset), Q(q) { }
|
||||
|
||||
/**
|
||||
@brief Assembly of the element vector
|
||||
|
||||
Assemble the element vector of for the right hand side on the element given
|
||||
by the FiniteElement and ElementTransformation.
|
||||
|
||||
@param [in] el finite Element the vector belongs to
|
||||
@param [in] Tr transformation of finite element
|
||||
@param [out] elvect vector containing the
|
||||
*/
|
||||
virtual void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
Vector &elvect) override
|
||||
{
|
||||
int dof = el.GetDof();
|
||||
shape.SetSize(dof);
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.;
|
||||
|
||||
// Update the surface integration rule for the current element
|
||||
SIntRule->SetElementinclSurfaceWeight(Tr.ElementNo);
|
||||
|
||||
for (int ip = 0; ip < SIntRule->GetNPoints(); ip++)
|
||||
{
|
||||
Tr.SetIntPoint((&(SIntRule->IntPoint(ip))));
|
||||
double val = Tr.Weight() * Q.Eval(Tr, SIntRule->IntPoint(ip));
|
||||
el.CalcShape(SIntRule->IntPoint(ip), shape);
|
||||
add(elvect, SIntRule->IntPoint(ip).weight * val, shape, elvect);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@brief Class for subdomain linearform integrator
|
||||
|
||||
Integrator to demonstrate the use of the subdomain integration rule within
|
||||
an area defined by an implicit surface defined by a level-set.
|
||||
*/
|
||||
class SubdomainLFIntegrator : public LinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
/// @brief vector to evaluate the basis functions
|
||||
Vector shape;
|
||||
|
||||
/// @brief surface integration rule
|
||||
CIntegrationRule* CIntRule;
|
||||
|
||||
/// @brief coefficient representing the level-set defining the interface
|
||||
Coefficient &LevelSet;
|
||||
|
||||
/// @brief coefficient representing the integrand
|
||||
Coefficient &Q;
|
||||
|
||||
public:
|
||||
/**
|
||||
@brief Constructor for the volumetric subdomain linear form integrator
|
||||
|
||||
Constructor for the subdomain linear form integrator to demonstrate the use
|
||||
of the volumetric subdomain integration rule by means of moment-fitting.
|
||||
|
||||
@param [in] q coefficient representing the inegrand
|
||||
@param [in] levelset level-set defining the implicit interfac
|
||||
@param [in] ir subdomain integrtion rule to be used
|
||||
*/
|
||||
SubdomainLFIntegrator(Coefficient &q, Coefficient &levelset,
|
||||
CIntegrationRule* ir)
|
||||
: LinearFormIntegrator(), CIntRule(ir), LevelSet(levelset), Q(q) { }
|
||||
|
||||
/**
|
||||
@brief Assembly of the element vector
|
||||
|
||||
Assemble the element vector of for the right hand side on the element given
|
||||
by the FiniteElement and ElementTransformation.
|
||||
|
||||
@param [in] el finite Element the vector belongs to
|
||||
@param [in] Tr transformation of finite element
|
||||
@param [out] elvect vector containing the
|
||||
*/
|
||||
virtual void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
Vector &elvect) override
|
||||
{
|
||||
int dof = el.GetDof();
|
||||
shape.SetSize(dof);
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.;
|
||||
|
||||
// Update the subdomain integration rule
|
||||
CIntRule->SetElement(Tr.ElementNo);
|
||||
|
||||
for (int ip = 0; ip < CIntRule->GetNPoints(); ip++)
|
||||
{
|
||||
Tr.SetIntPoint((&(CIntRule->IntPoint(ip))));
|
||||
double val = Tr.Weight()
|
||||
* Q.Eval(Tr, CIntRule->IntPoint(ip));
|
||||
el.CalcPhysShape(Tr, shape);
|
||||
add(elvect, CIntRule->IntPoint(ip).weight * val, shape, elvect);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // MFEM_USE_LAPACK
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifndef MFEM_USE_LAPACK
|
||||
cout << "MFEM must be build with LAPACK for this example." << endl;
|
||||
return EXIT_FAILURE;
|
||||
#else
|
||||
// 1. Parse he command-line options.
|
||||
int ref_levels = 3;
|
||||
int order = 2;
|
||||
const char *inttype = "surface2d";
|
||||
bool visualization = true;
|
||||
itype = IntegrationType::Surface2D;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&order, "-o", "--order", "Order of quadrature rule");
|
||||
args.AddOption(&ref_levels, "-r", "--refine", "Number of meh refinements");
|
||||
args.AddOption(&inttype, "-i", "--integrationtype",
|
||||
"IntegrationType to demonstrate");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.ParseCheck();
|
||||
|
||||
if (strcmp(inttype, "volumetric1d") == 0
|
||||
|| strcmp(inttype, "Volumetric1D") == 0)
|
||||
{
|
||||
itype = IntegrationType::Volumetric1D;
|
||||
}
|
||||
else if (strcmp(inttype, "surface2d") == 0
|
||||
|| strcmp(inttype, "Surface2D") == 0)
|
||||
{
|
||||
itype = IntegrationType::Surface2D;
|
||||
}
|
||||
else if (strcmp(inttype, "volumetric2d") == 0
|
||||
|| strcmp(inttype, "Volumetric2D") == 0)
|
||||
{
|
||||
itype = IntegrationType::Volumetric2D;
|
||||
}
|
||||
else if (strcmp(inttype, "surface3d") == 0
|
||||
|| strcmp(inttype, "Surface3d") == 0)
|
||||
{
|
||||
itype = IntegrationType::Surface3D;
|
||||
}
|
||||
else if (strcmp(inttype, "volumetric3d") == 0
|
||||
|| strcmp(inttype, "Volumetric3d") == 0)
|
||||
{
|
||||
itype = IntegrationType::Volumetric3D;
|
||||
}
|
||||
|
||||
// 2. Construct and refine the mesh.
|
||||
Mesh *mesh;
|
||||
if (itype == IntegrationType::Volumetric1D)
|
||||
{
|
||||
mesh = new Mesh("../data/inline-segment.mesh");
|
||||
}
|
||||
if (itype == IntegrationType::Surface2D
|
||||
|| itype == IntegrationType::Volumetric2D)
|
||||
{
|
||||
mesh = new Mesh(2, 4, 1, 0, 2);
|
||||
mesh->AddVertex(-1.6,-1.6);
|
||||
mesh->AddVertex(1.6,-1.6);
|
||||
mesh->AddVertex(1.6,1.6);
|
||||
mesh->AddVertex(-1.6,1.6);
|
||||
mesh->AddQuad(0,1,2,3);
|
||||
mesh->FinalizeQuadMesh(1, 0, 1);
|
||||
}
|
||||
else if (itype == IntegrationType::Surface3D
|
||||
|| itype == IntegrationType::Volumetric3D)
|
||||
{
|
||||
mesh = new Mesh(3, 8, 1, 0, 3);
|
||||
mesh->AddVertex(-1.6,-1.6,-1.6);
|
||||
mesh->AddVertex(1.6,-1.6,-1.6);
|
||||
mesh->AddVertex(1.6,1.6,-1.6);
|
||||
mesh->AddVertex(-1.6,1.6,-1.6);
|
||||
mesh->AddVertex(-1.6,-1.6,1.6);
|
||||
mesh->AddVertex(1.6,-1.6,1.6);
|
||||
mesh->AddVertex(1.6,1.6,1.6);
|
||||
mesh->AddVertex(-1.6,1.6,1.6);
|
||||
mesh->AddHex(0,1,2,3,4,5,6,7);
|
||||
mesh->FinalizeHexMesh(1, 0, 1);
|
||||
}
|
||||
|
||||
for (int lev = 0; lev < ref_levels; lev++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 3. Define the necessary finite element space on the mesh.
|
||||
H1_FECollection fe_coll(1, mesh->Dimension());
|
||||
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, &fe_coll);
|
||||
|
||||
// 4. Construction Coefficients for the level set and the integrand.
|
||||
FunctionCoefficient levelset(lvlset);
|
||||
FunctionCoefficient u(integrand);
|
||||
|
||||
// 5. Define the necessary Integration rules on element 0.
|
||||
IsoparametricTransformation Tr;
|
||||
mesh->GetElementTransformation(0, &Tr);
|
||||
SIntegrationRule* sir = new SIntegrationRule(order, levelset, 2, mesh);
|
||||
CIntegrationRule* cir = NULL;
|
||||
if (itype == IntegrationType::Volumetric1D
|
||||
|| itype == IntegrationType::Volumetric2D
|
||||
|| itype == IntegrationType::Volumetric3D)
|
||||
{
|
||||
cir = new CIntegrationRule(order, levelset, 2, mesh);
|
||||
}
|
||||
|
||||
// 6. Define and assemble the linear forms on the finite element space.
|
||||
LinearForm surface(fespace);
|
||||
LinearForm volume(fespace);
|
||||
|
||||
surface.AddDomainIntegrator(new SurfaceLFIntegrator(u, levelset, sir));
|
||||
surface.Assemble();
|
||||
|
||||
if (itype == IntegrationType::Volumetric1D
|
||||
|| itype == IntegrationType::Volumetric2D
|
||||
|| itype == IntegrationType::Volumetric3D)
|
||||
{
|
||||
volume.AddDomainIntegrator(new SubdomainLFIntegrator(u, levelset, cir));
|
||||
volume.Assemble();
|
||||
}
|
||||
|
||||
// 7. Print information, computed values and errors to the console.
|
||||
int qorder = 0;
|
||||
int nbasis = 2 * (order + 1) + (int)(order * (order + 1) / 2);
|
||||
IntegrationRules irs(0, Quadrature1D::GaussLegendre);
|
||||
IntegrationRule ir = irs.Get(Geometry::SQUARE, qorder);
|
||||
for (; ir.GetNPoints() <= nbasis; qorder++)
|
||||
{
|
||||
ir = irs.Get(Geometry::SQUARE, qorder);
|
||||
}
|
||||
cout << "============================================" << endl;
|
||||
cout << "Mesh size dx: ";
|
||||
if (itype != IntegrationType::Volumetric1D)
|
||||
{
|
||||
cout << 3.2 / pow(2., (double)ref_levels) << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << .25 / pow(2., (double)ref_levels) << endl;
|
||||
}
|
||||
if (itype == IntegrationType::Surface2D
|
||||
|| itype == IntegrationType::Volumetric2D)
|
||||
{
|
||||
cout << "Number of div free basis functions: " << nbasis << endl;
|
||||
cout << "Number of quadrature points: " << ir.GetNPoints() << endl;
|
||||
}
|
||||
cout << scientific << setprecision(2);
|
||||
cout << "============================================" << endl;
|
||||
cout << "Computed value of surface integral: " << surface.Sum() << endl;
|
||||
cout << "True value of surface integral: " << Surface() << endl;
|
||||
cout << "Absolut Error (Surface): ";
|
||||
cout << abs(surface.Sum() - Surface()) << endl;
|
||||
cout << "Relative Error (Surface): ";
|
||||
cout << abs(surface.Sum() - Surface()) / Surface() << endl;
|
||||
if (itype == IntegrationType::Volumetric1D
|
||||
|| itype == IntegrationType::Volumetric2D
|
||||
|| itype == IntegrationType::Volumetric3D)
|
||||
{
|
||||
cout << "--------------------------------------------" << endl;
|
||||
cout << "Computed value of volume integral: " << volume.Sum() << endl;
|
||||
cout << "True value of volume integral: " << Volume() << endl;
|
||||
cout << "Absolut Error (Volume): ";
|
||||
cout << abs(volume.Sum() - Volume()) << endl;
|
||||
cout << "Relative Error (Volume): ";
|
||||
cout << abs(volume.Sum() - Volume()) / Volume() << endl;
|
||||
}
|
||||
cout << "============================================" << endl;
|
||||
|
||||
// 8. Plot the level-set function on a high order finite element space.
|
||||
if (visualization)
|
||||
{
|
||||
H1_FECollection fe_coll2(5, mesh->Dimension());
|
||||
FiniteElementSpace fespace2(mesh, &fe_coll2);
|
||||
FunctionCoefficient levelset_coeff(levelset);
|
||||
GridFunction lgf(&fespace2);
|
||||
lgf.ProjectCoefficient(levelset_coeff);
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *mesh << lgf << flush;
|
||||
sol_sock << "keys pppppppppppppppppppppppppppcmmlRj\n";
|
||||
sol_sock << "levellines " << 0. << " " << 0. << " " << 1 << "\n" << flush;
|
||||
}
|
||||
|
||||
delete sir;
|
||||
delete cir;
|
||||
delete fespace;
|
||||
delete mesh;
|
||||
return EXIT_SUCCESS;
|
||||
#endif //MFEM_USE_LAPACK
|
||||
}
|
||||
+23
-23
@@ -3,28 +3,28 @@
|
||||
//
|
||||
// Compile with: make ex1
|
||||
//
|
||||
// Sample runs: ex1 -m ../../data/square-disc.mesh
|
||||
// ex1 -m ../../data/star.mesh
|
||||
// ex1 -m ../../data/star-mixed.mesh
|
||||
// ex1 -m ../../data/escher.mesh
|
||||
// ex1 -m ../../data/fichera.mesh
|
||||
// ex1 -m ../../data/fichera-mixed.mesh
|
||||
// ex1 -m ../../data/toroid-wedge.mesh
|
||||
// ex1 -m ../../data/square-disc-p2.vtk -o 2
|
||||
// ex1 -m ../../data/square-disc-p3.mesh -o 3
|
||||
// ex1 -m ../../data/square-disc-nurbs.mesh -o -1
|
||||
// ex1 -m ../../data/star-mixed-p2.mesh -o 2
|
||||
// ex1 -m ../../data/disc-nurbs.mesh -o -1
|
||||
// ex1 -m ../../data/pipe-nurbs.mesh -o -1
|
||||
// ex1 -m ../../data/fichera-mixed-p2.mesh -o 2
|
||||
// ex1 -m ../../data/star-surf.mesh
|
||||
// ex1 -m ../../data/square-disc-surf.mesh
|
||||
// ex1 -m ../../data/inline-segment.mesh
|
||||
// ex1 -m ../../data/amr-quad.mesh
|
||||
// ex1 -m ../../data/amr-hex.mesh
|
||||
// ex1 -m ../../data/fichera-amr.mesh
|
||||
// ex1 -m ../../data/mobius-strip.mesh
|
||||
// ex1 -m ../../data/mobius-strip.mesh -o -1 -sc
|
||||
// Sample runs: ex1 -m ../data/square-disc.mesh
|
||||
// ex1 -m ../data/star.mesh
|
||||
// ex1 -m ../data/star-mixed.mesh
|
||||
// ex1 -m ../data/escher.mesh
|
||||
// ex1 -m ../data/fichera.mesh
|
||||
// ex1 -m ../data/fichera-mixed.mesh
|
||||
// ex1 -m ../data/toroid-wedge.mesh
|
||||
// ex1 -m ../data/square-disc-p2.vtk -o 2
|
||||
// ex1 -m ../data/square-disc-p3.mesh -o 3
|
||||
// ex1 -m ../data/square-disc-nurbs.mesh -o -1
|
||||
// ex1 -m ../data/star-mixed-p2.mesh -o 2
|
||||
// ex1 -m ../data/disc-nurbs.mesh -o -1
|
||||
// ex1 -m ../data/pipe-nurbs.mesh -o -1
|
||||
// ex1 -m ../data/fichera-mixed-p2.mesh -o 2
|
||||
// ex1 -m ../data/star-surf.mesh
|
||||
// ex1 -m ../data/square-disc-surf.mesh
|
||||
// ex1 -m ../data/inline-segment.mesh
|
||||
// ex1 -m ../data/amr-quad.mesh
|
||||
// ex1 -m ../data/amr-hex.mesh
|
||||
// ex1 -m ../data/fichera-amr.mesh
|
||||
// ex1 -m ../data/mobius-strip.mesh
|
||||
// ex1 -m ../data/mobius-strip.mesh -o -1 -sc
|
||||
//
|
||||
// Device sample runs:
|
||||
// ex1 -pa -d cuda
|
||||
@@ -32,7 +32,7 @@
|
||||
// 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 -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
|
||||
|
||||
+6
-10
@@ -22,19 +22,15 @@ MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
SEQ_EXAMPLES = ex0 ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 \
|
||||
ex17 ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex28 ex29 ex30 \
|
||||
ex31 ex33 ex34 ex36 ex37
|
||||
ex17 ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex28 ex29 ex30 \
|
||||
ex31 ex33 ex34 ex36 ex37
|
||||
PAR_EXAMPLES = ex0p ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p \
|
||||
ex12p ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p \
|
||||
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p ex34p ex35p ex36p \
|
||||
ex37p
|
||||
ex12p ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p \
|
||||
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p ex34p ex35p ex36p \
|
||||
ex37p
|
||||
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
|
||||
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p \
|
||||
ex24p ex25p ex26p ex34p ex35p
|
||||
|
||||
ifeq ($(MFEM_USE_LAPACK),YES)
|
||||
SEQ_EXAMPLES += ex38
|
||||
endif
|
||||
ex24p ex25p ex26p ex34p ex35p
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
EXAMPLES = $(SEQ_EXAMPLES)
|
||||
|
||||
@@ -273,13 +273,12 @@ int main(int argc, char *argv[])
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
if (sp_solver)
|
||||
{
|
||||
STRUMPACKSolver * strumpack = new STRUMPACKSolver(MPI_COMM_WORLD, argc, argv);
|
||||
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->SetMatching(strumpack::MatchingJob::NONE);
|
||||
strumpack->SetCompression(strumpack::CompressionType::NONE);
|
||||
strumpack->DisableMatching();
|
||||
strumpack->SetOperator(*Arow);
|
||||
strumpack->SetFromCommandLine();
|
||||
precond = strumpack;
|
||||
|
||||
+3
-2
@@ -77,7 +77,6 @@ set(SRCS
|
||||
gridfunc.cpp
|
||||
hybridization.cpp
|
||||
intrules.cpp
|
||||
intrules_cut.cpp
|
||||
ceed/interface/basis.cpp
|
||||
ceed/interface/restriction.cpp
|
||||
ceed/interface/operator.cpp
|
||||
@@ -97,6 +96,9 @@ set(SRCS
|
||||
lor/lor_ads.cpp
|
||||
lor/lor_ams.cpp
|
||||
lor/lor_batched.cpp
|
||||
lor/lor_h1.cpp
|
||||
lor/lor_nd.cpp
|
||||
lor/lor_rt.cpp
|
||||
multigrid.cpp
|
||||
nonlinearform.cpp
|
||||
nonlinearform_ext.cpp
|
||||
@@ -184,7 +186,6 @@ set(HDRS
|
||||
gridfunc.hpp
|
||||
hybridization.hpp
|
||||
intrules.hpp
|
||||
intrules_cut.hpp
|
||||
ceed/interface/basis.hpp
|
||||
ceed/interface/integrator.hpp
|
||||
ceed/interface/interface.hpp
|
||||
|
||||
+41
-84
@@ -101,7 +101,6 @@ BilinearForm::BilinearForm (FiniteElementSpace * f, BilinearForm * bf, int ps)
|
||||
|
||||
// Copy the pointers to the integrators
|
||||
domain_integs = bf->domain_integs;
|
||||
domain_integs_marker = bf->domain_integs_marker;
|
||||
|
||||
boundary_integs = bf->boundary_integs;
|
||||
boundary_integs_marker = bf->boundary_integs_marker;
|
||||
@@ -434,6 +433,7 @@ void BilinearForm::Assemble(int skip_zeros)
|
||||
// Element-wise integration
|
||||
for (int i = 0; i < fes -> GetNE(); i++)
|
||||
{
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
if (element_matrices)
|
||||
{
|
||||
elmat_p = &(*element_matrices)(i);
|
||||
@@ -441,9 +441,6 @@ void BilinearForm::Assemble(int skip_zeros)
|
||||
else
|
||||
{
|
||||
const int elem_attr = fes->GetMesh()->GetAttribute(i);
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
eltrans = fes->GetElementTransformation(i);
|
||||
|
||||
elmat.SetSize(0);
|
||||
for (int k = 0; k < domain_integs.Size(); k++)
|
||||
{
|
||||
@@ -451,8 +448,9 @@ void BilinearForm::Assemble(int skip_zeros)
|
||||
(*(domain_integs_marker[k]))[elem_attr-1] == 1)
|
||||
&& !domain_integs[k]->Patchwise())
|
||||
{
|
||||
domain_integs[k]->AssembleElementMatrix(*fes->GetFE(i),
|
||||
*eltrans, elemmat);
|
||||
const FiniteElement &fe = *fes->GetFE(i);
|
||||
eltrans = fes->GetElementTransformation(i);
|
||||
domain_integs[k]->AssembleElementMatrix(fe, *eltrans, elemmat);
|
||||
if (elmat.Size() == 0)
|
||||
{
|
||||
elmat = elemmat;
|
||||
@@ -1224,14 +1222,11 @@ MixedBilinearForm::MixedBilinearForm (FiniteElementSpace *tr_fes,
|
||||
|
||||
// Copy the pointers to the integrators
|
||||
domain_integs = mbf->domain_integs;
|
||||
domain_integs_marker = mbf->domain_integs_marker;
|
||||
|
||||
boundary_integs = mbf->boundary_integs;
|
||||
boundary_integs_marker = mbf->boundary_integs_marker;
|
||||
|
||||
trace_face_integs = mbf->trace_face_integs;
|
||||
|
||||
boundary_trace_face_integs = mbf->boundary_trace_face_integs;
|
||||
|
||||
boundary_integs_marker = mbf->boundary_integs_marker;
|
||||
boundary_trace_face_integs_marker = mbf->boundary_trace_face_integs_marker;
|
||||
|
||||
assembly = AssemblyLevel::LEGACY;
|
||||
@@ -1354,14 +1349,6 @@ void MixedBilinearForm::GetBlocks(Array2D<SparseMatrix *> &blocks) const
|
||||
void MixedBilinearForm::AddDomainIntegrator (BilinearFormIntegrator * bfi)
|
||||
{
|
||||
domain_integs.Append (bfi);
|
||||
domain_integs_marker.Append(NULL); // NULL marker means apply everywhere
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddDomainIntegrator (BilinearFormIntegrator * bfi,
|
||||
Array<int> &elem_marker)
|
||||
{
|
||||
domain_integs.Append (bfi);
|
||||
domain_integs_marker.Append(&elem_marker);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::AddBoundaryIntegrator (BilinearFormIntegrator * bfi)
|
||||
@@ -1396,7 +1383,7 @@ void MixedBilinearForm::AddBdrTraceFaceIntegrator(BilinearFormIntegrator *bfi,
|
||||
boundary_trace_face_integs_marker.Append(&bdr_marker);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::Assemble(int skip_zeros)
|
||||
void MixedBilinearForm::Assemble (int skip_zeros)
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
@@ -1418,20 +1405,8 @@ void MixedBilinearForm::Assemble(int skip_zeros)
|
||||
|
||||
if (domain_integs.Size())
|
||||
{
|
||||
for (int k = 0; k < domain_integs.Size(); k++)
|
||||
{
|
||||
if (domain_integs_marker[k] != NULL)
|
||||
{
|
||||
MFEM_VERIFY(domain_integs_marker[k]->Size() ==
|
||||
(mesh->attributes.Size() ? mesh->attributes.Max() : 0),
|
||||
"invalid element marker for domain integrator #"
|
||||
<< k << ", counting from zero");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < test_fes -> GetNE(); i++)
|
||||
{
|
||||
const int elem_attr = mesh->GetAttribute(i);
|
||||
dom_dof_trans = trial_fes -> GetElementVDofs (i, trial_vdofs);
|
||||
ran_dof_trans = test_fes -> GetElementVDofs (i, test_vdofs);
|
||||
eltrans = test_fes -> GetElementTransformation (i);
|
||||
@@ -1440,14 +1415,10 @@ void MixedBilinearForm::Assemble(int skip_zeros)
|
||||
elmat = 0.0;
|
||||
for (int k = 0; k < domain_integs.Size(); k++)
|
||||
{
|
||||
if (domain_integs_marker[k] == NULL ||
|
||||
(*(domain_integs_marker[k]))[elem_attr-1] == 1)
|
||||
{
|
||||
domain_integs[k] -> AssembleElementMatrix2 (*trial_fes -> GetFE(i),
|
||||
*test_fes -> GetFE(i),
|
||||
*eltrans, elemmat);
|
||||
elmat += elemmat;
|
||||
}
|
||||
domain_integs[k] -> AssembleElementMatrix2 (*trial_fes -> GetFE(i),
|
||||
*test_fes -> GetFE(i),
|
||||
*eltrans, elemmat);
|
||||
elmat += elemmat;
|
||||
}
|
||||
if (ran_dof_trans || dom_dof_trans)
|
||||
{
|
||||
@@ -1970,56 +1941,41 @@ void DiscreteLinearOperator::Assemble(int skip_zeros)
|
||||
return;
|
||||
}
|
||||
|
||||
ElementTransformation *eltrans;
|
||||
Array<int> dom_vdofs, ran_vdofs;
|
||||
ElementTransformation *T;
|
||||
DofTransformation * dom_dof_trans;
|
||||
DofTransformation * ran_dof_trans;
|
||||
DenseMatrix elmat;
|
||||
|
||||
Mesh *mesh = test_fes->GetMesh();
|
||||
const FiniteElement *dom_fe, *ran_fe;
|
||||
DenseMatrix totelmat, elmat;
|
||||
|
||||
if (mat == NULL)
|
||||
{
|
||||
mat = new SparseMatrix(height, width);
|
||||
}
|
||||
|
||||
if (domain_integs.Size())
|
||||
if (domain_integs.Size() > 0)
|
||||
{
|
||||
for (int k = 0; k < domain_integs.Size(); k++)
|
||||
{
|
||||
if (domain_integs_marker[k] != NULL)
|
||||
{
|
||||
MFEM_VERIFY(domain_integs_marker[k]->Size() ==
|
||||
(mesh->attributes.Size() ? mesh->attributes.Max() : 0),
|
||||
"invalid element marker for domain integrator #"
|
||||
<< k << ", counting from zero");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < test_fes->GetNE(); i++)
|
||||
{
|
||||
const int elem_attr = mesh->GetAttribute(i);
|
||||
dom_dof_trans = trial_fes->GetElementVDofs(i, trial_vdofs);
|
||||
ran_dof_trans = test_fes->GetElementVDofs(i, test_vdofs);
|
||||
eltrans = test_fes->GetElementTransformation(i);
|
||||
dom_dof_trans = trial_fes->GetElementVDofs(i, dom_vdofs);
|
||||
ran_dof_trans = test_fes->GetElementVDofs(i, ran_vdofs);
|
||||
T = test_fes->GetElementTransformation(i);
|
||||
dom_fe = trial_fes->GetFE(i);
|
||||
ran_fe = test_fes->GetFE(i);
|
||||
|
||||
elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
|
||||
elmat = 0.0;
|
||||
for (int k = 0; k < domain_integs.Size(); k++)
|
||||
domain_integs[0]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T,
|
||||
totelmat);
|
||||
for (int j = 1; j < domain_integs.Size(); j++)
|
||||
{
|
||||
if (domain_integs_marker[k] == NULL ||
|
||||
(*(domain_integs_marker[k]))[elem_attr-1] == 1)
|
||||
{
|
||||
domain_integs[k]->AssembleElementMatrix2(*trial_fes->GetFE(i),
|
||||
*test_fes->GetFE(i),
|
||||
*eltrans, elemmat);
|
||||
elmat += elemmat;
|
||||
}
|
||||
domain_integs[j]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T,
|
||||
elmat);
|
||||
totelmat += elmat;
|
||||
}
|
||||
if (ran_dof_trans || dom_dof_trans)
|
||||
{
|
||||
TransformPrimal(ran_dof_trans, dom_dof_trans, elemmat);
|
||||
TransformPrimal(ran_dof_trans, dom_dof_trans, totelmat);
|
||||
}
|
||||
mat->SetSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
|
||||
mat->SetSubMatrix(ran_vdofs, dom_vdofs, totelmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2028,20 +1984,21 @@ void DiscreteLinearOperator::Assemble(int skip_zeros)
|
||||
const int nfaces = test_fes->GetMesh()->GetNumFaces();
|
||||
for (int i = 0; i < nfaces; i++)
|
||||
{
|
||||
trial_fes->GetFaceVDofs(i, trial_vdofs);
|
||||
test_fes->GetFaceVDofs(i, test_vdofs);
|
||||
eltrans = test_fes->GetMesh()->GetFaceTransformation(i);
|
||||
trial_fes->GetFaceVDofs(i, dom_vdofs);
|
||||
test_fes->GetFaceVDofs(i, ran_vdofs);
|
||||
T = test_fes->GetMesh()->GetFaceTransformation(i);
|
||||
dom_fe = trial_fes->GetFaceElement(i);
|
||||
ran_fe = test_fes->GetFaceElement(i);
|
||||
|
||||
elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
|
||||
elmat = 0.0;
|
||||
for (int k = 0; k < trace_face_integs.Size(); k++)
|
||||
trace_face_integs[0]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T,
|
||||
totelmat);
|
||||
for (int j = 1; j < trace_face_integs.Size(); j++)
|
||||
{
|
||||
trace_face_integs[k]->AssembleElementMatrix2(*trial_fes->GetFaceElement(i),
|
||||
*test_fes->GetFaceElement(i),
|
||||
*eltrans, elemmat);
|
||||
elmat += elemmat;
|
||||
trace_face_integs[j]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T,
|
||||
elmat);
|
||||
totelmat += elmat;
|
||||
}
|
||||
mat->SetSubMatrix(test_vdofs, trial_vdofs, elmat, skip_zeros);
|
||||
mat->SetSubMatrix(ran_vdofs, dom_vdofs, totelmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-22
@@ -100,7 +100,7 @@ protected:
|
||||
/// Includes all by default.
|
||||
/// 0 - ignore attribute
|
||||
/// 1 - include attribute
|
||||
Array<Array<int>*> domain_integs_marker; ///< Entries are not owned.
|
||||
Array<Array<int>*> domain_integs_marker;
|
||||
|
||||
/// Set of Boundary Integrators to be applied.
|
||||
Array<BilinearFormIntegrator*> boundary_integs;
|
||||
@@ -722,13 +722,10 @@ protected:
|
||||
|
||||
/// Domain integrators.
|
||||
Array<BilinearFormIntegrator*> domain_integs;
|
||||
/// Entries are not owned.
|
||||
Array<Array<int>*> domain_integs_marker;
|
||||
|
||||
/// Boundary integrators.
|
||||
Array<BilinearFormIntegrator*> boundary_integs;
|
||||
/// Entries are not owned.
|
||||
Array<Array<int>*> boundary_integs_marker;
|
||||
Array<Array<int>*> boundary_integs_marker; ///< Entries are not owned.
|
||||
|
||||
/// Trace face (skeleton) integrators.
|
||||
Array<BilinearFormIntegrator*> trace_face_integs;
|
||||
@@ -808,16 +805,12 @@ public:
|
||||
/// Adds a domain integrator. Assumes ownership of @a bfi.
|
||||
void AddDomainIntegrator(BilinearFormIntegrator *bfi);
|
||||
|
||||
/// Adds a domain integrator. Assumes ownership of @a bfi.
|
||||
void AddDomainIntegrator(BilinearFormIntegrator *bfi,
|
||||
Array<int> &elem_marker);
|
||||
|
||||
/// Adds a boundary integrator. Assumes ownership of @a bfi.
|
||||
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi);
|
||||
|
||||
/// Adds a boundary integrator. Assumes ownership of @a bfi.
|
||||
void AddBoundaryIntegrator(BilinearFormIntegrator * bfi,
|
||||
Array<int> &bdr_marker);
|
||||
void AddBoundaryIntegrator (BilinearFormIntegrator * bfi,
|
||||
Array<int> &bdr_marker);
|
||||
|
||||
/** @brief Add a trace face integrator. Assumes ownership of @a bfi.
|
||||
|
||||
@@ -827,18 +820,14 @@ public:
|
||||
void AddTraceFaceIntegrator(BilinearFormIntegrator *bfi);
|
||||
|
||||
/// Adds a boundary trace face integrator. Assumes ownership of @a bfi.
|
||||
void AddBdrTraceFaceIntegrator(BilinearFormIntegrator * bfi);
|
||||
void AddBdrTraceFaceIntegrator (BilinearFormIntegrator * bfi);
|
||||
|
||||
/// Adds a boundary trace face integrator. Assumes ownership of @a bfi.
|
||||
void AddBdrTraceFaceIntegrator(BilinearFormIntegrator * bfi,
|
||||
Array<int> &bdr_marker);
|
||||
void AddBdrTraceFaceIntegrator (BilinearFormIntegrator * bfi,
|
||||
Array<int> &bdr_marker);
|
||||
|
||||
/// Access all integrators added with AddDomainIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetDBFI() { return &domain_integs; }
|
||||
/** @brief Access all domain markers added with AddDomainIntegrator().
|
||||
If no marker was specified when the integrator was added, the
|
||||
corresponding pointer (to Array<int>) will be NULL. */
|
||||
Array<Array<int>*> *GetDBFI_Marker() { return &domain_integs_marker; }
|
||||
|
||||
/// Access all integrators added with AddBoundaryIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetBBFI() { return &boundary_integs; }
|
||||
@@ -1076,9 +1065,6 @@ public:
|
||||
/// Adds a domain interpolator. Assumes ownership of @a di.
|
||||
void AddDomainInterpolator(DiscreteInterpolator *di)
|
||||
{ AddDomainIntegrator(di); }
|
||||
void AddDomainInterpolator(DiscreteInterpolator *di,
|
||||
Array<int> &elem_marker)
|
||||
{ AddDomainIntegrator(di, elem_marker); }
|
||||
|
||||
/// Adds a trace face interpolator. Assumes ownership of @a di.
|
||||
void AddTraceFaceInterpolator(DiscreteInterpolator *di)
|
||||
@@ -1086,7 +1072,6 @@ public:
|
||||
|
||||
/// Access all interpolators added with AddDomainInterpolator().
|
||||
Array<BilinearFormIntegrator*> *GetDI() { return &domain_integs; }
|
||||
Array<Array<int>*> *GetDI_Marker() { return &domain_integs_marker; }
|
||||
|
||||
/// Set the desired assembly level. The default is AssemblyLevel::FULL.
|
||||
/** This method must be called before assembly. */
|
||||
|
||||
@@ -303,7 +303,7 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
|
||||
std::unordered_map<int,int> f_to_be;
|
||||
for (int i = 0; i < mesh.GetNBE(); ++i)
|
||||
{
|
||||
const int f = mesh.GetBdrElementFaceIndex(i);
|
||||
const int f = mesh.GetBdrElementEdgeIndex(i);
|
||||
f_to_be[f] = i;
|
||||
}
|
||||
const int nf_bdr = trial_fes->GetNFbyType(FaceType::Boundary);
|
||||
|
||||
+3
-4
@@ -1340,11 +1340,10 @@ void MassIntegrator::AssembleElementMatrix2(
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
trial_fe.CalcShape(ip, shape);
|
||||
test_fe.CalcShape(ip, te_shape);
|
||||
|
||||
Trans.SetIntPoint (&ip);
|
||||
|
||||
trial_fe.CalcPhysShape(Trans, shape);
|
||||
test_fe.CalcPhysShape(Trans, te_shape);
|
||||
|
||||
w = Trans.Weight() * ip.weight;
|
||||
if (Q)
|
||||
{
|
||||
|
||||
+172
-169
@@ -14,166 +14,175 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
void DofTransformation::TransformPrimal(double *v) const
|
||||
{
|
||||
MFEM_ASSERT(dof_trans_,
|
||||
"DofTransformation has no local transformation, call "
|
||||
"SetDofTransformation first!");
|
||||
int size = dof_trans_->Size();
|
||||
|
||||
if (vdim_ == 1 || (Ordering::Type)ordering_ == Ordering::byNODES)
|
||||
{
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
dof_trans_->TransformPrimal(Fo_, &v[i*size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vec(size);
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
vec(j) = v[j*vdim_+i];
|
||||
}
|
||||
dof_trans_->TransformPrimal(Fo_, vec);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
v[j*vdim_+i] = vec(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DofTransformation::InvTransformPrimal(double *v) const
|
||||
{
|
||||
MFEM_ASSERT(dof_trans_,
|
||||
"DofTransformation has no local transformation, call "
|
||||
"SetDofTransformation first!");
|
||||
int size = dof_trans_->Height();
|
||||
|
||||
if (vdim_ == 1 || (Ordering::Type)ordering_ == Ordering::byNODES)
|
||||
{
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
dof_trans_->InvTransformPrimal(Fo_, &v[i*size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vec(size);
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
vec(j) = v[j*vdim_+i];
|
||||
}
|
||||
dof_trans_->InvTransformPrimal(Fo_, vec);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
v[j*vdim_+i] = vec(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DofTransformation::TransformDual(double *v) const
|
||||
{
|
||||
MFEM_ASSERT(dof_trans_,
|
||||
"DofTransformation has no local transformation, call "
|
||||
"SetDofTransformation first!");
|
||||
int size = dof_trans_->Size();
|
||||
|
||||
if (vdim_ == 1 || (Ordering::Type)ordering_ == Ordering::byNODES)
|
||||
{
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
dof_trans_->TransformDual(Fo_, &v[i*size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vec(size);
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
vec(j) = v[j*vdim_+i];
|
||||
}
|
||||
dof_trans_->TransformDual(Fo_, vec);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
v[j*vdim_+i] = vec(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DofTransformation::InvTransformDual(double *v) const
|
||||
{
|
||||
MFEM_ASSERT(dof_trans_,
|
||||
"DofTransformation has no local transformation, call "
|
||||
"SetDofTransformation first!");
|
||||
int size = dof_trans_->Size();
|
||||
|
||||
if (vdim_ == 1 || (Ordering::Type)ordering_ == Ordering::byNODES)
|
||||
{
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
dof_trans_->InvTransformDual(Fo_, &v[i*size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vec(size);
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
vec(j) = v[j*vdim_+i];
|
||||
}
|
||||
dof_trans_->InvTransformDual(Fo_, vec);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
v[j*vdim_+i] = vec(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TransformPrimal(const DofTransformation *ran_dof_trans,
|
||||
const DofTransformation *dom_dof_trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
// No action if both transformations are NULL
|
||||
if (ran_dof_trans)
|
||||
if (ran_dof_trans && dom_dof_trans)
|
||||
{
|
||||
ran_dof_trans->TransformPrimalCols(elmat);
|
||||
dom_dof_trans->TransformDualRows(elmat);
|
||||
}
|
||||
else if (ran_dof_trans)
|
||||
{
|
||||
ran_dof_trans->TransformPrimalCols(elmat);
|
||||
}
|
||||
if (dom_dof_trans)
|
||||
else if (dom_dof_trans)
|
||||
{
|
||||
dom_dof_trans->TransformDualRows(elmat);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If both transformations are NULL this function should not be called
|
||||
}
|
||||
}
|
||||
|
||||
void TransformDual(const DofTransformation *ran_dof_trans,
|
||||
const DofTransformation *dom_dof_trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
// No action if both transformations are NULL
|
||||
if (ran_dof_trans)
|
||||
if (ran_dof_trans && dom_dof_trans)
|
||||
{
|
||||
ran_dof_trans->TransformDualCols(elmat);
|
||||
dom_dof_trans->TransformDualRows(elmat);
|
||||
}
|
||||
else if (ran_dof_trans)
|
||||
{
|
||||
ran_dof_trans->TransformDualCols(elmat);
|
||||
}
|
||||
if (dom_dof_trans)
|
||||
else if (dom_dof_trans)
|
||||
{
|
||||
dom_dof_trans->TransformDualRows(elmat);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If both transformations are NULL this function should not be called
|
||||
}
|
||||
}
|
||||
|
||||
void StatelessVDofTransformation::TransformPrimal(const Array<int> & face_ori,
|
||||
double *v) const
|
||||
{
|
||||
int size = sdoftrans_->Size();
|
||||
|
||||
if ((Ordering::Type)ordering_ == Ordering::byNODES || vdim_ == 1)
|
||||
{
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
sdoftrans_->TransformPrimal(face_ori, &v[i*size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vec(size);
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
vec(j) = v[j*vdim_+i];
|
||||
}
|
||||
sdoftrans_->TransformPrimal(face_ori, vec);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
v[j*vdim_+i] = vec(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StatelessVDofTransformation::InvTransformPrimal(
|
||||
const Array<int> & face_ori,
|
||||
double *v) const
|
||||
{
|
||||
int size = sdoftrans_->Height();
|
||||
|
||||
if ((Ordering::Type)ordering_ == Ordering::byNODES)
|
||||
{
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
sdoftrans_->InvTransformPrimal(face_ori, &v[i*size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vec(size);
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
vec(j) = v[j*vdim_+i];
|
||||
}
|
||||
sdoftrans_->InvTransformPrimal(face_ori, vec);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
v[j*vdim_+i] = vec(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StatelessVDofTransformation::TransformDual(const Array<int> & face_ori,
|
||||
double *v) const
|
||||
{
|
||||
int size = sdoftrans_->Size();
|
||||
|
||||
if ((Ordering::Type)ordering_ == Ordering::byNODES)
|
||||
{
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
sdoftrans_->TransformDual(face_ori, &v[i*size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vec(size);
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
vec(j) = v[j*vdim_+i];
|
||||
}
|
||||
sdoftrans_->TransformDual(face_ori, vec);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
v[j*vdim_+i] = vec(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StatelessVDofTransformation::InvTransformDual(const Array<int> & face_ori,
|
||||
double *v) const
|
||||
{
|
||||
int size = sdoftrans_->Size();
|
||||
|
||||
if ((Ordering::Type)ordering_ == Ordering::byNODES)
|
||||
{
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
sdoftrans_->InvTransformDual(face_ori, &v[i*size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vec(size);
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
vec(j) = v[j*vdim_+i];
|
||||
}
|
||||
sdoftrans_->InvTransformDual(face_ori, vec);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
v[j*vdim_+i] = vec(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ordering (i0j0, i1j0, i0j1, i1j1), each row is a column major matrix
|
||||
const double ND_DofTransformation::T_data[24] =
|
||||
const double ND_StatelessDofTransformation::T_data[24] =
|
||||
{
|
||||
1.0, 0.0, 0.0, 1.0,
|
||||
-1.0, -1.0, 0.0, 1.0,
|
||||
@@ -183,11 +192,11 @@ const double ND_DofTransformation::T_data[24] =
|
||||
0.0, 1.0, 1.0, 0.0
|
||||
};
|
||||
|
||||
const DenseTensor ND_DofTransformation
|
||||
::T(const_cast<double *>(ND_DofTransformation::T_data), 2, 2, 6);
|
||||
const DenseTensor ND_StatelessDofTransformation
|
||||
::T(const_cast<double*>(ND_StatelessDofTransformation::T_data), 2, 2, 6);
|
||||
|
||||
// ordering (i0j0, i1j0, i0j1, i1j1), each row is a column major matrix
|
||||
const double ND_DofTransformation::TInv_data[24] =
|
||||
const double ND_StatelessDofTransformation::TInv_data[24] =
|
||||
{
|
||||
1.0, 0.0, 0.0, 1.0,
|
||||
-1.0, -1.0, 0.0, 1.0,
|
||||
@@ -197,11 +206,12 @@ const double ND_DofTransformation::TInv_data[24] =
|
||||
0.0, 1.0, 1.0, 0.0
|
||||
};
|
||||
|
||||
const DenseTensor ND_DofTransformation
|
||||
::TInv(const_cast<double *>(TInv_data), 2, 2, 6);
|
||||
const DenseTensor ND_StatelessDofTransformation
|
||||
::TInv(const_cast<double*>(TInv_data), 2, 2, 6);
|
||||
|
||||
ND_DofTransformation::ND_DofTransformation(int size, int p, int num_edges,
|
||||
int num_tri_faces)
|
||||
ND_StatelessDofTransformation::ND_StatelessDofTransformation(int size, int p,
|
||||
int num_edges,
|
||||
int num_tri_faces)
|
||||
: StatelessDofTransformation(size)
|
||||
, order(p)
|
||||
, nedofs(p)
|
||||
@@ -211,19 +221,18 @@ ND_DofTransformation::ND_DofTransformation(int size, int p, int num_edges,
|
||||
{
|
||||
}
|
||||
|
||||
void ND_DofTransformation::TransformPrimal(const Array<int> & Fo,
|
||||
double *v) const
|
||||
void ND_StatelessDofTransformation::TransformPrimal(const Array<int> & Fo,
|
||||
double *v) const
|
||||
{
|
||||
// Return immediately when no face DoFs are present
|
||||
if (IsIdentity()) { return; }
|
||||
if (nfdofs < 2) { return; }
|
||||
|
||||
MFEM_VERIFY(Fo.Size() >= nfaces,
|
||||
"Face orientation array is shorter than the number of faces in "
|
||||
"ND_DofTransformation");
|
||||
"ND_StatelessDofTransformation");
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
DenseMatrix T2;
|
||||
|
||||
// Transform face DoFs
|
||||
for (int f=0; f<nfaces; f++)
|
||||
@@ -231,25 +240,23 @@ void ND_DofTransformation::TransformPrimal(const Array<int> & Fo,
|
||||
for (int i=0; i<nfdofs/2; i++)
|
||||
{
|
||||
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
|
||||
T2.UseExternalData(const_cast<double *>(T.GetData(Fo[f])), 2, 2);
|
||||
T2.Mult(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
|
||||
T(Fo[f]).Mult(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ND_DofTransformation::InvTransformPrimal(const Array<int> & Fo,
|
||||
double *v) const
|
||||
void ND_StatelessDofTransformation::InvTransformPrimal(const Array<int> & Fo,
|
||||
double *v) const
|
||||
{
|
||||
// Return immediately when no face DoFs are present
|
||||
if (IsIdentity()) { return; }
|
||||
if (nfdofs < 2) { return; }
|
||||
|
||||
MFEM_VERIFY(Fo.Size() >= nfaces,
|
||||
"Face orientation array is shorter than the number of faces in "
|
||||
"ND_DofTransformation");
|
||||
"ND_StatelessDofTransformation");
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
DenseMatrix T2Inv;
|
||||
|
||||
// Transform face DoFs
|
||||
for (int f=0; f<nfaces; f++)
|
||||
@@ -257,24 +264,23 @@ void ND_DofTransformation::InvTransformPrimal(const Array<int> & Fo,
|
||||
for (int i=0; i<nfdofs/2; i++)
|
||||
{
|
||||
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
|
||||
T2Inv.UseExternalData(const_cast<double *>(TInv.GetData(Fo[f])), 2, 2);
|
||||
T2Inv.Mult(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
|
||||
TInv(Fo[f]).Mult(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ND_DofTransformation::TransformDual(const Array<int> & Fo, double *v) const
|
||||
void ND_StatelessDofTransformation::TransformDual(const Array<int> & Fo,
|
||||
double *v) const
|
||||
{
|
||||
// Return immediately when no face DoFs are present
|
||||
if (IsIdentity()) { return; }
|
||||
if (nfdofs < 2) { return; }
|
||||
|
||||
MFEM_VERIFY(Fo.Size() >= nfaces,
|
||||
"Face orientation array is shorter than the number of faces in "
|
||||
"ND_DofTransformation");
|
||||
"ND_StatelessDofTransformation");
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
DenseMatrix T2Inv;
|
||||
|
||||
// Transform face DoFs
|
||||
for (int f=0; f<nfaces; f++)
|
||||
@@ -282,25 +288,23 @@ void ND_DofTransformation::TransformDual(const Array<int> & Fo, double *v) const
|
||||
for (int i=0; i<nfdofs/2; i++)
|
||||
{
|
||||
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
|
||||
T2Inv.UseExternalData(const_cast<double *>(TInv.GetData(Fo[f])), 2, 2);
|
||||
T2Inv.MultTranspose(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
|
||||
TInv(Fo[f]).MultTranspose(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ND_DofTransformation::InvTransformDual(const Array<int> & Fo,
|
||||
double *v) const
|
||||
void ND_StatelessDofTransformation::InvTransformDual(const Array<int> & Fo,
|
||||
double *v) const
|
||||
{
|
||||
// Return immediately when no face DoFs are present
|
||||
if (IsIdentity()) { return; }
|
||||
if (nfdofs < 2) { return; }
|
||||
|
||||
MFEM_VERIFY(Fo.Size() >= nfaces,
|
||||
"Face orientation array is shorter than the number of faces in "
|
||||
"ND_DofTransformation");
|
||||
"ND_StatelessDofTransformation");
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
DenseMatrix T2;
|
||||
|
||||
// Transform face DoFs
|
||||
for (int f=0; f<nfaces; f++)
|
||||
@@ -308,8 +312,7 @@ void ND_DofTransformation::InvTransformDual(const Array<int> & Fo,
|
||||
for (int i=0; i<nfdofs/2; i++)
|
||||
{
|
||||
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
|
||||
T2.UseExternalData(const_cast<double *>(T.GetData(Fo[f])), 2, 2);
|
||||
T2.MultTranspose(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
|
||||
T(Fo[f]).MultTranspose(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+251
-77
@@ -80,9 +80,6 @@ public:
|
||||
inline int Width() const { return size_; }
|
||||
inline int NumCols() const { return size_; }
|
||||
|
||||
/// If the DofTransformation performs no transformation
|
||||
virtual bool IsIdentity() const = 0;
|
||||
|
||||
/** Transform local DoFs to align with the global DoFs. For example, this
|
||||
transformation can be used to map the local vector computed by
|
||||
FiniteElement::Project() to the transformed vector stored within a
|
||||
@@ -118,8 +115,6 @@ public:
|
||||
inline void InvTransformDual(const Array<int> & face_orientation,
|
||||
Vector &v) const
|
||||
{ InvTransformDual(face_orientation, v.GetData()); }
|
||||
|
||||
virtual ~StatelessDofTransformation() = default;
|
||||
};
|
||||
|
||||
/** The DofTransformation class is an extension of the
|
||||
@@ -138,76 +133,35 @@ public:
|
||||
transferring finite element degrees of freedom between different meshes.
|
||||
For examples of its use see the TransferMap used by the SubMesh class.
|
||||
*/
|
||||
class DofTransformation
|
||||
class DofTransformation : virtual public StatelessDofTransformation
|
||||
{
|
||||
protected:
|
||||
Array<int> Fo_;
|
||||
const StatelessDofTransformation * dof_trans_;
|
||||
int vdim_;
|
||||
int ordering_;
|
||||
Array<int> Fo;
|
||||
|
||||
DofTransformation(int size)
|
||||
: StatelessDofTransformation(size) {}
|
||||
|
||||
public:
|
||||
/** @brief Default constructor which requires that SetDofTransformation be
|
||||
called before use. */
|
||||
DofTransformation(int vdim = 1, int ordering = 0)
|
||||
: dof_trans_(NULL)
|
||||
, vdim_(vdim)
|
||||
, ordering_(ordering)
|
||||
{}
|
||||
|
||||
/// Constructor with a known StatelessDofTransformation
|
||||
DofTransformation(const StatelessDofTransformation & dof_trans,
|
||||
int vdim = 1, int ordering = 0)
|
||||
: dof_trans_(&dof_trans)
|
||||
, vdim_(vdim)
|
||||
, ordering_(ordering)
|
||||
{}
|
||||
|
||||
/** @brief Configure the transformation using face orientations for the
|
||||
current element. */
|
||||
/// The face_orientation array can be obtained from Mesh::GetElementFaces.
|
||||
inline void SetFaceOrientations(const Array<int> & Fo)
|
||||
{ Fo_ = Fo; }
|
||||
inline void SetFaceOrientations(const Array<int> & face_orientation)
|
||||
{ Fo = face_orientation; }
|
||||
|
||||
/// Return the face orientations for the current element
|
||||
inline const Array<int> & GetFaceOrientations() const { return Fo_; }
|
||||
inline const Array<int> & GetFaceOrientations() const { return Fo; }
|
||||
|
||||
/// Set or change the nested StatelessDofTransformation object
|
||||
inline void SetDofTransformation(const StatelessDofTransformation & dof_trans)
|
||||
{
|
||||
dof_trans_ = &dof_trans;
|
||||
}
|
||||
inline void SetDofTransformation(const StatelessDofTransformation * dof_trans)
|
||||
{
|
||||
dof_trans_ = dof_trans;
|
||||
}
|
||||
|
||||
/// Return the nested StatelessDofTransformation object
|
||||
inline const StatelessDofTransformation * GetDofTransformation() const
|
||||
{ return dof_trans_; }
|
||||
|
||||
/// Set or change the vdim and ordering parameter
|
||||
inline void SetVDim(int vdim = 1, int ordering = 0)
|
||||
{
|
||||
vdim_ = vdim;
|
||||
ordering_ = ordering;
|
||||
}
|
||||
|
||||
/// Return the current vdim value
|
||||
inline int GetVDim() const { return vdim_; }
|
||||
|
||||
inline int Size() const { return dof_trans_->Size(); }
|
||||
inline int Height() const { return dof_trans_->Height(); }
|
||||
inline int NumRows() const { return dof_trans_->NumRows(); }
|
||||
inline int Width() const { return dof_trans_->Width(); }
|
||||
inline int NumCols() const { return dof_trans_->NumCols(); }
|
||||
inline bool IsIdentity() const { return dof_trans_->IsIdentity(); }
|
||||
using StatelessDofTransformation::TransformPrimal;
|
||||
using StatelessDofTransformation::InvTransformPrimal;
|
||||
using StatelessDofTransformation::TransformDual;
|
||||
using StatelessDofTransformation::InvTransformDual;
|
||||
|
||||
/** Transform local DoFs to align with the global DoFs. For example, this
|
||||
transformation can be used to map the local vector computed by
|
||||
FiniteElement::Project() to the transformed vector stored within a
|
||||
GridFunction object. */
|
||||
void TransformPrimal(double *v) const;
|
||||
inline void TransformPrimal(double *v) const
|
||||
{ TransformPrimal(Fo, v); }
|
||||
inline void TransformPrimal(Vector &v) const
|
||||
{ TransformPrimal(v.GetData()); }
|
||||
|
||||
@@ -225,18 +179,21 @@ public:
|
||||
transform the vector obtained using GridFunction::GetSubVector before it
|
||||
can be used to compute a local interpolation.
|
||||
*/
|
||||
void InvTransformPrimal(double *v) const;
|
||||
inline void InvTransformPrimal(double *v) const
|
||||
{ InvTransformPrimal(Fo, v); }
|
||||
inline void InvTransformPrimal(Vector &v) const
|
||||
{ InvTransformPrimal(v.GetData()); }
|
||||
|
||||
/** Transform dual DoFs as computed by a LinearFormIntegrator before summing
|
||||
into a LinearForm object. */
|
||||
void TransformDual(double *v) const;
|
||||
inline void TransformDual(double *v) const
|
||||
{ TransformDual(Fo, v); }
|
||||
inline void TransformDual(Vector &v) const
|
||||
{ TransformDual(v.GetData()); }
|
||||
|
||||
/** Inverse Transform dual DoFs */
|
||||
void InvTransformDual(double *v) const;
|
||||
inline void InvTransformDual(double *v) const
|
||||
{ InvTransformDual(Fo, v); }
|
||||
inline void InvTransformDual(Vector &v) const
|
||||
{ InvTransformDual(v.GetData()); }
|
||||
|
||||
@@ -268,6 +225,8 @@ public:
|
||||
TransformDual(V.GetColumn(c));
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~DofTransformation() = default;
|
||||
};
|
||||
|
||||
/** Transform a matrix of DoFs entries from different finite element spaces as
|
||||
@@ -286,6 +245,145 @@ void TransformDual(const DofTransformation *ran_dof_trans,
|
||||
const DofTransformation *dom_dof_trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
/** The StatelessVDofTransformation class implements a nested transformation
|
||||
where an arbitrary StatelessDofTransformation is replicated with a
|
||||
vdim >= 1.
|
||||
*/
|
||||
class StatelessVDofTransformation : virtual public StatelessDofTransformation
|
||||
{
|
||||
protected:
|
||||
int vdim_;
|
||||
int ordering_;
|
||||
StatelessDofTransformation * sdoftrans_;
|
||||
|
||||
public:
|
||||
/** @brief Default constructor which requires that SetDofTransformation be
|
||||
called before use. */
|
||||
StatelessVDofTransformation(int vdim = 1, int ordering = 0)
|
||||
: StatelessDofTransformation(0)
|
||||
, vdim_(vdim)
|
||||
, ordering_(ordering)
|
||||
, sdoftrans_(NULL)
|
||||
{}
|
||||
|
||||
/// Constructor with a known StatelessDofTransformation
|
||||
StatelessVDofTransformation(StatelessDofTransformation & doftrans,
|
||||
int vdim = 1,
|
||||
int ordering = 0)
|
||||
: StatelessDofTransformation(vdim * doftrans.Size())
|
||||
, vdim_(vdim)
|
||||
, ordering_(ordering)
|
||||
, sdoftrans_(&doftrans)
|
||||
{}
|
||||
|
||||
/// Set or change the vdim parameter
|
||||
inline void SetVDim(int vdim)
|
||||
{
|
||||
vdim_ = vdim;
|
||||
if (sdoftrans_)
|
||||
{
|
||||
size_ = vdim_ * sdoftrans_->Size();
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the current vdim value
|
||||
inline int GetVDim() const { return vdim_; }
|
||||
|
||||
/// Set or change the nested StatelessDofTransformation object
|
||||
inline void SetDofTransformation(StatelessDofTransformation & doftrans)
|
||||
{
|
||||
size_ = vdim_ * doftrans.Size();
|
||||
sdoftrans_ = &doftrans;
|
||||
}
|
||||
|
||||
/// Return the nested StatelessDofTransformation object
|
||||
inline StatelessDofTransformation * GetDofTransformation() const
|
||||
{ return sdoftrans_; }
|
||||
|
||||
using StatelessDofTransformation::TransformPrimal;
|
||||
using StatelessDofTransformation::InvTransformPrimal;
|
||||
using StatelessDofTransformation::TransformDual;
|
||||
using StatelessDofTransformation::InvTransformDual;
|
||||
|
||||
/** Specializations of these base class methods which account for the vdim
|
||||
and ordering of the full set of DoFs.
|
||||
*/
|
||||
void TransformPrimal(const Array<int> & face_ori, double *v) const;
|
||||
void InvTransformPrimal(const Array<int> & face_ori, double *v) const;
|
||||
void TransformDual(const Array<int> & face_ori, double *v) const;
|
||||
void InvTransformDual(const Array<int> & face_ori, double *v) const;
|
||||
};
|
||||
|
||||
/** The VDofTransformation class implements a nested transformation where an
|
||||
arbitrary DofTransformation is replicated with a vdim >= 1.
|
||||
*/
|
||||
class VDofTransformation : public StatelessVDofTransformation,
|
||||
public DofTransformation
|
||||
{
|
||||
protected:
|
||||
DofTransformation * doftrans_;
|
||||
|
||||
public:
|
||||
/** @brief Default constructor which requires that SetDofTransformation be
|
||||
called before use. */
|
||||
VDofTransformation(int vdim = 1, int ordering = 0)
|
||||
: StatelessDofTransformation(0)
|
||||
, StatelessVDofTransformation(vdim, ordering)
|
||||
, DofTransformation(0)
|
||||
, doftrans_(NULL)
|
||||
{}
|
||||
|
||||
/// Constructor with a known DofTransformation
|
||||
/// @note The face orientations in @a doftrans will be copied into the
|
||||
/// new VDofTransformation object.
|
||||
VDofTransformation(DofTransformation & doftrans, int vdim = 1,
|
||||
int ordering = 0)
|
||||
: StatelessDofTransformation(vdim * doftrans.Size())
|
||||
, StatelessVDofTransformation(doftrans, vdim, ordering)
|
||||
, DofTransformation(vdim * doftrans.Size())
|
||||
, doftrans_(&doftrans)
|
||||
{
|
||||
DofTransformation::SetFaceOrientations(doftrans.GetFaceOrientations());
|
||||
}
|
||||
|
||||
using StatelessVDofTransformation::SetDofTransformation;
|
||||
|
||||
/// Set or change the nested DofTransformation object
|
||||
/// @note The face orientations in @a doftrans will be copied into the
|
||||
/// VDofTransformation object.
|
||||
void SetDofTransformation(DofTransformation & doftrans)
|
||||
{
|
||||
doftrans_ = &doftrans;
|
||||
StatelessVDofTransformation::SetDofTransformation(doftrans);
|
||||
DofTransformation::SetFaceOrientations(doftrans.GetFaceOrientations());
|
||||
}
|
||||
|
||||
/// Return the nested DofTransformation object
|
||||
inline DofTransformation * GetDofTransformation() const { return doftrans_; }
|
||||
|
||||
/// Set new face orientations in both the VDofTransformation and the
|
||||
/// DofTransformation contained within (if there is one).
|
||||
inline void SetFaceOrientations(const Array<int> & face_orientation)
|
||||
{
|
||||
DofTransformation::SetFaceOrientations(face_orientation);
|
||||
if (doftrans_) { doftrans_->SetFaceOrientations(face_orientation); }
|
||||
}
|
||||
|
||||
using DofTransformation::TransformPrimal;
|
||||
using DofTransformation::InvTransformPrimal;
|
||||
using DofTransformation::TransformDual;
|
||||
using DofTransformation::InvTransformDual;
|
||||
|
||||
inline void TransformPrimal(double *v) const
|
||||
{ TransformPrimal(Fo, v); }
|
||||
inline void InvTransformPrimal(double *v) const
|
||||
{ InvTransformPrimal(Fo, v); }
|
||||
inline void TransformDual(double *v) const
|
||||
{ TransformDual(Fo, v); }
|
||||
inline void InvTransformDual(double *v) const
|
||||
{ InvTransformDual(Fo, v); }
|
||||
};
|
||||
|
||||
/** Abstract base class for high-order Nedelec spaces on elements with
|
||||
triangular faces.
|
||||
|
||||
@@ -298,7 +396,7 @@ void TransformDual(const DofTransformation *ran_dof_trans,
|
||||
be accessed as DenseMatrices using the GetFaceTransform() and
|
||||
GetFaceInverseTransform() methods.
|
||||
*/
|
||||
class ND_DofTransformation : public StatelessDofTransformation
|
||||
class ND_StatelessDofTransformation : virtual public StatelessDofTransformation
|
||||
{
|
||||
private:
|
||||
static const double T_data[24];
|
||||
@@ -312,7 +410,8 @@ protected:
|
||||
const int nedges; // number of edges per element
|
||||
const int nfaces; // number of triangular faces per element
|
||||
|
||||
ND_DofTransformation(int size, int order, int num_edges, int num_tri_faces);
|
||||
ND_StatelessDofTransformation(int size, int order,
|
||||
int num_edges, int num_tri_faces);
|
||||
|
||||
public:
|
||||
// Return the 2x2 transformation operator for the given face orientation
|
||||
@@ -322,41 +421,116 @@ public:
|
||||
static const DenseMatrix & GetFaceInverseTransform(int ori)
|
||||
{ return TInv(ori); }
|
||||
|
||||
bool IsIdentity() const override { return nfdofs < 2; }
|
||||
void TransformPrimal(const Array<int> & face_orientation,
|
||||
double *v) const;
|
||||
|
||||
void TransformPrimal(const Array<int> & Fo, double *v) const override;
|
||||
void InvTransformPrimal(const Array<int> & Fo, double *v) const override;
|
||||
void TransformDual(const Array<int> & Fo, double *v) const override;
|
||||
void InvTransformDual(const Array<int> & Fo, double *v) const override;
|
||||
void InvTransformPrimal(const Array<int> & face_orientation,
|
||||
double *v) const;
|
||||
|
||||
void TransformDual(const Array<int> & face_orientation,
|
||||
double *v) const;
|
||||
|
||||
void InvTransformDual(const Array<int> & face_orientation,
|
||||
double *v) const;
|
||||
};
|
||||
|
||||
/// Stateless DoF transformation implementation for the Nedelec basis on
|
||||
/// triangles
|
||||
class ND_TriDofTransformation : public ND_DofTransformation
|
||||
class ND_TriStatelessDofTransformation : public ND_StatelessDofTransformation
|
||||
{
|
||||
public:
|
||||
ND_TriStatelessDofTransformation(int order)
|
||||
: StatelessDofTransformation(order*(order + 2))
|
||||
, ND_StatelessDofTransformation(order*(order + 2), order, 3, 1)
|
||||
{}
|
||||
};
|
||||
|
||||
/// DoF transformation implementation for the Nedelec basis on triangles
|
||||
class ND_TriDofTransformation : public DofTransformation,
|
||||
public ND_TriStatelessDofTransformation
|
||||
{
|
||||
public:
|
||||
ND_TriDofTransformation(int order)
|
||||
: ND_DofTransformation(order*(order + 2), order, 3, 1)
|
||||
: StatelessDofTransformation(order*(order + 2))
|
||||
, DofTransformation(order*(order + 2))
|
||||
, ND_TriStatelessDofTransformation(order)
|
||||
{}
|
||||
|
||||
using DofTransformation::TransformPrimal;
|
||||
using DofTransformation::InvTransformPrimal;
|
||||
using DofTransformation::TransformDual;
|
||||
using DofTransformation::InvTransformDual;
|
||||
|
||||
using ND_TriStatelessDofTransformation::TransformPrimal;
|
||||
using ND_TriStatelessDofTransformation::InvTransformPrimal;
|
||||
using ND_TriStatelessDofTransformation::TransformDual;
|
||||
using ND_TriStatelessDofTransformation::InvTransformDual;
|
||||
};
|
||||
|
||||
/// DoF transformation implementation for the Nedelec basis on tetrahedra
|
||||
class ND_TetStatelessDofTransformation : public ND_StatelessDofTransformation
|
||||
{
|
||||
public:
|
||||
ND_TetStatelessDofTransformation(int order)
|
||||
: StatelessDofTransformation(order*(order + 2)*(order + 3)/2)
|
||||
, ND_StatelessDofTransformation(order*(order + 2)*(order + 3)/2, order,
|
||||
6, 4)
|
||||
{}
|
||||
};
|
||||
|
||||
/// DoF transformation implementation for the Nedelec basis on tetrahedra
|
||||
class ND_TetDofTransformation : public ND_DofTransformation
|
||||
class ND_TetDofTransformation : public DofTransformation,
|
||||
public ND_TetStatelessDofTransformation
|
||||
{
|
||||
public:
|
||||
ND_TetDofTransformation(int order)
|
||||
: ND_DofTransformation(order*(order + 2)*(order + 3)/2, order, 6, 4)
|
||||
: StatelessDofTransformation(order*(order + 2)*(order + 3)/2)
|
||||
, DofTransformation(order*(order + 2)*(order + 3)/2)
|
||||
, ND_TetStatelessDofTransformation(order)
|
||||
{}
|
||||
|
||||
using DofTransformation::TransformPrimal;
|
||||
using DofTransformation::InvTransformPrimal;
|
||||
using DofTransformation::TransformDual;
|
||||
using DofTransformation::InvTransformDual;
|
||||
|
||||
using ND_TetStatelessDofTransformation::TransformPrimal;
|
||||
using ND_TetStatelessDofTransformation::InvTransformPrimal;
|
||||
using ND_TetStatelessDofTransformation::TransformDual;
|
||||
using ND_TetStatelessDofTransformation::InvTransformDual;
|
||||
};
|
||||
|
||||
/// DoF transformation implementation for the Nedelec basis on wedge elements
|
||||
class ND_WedgeStatelessDofTransformation : public ND_StatelessDofTransformation
|
||||
{
|
||||
public:
|
||||
ND_WedgeStatelessDofTransformation(int order)
|
||||
: StatelessDofTransformation(3 * order * ((order + 1) * (order + 2))/2)
|
||||
, ND_StatelessDofTransformation(3 * order * ((order + 1) * (order + 2))/2,
|
||||
order, 9, 2)
|
||||
{}
|
||||
};
|
||||
|
||||
/// DoF transformation implementation for the Nedelec basis on wedge elements
|
||||
class ND_WedgeDofTransformation : public ND_DofTransformation
|
||||
class ND_WedgeDofTransformation : public DofTransformation,
|
||||
public ND_WedgeStatelessDofTransformation
|
||||
{
|
||||
public:
|
||||
ND_WedgeDofTransformation(int order)
|
||||
: ND_DofTransformation(3 * order * ((order + 1) * (order + 2))/2,
|
||||
order, 9, 2)
|
||||
: StatelessDofTransformation(3 * order * ((order + 1) * (order + 2))/2)
|
||||
, DofTransformation(3 * order * ((order + 1) * (order + 2))/2)
|
||||
, ND_WedgeStatelessDofTransformation(order)
|
||||
{}
|
||||
|
||||
using DofTransformation::TransformPrimal;
|
||||
using DofTransformation::InvTransformPrimal;
|
||||
using DofTransformation::TransformDual;
|
||||
using DofTransformation::InvTransformDual;
|
||||
|
||||
using ND_WedgeStatelessDofTransformation::TransformPrimal;
|
||||
using ND_WedgeStatelessDofTransformation::InvTransformPrimal;
|
||||
using ND_WedgeStatelessDofTransformation::TransformDual;
|
||||
using ND_WedgeStatelessDofTransformation::InvTransformDual;
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+5
-1
@@ -355,11 +355,15 @@ int InverseElementTransformation::Transform(const Vector &pt,
|
||||
}
|
||||
else
|
||||
{
|
||||
RefinedGeometry &RefG = *refiner.Refine(T->GetGeometryType(), order);
|
||||
const int old_type = GlobGeometryRefiner.GetType();
|
||||
GlobGeometryRefiner.SetType(qpts_type);
|
||||
RefinedGeometry &RefG =
|
||||
*GlobGeometryRefiner.Refine(T->GetGeometryType(), order);
|
||||
int closest_idx = (init_guess_type == ClosestPhysNode) ?
|
||||
FindClosestPhysPoint(pt, RefG.RefPts) :
|
||||
FindClosestRefPoint(pt, RefG.RefPts);
|
||||
ip0 = &RefG.RefPts.IntPoint(closest_idx);
|
||||
GlobGeometryRefiner.SetType(old_type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+4
-4
@@ -233,7 +233,7 @@ protected:
|
||||
// Parameters of the inversion algorithms:
|
||||
const IntegrationPoint *ip0;
|
||||
int init_guess_type; // algorithm to use
|
||||
GeometryRefiner refiner; // geometry refiner for initial guess
|
||||
int qpts_type; // Quadrature1D type for the initial guess type
|
||||
int rel_qpts_order; // num_1D_qpts = max(trans_order+rel_qpts_order,0)+1
|
||||
int solver_type; // solution strategy to use
|
||||
int max_iter; // max. number of Newton iterations
|
||||
@@ -276,7 +276,7 @@ public:
|
||||
: T(Trans),
|
||||
ip0(NULL),
|
||||
init_guess_type(Center),
|
||||
refiner(Quadrature1D::OpenHalfUniform),
|
||||
qpts_type(Quadrature1D::OpenHalfUniform),
|
||||
rel_qpts_order(-1),
|
||||
solver_type(NewtonElementProject),
|
||||
max_iter(16),
|
||||
@@ -301,7 +301,7 @@ public:
|
||||
{ ip0 = &init_ip; SetInitialGuessType(GivenPoint); }
|
||||
|
||||
/// Set the Quadrature1D type used for the `Closest*` initial guess types.
|
||||
void SetInitGuessPointsType(int q_type) { refiner.SetType(q_type); }
|
||||
void SetInitGuessPointsType(int q_type) { qpts_type = q_type; }
|
||||
|
||||
/// Set the relative order used for the `Closest*` initial guess types.
|
||||
/** The number of points in each spatial direction is given by the formula
|
||||
@@ -361,7 +361,7 @@ public:
|
||||
class IsoparametricTransformation : public ElementTransformation
|
||||
{
|
||||
private:
|
||||
DenseMatrix dshape, d2shape;
|
||||
DenseMatrix dshape,d2shape;
|
||||
Vector shape;
|
||||
|
||||
const FiniteElement *FElem;
|
||||
|
||||
+177
-219
@@ -359,148 +359,135 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
|
||||
|
||||
// Hessian in physical coords
|
||||
lhm.Invert();
|
||||
Mult(hess, lhm, Hessian);
|
||||
Mult( hess, lhm, Hessian);
|
||||
}
|
||||
|
||||
const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
DofToQuad *d2q = nullptr;
|
||||
MFEM_VERIFY(mode == DofToQuad::FULL, "invalid mode requested");
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
#pragma omp critical (DofToQuad)
|
||||
#endif
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
d2q = dof2quad_array[i];
|
||||
if (d2q->IntRule != &ir || d2q->mode != mode) { d2q = nullptr; }
|
||||
}
|
||||
if (!d2q)
|
||||
{
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix vshape(dof, dim);
|
||||
DenseMatrix vshape(dof, dim);
|
||||
#endif
|
||||
d2q = new DofToQuad;
|
||||
const int nqpt = ir.GetNPoints();
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = dof;
|
||||
d2q->nqpt = nqpt;
|
||||
switch (range_type)
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const int nqpt = ir.GetNPoints();
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = dof;
|
||||
d2q->nqpt = nqpt;
|
||||
if (range_type == SCALAR)
|
||||
{
|
||||
d2q->B.SetSize(nqpt*dof);
|
||||
d2q->Bt.SetSize(dof*nqpt);
|
||||
|
||||
Vector shape;
|
||||
vshape.GetColumnReference(0, shape);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcShape(ip, shape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
case SCALAR:
|
||||
{
|
||||
d2q->B.SetSize(nqpt*dof);
|
||||
d2q->Bt.SetSize(dof*nqpt);
|
||||
|
||||
Vector shape;
|
||||
vshape.GetColumnReference(0, shape);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcShape(ip, shape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = shape(j);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VECTOR:
|
||||
{
|
||||
d2q->B.SetSize(nqpt*dim*dof);
|
||||
d2q->Bt.SetSize(dof*nqpt*dim);
|
||||
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcVShape(ip, vshape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*(d+dim*j)] =
|
||||
d2q->Bt[j+dof*(i+nqpt*d)] = vshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UNKNOWN_RANGE_TYPE:
|
||||
// Skip B and Bt for unknown range type
|
||||
break;
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = shape(j);
|
||||
}
|
||||
switch (deriv_type)
|
||||
{
|
||||
case GRAD:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*dim*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt*dim);
|
||||
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcDShape(ip, vshape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*(d+dim*j)] =
|
||||
d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt);
|
||||
|
||||
Vector divshape;
|
||||
vshape.GetColumnReference(0, divshape);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcDivShape(ip, divshape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+dof*i] = divshape(j);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CURL:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*cdim*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt*cdim);
|
||||
|
||||
DenseMatrix curlshape(vshape.GetData(), dof, cdim); // cdim <= dim
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcCurlShape(ip, curlshape);
|
||||
for (int d = 0; d < cdim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*(d+cdim*j)] =
|
||||
d2q->Gt[j+dof*(i+nqpt*d)] = curlshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NONE:
|
||||
// Skip G and Gt for unknown derivative type
|
||||
break;
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
}
|
||||
}
|
||||
else if (range_type == VECTOR)
|
||||
{
|
||||
d2q->B.SetSize(nqpt*dim*dof);
|
||||
d2q->Bt.SetSize(dof*nqpt*dim);
|
||||
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcVShape(ip, vshape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*(d+dim*j)] = d2q->Bt[j+dof*(i+nqpt*d)] = vshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip B and Bt for unknown range type
|
||||
}
|
||||
switch (deriv_type)
|
||||
{
|
||||
case GRAD:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*dim*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt*dim);
|
||||
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcDShape(ip, vshape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt);
|
||||
|
||||
Vector divshape;
|
||||
vshape.GetColumnReference(0, divshape);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcDivShape(ip, divshape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+dof*i] = divshape(j);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CURL:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*cdim*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt*cdim);
|
||||
|
||||
DenseMatrix curlshape(vshape.GetData(), dof, cdim); // cdim <= dim
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcCurlShape(ip, curlshape);
|
||||
for (int d = 0; d < cdim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*(d+cdim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = curlshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NONE:
|
||||
default:
|
||||
// Skip G and Gt for unknown derivative type
|
||||
break;
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
@@ -917,14 +904,14 @@ VectorFiniteElement::VectorFiniteElement(int D, Geometry::Type G,
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcShape(
|
||||
const IntegrationPoint &ip, Vector &shape) const
|
||||
const IntegrationPoint &ip, Vector &shape ) const
|
||||
{
|
||||
mfem_error("Error: Cannot use scalar CalcShape(...) function with\n"
|
||||
" VectorFiniteElements!");
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcDShape(
|
||||
const IntegrationPoint &ip, DenseMatrix &dshape) const
|
||||
const IntegrationPoint &ip, DenseMatrix &dshape ) const
|
||||
{
|
||||
mfem_error("Error: Cannot use scalar CalcDShape(...) function with\n"
|
||||
" VectorFiniteElements!");
|
||||
@@ -2196,72 +2183,51 @@ void Poly_1D::CalcChebyshev(const int p, const double x, double *u, double *d,
|
||||
|
||||
const double *Poly_1D::GetPoints(const int p, const int btype)
|
||||
{
|
||||
Array<double*> *pts;
|
||||
BasisType::Check(btype);
|
||||
const int qtype = BasisType::GetQuadrature1D(btype);
|
||||
|
||||
if (qtype == Quadrature1D::Invalid) { return NULL; }
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
#pragma omp critical (Poly1DGetPoints)
|
||||
#endif
|
||||
if (points_container.find(btype) == points_container.end())
|
||||
{
|
||||
auto it = points_container.find(btype);
|
||||
if (it != points_container.end())
|
||||
{
|
||||
pts = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
pts = new Array<double*>(h_mt);
|
||||
points_container[btype] = pts;
|
||||
}
|
||||
if (pts->Size() <= p)
|
||||
{
|
||||
pts->SetSize(p + 1, NULL);
|
||||
}
|
||||
if ((*pts)[p] == NULL)
|
||||
{
|
||||
(*pts)[p] = new double[p + 1];
|
||||
quad_func.GivePolyPoints(p + 1, (*pts)[p], qtype);
|
||||
}
|
||||
points_container[btype] = new Array<double*>(h_mt);
|
||||
}
|
||||
return (*pts)[p];
|
||||
Array<double*> &pts = *points_container[btype];
|
||||
if (pts.Size() <= p)
|
||||
{
|
||||
pts.SetSize(p + 1, NULL);
|
||||
}
|
||||
if (pts[p] == NULL)
|
||||
{
|
||||
pts[p] = new double[p + 1];
|
||||
quad_func.GivePolyPoints(p+1, pts[p], qtype);
|
||||
}
|
||||
return pts[p];
|
||||
}
|
||||
|
||||
Poly_1D::Basis &Poly_1D::GetBasis(const int p, const int btype)
|
||||
{
|
||||
Array<Basis*> *bases;
|
||||
BasisType::Check(btype);
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
#pragma omp critical (Poly1DGetBasis)
|
||||
#endif
|
||||
if ( bases_container.find(btype) == bases_container.end() )
|
||||
{
|
||||
auto it = bases_container.find(btype);
|
||||
if (it != bases_container.end())
|
||||
{
|
||||
bases = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we haven't been asked for basis or points of this type yet
|
||||
bases = new Array<Basis*>(h_mt);
|
||||
bases_container[btype] = bases;
|
||||
}
|
||||
if (bases->Size() <= p)
|
||||
{
|
||||
bases->SetSize(p + 1, NULL);
|
||||
}
|
||||
if ((*bases)[p] == NULL)
|
||||
{
|
||||
EvalType etype;
|
||||
if (btype == BasisType::Positive) { etype = Positive; }
|
||||
else if (btype == BasisType::IntegratedGLL) { etype = Integrated; }
|
||||
else { etype = Barycentric; }
|
||||
(*bases)[p] = new Basis(p, GetPoints(p, btype), etype);
|
||||
}
|
||||
// we haven't been asked for basis or points of this type yet
|
||||
bases_container[btype] = new Array<Basis*>(h_mt);
|
||||
}
|
||||
return *(*bases)[p];
|
||||
Array<Basis*> &bases = *bases_container[btype];
|
||||
if (bases.Size() <= p)
|
||||
{
|
||||
bases.SetSize(p + 1, NULL);
|
||||
}
|
||||
if (bases[p] == NULL)
|
||||
{
|
||||
EvalType etype;
|
||||
if (btype == BasisType::Positive) { etype = Positive; }
|
||||
else if (btype == BasisType::IntegratedGLL) { etype = Integrated; }
|
||||
else { etype = Barycentric; }
|
||||
bases[p] = new Basis(p, GetPoints(p, btype), etype);
|
||||
}
|
||||
return *bases[p];
|
||||
}
|
||||
|
||||
Poly_1D::~Poly_1D()
|
||||
@@ -2270,7 +2236,7 @@ Poly_1D::~Poly_1D()
|
||||
it != points_container.end() ; ++it)
|
||||
{
|
||||
Array<double*>& pts = *it->second;
|
||||
for (int i = 0; i < pts.Size(); ++i)
|
||||
for ( int i = 0 ; i < pts.Size() ; ++i )
|
||||
{
|
||||
delete [] pts[i];
|
||||
}
|
||||
@@ -2281,7 +2247,7 @@ Poly_1D::~Poly_1D()
|
||||
it != bases_container.end() ; ++it)
|
||||
{
|
||||
Array<Basis*>& bases = *it->second;
|
||||
for (int i = 0; i < bases.Size(); ++i)
|
||||
for ( int i = 0 ; i < bases.Size() ; ++i )
|
||||
{
|
||||
delete bases[i];
|
||||
}
|
||||
@@ -2495,47 +2461,39 @@ const DofToQuad &TensorBasisElement::GetTensorDofToQuad(
|
||||
DofToQuad::Mode mode, const Poly_1D::Basis &basis, bool closed,
|
||||
Array<DofToQuad*> &dof2quad_array)
|
||||
{
|
||||
DofToQuad *d2q = nullptr;
|
||||
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
#pragma omp critical (DofToQuad)
|
||||
#endif
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const int ndof = closed ? fe.GetOrder() + 1 : fe.GetOrder();
|
||||
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/fe.GetDim()) + 0.5);
|
||||
d2q->FE = &fe;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = ndof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*ndof);
|
||||
d2q->Bt.SetSize(ndof*nqpt);
|
||||
d2q->G.SetSize(nqpt*ndof);
|
||||
d2q->Gt.SetSize(ndof*nqpt);
|
||||
Vector val(ndof), grad(ndof);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
|
||||
// of the 1D rule.
|
||||
basis.Eval(ir.IntPoint(i).x, val, grad);
|
||||
for (int j = 0; j < ndof; j++)
|
||||
{
|
||||
d2q = dof2quad_array[i];
|
||||
if (d2q->IntRule != &ir || d2q->mode != mode) { d2q = nullptr; }
|
||||
}
|
||||
if (!d2q)
|
||||
{
|
||||
d2q = new DofToQuad;
|
||||
const int ndof = closed ? fe.GetOrder() + 1 : fe.GetOrder();
|
||||
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/fe.GetDim()) + 0.5);
|
||||
d2q->FE = &fe;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = ndof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*ndof);
|
||||
d2q->Bt.SetSize(ndof*nqpt);
|
||||
d2q->G.SetSize(nqpt*ndof);
|
||||
d2q->Gt.SetSize(ndof*nqpt);
|
||||
Vector val(ndof), grad(ndof);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
|
||||
// of the 1D rule.
|
||||
basis.Eval(ir.IntPoint(i).x, val, grad);
|
||||
for (int j = 0; j < ndof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
|
||||
}
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
|
||||
}
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -250,7 +250,7 @@ protected:
|
||||
/// Container for all DofToQuad objects created by the FiniteElement.
|
||||
/** Multiple DofToQuad objects may be needed when different quadrature rules
|
||||
or different DofToQuad::Mode are used. */
|
||||
mutable Array<DofToQuad *> dof2quad_array;
|
||||
mutable Array<DofToQuad*> dof2quad_array;
|
||||
|
||||
public:
|
||||
/// Enumeration for range_type and deriv_range_type
|
||||
@@ -596,7 +596,7 @@ public:
|
||||
/** @brief Return a DoF transformation object for this particular type of
|
||||
basis.
|
||||
*/
|
||||
virtual const StatelessDofTransformation *GetDofTransformation() const
|
||||
virtual StatelessDofTransformation * GetDofTransformation() const
|
||||
{ return NULL; }
|
||||
|
||||
/// Deconstruct the FiniteElement
|
||||
@@ -1026,8 +1026,8 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
typedef std::map<int, Array<double*>*> PointsMap;
|
||||
typedef std::map<int, Array<Basis*>*> BasisMap;
|
||||
typedef std::map< int, Array<double*>* > PointsMap;
|
||||
typedef std::map< int, Array<Basis*>* > BasisMap;
|
||||
|
||||
MemoryType h_mt;
|
||||
PointsMap points_container;
|
||||
|
||||
@@ -6031,7 +6031,7 @@ void RT0PyrFiniteElement::CalcVShape(const IntegrationPoint &ip,
|
||||
shape(1,2) = z;
|
||||
|
||||
shape(2,0) = x * (2.0 - z) * ozi;
|
||||
shape(2,1) = - y * z * ozi;
|
||||
shape(2,1) = - y * z * ozi;;
|
||||
shape(2,2) = z;
|
||||
|
||||
shape(3,0) = - x * z * ozi;
|
||||
|
||||
+6
-6
@@ -179,7 +179,7 @@ class ND_TetrahedronElement : public VectorFiniteElement
|
||||
Array<int> dof2tk;
|
||||
DenseMatrixInverse Ti;
|
||||
|
||||
ND_TetDofTransformation doftrans;
|
||||
mutable ND_TetStatelessDofTransformation doftrans;
|
||||
|
||||
public:
|
||||
/// Construct the ND_TetrahedronElement of order @a p
|
||||
@@ -201,7 +201,7 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{ LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
|
||||
virtual const StatelessDofTransformation *GetDofTransformation() const
|
||||
virtual StatelessDofTransformation * GetDofTransformation() const
|
||||
{ return &doftrans; }
|
||||
using FiniteElement::Project;
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
@@ -242,7 +242,7 @@ class ND_TriangleElement : public VectorFiniteElement
|
||||
Array<int> dof2tk;
|
||||
DenseMatrixInverse Ti;
|
||||
|
||||
ND_TriDofTransformation doftrans;
|
||||
mutable ND_TriStatelessDofTransformation doftrans;
|
||||
|
||||
public:
|
||||
/// Construct the ND_TriangleElement of order @a p
|
||||
@@ -264,7 +264,7 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{ LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
|
||||
virtual const StatelessDofTransformation *GetDofTransformation() const
|
||||
virtual StatelessDofTransformation * GetDofTransformation() const
|
||||
{ return &doftrans; }
|
||||
using FiniteElement::Project;
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
@@ -346,7 +346,7 @@ private:
|
||||
#endif
|
||||
Array<int> dof2tk, t_dof, s_dof;
|
||||
|
||||
ND_WedgeDofTransformation doftrans;
|
||||
mutable ND_WedgeStatelessDofTransformation doftrans;
|
||||
|
||||
H1_TriangleElement H1TriangleFE;
|
||||
ND_TriangleElement NDTriangleFE;
|
||||
@@ -379,7 +379,7 @@ public:
|
||||
DenseMatrix &I) const
|
||||
{ LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
|
||||
|
||||
virtual const StatelessDofTransformation *GetDofTransformation() const
|
||||
virtual StatelessDofTransformation * GetDofTransformation() const
|
||||
{ return &doftrans; }
|
||||
|
||||
using FiniteElement::Project;
|
||||
|
||||
+10
-6
@@ -59,7 +59,7 @@ void H1Ser_QuadrilateralElement::CalcShape(const IntegrationPoint &ip,
|
||||
int p = (this)->GetOrder();
|
||||
double x = ip.x, y = ip.y;
|
||||
|
||||
Poly_1D::Basis &edgeNodalBasis = poly1d.GetBasis(p, BasisType::GaussLobatto);
|
||||
Poly_1D::Basis edgeNodalBasis(poly1d.GetBasis(p, BasisType::GaussLobatto));
|
||||
Vector nodalX(p+1);
|
||||
Vector nodalY(p+1);
|
||||
|
||||
@@ -113,9 +113,10 @@ void H1Ser_QuadrilateralElement::CalcShape(const IntegrationPoint &ip,
|
||||
{
|
||||
double *legX = new double[p-1];
|
||||
double *legY = new double[p-1];
|
||||
Poly_1D *storeLegendre = new Poly_1D();
|
||||
|
||||
Poly_1D::CalcLegendre(p-2, x, legX);
|
||||
Poly_1D::CalcLegendre(p-2, y, legY);
|
||||
storeLegendre->CalcLegendre(p-2, x, legX);
|
||||
storeLegendre->CalcLegendre(p-2, y, legY);
|
||||
|
||||
int interior_total = 0;
|
||||
for (int j = 4; j < p + 1; j++)
|
||||
@@ -130,6 +131,7 @@ void H1Ser_QuadrilateralElement::CalcShape(const IntegrationPoint &ip,
|
||||
|
||||
delete[] legX;
|
||||
delete[] legY;
|
||||
delete storeLegendre;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +141,7 @@ void H1Ser_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
|
||||
int p = (this)->GetOrder();
|
||||
double x = ip.x, y = ip.y;
|
||||
|
||||
Poly_1D::Basis &edgeNodalBasis = poly1d.GetBasis(p, BasisType::GaussLobatto);
|
||||
Poly_1D::Basis edgeNodalBasis(poly1d.GetBasis(p, BasisType::GaussLobatto));
|
||||
Vector nodalX(p+1);
|
||||
Vector DnodalX(p+1);
|
||||
Vector nodalY(p+1);
|
||||
@@ -201,9 +203,10 @@ void H1Ser_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
|
||||
double *legY = new double[p-1];
|
||||
double *DlegX = new double[p-1];
|
||||
double *DlegY = new double[p-1];
|
||||
Poly_1D *storeLegendre = new Poly_1D();
|
||||
|
||||
Poly_1D::CalcLegendre(p-2, x, legX, DlegX);
|
||||
Poly_1D::CalcLegendre(p-2, y, legY, DlegY);
|
||||
storeLegendre->CalcLegendre(p-2, x, legX, DlegX);
|
||||
storeLegendre->CalcLegendre(p-2, y, legY, DlegY);
|
||||
|
||||
int interior_total = 0;
|
||||
for (int j = 4; j < p + 1; j++)
|
||||
@@ -221,6 +224,7 @@ void H1Ser_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
|
||||
delete[] legY;
|
||||
delete[] DlegX;
|
||||
delete[] DlegY;
|
||||
delete storeLegendre;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -2896,7 +2896,7 @@ ND_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
}
|
||||
}
|
||||
|
||||
const StatelessDofTransformation *
|
||||
StatelessDofTransformation *
|
||||
ND_FECollection::DofTransformationForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
if (!Geometry::IsTensorProduct(GeomType) && this->GetOrder() > 1)
|
||||
|
||||
+2
-2
@@ -63,7 +63,7 @@ public:
|
||||
/** @brief Returns a DoF transformation object compatible with this basis
|
||||
and geometry type.
|
||||
*/
|
||||
virtual const StatelessDofTransformation *
|
||||
virtual StatelessDofTransformation *
|
||||
DofTransformationForGeometry(Geometry::Type GeomType) const
|
||||
{ return NULL; }
|
||||
|
||||
@@ -483,7 +483,7 @@ public:
|
||||
int DofForGeometry(Geometry::Type GeomType) const override
|
||||
{ return ND_dof[GeomType]; }
|
||||
|
||||
const StatelessDofTransformation *
|
||||
StatelessDofTransformation *
|
||||
DofTransformationForGeometry(Geometry::Type GeomType) const override;
|
||||
|
||||
const int *DofOrderForOrientation(Geometry::Type GeomType,
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#define MFEM_FEM_HPP
|
||||
|
||||
#include "intrules.hpp"
|
||||
#include "intrules_cut.hpp"
|
||||
#include "geom.hpp"
|
||||
#include "fe.hpp"
|
||||
#include "fe_coll.hpp"
|
||||
|
||||
+195
-187
@@ -63,6 +63,7 @@ FiniteElementSpace::FiniteElementSpace()
|
||||
elem_dof(NULL), elem_fos(NULL), bdr_elem_dof(NULL), bdr_elem_fos(NULL),
|
||||
face_dof(NULL),
|
||||
NURBSext(NULL), own_ext(false),
|
||||
DoFTrans(0), VDoFTrans(vdim, ordering),
|
||||
cP_is_set(false),
|
||||
Th(Operator::ANY_TYPE),
|
||||
sequence(0), mesh_sequence(0), orders_changed(false), relaxed_hp(false)
|
||||
@@ -71,6 +72,7 @@ FiniteElementSpace::FiniteElementSpace()
|
||||
FiniteElementSpace::FiniteElementSpace(const FiniteElementSpace &orig,
|
||||
Mesh *mesh_,
|
||||
const FiniteElementCollection *fec_)
|
||||
: VDoFTrans(orig.vdim, orig.ordering)
|
||||
{
|
||||
mesh_ = mesh_ ? mesh_ : orig.mesh;
|
||||
fec_ = fec_ ? fec_ : orig.fec;
|
||||
@@ -210,7 +212,7 @@ void FiniteElementSpace::GetVDofs(int vd, Array<int>& dofs, int ndofs_) const
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::DofsToVDofs(Array<int> &dofs, int ndofs_) const
|
||||
void FiniteElementSpace::DofsToVDofs (Array<int> &dofs, int ndofs_) const
|
||||
{
|
||||
if (vdim == 1) { return; }
|
||||
if (ndofs_ < 0) { ndofs_ = this->ndofs; }
|
||||
@@ -262,7 +264,7 @@ int FiniteElementSpace::DofToVDof(int dof, int vd, int ndofs_) const
|
||||
}
|
||||
|
||||
// static function
|
||||
void FiniteElementSpace::AdjustVDofs(Array<int> &vdofs)
|
||||
void FiniteElementSpace::AdjustVDofs (Array<int> &vdofs)
|
||||
{
|
||||
int n = vdofs.Size(), *vdof = vdofs;
|
||||
for (int i = 0; i < n; i++)
|
||||
@@ -275,36 +277,36 @@ void FiniteElementSpace::AdjustVDofs(Array<int> &vdofs)
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetElementVDofs(int i, Array<int> &vdofs,
|
||||
DofTransformation &doftrans) const
|
||||
{
|
||||
GetElementDofs(i, vdofs, doftrans);
|
||||
DofsToVDofs(vdofs);
|
||||
doftrans.SetVDim(vdim, ordering);
|
||||
}
|
||||
|
||||
DofTransformation *
|
||||
FiniteElementSpace::GetElementVDofs(int i, Array<int> &vdofs) const
|
||||
{
|
||||
DoFTrans.SetDofTransformation(NULL);
|
||||
GetElementVDofs(i, vdofs, DoFTrans);
|
||||
return DoFTrans.GetDofTransformation() ? &DoFTrans : NULL;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetBdrElementVDofs(int i, Array<int> &vdofs,
|
||||
DofTransformation &doftrans) const
|
||||
{
|
||||
GetBdrElementDofs(i, vdofs, doftrans);
|
||||
DofTransformation * doftrans = GetElementDofs(i, vdofs);
|
||||
DofsToVDofs(vdofs);
|
||||
doftrans.SetVDim(vdim, ordering);
|
||||
if (vdim == 1 || doftrans == NULL)
|
||||
{
|
||||
return doftrans;
|
||||
}
|
||||
else
|
||||
{
|
||||
VDoFTrans.SetDofTransformation(*doftrans);
|
||||
return &VDoFTrans;
|
||||
}
|
||||
}
|
||||
|
||||
DofTransformation *
|
||||
FiniteElementSpace::GetBdrElementVDofs(int i, Array<int> &vdofs) const
|
||||
{
|
||||
DoFTrans.SetDofTransformation(NULL);
|
||||
GetBdrElementVDofs(i, vdofs, DoFTrans);
|
||||
return DoFTrans.GetDofTransformation() ? &DoFTrans : NULL;
|
||||
DofTransformation * doftrans = GetBdrElementDofs(i, vdofs);
|
||||
DofsToVDofs(vdofs);
|
||||
if (vdim == 1 || doftrans == NULL)
|
||||
{
|
||||
return doftrans;
|
||||
}
|
||||
else
|
||||
{
|
||||
VDoFTrans.SetDofTransformation(*doftrans);
|
||||
return &VDoFTrans;
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetPatchVDofs(int i, Array<int> &vdofs) const
|
||||
@@ -775,9 +777,9 @@ FiniteElementSpace::H2L_GlobalRestrictionMatrix (FiniteElementSpace *lfes)
|
||||
return R;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::AddDependencies(
|
||||
SparseMatrix& deps, Array<int>& master_dofs, Array<int>& slave_dofs,
|
||||
DenseMatrix& I, int skipfirst)
|
||||
void FiniteElementSpace
|
||||
::AddDependencies(SparseMatrix& deps, Array<int>& master_dofs,
|
||||
Array<int>& slave_dofs, DenseMatrix& I, int skipfirst)
|
||||
{
|
||||
for (int i = skipfirst; i < slave_dofs.Size(); i++)
|
||||
{
|
||||
@@ -800,9 +802,11 @@ void FiniteElementSpace::AddDependencies(
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::AddEdgeFaceDependencies(
|
||||
SparseMatrix &deps, Array<int> &master_dofs, const FiniteElement *master_fe,
|
||||
Array<int> &slave_dofs, int slave_face, const DenseMatrix *pm) const
|
||||
void FiniteElementSpace
|
||||
::AddEdgeFaceDependencies(SparseMatrix &deps, Array<int> &master_dofs,
|
||||
const FiniteElement *master_fe,
|
||||
Array<int> &slave_dofs, int slave_face,
|
||||
const DenseMatrix *pm) const
|
||||
{
|
||||
// In variable-order spaces in 3D, we need to only constrain interior face
|
||||
// DOFs (this is done one level up), since edge dependencies can be more
|
||||
@@ -1529,12 +1533,12 @@ SparseMatrix* FiniteElementSpace::RefinementMatrix(int old_ndofs,
|
||||
localP);
|
||||
}
|
||||
|
||||
FiniteElementSpace::RefinementOperator::RefinementOperator(
|
||||
const FiniteElementSpace* fespace, Table* old_elem_dof, Table* old_elem_fos,
|
||||
int old_ndofs)
|
||||
: fespace(fespace),
|
||||
old_elem_dof(old_elem_dof),
|
||||
old_elem_fos(old_elem_fos)
|
||||
FiniteElementSpace::RefinementOperator::RefinementOperator
|
||||
(const FiniteElementSpace* fespace, Table* old_elem_dof, Table* old_elem_fos,
|
||||
int old_ndofs)
|
||||
: fespace(fespace)
|
||||
, old_elem_dof(old_elem_dof)
|
||||
, old_elem_fos(old_elem_fos)
|
||||
{
|
||||
MFEM_VERIFY(fespace->GetNE() >= old_elem_dof->Size(),
|
||||
"Previous mesh is not coarser.");
|
||||
@@ -1549,7 +1553,7 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
|
||||
fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
|
||||
}
|
||||
|
||||
ConstructDoFTransArray();
|
||||
ConstructDoFTrans();
|
||||
}
|
||||
|
||||
FiniteElementSpace::RefinementOperator::RefinementOperator(
|
||||
@@ -1574,58 +1578,59 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
|
||||
old_elem_fos = new Table(*coarse_fes->GetElementToFaceOrientationTable());
|
||||
}
|
||||
|
||||
ConstructDoFTransArray();
|
||||
ConstructDoFTrans();
|
||||
}
|
||||
|
||||
FiniteElementSpace::RefinementOperator::~RefinementOperator()
|
||||
{
|
||||
delete old_elem_dof;
|
||||
delete old_elem_fos;
|
||||
for (int i=0; i<old_DoFTransArray.Size(); i++)
|
||||
for (int i=0; i<old_DoFTrans.Size(); i++)
|
||||
{
|
||||
delete old_DoFTransArray[i];
|
||||
delete old_DoFTrans[i];
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::RefinementOperator::ConstructDoFTransArray()
|
||||
void FiniteElementSpace::RefinementOperator
|
||||
::ConstructDoFTrans()
|
||||
{
|
||||
old_DoFTransArray.SetSize(Geometry::NUM_GEOMETRIES);
|
||||
for (int i=0; i<old_DoFTransArray.Size(); i++)
|
||||
old_DoFTrans.SetSize(Geometry::NUM_GEOMETRIES);
|
||||
for (int i=0; i<old_DoFTrans.Size(); i++)
|
||||
{
|
||||
old_DoFTransArray[i] = NULL;
|
||||
old_DoFTrans[i] = NULL;
|
||||
}
|
||||
|
||||
const FiniteElementCollection *fec_ref = fespace->FEColl();
|
||||
if (dynamic_cast<const ND_FECollection*>(fec_ref))
|
||||
{
|
||||
const FiniteElement *nd_tri =
|
||||
const FiniteElement * nd_tri =
|
||||
fec_ref->FiniteElementForGeometry(Geometry::TRIANGLE);
|
||||
if (nd_tri)
|
||||
{
|
||||
old_DoFTransArray[Geometry::TRIANGLE] =
|
||||
old_DoFTrans[Geometry::TRIANGLE] =
|
||||
new ND_TriDofTransformation(nd_tri->GetOrder());
|
||||
}
|
||||
|
||||
const FiniteElement *nd_tet =
|
||||
const FiniteElement * nd_tet =
|
||||
fec_ref->FiniteElementForGeometry(Geometry::TETRAHEDRON);
|
||||
if (nd_tet)
|
||||
{
|
||||
old_DoFTransArray[Geometry::TETRAHEDRON] =
|
||||
old_DoFTrans[Geometry::TETRAHEDRON] =
|
||||
new ND_TetDofTransformation(nd_tet->GetOrder());
|
||||
}
|
||||
|
||||
const FiniteElement *nd_pri =
|
||||
const FiniteElement * nd_pri =
|
||||
fec_ref->FiniteElementForGeometry(Geometry::PRISM);
|
||||
if (nd_pri)
|
||||
{
|
||||
old_DoFTransArray[Geometry::PRISM] =
|
||||
old_DoFTrans[Geometry::PRISM] =
|
||||
new ND_WedgeDofTransformation(nd_pri->GetOrder());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::RefinementOperator::Mult(const Vector &x,
|
||||
Vector &y) const
|
||||
void FiniteElementSpace::RefinementOperator
|
||||
::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
Mesh* mesh_ref = fespace->GetMesh();
|
||||
const CoarseFineTransformations &trans_ref =
|
||||
@@ -1657,7 +1662,6 @@ void FiniteElementSpace::RefinementOperator::Mult(const Vector &x,
|
||||
fespace->DofsToVDofs(vd, vdofs);
|
||||
old_dofs.Copy(old_vdofs);
|
||||
fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
|
||||
|
||||
x.GetSubVector(old_vdofs, subX);
|
||||
lP.Mult(subX, subY);
|
||||
y.SetSubVector(vdofs, subY);
|
||||
@@ -1666,30 +1670,40 @@ void FiniteElementSpace::RefinementOperator::Mult(const Vector &x,
|
||||
else
|
||||
{
|
||||
old_elem_fos->GetRow(emb.parent, old_Fo);
|
||||
old_DoFTrans.SetDofTransformation(*old_DoFTransArray[geom]);
|
||||
old_DoFTrans.SetFaceOrientations(old_Fo);
|
||||
old_DoFTrans[geom]->SetFaceOrientations(old_Fo);
|
||||
|
||||
DofTransformation *new_doftrans = NULL;
|
||||
VDofTransformation *vdoftrans =
|
||||
dynamic_cast<VDofTransformation*>(doftrans);
|
||||
if (vdoftrans)
|
||||
{
|
||||
new_doftrans = doftrans;
|
||||
doftrans = vdoftrans->GetDofTransformation();
|
||||
}
|
||||
|
||||
doftrans->SetVDim();
|
||||
for (int vd = 0; vd < rvdim; vd++)
|
||||
{
|
||||
dofs.Copy(vdofs);
|
||||
fespace->DofsToVDofs(vd, vdofs);
|
||||
old_dofs.Copy(old_vdofs);
|
||||
fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
|
||||
|
||||
x.GetSubVector(old_vdofs, subX);
|
||||
old_DoFTrans.InvTransformPrimal(subX);
|
||||
old_DoFTrans[geom]->InvTransformPrimal(subX);
|
||||
lP.Mult(subX, subY);
|
||||
doftrans->TransformPrimal(subY);
|
||||
y.SetSubVector(vdofs, subY);
|
||||
}
|
||||
doftrans->SetVDim(rvdim, fespace->GetOrdering());
|
||||
|
||||
if (vdoftrans)
|
||||
{
|
||||
doftrans = new_doftrans;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::RefinementOperator::MultTranspose(const Vector &x,
|
||||
Vector &y) const
|
||||
void FiniteElementSpace::RefinementOperator
|
||||
::MultTranspose(const Vector &x, Vector &y) const
|
||||
{
|
||||
y = 0.0;
|
||||
|
||||
@@ -1713,7 +1727,7 @@ void FiniteElementSpace::RefinementOperator::MultTranspose(const Vector &x,
|
||||
const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
|
||||
const DenseMatrix &lP = localP[geom](emb.matrix);
|
||||
|
||||
DofTransformation *doftrans = fespace->GetElementDofs(k, f_dofs);
|
||||
DofTransformation * doftrans = fespace->GetElementDofs(k, f_dofs);
|
||||
old_elem_dof->GetRow(emb.parent, c_dofs);
|
||||
|
||||
if (!doftrans)
|
||||
@@ -1728,6 +1742,7 @@ void FiniteElementSpace::RefinementOperator::MultTranspose(const Vector &x,
|
||||
fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
|
||||
|
||||
x.GetSubVector(f_vdofs, subX);
|
||||
|
||||
for (int p = 0; p < f_dofs.Size(); ++p)
|
||||
{
|
||||
if (processed[DecodeDof(f_dofs[p])])
|
||||
@@ -1735,6 +1750,7 @@ void FiniteElementSpace::RefinementOperator::MultTranspose(const Vector &x,
|
||||
subX[p] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
lP.MultTranspose(subX, subY);
|
||||
y.AddElementVector(c_vdofs, subY);
|
||||
}
|
||||
@@ -1744,10 +1760,17 @@ void FiniteElementSpace::RefinementOperator::MultTranspose(const Vector &x,
|
||||
subYt.SetSize(lP.Width());
|
||||
|
||||
old_elem_fos->GetRow(emb.parent, old_Fo);
|
||||
old_DoFTrans.SetDofTransformation(*old_DoFTransArray[geom]);
|
||||
old_DoFTrans.SetFaceOrientations(old_Fo);
|
||||
old_DoFTrans[geom]->SetFaceOrientations(old_Fo);
|
||||
|
||||
DofTransformation *new_doftrans = NULL;
|
||||
VDofTransformation *vdoftrans =
|
||||
dynamic_cast<VDofTransformation*>(doftrans);
|
||||
if (vdoftrans)
|
||||
{
|
||||
new_doftrans = doftrans;
|
||||
doftrans = vdoftrans->GetDofTransformation();
|
||||
}
|
||||
|
||||
doftrans->SetVDim();
|
||||
for (int vd = 0; vd < rvdim; vd++)
|
||||
{
|
||||
f_dofs.Copy(f_vdofs);
|
||||
@@ -1764,11 +1787,16 @@ void FiniteElementSpace::RefinementOperator::MultTranspose(const Vector &x,
|
||||
subX[p] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
lP.MultTranspose(subX, subYt);
|
||||
old_DoFTrans.TransformDual(subYt);
|
||||
old_DoFTrans[geom]->TransformDual(subYt);
|
||||
y.AddElementVector(c_vdofs, subYt);
|
||||
}
|
||||
doftrans->SetVDim(rvdim, fespace->GetOrdering());
|
||||
|
||||
if (vdoftrans)
|
||||
{
|
||||
doftrans = new_doftrans;
|
||||
}
|
||||
}
|
||||
|
||||
for (int p = 0; p < f_dofs.Size(); ++p)
|
||||
@@ -1996,8 +2024,8 @@ FiniteElementSpace::DerefinementOperator::~DerefinementOperator()
|
||||
delete coarse_elem_dof;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::DerefinementOperator::Mult(const Vector &x,
|
||||
Vector &y) const
|
||||
void FiniteElementSpace::DerefinementOperator
|
||||
::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
Array<int> c_vdofs, f_vdofs;
|
||||
Vector loc_x, loc_y;
|
||||
@@ -2199,7 +2227,7 @@ void FiniteElementSpace::Constructor(Mesh *mesh_, NURBSExtension *NURBSext_,
|
||||
R_transpose.reset();
|
||||
cP_is_set = false;
|
||||
|
||||
ConstructDoFTransArray();
|
||||
ConstructDoFTrans();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2211,39 +2239,40 @@ void FiniteElementSpace::Constructor(Mesh *mesh_, NURBSExtension *NURBSext_,
|
||||
BuildElementToDofTable();
|
||||
}
|
||||
|
||||
void FiniteElementSpace::ConstructDoFTransArray()
|
||||
void FiniteElementSpace::ConstructDoFTrans()
|
||||
{
|
||||
DestroyDoFTransArray();
|
||||
DestroyDoFTrans();
|
||||
|
||||
DoFTransArray.SetSize(Geometry::NUM_GEOMETRIES);
|
||||
for (int i=0; i<DoFTransArray.Size(); i++)
|
||||
VDoFTrans.SetVDim(vdim);
|
||||
DoFTrans.SetSize(Geometry::NUM_GEOMETRIES);
|
||||
for (int i=0; i<DoFTrans.Size(); i++)
|
||||
{
|
||||
DoFTransArray[i] = NULL;
|
||||
DoFTrans[i] = NULL;
|
||||
}
|
||||
if (mesh->Dimension() < 3) { return; }
|
||||
if (dynamic_cast<const ND_FECollection*>(fec))
|
||||
{
|
||||
const FiniteElement *nd_tri =
|
||||
const FiniteElement * nd_tri =
|
||||
fec->FiniteElementForGeometry(Geometry::TRIANGLE);
|
||||
if (nd_tri)
|
||||
{
|
||||
DoFTransArray[Geometry::TRIANGLE] =
|
||||
DoFTrans[Geometry::TRIANGLE] =
|
||||
new ND_TriDofTransformation(nd_tri->GetOrder());
|
||||
}
|
||||
|
||||
const FiniteElement *nd_tet =
|
||||
const FiniteElement * nd_tet =
|
||||
fec->FiniteElementForGeometry(Geometry::TETRAHEDRON);
|
||||
if (nd_tet)
|
||||
{
|
||||
DoFTransArray[Geometry::TETRAHEDRON] =
|
||||
DoFTrans[Geometry::TETRAHEDRON] =
|
||||
new ND_TetDofTransformation(nd_tet->GetOrder());
|
||||
}
|
||||
|
||||
const FiniteElement *nd_pri =
|
||||
const FiniteElement * nd_pri =
|
||||
fec->FiniteElementForGeometry(Geometry::PRISM);
|
||||
if (nd_pri)
|
||||
{
|
||||
DoFTransArray[Geometry::PRISM] =
|
||||
DoFTrans[Geometry::PRISM] =
|
||||
new ND_WedgeDofTransformation(nd_pri->GetOrder());
|
||||
}
|
||||
}
|
||||
@@ -2295,7 +2324,7 @@ void FiniteElementSpace::BuildNURBSFaceToDofTable() const
|
||||
face_to_be = -1;
|
||||
for (int b = 0; b < GetNBE(); b++)
|
||||
{
|
||||
int f = mesh->GetBdrElementFaceIndex(b);
|
||||
int f = mesh->GetBdrElementEdgeIndex(b);
|
||||
face_to_be[f] = b;
|
||||
}
|
||||
|
||||
@@ -2447,7 +2476,7 @@ void FiniteElementSpace::Construct()
|
||||
|
||||
ndofs = nvdofs + nedofs + nfdofs + nbdofs;
|
||||
|
||||
ConstructDoFTransArray();
|
||||
ConstructDoFTrans();
|
||||
|
||||
// record the current mesh sequence number to detect refinement etc.
|
||||
mesh_sequence = mesh->GetSequence();
|
||||
@@ -2472,8 +2501,9 @@ int FiniteElementSpace::MinOrder(VarOrderBits bits)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::CalcEdgeFaceVarOrders(
|
||||
Array<VarOrderBits> &edge_orders, Array<VarOrderBits> &face_orders) const
|
||||
void FiniteElementSpace
|
||||
::CalcEdgeFaceVarOrders(Array<VarOrderBits> &edge_orders,
|
||||
Array<VarOrderBits> &face_orders) const
|
||||
{
|
||||
MFEM_ASSERT(IsVariableOrder(), "");
|
||||
MFEM_ASSERT(Nonconforming(), "");
|
||||
@@ -2697,8 +2727,8 @@ int FiniteElementSpace::GetNVariants(int entity, int index) const
|
||||
static const char* msg_orders_changed =
|
||||
"Element orders changed, you need to Update() the space first.";
|
||||
|
||||
void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
DofTransformation &doftrans) const
|
||||
DofTransformation *
|
||||
FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs) const
|
||||
{
|
||||
MFEM_VERIFY(!orders_changed, msg_orders_changed);
|
||||
|
||||
@@ -2706,16 +2736,13 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
{
|
||||
elem_dof->GetRow(elem, dofs);
|
||||
|
||||
if (DoFTransArray[mesh->GetElementBaseGeometry(elem)])
|
||||
if (DoFTrans[mesh->GetElementBaseGeometry(elem)])
|
||||
{
|
||||
Array<int> Fo;
|
||||
elem_fos -> GetRow (elem, Fo);
|
||||
doftrans.SetDofTransformation(
|
||||
*DoFTransArray[mesh->GetElementBaseGeometry(elem)]);
|
||||
doftrans.SetFaceOrientations(Fo);
|
||||
doftrans.SetVDim();
|
||||
DoFTrans[mesh->GetElementBaseGeometry(elem)]->SetFaceOrientations(Fo);
|
||||
}
|
||||
return;
|
||||
return DoFTrans[mesh->GetElementBaseGeometry(elem)];
|
||||
}
|
||||
|
||||
Array<int> V, E, Eo, F, Fo; // TODO: LocalArray
|
||||
@@ -2739,12 +2766,10 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
{
|
||||
nfd += fec->GetNumDof(mesh->GetFaceGeometry(F[i]), order);
|
||||
}
|
||||
if (DoFTransArray[mesh->GetElementBaseGeometry(elem)])
|
||||
if (DoFTrans[mesh->GetElementBaseGeometry(elem)])
|
||||
{
|
||||
doftrans.SetDofTransformation(
|
||||
*DoFTransArray[mesh->GetElementBaseGeometry(elem)]);
|
||||
doftrans.SetFaceOrientations(Fo);
|
||||
doftrans.SetVDim();
|
||||
DoFTrans[mesh->GetElementBaseGeometry(elem)]
|
||||
-> SetFaceOrientations(Fo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2803,18 +2828,54 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
dofs.Append(bbase + j);
|
||||
}
|
||||
}
|
||||
return DoFTrans[mesh->GetElementBaseGeometry(elem)];
|
||||
}
|
||||
|
||||
DofTransformation *FiniteElementSpace::GetElementDofs(int elem,
|
||||
Array<int> &dofs) const
|
||||
void FiniteElementSpace::GetPatchDofs(int patch, Array<int> &dofs) const
|
||||
{
|
||||
DoFTrans.SetDofTransformation(NULL);
|
||||
GetElementDofs(elem, dofs, DoFTrans);
|
||||
return DoFTrans.GetDofTransformation() ? &DoFTrans : NULL;
|
||||
MFEM_ASSERT(NURBSext,
|
||||
"FiniteElementSpace::GetPatchDofs needs a NURBSExtension");
|
||||
NURBSext->GetPatchDofs(patch, dofs);
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
DofTransformation &doftrans) const
|
||||
const FiniteElement *FiniteElementSpace::GetFE(int i) const
|
||||
{
|
||||
if (i < 0 || i >= mesh->GetNE())
|
||||
{
|
||||
if (mesh->GetNE() == 0)
|
||||
{
|
||||
MFEM_ABORT("Empty MPI partitions are not permitted!");
|
||||
}
|
||||
MFEM_ABORT("Invalid element id:" << i << "; minimum allowed:" << 0 <<
|
||||
", maximum allowed:" << mesh->GetNE()-1);
|
||||
}
|
||||
|
||||
const FiniteElement *FE =
|
||||
fec->GetFE(mesh->GetElementGeometry(i), GetElementOrderImpl(i));
|
||||
|
||||
if (NURBSext)
|
||||
{
|
||||
NURBSext->LoadFE(i, FE);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MFEM_DEBUG
|
||||
// consistency check: fec->GetOrder() and FE->GetOrder() should return
|
||||
// the same value (for standard, constant-order spaces)
|
||||
if (!IsVariableOrder() && FE->GetDim() > 0)
|
||||
{
|
||||
MFEM_ASSERT(FE->GetOrder() == fec->GetOrder(),
|
||||
"internal error: " <<
|
||||
FE->GetOrder() << " != " << fec->GetOrder());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return FE;
|
||||
}
|
||||
|
||||
DofTransformation *
|
||||
FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs) const
|
||||
{
|
||||
MFEM_VERIFY(!orders_changed, msg_orders_changed);
|
||||
|
||||
@@ -2822,19 +2883,17 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
{
|
||||
bdr_elem_dof->GetRow(bel, dofs);
|
||||
|
||||
if (DoFTransArray[mesh->GetBdrElementBaseGeometry(bel)])
|
||||
if (DoFTrans[mesh->GetBdrElementBaseGeometry(bel)])
|
||||
{
|
||||
Array<int> Fo;
|
||||
bdr_elem_fos -> GetRow (bel, Fo);
|
||||
doftrans.SetDofTransformation(
|
||||
*DoFTransArray[mesh->GetBdrElementBaseGeometry(bel)]);
|
||||
doftrans.SetFaceOrientations(Fo);
|
||||
doftrans.SetVDim();
|
||||
DoFTrans[mesh->GetBdrElementBaseGeometry(bel)]->
|
||||
SetFaceOrientations(Fo);
|
||||
}
|
||||
return;
|
||||
return DoFTrans[mesh->GetBdrElementBaseGeometry(bel)];
|
||||
}
|
||||
|
||||
Array<int> V, E, Eo; // TODO: LocalArray
|
||||
Array<int> V, E, Eo, Fo; // TODO: LocalArray
|
||||
int F, oF;
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
@@ -2858,14 +2917,11 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
{
|
||||
mesh->GetBdrElementFace(bel, &F, &oF);
|
||||
|
||||
if (DoFTransArray[mesh->GetBdrElementBaseGeometry(bel)])
|
||||
if (DoFTrans[mesh->GetBdrElementBaseGeometry(bel)])
|
||||
{
|
||||
mfem::Array<int> Fo(1);
|
||||
Fo[0] = oF;
|
||||
doftrans.SetDofTransformation(
|
||||
*DoFTransArray[mesh->GetBdrElementBaseGeometry(bel)]);
|
||||
doftrans.SetFaceOrientations(Fo);
|
||||
doftrans.SetVDim();
|
||||
Fo.Append(oF);
|
||||
DoFTrans[mesh->GetBdrElementBaseGeometry(bel)]->
|
||||
SetFaceOrientations(Fo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2907,14 +2963,8 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + fbase, ind[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DofTransformation *FiniteElementSpace::GetBdrElementDofs(int bel,
|
||||
Array<int> &dofs) const
|
||||
{
|
||||
DoFTrans.SetDofTransformation(NULL);
|
||||
GetBdrElementDofs(bel, dofs, DoFTrans);
|
||||
return DoFTrans.GetDofTransformation() ? &DoFTrans : NULL;
|
||||
return DoFTrans[mesh->GetBdrElementBaseGeometry(bel)];
|
||||
}
|
||||
|
||||
int FiniteElementSpace::GetFaceDofs(int face, Array<int> &dofs,
|
||||
@@ -3084,6 +3134,18 @@ int FiniteElementSpace::GetNumElementInteriorDofs(int i) const
|
||||
GetElementOrderImpl(i));
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetEdgeInteriorDofs(int i, Array<int> &dofs) const
|
||||
{
|
||||
MFEM_VERIFY(!IsVariableOrder(), "not implemented");
|
||||
|
||||
int ne = fec->DofForGeometry(Geometry::SEGMENT);
|
||||
dofs.SetSize (ne);
|
||||
for (int j = 0, k = nvdofs+i*ne; j < ne; j++, k++)
|
||||
{
|
||||
dofs[j] = k;
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetFaceInteriorDofs(int i, Array<int> &dofs) const
|
||||
{
|
||||
MFEM_VERIFY(!IsVariableOrder(), "not implemented");
|
||||
@@ -3108,61 +3170,6 @@ void FiniteElementSpace::GetFaceInteriorDofs(int i, Array<int> &dofs) const
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetEdgeInteriorDofs(int i, Array<int> &dofs) const
|
||||
{
|
||||
MFEM_VERIFY(!IsVariableOrder(), "not implemented");
|
||||
|
||||
int ne = fec->DofForGeometry(Geometry::SEGMENT);
|
||||
dofs.SetSize (ne);
|
||||
for (int j = 0, k = nvdofs+i*ne; j < ne; j++, k++)
|
||||
{
|
||||
dofs[j] = k;
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetPatchDofs(int patch, Array<int> &dofs) const
|
||||
{
|
||||
MFEM_ASSERT(NURBSext,
|
||||
"FiniteElementSpace::GetPatchDofs needs a NURBSExtension");
|
||||
NURBSext->GetPatchDofs(patch, dofs);
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetFE(int i) const
|
||||
{
|
||||
if (i < 0 || i >= mesh->GetNE())
|
||||
{
|
||||
if (mesh->GetNE() == 0)
|
||||
{
|
||||
MFEM_ABORT("Empty MPI partitions are not permitted!");
|
||||
}
|
||||
MFEM_ABORT("Invalid element id:" << i << "; minimum allowed:" << 0 <<
|
||||
", maximum allowed:" << mesh->GetNE()-1);
|
||||
}
|
||||
|
||||
const FiniteElement *FE =
|
||||
fec->GetFE(mesh->GetElementGeometry(i), GetElementOrderImpl(i));
|
||||
|
||||
if (NURBSext)
|
||||
{
|
||||
NURBSext->LoadFE(i, FE);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MFEM_DEBUG
|
||||
// consistency check: fec->GetOrder() and FE->GetOrder() should return
|
||||
// the same value (for standard, constant-order spaces)
|
||||
if (!IsVariableOrder() && FE->GetDim() > 0)
|
||||
{
|
||||
MFEM_ASSERT(FE->GetOrder() == fec->GetOrder(),
|
||||
"internal error: " <<
|
||||
FE->GetOrder() << " != " << fec->GetOrder());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return FE;
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetBE(int i) const
|
||||
{
|
||||
int order = fec->GetOrder();
|
||||
@@ -3235,8 +3242,8 @@ const FiniteElement *FiniteElementSpace::GetEdgeElement(int i,
|
||||
return fec->GetFE(Geometry::SEGMENT, eo);
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetTraceElement(
|
||||
int i, Geometry::Type geom_type) const
|
||||
const FiniteElement *FiniteElementSpace
|
||||
::GetTraceElement(int i, Geometry::Type geom_type) const
|
||||
{
|
||||
return fec->TraceFiniteElementForGeometry(geom_type);
|
||||
}
|
||||
@@ -3276,7 +3283,7 @@ void FiniteElementSpace::Destroy()
|
||||
}
|
||||
E2BFQ_array.SetSize(0);
|
||||
|
||||
DestroyDoFTransArray();
|
||||
DestroyDoFTrans();
|
||||
|
||||
dof_elem_array.DeleteAll();
|
||||
dof_ldof_array.DeleteAll();
|
||||
@@ -3294,18 +3301,19 @@ void FiniteElementSpace::Destroy()
|
||||
delete bdr_elem_dof;
|
||||
delete bdr_elem_fos;
|
||||
delete face_dof;
|
||||
|
||||
delete [] bdofs;
|
||||
}
|
||||
ceed::RemoveBasisAndRestriction(this);
|
||||
}
|
||||
|
||||
void FiniteElementSpace::DestroyDoFTransArray()
|
||||
void FiniteElementSpace::DestroyDoFTrans()
|
||||
{
|
||||
for (int i = 0; i < DoFTransArray.Size(); i++)
|
||||
for (int i = 0; i < DoFTrans.Size(); i++)
|
||||
{
|
||||
delete DoFTransArray[i];
|
||||
delete DoFTrans[i];
|
||||
}
|
||||
DoFTransArray.SetSize(0);
|
||||
DoFTrans.SetSize(0);
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetTransferOperator(
|
||||
|
||||
+21
-56
@@ -271,8 +271,8 @@ protected:
|
||||
int own_ext;
|
||||
mutable Array<int> face_to_be; // NURBS FE space only
|
||||
|
||||
Array<StatelessDofTransformation *> DoFTransArray;
|
||||
mutable DofTransformation DoFTrans;
|
||||
Array<DofTransformation*> DoFTrans;
|
||||
mutable VDofTransformation VDoFTrans;
|
||||
|
||||
/** Matrix representing the prolongation from the global conforming dofs to
|
||||
a set of intermediate partially conforming dofs, e.g. the dofs associated
|
||||
@@ -328,8 +328,8 @@ protected:
|
||||
void Construct();
|
||||
void Destroy();
|
||||
|
||||
void ConstructDoFTransArray();
|
||||
void DestroyDoFTransArray();
|
||||
void ConstructDoFTrans();
|
||||
void DestroyDoFTrans();
|
||||
|
||||
void BuildElementToDofTable() const;
|
||||
void BuildBdrElementToDofTable() const;
|
||||
@@ -416,10 +416,10 @@ protected:
|
||||
Table* old_elem_dof; // Owned.
|
||||
Table* old_elem_fos; // Owned.
|
||||
|
||||
Array<StatelessDofTransformation*> old_DoFTransArray;
|
||||
mutable DofTransformation old_DoFTrans;
|
||||
Array<DofTransformation*> old_DoFTrans;
|
||||
mutable VDofTransformation old_VDoFTrans;
|
||||
|
||||
void ConstructDoFTransArray();
|
||||
void ConstructDoFTrans();
|
||||
|
||||
public:
|
||||
/** Construct the operator based on the elem_dof table of the original
|
||||
@@ -803,16 +803,7 @@ public:
|
||||
/// with triangular faces.
|
||||
///
|
||||
/// @note The returned object should NOT be deleted by the caller.
|
||||
DofTransformation *GetElementDofs(int elem, Array<int> &dofs) const;
|
||||
|
||||
/// @brief The same as GetElementDofs(), but with a user-allocated
|
||||
/// DofTransformation object. @a doftrans must be allocated in advance and
|
||||
/// will be owned by the caller. The user can use the
|
||||
/// DofTransformation::GetDofTransformation method on the returned
|
||||
/// @a doftrans object to detect if the DofTransformation should actually be
|
||||
/// used.
|
||||
virtual void GetElementDofs(int elem, Array<int> &dofs,
|
||||
DofTransformation &doftrans) const;
|
||||
virtual DofTransformation *GetElementDofs(int elem, Array<int> &dofs) const;
|
||||
|
||||
/// @brief Returns indices of degrees of freedom for boundary element 'bel'.
|
||||
/// The returned indices are offsets into an @ref ldof vector. See also
|
||||
@@ -826,16 +817,13 @@ public:
|
||||
/// with triangular faces.
|
||||
///
|
||||
/// @note The returned object should NOT be deleted by the caller.
|
||||
DofTransformation *GetBdrElementDofs(int bel, Array<int> &dofs) const;
|
||||
virtual DofTransformation *GetBdrElementDofs(int bel,
|
||||
Array<int> &dofs) const;
|
||||
|
||||
/// @brief The same as GetBdrElementDofs(), but with a user-allocated
|
||||
/// DofTransformation object. @a doftrans must be allocated in advance and
|
||||
/// will be owned by the caller. The user can use the
|
||||
/// DofTransformation::GetDofTransformation method on the returned
|
||||
/// @a doftrans object to detect if the DofTransformation should actually be
|
||||
/// used.
|
||||
virtual void GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
DofTransformation &doftrans) const;
|
||||
/** @brief Returns indices of degrees of freedom for NURBS patch index
|
||||
@a patch. Cartesian ordering is used, for the tensor-product degrees of
|
||||
freedom. */
|
||||
void GetPatchDofs(int patch, Array<int> &dofs) const;
|
||||
|
||||
/// @brief Returns the indices of the degrees of freedom for the specified
|
||||
/// face, including the DOFs for the edges and the vertices of the face.
|
||||
@@ -882,13 +870,6 @@ public:
|
||||
/// GetElementInteriorVDofs().
|
||||
void GetElementInteriorDofs(int i, Array<int> &dofs) const;
|
||||
|
||||
/// @brief Returns the number of degrees of freedom associated with the
|
||||
/// interior of the specified element.
|
||||
///
|
||||
/// See GetElementInteriorDofs() for more information or to obtain the
|
||||
/// relevant indices.
|
||||
int GetNumElementInteriorDofs(int i) const;
|
||||
|
||||
/// @brief Returns the indices of the degrees of freedom for the interior
|
||||
/// of the specified face.
|
||||
///
|
||||
@@ -901,6 +882,13 @@ public:
|
||||
/// GetFaceInteriorVDofs().
|
||||
void GetFaceInteriorDofs(int i, Array<int> &dofs) const;
|
||||
|
||||
/// @brief Returns the number of degrees of freedom associated with the
|
||||
/// interior of the specified element.
|
||||
///
|
||||
/// See GetElementInteriorDofs() for more information or to obtain the
|
||||
/// relevant indices.
|
||||
int GetNumElementInteriorDofs(int i) const;
|
||||
|
||||
/// @brief Returns the indices of the degrees of freedom for the interior
|
||||
/// of the specified edge.
|
||||
///
|
||||
@@ -909,11 +897,6 @@ public:
|
||||
void GetEdgeInteriorDofs(int i, Array<int> &dofs) const;
|
||||
///@}
|
||||
|
||||
/** @brief Returns indices of degrees of freedom for NURBS patch index
|
||||
@a patch. Cartesian ordering is used, for the tensor-product degrees of
|
||||
freedom. */
|
||||
void GetPatchDofs(int patch, Array<int> &dofs) const;
|
||||
|
||||
/// @anchor dof2vdof @name DoF To VDoF Conversion methods
|
||||
/// These methods convert between local dof and local vector dof using the
|
||||
/// appropriate relationship based on the Ordering::Type defined in this
|
||||
@@ -1040,15 +1023,6 @@ public:
|
||||
/// @note The returned object should NOT be deleted by the caller.
|
||||
DofTransformation *GetElementVDofs(int i, Array<int> &vdofs) const;
|
||||
|
||||
/// @brief The same as GetElementVDofs(), but with a user-allocated
|
||||
/// DofTransformation object. @a doftrans must be allocated in advance and
|
||||
/// will be owned by the caller. The user can use the
|
||||
/// DofTransformation::GetDofTransformation method on the returned
|
||||
/// @a doftrans object to detect if the DofTransformation should actually be
|
||||
/// used.
|
||||
void GetElementVDofs(int i, Array<int> &vdofs,
|
||||
DofTransformation &doftrans) const;
|
||||
|
||||
/// @brief Returns indices of degrees of freedom for @a i'th boundary
|
||||
/// element.
|
||||
/// The returned indices are offsets into an @ref ldof vector with @b vdim
|
||||
@@ -1064,15 +1038,6 @@ public:
|
||||
/// @note The returned object should NOT be deleted by the caller.
|
||||
DofTransformation *GetBdrElementVDofs(int i, Array<int> &vdofs) const;
|
||||
|
||||
/// @brief The same as GetBdrElementVDofs(), but with a user-allocated
|
||||
/// DofTransformation object. @a doftrans must be allocated in advance and
|
||||
/// will be owned by the caller. The user can use the
|
||||
/// DofTransformation::GetDofTransformation method on the returned
|
||||
/// @a doftrans object to detect if the DofTransformation should actually be
|
||||
/// used.
|
||||
void GetBdrElementVDofs(int i, Array<int> &vdofs,
|
||||
DofTransformation &doftrans) const;
|
||||
|
||||
/// Returns indices of degrees of freedom in @a vdofs for NURBS patch @a i.
|
||||
void GetPatchVDofs(int i, Array<int> &vdofs) const;
|
||||
|
||||
|
||||
+9
-9
@@ -31,13 +31,13 @@ FmsBasisTypeToMfemBasis(FmsBasisType b)
|
||||
switch (b)
|
||||
{
|
||||
case FMS_NODAL_GAUSS_OPEN:
|
||||
retval = mfem::BasisType::GaussLegendre;
|
||||
retval = mfem::BasisType::GaussLegendre;;
|
||||
break;
|
||||
case FMS_NODAL_GAUSS_CLOSED:
|
||||
retval = mfem::BasisType::GaussLobatto;
|
||||
retval = mfem::BasisType::GaussLobatto;;
|
||||
break;
|
||||
case FMS_POSITIVE:
|
||||
retval = mfem::BasisType::Positive;
|
||||
retval = mfem::BasisType::Positive;;
|
||||
break;
|
||||
case FMS_NODAL_UNIFORM_OPEN:
|
||||
retval = mfem::BasisType::OpenUniform;
|
||||
@@ -1812,22 +1812,22 @@ MeshToFmsMesh(const Mesh *mmesh, FmsMesh *fmesh, FmsComponent *volume)
|
||||
switch (betype)
|
||||
{
|
||||
case Element::POINT:
|
||||
bdr_eles[FMS_VERTEX].push_back(mmesh->GetBdrElementFaceIndex(i));
|
||||
bdr_eles[FMS_VERTEX].push_back(mmesh->GetBdrElementEdgeIndex(i));
|
||||
break;
|
||||
case Element::SEGMENT:
|
||||
bdr_eles[FMS_EDGE].push_back(mmesh->GetBdrElementFaceIndex(i));
|
||||
bdr_eles[FMS_EDGE].push_back(mmesh->GetBdrElementEdgeIndex(i));
|
||||
break;
|
||||
case Element::TRIANGLE:
|
||||
bdr_eles[FMS_TRIANGLE].push_back(mmesh->GetBdrElementFaceIndex(i));
|
||||
bdr_eles[FMS_TRIANGLE].push_back(mmesh->GetBdrElementEdgeIndex(i));
|
||||
break;
|
||||
case Element::QUADRILATERAL:
|
||||
bdr_eles[FMS_QUADRILATERAL].push_back(mmesh->GetBdrElementFaceIndex(i));
|
||||
bdr_eles[FMS_QUADRILATERAL].push_back(mmesh->GetBdrElementEdgeIndex(i));
|
||||
break;
|
||||
case Element::TETRAHEDRON:
|
||||
bdr_eles[FMS_TETRAHEDRON].push_back(mmesh->GetBdrElementFaceIndex(i));
|
||||
bdr_eles[FMS_TETRAHEDRON].push_back(mmesh->GetBdrElementEdgeIndex(i));
|
||||
break;
|
||||
case Element::HEXAHEDRON:
|
||||
bdr_eles[FMS_HEXAHEDRON].push_back(mmesh->GetBdrElementFaceIndex(i));
|
||||
bdr_eles[FMS_HEXAHEDRON].push_back(mmesh->GetBdrElementEdgeIndex(i));
|
||||
break;
|
||||
default:
|
||||
MFEM_WARNING("Unsupported boundary element " << betype << " at boundary index "
|
||||
|
||||
+530
-645
File diff suppressed because it is too large
Load Diff
+15
-18
@@ -65,10 +65,10 @@ public:
|
||||
|
||||
/** @brief Return an IntegrationRule consisting of all vertices of the given
|
||||
Geometry::Type, @a GeomType. */
|
||||
const IntegrationRule *GetVertices(int GeomType) const;
|
||||
const IntegrationRule *GetVertices(int GeomType);
|
||||
|
||||
/// Return the center of the given Geometry::Type, @a GeomType.
|
||||
const IntegrationPoint &GetCenter(int GeomType) const
|
||||
const IntegrationPoint &GetCenter(int GeomType)
|
||||
{ return GeomCenter[GeomType]; }
|
||||
|
||||
/// Get a random point in the reference element specified by @a GeomType.
|
||||
@@ -97,9 +97,9 @@ public:
|
||||
|
||||
const DenseMatrix &GetGeomToPerfGeomJac(int GeomType) const
|
||||
{ return *GeomToPerfGeomJac[GeomType]; }
|
||||
const DenseMatrix *GetPerfGeomToGeomJac(int GeomType) const
|
||||
DenseMatrix *GetPerfGeomToGeomJac(int GeomType)
|
||||
{ return PerfGeomToGeomJac[GeomType]; }
|
||||
void GetPerfPointMat(int GeomType, DenseMatrix &pm) const;
|
||||
void GetPerfPointMat(int GeomType, DenseMatrix &pm);
|
||||
void JacToPerfJac(int GeomType, const DenseMatrix &J,
|
||||
DenseMatrix &PJ) const;
|
||||
|
||||
@@ -122,11 +122,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the inverse of the given orientation for the specified geometry type.
|
||||
static int GetInverseOrientation(Type geom_type, int orientation);
|
||||
|
||||
/// Return the number of boundary "faces" of a given Geometry::Type.
|
||||
int NumBdr(int GeomType) const { return NumBdrArray[GeomType]; }
|
||||
int NumBdr(int GeomType) { return NumBdrArray[GeomType]; }
|
||||
};
|
||||
|
||||
template <> struct
|
||||
@@ -320,27 +317,27 @@ public:
|
||||
int Type;
|
||||
|
||||
RefinedGeometry(int NPts, int NRefG, int NRefE, int NBdrE = 0) :
|
||||
RefPts(NPts), RefGeoms(NRefG), RefEdges(NRefE), NumBdrEdges(NBdrE) {}
|
||||
RefPts(NPts), RefGeoms(NRefG), RefEdges(NRefE), NumBdrEdges(NBdrE) { }
|
||||
};
|
||||
|
||||
class GeometryRefiner
|
||||
{
|
||||
private:
|
||||
int Type; // Quadrature1D type (ClosedUniform is default)
|
||||
int type; // Quadrature1D type (ClosedUniform is default)
|
||||
Array<RefinedGeometry *> RGeom[Geometry::NumGeom];
|
||||
Array<IntegrationRule *> IntPts[Geometry::NumGeom];
|
||||
|
||||
RefinedGeometry *FindInRGeom(Geometry::Type Geom, int Times,
|
||||
int ETimes) const;
|
||||
IntegrationRule *FindInIntPts(Geometry::Type Geom, int NPts) const;
|
||||
RefinedGeometry *FindInRGeom(Geometry::Type Geom, int Times, int ETimes,
|
||||
int Type);
|
||||
IntegrationRule *FindInIntPts(Geometry::Type Geom, int NPts);
|
||||
|
||||
public:
|
||||
GeometryRefiner(int t = Quadrature1D::ClosedUniform) : Type(t) {}
|
||||
GeometryRefiner();
|
||||
|
||||
/// Set the Quadrature1D type of points to use for subdivision.
|
||||
void SetType(int t) { Type = t; }
|
||||
void SetType(const int t) { type = t; }
|
||||
/// Get the Quadrature1D type of points used for subdivision.
|
||||
int GetType() const { return Type; }
|
||||
int GetType() const { return type; }
|
||||
|
||||
RefinedGeometry *Refine(Geometry::Type Geom, int Times, int ETimes = 1);
|
||||
|
||||
@@ -348,10 +345,10 @@ public:
|
||||
const IntegrationRule *RefineInterior(Geometry::Type Geom, int Times);
|
||||
|
||||
/// Get the Refinement level based on number of points
|
||||
static int GetRefinementLevelFromPoints(Geometry::Type Geom, int Npts);
|
||||
virtual int GetRefinementLevelFromPoints(Geometry::Type Geom, int Npts);
|
||||
|
||||
/// Get the Refinement level based on number of elements
|
||||
static int GetRefinementLevelFromElems(Geometry::Type geom, int Npts);
|
||||
virtual int GetRefinementLevelFromElems(Geometry::Type geom, int Npts);
|
||||
|
||||
~GeometryRefiner();
|
||||
};
|
||||
|
||||
+9
-10
@@ -38,8 +38,9 @@ GridFunction::GridFunction(Mesh *m, std::istream &input)
|
||||
// Grid functions are stored on the device
|
||||
UseDevice(true);
|
||||
|
||||
fes = new FiniteElementSpace;
|
||||
fec = fes->Load(m, input);
|
||||
owned_fes.reset(new FiniteElementSpace);
|
||||
fes = owned_fes.get();
|
||||
fec.reset(fes->Load(m, input));
|
||||
|
||||
skip_comment_lines(input, '#');
|
||||
istream::int_type next_char = input.peek();
|
||||
@@ -81,10 +82,11 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
|
||||
int vdim, ordering;
|
||||
|
||||
fes = gf_array[0]->FESpace();
|
||||
fec = FiniteElementCollection::New(fes->FEColl()->Name());
|
||||
fec.reset(FiniteElementCollection::New(fes->FEColl()->Name()));
|
||||
vdim = fes->GetVDim();
|
||||
ordering = fes->GetOrdering();
|
||||
fes = new FiniteElementSpace(m, fec, vdim, ordering);
|
||||
owned_fes.reset(new FiniteElementSpace(m, fec.get(), vdim, ordering));
|
||||
fes = owned_fes.get();
|
||||
SetSize(fes->GetVSize());
|
||||
|
||||
if (m->NURBSext)
|
||||
@@ -153,12 +155,9 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
|
||||
|
||||
void GridFunction::Destroy()
|
||||
{
|
||||
if (fec)
|
||||
{
|
||||
delete fes;
|
||||
delete fec;
|
||||
fec = NULL;
|
||||
}
|
||||
owned_fes.reset();
|
||||
fec.reset();
|
||||
fes = nullptr;
|
||||
}
|
||||
|
||||
void GridFunction::Update()
|
||||
|
||||
+7
-24
@@ -20,6 +20,7 @@
|
||||
#include "../general/adios2stream.hpp"
|
||||
#endif
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
@@ -30,14 +31,13 @@ namespace mfem
|
||||
class GridFunction : public Vector
|
||||
{
|
||||
protected:
|
||||
/// FE space on which the grid function lives. Owned if #fec is not NULL.
|
||||
/// FE space on which the grid function lives.
|
||||
FiniteElementSpace *fes;
|
||||
|
||||
/** @brief Used when the grid function is read from a file. It can also be
|
||||
set explicitly, see MakeOwner().
|
||||
|
||||
If not NULL, this pointer is owned by the GridFunction. */
|
||||
FiniteElementCollection *fec;
|
||||
set explicitly, see MakeOwner(). */
|
||||
std::shared_ptr<FiniteElementCollection> fec;
|
||||
std::shared_ptr<FiniteElementSpace> owned_fes;
|
||||
|
||||
long fes_sequence; // see FiniteElementSpace::sequence, Mesh::sequence
|
||||
|
||||
@@ -74,11 +74,6 @@ public:
|
||||
|
||||
GridFunction() { fes = NULL; fec = NULL; fes_sequence = 0; UseDevice(true); }
|
||||
|
||||
/// Copy constructor. The internal true-dof vector #t_vec is not copied.
|
||||
GridFunction(const GridFunction &orig)
|
||||
: Vector(orig), fes(orig.fes), fec(NULL), fes_sequence(orig.fes_sequence)
|
||||
{ UseDevice(true); }
|
||||
|
||||
/// Construct a GridFunction associated with the FiniteElementSpace @a *f.
|
||||
GridFunction(FiniteElementSpace *f) : Vector(f->GetVSize())
|
||||
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
@@ -107,21 +102,12 @@ public:
|
||||
|
||||
GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces);
|
||||
|
||||
/// 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.
|
||||
|
||||
@note Defining this method overwrites the implicitly defined copy
|
||||
assignment operator. */
|
||||
GridFunction &operator=(const GridFunction &rhs)
|
||||
{ return operator=((const Vector &)rhs); }
|
||||
|
||||
/// Make the GridFunction the owner of #fec and #fes.
|
||||
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec
|
||||
and #fes is taken away. */
|
||||
void MakeOwner(FiniteElementCollection *fec_) { fec = fec_; }
|
||||
void MakeOwner(FiniteElementCollection *fec_) { fec.reset(fec_); }
|
||||
|
||||
FiniteElementCollection *OwnFEC() { return fec; }
|
||||
FiniteElementCollection *OwnFEC() { return fec.get(); }
|
||||
|
||||
int VectorDim() const;
|
||||
int CurlDim() const;
|
||||
@@ -754,9 +740,6 @@ public:
|
||||
/** @brief Write the GridFunction in STL format. Note that the mesh dimension
|
||||
must be 2 and that quad elements will be broken into two triangles.*/
|
||||
void SaveSTL(std::ostream &out, int TimesToRefine = 1);
|
||||
|
||||
/// Destroys grid function.
|
||||
virtual ~GridFunction() { Destroy(); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
+47
-72
@@ -737,7 +737,7 @@ void QuadratureFunctions1D::GivePolyPoints(const int np, double *pts,
|
||||
ClosedGL(np, &ir);
|
||||
break;
|
||||
}
|
||||
case Quadrature1D::Invalid:
|
||||
default:
|
||||
{
|
||||
MFEM_ABORT("Asking for an unknown type of 1D Quadrature points, "
|
||||
"type = " << type);
|
||||
@@ -831,10 +831,7 @@ void QuadratureFunctions1D::CalculateUniformWeights(IntegrationRule *ir,
|
||||
hinv = p+1;
|
||||
ihoffset = 1;
|
||||
break;
|
||||
case Quadrature1D::GaussLegendre:
|
||||
case Quadrature1D::GaussLobatto:
|
||||
case Quadrature1D::ClosedGL:
|
||||
case Quadrature1D::Invalid:
|
||||
default:
|
||||
MFEM_ABORT("invalid Quadrature1D type: " << type);
|
||||
}
|
||||
// set w0 = (-1)^p*(p!)/(hinv^p)
|
||||
@@ -943,10 +940,10 @@ IntegrationRules IntRules(0, Quadrature1D::GaussLegendre);
|
||||
|
||||
IntegrationRules RefinedIntRules(1, Quadrature1D::GaussLegendre);
|
||||
|
||||
IntegrationRules::IntegrationRules(int ref, int type)
|
||||
: quad_type(type)
|
||||
IntegrationRules::IntegrationRules(int Ref, int type_):
|
||||
quad_type(type_)
|
||||
{
|
||||
refined = ref;
|
||||
refined = Ref;
|
||||
|
||||
if (refined < 0) { own_rules = 0; return; }
|
||||
|
||||
@@ -978,19 +975,11 @@ IntegrationRules::IntegrationRules(int ref, int type)
|
||||
|
||||
CubeIntRules.SetSize(32, h_mt);
|
||||
CubeIntRules = NULL;
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
IntRuleLocks.SetSize(Geometry::NUM_GEOMETRIES, h_mt);
|
||||
for (int i = 0; i < Geometry::NUM_GEOMETRIES; i++)
|
||||
{
|
||||
omp_init_lock(&IntRuleLocks[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const IntegrationRule &IntegrationRules::Get(int GeomType, int Order)
|
||||
{
|
||||
Array<IntegrationRule *> *ir_array = NULL;
|
||||
Array<IntegrationRule *> *ir_array;
|
||||
|
||||
switch (GeomType)
|
||||
{
|
||||
@@ -1002,9 +991,9 @@ const IntegrationRule &IntegrationRules::Get(int GeomType, int Order)
|
||||
case Geometry::CUBE: ir_array = &CubeIntRules; break;
|
||||
case Geometry::PRISM: ir_array = &PrismIntRules; break;
|
||||
case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
default:
|
||||
mfem_error("IntegrationRules::Get(...) : Unknown geometry type!");
|
||||
ir_array = NULL;
|
||||
}
|
||||
|
||||
if (Order < 0)
|
||||
@@ -1012,35 +1001,36 @@ const IntegrationRule &IntegrationRules::Get(int GeomType, int Order)
|
||||
Order = 0;
|
||||
}
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
omp_set_lock(&IntRuleLocks[GeomType]);
|
||||
#endif
|
||||
|
||||
if (!HaveIntRule(*ir_array, Order))
|
||||
{
|
||||
IntegrationRule *ir = GenerateIntegrationRule(GeomType, Order);
|
||||
#ifdef MFEM_DEBUG
|
||||
int RealOrder = Order;
|
||||
while (RealOrder+1 < ir_array->Size() && (*ir_array)[RealOrder+1] == ir)
|
||||
#ifdef MFEM_USE_LEGACY_OPENMP
|
||||
#pragma omp critical
|
||||
#endif
|
||||
{
|
||||
RealOrder++;
|
||||
}
|
||||
MFEM_VERIFY(RealOrder == ir->GetOrder(), "internal error");
|
||||
if (!HaveIntRule(*ir_array, Order))
|
||||
{
|
||||
IntegrationRule *ir = GenerateIntegrationRule(GeomType, Order);
|
||||
#ifdef MFEM_DEBUG
|
||||
int RealOrder = Order;
|
||||
while (RealOrder+1 < ir_array->Size() &&
|
||||
(*ir_array)[RealOrder+1] == ir)
|
||||
{
|
||||
RealOrder++;
|
||||
}
|
||||
MFEM_VERIFY(RealOrder == ir->GetOrder(), "internal error");
|
||||
#else
|
||||
MFEM_CONTRACT_VAR(ir);
|
||||
MFEM_CONTRACT_VAR(ir);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
omp_unset_lock(&IntRuleLocks[GeomType]);
|
||||
#endif
|
||||
|
||||
return *(*ir_array)[Order];
|
||||
}
|
||||
|
||||
void IntegrationRules::Set(int GeomType, int Order, IntegrationRule &IntRule)
|
||||
{
|
||||
Array<IntegrationRule *> *ir_array = NULL;
|
||||
Array<IntegrationRule *> *ir_array;
|
||||
|
||||
switch (GeomType)
|
||||
{
|
||||
@@ -1052,15 +1042,11 @@ void IntegrationRules::Set(int GeomType, int Order, IntegrationRule &IntRule)
|
||||
case Geometry::CUBE: ir_array = &CubeIntRules; break;
|
||||
case Geometry::PRISM: ir_array = &PrismIntRules; break;
|
||||
case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
default:
|
||||
mfem_error("IntegrationRules::Set(...) : Unknown geometry type!");
|
||||
ir_array = NULL;
|
||||
}
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
omp_set_lock(&IntRuleLocks[GeomType]);
|
||||
#endif
|
||||
|
||||
if (HaveIntRule(*ir_array, Order))
|
||||
{
|
||||
MFEM_ABORT("Overwriting set rules is not supported!");
|
||||
@@ -1069,19 +1055,16 @@ void IntegrationRules::Set(int GeomType, int Order, IntegrationRule &IntRule)
|
||||
AllocIntRule(*ir_array, Order);
|
||||
|
||||
(*ir_array)[Order] = &IntRule;
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
omp_unset_lock(&IntRuleLocks[GeomType]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void IntegrationRules::DeleteIntRuleArray(
|
||||
Array<IntegrationRule *> &ir_array) const
|
||||
void IntegrationRules::DeleteIntRuleArray(Array<IntegrationRule *> &ir_array)
|
||||
{
|
||||
int i;
|
||||
IntegrationRule *ir = NULL;
|
||||
|
||||
// Many of the intrules have multiple contiguous copies in the ir_array
|
||||
// so we have to be careful to not delete them twice.
|
||||
IntegrationRule *ir = NULL;
|
||||
for (int i = 0; i < ir_array.Size(); i++)
|
||||
for (i = 0; i < ir_array.Size(); i++)
|
||||
{
|
||||
if (ir_array[i] != NULL && ir_array[i] != ir)
|
||||
{
|
||||
@@ -1093,13 +1076,6 @@ void IntegrationRules::DeleteIntRuleArray(
|
||||
|
||||
IntegrationRules::~IntegrationRules()
|
||||
{
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
for (int i = 0; i < Geometry::NUM_GEOMETRIES; i++)
|
||||
{
|
||||
omp_destroy_lock(&IntRuleLocks[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!own_rules) { return; }
|
||||
|
||||
DeleteIntRuleArray(PointIntRules);
|
||||
@@ -1134,11 +1110,10 @@ IntegrationRule *IntegrationRules::GenerateIntegrationRule(int GeomType,
|
||||
return PrismIntegrationRule(Order);
|
||||
case Geometry::PYRAMID:
|
||||
return PyramidIntegrationRule(Order);
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
default:
|
||||
mfem_error("IntegrationRules::Set(...) : Unknown geometry type!");
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1147,7 +1122,7 @@ IntegrationRule *IntegrationRules::PointIntegrationRule(int Order)
|
||||
{
|
||||
if (Order > 1)
|
||||
{
|
||||
MFEM_ABORT("Point Integration Rule of Order > 1 not defined");
|
||||
mfem_error("Point Integration Rule of Order > 1 not defined");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1210,7 +1185,7 @@ IntegrationRule *IntegrationRules::SegmentIntegrationRule(int Order)
|
||||
QuadratureFunctions1D::OpenHalfUniform(n, ir);
|
||||
break;
|
||||
}
|
||||
case Quadrature1D::Invalid:
|
||||
default:
|
||||
{
|
||||
MFEM_ABORT("unknown Quadrature1D type: " << quad_type);
|
||||
}
|
||||
@@ -1787,8 +1762,8 @@ IntegrationRule *IntegrationRules::PyramidIntegrationRule(int Order)
|
||||
|
||||
for (int k=0; k<npts; k++)
|
||||
{
|
||||
const IntegrationPoint &ipc = irc.IntPoint(k);
|
||||
IntegrationPoint &ipp = PyramidIntRules[Order]->IntPoint(k);
|
||||
const IntegrationPoint & ipc = irc.IntPoint(k);
|
||||
IntegrationPoint & ipp = PyramidIntRules[Order]->IntPoint(k);
|
||||
ipp.x = ipc.x * (1.0 - ipc.z);
|
||||
ipp.y = ipc.y * (1.0 - ipc.z);
|
||||
ipp.z = ipc.z;
|
||||
@@ -1800,8 +1775,8 @@ IntegrationRule *IntegrationRules::PyramidIntegrationRule(int Order)
|
||||
// Integration rules for reference prism
|
||||
IntegrationRule *IntegrationRules::PrismIntegrationRule(int Order)
|
||||
{
|
||||
const IntegrationRule &irt = Get(Geometry::TRIANGLE, Order);
|
||||
const IntegrationRule &irs = Get(Geometry::SEGMENT, Order);
|
||||
const IntegrationRule & irt = Get(Geometry::TRIANGLE, Order);
|
||||
const IntegrationRule & irs = Get(Geometry::SEGMENT, Order);
|
||||
int nt = irt.GetNPoints();
|
||||
int ns = irs.GetNPoints();
|
||||
AllocIntRule(PrismIntRules, Order);
|
||||
@@ -1815,12 +1790,12 @@ IntegrationRule *IntegrationRules::PrismIntegrationRule(int Order)
|
||||
|
||||
for (int ks=0; ks<ns; ks++)
|
||||
{
|
||||
const IntegrationPoint &ips = irs.IntPoint(ks);
|
||||
const IntegrationPoint & ips = irs.IntPoint(ks);
|
||||
for (int kt=0; kt<nt; kt++)
|
||||
{
|
||||
int kp = ks * nt + kt;
|
||||
const IntegrationPoint &ipt = irt.IntPoint(kt);
|
||||
IntegrationPoint &ipp = PrismIntRules[Order]->IntPoint(kp);
|
||||
const IntegrationPoint & ipt = irt.IntPoint(kt);
|
||||
IntegrationPoint & ipp = PrismIntRules[Order]->IntPoint(kp);
|
||||
ipp.x = ipt.x;
|
||||
ipp.y = ipt.y;
|
||||
ipp.z = ips.x;
|
||||
|
||||
+5
-11
@@ -14,9 +14,6 @@
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "../general/array.hpp"
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
@@ -431,18 +428,14 @@ private:
|
||||
Array<IntegrationRule *> PrismIntRules;
|
||||
Array<IntegrationRule *> CubeIntRules;
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
Array<omp_lock_t> IntRuleLocks;
|
||||
#endif
|
||||
|
||||
void AllocIntRule(Array<IntegrationRule *> &ir_array, int Order) const
|
||||
void AllocIntRule(Array<IntegrationRule *> &ir_array, int Order)
|
||||
{
|
||||
if (ir_array.Size() <= Order)
|
||||
{
|
||||
ir_array.SetSize(Order + 1, NULL);
|
||||
}
|
||||
}
|
||||
bool HaveIntRule(Array<IntegrationRule *> &ir_array, int Order) const
|
||||
bool HaveIntRule(Array<IntegrationRule *> &ir_array, int Order)
|
||||
{
|
||||
return (ir_array.Size() > Order && ir_array[Order] != NULL);
|
||||
}
|
||||
@@ -450,7 +443,6 @@ private:
|
||||
{
|
||||
return Order | 1; // valid for all quad_type's
|
||||
}
|
||||
void DeleteIntRuleArray(Array<IntegrationRule *> &ir_array) const;
|
||||
|
||||
/// The following methods allocate new IntegrationRule objects without
|
||||
/// checking if they already exist. To avoid memory leaks use
|
||||
@@ -465,10 +457,12 @@ private:
|
||||
IntegrationRule *PrismIntegrationRule(int Order);
|
||||
IntegrationRule *CubeIntegrationRule(int Order);
|
||||
|
||||
void DeleteIntRuleArray(Array<IntegrationRule *> &ir_array);
|
||||
|
||||
public:
|
||||
/// Sets initial sizes for the integration rule arrays, but rules
|
||||
/// are defined the first time they are requested with the Get method.
|
||||
explicit IntegrationRules(int ref = 0,
|
||||
explicit IntegrationRules(int Ref = 0,
|
||||
int type = Quadrature1D::GaussLegendre);
|
||||
|
||||
/// Returns an integration rule for given GeomType and Order.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -137,7 +137,7 @@ bool LinearForm::SupportsDevice() const
|
||||
// Make sure every boundary element corresponds to a boundary face
|
||||
for (int be = 0; be < fes->GetNBE(); ++be)
|
||||
{
|
||||
const int f = mesh.GetBdrElementFaceIndex(be);
|
||||
const int f = mesh.GetBdrElementEdgeIndex(be);
|
||||
const auto face_info = mesh.GetFaceInformation(f);
|
||||
if (!face_info.IsBoundary())
|
||||
{
|
||||
|
||||
@@ -148,7 +148,7 @@ void LinearFormExtension::Update()
|
||||
std::unordered_map<int,int> f_to_be;
|
||||
for (int i = 0; i < mesh.GetNBE(); ++i)
|
||||
{
|
||||
const int f = mesh.GetBdrElementFaceIndex(i);
|
||||
const int f = mesh.GetBdrElementEdgeIndex(i);
|
||||
f_to_be[f] = i;
|
||||
}
|
||||
MFEM_VERIFY(size_t(nf_bdr) == f_to_be.size(), "Incompatible sizes");
|
||||
|
||||
+8
-8
@@ -257,13 +257,13 @@ void BatchedLOR_AMS::FormCoordinateVectors(const Vector &X_vert)
|
||||
// vertices of the LOR mesh. The vertex coordinates are already computed in
|
||||
// E-vector format and passed in in X_vert.
|
||||
//
|
||||
// In this function, we need to convert X_vert (which has the shape (sdim,
|
||||
// In this function, we need to convert X_vert (which has the shape (dim,
|
||||
// ndof_per_el, nel_ho)) to T-DOF format.
|
||||
//
|
||||
// We place the results in the vector xyz_tvec, which has shape (ntdofs, sdim)
|
||||
// We place the results in the vector xyz_tvec, which has shape (ntdofs, dim)
|
||||
// and then make the hypre vectors x, y, and z point to subvectors.
|
||||
//
|
||||
// When the space dimension is 2, z is NULL.
|
||||
// In 2D, z is NULL.
|
||||
|
||||
// Create the H1 vertex space and get the element restriction
|
||||
ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
@@ -275,17 +275,17 @@ void BatchedLOR_AMS::FormCoordinateVectors(const Vector &X_vert)
|
||||
const int nel_ho = vert_fes.GetNE();
|
||||
const int ndp1 = order + 1;
|
||||
const int ndof_per_el = static_cast<int>(pow(ndp1, dim));
|
||||
const int sdim = vert_fes.GetMesh()->SpaceDimension();
|
||||
const int sdim = dim;
|
||||
const int ntdofs = R->Height();
|
||||
|
||||
const MemoryClass mc = GetHypreMemoryClass();
|
||||
bool dev = (mc == MemoryClass::DEVICE);
|
||||
|
||||
xyz_tvec = new Vector(ntdofs*sdim);
|
||||
xyz_tvec = new Vector(ntdofs*dim);
|
||||
|
||||
auto xyz_tv = Reshape(HypreWrite(xyz_tvec->GetMemory()), ntdofs, sdim);
|
||||
auto xyz_tv = Reshape(HypreWrite(xyz_tvec->GetMemory()), ntdofs, dim);
|
||||
const auto xyz_e =
|
||||
Reshape(HypreRead(X_vert.GetMemory()), sdim, ndof_per_el, nel_ho);
|
||||
Reshape(HypreRead(X_vert.GetMemory()), dim, ndof_per_el, nel_ho);
|
||||
const auto d_offsets = HypreRead(el_restr->Offsets().GetMemory());
|
||||
const auto d_indices = HypreRead(el_restr->Indices().GetMemory());
|
||||
const auto ltdof_ldof = HypreRead(R->GetMemoryJ());
|
||||
@@ -309,7 +309,7 @@ void BatchedLOR_AMS::FormCoordinateVectors(const Vector &X_vert)
|
||||
x = new HypreParVector(vert_fes.GetComm(), glob_size, d_x_ptr, cols, dev);
|
||||
double *d_y_ptr = xyz_tv + 1*ntdofs;
|
||||
y = new HypreParVector(vert_fes.GetComm(), glob_size, d_y_ptr, cols, dev);
|
||||
if (sdim == 3)
|
||||
if (dim == 3)
|
||||
{
|
||||
double *d_z_ptr = xyz_tv + 2*ntdofs;
|
||||
z = new HypreParVector(vert_fes.GetComm(), glob_size, d_z_ptr, cols, dev);
|
||||
|
||||
+31
-37
@@ -77,7 +77,6 @@ void BatchedLORAssembly::FormLORVertexCoordinates(FiniteElementSpace &fes_ho,
|
||||
|
||||
// Get nodal points at the LOR vertices
|
||||
const int dim = mesh_ho.Dimension();
|
||||
const int sdim = mesh_ho.SpaceDimension();
|
||||
const int nel_ho = mesh_ho.GetNE();
|
||||
const int order = fes_ho.GetMaxElementOrder();
|
||||
const int nd1d = order + 1;
|
||||
@@ -95,7 +94,7 @@ void BatchedLORAssembly::FormLORVertexCoordinates(FiniteElementSpace &fes_ho,
|
||||
IntegrationRule ir = GetCollocatedIntRule(fes_ho);
|
||||
|
||||
// Map from nodal E-vector to Q-vector at the LOR vertex points
|
||||
X_vert.SetSize(sdim*ndof_per_el*nel_ho);
|
||||
X_vert.SetSize(dim*ndof_per_el*nel_ho);
|
||||
const QuadratureInterpolator *quad_interp =
|
||||
nodal_fes->GetQuadratureInterpolator(ir);
|
||||
quad_interp->SetOutputLayout(QVectorLayout::byVDIM);
|
||||
@@ -381,49 +380,44 @@ void BatchedLORAssembly::SparseIJToCSR(OperatorHandle &A) const
|
||||
FillJAndData(*A_mat);
|
||||
}
|
||||
|
||||
template <int ORDER, int SDIM, typename LOR_KERNEL>
|
||||
static void Assemble_(LOR_KERNEL &kernel, int dim)
|
||||
{
|
||||
if (dim == 2) { kernel.template Assemble2D<ORDER,SDIM>(); }
|
||||
else if (dim == 3) { kernel.template Assemble3D<ORDER>(); }
|
||||
else { MFEM_ABORT("Unsupported dimension"); }
|
||||
}
|
||||
|
||||
template <int ORDER, typename LOR_KERNEL>
|
||||
static void Assemble_(LOR_KERNEL &kernel, int dim, int sdim)
|
||||
{
|
||||
if (sdim == 2) { Assemble_<ORDER,2>(kernel, dim); }
|
||||
else if (sdim == 3) { Assemble_<ORDER,3>(kernel, dim); }
|
||||
else { MFEM_ABORT("Unsupported space dimension."); }
|
||||
}
|
||||
|
||||
template <typename LOR_KERNEL>
|
||||
static void Assemble_(LOR_KERNEL &kernel, int dim, int sdim, int order)
|
||||
{
|
||||
switch (order)
|
||||
{
|
||||
case 1: Assemble_<1>(kernel, dim, sdim); break;
|
||||
case 2: Assemble_<2>(kernel, dim, sdim); break;
|
||||
case 3: Assemble_<3>(kernel, dim, sdim); break;
|
||||
case 4: Assemble_<4>(kernel, dim, sdim); break;
|
||||
case 5: Assemble_<5>(kernel, dim, sdim); break;
|
||||
case 6: Assemble_<6>(kernel, dim, sdim); break;
|
||||
case 7: Assemble_<7>(kernel, dim, sdim); break;
|
||||
case 8: Assemble_<8>(kernel, dim, sdim); break;
|
||||
default: MFEM_ABORT("No kernel order " << order << "!");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LOR_KERNEL>
|
||||
void BatchedLORAssembly::AssemblyKernel(BilinearForm &a)
|
||||
{
|
||||
LOR_KERNEL kernel(a, fes_ho, X_vert, sparse_ij, sparse_mapping);
|
||||
|
||||
const int dim = fes_ho.GetMesh()->Dimension();
|
||||
const int sdim = fes_ho.GetMesh()->SpaceDimension();
|
||||
const int order = fes_ho.GetMaxElementOrder();
|
||||
|
||||
Assemble_(kernel, dim, sdim, order);
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (order)
|
||||
{
|
||||
case 1: kernel.template Assemble2D<1>(); break;
|
||||
case 2: kernel.template Assemble2D<2>(); break;
|
||||
case 3: kernel.template Assemble2D<3>(); break;
|
||||
case 4: kernel.template Assemble2D<4>(); break;
|
||||
case 5: kernel.template Assemble2D<5>(); break;
|
||||
case 6: kernel.template Assemble2D<6>(); break;
|
||||
case 7: kernel.template Assemble2D<7>(); break;
|
||||
case 8: kernel.template Assemble2D<8>(); break;
|
||||
default: MFEM_ABORT("No kernel order " << order << "!");
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch (order)
|
||||
{
|
||||
case 1: kernel.template Assemble3D<1>(); break;
|
||||
case 2: kernel.template Assemble3D<2>(); break;
|
||||
case 3: kernel.template Assemble3D<3>(); break;
|
||||
case 4: kernel.template Assemble3D<4>(); break;
|
||||
case 5: kernel.template Assemble3D<5>(); break;
|
||||
case 6: kernel.template Assemble3D<6>(); break;
|
||||
case 7: kernel.template Assemble3D<7>(); break;
|
||||
case 8: kernel.template Assemble3D<8>(); break;
|
||||
default: MFEM_ABORT("No kernel order " << order << "!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BatchedLORAssembly::AssembleWithoutBC(BilinearForm &a, OperatorHandle &A)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "lor_h1.hpp"
|
||||
#include "lor_util.hpp"
|
||||
#include "../../linalg/dtensor.hpp"
|
||||
#include "../../general/forall.hpp"
|
||||
@@ -16,7 +17,7 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template <int ORDER, int SDIM>
|
||||
template <int ORDER>
|
||||
void BatchedLOR_H1::Assemble2D()
|
||||
{
|
||||
const int nel_ho = fes_ho.GetNE();
|
||||
@@ -73,8 +74,31 @@ void BatchedLOR_H1::Assemble2D()
|
||||
|
||||
for (int i=0; i<sz_local_mat; ++i) { local_mat[i] = 0.0; }
|
||||
|
||||
SetupLORQuadData2D<ORDER,SDIM,false,false>(X, iel_ho, kx, ky, Q, false);
|
||||
double vx[4], vy[4];
|
||||
LORVertexCoordinates2D<ORDER>(X, iel_ho, kx, ky, vx, vy);
|
||||
|
||||
for (int iqy=0; iqy<2; ++iqy)
|
||||
{
|
||||
for (int iqx=0; iqx<2; ++iqx)
|
||||
{
|
||||
const double x = iqx;
|
||||
const double y = iqy;
|
||||
const double w = 1.0/4.0;
|
||||
|
||||
double J_[2*2];
|
||||
DeviceTensor<2> J(J_, 2, 2);
|
||||
|
||||
Jacobian2D(x, y, vx, vy, J);
|
||||
|
||||
const double detJ = Det2D(J);
|
||||
const double w_detJ = w/detJ;
|
||||
|
||||
Q(0,iqy,iqx) = w_detJ * (J(0,1)*J(0,1) + J(1,1)*J(1,1)); // 1,1
|
||||
Q(1,iqy,iqx) = -w_detJ * (J(0,1)*J(0,0) + J(1,1)*J(1,0)); // 1,2
|
||||
Q(2,iqy,iqx) = w_detJ * (J(0,0)*J(0,0) + J(1,0)*J(1,0)); // 2,2
|
||||
Q(3,iqy,iqx) = w*detJ;
|
||||
}
|
||||
}
|
||||
for (int iqx=0; iqx<2; ++iqx)
|
||||
{
|
||||
for (int iqy=0; iqy<2; ++iqy)
|
||||
@@ -495,4 +519,34 @@ void BatchedLOR_H1::Assemble3D()
|
||||
}
|
||||
}
|
||||
|
||||
// Explicit template instantiations
|
||||
template void BatchedLOR_H1::Assemble2D<1>();
|
||||
template void BatchedLOR_H1::Assemble2D<2>();
|
||||
template void BatchedLOR_H1::Assemble2D<3>();
|
||||
template void BatchedLOR_H1::Assemble2D<4>();
|
||||
template void BatchedLOR_H1::Assemble2D<5>();
|
||||
template void BatchedLOR_H1::Assemble2D<6>();
|
||||
template void BatchedLOR_H1::Assemble2D<7>();
|
||||
template void BatchedLOR_H1::Assemble2D<8>();
|
||||
|
||||
template void BatchedLOR_H1::Assemble3D<1>();
|
||||
template void BatchedLOR_H1::Assemble3D<2>();
|
||||
template void BatchedLOR_H1::Assemble3D<3>();
|
||||
template void BatchedLOR_H1::Assemble3D<4>();
|
||||
template void BatchedLOR_H1::Assemble3D<5>();
|
||||
template void BatchedLOR_H1::Assemble3D<6>();
|
||||
template void BatchedLOR_H1::Assemble3D<7>();
|
||||
template void BatchedLOR_H1::Assemble3D<8>();
|
||||
|
||||
BatchedLOR_H1::BatchedLOR_H1(BilinearForm &a,
|
||||
FiniteElementSpace &fes_ho_,
|
||||
Vector &X_vert_,
|
||||
Vector &sparse_ij_,
|
||||
Array<int> &sparse_mapping_)
|
||||
: BatchedLORKernel(fes_ho_, X_vert_, sparse_ij_, sparse_mapping_)
|
||||
{
|
||||
ProjectLORCoefficient<MassIntegrator>(a, c1);
|
||||
ProjectLORCoefficient<DiffusionIntegrator>(a, c2);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
+2
-9
@@ -22,22 +22,15 @@ namespace mfem
|
||||
class BatchedLOR_H1 : BatchedLORKernel
|
||||
{
|
||||
public:
|
||||
template <int ORDER, int SDIM> void Assemble2D();
|
||||
template <int ORDER> void Assemble2D();
|
||||
template <int ORDER> void Assemble3D();
|
||||
BatchedLOR_H1(BilinearForm &a,
|
||||
FiniteElementSpace &fes_ho_,
|
||||
Vector &X_vert_,
|
||||
Vector &sparse_ij_,
|
||||
Array<int> &sparse_mapping_)
|
||||
: BatchedLORKernel(fes_ho_, X_vert_, sparse_ij_, sparse_mapping_)
|
||||
{
|
||||
ProjectLORCoefficient<MassIntegrator>(a, c1);
|
||||
ProjectLORCoefficient<DiffusionIntegrator>(a, c2);
|
||||
}
|
||||
Array<int> &sparse_mapping_);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "lor_h1_impl.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "lor_nd.hpp"
|
||||
#include "lor_util.hpp"
|
||||
#include "../../linalg/dtensor.hpp"
|
||||
#include "../../general/forall.hpp"
|
||||
@@ -16,7 +17,7 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template <int ORDER, int SDIM>
|
||||
template <int ORDER>
|
||||
void BatchedLOR_ND::Assemble2D()
|
||||
{
|
||||
const int nel_ho = fes_ho.GetNE();
|
||||
@@ -82,8 +83,31 @@ void BatchedLOR_ND::Assemble2D()
|
||||
// local_mat is the local (dense) stiffness matrix
|
||||
for (int i=0; i<sz_local_mat; ++i) { local_mat[i] = 0.0; }
|
||||
|
||||
SetupLORQuadData2D<ORDER,SDIM,false,true>(X, iel_ho, kx, ky, Q, true);
|
||||
double vx[4], vy[4];
|
||||
LORVertexCoordinates2D<ORDER>(X, iel_ho, kx, ky, vx, vy);
|
||||
|
||||
for (int iqx=0; iqx<2; ++iqx)
|
||||
{
|
||||
for (int iqy=0; iqy<2; ++iqy)
|
||||
{
|
||||
const double x = iqx;
|
||||
const double y = iqy;
|
||||
const double w = 1.0/4.0;
|
||||
|
||||
double J_[2*2];
|
||||
DeviceTensor<2> J(J_, 2, 2);
|
||||
|
||||
Jacobian2D(x, y, vx, vy, J);
|
||||
|
||||
const double detJ = Det2D(J);
|
||||
const double w_detJ = w/detJ;
|
||||
|
||||
Q(0,iqy,iqx) = w_detJ * (J(0,1)*J(0,1) + J(1,1)*J(1,1)); // 1,1
|
||||
Q(1,iqy,iqx) = -w_detJ * (J(0,1)*J(0,0) + J(1,1)*J(1,0)); // 1,2
|
||||
Q(2,iqy,iqx) = w_detJ * (J(0,0)*J(0,0) + J(1,0)*J(1,0)); // 2,2
|
||||
Q(3,iqy,iqx) = w_detJ;
|
||||
}
|
||||
}
|
||||
for (int iqx=0; iqx<2; ++iqx)
|
||||
{
|
||||
for (int iqy=0; iqy<2; ++iqy)
|
||||
@@ -539,4 +563,34 @@ void BatchedLOR_ND::Assemble3D()
|
||||
}
|
||||
}
|
||||
|
||||
// Explicit template instantiations
|
||||
template void BatchedLOR_ND::Assemble2D<1>();
|
||||
template void BatchedLOR_ND::Assemble2D<2>();
|
||||
template void BatchedLOR_ND::Assemble2D<3>();
|
||||
template void BatchedLOR_ND::Assemble2D<4>();
|
||||
template void BatchedLOR_ND::Assemble2D<5>();
|
||||
template void BatchedLOR_ND::Assemble2D<6>();
|
||||
template void BatchedLOR_ND::Assemble2D<7>();
|
||||
template void BatchedLOR_ND::Assemble2D<8>();
|
||||
|
||||
template void BatchedLOR_ND::Assemble3D<1>();
|
||||
template void BatchedLOR_ND::Assemble3D<2>();
|
||||
template void BatchedLOR_ND::Assemble3D<3>();
|
||||
template void BatchedLOR_ND::Assemble3D<4>();
|
||||
template void BatchedLOR_ND::Assemble3D<5>();
|
||||
template void BatchedLOR_ND::Assemble3D<6>();
|
||||
template void BatchedLOR_ND::Assemble3D<7>();
|
||||
template void BatchedLOR_ND::Assemble3D<8>();
|
||||
|
||||
BatchedLOR_ND::BatchedLOR_ND(BilinearForm &a,
|
||||
FiniteElementSpace &fes_ho_,
|
||||
Vector &X_vert_,
|
||||
Vector &sparse_ij_,
|
||||
Array<int> &sparse_mapping_)
|
||||
: BatchedLORKernel(fes_ho_, X_vert_, sparse_ij_, sparse_mapping_)
|
||||
{
|
||||
ProjectLORCoefficient<VectorFEMassIntegrator>(a, c1);
|
||||
ProjectLORCoefficient<CurlCurlIntegrator>(a, c2);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
+2
-9
@@ -22,22 +22,15 @@ namespace mfem
|
||||
class BatchedLOR_ND : BatchedLORKernel
|
||||
{
|
||||
public:
|
||||
template <int ORDER, int SDIM> void Assemble2D();
|
||||
template <int ORDER> void Assemble2D();
|
||||
template <int ORDER> void Assemble3D();
|
||||
BatchedLOR_ND(BilinearForm &a,
|
||||
FiniteElementSpace &fes_ho_,
|
||||
Vector &X_vert_,
|
||||
Vector &sparse_ij_,
|
||||
Array<int> &sparse_mapping_)
|
||||
: BatchedLORKernel(fes_ho_, X_vert_, sparse_ij_, sparse_mapping_)
|
||||
{
|
||||
ProjectLORCoefficient<VectorFEMassIntegrator>(a, c1);
|
||||
ProjectLORCoefficient<CurlCurlIntegrator>(a, c2);
|
||||
}
|
||||
Array<int> &sparse_mapping_);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "lor_nd_impl.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "lor_rt.hpp"
|
||||
#include "lor_util.hpp"
|
||||
#include "../../linalg/dtensor.hpp"
|
||||
#include "../../general/forall.hpp"
|
||||
@@ -16,7 +17,7 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template <int ORDER, int SDIM>
|
||||
template <int ORDER>
|
||||
void BatchedLOR_RT::Assemble2D()
|
||||
{
|
||||
const int nel_ho = fes_ho.GetNE();
|
||||
@@ -78,8 +79,31 @@ void BatchedLOR_RT::Assemble2D()
|
||||
// local_mat is the local (dense) stiffness matrix
|
||||
for (int i=0; i<sz_local_mat; ++i) { local_mat[i] = 0.0; }
|
||||
|
||||
SetupLORQuadData2D<ORDER,SDIM,true,false>(X, iel_ho, kx, ky, Q, true);
|
||||
double vx[4], vy[4];
|
||||
LORVertexCoordinates2D<ORDER>(X, iel_ho, kx, ky, vx, vy);
|
||||
|
||||
for (int iqx=0; iqx<2; ++iqx)
|
||||
{
|
||||
for (int iqy=0; iqy<2; ++iqy)
|
||||
{
|
||||
const double x = iqx;
|
||||
const double y = iqy;
|
||||
const double w = 1.0/4.0;
|
||||
|
||||
double J_[2*2];
|
||||
DeviceTensor<2> J(J_, 2, 2);
|
||||
|
||||
Jacobian2D(x, y, vx, vy, J);
|
||||
|
||||
const double detJ = Det2D(J);
|
||||
const double w_detJ = w/detJ;
|
||||
|
||||
Q(0,iqy,iqx) = w_detJ * (J(0,0)*J(0,0) + J(1,0)*J(1,0)); // 1,1
|
||||
Q(1,iqy,iqx) = w_detJ * (J(0,0)*J(0,1) + J(1,0)*J(1,1)); // 1,2
|
||||
Q(2,iqy,iqx) = w_detJ * (J(0,1)*J(0,1) + J(1,1)*J(1,1)); // 2,2
|
||||
Q(3,iqy,iqx) = w_detJ;
|
||||
}
|
||||
}
|
||||
for (int iqx=0; iqx<2; ++iqx)
|
||||
{
|
||||
for (int iqy=0; iqy<2; ++iqy)
|
||||
@@ -523,4 +547,34 @@ void BatchedLOR_RT::Assemble3D()
|
||||
}
|
||||
}
|
||||
|
||||
// Explicit template instantiations
|
||||
template void BatchedLOR_RT::Assemble2D<1>();
|
||||
template void BatchedLOR_RT::Assemble2D<2>();
|
||||
template void BatchedLOR_RT::Assemble2D<3>();
|
||||
template void BatchedLOR_RT::Assemble2D<4>();
|
||||
template void BatchedLOR_RT::Assemble2D<5>();
|
||||
template void BatchedLOR_RT::Assemble2D<6>();
|
||||
template void BatchedLOR_RT::Assemble2D<7>();
|
||||
template void BatchedLOR_RT::Assemble2D<8>();
|
||||
|
||||
template void BatchedLOR_RT::Assemble3D<1>();
|
||||
template void BatchedLOR_RT::Assemble3D<2>();
|
||||
template void BatchedLOR_RT::Assemble3D<3>();
|
||||
template void BatchedLOR_RT::Assemble3D<4>();
|
||||
template void BatchedLOR_RT::Assemble3D<5>();
|
||||
template void BatchedLOR_RT::Assemble3D<6>();
|
||||
template void BatchedLOR_RT::Assemble3D<7>();
|
||||
template void BatchedLOR_RT::Assemble3D<8>();
|
||||
|
||||
BatchedLOR_RT::BatchedLOR_RT(BilinearForm &a,
|
||||
FiniteElementSpace &fes_ho_,
|
||||
Vector &X_vert_,
|
||||
Vector &sparse_ij_,
|
||||
Array<int> &sparse_mapping_)
|
||||
: BatchedLORKernel(fes_ho_, X_vert_, sparse_ij_, sparse_mapping_)
|
||||
{
|
||||
ProjectLORCoefficient<VectorFEMassIntegrator>(a, c1);
|
||||
ProjectLORCoefficient<DivDivIntegrator>(a, c2);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
+2
-9
@@ -22,22 +22,15 @@ namespace mfem
|
||||
class BatchedLOR_RT : BatchedLORKernel
|
||||
{
|
||||
public:
|
||||
template <int ORDER, int SDIM> void Assemble2D();
|
||||
template <int ORDER> void Assemble2D();
|
||||
template <int ORDER> void Assemble3D();
|
||||
BatchedLOR_RT(BilinearForm &a,
|
||||
FiniteElementSpace &fes_ho_,
|
||||
Vector &X_vert_,
|
||||
Vector &sparse_ij_,
|
||||
Array<int> &sparse_mapping_)
|
||||
: BatchedLORKernel(fes_ho_, X_vert_, sparse_ij_, sparse_mapping_)
|
||||
{
|
||||
ProjectLORCoefficient<VectorFEMassIntegrator>(a, c1);
|
||||
ProjectLORCoefficient<DivDivIntegrator>(a, c2);
|
||||
}
|
||||
Array<int> &sparse_mapping_);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "lor_rt_impl.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
+33
-105
@@ -20,22 +20,11 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_HOST_DEVICE inline double Det2D(DeviceMatrix &J)
|
||||
{
|
||||
return J(0,0)*J(1,1) - J(1,0)*J(0,1);
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Det3D(DeviceMatrix &J)
|
||||
{
|
||||
return J(0,0) * (J(1,1) * J(2,2) - J(2,1) * J(1,2)) -
|
||||
J(1,0) * (J(0,1) * J(2,2) - J(2,1) * J(0,2)) +
|
||||
J(2,0) * (J(0,1) * J(1,2) - J(1,1) * J(0,2));
|
||||
}
|
||||
|
||||
template <int ORDER, int SDIM=2>
|
||||
template <int ORDER>
|
||||
MFEM_HOST_DEVICE inline void LORVertexCoordinates2D(
|
||||
const double *X, int iel_ho, int kx, int ky, double **v)
|
||||
const double *X, int iel_ho, int kx, int ky, double vx[4], double vy[4])
|
||||
{
|
||||
const int dim = 2;
|
||||
const int nd1d = ORDER + 1;
|
||||
const int nvert_per_el = nd1d*nd1d;
|
||||
|
||||
@@ -44,31 +33,23 @@ MFEM_HOST_DEVICE inline void LORVertexCoordinates2D(
|
||||
const int v2 = kx + 1 + nd1d*(ky + 1);
|
||||
const int v3 = kx + nd1d*(ky + 1);
|
||||
|
||||
const int e0 = SDIM*(v0 + nvert_per_el*iel_ho);
|
||||
const int e1 = SDIM*(v1 + nvert_per_el*iel_ho);
|
||||
const int e2 = SDIM*(v2 + nvert_per_el*iel_ho);
|
||||
const int e3 = SDIM*(v3 + nvert_per_el*iel_ho);
|
||||
const int e0 = dim*(v0 + nvert_per_el*iel_ho);
|
||||
const int e1 = dim*(v1 + nvert_per_el*iel_ho);
|
||||
const int e2 = dim*(v2 + nvert_per_el*iel_ho);
|
||||
const int e3 = dim*(v3 + nvert_per_el*iel_ho);
|
||||
|
||||
// Vertex coordinates
|
||||
v[0][0] = X[e0 + 0];
|
||||
v[1][0] = X[e0 + 1];
|
||||
vx[0] = X[e0 + 0];
|
||||
vy[0] = X[e0 + 1];
|
||||
|
||||
v[0][1] = X[e1 + 0];
|
||||
v[1][1] = X[e1 + 1];
|
||||
vx[1] = X[e1 + 0];
|
||||
vy[1] = X[e1 + 1];
|
||||
|
||||
v[0][2] = X[e2 + 0];
|
||||
v[1][2] = X[e2 + 1];
|
||||
vx[2] = X[e2 + 0];
|
||||
vy[2] = X[e2 + 1];
|
||||
|
||||
v[0][3] = X[e3 + 0];
|
||||
v[1][3] = X[e3 + 1];
|
||||
|
||||
if (SDIM == 3)
|
||||
{
|
||||
v[2][0] = X[e0 + 2];
|
||||
v[2][1] = X[e1 + 2];
|
||||
v[2][2] = X[e2 + 2];
|
||||
v[2][3] = X[e3 + 2];
|
||||
}
|
||||
vx[3] = X[e3 + 0];
|
||||
vy[3] = X[e3 + 1];
|
||||
}
|
||||
|
||||
template <int ORDER>
|
||||
@@ -131,80 +112,15 @@ MFEM_HOST_DEVICE inline void LORVertexCoordinates3D(
|
||||
vz[7] = X[e7 + 2];
|
||||
}
|
||||
|
||||
template <int SDIM=2>
|
||||
MFEM_HOST_DEVICE inline void Jacobian2D(
|
||||
const double x, const double y, double **v, DeviceMatrix &J);
|
||||
|
||||
template <> MFEM_HOST_DEVICE inline void Jacobian2D<2>(
|
||||
const double x, const double y, double **v, DeviceMatrix &J)
|
||||
const double x, const double y, const double vx[4], const double vy[4],
|
||||
DeviceMatrix &J)
|
||||
{
|
||||
J(0,0) = -(1-y)*v[0][0] + (1-y)*v[0][1] + y*v[0][2] - y*v[0][3];
|
||||
J(0,1) = -(1-x)*v[0][0] - x*v[0][1] + x*v[0][2] + (1-x)*v[0][3];
|
||||
J(0,0) = -(1-y)*vx[0] + (1-y)*vx[1] + y*vx[2] - y*vx[3];
|
||||
J(0,1) = -(1-x)*vx[0] - x*vx[1] + x*vx[2] + (1-x)*vx[3];
|
||||
|
||||
J(1,0) = -(1-y)*v[1][0] + (1-y)*v[1][1] + y*v[1][2] - y*v[1][3];
|
||||
J(1,1) = -(1-x)*v[1][0] - x*v[1][1] + x*v[1][2] + (1-x)*v[1][3];
|
||||
}
|
||||
|
||||
template <> MFEM_HOST_DEVICE inline void Jacobian2D<3>(
|
||||
const double x, const double y, double **v, DeviceMatrix &J)
|
||||
{
|
||||
J(0,0) = -(1-y)*v[0][0] + (1-y)*v[0][1] + y*v[0][2] - y*v[0][3];
|
||||
J(0,1) = -(1-x)*v[0][0] - x*v[0][1] + x*v[0][2] + (1-x)*v[0][3];
|
||||
|
||||
J(1,0) = -(1-y)*v[1][0] + (1-y)*v[1][1] + y*v[1][2] - y*v[1][3];
|
||||
J(1,1) = -(1-x)*v[1][0] - x*v[1][1] + x*v[1][2] + (1-x)*v[1][3];
|
||||
|
||||
J(2,0) = -(1-y)*v[2][0] + (1-y)*v[2][1] + y*v[2][2] - y*v[2][3];
|
||||
J(2,1) = -(1-x)*v[2][0] - x*v[2][1] + x*v[2][2] + (1-x)*v[2][3];
|
||||
}
|
||||
|
||||
template <int ORDER, int SDIM, bool RT, bool ND>
|
||||
MFEM_HOST_DEVICE inline void SetupLORQuadData2D(
|
||||
const double *X, int iel_ho, int kx, int ky, DeviceTensor<3> &Q, bool piola)
|
||||
{
|
||||
double vx[4], vy[4], vz[4];
|
||||
double *v[] = {vx, vy, vz};
|
||||
LORVertexCoordinates2D<ORDER,SDIM>(X, iel_ho, kx, ky, v);
|
||||
|
||||
for (int iqy=0; iqy<2; ++iqy)
|
||||
{
|
||||
for (int iqx=0; iqx<2; ++iqx)
|
||||
{
|
||||
const double x = iqx;
|
||||
const double y = iqy;
|
||||
const double w = 1.0/4.0;
|
||||
|
||||
double J_[SDIM*2];
|
||||
DeviceTensor<2> J(J_, SDIM, 2);
|
||||
|
||||
Jacobian2D<SDIM>(x, y, v, J);
|
||||
|
||||
if (SDIM == 2)
|
||||
{
|
||||
const double detJ = Det2D(J);
|
||||
const double w_detJ = w/detJ;
|
||||
const double E = J(0,0)*J(0,0) + J(1,0)*J(1,0);
|
||||
const double F = J(0,0)*J(0,1) + J(1,0)*J(1,1);
|
||||
const double G = J(0,1)*J(0,1) + J(1,1)*J(1,1);
|
||||
Q(0,iqy,iqx) = w_detJ * (RT ? E : G); // 1,1
|
||||
Q(1,iqy,iqx) = w_detJ * (RT ? F : -F); // 1,2
|
||||
Q(2,iqy,iqx) = w_detJ * (RT ? G : E); // 2,2
|
||||
Q(3,iqy,iqx) = (ND || RT) ? w_detJ : w*detJ;
|
||||
}
|
||||
else
|
||||
{
|
||||
const double E = J(0,0)*J(0,0) + J(1,0)*J(1,0) + J(2,0)*J(2,0);
|
||||
const double F = J(0,0)*J(0,1) + J(1,0)*J(1,1) + J(2,0)*J(2,1);
|
||||
const double G = J(0,1)*J(0,1) + J(1,1)*J(1,1) + J(2,1)*J(2,1);
|
||||
const double detJ = sqrt(E*G - F*F);
|
||||
const double w_detJ = w/detJ;
|
||||
Q(0,iqy,iqx) = w_detJ * (RT ? E : G); // 1,1
|
||||
Q(1,iqy,iqx) = w_detJ * (RT ? F : -F); // 1,2
|
||||
Q(2,iqy,iqx) = w_detJ * (RT ? G : E); // 2,2
|
||||
Q(3,iqy,iqx) = (ND || RT) ? w_detJ : w*detJ;
|
||||
}
|
||||
}
|
||||
}
|
||||
J(1,0) = -(1-y)*vy[0] + (1-y)*vy[1] + y*vy[2] - y*vy[3];
|
||||
J(1,1) = -(1-x)*vy[0] - x*vy[1] + x*vy[2] + (1-x)*vy[3];
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline void Jacobian3D(
|
||||
@@ -264,6 +180,18 @@ MFEM_HOST_DEVICE inline void Adjugate3D(const DeviceMatrix &J, DeviceMatrix &A)
|
||||
A(2,2) = (J(0,0) * J(1,1)) - (J(0,1) * J(1,0));
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Det2D(DeviceMatrix &J)
|
||||
{
|
||||
return J(0,0)*J(1,1) - J(1,0)*J(0,1);
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Det3D(DeviceMatrix &J)
|
||||
{
|
||||
return J(0,0) * (J(1,1) * J(2,2) - J(2,1) * J(1,2)) -
|
||||
J(1,0) * (J(0,1) * J(2,2) - J(2,1) * J(0,2)) +
|
||||
J(2,0) * (J(0,1) * J(1,2) - J(1,1) * J(0,2));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+11
-169
@@ -97,37 +97,12 @@ double NonlinearForm::GetGridFunctionEnergy(const Vector &x) const
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *T;
|
||||
DofTransformation *doftrans;
|
||||
Mesh *mesh = fes->GetMesh();
|
||||
double energy = 0.0;
|
||||
|
||||
if (dnfi.Size())
|
||||
{
|
||||
// Which attributes need to be processed?
|
||||
Array<int> attr_marker(mesh->attributes.Size() ?
|
||||
mesh->attributes.Max() : 0);
|
||||
attr_marker = 0;
|
||||
for (int k = 0; k < dnfi.Size(); k++)
|
||||
{
|
||||
if (dnfi_marker[k] == NULL)
|
||||
{
|
||||
attr_marker = 1;
|
||||
break;
|
||||
}
|
||||
Array<int> &marker = *dnfi_marker[k];
|
||||
MFEM_ASSERT(marker.Size() == attr_marker.Size(),
|
||||
"invalid marker for domain integrator #"
|
||||
<< k << ", counting from zero");
|
||||
for (int i = 0; i < attr_marker.Size(); i++)
|
||||
{
|
||||
attr_marker[i] |= marker[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
const int attr = mesh->GetAttribute(i);
|
||||
if (attr_marker[attr-1] == 0) { continue; }
|
||||
|
||||
fe = fes->GetFE(i);
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
T = fes->GetElementTransformation(i);
|
||||
@@ -135,9 +110,6 @@ double NonlinearForm::GetGridFunctionEnergy(const Vector &x) const
|
||||
if (doftrans) {doftrans->InvTransformPrimal(el_x); }
|
||||
for (int k = 0; k < dnfi.Size(); k++)
|
||||
{
|
||||
if (dnfi_marker[k] &&
|
||||
(*dnfi_marker[k])[attr-1] == 0) { continue; }
|
||||
|
||||
energy += dnfi[k]->GetElementEnergy(*fe, *T, el_x);
|
||||
}
|
||||
}
|
||||
@@ -203,32 +175,8 @@ void NonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
|
||||
if (dnfi.Size())
|
||||
{
|
||||
// Which attributes need to be processed?
|
||||
Array<int> attr_marker(mesh->attributes.Size() ?
|
||||
mesh->attributes.Max() : 0);
|
||||
attr_marker = 0;
|
||||
for (int k = 0; k < dnfi.Size(); k++)
|
||||
{
|
||||
if (dnfi_marker[k] == NULL)
|
||||
{
|
||||
attr_marker = 1;
|
||||
break;
|
||||
}
|
||||
Array<int> &marker = *dnfi_marker[k];
|
||||
MFEM_ASSERT(marker.Size() == attr_marker.Size(),
|
||||
"invalid marker for domain integrator #"
|
||||
<< k << ", counting from zero");
|
||||
for (int i = 0; i < attr_marker.Size(); i++)
|
||||
{
|
||||
attr_marker[i] |= marker[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
const int attr = mesh->GetAttribute(i);
|
||||
if (attr_marker[attr-1] == 0) { continue; }
|
||||
|
||||
fe = fes->GetFE(i);
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
T = fes->GetElementTransformation(i);
|
||||
@@ -236,9 +184,6 @@ void NonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
if (doftrans) {doftrans->InvTransformPrimal(el_x); }
|
||||
for (int k = 0; k < dnfi.Size(); k++)
|
||||
{
|
||||
if (dnfi_marker[k] &&
|
||||
(*dnfi_marker[k])[attr-1] == 0) { continue; }
|
||||
|
||||
dnfi[k]->AssembleElementVector(*fe, *T, el_x, el_y);
|
||||
if (doftrans) {doftrans->TransformDual(el_y); }
|
||||
py.AddElementVector(vdofs, el_y);
|
||||
@@ -377,32 +322,8 @@ Operator &NonlinearForm::GetGradient(const Vector &x) const
|
||||
|
||||
if (dnfi.Size())
|
||||
{
|
||||
// Which attributes need to be processed?
|
||||
Array<int> attr_marker(mesh->attributes.Size() ?
|
||||
mesh->attributes.Max() : 0);
|
||||
attr_marker = 0;
|
||||
for (int k = 0; k < dnfi.Size(); k++)
|
||||
{
|
||||
if (dnfi_marker[k] == NULL)
|
||||
{
|
||||
attr_marker = 1;
|
||||
break;
|
||||
}
|
||||
Array<int> &marker = *dnfi_marker[k];
|
||||
MFEM_ASSERT(marker.Size() == attr_marker.Size(),
|
||||
"invalid marker for domain integrator #"
|
||||
<< k << ", counting from zero");
|
||||
for (int i = 0; i < attr_marker.Size(); i++)
|
||||
{
|
||||
attr_marker[i] |= marker[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
const int attr = mesh->GetAttribute(i);
|
||||
if (attr_marker[attr-1] == 0) { continue; }
|
||||
|
||||
fe = fes->GetFE(i);
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
T = fes->GetElementTransformation(i);
|
||||
@@ -410,9 +331,6 @@ Operator &NonlinearForm::GetGradient(const Vector &x) const
|
||||
if (doftrans) {doftrans->InvTransformPrimal(el_x); }
|
||||
for (int k = 0; k < dnfi.Size(); k++)
|
||||
{
|
||||
if (dnfi_marker[k] &&
|
||||
(*dnfi_marker[k])[attr-1] == 0) { continue; }
|
||||
|
||||
dnfi[k]->AssembleElementGrad(*fe, *T, el_x, elmat);
|
||||
if (doftrans) { doftrans->TransformDual(elmat); }
|
||||
Grad->AddSubMatrix(vdofs, vdofs, elmat, skip_zeros);
|
||||
@@ -643,6 +561,13 @@ BlockNonlinearForm::BlockNonlinearForm(Array<FiniteElementSpace *> &f) :
|
||||
SetSpaces(f);
|
||||
}
|
||||
|
||||
void BlockNonlinearForm::AddBdrFaceIntegrator(BlockNonlinearFormIntegrator *nfi,
|
||||
Array<int> &bdr_attr_marker)
|
||||
{
|
||||
bfnfi.Append(nfi);
|
||||
bfnfi_marker.Append(&bdr_attr_marker);
|
||||
}
|
||||
|
||||
void BlockNonlinearForm::SetEssentialBC(
|
||||
const Array<Array<int> *> &bdr_attr_is_ess, Array<Vector *> &rhs)
|
||||
{
|
||||
@@ -667,7 +592,6 @@ double BlockNonlinearForm::GetEnergyBlocked(const BlockVector &bx) const
|
||||
Array<const FiniteElement *> fe(fes.Size());
|
||||
ElementTransformation *T;
|
||||
DofTransformation *doftrans;
|
||||
Mesh *mesh = fes[0]->GetMesh();
|
||||
double energy = 0.0;
|
||||
|
||||
for (int i=0; i<fes.Size(); ++i)
|
||||
@@ -677,33 +601,8 @@ double BlockNonlinearForm::GetEnergyBlocked(const BlockVector &bx) const
|
||||
}
|
||||
|
||||
if (dnfi.Size())
|
||||
{
|
||||
// Which attributes need to be processed?
|
||||
Array<int> attr_marker(mesh->attributes.Size() ?
|
||||
mesh->attributes.Max() : 0);
|
||||
attr_marker = 0;
|
||||
for (int k = 0; k < dnfi.Size(); k++)
|
||||
{
|
||||
if (dnfi_marker[k] == NULL)
|
||||
{
|
||||
attr_marker = 1;
|
||||
break;
|
||||
}
|
||||
Array<int> &marker = *dnfi_marker[k];
|
||||
MFEM_ASSERT(marker.Size() == attr_marker.Size(),
|
||||
"invalid marker for domain integrator #"
|
||||
<< k << ", counting from zero");
|
||||
for (int i = 0; i < attr_marker.Size(); i++)
|
||||
{
|
||||
attr_marker[i] |= marker[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < fes[0]->GetNE(); ++i)
|
||||
{
|
||||
const int attr = mesh->GetAttribute(i);
|
||||
if (attr_marker[attr-1] == 0) { continue; }
|
||||
|
||||
T = fes[0]->GetElementTransformation(i);
|
||||
for (int s=0; s<fes.Size(); ++s)
|
||||
{
|
||||
@@ -715,13 +614,9 @@ double BlockNonlinearForm::GetEnergyBlocked(const BlockVector &bx) const
|
||||
|
||||
for (int k = 0; k < dnfi.Size(); ++k)
|
||||
{
|
||||
if (dnfi_marker[k] &&
|
||||
(*dnfi_marker[k])[attr-1] == 0) { continue; }
|
||||
|
||||
energy += dnfi[k]->GetElementEnergy(fe, *T, el_x_const);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// free the allocated memory
|
||||
for (int i = 0; i < fes.Size(); ++i)
|
||||
@@ -761,7 +656,6 @@ void BlockNonlinearForm::MultBlocked(const BlockVector &bx,
|
||||
Array<const FiniteElement *> fe2(fes.Size());
|
||||
ElementTransformation *T;
|
||||
Array<DofTransformation *> doftrans(fes.Size()); doftrans = nullptr;
|
||||
Mesh *mesh = fes[0]->GetMesh();
|
||||
|
||||
by.UseDevice(true);
|
||||
by = 0.0;
|
||||
@@ -776,32 +670,8 @@ void BlockNonlinearForm::MultBlocked(const BlockVector &bx,
|
||||
|
||||
if (dnfi.Size())
|
||||
{
|
||||
// Which attributes need to be processed?
|
||||
Array<int> attr_marker(mesh->attributes.Size() ?
|
||||
mesh->attributes.Max() : 0);
|
||||
attr_marker = 0;
|
||||
for (int k = 0; k < dnfi.Size(); k++)
|
||||
{
|
||||
if (dnfi_marker[k] == NULL)
|
||||
{
|
||||
attr_marker = 1;
|
||||
break;
|
||||
}
|
||||
Array<int> &marker = *dnfi_marker[k];
|
||||
MFEM_ASSERT(marker.Size() == attr_marker.Size(),
|
||||
"invalid marker for domain integrator #"
|
||||
<< k << ", counting from zero");
|
||||
for (int i = 0; i < attr_marker.Size(); i++)
|
||||
{
|
||||
attr_marker[i] |= marker[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < fes[0]->GetNE(); ++i)
|
||||
{
|
||||
const int attr = mesh->GetAttribute(i);
|
||||
if (attr_marker[attr-1] == 0) { continue; }
|
||||
|
||||
T = fes[0]->GetElementTransformation(i);
|
||||
for (int s = 0; s < fes.Size(); ++s)
|
||||
{
|
||||
@@ -813,9 +683,6 @@ void BlockNonlinearForm::MultBlocked(const BlockVector &bx,
|
||||
|
||||
for (int k = 0; k < dnfi.Size(); ++k)
|
||||
{
|
||||
if (dnfi_marker[k] &&
|
||||
(*dnfi_marker[k])[attr-1] == 0) { continue; }
|
||||
|
||||
dnfi[k]->AssembleElementVector(fe, *T,
|
||||
el_x_const, el_y);
|
||||
|
||||
@@ -831,6 +698,7 @@ void BlockNonlinearForm::MultBlocked(const BlockVector &bx,
|
||||
|
||||
if (fnfi.Size())
|
||||
{
|
||||
Mesh *mesh = fes[0]->GetMesh();
|
||||
FaceElementTransformations *tr;
|
||||
|
||||
for (int i = 0; i < mesh->GetNumFaces(); ++i)
|
||||
@@ -868,8 +736,8 @@ void BlockNonlinearForm::MultBlocked(const BlockVector &bx,
|
||||
|
||||
if (bfnfi.Size())
|
||||
{
|
||||
Mesh *mesh = fes[0]->GetMesh();
|
||||
FaceElementTransformations *tr;
|
||||
|
||||
// Which boundary attributes need to be processed?
|
||||
Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
|
||||
mesh->bdr_attributes.Max() : 0);
|
||||
@@ -990,7 +858,6 @@ void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx) const
|
||||
Array<const FiniteElement *>fe2(fes.Size());
|
||||
ElementTransformation * T;
|
||||
Array<DofTransformation *> doftrans(fes.Size()); doftrans = nullptr;
|
||||
Mesh *mesh = fes[0]->GetMesh();
|
||||
|
||||
for (int i=0; i<fes.Size(); ++i)
|
||||
{
|
||||
@@ -1021,32 +888,8 @@ void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx) const
|
||||
|
||||
if (dnfi.Size())
|
||||
{
|
||||
// Which attributes need to be processed?
|
||||
Array<int> attr_marker(mesh->attributes.Size() ?
|
||||
mesh->attributes.Max() : 0);
|
||||
attr_marker = 0;
|
||||
for (int k = 0; k < dnfi.Size(); k++)
|
||||
{
|
||||
if (dnfi_marker[k] == NULL)
|
||||
{
|
||||
attr_marker = 1;
|
||||
break;
|
||||
}
|
||||
Array<int> &marker = *dnfi_marker[k];
|
||||
MFEM_ASSERT(marker.Size() == attr_marker.Size(),
|
||||
"invalid marker for domain integrator #"
|
||||
<< k << ", counting from zero");
|
||||
for (int i = 0; i < attr_marker.Size(); i++)
|
||||
{
|
||||
attr_marker[i] |= marker[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < fes[0]->GetNE(); ++i)
|
||||
{
|
||||
const int attr = mesh->GetAttribute(i);
|
||||
if (attr_marker[attr-1] == 0) { continue; }
|
||||
|
||||
T = fes[0]->GetElementTransformation(i);
|
||||
for (int s = 0; s < fes.Size(); ++s)
|
||||
{
|
||||
@@ -1058,9 +901,6 @@ void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx) const
|
||||
|
||||
for (int k = 0; k < dnfi.Size(); ++k)
|
||||
{
|
||||
if (dnfi_marker[k] &&
|
||||
(*dnfi_marker[k])[attr-1] == 0) { continue; }
|
||||
|
||||
dnfi[k]->AssembleElementGrad(fe, *T, el_x_const, elmats);
|
||||
|
||||
for (int j=0; j<fes.Size(); ++j)
|
||||
@@ -1083,6 +923,7 @@ void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx) const
|
||||
if (fnfi.Size())
|
||||
{
|
||||
FaceElementTransformations *tr;
|
||||
Mesh *mesh = fes[0]->GetMesh();
|
||||
|
||||
for (int i = 0; i < mesh->GetNumFaces(); ++i)
|
||||
{
|
||||
@@ -1119,6 +960,7 @@ void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx) const
|
||||
if (bfnfi.Size())
|
||||
{
|
||||
FaceElementTransformations *tr;
|
||||
Mesh *mesh = fes[0]->GetMesh();
|
||||
|
||||
// Which boundary attributes need to be processed?
|
||||
Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
|
||||
|
||||
+4
-17
@@ -37,7 +37,6 @@ protected:
|
||||
|
||||
/// Set of Domain Integrators to be assembled (added).
|
||||
Array<NonlinearFormIntegrator*> dnfi; // owned
|
||||
Array<Array<int>*> dnfi_marker; // not owned
|
||||
|
||||
/// Set of interior face Integrators to be assembled (added).
|
||||
Array<NonlinearFormIntegrator*> fnfi; // owned
|
||||
@@ -109,12 +108,7 @@ public:
|
||||
|
||||
/// Adds new Domain Integrator.
|
||||
void AddDomainIntegrator(NonlinearFormIntegrator *nlfi)
|
||||
{ dnfi.Append(nlfi); dnfi_marker.Append(NULL); }
|
||||
|
||||
/// Adds new Domain Integrator, restricted to specific attributes.
|
||||
void AddDomainIntegrator(NonlinearFormIntegrator *nlfi,
|
||||
Array<int> &elem_marker)
|
||||
{ dnfi.Append(nlfi); dnfi_marker.Append(&elem_marker); }
|
||||
{ dnfi.Append(nlfi); }
|
||||
|
||||
/// Access all integrators added with AddDomainIntegrator().
|
||||
Array<NonlinearFormIntegrator*> *GetDNFI() { return &dnfi; }
|
||||
@@ -233,14 +227,13 @@ protected:
|
||||
|
||||
/// Set of Domain Integrators to be assembled (added).
|
||||
Array<BlockNonlinearFormIntegrator*> dnfi;
|
||||
Array<Array<int>*> dnfi_marker;
|
||||
|
||||
/// Set of interior face Integrators to be assembled (added).
|
||||
Array<BlockNonlinearFormIntegrator*> fnfi;
|
||||
|
||||
/// Set of Boundary Face Integrators to be assembled (added).
|
||||
Array<BlockNonlinearFormIntegrator*> bfnfi;
|
||||
Array<Array<int>*> bfnfi_marker;
|
||||
Array<Array<int>*> bfnfi_marker;
|
||||
|
||||
/** Auxiliary block-vectors for wrapping input and output vectors or holding
|
||||
GridFunction-like block-vector data (e.g. in parallel). */
|
||||
@@ -305,12 +298,7 @@ public:
|
||||
|
||||
/// Adds new Domain Integrator.
|
||||
void AddDomainIntegrator(BlockNonlinearFormIntegrator *nlfi)
|
||||
{ dnfi.Append(nlfi); dnfi_marker.Append(NULL); }
|
||||
|
||||
/// Adds new Domain Integrator, restricted to specific attributes.
|
||||
void AddDomainIntegrator(BlockNonlinearFormIntegrator *nlfi,
|
||||
Array<int> &elem_marker)
|
||||
{ dnfi.Append(nlfi); dnfi_marker.Append(&elem_marker); }
|
||||
{ dnfi.Append(nlfi); }
|
||||
|
||||
/// Adds new Interior Face Integrator.
|
||||
void AddInteriorFaceIntegrator(BlockNonlinearFormIntegrator *nlfi)
|
||||
@@ -323,8 +311,7 @@ public:
|
||||
/** @brief Adds new Boundary Face Integrator, restricted to specific boundary
|
||||
attributes. */
|
||||
void AddBdrFaceIntegrator(BlockNonlinearFormIntegrator *nlfi,
|
||||
Array<int> &bdr_marker)
|
||||
{ bfnfi.Append(nlfi); bfnfi_marker.Append(&bdr_marker); }
|
||||
Array<int> &bdr_marker);
|
||||
|
||||
virtual void SetEssentialBC(const Array<Array<int> *>&bdr_attr_is_ess,
|
||||
Array<Vector *> &rhs);
|
||||
|
||||
+52
-46
@@ -466,54 +466,53 @@ void ParFiniteElementSpace::ApplyLDofSigns(Table &el_dof) const
|
||||
ApplyLDofSigns(all_dofs);
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetElementDofs(int i, Array<int> &dofs,
|
||||
DofTransformation &doftrans) const
|
||||
DofTransformation *
|
||||
ParFiniteElementSpace::GetElementDofs(int i, Array<int> &dofs) const
|
||||
{
|
||||
if (elem_dof)
|
||||
{
|
||||
elem_dof->GetRow(i, dofs);
|
||||
|
||||
if (DoFTransArray[mesh->GetElementBaseGeometry(i)])
|
||||
if (DoFTrans[mesh->GetElementBaseGeometry(i)])
|
||||
{
|
||||
Array<int> Fo;
|
||||
elem_fos->GetRow(i, Fo);
|
||||
doftrans.SetDofTransformation(
|
||||
*DoFTransArray[mesh->GetElementBaseGeometry(i)]);
|
||||
doftrans.SetFaceOrientations(Fo);
|
||||
doftrans.SetVDim();
|
||||
DoFTrans[mesh->GetElementBaseGeometry(i)]->SetFaceOrientations(Fo);
|
||||
return DoFTrans[mesh->GetElementBaseGeometry(i)];
|
||||
}
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
FiniteElementSpace::GetElementDofs(i, dofs, doftrans);
|
||||
DofTransformation * doftrans = FiniteElementSpace::GetElementDofs(i, dofs);
|
||||
if (Conforming())
|
||||
{
|
||||
ApplyLDofSigns(dofs);
|
||||
}
|
||||
return doftrans;
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs,
|
||||
DofTransformation &doftrans) const
|
||||
DofTransformation *
|
||||
ParFiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
|
||||
{
|
||||
if (bdr_elem_dof)
|
||||
{
|
||||
bdr_elem_dof->GetRow(i, dofs);
|
||||
|
||||
if (DoFTransArray[mesh->GetBdrElementBaseGeometry(i)])
|
||||
if (DoFTrans[mesh->GetBdrElementBaseGeometry(i)])
|
||||
{
|
||||
Array<int> Fo;
|
||||
bdr_elem_fos->GetRow(i, Fo);
|
||||
doftrans.SetDofTransformation(
|
||||
*DoFTransArray[mesh->GetBdrElementBaseGeometry(i)]);
|
||||
doftrans.SetFaceOrientations(Fo);
|
||||
doftrans.SetVDim();
|
||||
bdr_elem_fos -> GetRow (i, Fo);
|
||||
DoFTrans[mesh->GetBdrElementBaseGeometry(i)]->SetFaceOrientations(Fo);
|
||||
return DoFTrans[mesh->GetBdrElementBaseGeometry(i)];
|
||||
}
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
FiniteElementSpace::GetBdrElementDofs(i, dofs, doftrans);
|
||||
DofTransformation * doftrans =
|
||||
FiniteElementSpace::GetBdrElementDofs(i, dofs);
|
||||
if (Conforming())
|
||||
{
|
||||
ApplyLDofSigns(dofs);
|
||||
}
|
||||
return doftrans;
|
||||
}
|
||||
|
||||
int ParFiniteElementSpace::GetFaceDofs(int i, Array<int> &dofs,
|
||||
@@ -940,8 +939,8 @@ void ParFiniteElementSpace::Build_Dof_TrueDof_Matrix() const // matrix P
|
||||
}
|
||||
else if (i_offd[i+1] == i_offd[i] + 2)
|
||||
{
|
||||
const double *T =
|
||||
ND_DofTransformation::GetFaceTransform(ltori[i]).GetData();
|
||||
const double * T = ND_StatelessDofTransformation
|
||||
::GetFaceTransform(ltori[i]).GetData();
|
||||
j_offd[i_offd[i] + 1] = j_offd[i_offd[i]] + 1;
|
||||
d_offd[i_offd[i]] = T[0]; d_offd[i_offd[i] + 1] = T[2];
|
||||
i++;
|
||||
@@ -1455,28 +1454,29 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
|
||||
delete [] requests;
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetFaceNbrElementVDofs(
|
||||
int i, Array<int> &vdofs, DofTransformation &doftrans) const
|
||||
{
|
||||
face_nbr_element_dof.GetRow(i, vdofs);
|
||||
|
||||
if (DoFTransArray[GetFaceNbrFE(i)->GetGeomType()])
|
||||
{
|
||||
Array<int> F, Fo;
|
||||
pmesh->GetFaceNbrElementFaces(pmesh->GetNE() + i, F, Fo);
|
||||
doftrans.SetDofTransformation(
|
||||
*DoFTransArray[GetFaceNbrFE(i)->GetGeomType()]);
|
||||
doftrans.SetFaceOrientations(Fo);
|
||||
doftrans.SetVDim(vdim, ordering);
|
||||
}
|
||||
}
|
||||
|
||||
DofTransformation *ParFiniteElementSpace::GetFaceNbrElementVDofs(
|
||||
int i, Array<int> &vdofs) const
|
||||
{
|
||||
DoFTrans.SetDofTransformation(NULL);
|
||||
GetFaceNbrElementVDofs(i, vdofs, DoFTrans);
|
||||
return DoFTrans.GetDofTransformation() ? &DoFTrans : NULL;
|
||||
face_nbr_element_dof.GetRow(i, vdofs);
|
||||
|
||||
DofTransformation *doftrans = NULL;
|
||||
Geometry::Type geom = GetFaceNbrFE(i)->GetGeomType();
|
||||
if (DoFTrans[geom])
|
||||
{
|
||||
Array<int> F, Fo;
|
||||
pmesh->GetFaceNbrElementFaces(pmesh->GetNE() + i, F, Fo);
|
||||
doftrans = DoFTrans[geom];
|
||||
doftrans->SetFaceOrientations(Fo);
|
||||
}
|
||||
if (vdim == 1 || doftrans == NULL)
|
||||
{
|
||||
return doftrans;
|
||||
}
|
||||
else
|
||||
{
|
||||
VDoFTrans.SetDofTransformation(*doftrans);
|
||||
return &VDoFTrans;
|
||||
}
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetFaceNbrFaceVDofs(int i, Array<int> &vdofs) const
|
||||
@@ -2235,13 +2235,19 @@ void NeighborRowMessage::Decode(int rank)
|
||||
|
||||
// This is the second "fundamental unit" used in the transformation.
|
||||
const auto initial_second_row = second_row;
|
||||
const double *T =
|
||||
ND_DofTransformation::GetFaceTransform(fo).GetData();
|
||||
|
||||
first_row.AddRow(initial_first_row, T[0] - 1.0);
|
||||
first_row.AddRow(initial_second_row, T[2]);
|
||||
second_row.AddRow(initial_first_row, T[1]);
|
||||
second_row.AddRow(initial_second_row, T[3] - 1.0);
|
||||
const auto T = [&fo]()
|
||||
{
|
||||
auto T = ND_StatelessDofTransformation::GetFaceTransform(fo);
|
||||
T(0,0) -= 1;
|
||||
T(1,1) -= 1;
|
||||
return T;
|
||||
}();
|
||||
|
||||
first_row.AddRow(initial_first_row, T(0,0));
|
||||
first_row.AddRow(initial_second_row, T(0,1));
|
||||
second_row.AddRow(initial_first_row, T(1,0));
|
||||
second_row.AddRow(initial_second_row, T(1,1));
|
||||
|
||||
first_row.Collapse();
|
||||
second_row.Collapse();
|
||||
|
||||
+5
-17
@@ -248,11 +248,7 @@ public:
|
||||
If the FiniteElementCollection, @a f, is NULL (default), the FE
|
||||
collection used by @a global_fes will be reused. If @a f is not NULL, it
|
||||
must be the same as, or a copy of, the FE collection used by
|
||||
@a global_fes.
|
||||
|
||||
@note Currently the @a partitioning array is not used by this
|
||||
constructor, it is required for general parallel variable-order support.
|
||||
*/
|
||||
@a global_fes. */
|
||||
ParFiniteElementSpace(ParMesh *pm, const FiniteElementSpace *global_fes,
|
||||
const int *partitioning,
|
||||
const FiniteElementCollection *f = NULL);
|
||||
@@ -288,17 +284,11 @@ public:
|
||||
/// Return the number of local vector true dofs.
|
||||
int GetTrueVSize() const override { return ltdof_size; }
|
||||
|
||||
/// Returns indexes of degrees of freedom in array dofs for i'th element and
|
||||
/// returns the DofTransformation data in a user-provided object.
|
||||
using FiniteElementSpace::GetElementDofs;
|
||||
void GetElementDofs(int i, Array<int> &dofs,
|
||||
DofTransformation &doftrans) const override;
|
||||
/// Returns indexes of degrees of freedom in array dofs for i'th element.
|
||||
DofTransformation *GetElementDofs(int i, Array<int> &dofs) const override;
|
||||
|
||||
/// Returns indexes of degrees of freedom for i'th boundary element and
|
||||
/// returns the DofTransformation data in a user-provided object.
|
||||
using FiniteElementSpace::GetBdrElementDofs;
|
||||
void GetBdrElementDofs(int i, Array<int> &dofs,
|
||||
DofTransformation &doftrans) const override;
|
||||
/// Returns indexes of degrees of freedom for i'th boundary element.
|
||||
DofTransformation *GetBdrElementDofs(int i, Array<int> &dofs) const override;
|
||||
|
||||
/** Returns the indexes of the degrees of freedom for i'th face
|
||||
including the dofs for the edges and the vertices of the face. */
|
||||
@@ -392,8 +382,6 @@ public:
|
||||
// Face-neighbor functions
|
||||
void ExchangeFaceNbrData();
|
||||
int GetFaceNbrVSize() const { return num_face_nbr_dofs; }
|
||||
void GetFaceNbrElementVDofs(int i, Array<int> &vdofs,
|
||||
DofTransformation &doftrans) const;
|
||||
DofTransformation *GetFaceNbrElementVDofs(int i, Array<int> &vdofs) const;
|
||||
void GetFaceNbrFaceVDofs(int i, Array<int> &vdofs) const;
|
||||
const FiniteElement *GetFaceNbrFE(int i) const;
|
||||
|
||||
+7
-21
@@ -39,9 +39,11 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, const GridFunction *gf,
|
||||
{
|
||||
const FiniteElementSpace *glob_fes = gf->FESpace();
|
||||
// duplicate the FiniteElementCollection from 'gf'
|
||||
fec = FiniteElementCollection::New(glob_fes->FEColl()->Name());
|
||||
fec.reset(FiniteElementCollection::New(glob_fes->FEColl()->Name()));
|
||||
// create a local ParFiniteElementSpace from the global one:
|
||||
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning, fec);
|
||||
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning,
|
||||
fec.get());
|
||||
owned_fes.reset(pfes);
|
||||
SetSize(pfes->GetVSize());
|
||||
|
||||
if (partitioning)
|
||||
@@ -81,10 +83,10 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, std::istream &input)
|
||||
: GridFunction(pmesh, input)
|
||||
{
|
||||
// Convert the FiniteElementSpace, fes, to a ParFiniteElementSpace:
|
||||
pfes = new ParFiniteElementSpace(pmesh, fec, fes->GetVDim(),
|
||||
pfes = new ParFiniteElementSpace(pmesh, fec.get(), fes->GetVDim(),
|
||||
fes->GetOrdering());
|
||||
delete fes;
|
||||
fes = pfes;
|
||||
owned_fes.reset(pfes);
|
||||
}
|
||||
|
||||
void ParGridFunction::Update()
|
||||
@@ -693,23 +695,7 @@ void ParGridFunction::ProjectBdrCoefficient(
|
||||
|
||||
#ifdef MFEM_DEBUG
|
||||
Array<int> ess_vdofs_marker;
|
||||
if (vcoeff) { pfes->GetEssentialVDofs(attr, ess_vdofs_marker); }
|
||||
else
|
||||
{
|
||||
ess_vdofs_marker.SetSize(Size());
|
||||
ess_vdofs_marker = 0;
|
||||
for (int i = 0; i < fes->GetVDim(); i++)
|
||||
{
|
||||
if (!coeff[i]) { continue; }
|
||||
Array<int> component_dof_marker;
|
||||
pfes->GetEssentialVDofs(attr, component_dof_marker,i);
|
||||
for (int j = 0; j<Size(); j++)
|
||||
{
|
||||
ess_vdofs_marker[j] = bool(ess_vdofs_marker[j]) ||
|
||||
bool(component_dof_marker[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
pfes->GetEssentialVDofs(attr, ess_vdofs_marker);
|
||||
for (int i = 0; i < values_counter.Size(); i++)
|
||||
{
|
||||
MFEM_ASSERT(pfes->GetLocalTDofNumber(i) == -1 ||
|
||||
|
||||
@@ -49,10 +49,6 @@ protected:
|
||||
public:
|
||||
ParGridFunction() { pfes = NULL; }
|
||||
|
||||
/// Copy constructor. The internal vector #face_nbr_data is not copied.
|
||||
ParGridFunction(const ParGridFunction &orig)
|
||||
: GridFunction(orig), pfes(orig.pfes) { }
|
||||
|
||||
ParGridFunction(ParFiniteElementSpace *pf) : GridFunction(pf), pfes(pf) { }
|
||||
|
||||
/// Construct a ParGridFunction using previously allocated array @a data.
|
||||
@@ -93,15 +89,6 @@ public:
|
||||
constructed. The new ParGridFunction assumes ownership of both. */
|
||||
ParGridFunction(ParMesh *pmesh, std::istream &input);
|
||||
|
||||
/// Copy assignment. Only the data of the base class Vector is copied.
|
||||
/** It is assumed that this object and @a rhs use ParFiniteElementSpace%s
|
||||
that have the same size.
|
||||
|
||||
@note Defining this method overwrites the implicitly defined copy
|
||||
assignment operator. */
|
||||
ParGridFunction &operator=(const ParGridFunction &rhs)
|
||||
{ return operator=((const Vector &)rhs); }
|
||||
|
||||
/// Assign constant values to the ParGridFunction data.
|
||||
ParGridFunction &operator=(double value)
|
||||
{ GridFunction::operator=(value); return *this; }
|
||||
@@ -459,8 +446,6 @@ public:
|
||||
|
||||
/// Merge the local grid functions
|
||||
void SaveAsOne(std::ostream &out = mfem::out) const;
|
||||
|
||||
virtual ~ParGridFunction() { }
|
||||
};
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ int FaceQuadratureSpace::GetEntityIndex(const ElementTransformation &T) const
|
||||
return get_face_index(T.ElementNo);
|
||||
case ElementTransformation::BDR_ELEMENT:
|
||||
case ElementTransformation::BDR_FACE:
|
||||
return get_face_index(mesh.GetBdrElementFaceIndex(T.ElementNo));
|
||||
return get_face_index(mesh.GetBdrElementEdgeIndex(T.ElementNo));
|
||||
default:
|
||||
MFEM_ABORT("Invalid element type.");
|
||||
return -1;
|
||||
|
||||
+10
-43
@@ -462,52 +462,21 @@ void TMOP_Metric_009::AssembleH(const DenseMatrix &Jpt,
|
||||
ie.Assemble_ddI1b(weight, A.GetData());
|
||||
}
|
||||
|
||||
double TMOP_Metric_014::EvalWMatrixForm(const DenseMatrix &Jpt) const
|
||||
{
|
||||
// mu_14 = |J - I|^2.
|
||||
DenseMatrix Mat(Jpt);
|
||||
Mat(0,0) -= 1.0;
|
||||
Mat(1,1) -= 1.0;
|
||||
return Mat.FNorm2();
|
||||
}
|
||||
|
||||
// mu_14 = |T-I|^2
|
||||
double TMOP_Metric_014::EvalW(const DenseMatrix &Jpt) const
|
||||
{
|
||||
// mu_14 = |J - I|^2 = I1[J-I].
|
||||
DenseMatrix Mat(Jpt);
|
||||
Mat(0,0) -= 1.0;
|
||||
Mat(1,1) -= 1.0;
|
||||
MFEM_VERIFY(Jtr != NULL,
|
||||
"Requires a target Jacobian, use SetTargetJacobian().");
|
||||
|
||||
ie.SetJacobian(Mat.GetData());
|
||||
return ie.Get_I1();
|
||||
}
|
||||
DenseMatrix Id(2,2);
|
||||
|
||||
void TMOP_Metric_014::EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const
|
||||
{
|
||||
// P = dI1[J-I] d/dJ[J-I] = dI1[J-I].
|
||||
DenseMatrix JptMinusId = Jpt;
|
||||
for (int i = 0; i < Jpt.Size(); i++)
|
||||
{
|
||||
JptMinusId(i, i) -= 1.0;
|
||||
}
|
||||
ie.SetJacobian(JptMinusId.GetData());
|
||||
P = ie.Get_dI1();
|
||||
}
|
||||
Id(0,0) = 1; Id(0,1) = 0;
|
||||
Id(1,0) = 0; Id(1,1) = 1;
|
||||
|
||||
void TMOP_Metric_014::AssembleH(const DenseMatrix &Jpt,
|
||||
const DenseMatrix &DS,
|
||||
const double weight,
|
||||
DenseMatrix &A) const
|
||||
{
|
||||
// dP = ddI1[J-I].
|
||||
DenseMatrix JptMinusId = Jpt;
|
||||
for (int i = 0; i < Jpt.Size(); i++)
|
||||
{
|
||||
JptMinusId(i, i) -= 1.0;
|
||||
}
|
||||
ie.SetJacobian(JptMinusId.GetData());
|
||||
ie.SetDerivativeMatrix(DS.Height(), DS.GetData());
|
||||
ie.Assemble_ddI1(weight, A.GetData());
|
||||
DenseMatrix Mat(2,2);
|
||||
Mat = Jpt;
|
||||
Mat.Add(-1,Id);
|
||||
return Mat.FNorm2();
|
||||
}
|
||||
|
||||
double TMOP_Metric_022::EvalW(const DenseMatrix &Jpt) const
|
||||
@@ -4378,8 +4347,6 @@ UpdateAfterMeshPositionChange(const Vector &x_new,
|
||||
{
|
||||
if (discr_tc) { PA.Jtr_needs_update = true; }
|
||||
|
||||
if (PA.enabled) { UpdateCoefficientsPA(x_new); }
|
||||
|
||||
Ordering::Type ordering = x_fes.GetOrdering();
|
||||
|
||||
// Update the finite difference delta if FD are used.
|
||||
|
||||
+9
-26
@@ -373,20 +373,16 @@ public:
|
||||
/// 2D non-barrier Shape+Size+Orientation (VOS) metric (polyconvex).
|
||||
class TMOP_Metric_014 : public TMOP_QualityMetric
|
||||
{
|
||||
protected:
|
||||
mutable InvariantsEvaluator2D<double> ie;
|
||||
|
||||
public:
|
||||
// W = |J - I|^2.
|
||||
virtual double EvalWMatrixForm(const DenseMatrix &Jpt) const;
|
||||
|
||||
// W = I1[J-I].
|
||||
// W = |T-I|^2.
|
||||
virtual double EvalW(const DenseMatrix &Jpt) const;
|
||||
|
||||
virtual void EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const;
|
||||
virtual void EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const
|
||||
{ MFEM_ABORT("Not implemented"); }
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
const double weight, DenseMatrix &A) const
|
||||
{ MFEM_ABORT("Not implemented"); }
|
||||
};
|
||||
|
||||
/// 2D Shifted barrier form of shape metric (mu_2).
|
||||
@@ -1821,27 +1817,17 @@ protected:
|
||||
|
||||
// PA extension
|
||||
// ------------
|
||||
// Jtr: all ref->target Jacobians, (dim x dim) Q-Vector as DenseTensor.
|
||||
// updated when needed, based on Jtr_needs_update.
|
||||
//
|
||||
// E: Q-vector for TMOP-energy
|
||||
// Used as temporary storage when the total energy is computed.
|
||||
// O: Q-Vector of 1.0, used to compute sums using the dot product kernel.
|
||||
// X0: E-vector for initial nodal coordinates used for limiting.
|
||||
// Does not change during the TMOP iteration.
|
||||
// H: Q-Vector for Hessian associated with the metric term.
|
||||
// Updated by every call to PANonlinearFormExtension::GetGradient().
|
||||
// C0: Q-Vector for spatial weight used for the limiting term.
|
||||
// Updated when the mesh nodes change.
|
||||
// LD: E-Vector constructed using limiting distance grid function (delta).
|
||||
// Does not change during the TMOP iteration.
|
||||
// H0: Q-Vector for Hessian associated with the limiting term.
|
||||
// Updated by every call to PANonlinearFormExtension::GetGradient().
|
||||
// MC: Q-Vector for the metric Coefficient.
|
||||
// Updated when the mesh nodes change.
|
||||
//
|
||||
// maps: Dof2Quad map for fes associated with the nodal coordinates.
|
||||
// maps_lim: Dof2Quad map for fes associated with the limiting dist GridFunc.
|
||||
// maps: Dof2Quad map for fespace associate with nodal coordinates.
|
||||
// maps_lim: Dof2Quad map for fespace associated with the limiting distance
|
||||
// grid function.
|
||||
//
|
||||
// Jtr_debug_grad
|
||||
// We keep track if Jtr was set by AssembleGradPA() in Jtr_debug_grad: it
|
||||
@@ -1860,7 +1846,7 @@ protected:
|
||||
mutable DenseTensor Jtr;
|
||||
mutable bool Jtr_needs_update;
|
||||
mutable bool Jtr_debug_grad;
|
||||
mutable Vector E, O, X0, H, C0, LD, H0, MC;
|
||||
mutable Vector E, O, X0, H, C0, LD, H0;
|
||||
const DofToQuad *maps;
|
||||
const DofToQuad *maps_lim = nullptr;
|
||||
const GeometricFactors *geom;
|
||||
@@ -1974,9 +1960,6 @@ protected:
|
||||
|
||||
void AssemblePA_Limiting();
|
||||
void ComputeAllElementTargets(const Vector &xe = Vector()) const;
|
||||
// Updates the Q-vectors for the metric_coeff and lim_coeff, based on the
|
||||
// new physical positions of the quadrature points.
|
||||
void UpdateCoefficientsPA(const Vector &x_loc);
|
||||
|
||||
// Compute Min(Det(Jpt)) in the mesh, does not reduce over MPI.
|
||||
double ComputeMinDetT(const Vector &x, const FiniteElementSpace &fes);
|
||||
|
||||
@@ -176,42 +176,6 @@ void TMOP_Integrator::ComputeAllElementTargets(const Vector &xe) const
|
||||
targetC->ComputeAllElementTargets(*fes, ir, xe, PA.Jtr);
|
||||
}
|
||||
|
||||
void TMOP_Integrator::UpdateCoefficientsPA(const Vector &x_loc)
|
||||
{
|
||||
// Both are constant or not specified.
|
||||
if (PA.MC.Size() == 1 && PA.C0.Size() == 1) { return; }
|
||||
|
||||
// Coefficients are always evaluated on the CPU for now.
|
||||
PA.MC.HostWrite();
|
||||
PA.C0.HostWrite();
|
||||
|
||||
const IntegrationRule &ir = *PA.ir;
|
||||
auto T = new IsoparametricTransformation;
|
||||
for (int e = 0; e < PA.ne; ++e)
|
||||
{
|
||||
// Uses the node positions in x_loc.
|
||||
PA.fes->GetMesh()->GetElementTransformation(e, x_loc, T);
|
||||
|
||||
if (PA.MC.Size() > 1)
|
||||
{
|
||||
for (int q = 0; q < PA.nq; ++q)
|
||||
{
|
||||
PA.MC(q + e * PA.nq) = metric_coeff->Eval(*T, ir.IntPoint(q));
|
||||
}
|
||||
}
|
||||
|
||||
if (PA.C0.Size() > 1)
|
||||
{
|
||||
for (int q = 0; q < PA.nq; ++q)
|
||||
{
|
||||
PA.C0(q + e * PA.nq) = lim_coeff->Eval(*T, ir.IntPoint(q));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete T;
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
|
||||
@@ -249,35 +213,6 @@ void TMOP_Integrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
PA.O.SetSize(ne*nq, Device::GetDeviceMemoryType());
|
||||
PA.O = 1.0;
|
||||
|
||||
if (metric_coeff)
|
||||
{
|
||||
if (auto cc = dynamic_cast<ConstantCoefficient *>(metric_coeff))
|
||||
{
|
||||
PA.MC.SetSize(1, Device::GetMemoryType());
|
||||
PA.MC.HostWrite();
|
||||
PA.MC(0) = cc->constant;
|
||||
}
|
||||
else
|
||||
{
|
||||
PA.MC.SetSize(PA.nq * PA.ne, Device::GetMemoryType());
|
||||
auto M0 = Reshape(PA.MC.HostWrite(), PA.nq, PA.ne);
|
||||
for (int e = 0; e < PA.ne; ++e)
|
||||
{
|
||||
ElementTransformation& T = *PA.fes->GetElementTransformation(e);
|
||||
for (int q = 0; q < ir.GetNPoints(); ++q)
|
||||
{
|
||||
M0(q,e) = metric_coeff->Eval(T, ir.IntPoint(q));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PA.MC.SetSize(1, Device::GetMemoryType());
|
||||
PA.MC.HostWrite();
|
||||
PA.MC(0) = 1.0;
|
||||
}
|
||||
|
||||
// Setup ref->target Jacobians, PA.Jtr, (dim x dim) Q-vector, DenseTensor
|
||||
PA.Jtr.SetSize(dim, dim, PA.ne*PA.nq, mt);
|
||||
PA.Jtr_needs_update = true;
|
||||
|
||||
@@ -258,7 +258,6 @@ void EvalH_094(const int e, const int qx, const int qy,
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, SetupGradPA_2D,
|
||||
const Vector &x_,
|
||||
const double metric_normal,
|
||||
const Vector &mc_,
|
||||
const Array<double> &metric_param,
|
||||
const int mid,
|
||||
const int NE,
|
||||
@@ -274,16 +273,11 @@ MFEM_REGISTER_TMOP_KERNELS(void, SetupGradPA_2D,
|
||||
|| mid == 80 || mid == 94,
|
||||
"2D metric not yet implemented!");
|
||||
|
||||
const bool const_m0 = mc_.Size() == 1;
|
||||
|
||||
constexpr int DIM = 2;
|
||||
constexpr int NBZ = 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto MC = const_m0 ?
|
||||
Reshape(mc_.Read(), 1, 1, 1) :
|
||||
Reshape(mc_.Read(), Q1D, Q1D, NE);
|
||||
const auto W = Reshape(w_.Read(), Q1D, Q1D);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
@@ -318,8 +312,7 @@ MFEM_REGISTER_TMOP_KERNELS(void, SetupGradPA_2D,
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,e);
|
||||
const double detJtr = kernels::Det<2>(Jtr);
|
||||
const double m_coef = const_m0 ? MC(0,0,0) : MC(qx,qy,e);
|
||||
const double weight = metric_normal * m_coef * W(qx,qy) * detJtr;
|
||||
const double weight = metric_normal * W(qx,qy) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[4];
|
||||
@@ -354,7 +347,6 @@ void TMOP_Integrator::AssembleGradPA_2D(const Vector &X) const
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double mn = metric_normal;
|
||||
const Vector &MC = PA.MC;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
@@ -367,7 +359,7 @@ void TMOP_Integrator::AssembleGradPA_2D(const Vector &X) const
|
||||
m->GetWeights(mp);
|
||||
}
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(SetupGradPA_2D,id,X,mn,MC,mp,M,N,W,B,G,J,H);
|
||||
MFEM_LAUNCH_TMOP_KERNEL(SetupGradPA_2D,id,X,mn,mp,M,N,W,B,G,J,H);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -312,7 +312,6 @@ void EvalH_338(const int e, const int qx, const int qy, const int qz,
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, SetupGradPA_3D,
|
||||
const double metric_normal,
|
||||
const Vector &mc_,
|
||||
const Array<double> &metric_param,
|
||||
const int mid,
|
||||
const Vector &x_,
|
||||
@@ -329,15 +328,10 @@ MFEM_REGISTER_TMOP_KERNELS(void, SetupGradPA_3D,
|
||||
mid == 321 || mid == 332 || mid == 338,
|
||||
"3D metric not yet implemented!");
|
||||
|
||||
const bool const_m0 = mc_.Size() == 1;
|
||||
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto MC = const_m0 ?
|
||||
Reshape(mc_.Read(), 1, 1, 1, 1) :
|
||||
Reshape(mc_.Read(), Q1D, Q1D, Q1D, NE);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
const auto W = Reshape(w_.Read(), Q1D, Q1D, Q1D);
|
||||
@@ -375,9 +369,7 @@ MFEM_REGISTER_TMOP_KERNELS(void, SetupGradPA_3D,
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,qz,e);
|
||||
const double detJtr = kernels::Det<3>(Jtr);
|
||||
const double m_coef = const_m0 ? MC(0,0,0,0) : MC(qx,qy,qz,e);
|
||||
const double weight = metric_normal * m_coef *
|
||||
W(qx,qy,qz) * detJtr;
|
||||
const double weight = metric_normal * W(qx,qy,qz) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[9];
|
||||
@@ -446,7 +438,6 @@ void TMOP_Integrator::AssembleGradPA_3D(const Vector &X) const
|
||||
const int M = metric->Id();
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double mn = metric_normal;
|
||||
const Vector &MC = PA.MC;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
@@ -459,7 +450,7 @@ void TMOP_Integrator::AssembleGradPA_3D(const Vector &X) const
|
||||
m->GetWeights(mp);
|
||||
}
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(SetupGradPA_3D,id,mn,MC,mp,M,X,N,W,B,G,J,H);
|
||||
MFEM_LAUNCH_TMOP_KERNEL(SetupGradPA_3D,id,mn,mp,M,X,N,W,B,G,J,H);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+2
-11
@@ -98,7 +98,6 @@ void EvalP_094(const double *Jpt, const double *w, double *P)
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AddMultPA_Kernel_2D,
|
||||
const double metric_normal,
|
||||
const Vector &mc_,
|
||||
const Array<double> &metric_param,
|
||||
const int mid,
|
||||
const int NE,
|
||||
@@ -115,17 +114,12 @@ MFEM_REGISTER_TMOP_KERNELS(void, AddMultPA_Kernel_2D,
|
||||
|| mid == 80 || mid == 94,
|
||||
"2D metric not yet implemented!");
|
||||
|
||||
const bool const_m0 = mc_.Size() == 1;
|
||||
|
||||
constexpr int DIM = 2;
|
||||
constexpr int NBZ = 1;
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto MC = const_m0 ?
|
||||
Reshape(mc_.Read(), 1, 1, 1) :
|
||||
Reshape(mc_.Read(), Q1D, Q1D, NE);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, NE);
|
||||
const auto W = Reshape(w_.Read(), Q1D, Q1D);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
@@ -160,9 +154,7 @@ MFEM_REGISTER_TMOP_KERNELS(void, AddMultPA_Kernel_2D,
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,e);
|
||||
const double detJtr = kernels::Det<2>(Jtr);
|
||||
const double m_coef = const_m0 ? MC(0,0,0) : MC(qx,qy,e);
|
||||
const double weight = metric_normal * m_coef *
|
||||
W(qx,qy) * detJtr;
|
||||
const double weight = metric_normal * W(qx,qy) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[4];
|
||||
@@ -212,7 +204,6 @@ void TMOP_Integrator::AddMultPA_2D(const Vector &X, Vector &Y) const
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
const double mn = metric_normal;
|
||||
const Vector &MC = PA.MC;
|
||||
|
||||
Array<double> mp;
|
||||
if (auto m = dynamic_cast<TMOP_Combo_QualityMetric *>(metric))
|
||||
@@ -220,7 +211,7 @@ void TMOP_Integrator::AddMultPA_2D(const Vector &X, Vector &Y) const
|
||||
m->GetWeights(mp);
|
||||
}
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultPA_Kernel_2D,id,mn,MC,mp,M,N,J,W,B,G,X,Y);
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultPA_Kernel_2D,id,mn,mp,M,N,J,W,B,G,X,Y);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+2
-11
@@ -131,7 +131,6 @@ void EvalP_338(const double *J, const double *w, double *P)
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AddMultPA_Kernel_3D,
|
||||
const double metric_normal,
|
||||
const Vector &mc_,
|
||||
const Array<double> &metric_param,
|
||||
const int mid,
|
||||
const int NE,
|
||||
@@ -148,15 +147,10 @@ MFEM_REGISTER_TMOP_KERNELS(void, AddMultPA_Kernel_3D,
|
||||
mid == 321 || mid == 332 || mid == 338,
|
||||
"3D metric not yet implemented!");
|
||||
|
||||
const bool const_m0 = mc_.Size() == 1;
|
||||
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto MC = const_m0 ?
|
||||
Reshape(mc_.Read(), 1, 1, 1, 1) :
|
||||
Reshape(mc_.Read(), Q1D, Q1D, Q1D, NE);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
const auto W = Reshape(w_.Read(), Q1D, Q1D, Q1D);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
@@ -194,9 +188,7 @@ MFEM_REGISTER_TMOP_KERNELS(void, AddMultPA_Kernel_3D,
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,qz,e);
|
||||
const double detJtr = kernels::Det<3>(Jtr);
|
||||
const double m_coef = const_m0 ? MC(0,0,0,0) : MC(qx,qy,qz,e);
|
||||
const double weight = metric_normal * m_coef *
|
||||
W(qx,qy,qz) * detJtr;
|
||||
const double weight = metric_normal * W(qx,qy,qz) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[9];
|
||||
@@ -248,7 +240,6 @@ void TMOP_Integrator::AddMultPA_3D(const Vector &X, Vector &Y) const
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
const double mn = metric_normal;
|
||||
const Vector &MC = PA.MC;
|
||||
|
||||
Array<double> mp;
|
||||
if (auto m = dynamic_cast<TMOP_Combo_QualityMetric *>(metric))
|
||||
@@ -256,7 +247,7 @@ void TMOP_Integrator::AddMultPA_3D(const Vector &X, Vector &Y) const
|
||||
m->GetWeights(mp);
|
||||
}
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultPA_Kernel_3D,id,mn,MC,mp,M,N,J,W,B,G,X,Y);
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultPA_Kernel_3D,id,mn,mp,M,N,J,W,B,G,X,Y);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+2
-10
@@ -73,7 +73,6 @@ double EvalW_094(const double *Jpt, const double *w)
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(double, EnergyPA_2D,
|
||||
const double metric_normal,
|
||||
const Vector &mc_,
|
||||
const Array<double> &metric_param,
|
||||
const int mid,
|
||||
const int NE,
|
||||
@@ -91,17 +90,12 @@ MFEM_REGISTER_TMOP_KERNELS(double, EnergyPA_2D,
|
||||
|| mid == 80 || mid == 94,
|
||||
"2D metric not yet implemented!");
|
||||
|
||||
const bool const_m0 = mc_.Size() == 1;
|
||||
|
||||
constexpr int DIM = 2;
|
||||
constexpr int NBZ = 1;
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto MC = const_m0 ?
|
||||
Reshape(mc_.Read(), 1, 1, 1) :
|
||||
Reshape(mc_.Read(), Q1D, Q1D, NE);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, NE);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
@@ -137,8 +131,7 @@ MFEM_REGISTER_TMOP_KERNELS(double, EnergyPA_2D,
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,e);
|
||||
const double detJtr = kernels::Det<2>(Jtr);
|
||||
const double m_coef = const_m0 ? MC(0,0,0) : MC(qx,qy,e);
|
||||
const double weight = metric_normal * m_coef * W(qx,qy) * detJtr;
|
||||
const double weight = metric_normal * W(qx,qy) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[4];
|
||||
@@ -176,7 +169,6 @@ double TMOP_Integrator::GetLocalStateEnergyPA_2D(const Vector &X) const
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double mn = metric_normal;
|
||||
const Vector &MC = PA.MC;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
@@ -190,7 +182,7 @@ double TMOP_Integrator::GetLocalStateEnergyPA_2D(const Vector &X) const
|
||||
m->GetWeights(mp);
|
||||
}
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(EnergyPA_2D,id,mn,MC,mp,M,N,J,W,B,G,X,O,E);
|
||||
MFEM_LAUNCH_TMOP_KERNEL(EnergyPA_2D,id,mn,mp,M,N,J,W,B,G,X,O,E);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+2
-11
@@ -82,7 +82,6 @@ double EvalW_338(const double *J, const double *w)
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(double, EnergyPA_3D,
|
||||
const double metric_normal,
|
||||
const Vector &mc_,
|
||||
const Array<double> &metric_param,
|
||||
const int mid,
|
||||
const int NE,
|
||||
@@ -100,15 +99,10 @@ MFEM_REGISTER_TMOP_KERNELS(double, EnergyPA_3D,
|
||||
mid == 321 || mid == 332 || mid == 338,
|
||||
"3D metric not yet implemented!");
|
||||
|
||||
const bool const_m0 = mc_.Size() == 1;
|
||||
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto MC = const_m0 ?
|
||||
Reshape(mc_.Read(), 1, 1, 1, 1) :
|
||||
Reshape(mc_.Read(), Q1D, Q1D, Q1D, NE);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
@@ -147,9 +141,7 @@ MFEM_REGISTER_TMOP_KERNELS(double, EnergyPA_3D,
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,qz,e);
|
||||
const double detJtr = kernels::Det<3>(Jtr);
|
||||
const double m_coef = const_m0 ? MC(0,0,0,0) : MC(qx,qy,qz,e);
|
||||
const double weight = metric_normal * m_coef *
|
||||
W(qx,qy,qz) * detJtr;
|
||||
const double weight = metric_normal * W(qx,qy,qz) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[9];
|
||||
@@ -189,7 +181,6 @@ double TMOP_Integrator::GetLocalStateEnergyPA_3D(const Vector &X) const
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double mn = metric_normal;
|
||||
const Vector &MC = PA.MC;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
@@ -203,7 +194,7 @@ double TMOP_Integrator::GetLocalStateEnergyPA_3D(const Vector &X) const
|
||||
m->GetWeights(mp);
|
||||
}
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(EnergyPA_3D,id,mn,MC,mp,M,N,J,W,B,G,O,X,E);
|
||||
MFEM_LAUNCH_TMOP_KERNEL(EnergyPA_3D,id,mn,mp,M,N,J,W,B,G,O,X,E);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+1
-7
@@ -781,13 +781,7 @@ std::unique_ptr<SparseMatrix>>
|
||||
int ndof_lor = fes_lor.GetNDofs();
|
||||
|
||||
// If the local mesh is empty, skip all computations
|
||||
if (nel_ho == 0)
|
||||
{
|
||||
return std::make_pair(
|
||||
std::unique_ptr<SparseMatrix>(new SparseMatrix),
|
||||
std::unique_ptr<SparseMatrix>(new SparseMatrix)
|
||||
);
|
||||
}
|
||||
if (nel_ho == 0) { return {nullptr, nullptr}; }
|
||||
|
||||
const CoarseFineTransformations& cf_tr = mesh_lor->GetRefinementTransforms();
|
||||
|
||||
|
||||
@@ -26,10 +26,6 @@
|
||||
#include "sort_pairs.hpp"
|
||||
#include "globals.hpp"
|
||||
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
#include <StrumpackConfig.hpp> // STRUMPACK_USE_PTSCOTCH, etc.
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
@@ -38,14 +34,6 @@ using namespace std;
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
#if defined(MFEM_USE_STRUMPACK) && \
|
||||
(defined(STRUMPACK_USE_PTSCOTCH) || defined(STRUMPACK_USE_SLATE_SCALAPACK))
|
||||
int Mpi::default_thread_required = MPI_THREAD_MULTIPLE;
|
||||
#else
|
||||
int Mpi::default_thread_required = MPI_THREAD_SINGLE;
|
||||
#endif
|
||||
|
||||
|
||||
GroupTopology::GroupTopology(const GroupTopology >)
|
||||
: MyComm(gt.MyComm),
|
||||
group_lproc(gt.group_lproc)
|
||||
|
||||
+14
-36
@@ -22,6 +22,7 @@
|
||||
#include "globals.hpp"
|
||||
#include <mpi.h>
|
||||
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
@@ -31,34 +32,10 @@ namespace mfem
|
||||
class Mpi
|
||||
{
|
||||
public:
|
||||
/// Singleton creation with Mpi::Init(argc, argv).
|
||||
static void Init(int &argc, char **&argv,
|
||||
int required = default_thread_required,
|
||||
int *provided = nullptr)
|
||||
{ Init(&argc, &argv, required, provided); }
|
||||
/// Singleton creation with Mpi::Init().
|
||||
static void Init(int *argc = nullptr, char ***argv = nullptr,
|
||||
int required = default_thread_required,
|
||||
int *provided = nullptr)
|
||||
{
|
||||
MFEM_VERIFY(!IsInitialized(), "MPI already initialized!");
|
||||
if (required == MPI_THREAD_SINGLE)
|
||||
{
|
||||
int mpi_err = MPI_Init(argc, argv);
|
||||
MFEM_VERIFY(!mpi_err, "error in MPI_Init()!");
|
||||
if (provided) { *provided = MPI_THREAD_SINGLE; }
|
||||
}
|
||||
else
|
||||
{
|
||||
int mpi_provided;
|
||||
int mpi_err = MPI_Init_thread(argc, argv, required, &mpi_provided);
|
||||
MFEM_VERIFY(!mpi_err, "error in MPI_Init()!");
|
||||
if (provided) { *provided = mpi_provided; }
|
||||
}
|
||||
// The Mpi singleton object below needs to be created after MPI_Init() for
|
||||
// some MPI implementations.
|
||||
Singleton();
|
||||
}
|
||||
/// Singleton creation with Mpi::Init();
|
||||
static void Init() { Init_(NULL, NULL); }
|
||||
/// Singleton creation with Mpi::Init(argc,argv);
|
||||
static void Init(int &argc, char **&argv) { Init_(&argc, &argv); }
|
||||
/// Finalize MPI (if it has been initialized and not yet already finalized).
|
||||
static void Finalize()
|
||||
{
|
||||
@@ -94,19 +71,20 @@ public:
|
||||
}
|
||||
/// Return true if the rank in MPI_COMM_WORLD is zero.
|
||||
static bool Root() { return WorldRank() == 0; }
|
||||
/// Default level of thread support for MPI_Init_thread.
|
||||
static MFEM_EXPORT int default_thread_required;
|
||||
private:
|
||||
/// Initialize the Mpi singleton.
|
||||
static Mpi &Singleton()
|
||||
/// Initialize MPI
|
||||
static void Init_(int *argc, char ***argv)
|
||||
{
|
||||
MFEM_VERIFY(!IsInitialized(), "MPI already initialized!")
|
||||
MPI_Init(argc, argv);
|
||||
// The "mpi" object below needs to be created after MPI_Init() for some
|
||||
// MPI implementations
|
||||
static Mpi mpi;
|
||||
return mpi;
|
||||
}
|
||||
/// Finalize MPI.
|
||||
/// Finalize MPI
|
||||
~Mpi() { Finalize(); }
|
||||
/// Prevent direct construction of objects of this class.
|
||||
Mpi() {}
|
||||
/// Prevent direct construction of objects of this class
|
||||
Mpi() { }
|
||||
};
|
||||
|
||||
/** @brief A simple convenience class based on the Mpi singleton class above.
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ void mfem_backtrace(int mode = 0, int depth = -1);
|
||||
|
||||
/** @brief Function called when an error is encountered. Used by the macros
|
||||
MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY. */
|
||||
[[noreturn]] void mfem_error(const char *msg = NULL);
|
||||
void mfem_error(const char *msg = NULL);
|
||||
|
||||
/// Function called by the macro MFEM_WARNING.
|
||||
void mfem_warning(const char *msg = NULL);
|
||||
|
||||
+31
-50
@@ -16,13 +16,13 @@
|
||||
#include <cstdlib>
|
||||
#include <errno.h>
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <winsock.h>
|
||||
#ifdef _MSC_VER
|
||||
typedef int ssize_t;
|
||||
// Link with ws2_32.lib
|
||||
@@ -51,66 +51,47 @@ int isockstream::establish()
|
||||
{
|
||||
// char myname[129];
|
||||
char myname[] = "localhost";
|
||||
int sfd;
|
||||
struct addrinfo hints, *res, *rp;
|
||||
int port;
|
||||
struct sockaddr_in sa;
|
||||
struct hostent *hp;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = 0;
|
||||
memset(&sa, 0, sizeof(struct sockaddr_in));
|
||||
// gethostname(myname, 128);
|
||||
hp= gethostbyname(myname);
|
||||
|
||||
int s = getaddrinfo(myname, NULL, &hints, &res);
|
||||
if (s != 0)
|
||||
if (hp == NULL)
|
||||
{
|
||||
mfem::err << "isockstream::establish(): getaddrinfo() failed!\n"
|
||||
<< "isockstream::establish(): getaddrinfo() returned: '"
|
||||
mfem::err << "isockstream::establish(): gethostbyname() failed!\n"
|
||||
<< "isockstream::establish(): gethostname() returned: '"
|
||||
<< myname << "'" << endl;
|
||||
error = 1;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// loop the list of address structures returned by getaddrinfo()
|
||||
for (rp = res; rp != NULL; rp = rp->ai_next)
|
||||
sa.sin_family= hp->h_addrtype;
|
||||
sa.sin_port= htons(portnum);
|
||||
|
||||
if ((port = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
if ((sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0)
|
||||
{
|
||||
mfem::err << "isockstream::establish(): socket() failed!" << endl;
|
||||
error = 2;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int on = 1;
|
||||
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
|
||||
{
|
||||
mfem::err << "isockstream::establish(): setsockopt() failed!" << endl;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (bind(sfd, (const struct sockaddr *)rp->ai_addr, rp->ai_addrlen) < 0)
|
||||
#else
|
||||
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) < 0)
|
||||
#endif
|
||||
{
|
||||
mfem::err << "isockstream::establish(): bind() failed!" << endl;
|
||||
close(sfd);
|
||||
error = 3;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// No address succeeded
|
||||
if (rp == NULL)
|
||||
{
|
||||
mfem::err << "Could not bind\n";
|
||||
mfem::err << "isockstream::establish(): socket() failed!" << endl;
|
||||
error = 2;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
listen(sfd, 4);
|
||||
return (sfd);
|
||||
int on=1;
|
||||
setsockopt(port, SOL_SOCKET, SO_REUSEADDR, (char *)(&on), sizeof(on));
|
||||
|
||||
if (bind(port,(const sockaddr*)&sa,(socklen_t)sizeof(struct sockaddr_in)) < 0)
|
||||
{
|
||||
mfem::err << "isockstream::establish(): bind() failed!" << endl;
|
||||
close(port);
|
||||
error = 3;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
listen(port, 4);
|
||||
error = 0;
|
||||
return (port);
|
||||
}
|
||||
|
||||
int isockstream::read_data(int s, char *buf, int n)
|
||||
|
||||
+34
-41
@@ -19,15 +19,15 @@
|
||||
#include <cstring> // memset, memcpy, strerror
|
||||
#include <cerrno> // errno
|
||||
#ifndef _WIN32
|
||||
#include <netdb.h> // getaddrinfo
|
||||
#include <netdb.h> // gethostbyname
|
||||
#include <arpa/inet.h> // htons
|
||||
#include <sys/types.h> // socket, setsockopt, connect, recv, send
|
||||
#include <sys/socket.h> // socket, setsockopt, connect, recv, send
|
||||
#include <unistd.h> // close
|
||||
#include <netinet/in.h> // sockaddr_in
|
||||
#define closesocket (::close)
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <winsock.h>
|
||||
#ifdef _MSC_VER
|
||||
typedef int ssize_t;
|
||||
// Link with ws2_32.lib
|
||||
@@ -93,7 +93,8 @@ int socketbuf::attach(int sd)
|
||||
|
||||
int socketbuf::open(const char hostname[], int port)
|
||||
{
|
||||
struct addrinfo hints, *res, *rp;
|
||||
struct sockaddr_in sa;
|
||||
struct hostent *hp;
|
||||
|
||||
if (!wsInit_.Initialized())
|
||||
{
|
||||
@@ -104,50 +105,42 @@ int socketbuf::open(const char hostname[], int port)
|
||||
setg(NULL, NULL, NULL);
|
||||
setp(obuf, obuf + buflen);
|
||||
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = 0;
|
||||
hints.ai_protocol = 0;
|
||||
|
||||
std::string portStr = std::to_string(port);
|
||||
int s = getaddrinfo(hostname, portStr.c_str(), &hints, &res);
|
||||
if (s != 0)
|
||||
hp = gethostbyname(hostname);
|
||||
if (hp == NULL)
|
||||
{
|
||||
socket_descriptor = -3;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (rp = res; rp != NULL; rp = rp->ai_next)
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
memcpy((char *)&sa.sin_addr, hp->h_addr, hp->h_length);
|
||||
sa.sin_family = hp->h_addrtype;
|
||||
sa.sin_port = htons(port);
|
||||
socket_descriptor = socket(hp->h_addrtype, SOCK_STREAM, 0);
|
||||
if (socket_descriptor < 0)
|
||||
{
|
||||
socket_descriptor = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if (socket_descriptor < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined __APPLE__
|
||||
// OS X does not support the MSG_NOSIGNAL option of send().
|
||||
// Instead we can use the SO_NOSIGPIPE socket option.
|
||||
int on = 1;
|
||||
if (setsockopt(socket_descriptor, SOL_SOCKET, SO_NOSIGPIPE,
|
||||
&on, sizeof(on)) < 0)
|
||||
{
|
||||
closesocket(socket_descriptor);
|
||||
socket_descriptor = -2;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (connect(socket_descriptor, rp->ai_addr, rp->ai_addrlen) < 0)
|
||||
{
|
||||
closesocket(socket_descriptor);
|
||||
socket_descriptor = -2;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
#if defined __APPLE__
|
||||
// OS X does not support the MSG_NOSIGNAL option of send().
|
||||
// Instead we can use the SO_NOSIGPIPE socket option.
|
||||
int on = 1;
|
||||
if (setsockopt(socket_descriptor, SOL_SOCKET, SO_NOSIGPIPE,
|
||||
(char *)(&on), sizeof(on)) < 0)
|
||||
{
|
||||
closesocket(socket_descriptor);
|
||||
socket_descriptor = -2;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (connect(socket_descriptor,
|
||||
(const struct sockaddr *)&sa, sizeof(sa)) < 0)
|
||||
{
|
||||
closesocket(socket_descriptor);
|
||||
socket_descriptor = -2;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+6
-50
@@ -937,14 +937,11 @@ GMRESSolver::GMRESSolver(GinkgoExecutor &exec,
|
||||
void GMRESSolver::SetKDim(int dim)
|
||||
{
|
||||
m = dim;
|
||||
using gmres = gko::solver::Gmres<double>;
|
||||
// Create new solver factory with other parameters the same, but new value for krylov_dim
|
||||
auto current_params = gko::as<gmres::Factory>(solver_gen)->get_parameters();
|
||||
this->solver_gen = current_params.with_krylov_dim(static_cast<unsigned long>(m))
|
||||
.on(this->executor);
|
||||
using gmres_type = gko::solver::Gmres<double>;
|
||||
gko::as<gmres_type::Factory>(solver_gen)->get_parameters().krylov_dim = m;
|
||||
if (solver)
|
||||
{
|
||||
gko::as<gmres>(solver)->set_krylov_dim(static_cast<unsigned long>(m));
|
||||
gko::as<gmres_type>(solver)->set_krylov_dim(static_cast<unsigned long>(m));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1039,14 +1036,11 @@ CBGMRESSolver::CBGMRESSolver(GinkgoExecutor &exec,
|
||||
void CBGMRESSolver::SetKDim(int dim)
|
||||
{
|
||||
m = dim;
|
||||
using gmres = gko::solver::CbGmres<double>;
|
||||
// Create new solver factory with other parameters the same, but new value for krylov_dim
|
||||
auto current_params = gko::as<gmres::Factory>(solver_gen)->get_parameters();
|
||||
this->solver_gen = current_params.with_krylov_dim(static_cast<unsigned long>(m))
|
||||
.on(this->executor);
|
||||
using gmres_type = gko::solver::CbGmres<double>;
|
||||
gko::as<gmres_type::Factory>(solver_gen)->get_parameters().krylov_dim = m;
|
||||
if (solver)
|
||||
{
|
||||
gko::as<gmres>(solver)->set_krylov_dim(static_cast<unsigned long>(m));
|
||||
gko::as<gmres_type>(solver)->set_krylov_dim(static_cast<unsigned long>(m));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1211,11 +1205,7 @@ IluPreconditioner::IluPreconditioner(
|
||||
.with_skip_sorting(skip_sort)
|
||||
.on(executor);
|
||||
precond_gen = gko::preconditioner::Ilu<>::build()
|
||||
#if MFEM_GINKGO_VERSION < 10700
|
||||
.with_factorization_factory(fact_factory)
|
||||
#else
|
||||
.with_factorization(fact_factory)
|
||||
#endif
|
||||
.on(executor);
|
||||
}
|
||||
else
|
||||
@@ -1227,11 +1217,7 @@ IluPreconditioner::IluPreconditioner(
|
||||
.with_skip_sorting(skip_sort)
|
||||
.on(executor);
|
||||
precond_gen = gko::preconditioner::Ilu<>::build()
|
||||
#if MFEM_GINKGO_VERSION < 10700
|
||||
.with_factorization_factory(fact_factory)
|
||||
#else
|
||||
.with_factorization(fact_factory)
|
||||
#endif
|
||||
.on(executor);
|
||||
}
|
||||
|
||||
@@ -1269,15 +1255,9 @@ IluIsaiPreconditioner::IluIsaiPreconditioner(
|
||||
.on(executor);
|
||||
precond_gen = gko::preconditioner::Ilu<l_solver_type,
|
||||
u_solver_type>::build()
|
||||
#if MFEM_GINKGO_VERSION < 10700
|
||||
.with_factorization_factory(fact_factory)
|
||||
.with_l_solver_factory(l_solver_factory)
|
||||
.with_u_solver_factory(u_solver_factory)
|
||||
#else
|
||||
.with_factorization(fact_factory)
|
||||
.with_l_solver(l_solver_factory)
|
||||
.with_u_solver(u_solver_factory)
|
||||
#endif
|
||||
.on(executor);
|
||||
|
||||
}
|
||||
@@ -1291,15 +1271,9 @@ IluIsaiPreconditioner::IluIsaiPreconditioner(
|
||||
.on(executor);
|
||||
precond_gen = gko::preconditioner::Ilu<l_solver_type,
|
||||
u_solver_type>::build()
|
||||
#if MFEM_GINKGO_VERSION < 10700
|
||||
.with_factorization_factory(fact_factory)
|
||||
.with_l_solver_factory(l_solver_factory)
|
||||
.with_u_solver_factory(u_solver_factory)
|
||||
#else
|
||||
.with_factorization(fact_factory)
|
||||
.with_l_solver(l_solver_factory)
|
||||
.with_u_solver(u_solver_factory)
|
||||
#endif
|
||||
.on(executor);
|
||||
}
|
||||
}
|
||||
@@ -1324,11 +1298,7 @@ IcPreconditioner::IcPreconditioner(
|
||||
.with_skip_sorting(skip_sort)
|
||||
.on(executor);
|
||||
precond_gen = gko::preconditioner::Ic<>::build()
|
||||
#if MFEM_GINKGO_VERSION < 10700
|
||||
.with_factorization_factory(fact_factory)
|
||||
#else
|
||||
.with_factorization(fact_factory)
|
||||
#endif
|
||||
.on(executor);
|
||||
}
|
||||
else
|
||||
@@ -1341,11 +1311,7 @@ IcPreconditioner::IcPreconditioner(
|
||||
.with_skip_sorting(skip_sort)
|
||||
.on(executor);
|
||||
precond_gen = gko::preconditioner::Ic<>::build()
|
||||
#if MFEM_GINKGO_VERSION < 10700
|
||||
.with_factorization_factory(fact_factory)
|
||||
#else
|
||||
.with_factorization(fact_factory)
|
||||
#endif
|
||||
.on(executor);
|
||||
}
|
||||
}
|
||||
@@ -1374,13 +1340,8 @@ IcIsaiPreconditioner::IcIsaiPreconditioner(
|
||||
.with_skip_sorting(skip_sort)
|
||||
.on(executor);
|
||||
precond_gen = gko::preconditioner::Ic<l_solver_type>::build()
|
||||
#if MFEM_GINKGO_VERSION < 10700
|
||||
.with_factorization_factory(fact_factory)
|
||||
.with_l_solver_factory(l_solver_factory)
|
||||
#else
|
||||
.with_factorization(fact_factory)
|
||||
.with_l_solver(l_solver_factory)
|
||||
#endif
|
||||
.on(executor);
|
||||
}
|
||||
else
|
||||
@@ -1393,13 +1354,8 @@ IcIsaiPreconditioner::IcIsaiPreconditioner(
|
||||
.with_skip_sorting(skip_sort)
|
||||
.on(executor);
|
||||
precond_gen = gko::preconditioner::Ic<l_solver_type>::build()
|
||||
#if MFEM_GINKGO_VERSION < 10700
|
||||
.with_factorization_factory(fact_factory)
|
||||
.with_l_solver_factory(l_solver_factory)
|
||||
#else
|
||||
.with_factorization(fact_factory)
|
||||
.with_l_solver(l_solver_factory)
|
||||
#endif
|
||||
.on(executor);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-12
@@ -862,10 +862,8 @@ public:
|
||||
{
|
||||
rel_tol = rtol;
|
||||
this->update_stop_factory();
|
||||
auto current_params = gko::as<typename SolverType::Factory>
|
||||
(solver_gen)->get_parameters();
|
||||
this->solver_gen = current_params.with_criteria(this->combined_factory)
|
||||
.on(this->executor);
|
||||
gko::as<typename SolverType::Factory>(solver_gen)->get_parameters().criteria =
|
||||
{ combined_factory };
|
||||
if (solver)
|
||||
{
|
||||
gko::as<SolverType>(solver)->set_stop_criterion_factory(combined_factory);
|
||||
@@ -876,10 +874,8 @@ public:
|
||||
{
|
||||
abs_tol = atol;
|
||||
this->update_stop_factory();
|
||||
auto current_params = gko::as<typename SolverType::Factory>
|
||||
(solver_gen)->get_parameters();
|
||||
this->solver_gen = current_params.with_criteria(this->combined_factory)
|
||||
.on(this->executor);
|
||||
gko::as<typename SolverType::Factory>(solver_gen)->get_parameters().criteria =
|
||||
{ combined_factory };
|
||||
if (solver)
|
||||
{
|
||||
gko::as<SolverType>(solver)->set_stop_criterion_factory(combined_factory);
|
||||
@@ -890,10 +886,8 @@ public:
|
||||
{
|
||||
max_iter = max_it;
|
||||
this->update_stop_factory();
|
||||
auto current_params = gko::as<typename SolverType::Factory>
|
||||
(solver_gen)->get_parameters();
|
||||
this->solver_gen = current_params.with_criteria(this->combined_factory)
|
||||
.on(this->executor);
|
||||
gko::as<typename SolverType::Factory>(solver_gen)->get_parameters().criteria =
|
||||
{ combined_factory };
|
||||
if (solver)
|
||||
{
|
||||
gko::as<SolverType>(solver)->set_stop_criterion_factory(combined_factory);
|
||||
|
||||
+3
-4
@@ -5075,8 +5075,7 @@ void HypreBoomerAMG::RecomputeRBMs()
|
||||
}
|
||||
}
|
||||
|
||||
void HypreBoomerAMG::SetElasticityOptions(ParFiniteElementSpace *fespace_,
|
||||
bool interp_refine_)
|
||||
void HypreBoomerAMG::SetElasticityOptions(ParFiniteElementSpace *fespace_)
|
||||
{
|
||||
#ifdef HYPRE_USING_GPU
|
||||
MFEM_ABORT("this method is not supported in hypre built with GPU support");
|
||||
@@ -5087,7 +5086,7 @@ void HypreBoomerAMG::SetElasticityOptions(ParFiniteElementSpace *fespace_,
|
||||
|
||||
// Make sure the systems AMG options are set
|
||||
int dim = fespace_->GetParMesh()->Dimension();
|
||||
SetSystemsOptions(dim, fespace->GetOrdering() == Ordering::byNODES);
|
||||
SetSystemsOptions(dim);
|
||||
|
||||
// Nodal coarsening options (nodal coarsening is required for this solver)
|
||||
// See hypre's new_ij driver and the paper for descriptions.
|
||||
@@ -5102,7 +5101,7 @@ void HypreBoomerAMG::SetElasticityOptions(ParFiniteElementSpace *fespace_,
|
||||
|
||||
// Optionally pre-process the interpolation matrix through iterative weight
|
||||
// refinement (this is generally applicable for any system)
|
||||
int interp_refine = interp_refine_;
|
||||
int interp_refine = 1;
|
||||
|
||||
HYPRE_BoomerAMGSetNodal(amg_precond, nodal);
|
||||
HYPRE_BoomerAMGSetNodalDiag(amg_precond, nodal_diag);
|
||||
|
||||
+3
-4
@@ -1623,10 +1623,9 @@ public:
|
||||
geometric rigid body modes and could perform better on some problems, see
|
||||
"Improving algebraic multigrid interpolation operators for linear
|
||||
elasticity problems", Baker, Kolev, Yang, NLAA 2009, DOI:10.1002/nla.688.
|
||||
The optional argument @ interp_refine is used to enable/disable pre-processing
|
||||
of the interpolation matrix through iterative weight refinement */
|
||||
void SetElasticityOptions(ParFiniteElementSpace *fespace,
|
||||
bool interp_refine = true);
|
||||
This solver assumes Ordering::byVDIM in the FiniteElementSpace used to
|
||||
construct A. */
|
||||
void SetElasticityOptions(ParFiniteElementSpace *fespace);
|
||||
|
||||
#if MFEM_HYPRE_VERSION >= 21800
|
||||
/** Hypre parameters to use AIR AMG solve for advection-dominated problems.
|
||||
|
||||
+162
-395
@@ -16,471 +16,238 @@
|
||||
|
||||
#include "strumpack.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace strumpack;
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
STRUMPACKRowLocMatrix::STRUMPACKRowLocMatrix(MPI_Comm comm,
|
||||
int num_loc_rows,
|
||||
HYPRE_BigInt first_loc_row,
|
||||
HYPRE_BigInt glob_nrows,
|
||||
HYPRE_BigInt glob_ncols,
|
||||
int *I, HYPRE_BigInt *J,
|
||||
double *data, bool sym_sparse)
|
||||
int num_loc_rows, int first_loc_row,
|
||||
int glob_nrows, int glob_ncols,
|
||||
int *I, int *J, double *data)
|
||||
: comm_(comm), A_(NULL)
|
||||
{
|
||||
// Set mfem::Operator member data
|
||||
height = num_loc_rows;
|
||||
width = num_loc_rows;
|
||||
|
||||
// Allocate STRUMPACK's CSRMatrixMPI (copies all inputs)
|
||||
int rank, nprocs;
|
||||
MPI_Comm_rank(comm, &rank);
|
||||
MPI_Comm_size(comm, &nprocs);
|
||||
Array<HYPRE_BigInt> dist(nprocs + 1);
|
||||
// Allocate STRUMPACK's CSRMatrixMPI
|
||||
int nprocs, rank;
|
||||
MPI_Comm_rank(comm_, &rank);
|
||||
MPI_Comm_size(comm_, &nprocs);
|
||||
int * dist = new int[nprocs + 1];
|
||||
dist[rank + 1] = first_loc_row + num_loc_rows;
|
||||
dist[0] = 0;
|
||||
dist[rank + 1] = first_loc_row + (HYPRE_BigInt)num_loc_rows;
|
||||
MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
|
||||
dist.GetData() + 1, 1, HYPRE_MPI_BIG_INT, comm);
|
||||
|
||||
#if !(defined(HYPRE_BIGINT) || defined(HYPRE_MIXEDINT))
|
||||
A_ = new strumpack::CSRMatrixMPI<double, HYPRE_BigInt>(
|
||||
(HYPRE_BigInt)num_loc_rows, I, J, data, dist.GetData(),
|
||||
comm, sym_sparse);
|
||||
#else
|
||||
Array<HYPRE_BigInt> II(num_loc_rows+1);
|
||||
for (int i = 0; i <= num_loc_rows; i++) { II[i] = (HYPRE_BigInt)I[i]; }
|
||||
A_ = new strumpack::CSRMatrixMPI<double, HYPRE_BigInt>(
|
||||
(HYPRE_BigInt)num_loc_rows, II.GetData(), J, data, dist.GetData(),
|
||||
comm, sym_sparse);
|
||||
#endif
|
||||
MPI_Allgather(MPI_IN_PLACE, 0, MPI_INT, dist + 1, 1, MPI_INT, comm_);
|
||||
A_ = new CSRMatrixMPI<double,int>(num_loc_rows, I, J, data, dist, comm_, false);
|
||||
delete[] dist;
|
||||
}
|
||||
|
||||
STRUMPACKRowLocMatrix::STRUMPACKRowLocMatrix(const Operator &op,
|
||||
bool sym_sparse)
|
||||
STRUMPACKRowLocMatrix::STRUMPACKRowLocMatrix(const HypreParMatrix & hypParMat)
|
||||
: comm_(hypParMat.GetComm()),
|
||||
A_(NULL)
|
||||
{
|
||||
const HypreParMatrix *APtr = dynamic_cast<const HypreParMatrix *>(&op);
|
||||
MFEM_VERIFY(APtr, "Not a compatible matrix type");
|
||||
MPI_Comm comm = APtr->GetComm();
|
||||
|
||||
// Set mfem::Operator member data
|
||||
height = op.Height();
|
||||
width = op.Width();
|
||||
|
||||
// First cast the parameter to a hypre_ParCSRMatrix
|
||||
hypre_ParCSRMatrix *parcsr_op =
|
||||
(hypre_ParCSRMatrix *)const_cast<HypreParMatrix &>(*APtr);
|
||||
hypre_ParCSRMatrix * parcsr_op =
|
||||
(hypre_ParCSRMatrix *)const_cast<HypreParMatrix&>(hypParMat);
|
||||
|
||||
// Create the CSRMatrixMPI A by taking the internal data from a
|
||||
// hypre_CSRMatrix
|
||||
APtr->HostRead();
|
||||
hypre_CSRMatrix *csr_op = hypre_MergeDiagAndOffd(parcsr_op);
|
||||
APtr->HypreRead();
|
||||
HYPRE_Int *Iptr = csr_op->i;
|
||||
MFEM_ASSERT(parcsr_op != NULL,"STRUMPACK: const_cast failed in SetOperator");
|
||||
|
||||
// Create the CSRMatrixMPI A_ by borrowing the internal data from a
|
||||
// hypre_CSRMatrix.
|
||||
hypParMat.HostRead();
|
||||
hypre_CSRMatrix * csr_op = hypre_MergeDiagAndOffd(parcsr_op);
|
||||
hypParMat.HypreRead();
|
||||
hypre_CSRMatrixSetDataOwner(csr_op,0);
|
||||
#if MFEM_HYPRE_VERSION >= 21600
|
||||
HYPRE_BigInt *Jptr = csr_op->big_j;
|
||||
#else
|
||||
HYPRE_Int *Jptr = csr_op->j;
|
||||
// For now, this method assumes that HYPRE_Int is int. Also, csr_op->num_cols
|
||||
// is of type HYPRE_Int, so if we want to check for big indices in
|
||||
// csr_op->big_j, we'll have to check all entries and that check will only be
|
||||
// necessary in HYPRE_MIXEDINT mode which is not supported at the moment.
|
||||
hypre_CSRMatrixBigJtoJ(csr_op);
|
||||
#endif
|
||||
double *data = csr_op->data;
|
||||
|
||||
HYPRE_BigInt fst_row = parcsr_op->first_row_index;
|
||||
HYPRE_Int m_loc = csr_op->num_rows;
|
||||
height = csr_op->num_rows;
|
||||
width = csr_op->num_rows;
|
||||
|
||||
// Allocate STRUMPACK's CSRMatrixMPI
|
||||
int rank, nprocs;
|
||||
MPI_Comm_rank(comm, &rank);
|
||||
MPI_Comm_size(comm, &nprocs);
|
||||
Array<HYPRE_BigInt> dist(nprocs + 1);
|
||||
int nprocs, rank;
|
||||
MPI_Comm_rank(comm_, &rank);
|
||||
MPI_Comm_size(comm_, &nprocs);
|
||||
int * dist = new int[nprocs + 1];
|
||||
dist[rank + 1] = parcsr_op->first_row_index + csr_op->num_rows;
|
||||
dist[0] = 0;
|
||||
dist[rank + 1] = fst_row + (HYPRE_BigInt)m_loc;
|
||||
MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
|
||||
dist.GetData() + 1, 1, HYPRE_MPI_BIG_INT, comm);
|
||||
MPI_Allgather(MPI_IN_PLACE, 0, MPI_INT, dist + 1, 1, MPI_INT, comm_);
|
||||
A_ = new CSRMatrixMPI<double,int>(csr_op->num_rows, csr_op->i, csr_op->j,
|
||||
csr_op->data, dist, comm_, false);
|
||||
delete[] dist;
|
||||
|
||||
#if !defined(HYPRE_MIXEDINT)
|
||||
A_ = new strumpack::CSRMatrixMPI<double, HYPRE_BigInt>(
|
||||
(HYPRE_BigInt)m_loc, Iptr, Jptr, data, dist.GetData(),
|
||||
comm, sym_sparse);
|
||||
#else
|
||||
Array<HYPRE_BigInt> II(m_loc+1);
|
||||
for (int i = 0; i <= m_loc; i++) { II[i] = (HYPRE_BigInt)Iptr[i]; }
|
||||
A_ = new strumpack::CSRMatrixMPI<double, HYPRE_BigInt>(
|
||||
(HYPRE_BigInt)m_loc, II.GetData(), Jptr, data, dist.GetData(),
|
||||
comm, sym_sparse);
|
||||
#endif
|
||||
|
||||
// Everything has been copied so delete the structure
|
||||
// Everything has been copied or abducted so delete the structure
|
||||
hypre_CSRMatrixDestroy(csr_op);
|
||||
}
|
||||
|
||||
STRUMPACKRowLocMatrix::~STRUMPACKRowLocMatrix()
|
||||
{
|
||||
delete A_;
|
||||
// Delete the struct
|
||||
if ( A_ != NULL ) { delete A_; }
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
STRUMPACKSolverBase(MPI_Comm comm, int argc, char *argv[])
|
||||
: APtr_(NULL),
|
||||
factor_verbose_(false),
|
||||
solve_verbose_(false),
|
||||
reorder_reuse_(false),
|
||||
nrhs_(-1)
|
||||
STRUMPACKSolver::STRUMPACKSolver( int argc, char* argv[], MPI_Comm comm )
|
||||
: comm_(comm),
|
||||
APtr_(NULL),
|
||||
solver_(NULL)
|
||||
{
|
||||
solver_ = new STRUMPACKSolverType(comm, argc, argv, false);
|
||||
this->Init(argc, argv);
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
STRUMPACKSolverBase(STRUMPACKRowLocMatrix &A, int argc, char *argv[])
|
||||
: APtr_(&A),
|
||||
factor_verbose_(false),
|
||||
solve_verbose_(false),
|
||||
reorder_reuse_(false),
|
||||
nrhs_(-1)
|
||||
STRUMPACKSolver::STRUMPACKSolver( STRUMPACKRowLocMatrix & A )
|
||||
: comm_(A.GetComm()),
|
||||
APtr_(&A),
|
||||
solver_(NULL)
|
||||
{
|
||||
solver_ = new STRUMPACKSolverType(A.GetComm(), argc, argv, false);
|
||||
SetOperator(A);
|
||||
height = A.Height();
|
||||
width = A.Width();
|
||||
|
||||
this->Init(0, NULL);
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
~STRUMPACKSolverBase()
|
||||
STRUMPACKSolver::~STRUMPACKSolver()
|
||||
{
|
||||
delete solver_;
|
||||
if ( solver_ != NULL ) { delete solver_; }
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetFromCommandLine()
|
||||
void STRUMPACKSolver::Init( int argc, char* argv[] )
|
||||
{
|
||||
solver_->options().set_from_command_line();
|
||||
MPI_Comm_size(comm_, &numProcs_);
|
||||
MPI_Comm_rank(comm_, &myid_);
|
||||
|
||||
factor_verbose_ = false;
|
||||
solve_verbose_ = false;
|
||||
|
||||
solver_ = new StrumpackSparseSolverMPIDist<double,int>(comm_, argc, argv,
|
||||
false);
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetPrintFactorStatistics(bool print_stat)
|
||||
void STRUMPACKSolver::SetFromCommandLine( )
|
||||
{
|
||||
solver_->options().set_from_command_line( );
|
||||
}
|
||||
|
||||
void STRUMPACKSolver::SetPrintFactorStatistics( bool print_stat )
|
||||
{
|
||||
factor_verbose_ = print_stat;
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetPrintSolveStatistics(bool print_stat)
|
||||
void STRUMPACKSolver::SetPrintSolveStatistics( bool print_stat )
|
||||
{
|
||||
solve_verbose_ = print_stat;
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>
|
||||
::SetRelTol(double rtol)
|
||||
void STRUMPACKSolver::SetKrylovSolver( strumpack::KrylovSolver method )
|
||||
{
|
||||
solver_->options().set_rel_tol(rtol);
|
||||
solver_->options().set_Krylov_solver( method );
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>
|
||||
::SetAbsTol(double atol)
|
||||
void STRUMPACKSolver::SetReorderingStrategy( strumpack::ReorderingStrategy
|
||||
method )
|
||||
{
|
||||
solver_->options().set_abs_tol(atol);
|
||||
solver_->options().set_reordering_method( method );
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>
|
||||
::SetMaxIter(int max_it)
|
||||
void STRUMPACKSolver::DisableMatching( )
|
||||
{
|
||||
solver_->options().set_maxit(max_it);
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>
|
||||
::SetReorderingReuse(bool reuse)
|
||||
{
|
||||
reorder_reuse_ = reuse;
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>
|
||||
::EnableGPU()
|
||||
{
|
||||
solver_->options().enable_gpu();
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>
|
||||
::DisableGPU()
|
||||
{
|
||||
solver_->options().disable_gpu();
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetKrylovSolver(strumpack::KrylovSolver method)
|
||||
{
|
||||
solver_->options().set_Krylov_solver(method);
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetReorderingStrategy(strumpack::ReorderingStrategy method)
|
||||
{
|
||||
solver_->options().set_reordering_method(method);
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetMatching(strumpack::MatchingJob job)
|
||||
{
|
||||
solver_->options().set_matching(job);
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetCompression(strumpack::CompressionType type)
|
||||
{
|
||||
#if STRUMPACK_VERSION_MAJOR >= 5
|
||||
solver_->options().set_compression(type);
|
||||
#if STRUMPACK_VERSION_MAJOR >= 3
|
||||
solver_->options().set_matching( strumpack::MatchingJob::NONE );
|
||||
#else
|
||||
switch (type)
|
||||
solver_->options().set_mc64job( strumpack::MC64Job::NONE );
|
||||
#endif
|
||||
}
|
||||
|
||||
void STRUMPACKSolver::EnableMatching( )
|
||||
{
|
||||
#if STRUMPACK_VERSION_MAJOR >= 3
|
||||
solver_->options().set_matching
|
||||
( strumpack::MatchingJob::MAX_DIAGONAL_PRODUCT_SCALING );
|
||||
#else
|
||||
solver_->options().set_mc64job
|
||||
( strumpack::MC64Job::MAX_DIAGONAL_PRODUCT_SCALING );
|
||||
#endif
|
||||
}
|
||||
|
||||
#if STRUMPACK_VERSION_MAJOR >= 3
|
||||
void STRUMPACKSolver::EnableParallelMatching( )
|
||||
{
|
||||
solver_->options().set_matching
|
||||
( strumpack::MatchingJob::COMBBLAS );
|
||||
}
|
||||
#endif
|
||||
|
||||
void STRUMPACKSolver::SetRelTol( double rtol )
|
||||
{
|
||||
solver_->options().set_rel_tol( rtol );
|
||||
}
|
||||
|
||||
void STRUMPACKSolver::SetAbsTol( double atol )
|
||||
{
|
||||
solver_->options().set_abs_tol( atol );
|
||||
}
|
||||
|
||||
|
||||
void STRUMPACKSolver::Mult( const Vector & x, Vector & y ) const
|
||||
{
|
||||
MFEM_ASSERT(APtr_ != NULL,
|
||||
"STRUMPACK Error: The operator must be set before"
|
||||
" the system can be solved.");
|
||||
MFEM_ASSERT(x.Size() == Width(), "invalid x.Size() = " << x.Size()
|
||||
<< ", expected size = " << Width());
|
||||
MFEM_ASSERT(y.Size() == Height(), "invalid y.Size() = " << y.Size()
|
||||
<< ", expected size = " << Height());
|
||||
|
||||
double* yPtr = y.HostWrite();
|
||||
const double* xPtr = x.HostRead();
|
||||
|
||||
solver_->options().set_verbose( factor_verbose_ );
|
||||
ReturnCode ret = solver_->factor();
|
||||
switch (ret)
|
||||
{
|
||||
case strumpack::NONE:
|
||||
solver_->options().disable_BLR();
|
||||
solver_->options().disable_HSS();
|
||||
break;
|
||||
case strumpack::BLR:
|
||||
solver_->options().enable_BLR();
|
||||
break;
|
||||
case strumpack::HSS:
|
||||
solver_->options().enable_HSS();
|
||||
break;
|
||||
case ReturnCode::SUCCESS: break;
|
||||
case ReturnCode::MATRIX_NOT_SET:
|
||||
{
|
||||
MFEM_ABORT("STRUMPACK: Matrix was not set!");
|
||||
}
|
||||
break;
|
||||
case ReturnCode::REORDERING_ERROR:
|
||||
{
|
||||
MFEM_ABORT("STRUMPACK: Matrix reordering failed!");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Invalid compression type for STRUMPACK version " <<
|
||||
STRUMPACK_VERSION_MAJOR << "!");
|
||||
break;
|
||||
{
|
||||
MFEM_ABORT("STRUMPACK: 'factor()' error code = " << ret);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
solver_->options().set_verbose( solve_verbose_ );
|
||||
solver_->solve(xPtr, yPtr);
|
||||
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetCompressionRelTol(double rtol)
|
||||
{
|
||||
#if STRUMPACK_VERSION_MAJOR >= 5
|
||||
solver_->options().set_compression_rel_tol(rtol);
|
||||
#else
|
||||
solver_->options().BLR_options().set_rel_tol(rtol);
|
||||
solver_->options().HSS_options().set_rel_tol(rtol);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetCompressionAbsTol(double atol)
|
||||
{
|
||||
#if STRUMPACK_VERSION_MAJOR >= 5
|
||||
solver_->options().set_compression_abs_tol(atol);
|
||||
#else
|
||||
solver_->options().BLR_options().set_abs_tol(atol);
|
||||
solver_->options().HSS_options().set_abs_tol(atol);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if STRUMPACK_VERSION_MAJOR >= 5
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetCompressionLossyPrecision(int precision)
|
||||
{
|
||||
solver_->options().set_lossy_precision(precision);
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetCompressionButterflyLevels(int levels)
|
||||
{
|
||||
solver_->options().HODLR_options().set_butterfly_levels(levels);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
SetOperator(const Operator &op)
|
||||
void STRUMPACKSolver::SetOperator( const Operator & op )
|
||||
{
|
||||
// Verify that we have a compatible operator
|
||||
bool first_mat = !APtr_;
|
||||
APtr_ = dynamic_cast<const STRUMPACKRowLocMatrix *>(&op);
|
||||
MFEM_VERIFY(APtr_,
|
||||
"STRUMPACK: Operator is not a STRUMPACKRowLocMatrix!");
|
||||
APtr_ = dynamic_cast<const STRUMPACKRowLocMatrix*>(&op);
|
||||
if ( APtr_ == NULL )
|
||||
{
|
||||
mfem_error("STRUMPACKSolver::SetOperator : not STRUMPACKRowLocMatrix!");
|
||||
}
|
||||
|
||||
solver_->set_matrix( *(APtr_->getA()) );
|
||||
|
||||
// Set mfem::Operator member data
|
||||
height = op.Height();
|
||||
width = op.Width();
|
||||
|
||||
if (first_mat || !reorder_reuse_)
|
||||
{
|
||||
solver_->set_matrix(*(APtr_->GetA()));
|
||||
}
|
||||
else
|
||||
{
|
||||
solver_->update_matrix_values(*(APtr_->GetA()));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
FactorInternal() const
|
||||
{
|
||||
MFEM_ASSERT(APtr_,
|
||||
"STRUMPACK: Operator must be set before the system can be "
|
||||
"solved!");
|
||||
solver_->options().set_verbose(factor_verbose_);
|
||||
strumpack::ReturnCode ret = solver_->factor();
|
||||
if (ret != strumpack::ReturnCode::SUCCESS)
|
||||
{
|
||||
#if STRUMPACK_VERSION_MAJOR >= 7
|
||||
MFEM_ABORT("STRUMPACK: Factor failed with return code " << ret << "!");
|
||||
#else
|
||||
MFEM_ABORT("STRUMPACK: Factor failed!");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
MFEM_ASSERT(x.Size() == Width(),
|
||||
"STRUMPACK: Invalid x.Size() = " << x.Size() <<
|
||||
", expected size = " << Width() << "!");
|
||||
MFEM_ASSERT(y.Size() == Height(),
|
||||
"STRUMPACK: Invalid y.Size() = " << y.Size() <<
|
||||
", expected size = " << Height() << "!");
|
||||
|
||||
const double *xPtr = x.HostRead();
|
||||
double *yPtr = y.HostReadWrite();
|
||||
|
||||
FactorInternal();
|
||||
solver_->options().set_verbose(solve_verbose_);
|
||||
strumpack::ReturnCode ret = solver_->solve(xPtr, yPtr, false);
|
||||
if (ret != strumpack::ReturnCode::SUCCESS)
|
||||
{
|
||||
#if STRUMPACK_VERSION_MAJOR >= 7
|
||||
MFEM_ABORT("STRUMPACK: Solve failed with return code " << ret << "!");
|
||||
#else
|
||||
MFEM_ABORT("STRUMPACK: Solve failed!");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <typename STRUMPACKSolverType>
|
||||
void STRUMPACKSolverBase<STRUMPACKSolverType>::
|
||||
ArrayMult(const Array<const Vector *> &X, Array<Vector *> &Y) const
|
||||
{
|
||||
MFEM_ASSERT(X.Size() == Y.Size(),
|
||||
"Number of columns mismatch in STRUMPACK solve!");
|
||||
if (X.Size() == 1)
|
||||
{
|
||||
nrhs_ = 1;
|
||||
MFEM_ASSERT(X[0] && Y[0], "Missing Vector in STRUMPACK solve!");
|
||||
Mult(*X[0], *Y[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Multiple RHS case
|
||||
int ldx = Height();
|
||||
if (nrhs_ != X.Size())
|
||||
{
|
||||
rhs_.SetSize(X.Size() * ldx);
|
||||
sol_.SetSize(X.Size() * ldx);
|
||||
nrhs_ = X.Size();
|
||||
}
|
||||
for (int i = 0; i < nrhs_; i++)
|
||||
{
|
||||
MFEM_ASSERT(X[i] && X[i]->Size() == Width(),
|
||||
"STRUMPACK: Missing or invalid sized RHS Vector in solve!");
|
||||
Vector s(rhs_, i * ldx, ldx);
|
||||
s = *X[i];
|
||||
rhs_.SyncMemory(s); // Update flags for rhs_ if updated on device
|
||||
}
|
||||
const double *xPtr = rhs_.HostRead();
|
||||
double *yPtr = sol_.HostReadWrite();
|
||||
|
||||
FactorInternal();
|
||||
solver_->options().set_verbose(solve_verbose_);
|
||||
strumpack::ReturnCode ret = solver_->solve(nrhs_, xPtr, ldx, yPtr, ldx,
|
||||
false);
|
||||
if (ret != strumpack::ReturnCode::SUCCESS)
|
||||
{
|
||||
#if STRUMPACK_VERSION_MAJOR >= 7
|
||||
MFEM_ABORT("STRUMPACK: Solve failed with return code " << ret << "!");
|
||||
#else
|
||||
MFEM_ABORT("STRUMPACK: Solve failed!");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (int i = 0; i < nrhs_; i++)
|
||||
{
|
||||
MFEM_ASSERT(Y[i] && Y[i]->Size() == Width(),
|
||||
"STRUMPACK: Missing or invalid sized solution Vector in solve!");
|
||||
Vector s(sol_, i * ldx, ldx);
|
||||
*Y[i] = s;
|
||||
}
|
||||
}
|
||||
|
||||
STRUMPACKSolver::
|
||||
STRUMPACKSolver(MPI_Comm comm)
|
||||
: STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMPIDist<double, HYPRE_BigInt>>
|
||||
(comm, 0, NULL) {}
|
||||
|
||||
STRUMPACKSolver::
|
||||
STRUMPACKSolver(STRUMPACKRowLocMatrix &A)
|
||||
: STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMPIDist<double, HYPRE_BigInt>>
|
||||
(A, 0, NULL) {}
|
||||
|
||||
STRUMPACKSolver::
|
||||
STRUMPACKSolver(MPI_Comm comm, int argc, char *argv[])
|
||||
: STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMPIDist<double, HYPRE_BigInt>>
|
||||
(comm, argc, argv) {}
|
||||
|
||||
STRUMPACKSolver::
|
||||
STRUMPACKSolver(STRUMPACKRowLocMatrix &A, int argc, char *argv[])
|
||||
: STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMPIDist<double, HYPRE_BigInt>>
|
||||
(A, argc, argv) {}
|
||||
|
||||
#if STRUMPACK_VERSION_MAJOR >= 7
|
||||
STRUMPACKMixedPrecisionSolver::
|
||||
STRUMPACKMixedPrecisionSolver(MPI_Comm comm)
|
||||
: STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMixedPrecisionMPIDist<float, double, HYPRE_BigInt>>
|
||||
(comm, 0, NULL) {}
|
||||
|
||||
STRUMPACKMixedPrecisionSolver::
|
||||
STRUMPACKMixedPrecisionSolver(STRUMPACKRowLocMatrix &A)
|
||||
: STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMixedPrecisionMPIDist<float, double, HYPRE_BigInt>>
|
||||
(A, 0, NULL) {}
|
||||
|
||||
STRUMPACKMixedPrecisionSolver::
|
||||
STRUMPACKMixedPrecisionSolver(MPI_Comm comm, int argc, char *argv[])
|
||||
: STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMixedPrecisionMPIDist<float, double, HYPRE_BigInt>>
|
||||
(comm, argc, argv) {}
|
||||
|
||||
STRUMPACKMixedPrecisionSolver::
|
||||
STRUMPACKMixedPrecisionSolver(STRUMPACKRowLocMatrix &A, int argc, char *argv[])
|
||||
: STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMixedPrecisionMPIDist<float, double, HYPRE_BigInt>>
|
||||
(A, argc, argv) {}
|
||||
#endif
|
||||
|
||||
template class STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMPIDist<double, HYPRE_BigInt>>;
|
||||
#if STRUMPACK_VERSION_MAJOR >= 7
|
||||
template class STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMixedPrecisionMPIDist<float, double, HYPRE_BigInt>>;
|
||||
#endif
|
||||
|
||||
} // mfem namespace
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
+67
-169
@@ -16,14 +16,12 @@
|
||||
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
#include "operator.hpp"
|
||||
#include "hypre.hpp"
|
||||
|
||||
#include <mpi.h>
|
||||
|
||||
// STRUMPACK headers
|
||||
#include "StrumpackSparseSolverMPIDist.hpp"
|
||||
#include "StrumpackSparseSolverMixedPrecisionMPIDist.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -36,80 +34,63 @@ public:
|
||||
be of size (local) nrows by (global) glob_ncols. The new parallel matrix
|
||||
contains copies of all input arrays (so they can be deleted). */
|
||||
STRUMPACKRowLocMatrix(MPI_Comm comm,
|
||||
int num_loc_rows, HYPRE_BigInt first_loc_row,
|
||||
HYPRE_BigInt glob_nrows, HYPRE_BigInt glob_ncols,
|
||||
int *I, HYPRE_BigInt *J, double *data,
|
||||
bool sym_sparse = false);
|
||||
int num_loc_rows, int first_loc_row,
|
||||
int glob_nrows, int glob_ncols,
|
||||
int *I, int *J, double *data);
|
||||
|
||||
/** Creates a copy of the parallel matrix hypParMat in STRUMPACK's RowLoc
|
||||
format. All data is copied so the original matrix may be deleted. */
|
||||
STRUMPACKRowLocMatrix(const Operator &op, bool sym_sparse = false);
|
||||
STRUMPACKRowLocMatrix(const HypreParMatrix & hypParMat);
|
||||
|
||||
~STRUMPACKRowLocMatrix();
|
||||
|
||||
void Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
MFEM_ABORT("STRUMPACKRowLocMatrix::Mult: Matrix vector products are not "
|
||||
"supported!");
|
||||
mfem_error("STRUMPACKRowLocMatrix::Mult(...)\n"
|
||||
" matrix vector products are not supported.");
|
||||
}
|
||||
|
||||
MPI_Comm GetComm() const { return A_->comm(); }
|
||||
MPI_Comm GetComm() const { return comm_; }
|
||||
|
||||
strumpack::CSRMatrixMPI<double, HYPRE_BigInt> *GetA() const { return A_; }
|
||||
strumpack::CSRMatrixMPI<double,int>* getA() const { return A_; }
|
||||
|
||||
private:
|
||||
strumpack::CSRMatrixMPI<double, HYPRE_BigInt> *A_;
|
||||
};
|
||||
MPI_Comm comm_;
|
||||
strumpack::CSRMatrixMPI<double,int>* A_;
|
||||
|
||||
}; // mfem::STRUMPACKRowLocMatrix
|
||||
|
||||
/** The MFEM STRUMPACK Direct Solver class.
|
||||
|
||||
The mfem::STRUMPACKSolver class uses the STRUMPACK library to perform LU
|
||||
factorization of a parallel sparse matrix. The solver is capable of handling
|
||||
double precision types. See
|
||||
http://portal.nersc.gov/project/sparse/strumpack/.
|
||||
double precision types. See http://portal.nersc.gov/project/sparse/strumpack
|
||||
*/
|
||||
template <typename STRUMPACKSolverType>
|
||||
class STRUMPACKSolverBase : public Solver
|
||||
class STRUMPACKSolver : public mfem::Solver
|
||||
{
|
||||
protected:
|
||||
// Constructor with MPI_Comm parameter and command line arguments.
|
||||
STRUMPACKSolverBase(MPI_Comm comm, int argc, char *argv[]);
|
||||
|
||||
// Constructor with STRUMPACK matrix object and command line arguments.
|
||||
STRUMPACKSolverBase(STRUMPACKRowLocMatrix &A, int argc, char *argv[]);
|
||||
|
||||
public:
|
||||
// Constructor with MPI_Comm parameter.
|
||||
STRUMPACKSolver( int argc, char* argv[], MPI_Comm comm );
|
||||
|
||||
// Constructor with STRUMPACK Matrix Object.
|
||||
STRUMPACKSolver( STRUMPACKRowLocMatrix & A);
|
||||
|
||||
// Default destructor.
|
||||
virtual ~STRUMPACKSolverBase();
|
||||
~STRUMPACKSolver( void );
|
||||
|
||||
// Factor and solve the linear system y = Op^{-1} x.
|
||||
void Mult(const Vector &x, Vector &y) const;
|
||||
void ArrayMult(const Array<const Vector *> &X, Array<Vector *> &Y) const;
|
||||
void Mult( const Vector & x, Vector & y ) const;
|
||||
|
||||
// Set the operator.
|
||||
void SetOperator(const Operator &op);
|
||||
void SetOperator( const Operator & op );
|
||||
|
||||
// Set various solver options. Refer to STRUMPACK documentation for
|
||||
// details.
|
||||
void SetFromCommandLine();
|
||||
void SetPrintFactorStatistics(bool print_stat);
|
||||
void SetPrintSolveStatistics(bool print_stat);
|
||||
|
||||
// Set tolerances and iterations for iterative solvers. Compression
|
||||
// tolerance is handled below.
|
||||
void SetRelTol(double rtol);
|
||||
void SetAbsTol(double atol);
|
||||
void SetMaxIter(int max_it);
|
||||
|
||||
// Set the flag controlling reuse of the symbolic factorization for multiple
|
||||
// operators. This method has to be called before repeated calls to
|
||||
// SetOperator.
|
||||
void SetReorderingReuse(bool reuse);
|
||||
|
||||
// Enable or not GPU off-loading available if STRUMPACK was compiled with CUDA. Note
|
||||
// that input/output from MFEM to STRUMPACK is all still through host memory.
|
||||
void EnableGPU();
|
||||
void DisableGPU();
|
||||
void SetFromCommandLine( );
|
||||
void SetPrintFactorStatistics( bool print_stat );
|
||||
void SetPrintSolveStatistics( bool print_stat );
|
||||
void SetRelTol( double rtol );
|
||||
void SetAbsTol( double atol );
|
||||
|
||||
/**
|
||||
* STRUMPACK is an (approximate) direct solver. It can be used as a direct
|
||||
@@ -119,153 +100,70 @@ public:
|
||||
* used without preconditioner.
|
||||
*
|
||||
* Supported values are:
|
||||
* AUTO: Use iterative refinement if no HSS compression is
|
||||
* used, otherwise use GMRes
|
||||
* DIRECT: No outer iterative solver, just a single application
|
||||
* of the multifrontal solver
|
||||
* REFINE: Iterative refinement
|
||||
* PREC_GMRES: Preconditioned GMRes
|
||||
* The preconditioner is the (approx) multifrontal solver
|
||||
* GMRES: UN-preconditioned GMRes (for testing mainly)
|
||||
* PREC_BICGSTAB: Preconditioned BiCGStab
|
||||
* The preconditioner is the (approx) multifrontal solver
|
||||
* AUTO: Use iterative refinement if no HSS compression is used,
|
||||
* otherwise use GMRes.
|
||||
* DIRECT: No outer iterative solver, just a single application of
|
||||
* the multifrontal solver.
|
||||
* REFINE: Iterative refinement.
|
||||
* PREC_GMRES: Preconditioned GMRes.
|
||||
* The preconditioner is the (approx) multifrontal solver.
|
||||
* GMRES: UN-preconditioned GMRes. (for testing mainly)
|
||||
* PREC_BICGSTAB: Preconditioned BiCGStab.
|
||||
* The preconditioner is the (approx) multifrontal solver.
|
||||
* BICGSTAB: UN-preconditioned BiCGStab. (for testing mainly)
|
||||
*/
|
||||
void SetKrylovSolver(strumpack::KrylovSolver method);
|
||||
void SetKrylovSolver( strumpack::KrylovSolver method );
|
||||
|
||||
/**
|
||||
* Supported reorderings are:
|
||||
* NATURAL: Do not reorder the system
|
||||
* METIS: Use Metis nested-dissection reordering (default)
|
||||
* PARMETIS: Use ParMetis nested-dissection reordering
|
||||
* SCOTCH: Use Scotch nested-dissection reordering
|
||||
* PTSCOTCH: Use PT-Scotch nested-dissection reordering
|
||||
* RCM: Use RCM reordering
|
||||
* GEOMETRIC: A simple geometric nested dissection code that
|
||||
* only works for regular meshes
|
||||
* AMD: Approximate minimum degree
|
||||
* MMD: Multiple minimum degree
|
||||
* AND: Nested dissection
|
||||
* MLF: Minimum local fill
|
||||
* SPECTRAL: Spectral nested dissection
|
||||
* METIS, PARMETIS, SCOTCH, PTSCOTCH, RCM
|
||||
*/
|
||||
void SetReorderingStrategy(strumpack::ReorderingStrategy method);
|
||||
void SetReorderingStrategy( strumpack::ReorderingStrategy method );
|
||||
|
||||
/**
|
||||
* Configure static pivoting for stability. The static pivoting in STRUMPACK
|
||||
* Disable static pivoting for stability. The static pivoting in strumpack
|
||||
* permutes the sparse input matrix in order to get large (nonzero) elements
|
||||
* on the diagonal. If the input matrix is already diagonally dominant, this
|
||||
* reordering can be disabled.
|
||||
*
|
||||
* Supported matching algorithms are:
|
||||
* NONE: Don't do anything
|
||||
* MAX_CARDINALITY: Maximum cardinality
|
||||
* MAX_SMALLEST_DIAGONAL: Maximum smallest diagonal value
|
||||
* MAX_SMALLEST_DIAGONAL_2: Same as MAX_SMALLEST_DIAGONAL
|
||||
* but different algorithm
|
||||
* MAX_DIAGONAL_SUM: Maximum sum of diagonal values
|
||||
* MAX_DIAGONAL_PRODUCT_SCALING: Maximum product of diagonal values
|
||||
* and row and column scaling (default)
|
||||
* COMBBLAS: Use AWPM from CombBLAS (only with
|
||||
* version >= 3)
|
||||
*/
|
||||
void SetMatching(strumpack::MatchingJob job);
|
||||
void DisableMatching();
|
||||
|
||||
/**
|
||||
* Enable support for rank-structured data formats, which can be used
|
||||
* for compression within the sparse solver.
|
||||
*
|
||||
* Supported compression types are:
|
||||
* NONE: No compression, purely direct solver (default)
|
||||
* HSS: HSS compression of frontal matrices
|
||||
* BLR: Block low-rank compression of fronts
|
||||
* HODLR: Hierarchically Off-diagonal Low-Rank
|
||||
* compression of frontal matrices
|
||||
* BLR_HODLR: Block low-rank compression of medium
|
||||
* fronts and Hierarchically Off-diagonal
|
||||
* Low-Rank compression of large fronts
|
||||
* ZFP_BLR_HODLR: ZFP compression for small fronts,
|
||||
* Block low-rank compression of medium
|
||||
* fronts and Hierarchically Off-diagonal
|
||||
* Low-Rank compression of large fronts
|
||||
* LOSSLESS: Lossless compression
|
||||
* LOSSY: Lossy compression
|
||||
*
|
||||
* For versions of STRUMPACK < 5, we support only NONE, HSS, and BLR.
|
||||
* BLR_HODLR and ZPR_BLR_HODLR are supported in STRUMPACK >= 6.
|
||||
* Enable static pivoting for stability using the MC64 algorithm with
|
||||
* job=5. Using a matching algorithm, this will permute the sparse input
|
||||
* matrix in order to get nonzero elements (as large as possible) on the
|
||||
* diagonal. And will also scale the rows and columns of the matrix.
|
||||
*/
|
||||
void SetCompression(strumpack::CompressionType type);
|
||||
void SetCompressionRelTol(double rtol);
|
||||
void SetCompressionAbsTol(double atol);
|
||||
#if STRUMPACK_VERSION_MAJOR >= 5
|
||||
void SetCompressionLossyPrecision(int precision);
|
||||
void SetCompressionButterflyLevels(int levels);
|
||||
void EnableMatching();
|
||||
|
||||
#if STRUMPACK_VERSION_MAJOR >= 3
|
||||
/**
|
||||
* Use the AWPM (approximate weight perfect matching) algorithm from the
|
||||
* Combinatorial BLAS library for static pivoting, i.e. getting large
|
||||
* nonzeros on the diagonal. This requires that strumpack was compiled with
|
||||
* support for Combinatorial BLAS.
|
||||
*/
|
||||
void EnableParallelMatching();
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Helper method for calling the STRUMPACK factoriation routine.
|
||||
void FactorInternal() const;
|
||||
void Init( int argc, char* argv[] );
|
||||
|
||||
protected:
|
||||
const STRUMPACKRowLocMatrix *APtr_;
|
||||
STRUMPACKSolverType *solver_;
|
||||
|
||||
MPI_Comm comm_;
|
||||
int numProcs_;
|
||||
int myid_;
|
||||
|
||||
bool factor_verbose_;
|
||||
bool solve_verbose_;
|
||||
bool reorder_reuse_;
|
||||
|
||||
mutable Vector rhs_, sol_;
|
||||
mutable int nrhs_;
|
||||
};
|
||||
const STRUMPACKRowLocMatrix * APtr_;
|
||||
strumpack::StrumpackSparseSolverMPIDist<double,int> * solver_;
|
||||
|
||||
class STRUMPACKSolver :
|
||||
public STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMPIDist<double, HYPRE_BigInt>>
|
||||
{
|
||||
public:
|
||||
// Constructor with MPI_Comm parameter.
|
||||
STRUMPACKSolver(MPI_Comm comm);
|
||||
}; // mfem::STRUMPACKSolver class
|
||||
|
||||
// Constructor with STRUMPACK matrix object.
|
||||
STRUMPACKSolver(STRUMPACKRowLocMatrix &A);
|
||||
|
||||
// Constructor with MPI_Comm parameter and command line arguments.
|
||||
STRUMPACKSolver(MPI_Comm comm, int argc, char *argv[]);
|
||||
MFEM_DEPRECATED STRUMPACKSolver(int argc, char *argv[], MPI_Comm comm)
|
||||
: STRUMPACKSolver(comm, argc, argv) {}
|
||||
|
||||
// Constructor with STRUMPACK matrix object and command line arguments.
|
||||
STRUMPACKSolver(STRUMPACKRowLocMatrix &A, int argc, char *argv[]);
|
||||
|
||||
// Destructor.
|
||||
~STRUMPACKSolver() {}
|
||||
};
|
||||
|
||||
#if STRUMPACK_VERSION_MAJOR >= 7
|
||||
class STRUMPACKMixedPrecisionSolver :
|
||||
public STRUMPACKSolverBase<strumpack::
|
||||
SparseSolverMixedPrecisionMPIDist<float, double, HYPRE_BigInt>>
|
||||
{
|
||||
public:
|
||||
// Constructor with MPI_Comm parameter.
|
||||
STRUMPACKMixedPrecisionSolver(MPI_Comm comm);
|
||||
|
||||
// Constructor with STRUMPACK matrix object.
|
||||
STRUMPACKMixedPrecisionSolver(STRUMPACKRowLocMatrix &A);
|
||||
|
||||
// Constructor with MPI_Comm parameter and command line arguments.
|
||||
STRUMPACKMixedPrecisionSolver(MPI_Comm comm, int argc, char *argv[]);
|
||||
|
||||
// Constructor with STRUMPACK matrix object and command line arguments.
|
||||
STRUMPACKMixedPrecisionSolver(STRUMPACKRowLocMatrix &A,
|
||||
int argc, char *argv[]);
|
||||
|
||||
// Destructor.
|
||||
~STRUMPACKMixedPrecisionSolver() {}
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace mfem
|
||||
} // mfem namespace
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
#endif // MFEM_USE_STRUMPACK
|
||||
|
||||
@@ -650,7 +650,6 @@ void SuperLUSolver::ArrayMult(const Array<const Vector *> &X,
|
||||
MFEM_ASSERT(X[i], "Missing Vector in SuperLUSolver::Mult!");
|
||||
Vector s(sol_, i * ldx, ldx);
|
||||
s = *X[i];
|
||||
sol_.SyncMemory(s); // Update flags for sol_ if updated on device
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+142
-559
File diff suppressed because it is too large
Load Diff
+70
-184
@@ -27,11 +27,12 @@
|
||||
#include "../general/adios2stream.hpp"
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// Data type mesh
|
||||
|
||||
class GeometricFactors;
|
||||
class FaceGeometricFactors;
|
||||
class KnotVector;
|
||||
@@ -48,15 +49,15 @@ class ParMesh;
|
||||
class ParNCMesh;
|
||||
#endif
|
||||
|
||||
/// Mesh data type
|
||||
class Mesh
|
||||
{
|
||||
friend class NCMesh;
|
||||
friend class NURBSExtension;
|
||||
#ifdef MFEM_USE_MPI
|
||||
friend class ParMesh;
|
||||
friend class ParNCMesh;
|
||||
#endif
|
||||
friend class NCMesh;
|
||||
friend class NURBSExtension;
|
||||
|
||||
#ifdef MFEM_USE_ADIOS2
|
||||
friend class adios2stream;
|
||||
#endif
|
||||
@@ -219,9 +220,9 @@ protected:
|
||||
Table *el_to_edge;
|
||||
Table *el_to_face;
|
||||
Table *el_to_el;
|
||||
Array<int> be_to_face; // faces = vertices (1D), edges (2D), faces (3D)
|
||||
|
||||
Table *bel_to_edge; // for 3D only
|
||||
Array<int> be_to_edge; // for 2D
|
||||
Table *bel_to_edge; // for 3D
|
||||
Array<int> be_to_face;
|
||||
|
||||
// Note that the following tables are owned by this class and should not be
|
||||
// deleted by the caller. Of these three tables, only face_edge and
|
||||
@@ -324,8 +325,35 @@ protected:
|
||||
|
||||
/* Note NetCDF (optional library) is used for reading cubit files */
|
||||
#ifdef MFEM_USE_NETCDF
|
||||
|
||||
/// @brief Load a mesh from a Genesis file.
|
||||
void ReadCubit(const std::string &filename, int &curved, int &read_gf);
|
||||
void ReadCubit(const char *filename, int &curved, int &read_gf);
|
||||
|
||||
/// @brief The final step in constructing the mesh from a Genesis file. This
|
||||
/// is only called if the mesh order == 2 (determined internally from the
|
||||
/// cubit element type).
|
||||
void FinalizeCubitSecondOrderMesh(const int cubit_element_type,
|
||||
const int num_element_blocks,
|
||||
const int num_nodes_per_element,
|
||||
const int *start_of_block,
|
||||
const double *coordx,
|
||||
const double *coordy,
|
||||
const double *coordz,
|
||||
const int **element_blocks);
|
||||
|
||||
/// @brief Returns a pointer to a new mfem::Element based on the provided
|
||||
/// cubit element type. This is used internally to create the mesh elements
|
||||
/// from a Genesis file.
|
||||
Element *CreateCubitElement(const int cubit_element_type,
|
||||
const int *vertex_ids,
|
||||
const int block_id);
|
||||
|
||||
/// @brief Returns a pointer to a new mfem::Element based on the provided
|
||||
/// cubit face type. This is used internally to create the boundary elements
|
||||
/// from a Genesis file.
|
||||
Element *CreateCubitBoundaryElement(const int cubit_face_type,
|
||||
const int *vertex_ids,
|
||||
const int sideset_id) const;
|
||||
#endif
|
||||
|
||||
/// Determine the mesh generator bitmask #meshgen, see MeshGenerator().
|
||||
@@ -337,8 +365,8 @@ protected:
|
||||
|
||||
void MarkForRefinement();
|
||||
void MarkTriMeshForRefinement();
|
||||
void GetEdgeOrdering(const DSTable &v_to_v, Array<int> &order);
|
||||
virtual void MarkTetMeshForRefinement(const DSTable &v_to_v);
|
||||
void GetEdgeOrdering(DSTable &v_to_v, Array<int> &order);
|
||||
virtual void MarkTetMeshForRefinement(DSTable &v_to_v);
|
||||
|
||||
// Methods used to prepare and apply permutation of the mesh nodes assuming
|
||||
// that the mesh elements may be rotated (e.g. to mark triangle or tet edges
|
||||
@@ -505,7 +533,7 @@ protected:
|
||||
nodes in the elements. For example, if T is the element to edge table
|
||||
T(i, 0) gives the index of edge in element i that connects vertex 0
|
||||
to vertex 1, etc. Returns the number of the edges. */
|
||||
int GetElementToEdgeTable(Table &);
|
||||
int GetElementToEdgeTable(Table &, Array<int> &);
|
||||
|
||||
/// Used in GenerateFaces()
|
||||
void AddPointFaceElement(int lf, int gf, int el);
|
||||
@@ -545,55 +573,24 @@ protected:
|
||||
void Printer(std::ostream &out = mfem::out,
|
||||
std::string section_delimiter = "") const;
|
||||
|
||||
/// @brief Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz],
|
||||
/// divided into nx*ny*nz hexahedra if @a type = HEXAHEDRON or into
|
||||
/// 6*nx*ny*nz tetrahedrons if @a type = TETRAHEDRON.
|
||||
///
|
||||
/// The parameter @a sfc_ordering controls how the elements
|
||||
/// (when @a type = HEXAHEDRON) are ordered: true - use space-filling curve
|
||||
/// ordering, or false - use lexicographic ordering.
|
||||
/** Creates mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into
|
||||
nx*ny*nz hexahedra if type=HEXAHEDRON or into 6*nx*ny*nz tetrahedrons if
|
||||
type=TETRAHEDRON. The parameter @a sfc_ordering controls how the elements
|
||||
(when type=HEXAHEDRON) are ordered: true - use space-filling curve
|
||||
ordering, or false - use lexicographic ordering. */
|
||||
void Make3D(int nx, int ny, int nz, Element::Type type,
|
||||
double sx, double sy, double sz, bool sfc_ordering);
|
||||
|
||||
/// @brief Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz],
|
||||
/// divided into nx*ny*nz*24 tetrahedrons.
|
||||
///
|
||||
/// The mesh is generated by taking nx*ny*nz hexahedra and splitting each
|
||||
/// hexahedron into 24 tetrahedrons. Each face of the hexahedron is split
|
||||
/// into 4 triangles (face edges are connected to a face-centered point),
|
||||
/// and the triangles are connected to a hex-centered point.
|
||||
void Make3D24TetsFromHex(int nx, int ny, int nz,
|
||||
double sx, double sy, double sz);
|
||||
|
||||
/// @brief Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny*4
|
||||
/// triangles.
|
||||
///
|
||||
/// The mesh is generated by taking nx*ny quadrilaterals and splitting each
|
||||
/// quadrilateral into 4 triangles by connecting the vertices to a
|
||||
/// quad-centered point.
|
||||
void Make2D4TrisFromQuad(int nx, int ny, double sx, double sy);
|
||||
|
||||
/// @brief Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny*5
|
||||
/// quadrilaterals.
|
||||
///
|
||||
/// The mesh is generated by taking nx*ny quadrilaterals and splitting
|
||||
/// each quadrilateral into 5 quadrilaterals. Each quadrilateral is projected
|
||||
/// inwards and connected to the original quadrilateral.
|
||||
void Make2D5QuadsFromQuad(int nx, int ny, double sx, double sy);
|
||||
|
||||
/// @brief Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny
|
||||
/// quadrilaterals if @a type = QUADRILATERAL or into 2*nx*ny triangles if
|
||||
/// @a type = TRIANGLE.
|
||||
///
|
||||
/// If generate_edges = 0 (default) edges are not generated, if 1 edges are
|
||||
/// generated. The parameter @a sfc_ordering controls how the elements (when
|
||||
/// @a type = QUADRILATERAL) are ordered: true - use space-filling curve
|
||||
/// ordering, or false - use lexicographic ordering.
|
||||
/** Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny
|
||||
quadrilaterals if type = QUADRILATERAL or into 2*nx*ny triangles if
|
||||
type = TRIANGLE. If generate_edges = 0 (default) edges are not generated,
|
||||
if 1 edges are generated. The parameter @a sfc_ordering controls how the
|
||||
elements (when type=QUADRILATERAL) are ordered: true - use space-filling
|
||||
curve ordering, or false - use lexicographic ordering. */
|
||||
void Make2D(int nx, int ny, Element::Type type, double sx, double sy,
|
||||
bool generate_edges, bool sfc_ordering);
|
||||
|
||||
/// @a brief Creates a 1D mesh for the interval [0,sx] divided into n equal
|
||||
/// intervals.
|
||||
/// Creates a 1D mesh for the interval [0,sx] divided into n equal intervals.
|
||||
void Make1D(int n, double sx = 1.0);
|
||||
|
||||
/// Internal function used in Mesh::MakeRefined
|
||||
@@ -733,63 +730,27 @@ public:
|
||||
int generate_edges = 0, int refine = 1,
|
||||
bool fix_orientation = true);
|
||||
|
||||
/// Creates 1D mesh , divided into n equal intervals.
|
||||
/** Creates 1D mesh , divided into n equal intervals. */
|
||||
static Mesh MakeCartesian1D(int n, double sx = 1.0);
|
||||
|
||||
/// @brief Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny
|
||||
/// quadrilaterals if @a type = QUADRILATERAL or into 2*nx*ny triangles if
|
||||
/// @a type = TRIANGLE.
|
||||
///
|
||||
/// If generate_edges = 0 (default) edges are not generated, if 1 edges are
|
||||
/// generated. The parameter @a sfc_ordering controls how the elements (when
|
||||
/// @a type = QUADRILATERAL) are ordered: true - use space-filling curve
|
||||
/// ordering, or false - use lexicographic ordering.
|
||||
/** Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny
|
||||
quadrilaterals if type = QUADRILATERAL or into 2*nx*ny triangles if
|
||||
type = TRIANGLE. If generate_edges = 0 (default) edges are not generated,
|
||||
if 1 edges are generated. If scf_ordering = true (default), elements are
|
||||
ordered along a space-filling curve, instead of row by row. */
|
||||
static Mesh MakeCartesian2D(
|
||||
int nx, int ny, Element::Type type, bool generate_edges = false,
|
||||
double sx = 1.0, double sy = 1.0, bool sfc_ordering = true);
|
||||
|
||||
/// @brief Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz],
|
||||
/// divided into nx*ny*nz hexahedra if @a type = HEXAHEDRON or into
|
||||
/// 6*nx*ny*nz tetrahedrons if @a type = TETRAHEDRON.
|
||||
///
|
||||
/// The parameter @a sfc_ordering controls how the elements
|
||||
/// (when @a type = HEXAHEDRON) are ordered: true - use space-filling curve
|
||||
/// ordering, or false - use lexicographic ordering.
|
||||
/** Creates mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into
|
||||
nx*ny*nz hexahedra if type=HEXAHEDRON or into 6*nx*ny*nz tetrahedrons if
|
||||
type=TETRAHEDRON. If sfc_ordering = true (default), elements are ordered
|
||||
along a space-filling curve, instead of row by row and layer by layer. */
|
||||
static Mesh MakeCartesian3D(
|
||||
int nx, int ny, int nz, Element::Type type,
|
||||
double sx = 1.0, double sy = 1.0, double sz = 1.0,
|
||||
bool sfc_ordering = true);
|
||||
|
||||
/// @brief Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz],
|
||||
/// divided into nx*ny*nz*24 tetrahedrons.
|
||||
///
|
||||
/// The mesh is generated by taking nx*ny*nz hexahedra and splitting each
|
||||
/// hexahedron into 24 tetrahedrons. Each face of the hexahedron is split
|
||||
/// into 4 triangles (face edges are connected to a face-centered point),
|
||||
/// and the triangles are connected to a hex-centered point.
|
||||
static Mesh MakeCartesian3DWith24TetsPerHex(int nx, int ny, int nz,
|
||||
double sx = 1.0, double sy = 1.0,
|
||||
double sz = 1.0);
|
||||
|
||||
/// @brief Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny*4
|
||||
/// triangles.
|
||||
///
|
||||
/// The mesh is generated by taking nx*ny quadrilaterals and splitting each
|
||||
/// quadrilateral into 4 triangles by connecting the vertices to a
|
||||
/// quad-centered point.
|
||||
static Mesh MakeCartesian2DWith4TrisPerQuad(int nx, int ny, double sx = 1.0,
|
||||
double sy = 1.0);
|
||||
|
||||
/// @brief Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny*5
|
||||
/// quadrilaterals.
|
||||
///
|
||||
/// The mesh is generated by taking nx*ny quadrilaterals and splitting
|
||||
/// each quadrilateral into 5 quadrilaterals. Each quadrilateral is projected
|
||||
/// inwards and connected to the original quadrilateral.
|
||||
static Mesh MakeCartesian2DWith5QuadsPerQuad(int nx, int ny, double sx = 1.0,
|
||||
double sy = 1.0);
|
||||
|
||||
|
||||
/// Create a refined (by any factor) version of @a orig_mesh.
|
||||
/** @param[in] orig_mesh The starting coarse mesh.
|
||||
@param[in] ref_factor The refinement factor, an integer > 1.
|
||||
@@ -857,82 +818,33 @@ public:
|
||||
int AddVertex(const Vector &coords);
|
||||
/// Mark vertex @a i as nonconforming, with parent vertices @a p1 and @a p2.
|
||||
void AddVertexParents(int i, int p1, int p2);
|
||||
/// Adds a vertex at the mean center of the @a nverts vertex indices given
|
||||
/// by @a vi.
|
||||
int AddVertexAtMeanCenter(const int *vi, const int nverts, int dim = 3);
|
||||
|
||||
/// Adds a segment to the mesh given by 2 vertices @a v1 and @a v2.
|
||||
int AddSegment(int v1, int v2, int attr = 1);
|
||||
/// Adds a segment to the mesh given by 2 vertices @a vi.
|
||||
int AddSegment(const int *vi, int attr = 1);
|
||||
|
||||
/// Adds a triangle to the mesh given by 3 vertices @a v1 through @a v3.
|
||||
int AddTriangle(int v1, int v2, int v3, int attr = 1);
|
||||
/// Adds a triangle to the mesh given by 3 vertices @a vi.
|
||||
int AddTriangle(const int *vi, int attr = 1);
|
||||
/// Adds a triangle to the mesh given by 3 vertices @a vi.
|
||||
int AddTri(const int *vi, int attr = 1) { return AddTriangle(vi, attr); }
|
||||
|
||||
/// Adds a quadrilateral to the mesh given by 4 vertices @a v1 through @a v4.
|
||||
int AddQuad(int v1, int v2, int v3, int v4, int attr = 1);
|
||||
/// Adds a quadrilateral to the mesh given by 4 vertices @a vi.
|
||||
int AddQuad(const int *vi, int attr = 1);
|
||||
|
||||
/// Adds a tetrahedron to the mesh given by 4 vertices @a v1 through @a v4.
|
||||
int AddTet(int v1, int v2, int v3, int v4, int attr = 1);
|
||||
/// Adds a tetrahedron to the mesh given by 4 vertices @a vi.
|
||||
int AddTet(const int *vi, int attr = 1);
|
||||
|
||||
/// Adds a wedge to the mesh given by 6 vertices @a v1 through @a v6.
|
||||
int AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr = 1);
|
||||
/// Adds a wedge to the mesh given by 6 vertices @a vi.
|
||||
int AddWedge(const int *vi, int attr = 1);
|
||||
|
||||
/// Adds a pyramid to the mesh given by 5 vertices @a v1 through @a v5.
|
||||
int AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr = 1);
|
||||
/// Adds a pyramid to the mesh given by 5 vertices @a vi.
|
||||
int AddPyramid(const int *vi, int attr = 1);
|
||||
|
||||
/// Adds a hexahedron to the mesh given by 8 vertices @a v1 through @a v8.
|
||||
int AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
|
||||
int attr = 1);
|
||||
/// Adds a hexahedron to the mesh given by 8 vertices @a vi.
|
||||
int AddHex(const int *vi, int attr = 1);
|
||||
/// @brief Adds 6 tetrahedrons to the mesh by splitting a hexahedron given by
|
||||
/// 8 vertices @a vi.
|
||||
void AddHexAsTets(const int *vi, int attr = 1);
|
||||
/// @brief Adds 2 wedges to the mesh by splitting a hexahedron given by
|
||||
/// 8 vertices @a vi.
|
||||
void AddHexAsWedges(const int *vi, int attr = 1);
|
||||
/// @brief Adds 6 pyramids to the mesh by splitting a hexahedron given by
|
||||
/// 8 vertices @a vi.
|
||||
void AddHexAsPyramids(const int *vi, int attr = 1);
|
||||
|
||||
/// @brief Adds 24 tetrahedrons to the mesh by splitting a hexahedron.
|
||||
///
|
||||
/// @a vi are the 8 vertices of the hexahedron, @a hex_face_verts has the
|
||||
/// map from the 4 vertices of each face of the hexahedron to the index
|
||||
/// of the point created at the center of the face, and @a attr is the
|
||||
/// attribute of the new elements. See @a Make3D24TetsFromHex for usage.
|
||||
void AddHexAs24TetsWithPoints(int *vi,
|
||||
std::map<std::array<int, 4>, int>
|
||||
&hex_face_verts,
|
||||
int attr = 1);
|
||||
|
||||
/// @brief Adds 4 triangles to the mesh by splitting a quadrilateral given by
|
||||
/// 4 vertices @a vi.
|
||||
///
|
||||
/// @a attr is the attribute of the new elements. See @a Make2D4TrisFromQuad
|
||||
/// for usage.
|
||||
void AddQuadAs4TrisWithPoints(int *vi, int attr = 1);
|
||||
|
||||
/// @brief Adds 5 quadrilaterals to the mesh by splitting a quadrilateral
|
||||
/// given by 4 vertices @a vi.
|
||||
///
|
||||
/// @a attr is the attribute of the new elements. See @a Make2D5QuadsFromQuad
|
||||
/// for usage.
|
||||
void AddQuadAs5QuadsWithPoints(int *vi, int attr = 1);
|
||||
|
||||
/// The parameter @a elem should be allocated using the NewElement() method
|
||||
/// @note Ownership of @a elem will pass to the Mesh object
|
||||
int AddElement(Element *elem);
|
||||
@@ -1455,6 +1367,11 @@ public:
|
||||
GetElementEdges/GetBdrElementEdges. */
|
||||
void GetBdrElementFace(int i, int *f, int *o) const;
|
||||
|
||||
/** Return the vertex index of boundary element i. (1D)
|
||||
Return the edge index of boundary element i. (2D)
|
||||
Return the face index of boundary element i. (3D) */
|
||||
int GetBdrElementEdgeIndex(int i) const;
|
||||
|
||||
/** @brief For the given boundary element, bdr_el, return its adjacent
|
||||
element and its info, i.e. 64*local_bdr_index+bdr_orientation.
|
||||
|
||||
@@ -1464,40 +1381,19 @@ public:
|
||||
@sa GetBdrElementAdjacentElement2() */
|
||||
void GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const;
|
||||
|
||||
/** @brief Deprecated.
|
||||
|
||||
For the given boundary element, bdr_el, return its adjacent element and
|
||||
its info, i.e. 64*local_bdr_index+inverse_bdr_orientation.
|
||||
/** @brief For the given boundary element, bdr_el, return its adjacent
|
||||
element and its info, i.e. 64*local_bdr_index+inverse_bdr_orientation.
|
||||
|
||||
The returned inverse_bdr_orientation is the inverse of the orientation of
|
||||
the boundary element relative to the respective face element. In other
|
||||
words this is the orientation of the face element relative to the
|
||||
boundary element.
|
||||
|
||||
@warning This only differs from GetBdrElementAdjacentElement by returning
|
||||
the face info with inverted orientation. It does @b not return
|
||||
information corresponding to a second adjacent face. This function is
|
||||
deprecated, use Geometry::GetInverseOrientation, Mesh::EncodeFaceInfo,
|
||||
Mesh::DecodeFaceInfoOrientaiton, and Mesh::DecodeFaceInfoLocalIndex
|
||||
instead.
|
||||
|
||||
@sa GetBdrElementAdjacentElement() */
|
||||
MFEM_DEPRECATED
|
||||
void GetBdrElementAdjacentElement2(int bdr_el, int &el, int &info) const;
|
||||
|
||||
/// @brief Return the local face (codimension-1) index for the given boundary
|
||||
/// element index.
|
||||
int GetBdrElementFaceIndex(int be_idx) const { return be_to_face[be_idx]; }
|
||||
|
||||
/// Deprecated in favor of GetBdrElementFaceIndex().
|
||||
MFEM_DEPRECATED int GetBdrFace(int i) const { return GetBdrElementFaceIndex(i); }
|
||||
|
||||
/** Return the vertex index of boundary element i. (1D)
|
||||
Return the edge index of boundary element i. (2D)
|
||||
Return the face index of boundary element i. (3D)
|
||||
|
||||
Deprecated in favor of GetBdrElementFaceIndex(). */
|
||||
MFEM_DEPRECATED int GetBdrElementEdgeIndex(int i) const { return GetBdrElementFaceIndex(i); }
|
||||
/// Return the local face index for the given boundary face.
|
||||
int GetBdrFace(int BdrElemNo) const;
|
||||
|
||||
/// @}
|
||||
|
||||
@@ -1896,16 +1792,6 @@ public:
|
||||
operator Mesh::FaceInfo() const;
|
||||
};
|
||||
|
||||
/// Given a "face info int", return the face orientation. @sa FaceInfo.
|
||||
static int DecodeFaceInfoOrientaiton(int info) { return info%64; }
|
||||
|
||||
/// Given a "face info int", return the local face index. @sa FaceInfo.
|
||||
static int DecodeFaceInfoLocalIndex(int info) { return info/64; }
|
||||
|
||||
/// @brief Given @a local_face_index and @a orientation, return the
|
||||
/// corresponding encoded "face info int". @sa FaceInfo.
|
||||
static int EncodeFaceInfo(int local_face_index, int orientation) { return orientation + local_face_index*64; }
|
||||
|
||||
/// @name More advanced entity information access methods
|
||||
/// @{
|
||||
|
||||
|
||||
+265
-203
@@ -3037,9 +3037,9 @@ static void ReadCubitDimensions(const int netcdf_descriptor,
|
||||
|
||||
static void ReadCubitBoundaries(const int netcdf_descriptor,
|
||||
const int num_boundaries,
|
||||
vector<size_t> &num_boundary_elements,
|
||||
vector<vector<int>> &boundary_elements,
|
||||
vector<vector<int>> &boundary_sides)
|
||||
std::vector<size_t> &num_boundary_elements,
|
||||
int **boundary_elements,
|
||||
int **boundary_sides)
|
||||
{
|
||||
int netcdf_status, variable_id;
|
||||
|
||||
@@ -3062,15 +3062,15 @@ static void ReadCubitBoundaries(const int netcdf_descriptor,
|
||||
num_boundary_elements[iboundary] = num_sides;
|
||||
|
||||
// 2. Extract elements and sides on each boundary.
|
||||
boundary_elements[iboundary].resize(num_sides); // (element, face) pairs.
|
||||
boundary_sides[iboundary].resize(num_sides);
|
||||
boundary_elements[iboundary] = new int[num_sides]; // (element, face) pairs.
|
||||
boundary_sides[iboundary] = new int[num_sides];
|
||||
|
||||
//
|
||||
snprintf(string_buffer, buffer_size, "elem_ss%d", iboundary + 1);
|
||||
|
||||
netcdf_status = nc_inq_varid(netcdf_descriptor, string_buffer, &variable_id);
|
||||
netcdf_status = nc_get_var_int(netcdf_descriptor, variable_id,
|
||||
boundary_elements[iboundary].data());
|
||||
boundary_elements[iboundary]);
|
||||
|
||||
if (netcdf_status != NC_NOERR) { break; }
|
||||
|
||||
@@ -3079,7 +3079,7 @@ static void ReadCubitBoundaries(const int netcdf_descriptor,
|
||||
|
||||
netcdf_status = nc_inq_varid(netcdf_descriptor, string_buffer, &variable_id);
|
||||
netcdf_status = nc_get_var_int(netcdf_descriptor, variable_id,
|
||||
boundary_sides[iboundary].data());
|
||||
boundary_sides[iboundary]);
|
||||
|
||||
if (netcdf_status != NC_NOERR) { break; }
|
||||
}
|
||||
@@ -3090,8 +3090,7 @@ static void ReadCubitBoundaries(const int netcdf_descriptor,
|
||||
|
||||
static void ReadCubitElementBlocks(const int netcdf_descriptor,
|
||||
const int num_element_blocks, const int num_nodes_per_element,
|
||||
const vector<size_t> &num_elements_for_block,
|
||||
vector<vector<int>> &block_elements)
|
||||
const std::vector<std::size_t> & num_elements_for_block, int **block_elements)
|
||||
{
|
||||
int netcdf_status, variable_id;
|
||||
|
||||
@@ -3100,8 +3099,8 @@ static void ReadCubitElementBlocks(const int netcdf_descriptor,
|
||||
|
||||
for (int iblock = 0; iblock < num_element_blocks; iblock++)
|
||||
{
|
||||
block_elements[iblock].resize(
|
||||
num_elements_for_block[iblock]*num_nodes_per_element);
|
||||
block_elements[iblock] = new int[num_elements_for_block[iblock] *
|
||||
num_nodes_per_element];
|
||||
|
||||
// Write variable name to buffer.
|
||||
snprintf(string_buffer, buffer_size, "connect%d", iblock + 1);
|
||||
@@ -3109,7 +3108,7 @@ static void ReadCubitElementBlocks(const int netcdf_descriptor,
|
||||
// Get variable ID and then set all nodes of element in block.
|
||||
netcdf_status = nc_inq_varid(netcdf_descriptor, string_buffer, &variable_id);
|
||||
netcdf_status = nc_get_var_int(netcdf_descriptor, variable_id,
|
||||
block_elements[iblock].data());
|
||||
block_elements[iblock]);
|
||||
|
||||
if (netcdf_status != NC_NOERR) { break; }
|
||||
}
|
||||
@@ -3340,147 +3339,10 @@ static int GetCubitBlockIndexForElement(const int global_element_index,
|
||||
return iblock;
|
||||
}
|
||||
|
||||
mfem::Element *NewElement(Mesh &mesh, Geometry::Type geom, const int *vertices,
|
||||
const int attribute)
|
||||
{
|
||||
Element *new_element = mesh.NewElement(geom);
|
||||
new_element->SetVertices(vertices);
|
||||
new_element->SetAttribute(attribute);
|
||||
return new_element;
|
||||
}
|
||||
|
||||
/// @brief Returns a pointer to a new mfem::Element based on the provided cubit
|
||||
/// element type. This is used to create the mesh elements from a Genesis file.
|
||||
mfem::Element *CreateCubitElement(Mesh &mesh,
|
||||
const int cubit_element_type,
|
||||
const int *vertex_ids,
|
||||
const int block_id)
|
||||
{
|
||||
switch (cubit_element_type)
|
||||
{
|
||||
case ELEMENT_TRI3:
|
||||
case ELEMENT_TRI6:
|
||||
return NewElement(mesh, Geometry::TRIANGLE, vertex_ids, block_id);
|
||||
case ELEMENT_QUAD4:
|
||||
case ELEMENT_QUAD9:
|
||||
return NewElement(mesh, Geometry::SQUARE, vertex_ids, block_id);
|
||||
case ELEMENT_TET4:
|
||||
case ELEMENT_TET10:
|
||||
return NewElement(mesh, Geometry::TETRAHEDRON, vertex_ids, block_id);
|
||||
case ELEMENT_HEX8:
|
||||
case ELEMENT_HEX27:
|
||||
return NewElement(mesh, Geometry::CUBE, vertex_ids, block_id);
|
||||
default:
|
||||
MFEM_ABORT("Unsupported cubit element type encountered.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Returns a pointer to a new mfem::Element based on the provided cubit
|
||||
/// face type. This is used to create the boundary elements from a Genesis file.
|
||||
mfem::Element *CreateCubitBoundaryElement(Mesh &mesh,
|
||||
const int cubit_face_type,
|
||||
const int *vertex_ids,
|
||||
const int sideset_id)
|
||||
{
|
||||
switch (cubit_face_type)
|
||||
{
|
||||
case FACE_EDGE2:
|
||||
case FACE_EDGE3:
|
||||
return NewElement(mesh, Geometry::SEGMENT, vertex_ids, sideset_id);
|
||||
case FACE_TRI3:
|
||||
case FACE_TRI6:
|
||||
return NewElement(mesh, Geometry::TRIANGLE, vertex_ids, sideset_id);
|
||||
case FACE_QUAD4:
|
||||
case FACE_QUAD9:
|
||||
return NewElement(mesh, Geometry::SQUARE, vertex_ids, sideset_id);
|
||||
default:
|
||||
MFEM_ABORT("Unsupported cubit face type encountered.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief The final step in constructing the mesh from a Genesis file. This is
|
||||
/// only called if the mesh order == 2 (determined internally from the cubit
|
||||
/// element type).
|
||||
void FinalizeCubitSecondOrderMesh(Mesh &mesh,
|
||||
const int cubit_element_type,
|
||||
const int num_element_blocks,
|
||||
const int num_nodes_per_element,
|
||||
const int *start_of_block,
|
||||
const double *coordx,
|
||||
const double *coordy,
|
||||
const double *coordz,
|
||||
const vector<vector<int>> &element_blocks)
|
||||
{
|
||||
int *mfem_to_genesis_map = nullptr;
|
||||
|
||||
switch (cubit_element_type)
|
||||
{
|
||||
case ELEMENT_TRI6:
|
||||
mfem_to_genesis_map = (int *) mfem_to_genesis_tri6;
|
||||
break;
|
||||
case ELEMENT_QUAD9:
|
||||
mfem_to_genesis_map = (int *) mfem_to_genesis_quad9;
|
||||
break;
|
||||
case ELEMENT_TET10:
|
||||
mfem_to_genesis_map = (int *) mfem_to_genesis_tet10;
|
||||
break;
|
||||
case ELEMENT_HEX27:
|
||||
mfem_to_genesis_map = (int *) mfem_to_genesis_hex27;
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Something went wrong. Linear elements detected when order is 2.");
|
||||
}
|
||||
|
||||
mesh.FinalizeTopology();
|
||||
|
||||
// Define quadratic FE space.
|
||||
const int Dim = mesh.Dimension();
|
||||
FiniteElementCollection *fec = new H1_FECollection(2,3);
|
||||
FiniteElementSpace *fes = new FiniteElementSpace(&mesh, fec, Dim,
|
||||
Ordering::byVDIM);
|
||||
GridFunction *Nodes = new GridFunction(fes);
|
||||
Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes'
|
||||
mesh.SetNodalGridFunction(Nodes, true);
|
||||
|
||||
for (int ielement = 0; ielement < mesh.GetNE(); ielement++)
|
||||
{
|
||||
Array<int> dofs;
|
||||
fes->GetElementDofs(ielement, dofs);
|
||||
|
||||
Array<int> vdofs = dofs; // Deep copy.
|
||||
fes->DofsToVDofs(vdofs);
|
||||
|
||||
// Find block that element is part of.
|
||||
const int iblock = GetCubitBlockIndexForElement(ielement,
|
||||
num_element_blocks,
|
||||
start_of_block);
|
||||
|
||||
// Find element offset in block.
|
||||
const int element_offset = ielement - start_of_block[iblock];
|
||||
const int node_offset = element_offset * num_nodes_per_element;
|
||||
|
||||
for (int jnode = 0; jnode < dofs.Size(); jnode++)
|
||||
{
|
||||
const int node_index = element_blocks[iblock][node_offset +
|
||||
mfem_to_genesis_map[jnode] - 1] - 1;
|
||||
|
||||
(*Nodes)(vdofs[jnode]) = coordx[node_index];
|
||||
(*Nodes)(vdofs[jnode] + 1) = coordy[node_index];
|
||||
|
||||
if (Dim == 3)
|
||||
{
|
||||
(*Nodes)(vdofs[jnode] + 2) = coordz[node_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cubit.
|
||||
|
||||
|
||||
void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
void Mesh::ReadCubit(const char *filename, int &curved, int &read_gf)
|
||||
{
|
||||
using namespace cubit;
|
||||
|
||||
@@ -3490,10 +3352,14 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
// Setup buffer used to write variable names to.
|
||||
int variable_id;
|
||||
|
||||
const int buffer_size = NC_MAX_NAME + 1; // NB: Add 1 for '\0'.
|
||||
|
||||
char variable_name_buffer[buffer_size];
|
||||
|
||||
// Open the file.
|
||||
int netcdf_status, netcdf_descriptor;
|
||||
|
||||
netcdf_status = nc_open(filename.c_str(), NC_NOWRITE, &netcdf_descriptor);
|
||||
netcdf_status = nc_open(filename, NC_NOWRITE, &netcdf_descriptor);
|
||||
if (netcdf_status != NC_NOERR) { HandleNetCDFError(netcdf_status); }
|
||||
|
||||
// Read important dimensions from file.
|
||||
@@ -3533,61 +3399,58 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
SetCubitFaceInfo(cubit_face_type, num_face_nodes, num_face_linear_nodes);
|
||||
|
||||
// Read the (element, corresponding side) on each of the boundaries.
|
||||
vector<size_t> num_boundary_elements(num_boundaries);
|
||||
std::vector<size_t> num_boundary_elements(num_boundaries);
|
||||
|
||||
vector<vector<int>> boundary_elements(num_boundaries);
|
||||
vector<vector<int>> boundary_sides(num_boundaries);
|
||||
int **boundary_elements = new int*[num_boundaries];
|
||||
int **boundary_sides = new int*[num_boundaries];
|
||||
|
||||
ReadCubitBoundaries(netcdf_descriptor, num_boundaries, num_boundary_elements,
|
||||
boundary_elements, boundary_sides);
|
||||
|
||||
// Read the boundary ids.
|
||||
vector<int> boundary_ids;
|
||||
int *boundary_ids = nullptr;
|
||||
|
||||
if (num_boundaries > 0)
|
||||
{
|
||||
boundary_ids.resize(num_boundaries);
|
||||
boundary_ids = new int[num_boundaries];
|
||||
|
||||
netcdf_status = nc_inq_varid(netcdf_descriptor, "ss_prop1", &variable_id);
|
||||
netcdf_status = nc_get_var_int(netcdf_descriptor, variable_id,
|
||||
boundary_ids.data());
|
||||
netcdf_status = nc_get_var_int(netcdf_descriptor, variable_id, boundary_ids);
|
||||
|
||||
if (netcdf_status != NC_NOERR) { HandleNetCDFError(netcdf_status); }
|
||||
}
|
||||
|
||||
// Read the xyz coordinates for each node.
|
||||
vector<double> coordx(num_nodes);
|
||||
vector<double> coordy(num_nodes);
|
||||
vector<double> coordz(num_dimensions == 3 ? num_nodes : 0);
|
||||
double *coordx = new double[num_nodes];
|
||||
double *coordy = new double[num_nodes];
|
||||
double *coordz = (num_dimensions == 3 ? new double[num_nodes] : nullptr);
|
||||
|
||||
ReadCubitNodeCoordinates(netcdf_descriptor, coordx.data(), coordy.data(),
|
||||
coordz.data());
|
||||
ReadCubitNodeCoordinates(netcdf_descriptor, coordx, coordy, coordz);
|
||||
|
||||
// Read the elements that make-up each block.
|
||||
vector<vector<int>> block_elements(num_element_blocks);
|
||||
int **block_elements = new int*[num_element_blocks];
|
||||
|
||||
ReadCubitElementBlocks(netcdf_descriptor, num_element_blocks,
|
||||
num_nodes_per_element, num_elements_for_block,
|
||||
block_elements);
|
||||
|
||||
// Read the block IDs.
|
||||
vector<int> block_ids(num_element_blocks);
|
||||
int *block_ids = new int[num_element_blocks];
|
||||
|
||||
{
|
||||
netcdf_status = nc_inq_varid(netcdf_descriptor, "eb_prop1", &variable_id);
|
||||
netcdf_status = nc_get_var_int(netcdf_descriptor, variable_id,
|
||||
block_ids.data());
|
||||
netcdf_status = nc_get_var_int(netcdf_descriptor, variable_id, block_ids);
|
||||
|
||||
if (netcdf_status != NC_NOERR) { HandleNetCDFError(netcdf_status); }
|
||||
}
|
||||
|
||||
// Create an array holding the index of the first element in each block. This
|
||||
// will allow the determination of the block that each element is in.
|
||||
vector<int> start_of_block(num_element_blocks + 1);
|
||||
int *start_of_block = new int[num_element_blocks + 1];
|
||||
|
||||
start_of_block[0] = 0;
|
||||
|
||||
for (size_t iblock = 1; iblock < num_element_blocks + 1; iblock++)
|
||||
for (int iblock = 1; iblock < num_element_blocks + 1; iblock++)
|
||||
{
|
||||
start_of_block[iblock] = start_of_block[iblock - 1] +
|
||||
num_elements_for_block[iblock - 1];
|
||||
@@ -3596,15 +3459,15 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
// Iterate over each boundary. For each boundary, we run through the
|
||||
// (element, side) pairs and extract the face nodes of each element on the
|
||||
// corresponding side.
|
||||
vector<vector<int>> boundary_nodes(num_boundaries);
|
||||
int **boundary_nodes = new int*[num_boundaries];
|
||||
|
||||
// Iterate over boundaries.
|
||||
for (size_t iboundary = 0; iboundary < num_boundaries; iboundary++)
|
||||
for (int iboundary = 0; iboundary < num_boundaries; iboundary++)
|
||||
{
|
||||
const int num_elements_on_boundary = num_boundary_elements[iboundary];
|
||||
const int num_nodes_on_boundary = num_elements_on_boundary * num_face_nodes;
|
||||
|
||||
boundary_nodes[iboundary].resize(num_nodes_on_boundary);
|
||||
boundary_nodes[iboundary] = new int[num_nodes_on_boundary];
|
||||
|
||||
// Iterate over (element, side) pairs on boundary.
|
||||
for (int jelement = 0; jelement < num_elements_on_boundary; jelement++)
|
||||
@@ -3617,7 +3480,7 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
// Determine the block the element is part-of.
|
||||
const int iblock = GetCubitBlockIndexForElement(element_global_index,
|
||||
num_element_blocks,
|
||||
start_of_block.data());
|
||||
start_of_block);
|
||||
|
||||
const int element_block_offset = element_global_index - start_of_block[iblock];
|
||||
const int node_block_offset = element_block_offset * num_nodes_per_element;
|
||||
@@ -3683,13 +3546,13 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
}
|
||||
|
||||
// We need another node ID mapping since MFEM needs contiguous vertex ids.
|
||||
vector<int> unique_vertex_ids;
|
||||
std::vector<int> unique_vertex_ids;
|
||||
|
||||
for (size_t iblock = 0; iblock < num_element_blocks; iblock++)
|
||||
for (int iblock = 0; iblock < num_element_blocks; iblock++)
|
||||
{
|
||||
const vector<int> &nodes_in_block = block_elements[iblock];
|
||||
const int *nodes_in_block = block_elements[iblock];
|
||||
|
||||
for (size_t jelement = 0; jelement < num_elements_for_block[iblock]; jelement++)
|
||||
for (int jelement = 0; jelement < num_elements_for_block[iblock]; jelement++)
|
||||
{
|
||||
const int element_block_offset = jelement * num_nodes_per_element;
|
||||
|
||||
@@ -3702,8 +3565,9 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
|
||||
// Sort and only retain unique node IDs.
|
||||
std::sort(unique_vertex_ids.begin(), unique_vertex_ids.end());
|
||||
std::vector<int>::iterator new_end;
|
||||
|
||||
auto new_end = std::unique(unique_vertex_ids.begin(), unique_vertex_ids.end());
|
||||
new_end = std::unique(unique_vertex_ids.begin(), unique_vertex_ids.end());
|
||||
unique_vertex_ids.resize(std::distance(unique_vertex_ids.begin(), new_end));
|
||||
|
||||
// unique_vertex_ids now contains a 1-based sorted list of node IDs for each
|
||||
@@ -3712,7 +3576,7 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
// ie. [1, 4, 5, 8, 9] --> [1, 2, 3, 4, 5].
|
||||
std::map<int,int> cubit_to_mfem_vertex_map;
|
||||
|
||||
for (size_t ivertex = 0; ivertex < unique_vertex_ids.size(); ivertex++)
|
||||
for (int ivertex = 0; ivertex < unique_vertex_ids.size(); ivertex++)
|
||||
{
|
||||
const int key = unique_vertex_ids[ivertex];
|
||||
const int value = ivertex + 1;
|
||||
@@ -3745,18 +3609,18 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
NumOfElements = num_elements;
|
||||
elements.SetSize(num_elements);
|
||||
|
||||
std::vector<int> renumbered_vertex_ids(max(num_element_linear_nodes,
|
||||
num_face_linear_nodes));
|
||||
int renumbered_vertex_ids[max(num_element_linear_nodes, num_face_linear_nodes)];
|
||||
|
||||
int element_counter = 0;
|
||||
|
||||
// Iterate over blocks.
|
||||
for (size_t iblock = 0; iblock < num_element_blocks; iblock++)
|
||||
for (int iblock = 0; iblock < num_element_blocks; iblock++)
|
||||
{
|
||||
const vector<int> &nodes_ids_for_block = block_elements[iblock];
|
||||
const int * nodes_ids_for_block = block_elements[iblock];
|
||||
|
||||
// Iterate over elements in block.
|
||||
for (size_t jelement = 0; jelement < num_elements_for_block[iblock]; jelement++)
|
||||
for (int jelement = 0; jelement < num_elements_for_block[iblock];
|
||||
jelement++)
|
||||
{
|
||||
// Iterate over linear nodes in block.
|
||||
for (int knode = 0; knode < num_element_linear_nodes; knode++)
|
||||
@@ -3769,8 +3633,8 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
}
|
||||
|
||||
// Create element.
|
||||
elements[element_counter++] = CreateCubitElement(*this, cubit_element_type,
|
||||
renumbered_vertex_ids.data(),
|
||||
elements[element_counter++] = CreateCubitElement(cubit_element_type,
|
||||
renumbered_vertex_ids,
|
||||
block_ids[iblock]);
|
||||
}
|
||||
}
|
||||
@@ -3779,7 +3643,7 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
// Load up the boundary elements.
|
||||
//
|
||||
NumOfBdrElements = 0;
|
||||
for (size_t iboundary = 0; iboundary < num_boundaries; iboundary++)
|
||||
for (int iboundary = 0; iboundary < num_boundaries; iboundary++)
|
||||
{
|
||||
NumOfBdrElements += num_boundary_elements[iboundary];
|
||||
}
|
||||
@@ -3789,13 +3653,12 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
int boundary_counter = 0;
|
||||
|
||||
// Iterate over boundaries.
|
||||
for (size_t iboundary = 0; iboundary < num_boundaries; iboundary++)
|
||||
for (int iboundary = 0; iboundary < num_boundaries; iboundary++)
|
||||
{
|
||||
const vector<int> &nodes_on_boundary = boundary_nodes[iboundary];
|
||||
const int *nodes_on_boundary = boundary_nodes[iboundary];
|
||||
|
||||
// Iterate over elements on boundary.
|
||||
for (size_t jelement = 0; jelement < num_boundary_elements[iboundary];
|
||||
jelement++)
|
||||
for (int jelement = 0; jelement < num_boundary_elements[iboundary]; jelement++)
|
||||
{
|
||||
// Iterate over element's face linear nodes.
|
||||
for (int knode = 0; knode < num_face_linear_nodes; knode++)
|
||||
@@ -3807,9 +3670,8 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
}
|
||||
|
||||
// Create boundary element.
|
||||
boundary[boundary_counter++] = CreateCubitBoundaryElement(*this,
|
||||
cubit_face_type,
|
||||
renumbered_vertex_ids.data(),
|
||||
boundary[boundary_counter++] = CreateCubitBoundaryElement(cubit_face_type,
|
||||
renumbered_vertex_ids,
|
||||
boundary_ids[iboundary]);
|
||||
}
|
||||
}
|
||||
@@ -3821,19 +3683,219 @@ void Mesh::ReadCubit(const std::string &filename, int &curved, int &read_gf)
|
||||
{
|
||||
curved = 1;
|
||||
|
||||
FinalizeCubitSecondOrderMesh(*this,
|
||||
cubit_element_type,
|
||||
num_element_blocks,
|
||||
num_nodes_per_element,
|
||||
start_of_block.data(),
|
||||
coordx.data(),
|
||||
coordy.data(),
|
||||
coordz.data(),
|
||||
block_elements);
|
||||
FinalizeCubitSecondOrderMesh(cubit_element_type, num_element_blocks,
|
||||
num_nodes_per_element, start_of_block, coordx, coordy, coordz,
|
||||
(const int **)block_elements);
|
||||
}
|
||||
|
||||
// Clean up all netcdf stuff.
|
||||
nc_close(netcdf_descriptor);
|
||||
|
||||
for (int iboundary = 0; iboundary < num_boundaries; iboundary++)
|
||||
{
|
||||
delete [] boundary_elements[iboundary];
|
||||
delete [] boundary_sides[iboundary];
|
||||
delete [] boundary_nodes[iboundary];
|
||||
}
|
||||
|
||||
delete [] boundary_elements;
|
||||
delete [] boundary_sides;
|
||||
delete [] boundary_nodes;
|
||||
|
||||
delete [] coordx;
|
||||
delete [] coordy;
|
||||
delete [] coordz;
|
||||
|
||||
for (int iblock = 0; iblock < num_element_blocks; iblock++)
|
||||
{
|
||||
delete [] block_elements[iblock];
|
||||
}
|
||||
|
||||
delete [] block_elements;
|
||||
delete [] start_of_block;
|
||||
|
||||
delete [] block_ids;
|
||||
delete [] boundary_ids;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::FinalizeCubitSecondOrderMesh(const int cubit_element_type,
|
||||
const int num_element_blocks,
|
||||
const int num_nodes_per_element,
|
||||
const int *start_of_block,
|
||||
const double *coordx,
|
||||
const double *coordy,
|
||||
const double *coordz,
|
||||
const int **element_blocks)
|
||||
{
|
||||
using namespace cubit;
|
||||
|
||||
int *mfem_to_genesis_map = nullptr;
|
||||
|
||||
switch (cubit_element_type)
|
||||
{
|
||||
case ELEMENT_TRI6:
|
||||
{
|
||||
mfem_to_genesis_map = (int *) mfem_to_genesis_tri6;
|
||||
break;
|
||||
}
|
||||
case ELEMENT_QUAD9:
|
||||
{
|
||||
mfem_to_genesis_map = (int *) mfem_to_genesis_quad9;
|
||||
break;
|
||||
}
|
||||
case ELEMENT_TET10:
|
||||
{
|
||||
mfem_to_genesis_map = (int *) mfem_to_genesis_tet10;
|
||||
break;
|
||||
}
|
||||
case ELEMENT_HEX27:
|
||||
{
|
||||
mfem_to_genesis_map = (int *) mfem_to_genesis_hex27;
|
||||
break;
|
||||
}
|
||||
case ELEMENT_TRI3:
|
||||
case ELEMENT_QUAD4:
|
||||
case ELEMENT_TET4:
|
||||
case ELEMENT_HEX8:
|
||||
default:
|
||||
{
|
||||
MFEM_ABORT("Something went wrong. Linear elements detected when order is 2.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FinalizeTopology();
|
||||
|
||||
// Define quadratic FE space.
|
||||
FiniteElementCollection *fec = new H1_FECollection(2,3);
|
||||
FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim,
|
||||
Ordering::byVDIM);
|
||||
Nodes = new GridFunction(fes);
|
||||
Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes'
|
||||
own_nodes = 1;
|
||||
|
||||
for (int ielement = 0; ielement < NumOfElements; ielement++)
|
||||
{
|
||||
Array<int> dofs;
|
||||
fes->GetElementDofs(ielement, dofs);
|
||||
|
||||
Array<int> vdofs = dofs; // Deep copy.
|
||||
fes->DofsToVDofs(vdofs);
|
||||
|
||||
// Find block that element is part of.
|
||||
const int iblock = GetCubitBlockIndexForElement(ielement,
|
||||
num_element_blocks,
|
||||
start_of_block);
|
||||
|
||||
// Find element offset in block.
|
||||
const int element_offset = ielement - start_of_block[iblock];
|
||||
const int node_offset = element_offset * num_nodes_per_element;
|
||||
|
||||
for (int jnode = 0; jnode < dofs.Size(); jnode++)
|
||||
{
|
||||
const int node_index = element_blocks[iblock][node_offset +
|
||||
mfem_to_genesis_map[jnode] - 1] - 1;
|
||||
|
||||
(*Nodes)(vdofs[jnode]) = coordx[node_index];
|
||||
(*Nodes)(vdofs[jnode] + 1) = coordy[node_index];
|
||||
|
||||
if (Dim == 3)
|
||||
{
|
||||
(*Nodes)(vdofs[jnode] + 2) = coordz[node_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mfem::Element *Mesh::CreateCubitElement(const int cubit_element_type,
|
||||
const int *vertex_ids,
|
||||
const int block_id)
|
||||
{
|
||||
using namespace cubit;
|
||||
|
||||
mfem::Element *new_element = nullptr;
|
||||
|
||||
switch (cubit_element_type)
|
||||
{
|
||||
case ELEMENT_TRI3:
|
||||
case ELEMENT_TRI6:
|
||||
{
|
||||
new_element = new Triangle(vertex_ids, block_id);
|
||||
break;
|
||||
}
|
||||
case ELEMENT_QUAD4:
|
||||
case ELEMENT_QUAD9:
|
||||
{
|
||||
new_element = new Quadrilateral(vertex_ids, block_id);
|
||||
break;
|
||||
}
|
||||
case ELEMENT_TET4:
|
||||
case ELEMENT_TET10:
|
||||
{
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
new_element = TetMemory.Alloc();
|
||||
new_element->SetVertices(vertex_ids);
|
||||
new_element->SetAttribute(block_id);
|
||||
#else
|
||||
new_element = new Tetrahedron(vertex_ids, block_id);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case ELEMENT_HEX8:
|
||||
case ELEMENT_HEX27:
|
||||
{
|
||||
new_element = new Hexahedron(vertex_ids, block_id);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
MFEM_ABORT("Unsupported cubit element type encountered.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new_element;
|
||||
}
|
||||
|
||||
|
||||
mfem::Element *Mesh::CreateCubitBoundaryElement(const int cubit_face_type,
|
||||
const int *vertex_ids,
|
||||
const int sideset_id) const
|
||||
{
|
||||
using namespace cubit;
|
||||
|
||||
mfem::Element *new_element = nullptr;
|
||||
|
||||
switch (cubit_face_type)
|
||||
{
|
||||
case FACE_EDGE2:
|
||||
case FACE_EDGE3:
|
||||
{
|
||||
new_element = new Segment(vertex_ids, sideset_id);
|
||||
break;
|
||||
}
|
||||
case FACE_TRI3:
|
||||
case FACE_TRI6:
|
||||
{
|
||||
new_element = new Triangle(vertex_ids, sideset_id);
|
||||
break;
|
||||
}
|
||||
case FACE_QUAD4:
|
||||
case FACE_QUAD9:
|
||||
{
|
||||
new_element = new Quadrilateral(vertex_ids, sideset_id);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
MFEM_ABORT("Unsupported cubit face type encountered.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new_element;
|
||||
}
|
||||
|
||||
#endif // #ifdef MFEM_USE_NETCDF
|
||||
|
||||
+22
-35
@@ -186,7 +186,7 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
|
||||
if (Dim > 1)
|
||||
{
|
||||
el_to_edge = new Table;
|
||||
NumOfEdges = Mesh::GetElementToEdgeTable(*el_to_edge);
|
||||
NumOfEdges = Mesh::GetElementToEdgeTable(*el_to_edge, be_to_edge);
|
||||
}
|
||||
|
||||
STable3D *faces_tbl = NULL;
|
||||
@@ -197,19 +197,6 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
|
||||
|
||||
GenerateFaces();
|
||||
|
||||
// Make sure the be_to_face array is initialized.
|
||||
// In 2D, it will be set in the above call to Mesh::GetElementToEdgeTable.
|
||||
// In 3D, it will be set in GetElementToFaceTable.
|
||||
// In 1D, we need to set it manually.
|
||||
if (Dim == 1)
|
||||
{
|
||||
be_to_face.SetSize(NumOfBdrElements);
|
||||
for (int i = 0; i < NumOfBdrElements; ++i)
|
||||
{
|
||||
be_to_face[i] = boundary[i]->GetVertices()[0];
|
||||
}
|
||||
}
|
||||
|
||||
ListOfIntegerSets groups;
|
||||
{
|
||||
// the first group is the local one
|
||||
@@ -448,7 +435,7 @@ int ParMesh::BuildLocalBoundary(const Mesh& mesh, const int* partitioning,
|
||||
|
||||
for (int i = 0; i < mesh.GetNBE(); i++)
|
||||
{
|
||||
int edge = mesh.GetBdrElementFaceIndex(i);
|
||||
int edge = mesh.GetBdrElementEdgeIndex(i);
|
||||
int el1 = edge_element->GetRow(edge)[0];
|
||||
if (partitioning[el1] == MyRank)
|
||||
{
|
||||
@@ -464,7 +451,7 @@ int ParMesh::BuildLocalBoundary(const Mesh& mesh, const int* partitioning,
|
||||
boundary.SetSize(nbdry);
|
||||
for (int i = 0; i < mesh.GetNBE(); i++)
|
||||
{
|
||||
int edge = mesh.GetBdrElementFaceIndex(i);
|
||||
int edge = mesh.GetBdrElementEdgeIndex(i);
|
||||
int el1 = edge_element->GetRow(edge)[0];
|
||||
if (partitioning[el1] == MyRank)
|
||||
{
|
||||
@@ -930,8 +917,7 @@ void ParMesh::FinalizeParTopo()
|
||||
}
|
||||
}
|
||||
|
||||
ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine, int generate_edges,
|
||||
bool fix_orientation)
|
||||
ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine)
|
||||
: glob_elem_offset(-1)
|
||||
, glob_offset_sequence(-1)
|
||||
, gtopo(comm)
|
||||
@@ -943,7 +929,9 @@ ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine, int generate_edges,
|
||||
have_face_nbr_data = false;
|
||||
pncmesh = NULL;
|
||||
|
||||
Load(input, generate_edges, refine, fix_orientation);
|
||||
const int gen_edges = 1;
|
||||
|
||||
Load(input, gen_edges, refine, true);
|
||||
}
|
||||
|
||||
void ParMesh::Load(istream &input, int generate_edges, int refine,
|
||||
@@ -1737,7 +1725,7 @@ void ParMesh::GetSharedTriCommunicator(int ordering,
|
||||
stria_comm.Finalize();
|
||||
}
|
||||
|
||||
void ParMesh::MarkTetMeshForRefinement(const DSTable &v_to_v)
|
||||
void ParMesh::MarkTetMeshForRefinement(DSTable &v_to_v)
|
||||
{
|
||||
Array<int> order;
|
||||
GetEdgeOrdering(v_to_v, order); // local edge ordering
|
||||
@@ -2062,7 +2050,6 @@ void ParMesh::DeleteFaceNbrData()
|
||||
|
||||
void ParMesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
|
||||
{
|
||||
DeleteFaceNbrData();
|
||||
space_dim = (space_dim == -1) ? spaceDim : space_dim;
|
||||
FiniteElementCollection* nfec;
|
||||
if (discont)
|
||||
@@ -2083,7 +2070,6 @@ void ParMesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
|
||||
|
||||
void ParMesh::SetNodalFESpace(FiniteElementSpace *nfes)
|
||||
{
|
||||
DeleteFaceNbrData();
|
||||
ParFiniteElementSpace *npfes = dynamic_cast<ParFiniteElementSpace*>(nfes);
|
||||
if (npfes)
|
||||
{
|
||||
@@ -2097,7 +2083,6 @@ void ParMesh::SetNodalFESpace(FiniteElementSpace *nfes)
|
||||
|
||||
void ParMesh::SetNodalFESpace(ParFiniteElementSpace *npfes)
|
||||
{
|
||||
DeleteFaceNbrData();
|
||||
ParGridFunction *nodes = new ParGridFunction(npfes);
|
||||
SetNodalGridFunction(nodes, true);
|
||||
}
|
||||
@@ -2106,17 +2091,19 @@ void ParMesh::EnsureParNodes()
|
||||
{
|
||||
if (Nodes && dynamic_cast<ParFiniteElementSpace*>(Nodes->FESpace()) == NULL)
|
||||
{
|
||||
DeleteFaceNbrData();
|
||||
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;
|
||||
}
|
||||
@@ -3212,15 +3199,17 @@ void ParMesh::ReorientTetMesh()
|
||||
// other ranks in the group
|
||||
Array<int> svert_master_rank(svert_lvert.Size());
|
||||
Array<int> svert_master_index(svert_lvert);
|
||||
for (int i = 0; i < group_svert.Size(); i++)
|
||||
{
|
||||
int rank = gtopo.GetGroupMasterRank(i+1);
|
||||
for (int j = 0; j < group_svert.RowSize(i); j++)
|
||||
for (int i = 0; i < group_svert.Size(); i++)
|
||||
{
|
||||
svert_master_rank[group_svert.GetRow(i)[j]] = rank;
|
||||
int rank = gtopo.GetGroupMasterRank(i+1);
|
||||
for (int j = 0; j < group_svert.RowSize(i); j++)
|
||||
{
|
||||
svert_master_rank[group_svert.GetRow(i)[j]] = rank;
|
||||
}
|
||||
}
|
||||
svert_comm.Bcast(svert_master_index);
|
||||
}
|
||||
svert_comm.Bcast(svert_master_index);
|
||||
|
||||
// the pairs (master rank, master local index) define a globally consistent
|
||||
// vertex ordering
|
||||
@@ -3331,7 +3320,7 @@ void ParMesh::ReorientTetMesh()
|
||||
GenerateFaces();
|
||||
if (el_to_edge)
|
||||
{
|
||||
NumOfEdges = GetElementToEdgeTable(*el_to_edge);
|
||||
NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -3566,7 +3555,7 @@ void ParMesh::LocalRefinement(const Array<int> &marked_el, int type)
|
||||
// 6. Update element-to-edge relations.
|
||||
if (el_to_edge != NULL)
|
||||
{
|
||||
NumOfEdges = GetElementToEdgeTable(*el_to_edge);
|
||||
NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
|
||||
}
|
||||
} // 'if (Dim == 3)'
|
||||
|
||||
@@ -3804,7 +3793,7 @@ void ParMesh::LocalRefinement(const Array<int> &marked_el, int type)
|
||||
|
||||
if (el_to_edge != NULL)
|
||||
{
|
||||
NumOfEdges = GetElementToEdgeTable(*el_to_edge);
|
||||
NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
|
||||
GenerateFaces();
|
||||
}
|
||||
} // 'if (Dim == 2)'
|
||||
@@ -3866,8 +3855,6 @@ void ParMesh::NonconformingRefinement(const Array<Refinement> &refinements,
|
||||
"serial Mesh)");
|
||||
}
|
||||
|
||||
ResetLazyData();
|
||||
|
||||
DeleteFaceNbrData();
|
||||
|
||||
// NOTE: no check of !refinements.Size(), in parallel we would have to reduce
|
||||
@@ -5299,7 +5286,7 @@ Mesh ParMesh::GetSerialMesh(int save_rank) const
|
||||
for (int e = 0; e < NumOfElements; e++)
|
||||
{
|
||||
const int attr = elements[e]->GetAttribute();
|
||||
const int geom_type = elements[e]->GetGeometryType();
|
||||
const int geom_type = elements[e]->GetGeometryType();;
|
||||
ints.Append(attr);
|
||||
ints.Append(geom_type);
|
||||
pfespace_linear.GetElementDofs(e, dofs);
|
||||
|
||||
+13
-19
@@ -24,7 +24,6 @@
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
#ifdef MFEM_USE_PUMI
|
||||
class ParPumiMesh;
|
||||
#endif
|
||||
@@ -32,16 +31,9 @@ class ParPumiMesh;
|
||||
/// Class for parallel meshes
|
||||
class ParMesh : public Mesh
|
||||
{
|
||||
friend class ParNCMesh;
|
||||
friend class ParSubMesh;
|
||||
#ifdef MFEM_USE_PUMI
|
||||
friend class ParPumiMesh;
|
||||
#endif
|
||||
#ifdef MFEM_USE_ADIOS2
|
||||
friend class adios2stream;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
friend class ParSubMesh;
|
||||
|
||||
MPI_Comm MyComm;
|
||||
int NRanks, MyRank;
|
||||
|
||||
@@ -113,7 +105,7 @@ protected:
|
||||
|
||||
// Mark all tets to ensure consistency across MPI tasks; also mark the
|
||||
// shared and boundary triangle faces using the consistently marked tets.
|
||||
void MarkTetMeshForRefinement(const DSTable &v_to_v) override;
|
||||
void MarkTetMeshForRefinement(DSTable &v_to_v) override;
|
||||
|
||||
/// Return a number(0-1) identifying how the given edge has been split
|
||||
int GetEdgeSplittings(Element *edge, const DSTable &v_to_v, int *middle);
|
||||
@@ -344,14 +336,8 @@ public:
|
||||
explicit ParMesh(const ParMesh &pmesh, bool copy_nodes = true);
|
||||
|
||||
/// Read a parallel mesh, each MPI rank from its own file/stream.
|
||||
/** The @a generate_edges parameter is passed to Mesh::Loader. The @a refine
|
||||
and @a fix_orientation parameters are passed to the method
|
||||
Mesh::Finalize().
|
||||
|
||||
@note The order of arguments and their default values are different than
|
||||
for the Mesh class. */
|
||||
ParMesh(MPI_Comm comm, std::istream &input, bool refine = true,
|
||||
int generate_edges = 1, bool fix_orientation = true);
|
||||
/** The @a refine parameter is passed to the method Mesh::Finalize(). */
|
||||
ParMesh(MPI_Comm comm, std::istream &input, bool refine = true);
|
||||
|
||||
/// Deprecated: see @a ParMesh::MakeRefined
|
||||
MFEM_DEPRECATED
|
||||
@@ -708,6 +694,14 @@ public:
|
||||
void PrintSharedEntities(const std::string &fname_prefix) const;
|
||||
|
||||
virtual ~ParMesh();
|
||||
|
||||
friend class ParNCMesh;
|
||||
#ifdef MFEM_USE_PUMI
|
||||
friend class ParPumiMesh;
|
||||
#endif
|
||||
#ifdef MFEM_USE_ADIOS2
|
||||
friend class adios2stream;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1028,6 +1028,9 @@ void ParPumiMesh::UpdateMesh(const ParMesh* AdaptedpMesh)
|
||||
bel_to_edge = (AdaptedpMesh->bel_to_edge) ?
|
||||
new Table(*(AdaptedpMesh->bel_to_edge)) : NULL;
|
||||
|
||||
// Copy the boudary-to-edge Array, be_to_edge (2D)
|
||||
AdaptedpMesh->be_to_edge.Copy(be_to_edge);
|
||||
|
||||
// Duplicate the faces and faces_info.
|
||||
faces.SetSize(AdaptedpMesh->faces.Size());
|
||||
for (int i = 0; i < faces.Size(); i++)
|
||||
|
||||
@@ -235,13 +235,10 @@ ParSubMesh::ParSubMesh(const ParMesh &parent, SubMesh::From from,
|
||||
|
||||
// Add boundaries
|
||||
{
|
||||
const int num_codim_1 = [this]()
|
||||
{
|
||||
if (Dim == 1) { return NumOfVertices; }
|
||||
else if (Dim == 2) { return NumOfEdges; }
|
||||
else if (Dim == 3) { return NumOfFaces; }
|
||||
else { MFEM_ABORT("Invalid dimension."); return -1; }
|
||||
}();
|
||||
int num_of_faces_or_edges =
|
||||
(Dim == 3) ? NumOfFaces :
|
||||
((Dim == 2) ? NumOfEdges : NumOfVertices);
|
||||
Array<int> &be2face = (Dim == 2) ? be_to_edge : be_to_face;
|
||||
|
||||
if (Dim == 3)
|
||||
{
|
||||
@@ -252,7 +249,7 @@ ParSubMesh::ParSubMesh(const ParMesh &parent, SubMesh::From from,
|
||||
}
|
||||
|
||||
NumOfBdrElements = 0;
|
||||
for (int i = 0; i < num_codim_1; i++)
|
||||
for (int i = 0; i < num_of_faces_or_edges; i++)
|
||||
{
|
||||
if (GetFaceInformation(i).IsBoundary())
|
||||
{
|
||||
@@ -261,17 +258,14 @@ ParSubMesh::ParSubMesh(const ParMesh &parent, SubMesh::From from,
|
||||
}
|
||||
|
||||
boundary.SetSize(NumOfBdrElements);
|
||||
be_to_face.SetSize(NumOfBdrElements);
|
||||
be2face.SetSize(NumOfBdrElements);
|
||||
Array<int> parent_face_to_be = parent.GetFaceToBdrElMap();
|
||||
int max_bdr_attr = parent.bdr_attributes.Max();
|
||||
|
||||
for (int i = 0, j = 0; i < num_codim_1; i++)
|
||||
for (int i = 0, j = 0; i < num_of_faces_or_edges; i++)
|
||||
{
|
||||
if (GetFaceInformation(i).IsBoundary())
|
||||
{
|
||||
boundary[j] = faces[i]->Duplicate(this);
|
||||
be_to_face[j] = i;
|
||||
|
||||
if (from == SubMesh::From::Domain && Dim >= 2)
|
||||
{
|
||||
int pbeid = Dim == 3 ? parent_face_to_be[parent_face_ids_[i]] :
|
||||
@@ -289,7 +283,7 @@ ParSubMesh::ParSubMesh(const ParMesh &parent, SubMesh::From from,
|
||||
{
|
||||
boundary[j]->SetAttribute(SubMesh::GENERATED_ATTRIBUTE);
|
||||
}
|
||||
++j;
|
||||
be2face[j++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,7 +323,7 @@ ParSubMesh::ParSubMesh(const ParMesh &parent, SubMesh::From from,
|
||||
if (Dim > 1)
|
||||
{
|
||||
if (!el_to_edge) { el_to_edge = new Table; }
|
||||
NumOfEdges = GetElementToEdgeTable(*el_to_edge);
|
||||
NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
|
||||
}
|
||||
|
||||
SetAttributes();
|
||||
|
||||
@@ -317,7 +317,8 @@ ParTransferMap::CorrectFaceOrientations(const ParFiniteElementSpace &fes,
|
||||
|
||||
if (parent_face_ori.Size() == 0) { return; }
|
||||
|
||||
DofTransformation doftrans(fes.GetVDim(), fes.GetOrdering());
|
||||
VDofTransformation vdoftrans(fes.GetVDim(),
|
||||
fes.GetOrdering());
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
bool face = (dim == 3);
|
||||
@@ -331,13 +332,17 @@ ParTransferMap::CorrectFaceOrientations(const ParFiniteElementSpace &fes,
|
||||
if (parent_face_ori[i] == 0) { continue; }
|
||||
|
||||
Geometry::Type geom = face ? mesh->GetFaceGeometry(i) :
|
||||
mesh->GetElementGeometry(i);
|
||||
mesh->GetElementGeometry(i);;
|
||||
|
||||
if (!fec->DofTransformationForGeometry(geom)) { continue; }
|
||||
doftrans.SetDofTransformation(*fec->DofTransformationForGeometry(geom));
|
||||
StatelessDofTransformation * doftrans =
|
||||
fec->DofTransformationForGeometry(geom);
|
||||
|
||||
if (doftrans == NULL) { continue; }
|
||||
|
||||
vdoftrans.SetDofTransformation(*doftrans);
|
||||
|
||||
Fo[0] = parent_face_ori[i];
|
||||
doftrans.SetFaceOrientations(Fo);
|
||||
vdoftrans.SetFaceOrientations(Fo);
|
||||
|
||||
if (face)
|
||||
{
|
||||
@@ -351,12 +356,12 @@ ParTransferMap::CorrectFaceOrientations(const ParFiniteElementSpace &fes,
|
||||
if (sub_to_parent_map)
|
||||
{
|
||||
src.GetSubVector(vdofs, face_vector);
|
||||
doftrans.TransformPrimal(face_vector);
|
||||
vdoftrans.TransformPrimal(face_vector);
|
||||
}
|
||||
else
|
||||
{
|
||||
dst.GetSubVector(vdofs, face_vector);
|
||||
doftrans.InvTransformPrimal(face_vector);
|
||||
vdoftrans.InvTransformPrimal(face_vector);
|
||||
}
|
||||
|
||||
for (int j = 0; j < vdofs.Size(); j++)
|
||||
|
||||
@@ -65,7 +65,7 @@ SubMesh::SubMesh(const Mesh &parent, From from,
|
||||
|
||||
for (int i = 0; i < NumOfBdrElements; i++)
|
||||
{
|
||||
int pbeid = parent_face_to_be[parent_face_ids_[GetBdrElementFaceIndex(i)]];
|
||||
int pbeid = parent_face_to_be[parent_face_ids_[GetBdrFace(i)]];
|
||||
if (pbeid != -1)
|
||||
{
|
||||
int attr = parent.GetBdrElement(pbeid)->GetAttribute();
|
||||
@@ -117,7 +117,7 @@ SubMesh::SubMesh(const Mesh &parent, From from,
|
||||
|
||||
for (int i = 0; i < NumOfBdrElements; i++)
|
||||
{
|
||||
int pbeid = parent_face_to_be[parent_edge_ids_[GetBdrElementFaceIndex(i)]];
|
||||
int pbeid = parent_face_to_be[parent_edge_ids_[GetBdrFace(i)]];
|
||||
if (pbeid != -1)
|
||||
{
|
||||
int attr = parent.GetBdrElement(pbeid)->GetAttribute();
|
||||
|
||||
@@ -117,21 +117,18 @@ void BuildVdofToVdofMap(const FiniteElementSpace& subfes,
|
||||
|
||||
auto pm = parentfes.GetMesh();
|
||||
|
||||
const Geometry::Type face_geom =
|
||||
pm->GetBdrElementBaseGeometry(parent_element_ids[i]);
|
||||
int face_info, parent_volel_id;
|
||||
pm->GetBdrElementAdjacentElement(
|
||||
parent_element_ids[i], parent_volel_id, face_info);
|
||||
face_info = Mesh::EncodeFaceInfo(
|
||||
Mesh::DecodeFaceInfoLocalIndex(face_info),
|
||||
Geometry::GetInverseOrientation(face_geom,
|
||||
Mesh::DecodeFaceInfoOrientaiton(face_info)));
|
||||
pm->GetBdrElementAdjacentElement2(parent_element_ids[i],
|
||||
parent_volel_id,
|
||||
face_info);
|
||||
pm->GetLocalFaceTransformation(
|
||||
pm->GetBdrElementType(parent_element_ids[i]),
|
||||
pm->GetElementType(parent_volel_id),
|
||||
Tr.Transf,
|
||||
face_info);
|
||||
|
||||
Geometry::Type face_geom =
|
||||
pm->GetBdrElementBaseGeometry(parent_element_ids[i]);
|
||||
const FiniteElement *face_el =
|
||||
parentfes.GetTraceElement(parent_element_ids[i], face_geom);
|
||||
MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
|
||||
|
||||
@@ -241,7 +241,8 @@ void TransferMap::CorrectFaceOrientations(const FiniteElementSpace &fes,
|
||||
|
||||
if (parent_face_ori.Size() == 0) { return; }
|
||||
|
||||
DofTransformation doftrans(fes.GetVDim(), fes.GetOrdering());
|
||||
VDofTransformation vdoftrans(fes.GetVDim(),
|
||||
fes.GetOrdering());
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
bool face = (dim == 3);
|
||||
@@ -255,13 +256,17 @@ void TransferMap::CorrectFaceOrientations(const FiniteElementSpace &fes,
|
||||
if (parent_face_ori[i] == 0) { continue; }
|
||||
|
||||
Geometry::Type geom = face ? mesh->GetFaceGeometry(i) :
|
||||
mesh->GetElementGeometry(i);
|
||||
mesh->GetElementGeometry(i);;
|
||||
|
||||
if (!fec->DofTransformationForGeometry(geom)) { continue; }
|
||||
doftrans.SetDofTransformation(*fec->DofTransformationForGeometry(geom));
|
||||
StatelessDofTransformation * doftrans =
|
||||
fec->DofTransformationForGeometry(geom);
|
||||
|
||||
if (doftrans == NULL) { continue; }
|
||||
|
||||
vdoftrans.SetDofTransformation(*doftrans);
|
||||
|
||||
Fo[0] = parent_face_ori[i];
|
||||
doftrans.SetFaceOrientations(Fo);
|
||||
vdoftrans.SetFaceOrientations(Fo);
|
||||
|
||||
if (face)
|
||||
{
|
||||
@@ -275,12 +280,12 @@ void TransferMap::CorrectFaceOrientations(const FiniteElementSpace &fes,
|
||||
if (sub_to_parent_map)
|
||||
{
|
||||
src.GetSubVector(vdofs, face_vector);
|
||||
doftrans.TransformPrimal(face_vector);
|
||||
vdoftrans.TransformPrimal(face_vector);
|
||||
}
|
||||
else
|
||||
{
|
||||
dst.GetSubVector(vdofs, face_vector);
|
||||
doftrans.InvTransformPrimal(face_vector);
|
||||
vdoftrans.InvTransformPrimal(face_vector);
|
||||
}
|
||||
|
||||
for (int j = 0; j < vdofs.Size(); j++)
|
||||
|
||||
@@ -1403,7 +1403,7 @@ void maxwell_solution_curlcurl(const Vector & X,
|
||||
curlcurlE.resize(dim);
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
curlcurlE[i] = 0.0;
|
||||
curlcurlE[i] = 0.0;;
|
||||
}
|
||||
switch (prob)
|
||||
{
|
||||
|
||||
@@ -18,10 +18,6 @@ CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
|
||||
# Include defaults.mk to get XLINKER
|
||||
DEFAULTS_MK = $(MFEM_DIR)/config/defaults.mk
|
||||
include $(DEFAULTS_MK)
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
|
||||
@@ -213,25 +213,24 @@ HypreParMatrix *FormDiscreteDivergenceMatrix(ParFiniteElementSpace &fes_rt,
|
||||
auto J = D_local.WriteJ();
|
||||
auto V = D_local.WriteData();
|
||||
|
||||
const int two_dim = 2*dim;
|
||||
|
||||
// Loop over L2 DOFs
|
||||
MFEM_FORALL(ii, n_l2*2*dim,
|
||||
MFEM_FORALL(i, n_l2,
|
||||
{
|
||||
const int k = ii % (two_dim);
|
||||
const int i = ii / (two_dim);
|
||||
const int i_loc = i%nvol_per_el;
|
||||
const int i_el = i/nvol_per_el;
|
||||
|
||||
const int sjv_loc = e2f(k, i_loc);
|
||||
const int jv_loc = (sjv_loc >= 0) ? sjv_loc : -1 - sjv_loc;
|
||||
const int sgn1 = (sjv_loc >= 0) ? 1 : -1;
|
||||
const int sj = gather_rt(jv_loc, i_el);
|
||||
const int j = (sj >= 0) ? sj : -1 - sj;
|
||||
const int sgn2 = (sj >= 0) ? 1 : -1;
|
||||
for (int k = 0; k < 2*dim; ++k)
|
||||
{
|
||||
const int sjv_loc = e2f(k, i_loc);
|
||||
const int jv_loc = (sjv_loc >= 0) ? sjv_loc : -1 - sjv_loc;
|
||||
const int sgn1 = (sjv_loc >= 0) ? 1 : -1;
|
||||
const int sj = gather_rt(jv_loc, i_el);
|
||||
const int j = (sj >= 0) ? sj : -1 - sj;
|
||||
const int sgn2 = (sj >= 0) ? 1 : -1;
|
||||
|
||||
J[k + 2*dim*i] = j;
|
||||
V[k + 2*dim*i] = sgn1*sgn2;
|
||||
J[k + 2*dim*i] = j;
|
||||
V[k + 2*dim*i] = sgn1*sgn2;
|
||||
}
|
||||
});
|
||||
|
||||
// Create a block diagonal parallel matrix
|
||||
|
||||
@@ -278,4 +278,4 @@ void SolveCG(Operator &A, Solver &P, const Vector &B, Vector &X)
|
||||
cout << "Done.\nIterations: " << cg.GetNumIterations()
|
||||
<< "\nElapsed: " << tic_toc.RealTime() << endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user