Compare commits
51
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98cf6b0817 | ||
|
|
97ec9f4cf2 | ||
|
|
6c794b6eac | ||
|
|
ee09690f4f | ||
|
|
309429fdfc | ||
|
|
7128a065b3 | ||
|
|
a6ba35ff36 | ||
|
|
4845624368 | ||
|
|
354a61e4b9 | ||
|
|
9c156c0b66 | ||
|
|
ae3af1214f | ||
|
|
9c5dc1464d | ||
|
|
eb88fddeea | ||
|
|
cb6770a4e6 | ||
|
|
e67c98e9a2 | ||
|
|
5f6c164316 | ||
|
|
c6dfc01dd8 | ||
|
|
9676db3664 | ||
|
|
b7691bba5f | ||
|
|
d7f5aec642 | ||
|
|
989e341572 | ||
|
|
f21f9ace69 | ||
|
|
26d36fe267 | ||
|
|
fe8fe5968e | ||
|
|
d849d810b6 | ||
|
|
fc63a4720f | ||
|
|
835d5ddc9d | ||
|
|
ee85bed9bd | ||
|
|
386d0b262b | ||
|
|
76d3923425 | ||
|
|
4bd5a4e3d0 | ||
|
|
ba1a296d36 | ||
|
|
9d4845d1a3 | ||
|
|
46470cd320 | ||
|
|
aeaf936552 | ||
|
|
b9219c5941 | ||
|
|
4435c8284f | ||
|
|
ad857589a0 | ||
|
|
cda243493a | ||
|
|
85e140bfcf | ||
|
|
53ff1a2bf8 | ||
|
|
4b47d0eb63 | ||
|
|
72aeb54227 | ||
|
|
22c33cbdf6 | ||
|
|
5287c9f509 | ||
|
|
fa2db9abf2 | ||
|
|
a8a7bc4e40 | ||
|
|
1e04cf7798 | ||
|
|
fa718bab9a | ||
|
|
84209babd2 | ||
|
|
e940331e39 |
+5
-9
@@ -147,6 +147,11 @@ examples/hiop/ex9-mesh.*
|
||||
examples/hiop/ex9-init.*
|
||||
examples/hiop/ex9-final.*
|
||||
|
||||
|
||||
examples/ex71
|
||||
examples/ex71p
|
||||
examples/Example71*
|
||||
|
||||
examples/pumi/refined.mesh
|
||||
examples/pumi/sol.gf
|
||||
examples/pumi/mesh.*
|
||||
@@ -253,15 +258,6 @@ tests/unit/unit_tests
|
||||
tests/unit/punit_tests
|
||||
tests/unit/sedov_tests_*
|
||||
tests/unit/psedov_tests_*
|
||||
tests/unit/tmop_tests_*
|
||||
tests/unit/ptmop_tests_*
|
||||
tests/unit/cube.mesh
|
||||
tests/unit/star.mesh
|
||||
tests/unit/blade.mesh
|
||||
tests/unit/square01.mesh
|
||||
tests/unit/toroid-hex.mesh
|
||||
tests/unit/beam-hex-nurbs.mesh
|
||||
tests/unit/square-disc-nurbs.mesh
|
||||
|
||||
# Test script output
|
||||
tests/scripts/*.err
|
||||
|
||||
@@ -50,11 +50,6 @@ Performance improvements
|
||||
Improved GPU capabilities
|
||||
-------------------------
|
||||
- Added support for Chebyshev accelerated polynomial smoother on GPU.
|
||||
- The TMOP mesh optimization algorithms were extended to GPU:
|
||||
- QualityMetric #1, #2 and #7 are available in 2D, #302, #303 and #321 in 3D
|
||||
- Both AnalyticAdaptTC and DiscreteAdaptTC TargetConstructor are available
|
||||
- Kernels for normalization and limiting have been added
|
||||
- The AdvectorCG now also support AssemblyLevel::PARTIAL
|
||||
|
||||
- Optimized AMD/HIP kernel support.
|
||||
|
||||
|
||||
+14
-1
@@ -296,6 +296,18 @@ if (MFEM_USE_HIOP)
|
||||
# find_package updates HIOP_FOUND, HIOP_INCLUDE_DIRS, HIOP_LIBRARIES
|
||||
endif()
|
||||
|
||||
# ADEPT package
|
||||
if (MFEM_USE_ADEPT)
|
||||
find_package(ADEPT REQUIRED)
|
||||
# find_package updates ADEPT_FOUND, ADEPT_INCLUDE_DIRS, ADEPT_LIBRARIES
|
||||
endif()
|
||||
|
||||
# FADBAD++ package
|
||||
if (MFEM_USE_FADBADPP)
|
||||
find_package(FADBADPP REQUIRED)
|
||||
# find_package updates FADBADPP_FOUND, FADBADPP_INCLUDE_DIRS, FADBADPP_LIBRARIES
|
||||
endif()
|
||||
|
||||
# CUDA
|
||||
if (MFEM_USE_CUDA)
|
||||
set(CMAKE_CUDA_STANDARD 11)
|
||||
@@ -357,7 +369,8 @@ endif()
|
||||
# be before SuiteSparse.
|
||||
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
|
||||
SLEPC MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
|
||||
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2)
|
||||
ADEPT FADBADPP MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA
|
||||
UMPIRE ADIOS2)
|
||||
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
|
||||
set(TPL_LIBRARIES "")
|
||||
set(TPL_INCLUDE_DIRS "")
|
||||
|
||||
@@ -448,6 +448,19 @@ MFEM_USE_HIOP = YES/NO
|
||||
Enable the usage of HiOp (https://github.com/LLNL/hiop) in MFEM. HiOp is an
|
||||
HPC solver for nonlinear optimization problems.
|
||||
|
||||
MFEM_USE_ADEPT = YES/NO
|
||||
Enable automatic differentiation using the ADEPT library.
|
||||
(http://www.met.reading.ac.uk/clouds/adept)
|
||||
Please, compile the library with flag --disable-openmp.
|
||||
|
||||
MFEM_USE_FADBADPP = YES/NO
|
||||
Enable automatic differentiation using the FADBAD++ library.
|
||||
www.fadbad.com/fadbad.html
|
||||
|
||||
MFEM_USE_ADFORWARD = YES/NO
|
||||
Enable forward mode for AD packages. This option is valid
|
||||
only if the AD package supports two modes (backward/forward).
|
||||
|
||||
MFEM_USE_CUDA = YES/NO
|
||||
Enables support for CUDA devices in MFEM. CUDA is a parallel computing
|
||||
platform and programming model for general computing on graphical processing
|
||||
@@ -635,6 +648,16 @@ The specific libraries and their options are:
|
||||
URL: https://github.com/LLNL/hiop
|
||||
Options: HIOP_OPT, HIOP_LIB.
|
||||
|
||||
- ADEPT (optional), used with MFEM_USE_ADEPT = YES
|
||||
URL: www.met.reading.ac.uk/clouds/adept/
|
||||
Options: ADEPT_OPT, ADEPT_LIB
|
||||
Versions: 1.1 and 2.0.5
|
||||
|
||||
- FADBAD++ (optiobal), used with MFEM_USE_FADBADPP = YES
|
||||
URL: www.fadbad.com/fadbad.html
|
||||
Options: FADBADPP_OPT
|
||||
Versions: 2.1
|
||||
|
||||
- GSLIB (optional), used when MFEM_USE_GSLIB = YES. The gslib library must be
|
||||
built prior to the MFEM build, as follows: download gslib-1.0.5, untar it at
|
||||
the same level as MFEM and create a symbolic link: "ln -s gslib-1.0.5 gslib".
|
||||
@@ -813,6 +836,9 @@ MFEM_USE_MPFR
|
||||
MFEM_USE_ZLIB
|
||||
MFEM_USE_PUMI
|
||||
MFEM_USE_HIOP
|
||||
MFEM_USE_ADEPT
|
||||
MFEM_USE_FADBADPP
|
||||
MFEM_USE_ADFORWARD
|
||||
MFEM_USE_CUDA
|
||||
MFEM_USE_OCCA
|
||||
MFEM_USE_CEED
|
||||
@@ -867,6 +893,8 @@ The CMake build system adds auto-detection for the following packages/libraries:
|
||||
- POSIXCLOCKS
|
||||
- PUMI
|
||||
- HIOP
|
||||
- ADEPT
|
||||
- FADBAD++
|
||||
- OCCA
|
||||
- RAJA
|
||||
- UMPIRE
|
||||
|
||||
@@ -50,6 +50,9 @@ set(MFEM_USE_CEED @MFEM_USE_CEED@)
|
||||
set(MFEM_USE_UMPIRE @MFEM_USE_UMPIRE@)
|
||||
set(MFEM_USE_SIMD @MFEM_USE_SIMD@)
|
||||
set(MFEM_USE_ADIOS2 @MFEM_USE_ADIOS2@)
|
||||
set(MFEM_USE_ADEPT @MFEM_USE_ADEPT@)
|
||||
set(MFEM_USE_FADBADPP @MFEM_USE_FADBADPP@)
|
||||
set(MFEM_USE_ADFORWARD @MFEM_USE_ADFORWARD@)
|
||||
|
||||
set(MFEM_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
|
||||
set(MFEM_CXX_FLAGS "@CMAKE_CXX_FLAGS@")
|
||||
|
||||
@@ -156,4 +156,13 @@
|
||||
// library.
|
||||
#cmakedefine MFEM_USE_SIMMETRIX
|
||||
|
||||
// use ADEPT library for AD
|
||||
#cmakedefine MFEM_USE_ADEPT
|
||||
|
||||
// use FADBAD++ library for AD
|
||||
#cmakedefine MFEM_USE_FADBADPP
|
||||
|
||||
// use forward mode for automatic differentiation
|
||||
#cmakedefine MFEM_USE_ADFORWARD
|
||||
|
||||
#endif // MFEM_CONFIG_HEADER
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at the
|
||||
# Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights reserved.
|
||||
# See file COPYRIGHT for details.
|
||||
#
|
||||
# This file is part of the MFEM library. For more information and source code
|
||||
# availability see http://mfem.org.
|
||||
#
|
||||
# MFEM is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the GNU Lesser General Public License (as published by the Free
|
||||
# Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
# Sets the following variables:
|
||||
# - ADEPT_FOUND
|
||||
# - ADEPT_INCLUDE_DIRS
|
||||
# - ADEPT_LIBRARIES
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(ADEPT ADEPT ADEPT_DIR
|
||||
"include" "adept.hpp"
|
||||
"lib" "libadept.so"
|
||||
"Paths to headers required by ADEPT."
|
||||
"Libraries required by ADEPT.")
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at the
|
||||
# Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights reserved.
|
||||
# See file COPYRIGHT for details.
|
||||
#
|
||||
# This file is part of the MFEM library. For more information and source code
|
||||
# availability see http://mfem.org.
|
||||
#
|
||||
# MFEM is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the GNU Lesser General Public License (as published by the Free
|
||||
# Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
# Sets the following variables:
|
||||
# - FADBADPP_FOUND
|
||||
# - FADBADPP_INCLUDE_DIRS
|
||||
# - FADBADPP_LIBRARIES
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(FADBADPP FADBADPP FADBADPP_DIR
|
||||
"include" "fadiff.h"
|
||||
"lib" ""
|
||||
"Paths to headers required by FADBADPP."
|
||||
"Libraries required by FADBADPP.")
|
||||
|
||||
@@ -733,7 +733,8 @@ function(mfem_export_mk_files)
|
||||
MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS
|
||||
MFEM_USE_GSLIB MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE
|
||||
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_CUDA MFEM_USE_OCCA MFEM_USE_RAJA
|
||||
MFEM_USE_UMPIRE MFEM_USE_SIMD MFEM_USE_ADIOS2)
|
||||
MFEM_USE_UMPIRE MFEM_USE_SIMD MFEM_USE_ADEPT MFEM_USE_FADBADPP
|
||||
MFEM_USE_ADFORWARD MFEM_USE_ADIOS2)
|
||||
foreach(var ${CONFIG_MK_BOOL_VARS})
|
||||
if (${var})
|
||||
set(${var} YES)
|
||||
|
||||
@@ -163,4 +163,14 @@
|
||||
// library.
|
||||
// #define MFEM_USE_SIMMETRIX
|
||||
|
||||
// use ADEPT library for AD
|
||||
// #define MFEM_USE_ADEPT
|
||||
|
||||
// use FADBAD++ library for AD
|
||||
// #define MFEM_USE_FADBADPP
|
||||
|
||||
// use forward mode for automatic differentiation
|
||||
// #define MFEM_USE_ADFORWARD
|
||||
|
||||
|
||||
#endif // MFEM_CONFIG_HEADER
|
||||
|
||||
@@ -43,6 +43,9 @@ MFEM_USE_SIDRE = @MFEM_USE_SIDRE@
|
||||
MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@
|
||||
MFEM_USE_PUMI = @MFEM_USE_PUMI@
|
||||
MFEM_USE_HIOP = @MFEM_USE_HIOP@
|
||||
MFEM_USE_ADEPT = @MFEM_USE_ADEPT@
|
||||
MFEM_USE_FADBADPP = @MFEM_USE_FADBADPP@
|
||||
MFEM_USE_ADFORWARD = @MFEM_USE_ADFORWARD@
|
||||
MFEM_USE_GSLIB = @MFEM_USE_GSLIB@
|
||||
MFEM_USE_CUDA = @MFEM_USE_CUDA@
|
||||
MFEM_USE_HIP = @MFEM_USE_HIP@
|
||||
|
||||
@@ -52,6 +52,9 @@ option(MFEM_USE_CEED "Enable CEED" OFF)
|
||||
option(MFEM_USE_UMPIRE "Enable Umpire" OFF)
|
||||
option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" OFF)
|
||||
option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
|
||||
option(MFEM_USE_ADEPT "Enable AD using ADEPT" OFF)
|
||||
option(MFEM_USE_FADBADPP "Enable AD using FADBAD++" OFF)
|
||||
option(MFEM_USE_ADFORWARD "Enable forward mode for AD" OFF)
|
||||
|
||||
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
|
||||
|
||||
@@ -190,6 +193,13 @@ set(BLAS_LIBRARIES "" CACHE STRING "The BLAS library.")
|
||||
set(LAPACK_INCLUDE_DIRS "" CACHE STRING "Path to LAPACK headers.")
|
||||
set(LAPACK_LIBRARIES "" CACHE STRING "The LAPACK library.")
|
||||
|
||||
set(ADEPT_INCLUDE_DIRS "${MFEM_DIR}/../adept-1.1/include" CACHE STRING "Path to ADEPT headers.")
|
||||
set(ADEPT_LIBRARIES "-L${MFEM_DIR}/../adept-1.1/lib -ladept" CACHE STRING "The ADEPT library.")
|
||||
|
||||
set(FADBADPP_INCLUDE_DIRS "${MFEM_DIR}/../FADBAD++" CACHE STRING "Path to FADBAD++ headers.")
|
||||
set(FADBADPP_LIBRARIES "")
|
||||
|
||||
|
||||
# Some useful variables:
|
||||
set(CMAKE_SKIP_PREPROCESSED_SOURCE_RULES ON) # Skip *.i rules
|
||||
set(CMAKE_SKIP_ASSEMBLY_SOURCE_RULES ON) # Skip *.s rules
|
||||
|
||||
+15
-8
@@ -138,9 +138,11 @@ MFEM_USE_RAJA = NO
|
||||
MFEM_USE_OCCA = NO
|
||||
MFEM_USE_CEED = NO
|
||||
MFEM_USE_UMPIRE = NO
|
||||
MFEM_USE_CAMP = NO
|
||||
MFEM_USE_SIMD = NO
|
||||
MFEM_USE_ADIOS2 = NO
|
||||
MFEM_USE_ADEPT = NO
|
||||
MFEM_USE_FADBADPP = NO
|
||||
MFEM_USE_ADFORWARD = NO
|
||||
|
||||
# Compile and link options for zlib.
|
||||
ZLIB_DIR =
|
||||
@@ -337,14 +339,24 @@ HIOP_DIR = @MFEM_DIR@/../hiop/install
|
||||
HIOP_OPT = -I$(HIOP_DIR)/include
|
||||
HIOP_LIB = -L$(HIOP_DIR)/lib -lhiop $(LAPACK_LIB)
|
||||
|
||||
# ADEPT
|
||||
ADEPT_DIR = @MFEM_DIR@/../adept-1.1
|
||||
ADEPT_OPT = -I$(ADEPT_DIR)/include
|
||||
ADEPT_LIB = -L$(ADEPT_DIR)/lib -ladept
|
||||
|
||||
# FADBAD++
|
||||
FADBADPP_DIR = @MFEM_DIR@/../FADBAD++
|
||||
FADBADPP_OPT = -I$(FADBADPP_DIR)
|
||||
FADBADPP_LIB = -L.
|
||||
|
||||
# GSLIB library
|
||||
GSLIB_DIR = @MFEM_DIR@/../gslib/build
|
||||
GSLIB_OPT = -I$(GSLIB_DIR)/include
|
||||
GSLIB_LIB = -L$(GSLIB_DIR)/lib -lgs
|
||||
|
||||
# CUDA library configuration
|
||||
# CUDA library configuration (currently not needed)
|
||||
CUDA_OPT =
|
||||
CUDA_LIB = -lcusparse
|
||||
CUDA_LIB =
|
||||
|
||||
# HIP library configuration (currently not needed)
|
||||
HIP_OPT =
|
||||
@@ -373,11 +385,6 @@ UMPIRE_DIR = @MFEM_DIR@/../umpire
|
||||
UMPIRE_OPT = -I$(UMPIRE_DIR)/include
|
||||
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -lumpire
|
||||
|
||||
# CAMP library configuration
|
||||
CAMP_DIR = @MFEM_DIR@/../camp
|
||||
CAMP_OPT = -I$(CAMP_DIR)/include
|
||||
CAMP_LIB = -L$(CAMP_DIR)/lib
|
||||
|
||||
# If YES, enable some informational messages
|
||||
VERBOSE = NO
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ list(APPEND ALL_EXE_SRCS
|
||||
ex25.cpp
|
||||
ex26.cpp
|
||||
ex27.cpp
|
||||
ex71.cpp
|
||||
)
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
@@ -64,6 +65,7 @@ if (MFEM_USE_MPI)
|
||||
ex25p.cpp
|
||||
ex26p.cpp
|
||||
ex27p.cpp
|
||||
ex71p.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
// MFEM Example 71 - Serial Version
|
||||
//
|
||||
// Compile with: make ex71
|
||||
//
|
||||
// Sample runs:
|
||||
// ex71 -m ../data/beam-quad.mesh -pp 3.5
|
||||
// ex71 -m ../data/beam-tri.mesh -pp 4.6
|
||||
// ex71 -m ../data/beam-hex.mesh
|
||||
// ex71 -m ../data/beam-tet.mesh
|
||||
// ex71 -m ../data/beam-wedge.mesh
|
||||
//
|
||||
// Description: This examples solves a quasi-static nonlinear
|
||||
// p-Laplacian problem with zero Dirichlet boundary
|
||||
// conditions applied on all defined boundaries
|
||||
//
|
||||
// The example demonstrates the use of nonlinear operators
|
||||
// combined with automatic differentiation (AD). The definitions
|
||||
// of the integrators are written in the ex71.hpp.
|
||||
// Selecting integrator=0 will use the handcoded integrator.
|
||||
// Selecting integrator=1 will utilize the AD integrator.
|
||||
// The AD integrator can be modifief to use ADQFunctionTJ.
|
||||
//
|
||||
// qint (the integrand) is a function which is evaluated
|
||||
// at every integration point. For implementations utilizing
|
||||
// ADQFunctionTJ, the user has to implement the function and the
|
||||
// residual evaluation. The Jacobian of the residual is evaluated
|
||||
// using AD
|
||||
//
|
||||
// For implementations utilizing ADQFunctionTH, the user has
|
||||
// to implement only the function evaluation (as
|
||||
// a template) and the first derivative (the residual) and the
|
||||
// second derivatives (the Hessian) are evaluated using AD.
|
||||
//
|
||||
// We recommend viewing examples 1 and 19, before viewing this
|
||||
// example.
|
||||
|
||||
#include "ex71.hpp"
|
||||
|
||||
#undef MFEM_USE_SUITESPARSE
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options
|
||||
const char *mesh_file = "../data/beam-tet.mesh";
|
||||
int ser_ref_levels = 3;
|
||||
int order = 1;
|
||||
bool visualization = true;
|
||||
double newton_rel_tol = 1e-4;
|
||||
double newton_abs_tol = 1e-6;
|
||||
int newton_iter = 500;
|
||||
int print_level = 0;
|
||||
double pp = 2.0;
|
||||
int integrator=1; //use AD
|
||||
mfem::StopWatch* timer=new mfem::StopWatch();
|
||||
|
||||
mfem::OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
|
||||
"Number of times to refine the mesh uniformly in serial.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&newton_rel_tol, "-rel", "--relative-tolerance",
|
||||
"Relative tolerance for the Newton solve.");
|
||||
args.AddOption(&newton_abs_tol, "-abs", "--absolute-tolerance",
|
||||
"Absolute tolerance for the Newton solve.");
|
||||
args.AddOption(&newton_iter, "-it", "--newton-iterations",
|
||||
"Maximum iterations for the Newton solve.");
|
||||
args.AddOption(&pp, "-pp", "--power-parameter",
|
||||
"Power parameter (>=2.0) for the p-Laplacian.");
|
||||
args.AddOption((&print_level),"-prt","--print-level",
|
||||
"Print level.");
|
||||
args.AddOption(&integrator, "-int","--integrator",
|
||||
"Integrator 0: standard; 1: AD;");
|
||||
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(std::cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(std::cout);
|
||||
|
||||
|
||||
// 2. Read the (serial) mesh from the given mesh file.
|
||||
mfem::Mesh *mesh = new mfem::Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 3. Refine the mesh in serial to increase the resolution. In this example
|
||||
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
|
||||
// a command-line parameter.
|
||||
for (int lev = 0; lev < ser_ref_levels; lev++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 4. Define the power parameter for the p-Laplacian and all other
|
||||
// coefficients
|
||||
mfem::ConstantCoefficient c_pp(pp);
|
||||
mfem::ConstantCoefficient load(1.000000000);
|
||||
mfem::ConstantCoefficient c_ee(0.000000001);
|
||||
|
||||
// 5. Define the finite element spaces for the solution
|
||||
mfem::H1_FECollection fec(order,dim);
|
||||
mfem::FiniteElementSpace fespace(mesh,&fec,1,mfem::Ordering::byVDIM);
|
||||
int glob_size=fespace.GetTrueVSize();
|
||||
std::cout << "Number of finite element unknowns: " << glob_size << std::endl;
|
||||
|
||||
// 6. Define the Dirichlet conditions
|
||||
mfem::Array<int> ess_bdr(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
|
||||
// 7. Define the nonlinear form
|
||||
mfem::NonlinearForm* nf=new mfem::NonlinearForm(&fespace);
|
||||
|
||||
// 8. Define the solution vector x
|
||||
mfem::GridFunction x(&fespace);
|
||||
x = 0.0;
|
||||
mfem::Vector tv(fespace.GetTrueVSize());
|
||||
mfem::Vector sv(fespace.GetTrueVSize());
|
||||
tv=0.0;
|
||||
sv=0.0;
|
||||
|
||||
// 9. Define ParaView DataCollection
|
||||
mfem::ParaViewDataCollection *dacol=new
|
||||
mfem::ParaViewDataCollection("Example71",
|
||||
mesh);
|
||||
dacol->SetLevelsOfDetail(order);
|
||||
dacol->RegisterField("sol",&x);
|
||||
|
||||
// 11. Set domain integrators - start with linear diffusion
|
||||
{
|
||||
// the default power coefficient is 2.0
|
||||
mfem::ConstantCoefficient lpp(2.0);
|
||||
if (integrator==0)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplace(lpp,c_ee,load));
|
||||
}
|
||||
else if (integrator==1)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplaceAD(lpp,c_ee,load));
|
||||
}
|
||||
nf->SetEssentialBC(ess_bdr);
|
||||
// compute the energy
|
||||
double energy=nf->GetEnergy(tv);
|
||||
std::cout<<"[2] The total energy of the system is E="<<energy<<std::endl;
|
||||
// time the assembly
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
nf->GetGradient(sv);
|
||||
timer->Stop();
|
||||
std::cout<<"[2] The assembly time is: "<<timer->RealTime()<<std::endl;
|
||||
mfem::Solver *prec;
|
||||
#ifdef MFEM_USE_SUITESPARSE
|
||||
prec=new mfem::UMFPackSolver();
|
||||
#else
|
||||
prec=new mfem::GSSmoother();
|
||||
#endif
|
||||
mfem::CGSolver *j_pcg = new mfem::CGSolver();
|
||||
j_pcg->SetRelTol(1e-7);
|
||||
j_pcg->SetAbsTol(1e-15);
|
||||
j_pcg->SetMaxIter(500);
|
||||
j_pcg->SetPrintLevel(print_level);
|
||||
j_pcg->SetPreconditioner(*prec);
|
||||
|
||||
mfem::NewtonSolver* ns;
|
||||
ns=new mfem::NewtonSolver();
|
||||
ns->iterative_mode = true;
|
||||
ns->SetSolver(*j_pcg);
|
||||
ns->SetOperator(*nf);
|
||||
ns->SetPrintLevel(print_level);
|
||||
ns->SetRelTol(1e-6);
|
||||
ns->SetAbsTol(1e-12);
|
||||
ns->SetMaxIter(10);
|
||||
//solve the problem
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
ns->Mult(tv, sv);
|
||||
timer->Stop();
|
||||
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;
|
||||
|
||||
energy=nf->GetEnergy(sv);
|
||||
std::cout<<"[pp=2] The total energy of the system is E="<<energy<<std::endl;
|
||||
|
||||
delete ns;
|
||||
delete j_pcg;
|
||||
delete prec;
|
||||
|
||||
x.SetFromTrueDofs(sv);
|
||||
dacol->SetTime(2.0);
|
||||
dacol->SetCycle(2);
|
||||
dacol->Save();
|
||||
}
|
||||
|
||||
// 12. Continue with powers higher than 2
|
||||
for (int i=3; i<pp; i++)
|
||||
{
|
||||
delete nf;
|
||||
nf=new mfem::NonlinearForm(&fespace);
|
||||
mfem::ConstantCoefficient lpp((double)i);
|
||||
if (integrator==0)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplace(lpp,c_ee,load));
|
||||
}
|
||||
else if (integrator==1)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplaceAD(lpp,c_ee,load));
|
||||
}
|
||||
nf->SetEssentialBC(ess_bdr);
|
||||
// compute the energy
|
||||
double energy=nf->GetEnergy(sv);
|
||||
std::cout<<"[pp="<<i<<"] The total energy of the system is E="<<energy<<std::endl;
|
||||
// time the assembly
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
nf->GetGradient(sv);
|
||||
timer->Stop();
|
||||
std::cout<<"[pp="<<i<<"] The assembly time is: "<<timer->RealTime()<<std::endl;
|
||||
mfem::Solver *prec;
|
||||
#ifdef MFEM_USE_SUITESPARSE
|
||||
prec=new mfem::UMFPackSolver();
|
||||
#else
|
||||
prec=new mfem::GSSmoother();
|
||||
#endif
|
||||
mfem::CGSolver *j_pcg = new mfem::CGSolver();
|
||||
j_pcg->SetRelTol(1e-7);
|
||||
j_pcg->SetAbsTol(1e-15);
|
||||
j_pcg->SetMaxIter(500);
|
||||
j_pcg->SetPrintLevel(print_level);
|
||||
j_pcg->SetPreconditioner(*prec);
|
||||
|
||||
mfem::NewtonSolver* ns;
|
||||
ns=new mfem::NewtonSolver();
|
||||
ns->iterative_mode = true;
|
||||
ns->SetSolver(*j_pcg);
|
||||
ns->SetOperator(*nf);
|
||||
ns->SetPrintLevel(print_level);
|
||||
ns->SetRelTol(1e-6);
|
||||
ns->SetAbsTol(1e-12);
|
||||
ns->SetMaxIter(10);
|
||||
//solve the problem
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
ns->Mult(tv, sv);
|
||||
timer->Stop();
|
||||
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;
|
||||
|
||||
energy=nf->GetEnergy(sv);
|
||||
std::cout<<"[pp="<<i<<"] The total energy of the system is E="<<energy<<std::endl;
|
||||
|
||||
delete ns;
|
||||
delete j_pcg;
|
||||
delete prec;
|
||||
|
||||
x.SetFromTrueDofs(sv);
|
||||
dacol->SetTime(i);
|
||||
dacol->SetCycle(i);
|
||||
dacol->Save();
|
||||
}
|
||||
|
||||
// 13. Continue with the final power
|
||||
if ( std::abs(pp-2.0) > std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
delete nf;
|
||||
nf=new mfem::NonlinearForm(&fespace);
|
||||
if (integrator==0)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplace(c_pp,c_ee,load));
|
||||
}
|
||||
else if (integrator==1)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplaceAD(c_pp,c_ee,load));
|
||||
}
|
||||
nf->SetEssentialBC(ess_bdr);
|
||||
// compute the energy
|
||||
double energy=nf->GetEnergy(sv);
|
||||
std::cout<<"[pp="<<pp<<"] The total energy of the system is E="<<energy<<std::endl;
|
||||
// time the assembly
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
nf->GetGradient(sv);
|
||||
timer->Stop();
|
||||
std::cout<<"[pp="<<pp<<"] The assembly time is: "<<timer->RealTime()<<std::endl;
|
||||
mfem::Solver *prec;
|
||||
#ifdef MFEM_USE_SUITESPARSE
|
||||
prec=new mfem::UMFPackSolver();
|
||||
#else
|
||||
prec=new mfem::GSSmoother();
|
||||
#endif
|
||||
mfem::CGSolver *j_pcg = new mfem::CGSolver();
|
||||
j_pcg->SetRelTol(1e-7);
|
||||
j_pcg->SetAbsTol(1e-15);
|
||||
j_pcg->SetMaxIter(500);
|
||||
j_pcg->SetPrintLevel(print_level);
|
||||
j_pcg->SetPreconditioner(*prec);
|
||||
|
||||
mfem::NewtonSolver* ns;
|
||||
ns=new mfem::NewtonSolver();
|
||||
ns->iterative_mode = true;
|
||||
ns->SetSolver(*j_pcg);
|
||||
ns->SetOperator(*nf);
|
||||
ns->SetPrintLevel(print_level);
|
||||
ns->SetRelTol(1e-6);
|
||||
ns->SetAbsTol(1e-12);
|
||||
ns->SetMaxIter(10);
|
||||
//solve the problem
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
ns->Mult(tv, sv);
|
||||
timer->Stop();
|
||||
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;
|
||||
|
||||
energy=nf->GetEnergy(sv);
|
||||
std::cout<<"[pp="<<pp<<"] The total energy of the system is E="<<energy<<std::endl;
|
||||
|
||||
delete ns;
|
||||
delete j_pcg;
|
||||
delete prec;
|
||||
|
||||
x.SetFromTrueDofs(sv);
|
||||
dacol->SetTime(pp);
|
||||
if (pp<2.0)
|
||||
{
|
||||
dacol->SetCycle(std::floor(pp));
|
||||
}
|
||||
else
|
||||
{
|
||||
dacol->SetCycle(std::ceil(pp));
|
||||
}
|
||||
dacol->Save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 19. Free the used memory
|
||||
delete dacol;
|
||||
delete nf;
|
||||
delete mesh;
|
||||
delete timer;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,587 @@
|
||||
// shared implementation ex71p/ex71 for the AD integrands and
|
||||
// the handconded integrators
|
||||
|
||||
|
||||
#ifndef EXAMPLE71_H
|
||||
#define EXAMPLE71_H
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
|
||||
template<typename DType, typename MVType>
|
||||
class MyQFunctorJ
|
||||
{
|
||||
public:
|
||||
DType operator()(const mfem::Vector& vparam, MVType& uu)
|
||||
{
|
||||
double pp=vparam[0];
|
||||
double ee=vparam[1];
|
||||
double ff=vparam[2];
|
||||
|
||||
DType u=uu[3];
|
||||
DType norm2=uu[0]*uu[0]+uu[1]*uu[1]+uu[2]*uu[2];
|
||||
|
||||
DType rez= pow(ee*ee+norm2,pp/2.0)/pp-ff*u;
|
||||
return rez;
|
||||
}
|
||||
|
||||
void operator()(const mfem::Vector& vparam, MVType& uu, MVType& rr)
|
||||
{
|
||||
double pp=vparam[0];
|
||||
double ee=vparam[1];
|
||||
double ff=vparam[2];
|
||||
|
||||
DType norm2=uu[0]*uu[0]+uu[1]*uu[1]+uu[2]*uu[2];
|
||||
DType tvar=pow(ee*ee+norm2,(pp-2.0)/2.0);
|
||||
|
||||
rr[0]=tvar*uu[0];
|
||||
rr[1]=tvar*uu[1];
|
||||
rr[2]=tvar*uu[2];
|
||||
rr[3]=-ff;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef ADQFunctionTJ<MyQFunctorJ,4> pLapIntegrandTJ;
|
||||
|
||||
|
||||
template<typename DType, typename MVType>
|
||||
class MyQFunctorH
|
||||
{
|
||||
public:
|
||||
DType operator()(const mfem::Vector& vparam, MVType& uu)
|
||||
{
|
||||
double pp=vparam[0];
|
||||
double ee=vparam[1];
|
||||
double ff=vparam[2];
|
||||
|
||||
DType u=uu[3];
|
||||
DType norm2=uu[0]*uu[0]+uu[1]*uu[1]+uu[2]*uu[2];
|
||||
|
||||
DType rez= pow(ee*ee+norm2,pp/2.0)/pp-ff*u;
|
||||
return rez;
|
||||
}
|
||||
};
|
||||
|
||||
typedef ADQFunctionTH<MyQFunctorH> pLapIntegrandTH;
|
||||
|
||||
//comment the line below in order to use
|
||||
//pLapIntegrandTJ for differentiation
|
||||
//the user interface for both TH and TJ versions
|
||||
//is exacly the same
|
||||
//#define USE_ADH
|
||||
|
||||
class pLaplaceAD: public mfem::NonlinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
mfem::Coefficient* pp;
|
||||
mfem::Coefficient* coeff;
|
||||
mfem::Coefficient* load;
|
||||
#ifdef USE_ADH
|
||||
pLapIntegrandTH qint;
|
||||
#else
|
||||
pLapIntegrandTJ qint;
|
||||
#endif
|
||||
public:
|
||||
pLaplaceAD()
|
||||
{
|
||||
coeff=nullptr;
|
||||
pp=nullptr;
|
||||
}
|
||||
|
||||
pLaplaceAD(mfem::Coefficient& pp_):pp(&pp_), coeff(nullptr), load(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
pLaplaceAD(mfem::Coefficient &pp_,mfem::Coefficient& q,
|
||||
mfem::Coefficient& ld_): pp(&pp_), coeff(&q), load(&ld_)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~pLaplaceAD()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual double GetElementEnergy(const mfem::FiniteElement &el,
|
||||
mfem::ElementTransformation &trans, const mfem::Vector &elfun) override
|
||||
{
|
||||
double energy=0.0;
|
||||
int ndof = el.GetDof();
|
||||
int ndim = el.GetDim();
|
||||
int spaceDim = trans.GetSpaceDim();
|
||||
bool square = (ndim == spaceDim);
|
||||
const mfem::IntegrationRule *ir = NULL;
|
||||
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
|
||||
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
|
||||
|
||||
mfem::Vector shapef(ndof);
|
||||
mfem::DenseMatrix dshape_iso(ndof,ndim);
|
||||
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
|
||||
mfem::Vector grad(spaceDim);
|
||||
|
||||
mfem::Vector vparam(3);//[power, epsilon, load]
|
||||
mfem::Vector uu(4);//[diff_x,diff_y,diff_z,u]
|
||||
|
||||
uu=0.0;
|
||||
vparam[0]=2.0; //default power
|
||||
vparam[1]=1e-8; //default epsilon
|
||||
vparam[2]=1.0; //default load
|
||||
|
||||
double w;
|
||||
double detJ;
|
||||
|
||||
for (int i = 0; i < ir -> GetNPoints(); i++)
|
||||
{
|
||||
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
|
||||
trans.SetIntPoint(&ip);
|
||||
w = trans.Weight();
|
||||
detJ = (square ? w : w*w);
|
||||
w = ip.weight *w;
|
||||
|
||||
el.CalcDShape(ip,dshape_iso);
|
||||
el.CalcShape(ip,shapef);
|
||||
// AdjugateJacobian = / adj(J), if J is square
|
||||
// \ adj(J^t.J).J^t, otherwise
|
||||
mfem::Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
|
||||
// dshape_xyz should be devided by detJ for obtaining the real value
|
||||
// calculate the gradient
|
||||
dshape_xyz.MultTranspose(elfun,grad);
|
||||
|
||||
//set the power
|
||||
if (pp!=nullptr)
|
||||
{
|
||||
vparam[0]=pp->Eval(trans,ip);
|
||||
}
|
||||
|
||||
//set the coefficient ensuring possitiveness of the tangent matrix
|
||||
if (coeff!=nullptr)
|
||||
{
|
||||
vparam[1]=coeff->Eval(trans,ip);
|
||||
}
|
||||
//add the contribution from the load
|
||||
if (load!=nullptr)
|
||||
{
|
||||
vparam[2]=load->Eval(trans,ip);
|
||||
}
|
||||
//fill the values of vector uu
|
||||
for (int jj=0; jj<spaceDim; jj++)
|
||||
{
|
||||
uu[jj]=grad[jj]/detJ;
|
||||
}
|
||||
uu[3]=shapef*elfun;
|
||||
|
||||
energy = energy + w * (qint.QFunction(vparam,uu));
|
||||
|
||||
}
|
||||
return energy;
|
||||
}
|
||||
|
||||
virtual void AssembleElementVector(const mfem::FiniteElement & el,
|
||||
mfem::ElementTransformation & trans,
|
||||
const mfem::Vector & elfun,
|
||||
mfem::Vector & elvect) override
|
||||
{
|
||||
int ndof = el.GetDof();
|
||||
int ndim = el.GetDim();
|
||||
int spaceDim = trans.GetSpaceDim();
|
||||
const mfem::IntegrationRule *ir = NULL;
|
||||
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
|
||||
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
|
||||
|
||||
mfem::Vector shapef(ndof);
|
||||
mfem::DenseMatrix dshape_iso(ndof,ndim);
|
||||
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
|
||||
mfem::Vector lvec(ndof);
|
||||
elvect.SetSize(ndof);
|
||||
elvect=0.0;
|
||||
|
||||
mfem::DenseMatrix B(ndof,4); //[diff_x,diff_y,diff_z, shape]
|
||||
mfem::Vector vparam(3);//[power, epsilon, load]
|
||||
mfem::Vector uu(4);//[diff_x,diff_y,diff_z,u]
|
||||
mfem::Vector du(4);
|
||||
B=0.0;
|
||||
uu=0.0;
|
||||
//initialize the parameters - keep the same order
|
||||
//utilized in the pLapIntegrator definition
|
||||
vparam[0]=2.0; //default power
|
||||
vparam[1]=1e-8; //default epsilon
|
||||
vparam[2]=1.0; //default load
|
||||
|
||||
double w;
|
||||
|
||||
for (int i = 0; i < ir -> GetNPoints(); i++)
|
||||
{
|
||||
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
|
||||
trans.SetIntPoint(&ip);
|
||||
w = trans.Weight();
|
||||
//detJ = (square ? w : w*w);
|
||||
w = ip.weight * w;
|
||||
|
||||
el.CalcDShape(ip,dshape_iso);
|
||||
el.CalcShape(ip,shapef);
|
||||
mfem::Mult(dshape_iso, trans.InverseJacobian(), dshape_xyz);
|
||||
|
||||
//set the matrix B
|
||||
for (int jj=0; jj<spaceDim; jj++)
|
||||
{
|
||||
B.SetCol(jj,dshape_xyz.GetColumn(jj));
|
||||
}
|
||||
B.SetCol(3,shapef);
|
||||
|
||||
|
||||
//set the power
|
||||
if (pp!=nullptr)
|
||||
{
|
||||
vparam[0]=pp->Eval(trans,ip);
|
||||
}
|
||||
//set the coefficient ensuring possitiveness of the tangent matrix
|
||||
if (coeff!=nullptr)
|
||||
{
|
||||
vparam[1]=coeff->Eval(trans,ip);
|
||||
}
|
||||
//add the contribution from the load
|
||||
if (load!=nullptr)
|
||||
{
|
||||
vparam[2]=load->Eval(trans,ip);
|
||||
}
|
||||
|
||||
//calculate uu
|
||||
B.MultTranspose(elfun,uu);
|
||||
//calculate derivative of the energy with respect to uu
|
||||
qint.QFunctionDU(vparam,uu,du);
|
||||
|
||||
B.Mult(du,lvec);
|
||||
elvect.Add( w, lvec);
|
||||
}// end integration loop
|
||||
}
|
||||
|
||||
virtual void AssembleElementGrad(const mfem::FiniteElement & el,
|
||||
mfem::ElementTransformation & trans,
|
||||
const mfem::Vector & elfun, mfem::DenseMatrix & elmat) override
|
||||
{
|
||||
int ndof = el.GetDof();
|
||||
int ndim = el.GetDim();
|
||||
int spaceDim = trans.GetSpaceDim();
|
||||
const mfem::IntegrationRule *ir = NULL;
|
||||
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
|
||||
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
|
||||
|
||||
mfem::Vector shapef(ndof);
|
||||
mfem::DenseMatrix dshape_iso(ndof,ndim);
|
||||
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
|
||||
elmat.SetSize(ndof,ndof);
|
||||
elmat=0.0;
|
||||
|
||||
mfem::DenseMatrix B(ndof,4); //[diff_x,diff_y,diff_z, shape]
|
||||
mfem::DenseMatrix A(ndof,4);
|
||||
mfem::Vector vparam(3);//[power, epsilon, load]
|
||||
mfem::Vector uu(4);//[diff_x,diff_y,diff_z,u]
|
||||
mfem::DenseMatrix duu(4,4);
|
||||
B=0.0;
|
||||
uu=0.0;
|
||||
//initialize the parameters - keep the same order
|
||||
//utilized in the pLapIntegrator definition
|
||||
vparam[0]=2.0; //default power
|
||||
vparam[1]=1e-8; //default epsilon
|
||||
vparam[2]=1.0; //default load
|
||||
|
||||
double w;
|
||||
|
||||
for (int i = 0; i < ir -> GetNPoints(); i++)
|
||||
{
|
||||
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
|
||||
trans.SetIntPoint(&ip);
|
||||
w = trans.Weight();
|
||||
w = ip.weight * w;
|
||||
|
||||
el.CalcDShape(ip,dshape_iso);
|
||||
el.CalcShape(ip,shapef);
|
||||
mfem::Mult(dshape_iso, trans.InverseJacobian(), dshape_xyz);
|
||||
|
||||
//set the matrix B
|
||||
for (int jj=0; jj<spaceDim; jj++)
|
||||
{
|
||||
B.SetCol(jj,dshape_xyz.GetColumn(jj));
|
||||
}
|
||||
B.SetCol(3,shapef);
|
||||
|
||||
|
||||
//set the power
|
||||
if (pp!=nullptr)
|
||||
{
|
||||
vparam[0]=pp->Eval(trans,ip);
|
||||
}
|
||||
//set the coefficient ensuring possitiveness of the tangent matrix
|
||||
if (coeff!=nullptr)
|
||||
{
|
||||
vparam[1]=coeff->Eval(trans,ip);
|
||||
}
|
||||
//add the contribution from the load
|
||||
if (load!=nullptr)
|
||||
{
|
||||
vparam[2]=load->Eval(trans,ip);
|
||||
}
|
||||
|
||||
//calculate uu
|
||||
B.MultTranspose(elfun,uu);
|
||||
//calculate derivative of the energy with respect to uu
|
||||
qint.QFunctionDD(vparam,uu,duu);
|
||||
|
||||
mfem::Mult(B,duu,A);
|
||||
mfem::AddMult_a_ABt(w,A,B,elmat);
|
||||
|
||||
}//end integration loop
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
class pLaplace: public mfem::NonlinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
mfem::Coefficient* pp;
|
||||
mfem::Coefficient* coeff;
|
||||
mfem::Coefficient* load;
|
||||
public:
|
||||
pLaplace()
|
||||
{
|
||||
coeff=nullptr;
|
||||
pp=nullptr;
|
||||
}
|
||||
|
||||
pLaplace(mfem::Coefficient& pp_):pp(&pp_), coeff(nullptr), load(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
pLaplace(mfem::Coefficient &pp_,mfem::Coefficient& q,
|
||||
mfem::Coefficient& ld_): pp(&pp_), coeff(&q), load(&ld_)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~pLaplace()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual double GetElementEnergy(const mfem::FiniteElement &el,
|
||||
mfem::ElementTransformation &trans, const mfem::Vector &elfun) override
|
||||
{
|
||||
double energy=0.0;
|
||||
int ndof = el.GetDof();
|
||||
int ndim = el.GetDim();
|
||||
int spaceDim = trans.GetSpaceDim();
|
||||
bool square = (ndim == spaceDim);
|
||||
const mfem::IntegrationRule *ir = NULL;
|
||||
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
|
||||
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
|
||||
|
||||
mfem::Vector shapef(ndof);
|
||||
mfem::DenseMatrix dshape_iso(ndof,ndim);
|
||||
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
|
||||
mfem::Vector grad(spaceDim);
|
||||
|
||||
double w;
|
||||
double detJ;
|
||||
double nrgrad2;
|
||||
double ppp=2.0;
|
||||
double eee=0.0;
|
||||
|
||||
for (int i = 0; i < ir -> GetNPoints(); i++)
|
||||
{
|
||||
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
|
||||
trans.SetIntPoint(&ip);
|
||||
w = trans.Weight();
|
||||
detJ = (square ? w : w*w);
|
||||
w = ip.weight *w;
|
||||
|
||||
el.CalcDShape(ip,dshape_iso);
|
||||
el.CalcShape(ip,shapef);
|
||||
// AdjugateJacobian = / adj(J), if J is square
|
||||
// \ adj(J^t.J).J^t, otherwise
|
||||
mfem::Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
|
||||
// dshape_xyz should be devided by detJ for obtaining the real value
|
||||
// calculate the gradient
|
||||
dshape_xyz.MultTranspose(elfun,grad);
|
||||
nrgrad2=grad*grad/(detJ*detJ);
|
||||
|
||||
//set the power
|
||||
if (pp!=nullptr)
|
||||
{
|
||||
ppp=pp->Eval(trans,ip);
|
||||
}
|
||||
|
||||
//set the coefficient ensuring possitiveness of the tangent matrix
|
||||
if (coeff!=nullptr)
|
||||
{
|
||||
eee=coeff->Eval(trans,ip);
|
||||
}
|
||||
|
||||
energy = energy + w * std::pow( nrgrad2 + eee * eee , ppp / 2.0 ) / ppp;
|
||||
|
||||
//add the contribution from the load
|
||||
if (load!=nullptr)
|
||||
{
|
||||
energy = energy - w * (shapef*elfun) * load->Eval(trans,ip);
|
||||
}
|
||||
}
|
||||
return energy;
|
||||
}
|
||||
|
||||
virtual void AssembleElementVector(const mfem::FiniteElement & el,
|
||||
mfem::ElementTransformation & trans,
|
||||
const mfem::Vector & elfun,
|
||||
mfem::Vector & elvect) override
|
||||
{
|
||||
int ndof = el.GetDof();
|
||||
int ndim = el.GetDim();
|
||||
int spaceDim = trans.GetSpaceDim();
|
||||
bool square = (ndim == spaceDim);
|
||||
const mfem::IntegrationRule *ir = NULL;
|
||||
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
|
||||
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
|
||||
|
||||
mfem::Vector shapef(ndof);
|
||||
mfem::DenseMatrix dshape_iso(ndof,ndim);
|
||||
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
|
||||
mfem::Vector grad(spaceDim);
|
||||
mfem::Vector lvec(ndof);
|
||||
elvect.SetSize(ndof);
|
||||
elvect=0.0;
|
||||
|
||||
double w;
|
||||
double detJ;
|
||||
double nrgrad;
|
||||
double aa;
|
||||
double ppp=2.0;
|
||||
double eee=0.0;
|
||||
|
||||
for (int i = 0; i < ir -> GetNPoints(); i++)
|
||||
{
|
||||
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
|
||||
trans.SetIntPoint(&ip);
|
||||
w = trans.Weight();
|
||||
detJ = (square ? w : w*w);
|
||||
w = ip.weight * w;//w;
|
||||
|
||||
el.CalcDShape(ip,dshape_iso);
|
||||
el.CalcShape(ip,shapef);
|
||||
// AdjugateJacobian = / adj(J), if J is square
|
||||
// \ adj(J^t.J).J^t, otherwise
|
||||
mfem::Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
|
||||
// dshape_xyz should be devided by detJ for obtaining the real value
|
||||
|
||||
//calculate the gradient
|
||||
dshape_xyz.MultTranspose(elfun,grad);
|
||||
nrgrad=grad.Norml2()/detJ;
|
||||
//grad is not scaled so far, i.e., grad=grad/detJ
|
||||
|
||||
//set the power
|
||||
if (pp!=nullptr)
|
||||
{
|
||||
ppp=pp->Eval(trans,ip);
|
||||
}
|
||||
|
||||
//set the coefficient ensuring possitiveness of the tangent matrix
|
||||
if (coeff!=nullptr)
|
||||
{
|
||||
eee=coeff->Eval(trans,ip);
|
||||
}
|
||||
|
||||
aa = nrgrad * nrgrad + eee * eee;
|
||||
aa=std::pow( aa , ( ppp - 2.0 ) / 2.0 );
|
||||
dshape_xyz.Mult(grad,lvec);
|
||||
elvect.Add( w * aa / ( detJ * detJ ), lvec);
|
||||
|
||||
|
||||
//add loading
|
||||
if (load!=nullptr)
|
||||
{
|
||||
elvect.Add(-w*load->Eval(trans,ip),shapef);
|
||||
}
|
||||
}// end integration loop
|
||||
}
|
||||
|
||||
virtual void AssembleElementGrad(const mfem::FiniteElement & el,
|
||||
mfem::ElementTransformation & trans,
|
||||
const mfem::Vector & elfun, mfem::DenseMatrix & elmat) override
|
||||
{
|
||||
int ndof = el.GetDof();
|
||||
int ndim = el.GetDim();
|
||||
int spaceDim = trans.GetSpaceDim();
|
||||
bool square = (ndim == spaceDim);
|
||||
const mfem::IntegrationRule *ir = NULL;
|
||||
int order = 2 * trans.OrderGrad(&el) - 1; // correct order?
|
||||
ir = &mfem::IntRules.Get(el.GetGeomType(), order);
|
||||
|
||||
mfem::DenseMatrix dshape_iso(ndof,ndim);
|
||||
mfem::DenseMatrix dshape_xyz(ndof,spaceDim);
|
||||
mfem::Vector grad(spaceDim);
|
||||
mfem::Vector lvec(ndof);
|
||||
elmat.SetSize(ndof,ndof);
|
||||
elmat=0.0;
|
||||
|
||||
double w;
|
||||
double detJ;
|
||||
double nrgrad;
|
||||
double aa0;
|
||||
double aa1;
|
||||
double ppp=2.0;
|
||||
double eee=0.0;
|
||||
|
||||
for (int i = 0; i < ir -> GetNPoints(); i++)
|
||||
{
|
||||
const mfem::IntegrationPoint &ip = ir->IntPoint(i);
|
||||
trans.SetIntPoint(&ip);
|
||||
w = trans.Weight();
|
||||
detJ = (square ? w : w*w);
|
||||
w = ip.weight * w;
|
||||
|
||||
el.CalcDShape(ip,dshape_iso);
|
||||
// AdjugateJacobian = / adj(J), if J is square
|
||||
// \ adj(J^t.J).J^t, otherwise
|
||||
mfem::Mult(dshape_iso, trans.AdjugateJacobian(), dshape_xyz);
|
||||
// dshape_xyz should be devided by detJ for obtaining the real value
|
||||
// grad is not scaled so far,i.e., grad=grad/detJ
|
||||
|
||||
//set the power
|
||||
if (pp!=nullptr)
|
||||
{
|
||||
ppp=pp->Eval(trans,ip);
|
||||
}
|
||||
//set the coefficient ensuring possitiveness of the tangent matrix
|
||||
if (coeff!=nullptr)
|
||||
{
|
||||
eee=coeff->Eval(trans,ip);
|
||||
}
|
||||
|
||||
//calculate the gradient
|
||||
dshape_xyz.MultTranspose(elfun,grad);
|
||||
nrgrad = grad.Norml2() / detJ;
|
||||
aa0 = nrgrad * nrgrad + eee * eee;
|
||||
aa1 = std::pow( aa0 , ( ppp - 2.0 ) / 2.0 );
|
||||
aa0 = ( ppp - 2.0 ) * std::pow(aa0, ( ppp - 4.0 ) / 2.0 );
|
||||
dshape_xyz.Mult(grad,lvec);
|
||||
w = w / ( detJ * detJ );
|
||||
mfem::AddMult_a_VVt( w * aa0 / ( detJ * detJ ), lvec, elmat);
|
||||
mfem::AddMult_a_AAt( w * aa1 , dshape_xyz, elmat);
|
||||
|
||||
}//end integration loop
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,401 @@
|
||||
// MFEM Example 71 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex71p
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 2 ex71p -m ../data/beam-quad.mesh -pp 3.8
|
||||
// mpirun -np 2 ex71p -m ../data/beam-tri.mesh -pp 7.2
|
||||
// mpirun -np 2 ex71p -m ../data/beam-hex.mesh
|
||||
// mpirun -np 2 ex71p -m ../data/beam-tet.mesh
|
||||
// mpirun -np 2 ex71p -m ../data/beam-wedge.mesh
|
||||
//
|
||||
// Description: This examples solves a quasi-static nonlinear
|
||||
// p-Laplacian problem with zero Dirichlet boundary
|
||||
// conditions applied on all defined boundaries
|
||||
//
|
||||
// The example demonstrates the use of nonlinear operators
|
||||
// combined with automatic differentiation (AD). The definitions
|
||||
// of the integrators are written in the ex71.hpp.
|
||||
// Selecting integrator=0 will use the handcoded integrator.
|
||||
// Selecting integrator=1 will utilize the AD integrator.
|
||||
// The AD integrator can be modifief to use ADQFunctionTJ.
|
||||
//
|
||||
// qint (the integrand) is a function which is evaluated
|
||||
// at every integration point. For implementations utilizing
|
||||
// ADQFunctionTJ, the user has to implement the function and the
|
||||
// residual evaluation. The Jacobian of the residual is evaluated
|
||||
// using AD
|
||||
//
|
||||
// For implementations utilizing ADQFunctionTH, the user has
|
||||
// to implement only the function evaluation (as
|
||||
// a template) and the first derivative (the residual) and the
|
||||
// second derivatives (the Hessian) are evaluated using AD.
|
||||
//
|
||||
// We recommend viewing examples 1 and 19, before viewing this
|
||||
// example.
|
||||
|
||||
#include "ex71.hpp"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI
|
||||
int num_procs, myrank;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
|
||||
|
||||
// 2. Parse command-line options
|
||||
const char *mesh_file = "../data/beam-tet.mesh";
|
||||
int ser_ref_levels = 0;
|
||||
int par_ref_levels = 0;
|
||||
int order = 2;
|
||||
bool visualization = true;
|
||||
double newton_rel_tol = 1e-4;
|
||||
double newton_abs_tol = 1e-6;
|
||||
int newton_iter = 500;
|
||||
int print_level = 0;
|
||||
double pp = 2.0;
|
||||
int integrator=1; //use AD
|
||||
mfem::StopWatch* timer=new mfem::StopWatch();
|
||||
|
||||
mfem::OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
|
||||
"Number of times to refine the mesh uniformly in serial.");
|
||||
args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
|
||||
"Number of times to refine the mesh uniformly in parallel.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Order (degree) of the finite elements.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&newton_rel_tol, "-rel", "--relative-tolerance",
|
||||
"Relative tolerance for the Newton solve.");
|
||||
args.AddOption(&newton_abs_tol, "-abs", "--absolute-tolerance",
|
||||
"Absolute tolerance for the Newton solve.");
|
||||
args.AddOption(&newton_iter, "-it", "--newton-iterations",
|
||||
"Maximum iterations for the Newton solve.");
|
||||
args.AddOption(&pp, "-pp", "--power-parameter",
|
||||
"Power parameter (>=2.0) for the p-Laplacian.");
|
||||
args.AddOption((&print_level),"-prt","--print-level",
|
||||
"Print level.");
|
||||
args.AddOption(&integrator, "-int","--integrator",
|
||||
"Integrator 0: standard; 1: AD");
|
||||
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myrank == 0)
|
||||
{
|
||||
args.PrintUsage(std::cout);
|
||||
}
|
||||
MPI_Finalize();
|
||||
return 1;
|
||||
}
|
||||
if (myrank == 0)
|
||||
{
|
||||
args.PrintOptions(std::cout);
|
||||
}
|
||||
|
||||
// 3. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral and hexahedral meshes
|
||||
// with the same code.
|
||||
mfem::Mesh *mesh = new mfem::Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 4. Refine the mesh in serial to increase the resolution. In this example
|
||||
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
|
||||
// a command-line parameter.
|
||||
for (int lev = 0; lev < ser_ref_levels; lev++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
mfem::ParMesh *pmesh = new mfem::ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
for (int lev = 0; lev < par_ref_levels; lev++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 6. Define the power parameter for the p-Laplacian and all other
|
||||
// coefficients
|
||||
mfem::ConstantCoefficient c_pp(pp);
|
||||
mfem::ConstantCoefficient load(1.000000000);
|
||||
mfem::ConstantCoefficient c_ee(0.000000001);
|
||||
|
||||
// 7. Define the finite element spaces for the solution
|
||||
mfem::H1_FECollection fec(order,dim);
|
||||
mfem::ParFiniteElementSpace fespace(pmesh,&fec,1,mfem::Ordering::byVDIM);
|
||||
HYPRE_Int glob_size=fespace.GlobalTrueVSize();
|
||||
if (myrank == 0)
|
||||
{
|
||||
std::cout << "Number of finite element unknowns: " << glob_size << std::endl;
|
||||
}
|
||||
|
||||
// 8. Define the Dirichlet conditions
|
||||
mfem::Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
|
||||
// 9. Define the nonlinear form
|
||||
mfem::ParNonlinearForm* nf=new mfem::ParNonlinearForm(&fespace);
|
||||
|
||||
// 10. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x with initial guess of zero,
|
||||
// which satisfies the boundary conditions.
|
||||
mfem::ParGridFunction x(&fespace);
|
||||
x = 0.0;
|
||||
mfem::HypreParVector* tv=x.GetTrueDofs();
|
||||
mfem::HypreParVector* sv=x.GetTrueDofs();
|
||||
|
||||
// 11. Define ParaView DataCollection
|
||||
mfem::ParaViewDataCollection *dacol=new
|
||||
mfem::ParaViewDataCollection("Example71",
|
||||
pmesh);
|
||||
dacol->SetLevelsOfDetail(order);
|
||||
dacol->RegisterField("sol",&x);
|
||||
|
||||
|
||||
// 11. Set domain integrators - start with linear diffusion
|
||||
{
|
||||
// the default power coefficient is 2.0
|
||||
mfem::ConstantCoefficient lpp(2.0);
|
||||
if (integrator==0)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplace(lpp,c_ee,load));
|
||||
}
|
||||
else if (integrator==1)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplaceAD(lpp,c_ee,load));
|
||||
}
|
||||
nf->SetEssentialBC(ess_bdr);
|
||||
// compute the energy
|
||||
double energy=nf->GetEnergy(*tv);
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"[2] The total energy of the system is E="<<energy<<std::endl;
|
||||
}
|
||||
// time the assembly
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
nf->GetGradient(*sv);
|
||||
timer->Stop();
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"[2] The assembly time is: "<<timer->RealTime()<<std::endl;
|
||||
}
|
||||
mfem::Solver *prec=new mfem::HypreBoomerAMG();
|
||||
mfem::GMRESSolver *j_gmres = new mfem::GMRESSolver(MPI_COMM_WORLD);
|
||||
j_gmres->SetRelTol(1e-7);
|
||||
j_gmres->SetAbsTol(1e-15);
|
||||
j_gmres->SetMaxIter(300);
|
||||
j_gmres->SetPrintLevel(print_level);
|
||||
j_gmres->SetPreconditioner(*prec);
|
||||
|
||||
mfem::NewtonSolver* ns;
|
||||
ns=new mfem::NewtonSolver(MPI_COMM_WORLD);
|
||||
ns->iterative_mode = true;
|
||||
ns->SetSolver(*j_gmres);
|
||||
ns->SetOperator(*nf);
|
||||
ns->SetPrintLevel(print_level);
|
||||
ns->SetRelTol(1e-6);
|
||||
ns->SetAbsTol(1e-12);
|
||||
ns->SetMaxIter(3);
|
||||
//solve the problem
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
ns->Mult(*tv, *sv);
|
||||
timer->Stop();
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;
|
||||
}
|
||||
|
||||
energy=nf->GetEnergy(*sv);
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"[pp=2] The total energy of the system is E="<<energy<<std::endl;
|
||||
}
|
||||
|
||||
delete ns;
|
||||
delete j_gmres;
|
||||
delete prec;
|
||||
|
||||
x.SetFromTrueDofs(*sv);
|
||||
dacol->SetTime(2.0);
|
||||
dacol->SetCycle(2);
|
||||
dacol->Save();
|
||||
}
|
||||
|
||||
// 12. Continue with powers higher than 2
|
||||
for (int i=3; i<pp; i++)
|
||||
{
|
||||
delete nf;
|
||||
nf=new mfem::ParNonlinearForm(&fespace);
|
||||
mfem::ConstantCoefficient lpp((double)i);
|
||||
if (integrator==0)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplace(lpp,c_ee,load));
|
||||
}
|
||||
else if (integrator==1)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplaceAD(lpp,c_ee,load));
|
||||
}
|
||||
nf->SetEssentialBC(ess_bdr);
|
||||
// compute the energy
|
||||
double energy=nf->GetEnergy(*sv);
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"[pp="<<i<<"] The total energy of the system is E="<<energy<<std::endl;
|
||||
}
|
||||
// time the assembly
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
nf->GetGradient(*sv);
|
||||
timer->Stop();
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"[pp="<<i<<"] The assembly time is: "<<timer->RealTime()<<std::endl;
|
||||
}
|
||||
mfem::Solver *prec=new mfem::HypreBoomerAMG();
|
||||
mfem::GMRESSolver *j_gmres = new mfem::GMRESSolver(MPI_COMM_WORLD);
|
||||
j_gmres->SetRelTol(1e-7);
|
||||
j_gmres->SetAbsTol(1e-15);
|
||||
j_gmres->SetMaxIter(300);
|
||||
j_gmres->SetPrintLevel(print_level);
|
||||
j_gmres->SetPreconditioner(*prec);
|
||||
|
||||
mfem::NewtonSolver* ns;
|
||||
ns=new mfem::NewtonSolver(MPI_COMM_WORLD);
|
||||
ns->iterative_mode = true;
|
||||
ns->SetSolver(*j_gmres);
|
||||
ns->SetOperator(*nf);
|
||||
ns->SetPrintLevel(print_level);
|
||||
ns->SetRelTol(1e-6);
|
||||
ns->SetAbsTol(1e-12);
|
||||
ns->SetMaxIter(3);
|
||||
//solve the problem
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
ns->Mult(*tv, *sv);
|
||||
timer->Stop();
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;
|
||||
}
|
||||
|
||||
energy=nf->GetEnergy(*sv);
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"[pp="<<i<<"] The total energy of the system is E="<<energy<<std::endl;
|
||||
}
|
||||
|
||||
delete ns;
|
||||
delete j_gmres;
|
||||
delete prec;
|
||||
|
||||
x.SetFromTrueDofs(*sv);
|
||||
dacol->SetTime(i);
|
||||
dacol->SetCycle(i);
|
||||
dacol->Save();
|
||||
}
|
||||
|
||||
// 13. Continue with the final power
|
||||
if ( std::abs(pp-2.0) > std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
delete nf;
|
||||
nf=new mfem::ParNonlinearForm(&fespace);
|
||||
if (integrator==0)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplace(c_pp,c_ee,load));
|
||||
}
|
||||
else if (integrator==1)
|
||||
{
|
||||
nf->AddDomainIntegrator(new mfem::pLaplaceAD(c_pp,c_ee,load));
|
||||
}
|
||||
nf->SetEssentialBC(ess_bdr);
|
||||
// compute the energy
|
||||
double energy=nf->GetEnergy(*sv);
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"[pp="<<pp<<"] The total energy of the system is E="<<energy<<std::endl;
|
||||
}
|
||||
// time the assembly
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
nf->GetGradient(*sv);
|
||||
timer->Stop();
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"[pp="<<pp<<"] The assembly time is: "<<timer->RealTime()<<std::endl;
|
||||
}
|
||||
mfem::Solver *prec=new mfem::HypreBoomerAMG();
|
||||
mfem::GMRESSolver *j_gmres = new mfem::GMRESSolver(MPI_COMM_WORLD);
|
||||
j_gmres->SetRelTol(1e-8);
|
||||
j_gmres->SetAbsTol(1e-15);
|
||||
j_gmres->SetMaxIter(300);
|
||||
j_gmres->SetPrintLevel(print_level);
|
||||
j_gmres->SetPreconditioner(*prec);
|
||||
|
||||
mfem::NewtonSolver* ns;
|
||||
ns=new mfem::NewtonSolver(MPI_COMM_WORLD);
|
||||
ns->iterative_mode = true;
|
||||
ns->SetSolver(*j_gmres);
|
||||
ns->SetOperator(*nf);
|
||||
ns->SetPrintLevel(print_level);
|
||||
ns->SetRelTol(1e-6);
|
||||
ns->SetAbsTol(1e-12);
|
||||
ns->SetMaxIter(3);
|
||||
//solve the problem
|
||||
timer->Clear();
|
||||
timer->Start();
|
||||
ns->Mult(*tv, *sv);
|
||||
timer->Stop();
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"Time for the NewtonSolver: "<<timer->RealTime()<<std::endl;
|
||||
}
|
||||
|
||||
energy=nf->GetEnergy(*sv);
|
||||
if (myrank==0)
|
||||
{
|
||||
std::cout<<"[pp="<<pp<<"] The total energy of the system is E="<<energy<<std::endl;
|
||||
}
|
||||
|
||||
delete ns;
|
||||
delete j_gmres;
|
||||
delete prec;
|
||||
|
||||
x.SetFromTrueDofs(*sv);
|
||||
dacol->SetTime(pp);
|
||||
if (pp<2.0)
|
||||
{
|
||||
dacol->SetCycle(std::floor(pp));
|
||||
}
|
||||
else
|
||||
{
|
||||
dacol->SetCycle(std::ceil(pp));
|
||||
}
|
||||
dacol->Save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 19. Free the used memory
|
||||
delete dacol;
|
||||
delete sv;
|
||||
delete tv;
|
||||
delete nf;
|
||||
delete pmesh;
|
||||
delete timer;
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -22,10 +22,10 @@ MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
SEQ_EXAMPLES = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 ex17\
|
||||
ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27
|
||||
ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex71
|
||||
PAR_EXAMPLES = 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
|
||||
ex26p ex27p ex71p
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
EXAMPLES = $(SEQ_EXAMPLES)
|
||||
@@ -146,3 +146,4 @@ clean-exec:
|
||||
@rm -f ex21*.mesh ex21*.sol ex21p_*.*
|
||||
@rm -f ex23.mesh ex23-*.gf
|
||||
@rm -f ex25.mesh ex25-*.gf ex25p-*.*
|
||||
@rm -rf Example71
|
||||
|
||||
+1
-37
@@ -50,43 +50,10 @@ set(SRCS
|
||||
fespacehierarchy.cpp
|
||||
nonlininteg_vectorconvection.cpp
|
||||
quadinterpolator.cpp
|
||||
quadinterpolator_det.cpp
|
||||
quadinterpolator_eval_by_nodes.cpp
|
||||
quadinterpolator_eval_by_vdim.cpp
|
||||
quadinterpolator_grad_by_nodes.cpp
|
||||
quadinterpolator_grad_by_vdim.cpp
|
||||
quadinterpolator_grad_phys_by_nodes.cpp
|
||||
quadinterpolator_grad_phys_by_vdim.cpp
|
||||
quadinterpolator_face.cpp
|
||||
restriction.cpp
|
||||
staticcond.cpp
|
||||
tmop.cpp
|
||||
tmop_pa.cpp
|
||||
tmop_pa_h2d.cpp
|
||||
tmop_pa_h2d_c0.cpp
|
||||
tmop_pa_h2m.cpp
|
||||
tmop_pa_h2m_c0.cpp
|
||||
tmop_pa_h2s.cpp
|
||||
tmop_pa_h2s_c0.cpp
|
||||
tmop_pa_h3d.cpp
|
||||
tmop_pa_h3d_c0.cpp
|
||||
tmop_pa_h3m.cpp
|
||||
tmop_pa_h3m_c0.cpp
|
||||
tmop_pa_h3s.cpp
|
||||
tmop_pa_h3s_c0.cpp
|
||||
tmop_pa_jp2.cpp
|
||||
tmop_pa_jp3.cpp
|
||||
tmop_pa_jt2_tc.cpp
|
||||
tmop_pa_jt3_datc.cpp
|
||||
tmop_pa_jt3_tc.cpp
|
||||
tmop_pa_p2.cpp
|
||||
tmop_pa_p2_c0.cpp
|
||||
tmop_pa_p3.cpp
|
||||
tmop_pa_p3_c0.cpp
|
||||
tmop_pa_w2.cpp
|
||||
tmop_pa_w2_c0.cpp
|
||||
tmop_pa_w3.cpp
|
||||
tmop_pa_w3_c0.cpp
|
||||
tmop_tools.cpp
|
||||
gslib.cpp
|
||||
transfer.cpp
|
||||
@@ -116,10 +83,7 @@ set(HDRS
|
||||
nonlinearform_ext.hpp
|
||||
nonlininteg.hpp
|
||||
quadinterpolator.hpp
|
||||
quadinterpolator_eval.hpp
|
||||
quadinterpolator_face.hpp
|
||||
quadinterpolator_grad.hpp
|
||||
quadinterpolator_grad_phys.hpp
|
||||
restriction.hpp
|
||||
fespacehierarchy.hpp
|
||||
staticcond.hpp
|
||||
@@ -132,9 +96,9 @@ set(HDRS
|
||||
tfespace.hpp
|
||||
tintrules.hpp
|
||||
tmop.hpp
|
||||
tmop_pa.hpp
|
||||
tmop_tools.hpp
|
||||
gslib.hpp
|
||||
adnonlininteg.hpp
|
||||
transfer.hpp
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,402 @@
|
||||
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
||||
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
||||
// reserved. See file COPYRIGHT for details.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability see http://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU Lesser General Public License (as published by the Free
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
|
||||
|
||||
#ifndef MFEM_ADNONLININTEG
|
||||
#define MFEM_ADNONLININTEG
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "fe.hpp"
|
||||
#include "coefficient.hpp"
|
||||
#include "fespace.hpp"
|
||||
#include "nonlininteg.hpp"
|
||||
#include "../linalg/tadvector.hpp"
|
||||
#include "../linalg/taddensemat.hpp"
|
||||
#include "../linalg/fdual.hpp"
|
||||
|
||||
#if defined MFEM_USE_ADEPT
|
||||
#include <adept.h>
|
||||
#elif defined MFEM_USE_FADBADPP
|
||||
#include <fadiff.h>
|
||||
#include <badiff.h>
|
||||
#endif
|
||||
|
||||
//define Forward AD mode
|
||||
//#define MFEM_USE_ADFORWARD
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// m - dimension of the residual vector
|
||||
// the Jacobian will have dimensions [m,length(uu)]
|
||||
template<template <typename, typename> class CTD, int m>
|
||||
class ADQFunctionTJ
|
||||
{
|
||||
protected:
|
||||
#ifdef MFEM_USE_ADEPT
|
||||
adept::Stack m_stack;
|
||||
#endif
|
||||
|
||||
public:
|
||||
#if defined MFEM_USE_ADEPT
|
||||
typedef adept::adouble ADFType;
|
||||
typedef TADVector<ADFType> ADFVector;
|
||||
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
|
||||
#elif defined MFEM_USE_FADBADPP
|
||||
#ifdef MFEM_USE_ADFORWARD
|
||||
typedef fadbad::F<double> ADFType;
|
||||
typedef TADVector<ADFType> ADFVector;
|
||||
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
|
||||
#else
|
||||
typedef fadbad::B<double> ADFType;
|
||||
typedef TADVector<ADFType> ADFVector;
|
||||
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
|
||||
#endif
|
||||
#else
|
||||
typedef mfem::ad::FDual<double> ADFType;
|
||||
typedef TADVector<ADFType> ADFVector;
|
||||
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
|
||||
#endif
|
||||
|
||||
#ifdef MFEM_USE_ADEPT
|
||||
ADQFunctionTJ():m_stack(false) {}
|
||||
#else
|
||||
ADQFunctionTJ() {}
|
||||
#endif
|
||||
|
||||
~ADQFunctionTJ() {}
|
||||
|
||||
double QFunction(const mfem::Vector& vparam, mfem::Vector& uu)
|
||||
{
|
||||
CTD<double,mfem::Vector> func;
|
||||
return func(vparam,uu);
|
||||
}
|
||||
|
||||
void QFunctionDU(const mfem::Vector& vparam, ADFVector& uu,
|
||||
ADFVector& rr)
|
||||
{
|
||||
CTD<ADFType,ADFVector> func;
|
||||
func(vparam,uu,rr);
|
||||
}
|
||||
|
||||
void QFunctionAU(const Vector &vparam, mfem::Vector &uu,
|
||||
mfem::Vector &rr)
|
||||
{
|
||||
//the result is computed automaticaly by differentiating
|
||||
//QFunction with respect to uu
|
||||
CTD<ADFType,ADFVector> func;
|
||||
int n=uu.Size();
|
||||
rr.SetSize(n);
|
||||
|
||||
#if defined MFEM_USE_ADEPT
|
||||
//use ADEPT package
|
||||
adept::Stack* p_stack=adept::active_stack();
|
||||
p_stack->deactivate();
|
||||
|
||||
m_stack.activate();
|
||||
{
|
||||
ADFVector aduu(uu);
|
||||
ADFType rez;
|
||||
m_stack.new_recording();
|
||||
rez=func(vparam,aduu);
|
||||
m_stack.independent(aduu.GetData(), n);//independent variables
|
||||
m_stack.dependent(&rez, 1);//dependent variables
|
||||
m_stack.jacobian(rr.GetData());
|
||||
}
|
||||
m_stack.deactivate();
|
||||
#elif defined MFEM_USE_FADBADPP
|
||||
//use FADBAD++
|
||||
#ifdef MFEM_USE_ADFORWARD
|
||||
{
|
||||
ADFVector aduu(uu);
|
||||
ADFType rez;
|
||||
for (int ii=0; ii<n; ii++)
|
||||
{
|
||||
aduu[ii].diff(ii,n);
|
||||
}
|
||||
rez=func(vparam,aduu);
|
||||
for (int ii=0; ii<n; ii++)
|
||||
{
|
||||
rr[ii]=rez.d(ii);
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
ADFVector aduu(uu);
|
||||
ADFType rez;
|
||||
rez=func(vparam,aduu);
|
||||
rez.diff(0,1);
|
||||
for (int ii=0; ii<n; ii++)
|
||||
{
|
||||
rr[ii]=aduu[ii].d(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
//use native AD package
|
||||
{
|
||||
ADFVector aduu(uu); //all dual numbers are initialized to zero
|
||||
ADFType rez;
|
||||
|
||||
for (int ii=0; ii<n; ii++)
|
||||
{
|
||||
aduu[ii].dual(1.0);
|
||||
rez=func(vparam,aduu);
|
||||
rr[ii]=rez.dual();
|
||||
aduu[ii].dual(0.0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void QFunctionDU(const mfem::Vector& vparam, mfem::Vector& uu,
|
||||
mfem::Vector& rr)
|
||||
{
|
||||
CTD<double,mfem::Vector> func;
|
||||
func(vparam,uu,rr);
|
||||
}
|
||||
|
||||
void QFunctionDD(const mfem::Vector& vparam, mfem::Vector& uu,
|
||||
mfem::DenseMatrix& jac)
|
||||
{
|
||||
#if defined MFEM_USE_ADEPT
|
||||
//use ADEPT package
|
||||
adept::Stack* p_stack=adept::active_stack();
|
||||
p_stack->deactivate();
|
||||
|
||||
int n=uu.Size();
|
||||
jac.SetSize(m,n);
|
||||
jac=0.0;
|
||||
m_stack.activate();
|
||||
{
|
||||
ADFVector aduu(uu);
|
||||
ADFVector rr(m); //residual vector
|
||||
m_stack.new_recording();
|
||||
QFunctionDU(vparam,aduu,rr);
|
||||
m_stack.independent(aduu.GetData(), n);//independent variables
|
||||
m_stack.dependent(rr.GetData(), m);//dependent variables
|
||||
m_stack.jacobian(jac.Data());
|
||||
}
|
||||
m_stack.deactivate();
|
||||
#elif defined MFEM_USE_FADBADPP
|
||||
//use FADBAD++
|
||||
#ifdef MFEM_USE_ADFORWARD
|
||||
int n=uu.Size();
|
||||
jac.SetSize(m,n);
|
||||
jac=0.0;
|
||||
{
|
||||
ADFVector aduu(uu);
|
||||
ADFVector rr(m);
|
||||
|
||||
for (int ii=0; ii<n; ii++)
|
||||
{
|
||||
aduu[ii].diff(ii,n);
|
||||
}
|
||||
QFunctionDU(vparam,aduu,rr);
|
||||
for (int ii=0; ii<n; ii++)
|
||||
{
|
||||
for (int jj=0; jj<m; jj++)
|
||||
{
|
||||
jac(jj,ii)=rr[jj].d(ii);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
int n=uu.Size();
|
||||
jac.SetSize(m,n);
|
||||
jac=0.0;
|
||||
{
|
||||
ADFVector aduu(uu);
|
||||
ADFVector rr(m);
|
||||
QFunctionDU(vparam,aduu,rr);
|
||||
for (int ii=0; ii<m; ii++)
|
||||
{
|
||||
rr[ii].diff(ii,m);
|
||||
}
|
||||
for (int ii=0; ii<n; ii++)
|
||||
{
|
||||
for (int jj=0; jj<m; jj++)
|
||||
{
|
||||
jac(jj,ii)=aduu[ii].d(jj);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
//use native AD package
|
||||
int n=uu.Size();
|
||||
jac.SetSize(m,n);
|
||||
jac=0.0;
|
||||
{
|
||||
ADFVector aduu(uu); //all dual numbers are initialized to zero
|
||||
ADFVector rr(m);
|
||||
|
||||
for (int ii=0; ii<n; ii++)
|
||||
{
|
||||
aduu[ii].dual(1.0);
|
||||
QFunctionDU(vparam,aduu,rr);
|
||||
for (int jj=0; jj<m; jj++)
|
||||
{
|
||||
jac(jj,ii)=rr[jj].dual();
|
||||
}
|
||||
aduu[ii].dual(0.0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
//template class for differentiation; the function
|
||||
//for differentiation is supplied as a functor
|
||||
//the operator()(scalar,vector) defines the actual function
|
||||
template<template <typename, typename> class CTD>
|
||||
class ADQFunctionTH
|
||||
{
|
||||
public:
|
||||
#if defined MFEM_USE_FADBADPP
|
||||
typedef fadbad::B<double> ADFType;
|
||||
typedef TADVector<ADFType> ADFVector;
|
||||
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
|
||||
|
||||
typedef fadbad::B<fadbad::F<double>> ADSType;
|
||||
typedef TADVector<ADSType> ADSVector;
|
||||
typedef TADDenseMatrix<ADSType> ADSDenseMatrix;
|
||||
#else
|
||||
typedef mfem::ad::FDual<double> ADFType;
|
||||
typedef TADVector<ADFType> ADFVector;
|
||||
typedef TADDenseMatrix<ADFType> ADFDenseMatrix;
|
||||
|
||||
typedef mfem::ad::FDual<ADFType> ADSType;
|
||||
typedef TADVector<ADSType> ADSVector;
|
||||
typedef TADDenseMatrix<ADSType> ADSDenseMatrix;
|
||||
#endif
|
||||
|
||||
ADQFunctionTH() {}
|
||||
|
||||
~ADQFunctionTH() {}
|
||||
|
||||
double QFunction(const mfem::Vector& vparam, mfem::Vector& uu)
|
||||
{
|
||||
CTD<double, mfem::Vector> tf;
|
||||
return tf(vparam, uu);
|
||||
}
|
||||
|
||||
ADFType QFunction(const mfem::Vector& vparam, ADFVector& uu)
|
||||
{
|
||||
CTD<ADFType,ADFVector> tf;
|
||||
return tf(vparam, uu);
|
||||
}
|
||||
|
||||
ADSType QFunction(const mfem::Vector &vparam, ADSVector& uu)
|
||||
{
|
||||
CTD<ADSType,ADSVector> tf;
|
||||
return tf(vparam, uu);
|
||||
}
|
||||
|
||||
void QFunctionDU(const mfem::Vector& vparam, mfem::Vector& uu,
|
||||
mfem::Vector& rr)
|
||||
{
|
||||
#if defined MFEM_USE_FADBADPP
|
||||
int n=uu.Size();
|
||||
rr.SetSize(n);
|
||||
ADFVector aduu(uu);
|
||||
ADFType rez;
|
||||
rez=QFunction(vparam,aduu);
|
||||
rez.diff(0,1);
|
||||
for (int ii=0; ii<n; ii++)
|
||||
{
|
||||
rr[ii]=aduu[ii].d(0);
|
||||
}
|
||||
#else
|
||||
int n=uu.Size();
|
||||
rr.SetSize(n);
|
||||
ADFVector aduu(uu);
|
||||
ADFType rez;
|
||||
for (int ii=0; ii<n; ii++)
|
||||
{
|
||||
aduu[ii].dual(1.0);
|
||||
rez=QFunction(vparam,aduu);
|
||||
rr[ii]=rez.dual();
|
||||
aduu[ii].dual(0.0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void QFunctionDD(const mfem::Vector& vparam, const mfem::Vector& uu,
|
||||
mfem::DenseMatrix& jac)
|
||||
{
|
||||
#if defined MFEM_USE_FADBADPP
|
||||
int n=uu.Size();
|
||||
jac.SetSize(n);
|
||||
jac=0.0;
|
||||
{
|
||||
ADSVector aduu(n);
|
||||
for (int ii = 0; ii < n ; ii++)
|
||||
{
|
||||
aduu[ii]=uu[ii];
|
||||
aduu[ii].x().diff(ii,n);
|
||||
}
|
||||
ADSType rez=QFunction(vparam,aduu);
|
||||
rez.diff(0,1);
|
||||
for (int ii = 0; ii < n ; ii++)
|
||||
{
|
||||
for (int jj=0; jj<ii; jj++)
|
||||
{
|
||||
jac(ii,jj)=aduu[ii].d(0).d(jj);
|
||||
jac(jj,ii)=aduu[jj].d(0).d(ii);
|
||||
}
|
||||
jac(ii,ii)=aduu[ii].d(0).d(ii);
|
||||
}
|
||||
}
|
||||
#else
|
||||
int n=uu.Size();
|
||||
jac.SetSize(n);
|
||||
jac=0.0;
|
||||
{
|
||||
ADSVector aduu(n);
|
||||
for (int ii = 0; ii < n ; ii++)
|
||||
{
|
||||
aduu[ii].real(ADFType(uu[ii],0.0));
|
||||
aduu[ii].dual(ADFType(0.0,0.0));
|
||||
}
|
||||
|
||||
for (int ii = 0; ii < n ; ii++)
|
||||
{
|
||||
aduu[ii].real(ADFType(uu[ii],1.0));
|
||||
for (int jj=0; jj<(ii+1); jj++)
|
||||
{
|
||||
aduu[jj].dual(ADFType(1.0,0.0));
|
||||
ADSType rez=QFunction(vparam,aduu);
|
||||
jac(ii,jj)=rez.dual().dual();
|
||||
jac(jj,ii)=rez.dual().dual();
|
||||
aduu[jj].dual(ADFType(0.0,0.0));
|
||||
}
|
||||
aduu[ii].real(ADFType(uu[ii],0.0));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
};// end template ADFunctionTH
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
#include "bilininteg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
|
||||
#include "restriction.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mfem
|
||||
@@ -72,53 +68,47 @@ static void PAConvectionSetup3D(const int Q1D,
|
||||
const double alpha,
|
||||
Vector &op)
|
||||
{
|
||||
const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
|
||||
const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
|
||||
const int NQ = Q1D*Q1D*Q1D;
|
||||
auto W = w.Read();
|
||||
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
|
||||
const bool const_v = vel.Size() == 3;
|
||||
const auto V = const_v ?
|
||||
Reshape(vel.Read(), 3,1,1,1,1) :
|
||||
Reshape(vel.Read(), 3,Q1D,Q1D,Q1D,NE);
|
||||
auto y = Reshape(op.Write(), Q1D,Q1D,Q1D,3,NE);
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
auto V =
|
||||
const_v ? Reshape(vel.Read(), 3,1,1) : Reshape(vel.Read(), 3,NQ,NE);
|
||||
auto y = Reshape(op.Write(), NQ, 3, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
const double J11 = J(qx,qy,qz,0,0,e);
|
||||
const double J12 = J(qx,qy,qz,0,1,e);
|
||||
const double J13 = J(qx,qy,qz,0,2,e);
|
||||
const double J21 = J(qx,qy,qz,1,0,e);
|
||||
const double J22 = J(qx,qy,qz,1,1,e);
|
||||
const double J23 = J(qx,qy,qz,1,2,e);
|
||||
const double J31 = J(qx,qy,qz,2,0,e);
|
||||
const double J32 = J(qx,qy,qz,2,1,e);
|
||||
const double J33 = J(qx,qy,qz,2,2,e);
|
||||
const double w = alpha * W(qx,qy,qz);
|
||||
const double v0 = const_v ? V(0,0,0,0,0) : V(0,qx,qy,qz,e);
|
||||
const double v1 = const_v ? V(1,0,0,0,0) : V(1,qx,qy,qz,e);
|
||||
const double v2 = const_v ? V(2,0,0,0,0) : V(2,qx,qy,qz,e);
|
||||
const double wx = w * v0;
|
||||
const double wy = w * v1;
|
||||
const double wz = w * v2;
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
const double A12 = (J32 * J13) - (J12 * J33);
|
||||
const double A13 = (J12 * J23) - (J22 * J13);
|
||||
const double A21 = (J31 * J23) - (J21 * J33);
|
||||
const double A22 = (J11 * J33) - (J13 * J31);
|
||||
const double A23 = (J21 * J13) - (J11 * J23);
|
||||
const double A31 = (J21 * J32) - (J31 * J22);
|
||||
const double A32 = (J31 * J12) - (J11 * J32);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
// q . J^{-1} = q . adj(J)
|
||||
y(qx,qy,qz,0,e) = wx * A11 + wy * A12 + wz * A13;
|
||||
y(qx,qy,qz,1,e) = wx * A21 + wy * A22 + wz * A23;
|
||||
y(qx,qy,qz,2,e) = wx * A31 + wy * A32 + wz * A33;
|
||||
}
|
||||
}
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J31 = J(q,2,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double J32 = J(q,2,1,e);
|
||||
const double J13 = J(q,0,2,e);
|
||||
const double J23 = J(q,1,2,e);
|
||||
const double J33 = J(q,2,2,e);
|
||||
const double w = alpha * W[q];
|
||||
const double v0 = const_v ? V(0,0,0) : V(0,q,e);
|
||||
const double v1 = const_v ? V(1,0,0) : V(1,q,e);
|
||||
const double v2 = const_v ? V(2,0,0) : V(2,q,e);
|
||||
const double wx = w * v0;
|
||||
const double wy = w * v1;
|
||||
const double wz = w * v2;
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
const double A12 = (J32 * J13) - (J12 * J33);
|
||||
const double A13 = (J12 * J23) - (J22 * J13);
|
||||
const double A21 = (J31 * J23) - (J21 * J33);
|
||||
const double A22 = (J11 * J33) - (J13 * J31);
|
||||
const double A23 = (J21 * J13) - (J11 * J23);
|
||||
const double A31 = (J21 * J32) - (J31 * J22);
|
||||
const double A32 = (J31 * J12) - (J11 * J32);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
// q . J^{-1} = q . adj(J)
|
||||
y(q,0,e) = wx * A11 + wy * A12 + wz * A13;
|
||||
y(q,1,e) = wx * A21 + wy * A22 + wz * A23;
|
||||
y(q,2,e) = wx * A31 + wy * A32 + wz * A33;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -194,8 +184,8 @@ void PAConvectionApply2D(const int ne,
|
||||
Gu[dy][qx] = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double x = u[dy][dx];
|
||||
Bu[dy][qx] += bx * x;
|
||||
Gu[dy][qx] += gx * x;
|
||||
@@ -212,8 +202,8 @@ void PAConvectionApply2D(const int ne,
|
||||
BGu[qy][qx] = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
GBu[qy][qx] += gx * Bu[dy][qx];
|
||||
BGu[qy][qx] += bx * Gu[dy][qx];
|
||||
}
|
||||
@@ -242,7 +232,7 @@ void PAConvectionApply2D(const int ne,
|
||||
BDGu[dy][qx] = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double w = Bt(dy,qy);
|
||||
const double w = Bt(dy,qy);
|
||||
BDGu[dy][qx] += w * DGu[qy][qx];
|
||||
}
|
||||
}
|
||||
@@ -254,7 +244,7 @@ void PAConvectionApply2D(const int ne,
|
||||
double BBDGu = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double w = Bt(dx,qx);
|
||||
const double w = Bt(dx,qx);
|
||||
BBDGu += w * BDGu[dy][qx];
|
||||
}
|
||||
y(dx,dy,e) += BBDGu;
|
||||
@@ -320,7 +310,7 @@ void SmemPAConvectionApply2D(const int ne,
|
||||
{
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double x = u[tidz][dy][dx];
|
||||
const double x = u[tidz][dy][dx];
|
||||
Bu[tidz][dy][qx] += bx * x;
|
||||
Gu[tidz][dy][qx] += gx * x;
|
||||
}
|
||||
@@ -337,8 +327,8 @@ void SmemPAConvectionApply2D(const int ne,
|
||||
BGu[tidz][qy][qx] = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
GBu[tidz][qy][qx] += gx * Bu[tidz][dy][qx];
|
||||
BGu[tidz][qy][qx] += bx * Gu[tidz][dy][qx];
|
||||
}
|
||||
@@ -369,7 +359,7 @@ void SmemPAConvectionApply2D(const int ne,
|
||||
BDGu[tidz][dy][qx] = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double w = Bt(dy,qy);
|
||||
const double w = Bt(dy,qy);
|
||||
BDGu[tidz][dy][qx] += w * DGu[tidz][qy][qx];
|
||||
}
|
||||
}
|
||||
@@ -382,7 +372,7 @@ void SmemPAConvectionApply2D(const int ne,
|
||||
double BBDGu = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double w = Bt(dx,qx);
|
||||
const double w = Bt(dx,qx);
|
||||
BBDGu += w * BDGu[tidz][dy][qx];
|
||||
}
|
||||
y(dx,dy,e) += BBDGu;
|
||||
@@ -446,8 +436,8 @@ void PAConvectionApply3D(const int ne,
|
||||
Gu[dz][dy][qx] = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double x = u[dz][dy][dx];
|
||||
Bu[dz][dy][qx] += bx * x;
|
||||
Gu[dz][dy][qx] += gx * x;
|
||||
@@ -469,8 +459,8 @@ void PAConvectionApply3D(const int ne,
|
||||
BGu[dz][qy][qx] = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
BBu[dz][qy][qx] += bx * Bu[dz][dy][qx];
|
||||
GBu[dz][qy][qx] += gx * Bu[dz][dy][qx];
|
||||
BGu[dz][qy][qx] += bx * Gu[dz][dy][qx];
|
||||
@@ -492,8 +482,8 @@ void PAConvectionApply3D(const int ne,
|
||||
BBGu[qz][qy][qx] = 0.0;
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
const double bx = B(qz,dz);
|
||||
const double gx = G(qz,dz);
|
||||
const double bx = B(qz,dz);
|
||||
const double gx = G(qz,dz);
|
||||
GBBu[qz][qy][qx] += gx * BBu[dz][qy][qx];
|
||||
BGBu[qz][qy][qx] += bx * GBu[dz][qy][qx];
|
||||
BBGu[qz][qy][qx] += bx * BGu[dz][qy][qx];
|
||||
@@ -531,7 +521,7 @@ void PAConvectionApply3D(const int ne,
|
||||
BDGu[dz][qy][qx] = 0.0;
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const double w = Bt(dz,qz);
|
||||
const double w = Bt(dz,qz);
|
||||
BDGu[dz][qy][qx] += w * DGu[qz][qy][qx];
|
||||
}
|
||||
}
|
||||
@@ -547,7 +537,7 @@ void PAConvectionApply3D(const int ne,
|
||||
BBDGu[dz][dy][qx] = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double w = Bt(dy,qy);
|
||||
const double w = Bt(dy,qy);
|
||||
BBDGu[dz][dy][qx] += w * BDGu[dz][qy][qx];
|
||||
}
|
||||
}
|
||||
@@ -562,7 +552,7 @@ void PAConvectionApply3D(const int ne,
|
||||
double BBBDGu = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double w = Bt(dx,qx);
|
||||
const double w = Bt(dx,qx);
|
||||
BBBDGu += w * BBDGu[dz][dy][qx];
|
||||
}
|
||||
y(dx,dy,dz,e) += BBBDGu;
|
||||
@@ -635,8 +625,8 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double Gu_ = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double x = u[dz][dy][dx];
|
||||
Bu_ += bx * x;
|
||||
Gu_ += gx * x;
|
||||
@@ -661,8 +651,8 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double BGu_ = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
BBu_ += bx * Bu[dz][dy][qx];
|
||||
GBu_ += gx * Bu[dz][dy][qx];
|
||||
BGu_ += bx * Gu[dz][dy][qx];
|
||||
@@ -688,8 +678,8 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double BBGu_ = 0.0;
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
const double bx = B(qz,dz);
|
||||
const double gx = G(qz,dz);
|
||||
const double bx = B(qz,dz);
|
||||
const double gx = G(qz,dz);
|
||||
GBBu_ += gx * BBu[dz][qy][qx];
|
||||
BGBu_ += bx * GBu[dz][qy][qx];
|
||||
BBGu_ += bx * BGu[dz][qy][qx];
|
||||
@@ -731,7 +721,7 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double BDGu_ = 0.0;
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const double w = Bt(dz,qz);
|
||||
const double w = Bt(dz,qz);
|
||||
BDGu_ += w * DGu[qz][qy][qx];
|
||||
}
|
||||
BDGu[dz][qy][qx] = BDGu_;
|
||||
@@ -749,7 +739,7 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double BBDGu_ = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double w = Bt(dy,qy);
|
||||
const double w = Bt(dy,qy);
|
||||
BBDGu_ += w * BDGu[dz][qy][qx];
|
||||
}
|
||||
BBDGu[dz][dy][qx] = BBDGu_;
|
||||
@@ -766,7 +756,7 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double BBBDGu = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double w = Bt(dx,qx);
|
||||
const double w = Bt(dx,qx);
|
||||
BBBDGu += w * BBDGu[dz][dy][qx];
|
||||
}
|
||||
y(dx,dy,dz,e) = BBBDGu;
|
||||
@@ -776,117 +766,6 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
});
|
||||
}
|
||||
|
||||
template<int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0, int T_MAX = 0>
|
||||
static void QEvalVGF2D(const int NE,
|
||||
const double *b_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 1,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto X = Reshape(x_, D1D, D1D, VDIM, NE);
|
||||
auto C = Reshape(y_, VDIM, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
|
||||
{
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
mfem::kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
|
||||
MFEM_SHARED double DD[NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[NBZ][MQ1*MQ1];
|
||||
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
mfem::kernels::LoadX<MD1,NBZ>(e,D1D,c,X,DD);
|
||||
mfem::kernels::EvalX<MD1,MQ1,NBZ>(D1D,Q1D,B,DD,DQ);
|
||||
mfem::kernels::EvalY<MD1,MQ1,NBZ>(D1D,Q1D,B,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
double G;
|
||||
mfem::kernels::PullEval<MQ1,NBZ>(qx,qy,QQ,G);
|
||||
C(c,qx,qy,e) = G;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0, int T_MAX = 0>
|
||||
static void QEvalVGF3D(const int NE,
|
||||
const double *b_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 1,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto X = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
|
||||
auto C = Reshape(y_, VDIM, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
mfem::kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
|
||||
MFEM_SHARED double DDD[MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[MQ1*MQ1*MQ1];
|
||||
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
mfem::kernels::LoadX<MD1>(e,D1D,c,X,DDD);
|
||||
mfem::kernels::EvalX<MD1,MQ1>(D1D,Q1D,B,DDD,DDQ);
|
||||
mfem::kernels::EvalY<MD1,MQ1>(D1D,Q1D,B,DDQ,DQQ);
|
||||
mfem::kernels::EvalZ<MD1,MQ1>(D1D,Q1D,B,DQQ,QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
double G;
|
||||
mfem::kernels::PullEval<MQ1>(qx,qy,qz,QQQ,G);
|
||||
C(c,qx,qy,qz,e) = G;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
// Assumes tensor-product elements
|
||||
@@ -899,90 +778,16 @@ void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
const int nq = ir->GetNPoints();
|
||||
dim = mesh->Dimension();
|
||||
ne = fes.GetNE();
|
||||
const DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
const MemoryType temp_type = Device::GetDeviceMemoryType() == MemoryType::DEVICE_UMPIRE
|
||||
? MemoryType::DEVICE_UMPIRE_2 : Device::GetDeviceMemoryType();
|
||||
#else
|
||||
const MemoryType temp_type = Device::GetDeviceMemoryType();
|
||||
#endif
|
||||
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mode, temp_type);
|
||||
maps = &el.GetDofToQuad(*ir, mode);
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
|
||||
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
pa_data.SetSize(symmDims * nq * ne, temp_type);
|
||||
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
|
||||
Vector vel;
|
||||
if (VectorConstantCoefficient *cQ =
|
||||
dynamic_cast<VectorConstantCoefficient*>(Q))
|
||||
if (VectorConstantCoefficient *cQ = dynamic_cast<VectorConstantCoefficient*>(Q))
|
||||
{
|
||||
vel = cQ->GetVec();
|
||||
}
|
||||
else if (VectorGridFunctionCoefficient *vgfQ =
|
||||
dynamic_cast<VectorGridFunctionCoefficient*>(Q))
|
||||
{
|
||||
Vector xe;
|
||||
vel.SetSize(dim * nq * ne, temp_type);
|
||||
|
||||
const GridFunction *gf = vgfQ->GetGridFunction();
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
const FiniteElementSpace &gf_fes = *gf->FESpace();
|
||||
|
||||
const int vdim = gf_fes.GetVDim();
|
||||
const Operator *R = gf_fes.GetElementRestriction(ordering);
|
||||
const FiniteElement &el_gf = *gf_fes.GetFE(0);
|
||||
const DofToQuad *maps_gf = &el_gf.GetDofToQuad(*ir, mode);
|
||||
const int D1D = maps_gf->ndof;
|
||||
const int Q1D = maps_gf->nqpt;
|
||||
|
||||
MFEM_VERIFY(R,"");
|
||||
MFEM_VERIFY(vdim == dim, "");
|
||||
MFEM_VERIFY(dim==2 || dim==3,"");
|
||||
|
||||
xe.SetSize(R->Height(), Device::GetMemoryType());
|
||||
xe.UseDevice(true);
|
||||
R->Mult(*gf, xe);
|
||||
|
||||
const auto B = maps_gf->B.Read();
|
||||
const auto x = xe.Read();
|
||||
auto y = vel.Write();
|
||||
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x22: QEvalVGF2D<2,2,2>(ne,B,x,y); break;
|
||||
case 0x33: QEvalVGF2D<2,3,3>(ne,B,x,y); break;
|
||||
case 0x34: QEvalVGF2D<2,3,4>(ne,B,x,y); break;
|
||||
default:
|
||||
{
|
||||
constexpr int MAX_DQ = 8;
|
||||
MFEM_VERIFY(D1D <= MAX_DQ, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_DQ, "");
|
||||
QEvalVGF2D<0,0,0,MAX_DQ>(ne,B,x,y,vdim,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x23: QEvalVGF3D<3,2,3>(ne,B,x,y); break;
|
||||
case 0x34: QEvalVGF3D<3,3,4>(ne,B,x,y); break;
|
||||
case 0x35: QEvalVGF3D<3,3,5>(ne,B,x,y); break;
|
||||
case 0x46: QEvalVGF3D<3,4,6>(ne,B,x,y); break;
|
||||
case 0x48: QEvalVGF3D<3,4,8>(ne,B,x,y); break;
|
||||
default:
|
||||
{
|
||||
constexpr int MAX_DQ = 6;
|
||||
MFEM_VERIFY(D1D <= MAX_DQ, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_DQ, "");
|
||||
QEvalVGF3D<0,0,0,MAX_DQ>(ne,B,x,y,vdim,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (VectorQuadratureFunctionCoefficient* cQ =
|
||||
dynamic_cast<VectorQuadratureFunctionCoefficient*>(Q))
|
||||
{
|
||||
@@ -1036,12 +841,9 @@ static void PAConvectionApply(const int dim,
|
||||
switch ((D1D << 4 ) | Q1D)
|
||||
{
|
||||
case 0x22: return SmemPAConvectionApply2D<2,2,8>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x33: return SmemPAConvectionApply2D<3,3,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x34: return SmemPAConvectionApply2D<3,4,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x44: return SmemPAConvectionApply2D<4,4,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x46: return SmemPAConvectionApply2D<4,6,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x33: return SmemPAConvectionApply2D<3,3,3>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x44: return SmemPAConvectionApply2D<4,4,2>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x55: return SmemPAConvectionApply2D<5,5,2>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x58: return SmemPAConvectionApply2D<5,8,2>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x66: return SmemPAConvectionApply2D<6,6,1>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x77: return SmemPAConvectionApply2D<7,7,1>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x88: return SmemPAConvectionApply2D<8,8,1>(NE,B,G,Bt,Gt,op,x,y);
|
||||
@@ -1054,12 +856,8 @@ static void PAConvectionApply(const int dim,
|
||||
switch ((D1D << 4 ) | Q1D)
|
||||
{
|
||||
case 0x23: return SmemPAConvectionApply3D<2,3>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x24: return SmemPAConvectionApply3D<2,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x26: return SmemPAConvectionApply3D<2,6>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x34: return SmemPAConvectionApply3D<3,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x35: return SmemPAConvectionApply3D<3,5>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x45: return SmemPAConvectionApply3D<4,5>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x48: return SmemPAConvectionApply3D<4,8>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x56: return SmemPAConvectionApply3D<5,6>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x67: return SmemPAConvectionApply3D<6,7>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x78: return SmemPAConvectionApply3D<7,8>(NE,B,G,Bt,Gt,op,x,y);
|
||||
|
||||
@@ -170,53 +170,47 @@ static void PADiffusionSetup3D(const int Q1D,
|
||||
const Vector &c,
|
||||
Vector &d)
|
||||
{
|
||||
const int NQ = Q1D*Q1D*Q1D;
|
||||
const bool const_c = c.Size() == 1;
|
||||
const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
|
||||
const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
|
||||
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1) :
|
||||
Reshape(c.Read(), Q1D,Q1D,Q1D,NE);
|
||||
auto D = Reshape(d.Write(), Q1D,Q1D,Q1D, 6, NE);
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
auto W = w.Read();
|
||||
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
|
||||
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
|
||||
auto D = Reshape(d.Write(), NQ, 6, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
const double J11 = J(qx,qy,qz,0,0,e);
|
||||
const double J21 = J(qx,qy,qz,1,0,e);
|
||||
const double J31 = J(qx,qy,qz,2,0,e);
|
||||
const double J12 = J(qx,qy,qz,0,1,e);
|
||||
const double J22 = J(qx,qy,qz,1,1,e);
|
||||
const double J32 = J(qx,qy,qz,2,1,e);
|
||||
const double J13 = J(qx,qy,qz,0,2,e);
|
||||
const double J23 = J(qx,qy,qz,1,2,e);
|
||||
const double J33 = J(qx,qy,qz,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double coeff = const_c ? C(0,0,0,0) : C(qx,qy,qz,e);
|
||||
const double c_detJ = W(qx,qy,qz) * coeff / detJ;
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
const double A12 = (J32 * J13) - (J12 * J33);
|
||||
const double A13 = (J12 * J23) - (J22 * J13);
|
||||
const double A21 = (J31 * J23) - (J21 * J33);
|
||||
const double A22 = (J11 * J33) - (J13 * J31);
|
||||
const double A23 = (J21 * J13) - (J11 * J23);
|
||||
const double A31 = (J21 * J32) - (J31 * J22);
|
||||
const double A32 = (J31 * J12) - (J11 * J32);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
|
||||
D(qx,qy,qz,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
|
||||
D(qx,qy,qz,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
|
||||
D(qx,qy,qz,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
|
||||
D(qx,qy,qz,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
|
||||
D(qx,qy,qz,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
|
||||
D(qx,qy,qz,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
|
||||
}
|
||||
}
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J31 = J(q,2,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double J32 = J(q,2,1,e);
|
||||
const double J13 = J(q,0,2,e);
|
||||
const double J23 = J(q,1,2,e);
|
||||
const double J33 = J(q,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
const double c_detJ = W[q] * coeff / detJ;
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
const double A12 = (J32 * J13) - (J12 * J33);
|
||||
const double A13 = (J12 * J23) - (J22 * J13);
|
||||
const double A21 = (J31 * J23) - (J21 * J33);
|
||||
const double A22 = (J11 * J33) - (J13 * J31);
|
||||
const double A23 = (J21 * J13) - (J11 * J23);
|
||||
const double A31 = (J21 * J32) - (J31 * J22);
|
||||
const double A32 = (J31 * J12) - (J11 * J32);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
|
||||
D(q,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
|
||||
D(q,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
|
||||
D(q,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
|
||||
D(q,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
|
||||
D(q,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
|
||||
D(q,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -282,10 +276,9 @@ void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
const int nq = ir->GetNPoints();
|
||||
dim = mesh->Dimension();
|
||||
ne = fes.GetNE();
|
||||
const DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mode);
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
|
||||
const int sdim = mesh->SpaceDimension();
|
||||
maps = &el.GetDofToQuad(*ir, mode);
|
||||
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
pa_data.SetSize(symmDims * nq * ne, Device::GetDeviceMemoryType());
|
||||
@@ -740,7 +733,6 @@ static void PADiffusionAssembleDiagonal(const int dim,
|
||||
case 0x23: return SmemPADiffusionDiagonal3D<2,3>(NE,B,G,D,Y);
|
||||
case 0x34: return SmemPADiffusionDiagonal3D<3,4>(NE,B,G,D,Y);
|
||||
case 0x45: return SmemPADiffusionDiagonal3D<4,5>(NE,B,G,D,Y);
|
||||
case 0x46: return SmemPADiffusionDiagonal3D<4,6>(NE,B,G,D,Y);
|
||||
case 0x56: return SmemPADiffusionDiagonal3D<5,6>(NE,B,G,D,Y);
|
||||
case 0x67: return SmemPADiffusionDiagonal3D<6,7>(NE,B,G,D,Y);
|
||||
case 0x78: return SmemPADiffusionDiagonal3D<7,8>(NE,B,G,D,Y);
|
||||
@@ -1701,7 +1693,6 @@ static void PADiffusionApply(const int dim,
|
||||
switch (ID)
|
||||
{
|
||||
case 0x23: return SmemPADiffusionApply3D<2,3>(NE,B,G,D,X,Y);
|
||||
case 0x24: return SmemPADiffusionApply3D<2,4>(NE,B,G,D,X,Y);
|
||||
case 0x34: return SmemPADiffusionApply3D<3,4>(NE,B,G,D,X,Y);
|
||||
case 0x45: return SmemPADiffusionApply3D<4,5>(NE,B,G,D,X,Y);
|
||||
case 0x46: return SmemPADiffusionApply3D<4,6>(NE,B,G,D,X,Y);
|
||||
|
||||
+31
-74
@@ -25,7 +25,6 @@ namespace mfem
|
||||
|
||||
void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
{
|
||||
|
||||
// Assuming the same element type
|
||||
fespace = &fes;
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
@@ -46,38 +45,22 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
dim = mesh->Dimension();
|
||||
ne = fes.GetMesh()->GetNE();
|
||||
nq = ir->GetNPoints();
|
||||
const DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
const int flags = GeometricFactors::JACOBIANS |
|
||||
GeometricFactors::COORDINATES;
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
const MemoryType temp_type = Device::GetDeviceMemoryType() == MemoryType::DEVICE_UMPIRE
|
||||
? MemoryType::DEVICE_UMPIRE_2 : Device::GetDeviceMemoryType();
|
||||
#else
|
||||
const MemoryType temp_type = Device::GetDeviceMemoryType();
|
||||
#endif
|
||||
geom = mesh->GetGeometricFactors(*ir, flags, mode, temp_type);
|
||||
maps = &el.GetDofToQuad(*ir, mode);
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::COORDINATES |
|
||||
GeometricFactors::JACOBIANS);
|
||||
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
pa_data.SetSize(ne*nq, Device::GetDeviceMemoryType());
|
||||
Vector *coeff{nullptr};
|
||||
bool own_coeff{true};
|
||||
Vector coeff;
|
||||
if (Q == nullptr)
|
||||
{
|
||||
coeff = new Vector;
|
||||
coeff->SetSize(1);
|
||||
(*coeff)(0) = 1.0;
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = 1.0;
|
||||
}
|
||||
else if (ConstantCoefficient* cQ = dynamic_cast<ConstantCoefficient*>(Q))
|
||||
{
|
||||
coeff = new Vector;
|
||||
coeff->SetSize(1);
|
||||
(*coeff)(0) = cQ->constant;
|
||||
}
|
||||
else if (QuadratureCoefficient* cQ = dynamic_cast<QuadratureCoefficient*>(Q))
|
||||
{
|
||||
coeff = cQ->Data();
|
||||
own_coeff = false;
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = cQ->constant;
|
||||
}
|
||||
else if (QuadratureFunctionCoefficient* cQ =
|
||||
dynamic_cast<QuadratureFunctionCoefficient*>(Q))
|
||||
@@ -90,13 +73,12 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
qFun.Read();
|
||||
coeff->MakeRef(const_cast<QuadratureFunction &>(qFun),0);
|
||||
coeff.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
|
||||
}
|
||||
else
|
||||
{
|
||||
coeff = new Vector;
|
||||
coeff->SetSize(nq * ne);
|
||||
auto C = Reshape(coeff->HostWrite(), nq, ne);
|
||||
coeff.SetSize(nq * ne);
|
||||
auto C = Reshape(coeff.HostWrite(), nq, ne);
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
ElementTransformation& T = *fes.GetElementTransformation(e);
|
||||
@@ -111,11 +93,11 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
{
|
||||
const int NE = ne;
|
||||
const int NQ = nq;
|
||||
const bool const_c = coeff->Size() == 1;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
auto w = ir->GetWeights().Read();
|
||||
auto J = Reshape(geom->J.Read(), NQ,2,2,NE);
|
||||
auto C =
|
||||
const_c ? Reshape(coeff->Read(), 1,1) : Reshape(coeff->Read(), NQ,NE);
|
||||
const_c ? Reshape(coeff.Read(), 1,1) : Reshape(coeff.Read(), NQ,NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
@@ -134,43 +116,28 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
if (dim==3)
|
||||
{
|
||||
const int NE = ne;
|
||||
const int Q1D = quad1D;
|
||||
const bool const_c = coeff->Size() == 1;
|
||||
const auto W = Reshape(ir->GetWeights().Read(),Q1D,Q1D,Q1D);
|
||||
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,Q1D,3,3,NE);
|
||||
const auto C = const_c ?
|
||||
Reshape(coeff->Read(), 1,1,1,1) :
|
||||
Reshape(coeff->Read(), Q1D,Q1D,Q1D,NE);
|
||||
auto V = Reshape(pa_data.Write(), Q1D,Q1D,Q1D,NE);
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
const int NQ = nq;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
auto W = ir->GetWeights().Read();
|
||||
auto J = Reshape(geom->J.Read(), NQ,3,3,NE);
|
||||
auto C =
|
||||
const_c ? Reshape(coeff.Read(), 1,1) : Reshape(coeff.Read(), NQ,NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ,NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
const double J11 = J(qx,qy,qz,0,0,e);
|
||||
const double J12 = J(qx,qy,qz,0,1,e);
|
||||
const double J13 = J(qx,qy,qz,0,2,e);
|
||||
const double J21 = J(qx,qy,qz,1,0,e);
|
||||
const double J22 = J(qx,qy,qz,1,1,e);
|
||||
const double J23 = J(qx,qy,qz,1,2,e);
|
||||
const double J31 = J(qx,qy,qz,2,0,e);
|
||||
const double J32 = J(qx,qy,qz,2,1,e);
|
||||
const double J33 = J(qx,qy,qz,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double coeff = const_c ? C(0,0,0,0) : C(qx,qy,qz,e);
|
||||
V(qx,qy,qz,e) = W(qx,qy,qz) * coeff * detJ;
|
||||
}
|
||||
}
|
||||
const double J11 = J(q,0,0,e), J12 = J(q,0,1,e), J13 = J(q,0,2,e);
|
||||
const double J21 = J(q,1,0,e), J22 = J(q,1,1,e), J23 = J(q,1,2,e);
|
||||
const double J31 = J(q,2,0,e), J32 = J(q,2,1,e), J33 = J(q,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
v(q,e) = W[q] * coeff * detJ;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (own_coeff) { delete coeff; }
|
||||
}
|
||||
|
||||
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
@@ -472,12 +439,8 @@ static void PAMassAssembleDiagonal(const int dim, const int D1D,
|
||||
switch ((D1D << 4 ) | Q1D)
|
||||
{
|
||||
case 0x23: return SmemPAMassAssembleDiagonal3D<2,3>(NE,B,D,Y);
|
||||
case 0x24: return SmemPAMassAssembleDiagonal3D<2,4>(NE,B,D,Y);
|
||||
case 0x26: return SmemPAMassAssembleDiagonal3D<2,6>(NE,B,D,Y);
|
||||
case 0x34: return SmemPAMassAssembleDiagonal3D<3,4>(NE,B,D,Y);
|
||||
case 0x35: return SmemPAMassAssembleDiagonal3D<3,5>(NE,B,D,Y);
|
||||
case 0x45: return SmemPAMassAssembleDiagonal3D<4,5>(NE,B,D,Y);
|
||||
case 0x48: return SmemPAMassAssembleDiagonal3D<4,8>(NE,B,D,Y);
|
||||
case 0x56: return SmemPAMassAssembleDiagonal3D<5,6>(NE,B,D,Y);
|
||||
case 0x67: return SmemPAMassAssembleDiagonal3D<6,7>(NE,B,D,Y);
|
||||
case 0x78: return SmemPAMassAssembleDiagonal3D<7,8>(NE,B,D,Y);
|
||||
@@ -1211,13 +1174,10 @@ static void PAMassApply(const int dim,
|
||||
case 0x24: return SmemPAMassApply2D<2,4,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x33: return SmemPAMassApply2D<3,3,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x34: return SmemPAMassApply2D<3,4,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x35: return SmemPAMassApply2D<3,5,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x36: return SmemPAMassApply2D<3,6,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x44: return SmemPAMassApply2D<4,4,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x46: return SmemPAMassApply2D<4,6,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x48: return SmemPAMassApply2D<4,8,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x55: return SmemPAMassApply2D<5,5,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x57: return SmemPAMassApply2D<5,7,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x58: return SmemPAMassApply2D<5,8,2>(NE,B,Bt,D,X,Y);
|
||||
case 0x66: return SmemPAMassApply2D<6,6,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x77: return SmemPAMassApply2D<7,7,4>(NE,B,Bt,D,X,Y);
|
||||
@@ -1225,7 +1185,6 @@ static void PAMassApply(const int dim,
|
||||
case 0x99: return SmemPAMassApply2D<9,9,2>(NE,B,Bt,D,X,Y);
|
||||
default: return PAMassApply2D(NE,B,Bt,D,X,Y,D1D,Q1D);
|
||||
}
|
||||
mfem::out << "Unknown 2D kernel 0x" << std::hex << id << std::endl;
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
@@ -1234,9 +1193,7 @@ static void PAMassApply(const int dim,
|
||||
case 0x23: return SmemPAMassApply3D<2,3>(NE,B,Bt,D,X,Y);
|
||||
case 0x24: return SmemPAMassApply3D<2,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x34: return SmemPAMassApply3D<3,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x35: return SmemPAMassApply3D<3,5>(NE,B,Bt,D,X,Y);
|
||||
case 0x36: return SmemPAMassApply3D<3,6>(NE,B,Bt,D,X,Y);
|
||||
case 0x37: return SmemPAMassApply3D<3,7>(NE,B,Bt,D,X,Y);
|
||||
case 0x45: return SmemPAMassApply3D<4,5>(NE,B,Bt,D,X,Y);
|
||||
case 0x46: return SmemPAMassApply3D<4,6>(NE,B,Bt,D,X,Y);
|
||||
case 0x48: return SmemPAMassApply3D<4,8>(NE,B,Bt,D,X,Y);
|
||||
@@ -1248,8 +1205,8 @@ static void PAMassApply(const int dim,
|
||||
case 0x9A: return SmemPAMassApply3D<9,10>(NE,B,Bt,D,X,Y);
|
||||
default: return PAMassApply3D(NE,B,Bt,D,X,Y,D1D,Q1D);
|
||||
}
|
||||
mfem::out << "Unknown 3D kernel 0x" << std::hex << id << std::endl;
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
// Implementation of Coefficient class
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
@@ -22,13 +21,6 @@ namespace mfem
|
||||
|
||||
using namespace std;
|
||||
|
||||
double QuadratureCoefficient::Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
auto coeff = mfem::Reshape(qData->HostRead(), nip, NE);
|
||||
return coeff(ip.index, T.ElementNo);
|
||||
}
|
||||
|
||||
double PWConstCoefficient::Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
|
||||
@@ -87,33 +87,6 @@ public:
|
||||
{ return (constant); }
|
||||
};
|
||||
|
||||
|
||||
/// class for quadrature coefficient
|
||||
class QuadratureCoefficient : public Coefficient
|
||||
{
|
||||
|
||||
private:
|
||||
const int nip;
|
||||
const int NE;
|
||||
public:
|
||||
Vector *qData{nullptr};
|
||||
|
||||
//Set external data
|
||||
QuadratureCoefficient(Vector *Data, int in_nip, int in_NE)
|
||||
: qData(Data), nip(in_nip), NE(in_NE)
|
||||
{ }
|
||||
|
||||
virtual double Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
Vector *Data()
|
||||
{
|
||||
return qData;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// class for piecewise constant coefficient
|
||||
/** @brief A piecewise constant coefficient with the constants keyed
|
||||
off the element attribute numbers. */
|
||||
class PWConstCoefficient : public Coefficient
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_tools.hpp"
|
||||
#include "gslib.hpp"
|
||||
#include "adnonlininteg.hpp"
|
||||
#include "restriction.hpp"
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "quadinterpolator_face.hpp"
|
||||
|
||||
+6
-6
@@ -944,7 +944,7 @@ const Operator *FiniteElementSpace::GetFaceRestriction(
|
||||
}
|
||||
|
||||
const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
|
||||
const IntegrationRule &ir, const DofToQuad::Mode mode) const
|
||||
const IntegrationRule &ir) const
|
||||
{
|
||||
for (int i = 0; i < E2Q_array.Size(); i++)
|
||||
{
|
||||
@@ -952,13 +952,13 @@ const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
|
||||
if (qi->IntRule == &ir) { return qi; }
|
||||
}
|
||||
|
||||
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, ir, mode);
|
||||
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, ir);
|
||||
E2Q_array.Append(qi);
|
||||
return qi;
|
||||
}
|
||||
|
||||
const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
|
||||
const QuadratureSpace &qs, const DofToQuad::Mode mode) const
|
||||
const QuadratureSpace &qs) const
|
||||
{
|
||||
for (int i = 0; i < E2Q_array.Size(); i++)
|
||||
{
|
||||
@@ -966,7 +966,7 @@ const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
|
||||
if (qi->qspace == &qs) { return qi; }
|
||||
}
|
||||
|
||||
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, qs, mode);
|
||||
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, qs);
|
||||
E2Q_array.Append(qi);
|
||||
return qi;
|
||||
}
|
||||
@@ -983,8 +983,8 @@ const FaceQuadratureInterpolator
|
||||
if (qi->IntRule == &ir) { return qi; }
|
||||
}
|
||||
|
||||
FaceQuadratureInterpolator *qi =
|
||||
new FaceQuadratureInterpolator(*this, ir, type);
|
||||
FaceQuadratureInterpolator *qi = new FaceQuadratureInterpolator(*this, ir,
|
||||
type);
|
||||
E2IFQ_array.Append(qi);
|
||||
return qi;
|
||||
}
|
||||
|
||||
+2
-2
@@ -367,7 +367,7 @@ public:
|
||||
All elements will use the same IntegrationRule, @a ir as the target
|
||||
quadrature points. */
|
||||
const QuadratureInterpolator *GetQuadratureInterpolator(
|
||||
const IntegrationRule &ir, const DofToQuad::Mode = DofToQuad::FULL) const;
|
||||
const IntegrationRule &ir) const;
|
||||
|
||||
/** @brief Return a QuadratureInterpolator that interpolates E-vectors to
|
||||
quadrature point values and/or derivatives (Q-vectors). */
|
||||
@@ -378,7 +378,7 @@ public:
|
||||
The target quadrature points in the elements are described by the given
|
||||
QuadratureSpace, @a qs. */
|
||||
const QuadratureInterpolator *GetQuadratureInterpolator(
|
||||
const QuadratureSpace &qs, const DofToQuad::Mode = DofToQuad::FULL) const;
|
||||
const QuadratureSpace &qs) const;
|
||||
|
||||
/** @brief Return a FaceQuadratureInterpolator that interpolates E-vectors to
|
||||
quadrature point values and/or derivatives (Q-vectors). */
|
||||
|
||||
-1465
File diff suppressed because it is too large
Load Diff
+10
-52
@@ -10,7 +10,6 @@
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -28,7 +27,7 @@ void NonlinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
|
||||
// This is the default behavior.
|
||||
break;
|
||||
case AssemblyLevel::PARTIAL:
|
||||
ext = new PANonlinearForm(this);
|
||||
ext = new PANonlinearFormExtension(this);
|
||||
break;
|
||||
default:
|
||||
mfem_error("Unknown assembly level for this form.");
|
||||
@@ -81,13 +80,6 @@ void NonlinearForm::SetEssentialVDofs(const Array<int> &ess_vdofs_list)
|
||||
|
||||
double NonlinearForm::GetGridFunctionEnergy(const Vector &x) const
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
MFEM_VERIFY(!fnfi.Size(), "Interior faces terms not yet implemented!");
|
||||
MFEM_VERIFY(!bfnfi.Size(), "Boundary face terms not yet implemented!");
|
||||
return ext->GetGridFunctionEnergy(x);
|
||||
}
|
||||
|
||||
Array<int> vdofs;
|
||||
Vector el_x;
|
||||
const FiniteElement *fe;
|
||||
@@ -146,14 +138,6 @@ void NonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
if (ext)
|
||||
{
|
||||
ext->Mult(px, py);
|
||||
if (Serial())
|
||||
{
|
||||
if (cP) { cP->MultTranspose(py, y); }
|
||||
const int N = ess_tdof_list.Size();
|
||||
const auto tdof = ess_tdof_list.Read();
|
||||
auto Y = y.ReadWrite();
|
||||
MFEM_FORALL(i, N, Y[tdof[i]] = 0.0; );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -280,16 +264,7 @@ Operator &NonlinearForm::GetGradient(const Vector &x) const
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
Operator &grad = ext->GetGradient(Prolongate(x));
|
||||
hGrad.Reset(&grad, false);
|
||||
if (Serial())
|
||||
{
|
||||
Operator *Gop;
|
||||
if (cP) { hGrad.Reset(new RAPOperator(*cP, grad, *cP)); }
|
||||
hGrad.Ptr()->Operator::FormSystemOperator(ess_tdof_list, Gop);
|
||||
hGrad.Reset(Gop);
|
||||
}
|
||||
return *hGrad.Ptr();
|
||||
MFEM_ABORT("Not yet implemented!");
|
||||
}
|
||||
|
||||
const int skip_zeros = 0;
|
||||
@@ -451,31 +426,7 @@ void NonlinearForm::Update()
|
||||
|
||||
void NonlinearForm::Setup()
|
||||
{
|
||||
if (ext) { return ext->Setup(); }
|
||||
}
|
||||
|
||||
void NonlinearForm::AssembleGradientDiagonal(Vector &diag) const
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
MFEM_ASSERT(diag.Size() == fes->GetTrueVSize(),
|
||||
"Vector for holding diagonal has wrong size!");
|
||||
const Operator *P = fes->GetProlongationMatrix();
|
||||
if (!IsIdentityProlongation(P))
|
||||
{
|
||||
Vector local_diag(P->Height());
|
||||
ext->AssembleGradientDiagonal(local_diag);
|
||||
P->MultTranspose(local_diag, diag);
|
||||
}
|
||||
else
|
||||
{
|
||||
ext->AssembleGradientDiagonal(diag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Not implemented. Can be obtained through GetGradient().");
|
||||
}
|
||||
if (ext) { return ext->AssemblePA(); }
|
||||
}
|
||||
|
||||
NonlinearForm::~NonlinearForm()
|
||||
@@ -630,6 +581,13 @@ double BlockNonlinearForm::GetEnergyBlocked(const BlockVector &bx) const
|
||||
}
|
||||
}
|
||||
|
||||
//free the allocated memory
|
||||
for (int i=0; i<fes.Size(); ++i)
|
||||
{
|
||||
delete el_x[i];
|
||||
delete vdofs[i];
|
||||
}
|
||||
|
||||
if (fnfi.Size())
|
||||
{
|
||||
MFEM_ABORT("TODO: add energy contribution from interior face terms");
|
||||
|
||||
@@ -45,7 +45,6 @@ protected:
|
||||
Array<Array<int>*> bfnfi_marker; // not owned
|
||||
|
||||
mutable SparseMatrix *Grad, *cGrad; // owned
|
||||
mutable OperatorHandle hGrad;
|
||||
|
||||
/// A list of all essential true dofs
|
||||
Array<int> ess_tdof_list;
|
||||
@@ -166,15 +165,6 @@ public:
|
||||
/// Setup the NonlinearForm
|
||||
virtual void Setup();
|
||||
|
||||
/** @brief Assemble the diagonal of the gradient into diag
|
||||
|
||||
For adaptively refined meshes, this returns P^T d_e, where d_e is the
|
||||
locally assembled diagonal on each element and P^T is the transpose of
|
||||
the conforming prolongation. In general this is not the correct diagonal
|
||||
for an AMR mesh. */
|
||||
void AssembleGradientDiagonal(Vector &diag) const;
|
||||
|
||||
|
||||
/// Get the finite element space prolongation matrix
|
||||
virtual const Operator *GetProlongation() const { return P; }
|
||||
/// Get the finite element space restriction matrix
|
||||
|
||||
+38
-77
@@ -13,101 +13,62 @@
|
||||
// PABilinearFormExtension and MFBilinearFormExtension.
|
||||
|
||||
#include "nonlinearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
NonlinearFormExtension::NonlinearFormExtension(const NonlinearForm *nlf)
|
||||
: Operator(nlf->FESpace()->GetTrueVSize()), nlf(nlf) { }
|
||||
|
||||
PANonlinearForm::PANonlinearForm(NonlinearForm *nlf):
|
||||
NonlinearFormExtension(nlf),
|
||||
x_grad(NULL),
|
||||
fes(*nlf->FESpace()),
|
||||
dnfi(*nlf->GetDNFI()),
|
||||
R(fes.GetElementRestriction(ElementDofOrdering::LEXICOGRAPHIC))
|
||||
NonlinearFormExtension::NonlinearFormExtension(NonlinearForm *form)
|
||||
: Operator(form->FESpace()->GetTrueVSize()), n(form)
|
||||
{
|
||||
MFEM_VERIFY(R, "Not yet implemented!");
|
||||
xe.SetSize(R->Height(), Device::GetMemoryType());
|
||||
ye.SetSize(R->Height(), Device::GetMemoryType());
|
||||
ye.UseDevice(true);
|
||||
// empty
|
||||
}
|
||||
|
||||
double PANonlinearForm::GetGridFunctionEnergy(const Vector &x) const
|
||||
PANonlinearFormExtension::PANonlinearFormExtension(NonlinearForm *form):
|
||||
NonlinearFormExtension(form), fes(*form->FESpace())
|
||||
{
|
||||
double energy = 0.0;
|
||||
|
||||
R->Mult(x, xe);
|
||||
for (int i = 0; i < dnfi.Size(); i++)
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
elem_restrict_lex = fes.GetElementRestriction(ordering);
|
||||
if (elem_restrict_lex)
|
||||
{
|
||||
energy += dnfi[i]->GetGridFunctionEnergyPA(xe);
|
||||
localX.SetSize(elem_restrict_lex->Height(), Device::GetMemoryType());
|
||||
localY.SetSize(elem_restrict_lex->Height(), Device::GetMemoryType());
|
||||
localY.UseDevice(true); // ensure 'localY = 0.0' is done on device
|
||||
}
|
||||
return energy;
|
||||
}
|
||||
|
||||
void PANonlinearForm::Setup()
|
||||
void PANonlinearFormExtension::AssemblePA()
|
||||
{
|
||||
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AssemblePA(fes); }
|
||||
}
|
||||
|
||||
void PANonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
ye = 0.0;
|
||||
R->Mult(x, xe);
|
||||
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AddMultPA(xe, ye); }
|
||||
R->MultTranspose(ye, y);
|
||||
}
|
||||
|
||||
void PANonlinearForm::AssembleGradientDiagonal(Vector &diag) const
|
||||
{
|
||||
MFEM_VERIFY(x_grad, "GetGradient() has not been called");
|
||||
R->Mult(*x_grad, xe);
|
||||
|
||||
ye = 0.0;
|
||||
for (int i = 0; i < dnfi.Size(); ++i)
|
||||
Array<NonlinearFormIntegrator*> &integrators = *n->GetDNFI();
|
||||
const int Ni = integrators.Size();
|
||||
for (int i = 0; i < Ni; ++i)
|
||||
{
|
||||
dnfi[i]->AssembleGradientDiagonalPA(xe, ye);
|
||||
integrators[i]->AssemblePA(*n->FESpace());
|
||||
}
|
||||
R->MultTranspose(ye, diag);
|
||||
}
|
||||
|
||||
Operator &PANonlinearForm::GetGradient(const Vector &x) const
|
||||
void PANonlinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
// Store the last x that was used to compute the gradient.
|
||||
x_grad = &x;
|
||||
|
||||
Grad.Reset(new PANonlinearForm::Gradient(x, *this));
|
||||
return *Grad.Ptr();
|
||||
Array<NonlinearFormIntegrator*> &integrators = *n->GetDNFI();
|
||||
const int iSz = integrators.Size();
|
||||
if (elem_restrict_lex)
|
||||
{
|
||||
elem_restrict_lex->Mult(x, localX);
|
||||
localY = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
integrators[i]->AddMultPA(localX, localY);
|
||||
}
|
||||
elem_restrict_lex->MultTranspose(localY, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
y.UseDevice(true); // typically this is a large vector, so store on device
|
||||
y = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
integrators[i]->AddMultPA(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PANonlinearForm::Gradient::Gradient(const Vector &x, const PANonlinearForm &e):
|
||||
Operator(e.fes.GetVSize()), R(e.R), dnfi(e.dnfi)
|
||||
{
|
||||
ge.UseDevice(true);
|
||||
ge.SetSize(R->Height(), Device::GetMemoryType());
|
||||
R->Mult(x, ge);
|
||||
|
||||
xe.UseDevice(true);
|
||||
xe.SetSize(R->Height(), Device::GetMemoryType());
|
||||
|
||||
ye.UseDevice(true);
|
||||
ye.SetSize(R->Height(), Device::GetMemoryType());
|
||||
|
||||
ze.UseDevice(true);
|
||||
ze.SetSize(R->Height(), Device::GetMemoryType());
|
||||
|
||||
// Do we still need to do this?
|
||||
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AssemblePA(e.fes); }
|
||||
}
|
||||
|
||||
void PANonlinearForm::Gradient::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
ze = x;
|
||||
ye = 0.0;
|
||||
R->Mult(ze, xe);
|
||||
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AddMultGradPA(ge, xe, ye); }
|
||||
R->MultTranspose(ye, y);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -17,60 +17,28 @@
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
class NonlinearForm;
|
||||
class NonlinearFormIntegrator;
|
||||
|
||||
/** @brief Class extending the NonlinearForm class to support the different
|
||||
AssemblyLevel%s. */
|
||||
class NonlinearFormExtension : public Operator
|
||||
{
|
||||
protected:
|
||||
const NonlinearForm *nlf;
|
||||
NonlinearForm *n; ///< Not owned
|
||||
public:
|
||||
NonlinearFormExtension(const NonlinearForm*);
|
||||
virtual void Setup() = 0;
|
||||
virtual Operator &GetGradient(const Vector&) const = 0;
|
||||
virtual double GetGridFunctionEnergy(const Vector &x) const = 0;
|
||||
virtual void AssembleGradientDiagonal(Vector &diag) const
|
||||
{
|
||||
MFEM_ABORT("Not implemented for this assembly level!");
|
||||
}
|
||||
NonlinearFormExtension(NonlinearForm *form);
|
||||
virtual void AssemblePA() = 0;
|
||||
};
|
||||
|
||||
class PANonlinearForm;
|
||||
|
||||
|
||||
/// Data and methods for partially-assembled nonlinear forms
|
||||
class PANonlinearForm : public NonlinearFormExtension
|
||||
class PANonlinearFormExtension : public NonlinearFormExtension
|
||||
{
|
||||
private:
|
||||
class Gradient : public Operator
|
||||
{
|
||||
protected:
|
||||
const Operator *R;
|
||||
mutable Vector ge, xe, ye, ze;
|
||||
const Array<NonlinearFormIntegrator*> &dnfi;
|
||||
public:
|
||||
Gradient(const Vector &x, const PANonlinearForm &ext);
|
||||
virtual void Mult(const Vector &x, Vector &y) const;
|
||||
};
|
||||
|
||||
protected:
|
||||
mutable Vector xe, ye;
|
||||
mutable const Vector *x_grad;
|
||||
mutable OperatorHandle Grad;
|
||||
const FiniteElementSpace &fes;
|
||||
const Array<NonlinearFormIntegrator*> &dnfi;
|
||||
const Operator *R;
|
||||
|
||||
const FiniteElementSpace &fes; // Not owned
|
||||
mutable Vector localX, localY;
|
||||
const Operator *elem_restrict_lex; // Not owned
|
||||
public:
|
||||
PANonlinearForm(NonlinearForm *nlf);
|
||||
void Setup();
|
||||
PANonlinearFormExtension(NonlinearForm*);
|
||||
void AssemblePA();
|
||||
void Mult(const Vector &x, Vector &y) const;
|
||||
Operator &GetGradient(const Vector &x) const;
|
||||
double GetGridFunctionEnergy(const Vector &x) const;
|
||||
void AssembleGradientDiagonal(Vector &diag) const;
|
||||
};
|
||||
}
|
||||
#endif // NONLINEARFORM_EXT_HPP
|
||||
|
||||
@@ -15,13 +15,6 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
double NonlinearFormIntegrator::GetGridFunctionEnergyPA(const Vector &x) const
|
||||
{
|
||||
mfem_error ("NonlinearFormIntegrator::GetGridFunctionEnergyPA(...)\n"
|
||||
" is not implemented for this class.");
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void NonlinearFormIntegrator::AssemblePA(const FiniteElementSpace&)
|
||||
{
|
||||
mfem_error ("NonlinearFormIntegrator::AssemblePA(...)\n"
|
||||
@@ -41,20 +34,6 @@ void NonlinearFormIntegrator::AddMultPA(const Vector &, Vector &) const
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void NonlinearFormIntegrator::AddMultGradPA(const Vector&,
|
||||
const Vector&, Vector&) const
|
||||
{
|
||||
mfem_error ("NonlinearFormIntegrator::AddMultGradPA(...)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void NonlinearFormIntegrator::AssembleGradientDiagonalPA(const mfem::Vector &x,
|
||||
mfem::Vector &diag) const
|
||||
{
|
||||
mfem_error ("NonlinearFormIntegrator::AssembleDiagonalPA(...)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void NonlinearFormIntegrator::AssembleElementVector(
|
||||
const FiniteElement &el, ElementTransformation &Tr,
|
||||
const Vector &elfun, Vector &elvect)
|
||||
|
||||
@@ -68,9 +68,6 @@ public:
|
||||
ElementTransformation &Tr,
|
||||
const Vector &elfun);
|
||||
|
||||
/// Compute the local energy with partial assembly.
|
||||
virtual double GetGridFunctionEnergyPA(const Vector &x) const;
|
||||
|
||||
/// Method defining partial assembly.
|
||||
/** The result of the partial assembly is stored internally so that it can be
|
||||
used later in the methods AddMultPA(). */
|
||||
@@ -91,12 +88,6 @@ public:
|
||||
called. */
|
||||
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
||||
|
||||
/// Method for partially assembled gradient action.
|
||||
virtual void AddMultGradPA(const Vector &g,
|
||||
const Vector &x, Vector &y) const;
|
||||
|
||||
virtual void AssembleGradientDiagonalPA(const Vector &x, Vector &diag) const;
|
||||
|
||||
virtual ~NonlinearFormIntegrator() { }
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -3147,7 +3147,7 @@ static void SetSubVector(const int N,
|
||||
const Array<int> &indices,
|
||||
const Vector &in, Vector &out)
|
||||
{
|
||||
auto y = out.ReadWrite();
|
||||
auto y = out.Write();
|
||||
const auto x = in.Read();
|
||||
const auto I = indices.Read();
|
||||
MFEM_FORALL(i, N, y[I[i]] = x[i];);
|
||||
@@ -3234,7 +3234,7 @@ static void AddSubVector(const int num_unique_dst_indices,
|
||||
const Vector &src,
|
||||
Vector &dst)
|
||||
{
|
||||
auto y = dst.ReadWrite();
|
||||
auto y = dst.Write();
|
||||
const auto x = src.Read();
|
||||
const auto DST_I = unique_dst_indices.Read();
|
||||
const auto SRC_O = unique_to_src_offsets.Read();
|
||||
|
||||
+3
-3
@@ -711,9 +711,9 @@ void ParGridFunction::SaveAsOne(std::ostream &out)
|
||||
int *nfdofs = new int[NRanks];
|
||||
int *nrdofs = new int[NRanks];
|
||||
|
||||
HostReadWrite();
|
||||
values[0] = data;
|
||||
double * h_data = const_cast<double *>(this->HostRead());
|
||||
|
||||
values[0] = h_data;
|
||||
nv[0] = pfes -> GetVSize();
|
||||
nvdofs[0] = pfes -> GetNVDofs();
|
||||
nedofs[0] = pfes -> GetNEDofs();
|
||||
@@ -814,7 +814,7 @@ void ParGridFunction::SaveAsOne(std::ostream &out)
|
||||
MPI_Send(&nvdofs[0], 1, MPI_INT, 0, 456, MyComm);
|
||||
MPI_Send(&nedofs[0], 1, MPI_INT, 0, 457, MyComm);
|
||||
MPI_Send(&nfdofs[0], 1, MPI_INT, 0, 458, MyComm);
|
||||
MPI_Send(data, nv[0], MPI_DOUBLE, 0, 460, MyComm);
|
||||
MPI_Send(h_data, nv[0], MPI_DOUBLE, 0, 460, MyComm);
|
||||
}
|
||||
|
||||
delete [] values;
|
||||
|
||||
+9
-16
@@ -14,7 +14,6 @@
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -50,7 +49,6 @@ void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
|
||||
if (fnfi.Size())
|
||||
{
|
||||
MFEM_VERIFY(!NonlinearForm::ext,"");
|
||||
// Terms over shared interior faces in parallel.
|
||||
ParFiniteElementSpace *pfes = ParFESpace();
|
||||
ParMesh *pmesh = pfes->GetParMesh();
|
||||
@@ -88,16 +86,15 @@ void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
|
||||
P->MultTranspose(aux2, y);
|
||||
|
||||
const int N = ess_tdof_list.Size();
|
||||
const auto idx = ess_tdof_list.Read();
|
||||
auto Y = y.ReadWrite();
|
||||
MFEM_FORALL(i, N, Y[idx[i]] = 0.0; );
|
||||
y.HostReadWrite();
|
||||
for (int i = 0; i < ess_tdof_list.Size(); i++)
|
||||
{
|
||||
y(ess_tdof_list[i]) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
const SparseMatrix &ParNonlinearForm::GetLocalGradient(const Vector &x) const
|
||||
{
|
||||
if (NonlinearForm::ext) { MFEM_ABORT("Not yet implemented!"); }
|
||||
|
||||
NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.
|
||||
|
||||
return *Grad;
|
||||
@@ -107,20 +104,16 @@ Operator &ParNonlinearForm::GetGradient(const Vector &x) const
|
||||
{
|
||||
ParFiniteElementSpace *pfes = ParFESpace();
|
||||
|
||||
Operator &grad = NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.
|
||||
|
||||
pGrad.Clear();
|
||||
|
||||
NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.
|
||||
|
||||
OperatorHandle dA(pGrad.Type()), Ph(pGrad.Type());
|
||||
|
||||
if (fnfi.Size() == 0)
|
||||
{
|
||||
if (NonlinearForm::ext) { dA.Reset(&grad, false); }
|
||||
else
|
||||
{
|
||||
dA.MakeSquareBlockDiag(pfes->GetComm(), pfes->GlobalVSize(),
|
||||
pfes->GetDofOffsets(), Grad);
|
||||
}
|
||||
dA.MakeSquareBlockDiag(pfes->GetComm(), pfes->GlobalVSize(),
|
||||
pfes->GetDofOffsets(), Grad);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+1121
-396
File diff suppressed because it is too large
Load Diff
+15
-33
@@ -41,11 +41,10 @@ protected:
|
||||
const FiniteElementSpace *fespace; ///< Not owned
|
||||
const QuadratureSpace *qspace; ///< Not owned
|
||||
const IntegrationRule *IntRule; ///< Not owned
|
||||
|
||||
mutable QVectorLayout q_layout; ///< Output Q-vector layout
|
||||
mutable bool use_tensor_products; ///< Tensor product evaluation mmode
|
||||
|
||||
public:
|
||||
mutable bool use_tensor_products;
|
||||
|
||||
static const int MAX_NQ2D = 100;
|
||||
static const int MAX_ND2D = 100;
|
||||
static const int MAX_VDIM2D = 3;
|
||||
@@ -54,6 +53,7 @@ public:
|
||||
static const int MAX_ND3D = 1000;
|
||||
static const int MAX_VDIM3D = 3;
|
||||
|
||||
public:
|
||||
enum EvalFlags
|
||||
{
|
||||
VALUES = 1 << 0, ///< Evaluate the values at quadrature points
|
||||
@@ -61,28 +61,21 @@ public:
|
||||
/** @brief Assuming the derivative at quadrature points form a matrix,
|
||||
this flag can be used to compute and store their determinants. This
|
||||
flag can only be used in Mult(). */
|
||||
DETERMINANTS = 1 << 2,
|
||||
PHYSICAL_DERIVATIVES = 1 << 3 ///< Evaluate the physical derivatives
|
||||
DETERMINANTS = 1 << 2
|
||||
};
|
||||
|
||||
QuadratureInterpolator(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
const bool use_tensor_products = false);
|
||||
const IntegrationRule &ir);
|
||||
|
||||
QuadratureInterpolator(const FiniteElementSpace &fes,
|
||||
const QuadratureSpace &qs,
|
||||
const bool use_tensor_products = false);
|
||||
const QuadratureSpace &qs);
|
||||
|
||||
/** @brief Disable the use of tensor product evaluations, for tensor-product
|
||||
elements, e.g. quads and hexes. */
|
||||
void DisableTensorProducts() const { use_tensor_products = false; }
|
||||
|
||||
/** @brief Enable the use of tensor product evaluations, for tensor-product
|
||||
elements, e.g. quads and hexes. */
|
||||
void EnableTensorProducts() const { use_tensor_products = true; }
|
||||
|
||||
/** @brief Query the current evaluation mode. */
|
||||
bool UseTensorProducts() const { return use_tensor_products; }
|
||||
/** Currently, tensor product evaluations are not implemented and this method
|
||||
has no effect. */
|
||||
void DisableTensorProducts(bool disable = true) const
|
||||
{ use_tensor_products = !disable; }
|
||||
|
||||
/** @brief Query the current output Q-vector layout. The default value is
|
||||
QVectorLayout::byNODES. */
|
||||
@@ -90,7 +83,8 @@ public:
|
||||
|
||||
/** @brief Set the desired output Q-vector layout. The default value is
|
||||
QVectorLayout::byNODES. */
|
||||
void SetOutputLayout(QVectorLayout layout) const { q_layout = layout; }
|
||||
void SetOutputLayout(QVectorLayout out_layout) const
|
||||
{ q_layout = out_layout; }
|
||||
|
||||
/// Interpolate the E-vector @a e_vec to quadrature points.
|
||||
/** The @a eval_flags are a bitwise mask of constants from the EvalFlags
|
||||
@@ -105,36 +99,26 @@ public:
|
||||
Vector &q_val, Vector &q_der, Vector &q_det) const;
|
||||
|
||||
/// Interpolate the values of the E-vector @a e_vec at quadrature points.
|
||||
template <QVectorLayout>
|
||||
void Values(const Vector &e_vec, Vector &q_val) const;
|
||||
void Values(const Vector &e_vec, Vector &q_val) const;
|
||||
|
||||
/** @brief Interpolate the derivatives of the E-vector @a e_vec at quadrature
|
||||
points. */
|
||||
template <QVectorLayout>
|
||||
void Derivatives(const Vector &e_vec, Vector &q_der) const;
|
||||
void Derivatives(const Vector &e_vec, Vector &q_der) const;
|
||||
|
||||
/** @brief Interpolate the derivatives in physical space of the E-vector
|
||||
@a e_vec at quadrature points. */
|
||||
template <QVectorLayout>
|
||||
void PhysDerivatives(const Vector &e_vec, Vector &q_der) const;
|
||||
void PhysDerivatives(const Vector &e_vec, Vector &q_der) const;
|
||||
|
||||
/// Compute the determinant of the E-vector @a e_vec at quadrature points.
|
||||
void Determinants(const Vector &e_vec, Vector &q_det) const;
|
||||
|
||||
/// Perform the transpose operation of Mult(). (TODO)
|
||||
void MultTranspose(unsigned eval_flags, const Vector &q_val,
|
||||
const Vector &q_der, Vector &e_vec) const;
|
||||
|
||||
// Compute kernels follow (cannot be private or protected with nvcc)
|
||||
|
||||
/// Template compute kernel for 2D.
|
||||
template<const int T_VDIM = 0, const int T_ND = 0, const int T_NQ = 0>
|
||||
static void Mult2D(const int NE,
|
||||
static void Eval2D(const int NE,
|
||||
const int vdim,
|
||||
const QVectorLayout q_layout,
|
||||
const GeometricFactors *geom,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val,
|
||||
@@ -144,10 +128,8 @@ public:
|
||||
|
||||
/// Template compute kernel for 3D.
|
||||
template<const int T_VDIM = 0, const int T_ND = 0, const int T_NQ = 0>
|
||||
static void Mult3D(const int NE,
|
||||
static void Eval3D(const int NE,
|
||||
const int vdim,
|
||||
const QVectorLayout q_layout,
|
||||
const GeometricFactors *geom,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val,
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop_pa.hpp"
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
#include "../fem/kernels.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<int T_D1D = 0, int T_Q1D = 0, int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Det2D(const int NE,
|
||||
const double *b,
|
||||
const double *g,
|
||||
const double *x,
|
||||
double *y,
|
||||
const int vdim = 1,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
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 B = Reshape(b, Q1D, D1D);
|
||||
const auto G = Reshape(g, Q1D, D1D);
|
||||
const auto X = Reshape(x, D1D, D1D, DIM, NE);
|
||||
auto Y = Reshape(y, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double XY[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[4][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[4][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X,XY);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,B,G,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1,NBZ>(D1D,Q1D,BG,XY,DQ);
|
||||
kernels::GradY<MD1,MQ1,NBZ>(D1D,Q1D,BG,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double J[4];
|
||||
kernels::PullGrad<MQ1,NBZ>(qx,qy,QQ,J);
|
||||
Y(qx,qy,e) = kernels::Det<2>(J);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<int T_D1D = 0, int T_Q1D = 0, int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Det3D(const int NE,
|
||||
const double *b,
|
||||
const double *g,
|
||||
const double *x,
|
||||
double *y,
|
||||
const int vdim = 1,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto B = Reshape(b, Q1D, D1D);
|
||||
const auto G = Reshape(g, Q1D, D1D);
|
||||
const auto X = Reshape(x, D1D, D1D, D1D, DIM, NE);
|
||||
auto Y = Reshape(y, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MDQ = MQ1 > MD1 ? MQ1 : MD1;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double sm0[9][MDQ*MDQ*MDQ];
|
||||
MFEM_SHARED double sm1[9][MDQ*MDQ*MDQ];
|
||||
|
||||
double (*DDD)[MD1*MD1*MD1] = (double (*)[MD1*MD1*MD1]) (sm0);
|
||||
double (*DDQ)[MD1*MD1*MQ1] = (double (*)[MD1*MD1*MQ1]) (sm1);
|
||||
double (*DQQ)[MD1*MQ1*MQ1] = (double (*)[MD1*MQ1*MQ1]) (sm0);
|
||||
double (*QQQ)[MQ1*MQ1*MQ1] = (double (*)[MQ1*MQ1*MQ1]) (sm1);
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,X,DDD);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,B,G,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1>(D1D,Q1D,BG,DDD,DDQ);
|
||||
kernels::GradY<MD1,MQ1>(D1D,Q1D,BG,DDQ,DQQ);
|
||||
kernels::GradZ<MD1,MQ1>(D1D,Q1D,BG,DQQ,QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double J[9];
|
||||
kernels::PullGrad<MQ1>(qx,qy,qz, QQQ, J);
|
||||
Y(qx,qy,qz,e) = kernels::Det<3>(J);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void QuadratureInterpolator::Determinants(const Vector &e_vec,
|
||||
Vector &q_det) const
|
||||
{
|
||||
if (use_tensor_products)
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const double *B = maps.B.Read();
|
||||
const double *G = maps.G.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_det.Write();
|
||||
|
||||
const int id = (dim<<12) | (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0x2222: return Det2D<2,2>(NE,B,G,X,Y);
|
||||
case 0x2223: return Det2D<2,3>(NE,B,G,X,Y);
|
||||
case 0x2224: return Det2D<2,4>(NE,B,G,X,Y);
|
||||
case 0x2226: return Det2D<2,6>(NE,B,G,X,Y);
|
||||
case 0x2234: return Det2D<3,4>(NE,B,G,X,Y);
|
||||
case 0x2236: return Det2D<3,6>(NE,B,G,X,Y);
|
||||
case 0x2244: return Det2D<4,4>(NE,B,G,X,Y);
|
||||
case 0x2246: return Det2D<4,6>(NE,B,G,X,Y);
|
||||
case 0x2256: return Det2D<5,6>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3324: return Det3D<2,4>(NE,B,G,X,Y);
|
||||
case 0x3333: return Det3D<3,3>(NE,B,G,X,Y);
|
||||
case 0x3335: return Det3D<3,5>(NE,B,G,X,Y);
|
||||
case 0x3336: return Det3D<3,6>(NE,B,G,X,Y);
|
||||
//case 0x3348: return Det3D<4,8>(NE,B,G,X,Y);
|
||||
|
||||
default:
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
constexpr int MD1 = 8;
|
||||
constexpr int MQ1 = 8;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
return Det2D<0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D);
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
constexpr int MD1 = 6;
|
||||
constexpr int MQ1 = 6;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
return Det3D<0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
MFEM_ABORT("Kernel " << std::hex << id << std::dec << " not supported yet");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector empty;
|
||||
Mult(e_vec, DETERMINANTS, empty, empty, q_det);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,233 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<QVectorLayout Q_LAYOUT,
|
||||
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
|
||||
int T_NBZ = 1, int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Eval2D(const int NE,
|
||||
const double *b_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
|
||||
Reshape(y_, Q1D, Q1D, VDIM, NE):
|
||||
Reshape(y_, VDIM, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
|
||||
MFEM_SHARED double s_B[MQ1*MD1];
|
||||
DeviceTensor<2,double> B(s_B, Q1D, D1D);
|
||||
|
||||
MFEM_SHARED double s_DD[NBZ][MD1*MD1];
|
||||
DeviceTensor<2,double> DD((double*)(s_DD+tidz), MD1, MD1);
|
||||
|
||||
MFEM_SHARED double s_DQ[NBZ][MD1*MQ1];
|
||||
DeviceTensor<2,double> DQ((double*)(s_DQ+tidz), MD1, MQ1);
|
||||
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B(q,d) = b(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
DD(dx,dy) = x(dx,dy,c,e);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
u += B(qx,dx) * DD(dx,dy);
|
||||
}
|
||||
DQ(dy,qx) = u;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
u += DQ(dy,qx) * B(qy,dy);
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM) { y(c,qx,qy,e) = u; }
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES) { y(qx,qy,c,e) = u; }
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<QVectorLayout Q_LAYOUT,
|
||||
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
|
||||
int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Eval3D(const int NE,
|
||||
const double *b_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
|
||||
Reshape(y_, Q1D, Q1D, Q1D, VDIM, NE):
|
||||
Reshape(y_, VDIM, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
|
||||
MFEM_SHARED double s_B[MQ1*MD1];
|
||||
DeviceTensor<2,double> B(s_B, Q1D, D1D);
|
||||
|
||||
MFEM_SHARED double sm0[MDQ*MDQ*MDQ];
|
||||
MFEM_SHARED double sm1[MDQ*MDQ*MDQ];
|
||||
DeviceTensor<3,double> DDD(sm0, MD1, MD1, MD1);
|
||||
DeviceTensor<3,double> DDQ(sm1, MD1, MD1, MQ1);
|
||||
DeviceTensor<3,double> DQQ(sm0, MD1, MQ1, MQ1);
|
||||
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B(q,d) = b(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
DDD(dx,dy,dz) = x(dx,dy,dz,c,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
u += B(qx,dx) * DDD(dx,dy,dz);
|
||||
}
|
||||
DDQ(dz,dy,qx) = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
u += DDQ(dz,dy,qx) * B(qy,dy);
|
||||
}
|
||||
DQQ(dz,qy,qx) = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
u += DQQ(dz,qy,qx) * B(qz,dz);
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM) { y(c,qx,qy,qz,e) = u; }
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES) { y(qx,qy,qz,c,e) = u; }
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,110 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "quadinterpolator_eval.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<>
|
||||
void QuadratureInterpolator::Values<QVectorLayout::byNODES>(
|
||||
const Vector &e_vec, Vector &q_val) const
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const double *B = maps.B.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_val.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byNODES;
|
||||
|
||||
const int id = (dim<<12) | (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0x2133: return Eval2D<L,1,3,3>(NE,B,X,Y);
|
||||
case 0x2124: return Eval2D<L,1,2,4>(NE,B,X,Y);
|
||||
case 0x2132: return Eval2D<L,1,3,2>(NE,B,X,Y);
|
||||
case 0x2134: return Eval2D<L,1,3,4>(NE,B,X,Y);
|
||||
case 0x2143: return Eval2D<L,1,4,3>(NE,B,X,Y);
|
||||
case 0x2144: return Eval2D<L,1,4,4>(NE,B,X,Y);
|
||||
|
||||
case 0x2222: return Eval2D<L,2,2,2>(NE,B,X,Y);
|
||||
case 0x2223: return Eval2D<L,2,2,3>(NE,B,X,Y);
|
||||
case 0x2224: return Eval2D<L,2,2,4>(NE,B,X,Y);
|
||||
case 0x2225: return Eval2D<L,2,2,5>(NE,B,X,Y);
|
||||
case 0x2226: return Eval2D<L,2,2,6>(NE,B,X,Y);
|
||||
case 0x2233: return Eval2D<L,2,3,3>(NE,B,X,Y);
|
||||
case 0x2234: return Eval2D<L,2,3,4>(NE,B,X,Y);
|
||||
case 0x2236: return Eval2D<L,2,3,6>(NE,B,X,Y);
|
||||
case 0x2243: return Eval2D<L,2,4,3>(NE,B,X,Y);
|
||||
case 0x2244: return Eval2D<L,2,4,4>(NE,B,X,Y);
|
||||
case 0x2245: return Eval2D<L,2,4,5>(NE,B,X,Y);
|
||||
case 0x2246: return Eval2D<L,2,4,6>(NE,B,X,Y);
|
||||
case 0x2247: return Eval2D<L,2,4,7>(NE,B,X,Y);
|
||||
case 0x2256: return Eval2D<L,2,5,6>(NE,B,X,Y);
|
||||
|
||||
case 0x3124: return Eval3D<L,1,2,4>(NE,B,X,Y);
|
||||
case 0x3133: return Eval3D<L,1,3,3>(NE,B,X,Y);
|
||||
case 0x3134: return Eval3D<L,1,3,4>(NE,B,X,Y);
|
||||
case 0x3136: return Eval3D<L,1,3,6>(NE,B,X,Y);
|
||||
case 0x3143: return Eval3D<L,1,4,3>(NE,B,X,Y);
|
||||
case 0x3144: return Eval3D<L,1,4,4>(NE,B,X,Y);
|
||||
case 0x3148: return Eval3D<L,1,4,8>(NE,B,X,Y);
|
||||
|
||||
case 0x3222: return Eval3D<L,2,2,2>(NE,B,X,Y);
|
||||
case 0x3223: return Eval3D<L,2,2,3>(NE,B,X,Y);
|
||||
case 0x3234: return Eval3D<L,2,3,4>(NE,B,X,Y);
|
||||
|
||||
case 0x3323: return Eval3D<L,3,2,3>(NE,B,X,Y);
|
||||
case 0x3324: return Eval3D<L,3,2,4>(NE,B,X,Y);
|
||||
case 0x3325: return Eval3D<L,3,2,5>(NE,B,X,Y);
|
||||
case 0x3326: return Eval3D<L,3,2,6>(NE,B,X,Y);
|
||||
case 0x3333: return Eval3D<L,3,3,3>(NE,B,X,Y);
|
||||
case 0x3334: return Eval3D<L,3,3,4>(NE,B,X,Y);
|
||||
case 0x3335: return Eval3D<L,3,3,5>(NE,B,X,Y);
|
||||
case 0x3336: return Eval3D<L,3,3,6>(NE,B,X,Y);
|
||||
case 0x3343: return Eval3D<L,3,4,3>(NE,B,X,Y);
|
||||
case 0x3344: return Eval3D<L,3,4,4>(NE,B,X,Y);
|
||||
case 0x3346: return Eval3D<L,3,4,6>(NE,B,X,Y);
|
||||
case 0x3347: return Eval3D<L,3,4,7>(NE,B,X,Y);
|
||||
case 0x3348: return Eval3D<L,3,4,8>(NE,B,X,Y);
|
||||
|
||||
default:
|
||||
{
|
||||
constexpr int MD1 = 8;
|
||||
constexpr int MQ1 = 8;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
if (dim == 2) { Eval2D<L,0,0,0,0,MD1,MQ1>(NE,B,X,Y,vdim,D1D,Q1D); }
|
||||
if (dim == 3) { Eval3D<L,0,0,0,MD1,MQ1>(NE,B,X,Y,vdim,D1D,Q1D); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "quadinterpolator_eval.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<>
|
||||
void QuadratureInterpolator::Values<QVectorLayout::byVDIM>(
|
||||
const Vector &e_vec, Vector &q_val) const
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const double *B = maps.B.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_val.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byVDIM;
|
||||
|
||||
const int id = (dim<<12) | (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0x2124: return Eval2D<L,1,2,4,8>(NE,B,X,Y);
|
||||
case 0x2136: return Eval2D<L,1,3,6,4>(NE,B,X,Y);
|
||||
case 0x2148: return Eval2D<L,1,4,8,2>(NE,B,X,Y);
|
||||
|
||||
case 0x2224: return Eval2D<L,2,2,4,8>(NE,B,X,Y);
|
||||
case 0x2234: return Eval2D<L,2,3,4,8>(NE,B,X,Y);
|
||||
case 0x2236: return Eval2D<L,2,3,6,4>(NE,B,X,Y);
|
||||
case 0x2248: return Eval2D<L,2,4,8,2>(NE,B,X,Y);
|
||||
|
||||
case 0x3124: return Eval3D<L,1,2,4>(NE,B,X,Y);
|
||||
case 0x3136: return Eval3D<L,1,3,6>(NE,B,X,Y);
|
||||
case 0x3148: return Eval3D<L,1,4,8>(NE,B,X,Y);
|
||||
|
||||
case 0x3324: return Eval3D<L,3,2,4>(NE,B,X,Y);
|
||||
case 0x3336: return Eval3D<L,3,3,6>(NE,B,X,Y);
|
||||
case 0x3348: return Eval3D<L,3,4,8>(NE,B,X,Y);
|
||||
|
||||
default:
|
||||
{
|
||||
constexpr int MD1 = 8;
|
||||
constexpr int MQ1 = 8;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
if (dim == 2) { Eval2D<L,0,0,0,0,MD1,MQ1>(NE,B,X,Y,vdim,D1D,Q1D); }
|
||||
if (dim == 3) { Eval3D<L,0,0,0,MD1,MQ1>(NE,B,X,Y,vdim,D1D,Q1D); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -495,9 +495,8 @@ void FaceQuadratureInterpolator::Mult(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FaceQuadratureInterpolator::Values(const Vector &e_vec,
|
||||
Vector &q_val) const
|
||||
void FaceQuadratureInterpolator::Values(
|
||||
const Vector &e_vec, Vector &q_val) const
|
||||
{
|
||||
Vector q_der, q_det, q_nor;
|
||||
Mult(e_vec, VALUES, q_val, q_der, q_det, q_nor);
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<QVectorLayout Q_LAYOUT,
|
||||
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
|
||||
int T_NBZ = 1, int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Grad2D(const int NE,
|
||||
const double *b_,
|
||||
const double *g_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto g = Reshape(g_, Q1D, D1D);
|
||||
const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT ==QVectorLayout:: byNODES ?
|
||||
Reshape(y_, Q1D, Q1D, VDIM, 2, NE):
|
||||
Reshape(y_, VDIM, 2, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
MFEM_SHARED double s_B[MQ1*MD1];
|
||||
MFEM_SHARED double s_G[MQ1*MD1];
|
||||
DeviceTensor<2,double> B(s_B, Q1D, D1D);
|
||||
DeviceTensor<2,double> G(s_G, Q1D, D1D);
|
||||
|
||||
MFEM_SHARED double s_X[NBZ][MD1*MD1];
|
||||
DeviceTensor<2,double> X((double*)(s_X+tidz), MD1, MD1);
|
||||
|
||||
MFEM_SHARED double s_DQ[2][NBZ][MD1*MQ1];
|
||||
DeviceTensor<2,double> DQ0((double*)(s_DQ[0]+tidz), MD1, MQ1);
|
||||
DeviceTensor<2,double> DQ1((double*)(s_DQ[1]+tidz), MD1, MQ1);
|
||||
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B(q,d) = b(q,d);
|
||||
G(q,d) = g(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int c = 0; c < VDIM; ++c)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
X(dx,dy) = x(dx,dy,c,e);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double input = X(dx,dy);
|
||||
u += input * B(qx,dx);
|
||||
v += input * G(qx,dx);
|
||||
}
|
||||
DQ0(dy,qx) = u;
|
||||
DQ1(dy,qx) = v;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
u += DQ1(dy,qx) * B(qy,dy);
|
||||
v += DQ0(dy,qx) * G(qy,dy);
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES)
|
||||
{
|
||||
y(qx,qy,c,0,e) = u;
|
||||
y(qx,qy,c,1,e) = v;
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM)
|
||||
{
|
||||
y(c,0,qx,qy,e) = u;
|
||||
y(c,1,qx,qy,e) = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<QVectorLayout Q_LAYOUT,
|
||||
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
|
||||
int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Grad3D(const int NE,
|
||||
const double *b_,
|
||||
const double *g_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto g = Reshape(g_, Q1D, D1D);
|
||||
const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT ==QVectorLayout:: byNODES ?
|
||||
Reshape(y_, Q1D, Q1D, Q1D, VDIM, 3, NE):
|
||||
Reshape(y_, VDIM, 3, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
MFEM_SHARED double s_B[MQ1*MD1];
|
||||
MFEM_SHARED double s_G[MQ1*MD1];
|
||||
DeviceTensor<2,double> B(s_B, Q1D, D1D);
|
||||
DeviceTensor<2,double> G(s_G, Q1D, D1D);
|
||||
|
||||
MFEM_SHARED double sm0[3][MQ1*MQ1*MQ1];
|
||||
MFEM_SHARED double sm1[3][MQ1*MQ1*MQ1];
|
||||
DeviceTensor<3,double> X((double*)(sm0+2), MD1, MD1, MD1);
|
||||
DeviceTensor<3,double> DDQ0((double*)(sm0+0), MD1, MD1, MQ1);
|
||||
DeviceTensor<3,double> DDQ1((double*)(sm0+1), MD1, MD1, MQ1);
|
||||
DeviceTensor<3,double> DQQ0((double*)(sm1+0), MD1, MQ1, MQ1);
|
||||
DeviceTensor<3,double> DQQ1((double*)(sm1+1), MD1, MQ1, MQ1);
|
||||
DeviceTensor<3,double> DQQ2((double*)(sm1+2), MD1, MQ1, MQ1);
|
||||
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B(q,d) = b(q,d);
|
||||
G(q,d) = g(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int c = 0; c < VDIM; ++c)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
X(dx,dy,dz) = x(dx,dy,dz,c,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double input = X(dx,dy,dz);
|
||||
u += input * B(qx,dx);
|
||||
v += input * G(qx,dx);
|
||||
}
|
||||
DDQ0(dz,dy,qx) = u;
|
||||
DDQ1(dz,dy,qx) = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
double w = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
u += DDQ1(dz,dy,qx) * B(qy,dy);
|
||||
v += DDQ0(dz,dy,qx) * G(qy,dy);
|
||||
w += DDQ0(dz,dy,qx) * B(qy,dy);
|
||||
}
|
||||
DQQ0(dz,qy,qx) = u;
|
||||
DQQ1(dz,qy,qx) = v;
|
||||
DQQ2(dz,qy,qx) = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
double w = 0.0;
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
u += DQQ0(dz,qy,qx) * B(qz,dz);
|
||||
v += DQQ1(dz,qy,qx) * B(qz,dz);
|
||||
w += DQQ2(dz,qy,qx) * G(qz,dz);
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES)
|
||||
{
|
||||
y(qx,qy,qz,c,0,e) = u;
|
||||
y(qx,qy,qz,c,1,e) = v;
|
||||
y(qx,qy,qz,c,2,e) = w;
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM)
|
||||
{
|
||||
y(c,0,qx,qy,qz,e) = u;
|
||||
y(c,1,qx,qy,qz,e) = v;
|
||||
y(c,2,qx,qy,qz,e) = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,109 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "quadinterpolator_grad.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<>
|
||||
void QuadratureInterpolator::Derivatives<QVectorLayout::byNODES>(
|
||||
const Vector &e_vec, Vector &q_der) const
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const double *B = maps.B.Read();
|
||||
const double *G = maps.G.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_der.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byNODES;
|
||||
|
||||
const int id = (dim<<12) | (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0x2133: return Grad2D<L,1,3,3,16>(NE,B,G,X,Y);
|
||||
case 0x2134: return Grad2D<L,1,3,4,16>(NE,B,G,X,Y);
|
||||
case 0x2143: return Grad2D<L,1,4,3,16>(NE,B,G,X,Y);
|
||||
case 0x2144: return Grad2D<L,1,4,4,16>(NE,B,G,X,Y);
|
||||
|
||||
case 0x2222: return Grad2D<L,2,2,2,16>(NE,B,G,X,Y);
|
||||
case 0x2223: return Grad2D<L,2,2,3,8>(NE,B,G,X,Y);
|
||||
case 0x2224: return Grad2D<L,2,2,4,4>(NE,B,G,X,Y);
|
||||
case 0x2225: return Grad2D<L,2,2,5,4>(NE,B,G,X,Y);
|
||||
case 0x2226: return Grad2D<L,2,2,6,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x2233: return Grad2D<L,2,3,3,2>(NE,B,G,X,Y);
|
||||
case 0x2234: return Grad2D<L,2,3,4,4>(NE,B,G,X,Y);
|
||||
case 0x2243: return Grad2D<L,2,4,3,4>(NE,B,G,X,Y);
|
||||
case 0x2236: return Grad2D<L,2,3,6,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x2244: return Grad2D<L,2,4,4,2>(NE,B,G,X,Y);
|
||||
case 0x2245: return Grad2D<L,2,4,5,2>(NE,B,G,X,Y);
|
||||
case 0x2246: return Grad2D<L,2,4,6,2>(NE,B,G,X,Y);
|
||||
case 0x2247: return Grad2D<L,2,4,7,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x2256: return Grad2D<L,2,5,6,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3124: return Grad3D<L,1,2,4>(NE,B,G,X,Y);
|
||||
case 0x3133: return Grad3D<L,1,3,3>(NE,B,G,X,Y);
|
||||
case 0x3134: return Grad3D<L,1,3,4>(NE,B,G,X,Y);
|
||||
case 0x3136: return Grad3D<L,1,3,6>(NE,B,G,X,Y);
|
||||
case 0x3144: return Grad3D<L,1,4,4>(NE,B,G,X,Y);
|
||||
case 0x3148: return Grad3D<L,1,4,8>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3323: return Grad3D<L,3,2,3>(NE,B,G,X,Y);
|
||||
case 0x3324: return Grad3D<L,3,2,4>(NE,B,G,X,Y);
|
||||
case 0x3325: return Grad3D<L,3,2,5>(NE,B,G,X,Y);
|
||||
case 0x3326: return Grad3D<L,3,2,6>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3333: return Grad3D<L,3,3,3>(NE,B,G,X,Y);
|
||||
case 0x3334: return Grad3D<L,3,3,4>(NE,B,G,X,Y);
|
||||
case 0x3335: return Grad3D<L,3,3,5>(NE,B,G,X,Y);
|
||||
case 0x3336: return Grad3D<L,3,3,6>(NE,B,G,X,Y);
|
||||
case 0x3344: return Grad3D<L,3,4,4>(NE,B,G,X,Y);
|
||||
case 0x3346: return Grad3D<L,3,4,6>(NE,B,G,X,Y);
|
||||
case 0x3347: return Grad3D<L,3,4,7>(NE,B,G,X,Y);
|
||||
case 0x3348: return Grad3D<L,3,4,8>(NE,B,G,X,Y);
|
||||
default:
|
||||
{
|
||||
constexpr int MD1 = 8;
|
||||
constexpr int MQ1 = 8;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
if (dim == 2)
|
||||
{
|
||||
return Grad2D<L,0,0,0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D);
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
return Grad3D<L,0,0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,76 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "quadinterpolator_grad.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<>
|
||||
void QuadratureInterpolator::Derivatives<QVectorLayout::byVDIM>(
|
||||
const Vector &e_vec, Vector &q_der) const
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const double *B = maps.B.Read();
|
||||
const double *G = maps.G.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_der.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byVDIM;
|
||||
|
||||
const int id = (dim<<12) | (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0x2134: return Grad2D<L,1,3,4,8>(NE,B,G,X,Y);
|
||||
case 0x2146: return Grad2D<L,1,4,6,4>(NE,B,G,X,Y);
|
||||
case 0x2158: return Grad2D<L,1,5,8,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x2234: return Grad2D<L,2,3,4,8>(NE,B,G,X,Y);
|
||||
case 0x2246: return Grad2D<L,2,4,6,4>(NE,B,G,X,Y);
|
||||
case 0x2258: return Grad2D<L,2,5,8,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3134: return Grad3D<L,1,3,4>(NE,B,G,X,Y);
|
||||
case 0x3146: return Grad3D<L,1,4,6>(NE,B,G,X,Y);
|
||||
case 0x3158: return Grad3D<L,1,5,8>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3334: return Grad3D<L,3,3,4>(NE,B,G,X,Y);
|
||||
case 0x3346: return Grad3D<L,3,4,6>(NE,B,G,X,Y);
|
||||
case 0x3358: return Grad3D<L,3,5,8>(NE,B,G,X,Y);
|
||||
default:
|
||||
{
|
||||
constexpr int MD1 = 8;
|
||||
constexpr int MQ1 = 8;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
if (dim == 2) { Grad2D<L,0,0,0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D); }
|
||||
if (dim == 3) { Grad3D<L,0,0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,303 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<QVectorLayout Q_LAYOUT,
|
||||
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
|
||||
int T_NBZ = 1, int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void PhysGrad2D(const int NE,
|
||||
const double *b_,
|
||||
const double *g_,
|
||||
const double *j_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto g = Reshape(g_, Q1D, D1D);
|
||||
const auto j = Reshape(j_, Q1D, Q1D, 2, 2, NE);
|
||||
const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT ==QVectorLayout:: byNODES ?
|
||||
Reshape(y_, Q1D, Q1D, VDIM, 2, NE):
|
||||
Reshape(y_, VDIM, 2, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
MFEM_SHARED double s_B[MQ1][MD1];
|
||||
MFEM_SHARED double s_G[MQ1][MD1];
|
||||
DeviceTensor<2,double> B((double*)(s_B), Q1D, D1D);
|
||||
DeviceTensor<2,double> G((double*)(s_G), Q1D, D1D);
|
||||
|
||||
MFEM_SHARED double s_X[NBZ][MD1*MD1];
|
||||
DeviceTensor<2,double> X((double*)(s_X+tidz), MD1, MD1);
|
||||
|
||||
MFEM_SHARED double sm[2][NBZ][MD1*MQ1];
|
||||
DeviceTensor<2,double> DQ0((double*)(sm[0]+tidz), MD1, MQ1);
|
||||
DeviceTensor<2,double> DQ1((double*)(sm[1]+tidz), MD1, MQ1);
|
||||
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B(q,d) = b(q,d);
|
||||
G(q,d) = g(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int c = 0; c < VDIM; ++c)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
X(dx,dy) = x(dx,dy,c,e);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double input = X(dx,dy);
|
||||
u += input * B(qx,dx);
|
||||
v += input * G(qx,dx);
|
||||
}
|
||||
DQ0(dy,qx) = u;
|
||||
DQ1(dy,qx) = v;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
u += DQ1(dy,qx) * B(qy,dy);
|
||||
v += DQ0(dy,qx) * G(qy,dy);
|
||||
}
|
||||
double Jloc[4], Jinv[4];
|
||||
Jloc[0] = j(qx,qy,0,0,e);
|
||||
Jloc[1] = j(qx,qy,1,0,e);
|
||||
Jloc[2] = j(qx,qy,0,1,e);
|
||||
Jloc[3] = j(qx,qy,1,1,e);
|
||||
kernels::CalcInverse<2>(Jloc, Jinv);
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM)
|
||||
{
|
||||
y(c,0,qx,qy,e) = Jinv[0]*u + Jinv[1]*v;
|
||||
y(c,1,qx,qy,e) = Jinv[2]*u + Jinv[3]*v;
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES)
|
||||
{
|
||||
y(qx,qy,c,0,e) = Jinv[0]*u + Jinv[1]*v;
|
||||
y(qx,qy,c,1,e) = Jinv[2]*u + Jinv[3]*v;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<QVectorLayout Q_LAYOUT,
|
||||
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
|
||||
int MAX_D = 0, int MAX_Q = 0>
|
||||
static void PhysGrad3D(const int NE,
|
||||
const double *b_,
|
||||
const double *g_,
|
||||
const double *j_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 1,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto g = Reshape(g_, Q1D, D1D);
|
||||
const auto j = Reshape(j_, Q1D, Q1D, Q1D, 3, 3, NE);
|
||||
const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT ==QVectorLayout:: byNODES ?
|
||||
Reshape(y_, Q1D, Q1D, Q1D, VDIM, 3, NE):
|
||||
Reshape(y_, VDIM, 3, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D;
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
MFEM_SHARED double s_B[MQ1][MD1];
|
||||
MFEM_SHARED double s_G[MQ1][MD1];
|
||||
DeviceTensor<2,double> B((double*)(s_B), Q1D, D1D);
|
||||
DeviceTensor<2,double> G((double*)(s_G), Q1D, D1D);
|
||||
|
||||
MFEM_SHARED double sm0[3][MQ1*MQ1*MQ1];
|
||||
MFEM_SHARED double sm1[3][MQ1*MQ1*MQ1];
|
||||
DeviceTensor<3,double> X((double*)(sm0+2), MD1, MD1, MD1);
|
||||
DeviceTensor<3,double> DDQ0((double*)(sm0+0), MD1, MD1, MQ1);
|
||||
DeviceTensor<3,double> DDQ1((double*)(sm0+1), MD1, MD1, MQ1);
|
||||
DeviceTensor<3,double> DQQ0((double*)(sm1+0), MD1, MQ1, MQ1);
|
||||
DeviceTensor<3,double> DQQ1((double*)(sm1+1), MD1, MQ1, MQ1);
|
||||
DeviceTensor<3,double> DQQ2((double*)(sm1+2), MD1, MQ1, MQ1);
|
||||
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B(q,d) = b(q,d);
|
||||
G(q,d) = g(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int c = 0; c < VDIM; ++c)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
X(dx,dy,dz) = x(dx,dy,dz,c,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double coords = X(dx,dy,dz);
|
||||
u += coords * B(qx,dx);
|
||||
v += coords * G(qx,dx);
|
||||
}
|
||||
DDQ0(dz,dy,qx) = u;
|
||||
DDQ1(dz,dy,qx) = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
double w = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
u += DDQ1(dz,dy,qx) * B(qy,dy);
|
||||
v += DDQ0(dz,dy,qx) * G(qy,dy);
|
||||
w += DDQ0(dz,dy,qx) * B(qy,dy);
|
||||
}
|
||||
DQQ0(dz,qy,qx) = u;
|
||||
DQQ1(dz,qy,qx) = v;
|
||||
DQQ2(dz,qy,qx) = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
double w = 0.0;
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
u += DQQ0(dz,qy,qx) * B(qz,dz);
|
||||
v += DQQ1(dz,qy,qx) * B(qz,dz);
|
||||
w += DQQ2(dz,qy,qx) * G(qz,dz);
|
||||
}
|
||||
double Jloc[9], Jinv[9];
|
||||
for (int col = 0; col < 3; col++)
|
||||
{
|
||||
for (int row = 0; row < 3; row++)
|
||||
{
|
||||
Jloc[row+3*col] = j(qx,qy,qz,row,col,e);
|
||||
}
|
||||
}
|
||||
kernels::CalcInverse<3>(Jloc, Jinv);
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES)
|
||||
{
|
||||
y(qx,qy,qz,c,0,e) = Jinv[0]*u + Jinv[1]*v + Jinv[2]*w;
|
||||
y(qx,qy,qz,c,1,e) = Jinv[3]*u + Jinv[4]*v + Jinv[5]*w;
|
||||
y(qx,qy,qz,c,2,e) = Jinv[6]*u + Jinv[7]*v + Jinv[8]*w;
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM)
|
||||
{
|
||||
y(c,0,qx,qy,qz,e) = Jinv[0]*u + Jinv[1]*v + Jinv[2]*w;
|
||||
y(c,1,qx,qy,qz,e) = Jinv[3]*u + Jinv[4]*v + Jinv[5]*w;
|
||||
y(c,2,qx,qy,qz,e) = Jinv[6]*u + Jinv[7]*v + Jinv[8]*w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,110 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "quadinterpolator_grad_phys.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<>
|
||||
void QuadratureInterpolator::PhysDerivatives<QVectorLayout::byNODES>(
|
||||
const Vector &e_vec, Vector &q_der) const
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
Mesh *mesh = fespace->GetMesh();
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
constexpr DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, mode);
|
||||
const GeometricFactors *geom =
|
||||
mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mode);
|
||||
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
|
||||
const double *B = maps.B.Read();
|
||||
const double *G = maps.G.Read();
|
||||
const double *J = geom->J.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_der.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byNODES;
|
||||
|
||||
const int id = (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x133: return PhysGrad2D<L,1,3,3,8>(NE,B,G,J,X,Y);
|
||||
case 0x134: return PhysGrad2D<L,1,3,4,8>(NE,B,G,J,X,Y);
|
||||
case 0x143: return PhysGrad2D<L,1,4,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x144: return PhysGrad2D<L,1,4,4,4>(NE,B,G,J,X,Y);
|
||||
case 0x146: return PhysGrad2D<L,1,4,6,4>(NE,B,G,J,X,Y);
|
||||
case 0x158: return PhysGrad2D<L,1,5,8,2>(NE,B,G,J,X,Y);
|
||||
|
||||
case 0x233: return PhysGrad2D<L,2,3,3,8>(NE,B,G,J,X,Y);
|
||||
case 0x234: return PhysGrad2D<L,2,3,4,8>(NE,B,G,J,X,Y);
|
||||
case 0x243: return PhysGrad2D<L,2,4,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x244: return PhysGrad2D<L,2,4,4,4>(NE,B,G,J,X,Y);
|
||||
case 0x246: return PhysGrad2D<L,2,4,6,4>(NE,B,G,J,X,Y);
|
||||
case 0x258: return PhysGrad2D<L,2,5,8,2>(NE,B,G,J,X,Y);
|
||||
default:
|
||||
{
|
||||
constexpr int MD = MAX_D1D;
|
||||
constexpr int MQ = MAX_Q1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than " << MQ
|
||||
<< " 1D points are not supported!");
|
||||
PhysGrad2D<L,0,0,0,0,MD,MQ>(NE, B, G, J, X, Y, vdim, D1D, Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x133: return PhysGrad3D<L,1,3,3>(NE,B,G,J,X,Y);
|
||||
case 0x134: return PhysGrad3D<L,1,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x144: return PhysGrad3D<L,1,4,4>(NE,B,G,J,X,Y);
|
||||
case 0x146: return PhysGrad3D<L,1,4,6>(NE,B,G,J,X,Y);
|
||||
case 0x158: return PhysGrad3D<L,1,5,8>(NE,B,G,J,X,Y);
|
||||
|
||||
case 0x333: return PhysGrad3D<L,3,3,3>(NE,B,G,J,X,Y);
|
||||
case 0x334: return PhysGrad3D<L,3,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x344: return PhysGrad3D<L,3,4,4>(NE,B,G,J,X,Y);
|
||||
case 0x346: return PhysGrad3D<L,3,4,6>(NE,B,G,J,X,Y);
|
||||
case 0x358: return PhysGrad3D<L,3,5,8>(NE,B,G,J,X,Y);
|
||||
default:
|
||||
{
|
||||
constexpr int MD = 8;
|
||||
constexpr int MQ = 8;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than " << MQ
|
||||
<< " 1D points are not supported!");
|
||||
PhysGrad3D<L,0,0,0,MD,MQ>(NE, B, G, J, X, Y, vdim, D1D, Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Unknown kernel");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,101 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "quadinterpolator_grad_phys.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<>
|
||||
void QuadratureInterpolator::PhysDerivatives<QVectorLayout::byVDIM>(
|
||||
const Vector &e_vec, Vector &q_der) const
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
Mesh *mesh = fespace->GetMesh();
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
constexpr DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, mode);
|
||||
const GeometricFactors *geom =
|
||||
mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mode);
|
||||
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
|
||||
const double *B = maps.B.Read();
|
||||
const double *G = maps.G.Read();
|
||||
const double *J = geom->J.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_der.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byVDIM;
|
||||
|
||||
const int id = (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x134: return PhysGrad2D<L,1,3,4,8>(NE, B, G, J, X, Y);
|
||||
case 0x146: return PhysGrad2D<L,1,4,6,4>(NE, B, G, J, X, Y);
|
||||
case 0x158: return PhysGrad2D<L,1,5,8,2>(NE, B, G, J, X, Y);
|
||||
|
||||
case 0x233: return PhysGrad2D<L,2,3,3,8>(NE, B, G, J, X, Y);
|
||||
case 0x234: return PhysGrad2D<L,2,3,4,8>(NE, B, G, J, X, Y);
|
||||
case 0x246: return PhysGrad2D<L,2,4,6,4>(NE, B, G, J, X, Y);
|
||||
case 0x258: return PhysGrad2D<L,2,5,8,2>(NE, B, G, J, X, Y);
|
||||
default:
|
||||
{
|
||||
constexpr int MD = MAX_D1D;
|
||||
constexpr int MQ = MAX_Q1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than " << MQ
|
||||
<< " 1D points are not supported!");
|
||||
PhysGrad2D<L,0,0,0,0,MD,MQ>(NE, B, G, J, X, Y, vdim, D1D, Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x134: return PhysGrad3D<L,1,3,4>(NE, B, G, J, X, Y);
|
||||
case 0x146: return PhysGrad3D<L,1,4,6>(NE, B, G, J, X, Y);
|
||||
case 0x158: return PhysGrad3D<L,1,5,8>(NE, B, G, J, X, Y);
|
||||
|
||||
case 0x334: return PhysGrad3D<L,3,3,4>(NE, B, G, J, X, Y);
|
||||
case 0x346: return PhysGrad3D<L,3,4,6>(NE, B, G, J, X, Y);
|
||||
case 0x358: return PhysGrad3D<L,3,5,8>(NE, B, G, J, X, Y);
|
||||
default:
|
||||
{
|
||||
constexpr int MD = 8;
|
||||
constexpr int MQ = 8;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than " << MQ
|
||||
<< " 1D points are not supported!");
|
||||
PhysGrad3D<L,0,0,0,MD,MQ>(NE, B, G, J, X, Y, vdim, D1D, Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Unknown kernel");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
+22
-80
@@ -13,7 +13,6 @@
|
||||
#include "linearform.hpp"
|
||||
#include "pgridfunc.hpp"
|
||||
#include "tmop_tools.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -442,8 +441,8 @@ void TMOP_Metric_058::AssembleH(const DenseMatrix &Jpt,
|
||||
double TMOP_Metric_077::EvalW(const DenseMatrix &Jpt) const
|
||||
{
|
||||
ie.SetJacobian(Jpt.GetData());
|
||||
const double I2b = ie.Get_I2b();
|
||||
return 0.5*(I2b*I2b + 1./(I2b*I2b) - 2.);
|
||||
const double I2 = ie.Get_I2b();
|
||||
return 0.5*(I2*I2 + 1./(I2*I2) - 2.);
|
||||
}
|
||||
|
||||
void TMOP_Metric_077::EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const
|
||||
@@ -1039,10 +1038,11 @@ void DiscreteAdaptTC::SetTspecAtIndex(int idx, const ParGridFunction &tspec_)
|
||||
{
|
||||
const int vdim = tspec_.FESpace()->GetVDim(),
|
||||
dof_cnt = tspec_.Size()/vdim;
|
||||
const auto tspec__d = tspec_.Read();
|
||||
auto tspec_d = tspec.ReadWrite();
|
||||
const int offset = idx*dof_cnt;
|
||||
MFEM_FORALL(i, dof_cnt*vdim, tspec_d[i+offset] = tspec__d[i];);
|
||||
for (int i = 0; i < dof_cnt*vdim; i++)
|
||||
{
|
||||
tspec(i+idx*dof_cnt) = tspec_(i);
|
||||
}
|
||||
|
||||
FinalizeParDiscreteTargetSpec(tspec_);
|
||||
}
|
||||
|
||||
@@ -1102,33 +1102,34 @@ void DiscreteAdaptTC::SetDiscreteTargetBase(const GridFunction &tspec_)
|
||||
// make a copy of tspec->tspec_temp, increase its size, and
|
||||
// copy data from tspec_temp -> tspec, then add new entries
|
||||
Vector tspec_temp = tspec;
|
||||
tspec.UseDevice(true);
|
||||
tspec_sav.UseDevice(true);
|
||||
tspec.SetSize(ncomp*dof_cnt);
|
||||
|
||||
const auto tspec_temp_d = tspec_temp.Read();
|
||||
auto tspec_d = tspec.ReadWrite();
|
||||
MFEM_FORALL(i, tspec_temp.Size(), tspec_d[i] = tspec_temp_d[i];);
|
||||
for (int i = 0; i < tspec_temp.Size(); i++)
|
||||
{
|
||||
tspec(i) = tspec_temp(i);
|
||||
}
|
||||
|
||||
const auto tspec__d = tspec_.Read();
|
||||
const int offset = (ncomp-vdim)*dof_cnt;
|
||||
MFEM_FORALL(i, dof_cnt*vdim, tspec_d[i+offset] = tspec__d[i];);
|
||||
for (int i = 0; i < dof_cnt*vdim; i++)
|
||||
{
|
||||
tspec(i+(ncomp-vdim)*dof_cnt) = tspec_(i);
|
||||
}
|
||||
}
|
||||
|
||||
void DiscreteAdaptTC::SetTspecAtIndex(int idx, const GridFunction &tspec_)
|
||||
{
|
||||
const int vdim = tspec_.FESpace()->GetVDim(),
|
||||
dof_cnt = tspec_.Size()/vdim;
|
||||
for (int i = 0; i < dof_cnt*vdim; i++)
|
||||
{
|
||||
tspec(i+idx*dof_cnt) = tspec_(i);
|
||||
}
|
||||
|
||||
const auto tspec__d = tspec_.Read();
|
||||
auto tspec_d = tspec.ReadWrite();
|
||||
const int offset = idx*dof_cnt;
|
||||
MFEM_FORALL(i, dof_cnt*vdim, tspec_d[i+offset] = tspec__d[i];);
|
||||
FinalizeSerialDiscreteTargetSpec();
|
||||
}
|
||||
|
||||
void DiscreteAdaptTC::SetSerialDiscreteTargetSize(const GridFunction &tspec_)
|
||||
{
|
||||
|
||||
if (sizeidx > -1) { SetTspecAtIndex(sizeidx, tspec_); return; }
|
||||
sizeidx = ncomp;
|
||||
SetDiscreteTargetBase(tspec_);
|
||||
@@ -1256,17 +1257,16 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
|
||||
Vector shape(ndofs), tspec_vals(ntspec_dofs), par_vals,
|
||||
par_vals_c1, par_vals_c2, par_vals_c3;
|
||||
|
||||
Array<int> dofs;
|
||||
DenseMatrix D_rho(dim), Q_phi(dim), R_theta(dim);
|
||||
tspec_fesv->GetElementVDofs(e_id, dofs);
|
||||
tspec.UseDevice(true);
|
||||
tspec.GetSubVector(dofs, tspec_vals);
|
||||
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(q);
|
||||
tspec_fes->GetFE(e_id)->CalcShape(ip, shape);
|
||||
|
||||
Jtr(q) = Wideal; // Initialize to identity
|
||||
for (int d = 0; d < 4; d++)
|
||||
{
|
||||
@@ -1872,17 +1872,6 @@ void AdaptivityEvaluator::SetParMetaInfo(const ParMesh &m,
|
||||
}
|
||||
#endif
|
||||
|
||||
void AdaptivityEvaluator::ClearGeometricFactors()
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (pmesh) pmesh->DeleteGeometricFactors();
|
||||
if (pfes) pfes->GetParMesh()->DeleteGeometricFactors();
|
||||
#else
|
||||
if (mesh) mesh->DeleteGeometricFactors();
|
||||
if (fes) fes->GetMesh()->DeleteGeometricFactors();
|
||||
#endif
|
||||
}
|
||||
|
||||
AdaptivityEvaluator::~AdaptivityEvaluator()
|
||||
{
|
||||
delete fes;
|
||||
@@ -1910,7 +1899,6 @@ void TMOP_Integrator::EnableLimiting(const GridFunction &n0,
|
||||
{
|
||||
EnableLimiting(n0, w0, lfunc);
|
||||
lim_dist = &dist;
|
||||
if (PA.enabled) { EnableLimitingPA(n0); }
|
||||
}
|
||||
void TMOP_Integrator::EnableLimiting(const GridFunction &n0, Coefficient &w0,
|
||||
TMOP_LimiterFunction *lfunc)
|
||||
@@ -2056,8 +2044,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
PMatI.MultTranspose(shape, p);
|
||||
pos0.MultTranspose(shape, p0);
|
||||
val += lim_normal *
|
||||
lim_func->Eval(p, p0, d_vals(i)) *
|
||||
coeff0->Eval(*Tpr, ip);
|
||||
lim_func->Eval(p, p0, d_vals(i)) * coeff0->Eval(*Tpr, ip);
|
||||
}
|
||||
|
||||
if (adaptive_limiting)
|
||||
@@ -2737,8 +2724,6 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x,
|
||||
|
||||
void TMOP_Integrator::UpdateAfterMeshChange(const Vector &new_x)
|
||||
{
|
||||
PA.setup_Jtr = false;
|
||||
PA.setup_Grad = false;
|
||||
// Update zeta if adaptive limiting is enabled.
|
||||
if (zeta) { adapt_eval->ComputeAtNewPosition(new_x, *zeta); }
|
||||
}
|
||||
@@ -2894,49 +2879,6 @@ void TMOPComboIntegrator::ParEnableNormalization(const ParGridFunction &x)
|
||||
}
|
||||
#endif
|
||||
|
||||
void TMOPComboIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
for (int i = 0; i < tmopi.Size(); i++)
|
||||
{
|
||||
tmopi[i]->AssemblePA(fes);
|
||||
}
|
||||
}
|
||||
|
||||
void TMOPComboIntegrator::AssembleGradientDiagonalPA(const Vector &xe,
|
||||
Vector &de) const
|
||||
{
|
||||
for (int i = 0; i < tmopi.Size(); i++)
|
||||
{
|
||||
tmopi[i]->AssembleGradientDiagonalPA(xe, de);
|
||||
}
|
||||
}
|
||||
|
||||
void TMOPComboIntegrator::AddMultPA(const Vector &xe, Vector &ye) const
|
||||
{
|
||||
for (int i = 0; i < tmopi.Size(); i++)
|
||||
{
|
||||
tmopi[i]->AddMultPA(xe, ye);
|
||||
}
|
||||
}
|
||||
|
||||
void TMOPComboIntegrator::AddMultGradPA(const Vector &xe, const Vector &re,
|
||||
Vector &ce) const
|
||||
{
|
||||
for (int i = 0; i < tmopi.Size(); i++)
|
||||
{
|
||||
tmopi[i]->AddMultGradPA(xe, re, ce);
|
||||
}
|
||||
}
|
||||
|
||||
double TMOPComboIntegrator::GetGridFunctionEnergyPA(const Vector &xe) const
|
||||
{
|
||||
double energy = 0.0;
|
||||
for (int i = 0; i < tmopi.Size(); i++)
|
||||
{
|
||||
energy += tmopi[i]->GetGridFunctionEnergyPA(xe);
|
||||
}
|
||||
return energy;
|
||||
}
|
||||
|
||||
void InterpolateTMOP_QualityMetric(TMOP_QualityMetric &metric,
|
||||
const TargetConstructor &tc,
|
||||
|
||||
+6
-134
@@ -68,10 +68,6 @@ public:
|
||||
*/
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const = 0;
|
||||
|
||||
/** @brief Return the metric ID.
|
||||
*/
|
||||
virtual int Id() const { return 0; }
|
||||
};
|
||||
|
||||
|
||||
@@ -89,8 +85,6 @@ public:
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
|
||||
virtual int Id() const { return 1; }
|
||||
};
|
||||
|
||||
/// Skew metric, 2D.
|
||||
@@ -182,8 +176,6 @@ public:
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
|
||||
virtual int Id() const { return 2; }
|
||||
};
|
||||
|
||||
/// Shape & area, ideal barrier metric, 2D
|
||||
@@ -200,8 +192,6 @@ public:
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
|
||||
virtual int Id() const { return 7; }
|
||||
};
|
||||
|
||||
/// Shape & area metric, 2D
|
||||
@@ -288,6 +278,7 @@ public:
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
|
||||
};
|
||||
|
||||
/// Shape, ideal barrier metric, 2D
|
||||
@@ -305,6 +296,7 @@ public:
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
|
||||
};
|
||||
|
||||
/// Area, ideal barrier metric, 2D
|
||||
@@ -322,7 +314,6 @@ public:
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
|
||||
virtual int Id() const { return 77; }
|
||||
};
|
||||
|
||||
/// Shape & orientation metric, 2D.
|
||||
@@ -409,8 +400,6 @@ public:
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
|
||||
virtual int Id() const { return 302; }
|
||||
};
|
||||
|
||||
/// Shape, ideal barrier metric, 3D
|
||||
@@ -427,8 +416,6 @@ public:
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
|
||||
virtual int Id() const { return 303; }
|
||||
};
|
||||
|
||||
/// Volume metric, 3D
|
||||
@@ -445,8 +432,6 @@ public:
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
|
||||
virtual int Id() const { return 315; }
|
||||
};
|
||||
|
||||
/// Volume, ideal barrier metric, 3D
|
||||
@@ -481,8 +466,6 @@ public:
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
|
||||
virtual int Id() const { return 321; }
|
||||
};
|
||||
|
||||
/// Shifted barrier form of 3D metric 16 (volume, ideal barrier metric), 3D
|
||||
@@ -606,8 +589,6 @@ public:
|
||||
|
||||
virtual void ComputeAtNewPosition(const Vector &new_nodes,
|
||||
Vector &new_field) = 0;
|
||||
|
||||
void ClearGeometricFactors();
|
||||
};
|
||||
|
||||
/** @brief Base class representing target-matrix construction algorithms for
|
||||
@@ -683,14 +664,9 @@ public:
|
||||
nodes are used by all target types except IDEAL_SHAPE_UNIT_SIZE. */
|
||||
void SetNodes(const GridFunction &n) { nodes = &n; avg_volume = 0.0; }
|
||||
|
||||
/** @brief Get the nodes to be used in the target-matrix construction. */
|
||||
const GridFunction *GetNodes() const { return nodes; }
|
||||
|
||||
/// Used by target type IDEAL_SHAPE_EQUAL_SIZE. The default volume scale is 1.
|
||||
void SetVolumeScale(double vol_scale) { volume_scale = vol_scale; }
|
||||
|
||||
const TargetType &Type() const { return target_type; }
|
||||
|
||||
/// Checks if the target matrices contain non-trivial size specification.
|
||||
virtual bool ContainsVolumeInfo() const;
|
||||
|
||||
@@ -702,16 +678,6 @@ public:
|
||||
const Vector &elfun,
|
||||
DenseTensor &Jtr) const;
|
||||
|
||||
template<int DIM>
|
||||
bool ComputeElementTargetsPA(const FiniteElementSpace *fes,
|
||||
const IntegrationRule *ir,
|
||||
DenseTensor &Jtr,
|
||||
const Vector &xe = Vector()) const;
|
||||
virtual bool ComputeElementTargetsPA(const FiniteElementSpace *fes,
|
||||
const IntegrationRule *ir,
|
||||
DenseTensor &Jtr,
|
||||
const Vector &xe = Vector()) const;
|
||||
|
||||
virtual void ComputeElementTargetsGradient(const IntegrationRule &ir,
|
||||
const Vector &elfun,
|
||||
IsoparametricTransformation &Tpr,
|
||||
@@ -757,11 +723,6 @@ public:
|
||||
const Vector &elfun,
|
||||
DenseTensor &Jtr) const;
|
||||
|
||||
virtual bool ComputeElementTargetsPA(const FiniteElementSpace *fes,
|
||||
const IntegrationRule *ir,
|
||||
DenseTensor &Jtr,
|
||||
const Vector &xe = Vector()) const;
|
||||
|
||||
virtual void ComputeElementTargetsGradient(const IntegrationRule &ir,
|
||||
const Vector &elfun,
|
||||
IsoparametricTransformation &Tpr,
|
||||
@@ -804,19 +765,12 @@ protected:
|
||||
// Owned.
|
||||
AdaptivityEvaluator *adapt_eval;
|
||||
|
||||
// PA extension
|
||||
struct { mutable Vector tspec_e; } PA;
|
||||
|
||||
void FinalizeSerialDiscreteTargetSpec();
|
||||
#ifdef MFEM_USE_MPI
|
||||
void FinalizeParDiscreteTargetSpec(const ParGridFunction &tspec_);
|
||||
#endif
|
||||
|
||||
public: // MFEM_FORALL nvcc restriction that it must be public
|
||||
void SetDiscreteTargetBase(const GridFunction &tspec_);
|
||||
void SetTspecAtIndex(int idx, const GridFunction &tspec_);
|
||||
void FinalizeSerialDiscreteTargetSpec();
|
||||
#ifdef MFEM_USE_MPI
|
||||
void SetTspecAtIndex(int idx, const ParGridFunction &tspec_);
|
||||
void FinalizeParDiscreteTargetSpec(const ParGridFunction &tspec_);
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -901,7 +855,6 @@ public:
|
||||
const Vector &GetTspecPert1H() { return tspec_pert1h; }
|
||||
const Vector &GetTspecPert2H() { return tspec_pert2h; }
|
||||
const Vector &GetTspecPertMixH() { return tspec_pertmix; }
|
||||
const FiniteElementSpace *GetTspecFesv() const { return tspec_fesv; }
|
||||
|
||||
/** @brief Given an element and quadrature rule, computes ref->target
|
||||
transformation Jacobians for each quadrature point in the element.
|
||||
@@ -913,11 +866,6 @@ public:
|
||||
const Vector &elfun,
|
||||
DenseTensor &Jtr) const;
|
||||
|
||||
virtual bool ComputeElementTargetsPA(const FiniteElementSpace *fes,
|
||||
const IntegrationRule *ir,
|
||||
DenseTensor &Jtr,
|
||||
const Vector &xe = Vector()) const;
|
||||
|
||||
virtual void ComputeElementTargetsGradient(const IntegrationRule &ir,
|
||||
const Vector &elfun,
|
||||
IsoparametricTransformation &Tpr,
|
||||
@@ -993,25 +941,10 @@ protected:
|
||||
// output - the result of AssembleElementVector() (dof x dim).
|
||||
DenseMatrix DSh, DS, Jrt, Jpr, Jpt, P, PMatI, PMatO;
|
||||
|
||||
// PA extension
|
||||
struct
|
||||
{
|
||||
bool enabled;
|
||||
int dim, ne, nq;
|
||||
mutable DenseTensor Jtr;
|
||||
mutable bool setup_Grad, setup_Jtr;
|
||||
mutable Vector E, O, W, X0, H, C0, LD, H0;
|
||||
const DofToQuad *maps;
|
||||
const DofToQuad *maps_lim = nullptr;
|
||||
const GeometricFactors *geom;
|
||||
const FiniteElementSpace *fes;
|
||||
const Operator *R;
|
||||
const IntegrationRule *ir;
|
||||
} PA;
|
||||
|
||||
void ComputeNormalizationEnergies(const GridFunction &x,
|
||||
double &metric_energy, double &lim_energy);
|
||||
|
||||
|
||||
void AssembleElementVectorExact(const FiniteElement &el,
|
||||
ElementTransformation &T,
|
||||
const Vector &elfun, Vector &elvect);
|
||||
@@ -1082,7 +1015,7 @@ public:
|
||||
zeta_0(NULL), zeta(NULL), coeff_zeta(NULL), adapt_eval(NULL),
|
||||
discr_tc(dynamic_cast<DiscreteAdaptTC *>(tc)),
|
||||
fdflag(false), dxscale(1.0e3), fd_call_flag(false), exact_action(false)
|
||||
{ PA.enabled = false; }
|
||||
{ }
|
||||
|
||||
~TMOP_Integrator();
|
||||
|
||||
@@ -1150,45 +1083,6 @@ public:
|
||||
virtual void AssembleElementGrad(const FiniteElement &el,
|
||||
ElementTransformation &T,
|
||||
const Vector &elfun, DenseMatrix &elmat);
|
||||
/// PA extension
|
||||
void SetupGradPA(const Vector &xe) const;
|
||||
void EnableLimitingPA(const GridFunction &n0);
|
||||
void ComputeElementTargetsPA(const Vector &xe = Vector()) const;
|
||||
|
||||
using NonlinearFormIntegrator::GetGridFunctionEnergyPA;
|
||||
double GetGridFunctionEnergyPA_2D(const Vector&) const;
|
||||
double GetGridFunctionEnergyPA_C0_2D(const Vector&) const;
|
||||
double GetGridFunctionEnergyPA_3D(const Vector&) const;
|
||||
double GetGridFunctionEnergyPA_C0_3D(const Vector&) const;
|
||||
virtual double GetGridFunctionEnergyPA(const Vector&) const;
|
||||
|
||||
using NonlinearFormIntegrator::AssemblePA;
|
||||
virtual void AssemblePA(const FiniteElementSpace&);
|
||||
|
||||
virtual void AssembleGradientDiagonalPA(const Vector&, Vector&) const;
|
||||
void AssembleDiagonalPA_2D(Vector&) const;
|
||||
void AssembleDiagonalPA_3D(Vector&) const;
|
||||
void AssembleDiagonalPA_C0_2D(Vector&) const;
|
||||
void AssembleDiagonalPA_C0_3D(Vector&) const;
|
||||
|
||||
using NonlinearFormIntegrator::AddMultPA;
|
||||
void AddMultPA_2D(const Vector&, Vector&) const;
|
||||
void AddMultPA_3D(const Vector&, Vector&) const;
|
||||
void AddMultPA_C0_2D(const Vector&, Vector&) const;
|
||||
void AddMultPA_C0_3D(const Vector&, Vector&) const;
|
||||
virtual void AddMultPA(const Vector&, Vector&) const;
|
||||
|
||||
using NonlinearFormIntegrator::AddMultGradPA;
|
||||
void AddMultGradPA_2D(const Vector&, Vector&) const;
|
||||
void AddMultGradPA_3D(const Vector&, const Vector&, Vector&) const;
|
||||
void AddMultGradPA_C0_2D(const Vector&, const Vector&, Vector&) const;
|
||||
void AddMultGradPA_C0_3D(const Vector&, const Vector&, Vector&) const;
|
||||
virtual void AddMultGradPA(const Vector&, const Vector&, Vector&) const;
|
||||
|
||||
void AssembleGradPA_2D(const Vector&) const;
|
||||
void AssembleGradPA_3D(const Vector&) const;
|
||||
void AssembleGradPA_C0_2D(const Vector&) const;
|
||||
void AssembleGradPA_C0_3D(const Vector&) const;
|
||||
|
||||
DiscreteAdaptTC *GetDiscreteAdaptTC() const { return discr_tc; }
|
||||
|
||||
@@ -1211,17 +1105,6 @@ public:
|
||||
|
||||
/** @brief Flag to control if exact action of Integration is effected. */
|
||||
void SetExactActionFlag(bool flag_) { exact_action = flag_; }
|
||||
|
||||
void ReleaseTemporaryMemory()
|
||||
{
|
||||
if (PA.enabled)
|
||||
{
|
||||
PA.H.GetMemory().DeleteDevice();
|
||||
PA.H0.GetMemory().DeleteDevice();
|
||||
//PA.Jtr.GetMemory().DeleteDevice();
|
||||
//PA.setup_Jtr = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class TMOPComboIntegrator : public NonlinearFormIntegrator
|
||||
@@ -1270,17 +1153,6 @@ public:
|
||||
#ifdef MFEM_USE_MPI
|
||||
void ParEnableNormalization(const ParGridFunction &x);
|
||||
#endif
|
||||
|
||||
/// PA extension
|
||||
using NonlinearFormIntegrator::AssemblePA;
|
||||
virtual void AssemblePA(const FiniteElementSpace&);
|
||||
virtual void AssembleGradientDiagonalPA(const Vector&, Vector&) const;
|
||||
using NonlinearFormIntegrator::AddMultPA;
|
||||
virtual void AddMultPA(const Vector&, Vector&) const;
|
||||
using NonlinearFormIntegrator::AddMultGradPA;
|
||||
virtual void AddMultGradPA(const Vector&, const Vector&, Vector&) const;
|
||||
using NonlinearFormIntegrator::GetGridFunctionEnergyPA;
|
||||
virtual double GetGridFunctionEnergyPA(const Vector&) const;
|
||||
};
|
||||
|
||||
/// Interpolates the @a metric's values at the nodes of @a metric_gf.
|
||||
|
||||
-363
@@ -1,363 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "pgridfunc.hpp"
|
||||
#include "tmop_tools.hpp"
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
|
||||
void TMOP_Integrator::SetupGradPA(const Vector &xe) const
|
||||
{
|
||||
MFEM_VERIFY(PA.R, "PA extension setup has not been done!");
|
||||
PA.setup_Grad = true;
|
||||
|
||||
if (PA.dim == 2)
|
||||
{
|
||||
AssembleGradPA_2D(xe);
|
||||
if (coeff0) { AssembleGradPA_C0_2D(xe); }
|
||||
}
|
||||
|
||||
if (PA.dim == 3)
|
||||
{
|
||||
AssembleGradPA_3D(xe);
|
||||
if (coeff0) { AssembleGradPA_C0_3D(xe); }
|
||||
}
|
||||
}
|
||||
|
||||
// We might come here w/o knowing that PA will be used.
|
||||
// It is the case when EnableLimiting is called before the Setup => AssemblePA.
|
||||
void TMOP_Integrator::EnableLimitingPA(const GridFunction &n0)
|
||||
{
|
||||
MFEM_VERIFY(PA.enabled, "EnableLimitingPA but PA is not enabled!");
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
|
||||
// Nodes0
|
||||
const FiniteElementSpace *n0_fes = n0.FESpace();
|
||||
const Operator *n0_R = n0_fes->GetElementRestriction(ordering);
|
||||
PA.X0.SetSize(n0_R->Height(), Device::GetMemoryType());
|
||||
PA.X0.UseDevice(true);
|
||||
n0_R->Mult(n0, PA.X0);
|
||||
|
||||
// Get the 1D maps for the distance FE space.
|
||||
const IntegrationRule &ir = *EnergyIntegrationRule(*n0.FESpace()->GetFE(0));
|
||||
PA.maps_lim =
|
||||
&lim_dist->FESpace()->GetFE(0)->GetDofToQuad(ir, DofToQuad::TENSOR);
|
||||
|
||||
// lim_dist & lim_func checks
|
||||
MFEM_VERIFY(lim_dist, "No lim_dist!")
|
||||
const FiniteElementSpace *ld_fes = lim_dist->FESpace();
|
||||
const Operator *ld_R = ld_fes->GetElementRestriction(ordering);
|
||||
MFEM_VERIFY(ld_R, "No lim_dist restriction operator found!");
|
||||
PA.LD.SetSize(ld_R->Height(), Device::GetMemoryType());
|
||||
PA.LD.UseDevice(true);
|
||||
ld_R->Mult(*lim_dist, PA.LD);
|
||||
|
||||
// Only TMOP_QuadraticLimiter is supported
|
||||
MFEM_VERIFY(lim_func, "No lim_func!")
|
||||
MFEM_VERIFY(dynamic_cast<TMOP_QuadraticLimiter*>(lim_func),
|
||||
"Only TMOP_QuadraticLimiter is supported");
|
||||
}
|
||||
|
||||
bool TargetConstructor::ComputeElementTargetsPA(const FiniteElementSpace *fes,
|
||||
const IntegrationRule *ir,
|
||||
DenseTensor &Jtr,
|
||||
const Vector &xe) const
|
||||
{
|
||||
MFEM_VERIFY(Jtr.SizeI() == Jtr.SizeJ() && Jtr.SizeI() > 1, "");
|
||||
const int dim = Jtr.SizeI();
|
||||
if (dim == 2) { return ComputeElementTargetsPA<2>(fes, ir, Jtr, xe); }
|
||||
if (dim == 3) { return ComputeElementTargetsPA<3>(fes, ir, Jtr, xe); }
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AnalyticAdaptTC::ComputeElementTargetsPA(const FiniteElementSpace *fes,
|
||||
const IntegrationRule *ir,
|
||||
DenseTensor &Jtr,
|
||||
const Vector &xe) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Code paths leading to ComputeElementTargets:
|
||||
// - GetElementEnergy(elfun) which is done through GetGridFunctionEnergyPA(x)
|
||||
// - AssembleElementVectorExact(elfun)
|
||||
// - AssembleElementGradExact(elfun)
|
||||
// - EnableNormalization(x) -> ComputeNormalizationEnergies(x)
|
||||
// - (AssembleElementVectorFD(elfun))
|
||||
// - (AssembleElementGradFD(elfun))
|
||||
// ============================================================================
|
||||
// - TargetConstructor():
|
||||
// - IDEAL_SHAPE_UNIT_SIZE: Wideal
|
||||
// - IDEAL_SHAPE_EQUAL_SIZE: α * Wideal
|
||||
// - IDEAL_SHAPE_GIVEN_SIZE: β * Wideal
|
||||
// - GIVEN_SHAPE_AND_SIZE: β * Wideal
|
||||
// - AnalyticAdaptTC(elfun):
|
||||
// - GIVEN_FULL: matrix_tspec->Eval(Jtr(elfun))
|
||||
// - DiscreteAdaptTC():
|
||||
// - IDEAL_SHAPE_GIVEN_SIZE: size^{1.0/dim} * Jtr(i) (size)
|
||||
// - GIVEN_SHAPE_AND_SIZE: Jtr(i) *= D_rho (ratio)
|
||||
// Jtr(i) *= Q_phi (skew)
|
||||
// Jtr(i) *= R_theta (orientation)
|
||||
void TMOP_Integrator::ComputeElementTargetsPA(const Vector &xe) const
|
||||
{
|
||||
PA.setup_Jtr = false;
|
||||
const FiniteElementSpace *fes = PA.fes;
|
||||
const IntegrationRule *ir = EnergyIntegrationRule(*fes->GetFE(0));
|
||||
const TargetConstructor::TargetType &target_type = targetC->Type();
|
||||
const DiscreteAdaptTC *discr_tc = GetDiscreteAdaptTC();
|
||||
|
||||
// Skip when TargetConstructor needs the nodes but have not been set
|
||||
const bool use_nodes =
|
||||
target_type == TargetConstructor::IDEAL_SHAPE_EQUAL_SIZE ||
|
||||
target_type == TargetConstructor::IDEAL_SHAPE_GIVEN_SIZE ||
|
||||
target_type == TargetConstructor::GIVEN_SHAPE_AND_SIZE;
|
||||
if (targetC && !discr_tc && use_nodes && !targetC->GetNodes()) { return; }
|
||||
|
||||
// Try to use the TargetConstructor ComputeElementTargetsPA
|
||||
PA.setup_Jtr = targetC->ComputeElementTargetsPA(fes, ir, PA.Jtr);
|
||||
if (PA.setup_Jtr) { return; }
|
||||
|
||||
// Defaulting to host version
|
||||
PA.Jtr.HostWrite();
|
||||
|
||||
const int NE = PA.ne;
|
||||
const int NQ = PA.nq;
|
||||
const int dim = PA.dim;
|
||||
DenseTensor &Jtr = PA.Jtr;
|
||||
|
||||
Vector x;
|
||||
const bool useable_input_vector = xe.Size() > 0;
|
||||
const bool use_input_vector = target_type == TargetConstructor::GIVEN_FULL;
|
||||
|
||||
if (use_input_vector && !useable_input_vector) { return; }
|
||||
|
||||
if (discr_tc && !discr_tc->GetTspecFesv()) { return; }
|
||||
|
||||
if (use_input_vector)
|
||||
{
|
||||
x.SetSize(PA.R->Width(), Device::GetMemoryType());
|
||||
x.UseDevice(true);
|
||||
PA.R->MultTranspose(xe, x);
|
||||
// Scale by weights
|
||||
const int N = PA.W.Size();
|
||||
const auto W = Reshape(PA.W.Read(), N);
|
||||
auto X = Reshape(x.ReadWrite(), N);
|
||||
MFEM_FORALL(i, N, X(i) /= W(i););
|
||||
}
|
||||
|
||||
// Use TargetConstructor::ComputeElementTargets to fill the PA.Jtr
|
||||
Vector elfun;
|
||||
Array<int> vdofs;
|
||||
DenseTensor J;
|
||||
for (int e = 0; e < NE; e++)
|
||||
{
|
||||
const FiniteElement &fe = *fes->GetFE(e);
|
||||
if (use_input_vector)
|
||||
{
|
||||
fes->GetElementVDofs(e, vdofs);
|
||||
x.GetSubVector(vdofs, elfun);
|
||||
}
|
||||
J.UseExternalData(Jtr(e*NQ).Data(), dim, dim, NQ);
|
||||
targetC->ComputeElementTargets(e, fe, *ir, elfun, J);
|
||||
}
|
||||
PA.setup_Jtr = true;
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
PA.enabled = true;
|
||||
MFEM_ASSERT(fes.GetMesh()->GetNE() > 0, "");
|
||||
PA.ir = EnergyIntegrationRule(*fes.GetFE(0));
|
||||
const IntegrationRule *ir = PA.ir;
|
||||
MFEM_ASSERT(fes.GetOrdering() == Ordering::byNODES,
|
||||
"PA Only supports Ordering::byNODES!");
|
||||
|
||||
PA.fes = &fes;
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const int nq = PA.nq = ir->GetNPoints();
|
||||
const int ne = PA.ne = fes.GetMesh()->GetNE();
|
||||
const int dim = PA.dim = mesh->Dimension();
|
||||
MFEM_VERIFY(PA.dim == 2 || PA.dim == 3, "Not yet implemented!");
|
||||
|
||||
const DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
PA.maps = &fes.GetFE(0)->GetDofToQuad(*ir, mode);
|
||||
PA.geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mode);
|
||||
|
||||
// Energy vector
|
||||
PA.E.UseDevice(true);
|
||||
PA.E.SetSize(ne*nq, Device::GetDeviceMemoryType());
|
||||
|
||||
// Setup initialization
|
||||
PA.setup_Jtr = false;
|
||||
PA.setup_Grad = false;
|
||||
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
const MemoryType temp_type = Device::GetDeviceMemoryType() == MemoryType::DEVICE_UMPIRE
|
||||
? MemoryType::DEVICE_UMPIRE_2 : Device::GetDeviceMemoryType();
|
||||
#else
|
||||
const MemoryType temp_type = Device::GetDeviceMemoryType();
|
||||
#endif
|
||||
|
||||
// H for Grad
|
||||
PA.H.SetSize(dim*dim * dim*dim * nq*ne, temp_type);
|
||||
// H0 for coeff0
|
||||
PA.H0.SetSize(dim * dim * nq*ne, temp_type);
|
||||
|
||||
// Restriction setup
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
PA.R = fes.GetElementRestriction(ordering);
|
||||
MFEM_VERIFY(PA.R, "Not yet implemented!");
|
||||
|
||||
// Weight of the R^t
|
||||
PA.W.SetSize(PA.R->Width(), Device::GetDeviceMemoryType());
|
||||
PA.W.UseDevice(true);
|
||||
PA.O.SetSize(dim*ne*nq, Device::GetDeviceMemoryType());
|
||||
PA.O.UseDevice(true);
|
||||
PA.O = 1.0;
|
||||
PA.R->MultTranspose(PA.O, PA.W);
|
||||
|
||||
// Scalar vector of '1'
|
||||
PA.O.SetSize(ne*nq, Device::GetDeviceMemoryType());
|
||||
PA.O = 1.0;
|
||||
|
||||
// TargetConstructor TargetType setup
|
||||
PA.Jtr.SetSize(dim, dim, PA.ne*PA.nq);//, temp_type);
|
||||
ComputeElementTargetsPA();
|
||||
|
||||
// Coeff0 PA.C0
|
||||
PA.C0.UseDevice(true);
|
||||
if (coeff0 == nullptr)
|
||||
{
|
||||
PA.C0.SetSize(1, Device::GetMemoryType());
|
||||
PA.C0.HostWrite();
|
||||
PA.C0(0) = 0.0;
|
||||
}
|
||||
else if (ConstantCoefficient* cQ =
|
||||
dynamic_cast<ConstantCoefficient*>(coeff0))
|
||||
{
|
||||
PA.C0.SetSize(1, Device::GetMemoryType());
|
||||
PA.C0.HostWrite();
|
||||
PA.C0(0) = cQ->constant;
|
||||
}
|
||||
else
|
||||
{
|
||||
PA.C0.SetSize(PA.nq * PA.ne, Device::GetMemoryType());
|
||||
auto C0 = Reshape(PA.C0.HostWrite(), PA.nq, PA.ne);
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
ElementTransformation& T = *fes.GetElementTransformation(e);
|
||||
for (int q = 0; q < nq; ++q)
|
||||
{
|
||||
C0(q,e) = coeff0->Eval(T, ir->IntPoint(q));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (coeff0)
|
||||
{
|
||||
MFEM_VERIFY(nodes0, "nodes0 has not been set!");
|
||||
EnableLimitingPA(*nodes0);
|
||||
}
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleGradientDiagonalPA(const Vector &xe,
|
||||
Vector &de) const
|
||||
{
|
||||
MFEM_VERIFY(PA.R, "PA extension setup has not been done!");
|
||||
|
||||
if (!PA.setup_Jtr) { ComputeElementTargetsPA(xe); }
|
||||
|
||||
if (!PA.setup_Grad) { SetupGradPA(xe); }
|
||||
|
||||
if (PA.dim == 2)
|
||||
{
|
||||
AssembleDiagonalPA_2D(de);
|
||||
if (coeff0) { AssembleDiagonalPA_C0_2D(de); }
|
||||
}
|
||||
else if (PA.dim == 3)
|
||||
{
|
||||
AssembleDiagonalPA_3D(de);
|
||||
if (coeff0) { AssembleDiagonalPA_C0_3D(de); }
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("3D diagonal computation is WIP.");
|
||||
}
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AddMultPA(const Vector &xe, Vector &ye) const
|
||||
{
|
||||
if (!PA.setup_Jtr) { ComputeElementTargetsPA(); }
|
||||
|
||||
if (PA.dim == 2)
|
||||
{
|
||||
AddMultPA_2D(xe,ye);
|
||||
if (coeff0) { AddMultPA_C0_2D(xe,ye); }
|
||||
}
|
||||
|
||||
if (PA.dim == 3)
|
||||
{
|
||||
AddMultPA_3D(xe,ye);
|
||||
if (coeff0) { AddMultPA_C0_3D(xe,ye); }
|
||||
}
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AddMultGradPA(const Vector &xe,
|
||||
const Vector &re, Vector &ce) const
|
||||
{
|
||||
if (!PA.setup_Jtr) { ComputeElementTargetsPA(xe); }
|
||||
|
||||
if (!PA.setup_Grad) { SetupGradPA(xe); }
|
||||
|
||||
if (PA.dim == 2)
|
||||
{
|
||||
AddMultGradPA_2D(re,ce);
|
||||
if (coeff0) { AddMultGradPA_C0_2D(xe,re,ce); }
|
||||
}
|
||||
|
||||
if (PA.dim == 3)
|
||||
{
|
||||
AddMultGradPA_3D(xe,re,ce);
|
||||
if (coeff0) { AddMultGradPA_C0_3D(xe,re,ce); }
|
||||
}
|
||||
}
|
||||
|
||||
double TMOP_Integrator::GetGridFunctionEnergyPA(const Vector &xe) const
|
||||
{
|
||||
double energy = 0.0;
|
||||
|
||||
ComputeElementTargetsPA(xe);
|
||||
|
||||
if (PA.dim == 2)
|
||||
{
|
||||
energy = GetGridFunctionEnergyPA_2D(xe);
|
||||
if (coeff0) { energy += GetGridFunctionEnergyPA_C0_2D(xe); }
|
||||
}
|
||||
|
||||
if (PA.dim == 3)
|
||||
{
|
||||
energy = GetGridFunctionEnergyPA_3D(xe);
|
||||
if (coeff0) { energy += GetGridFunctionEnergyPA_C0_3D(xe); }
|
||||
}
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_TMOP_PA_HPP
|
||||
#define MFEM_TMOP_PA_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
|
||||
#include "../fem/kernels.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace kernels
|
||||
{
|
||||
|
||||
/// Generic emplace
|
||||
template<typename K, const int N,
|
||||
typename Key_t = typename K::Key_t,
|
||||
typename Kernel_t = typename K::Kernel_t>
|
||||
void emplace(std::unordered_map<Key_t, Kernel_t> &map)
|
||||
{
|
||||
constexpr Key_t key = K::template GetKey<N>();
|
||||
constexpr Kernel_t value = K::template GetValue<key>();
|
||||
map.emplace(key, value);
|
||||
}
|
||||
|
||||
/// Instances
|
||||
template<class K, typename T, T... idx>
|
||||
struct instances
|
||||
{
|
||||
static void Fill(std::unordered_map<typename K::Key_t,
|
||||
typename K::Kernel_t> &map)
|
||||
{
|
||||
using unused = int[];
|
||||
(void) unused {0, (emplace<K,idx>(map), 0)... };
|
||||
}
|
||||
};
|
||||
|
||||
/// Cat instances
|
||||
template<class K, typename Offset, typename Lhs, typename Rhs> struct cat;
|
||||
template<class K, typename T, T Offset, T... Lhs, T... Rhs>
|
||||
struct cat<K, std::integral_constant<T, Offset>,
|
||||
instances<K, T, Lhs...>,
|
||||
instances<K, T, Rhs...> >
|
||||
{ using type = instances<K, T, Lhs..., (Offset + Rhs)...>; };
|
||||
|
||||
/// Sequence, empty and one element terminal cases
|
||||
template<class K, typename T, typename N>
|
||||
struct sequence
|
||||
{
|
||||
using Lhs = std::integral_constant<T, N::value/2>;
|
||||
using Rhs = std::integral_constant<T, N::value-Lhs::value>;
|
||||
using type = typename cat<K, Lhs,
|
||||
typename sequence<K, T, Lhs>::type,
|
||||
typename sequence<K, T, Rhs>::type>::type;
|
||||
};
|
||||
|
||||
template<class K, typename T>
|
||||
struct sequence<K, T, std::integral_constant<T,0> >
|
||||
{ using type = instances<K,T>; };
|
||||
|
||||
template<class K, typename T>
|
||||
struct sequence<K, T, std::integral_constant<T,1> >
|
||||
{ using type = instances<K,T,0>; };
|
||||
|
||||
/// Make_sequence
|
||||
template<class Instance, typename T = typename Instance::Key_t>
|
||||
using make_sequence =
|
||||
typename sequence<Instance, T, std::integral_constant<T,Instance::N> >::type;
|
||||
|
||||
/// Instantiator class
|
||||
template<class Instance,
|
||||
typename Key_t = typename Instance::Key_t,
|
||||
typename Return_t = typename Instance::Return_t,
|
||||
typename Kernel_t = typename Instance::Kernel_t>
|
||||
class Instantiator
|
||||
{
|
||||
private:
|
||||
using map_t = std::unordered_map<Key_t, Kernel_t>;
|
||||
map_t map;
|
||||
|
||||
public:
|
||||
Instantiator() { make_sequence<Instance>().Fill(map); }
|
||||
|
||||
bool Find(const Key_t id)
|
||||
{
|
||||
return (map.find(id) != map.end()) ? true : false;
|
||||
}
|
||||
|
||||
Kernel_t At(const Key_t id) { return map.at(id); }
|
||||
};
|
||||
|
||||
/// MFEM_REGISTER_TMOP_KERNELS macro:
|
||||
/// - forward declaration of the kernel
|
||||
/// - kernel pointer declaration
|
||||
/// - struct K##name##_T definition
|
||||
/// - Instantiator definition
|
||||
/// - re-use kernel return type and name before its body
|
||||
#define MFEM_REGISTER_TMOP_KERNELS(return_t, kernel, ...) \
|
||||
template<int T_D1D = 0, int T_Q1D = 0, int T_MAX = 0> \
|
||||
return_t kernel(__VA_ARGS__);\
|
||||
typedef return_t (*kernel##_p)(__VA_ARGS__);\
|
||||
struct K##kernel##_T {\
|
||||
static const int N = 14;\
|
||||
using Key_t = std::size_t;\
|
||||
using Kernel_t = kernel##_p;\
|
||||
using Return_t = return_t;\
|
||||
template<Key_t I> static constexpr Key_t GetKey() noexcept { return \
|
||||
I==0 ? 0x22 : I==1 ? 0x23 : I==2 ? 0x24 : I==3 ? 0x25 : I==4 ? 0x26 :\
|
||||
I==5 ? 0x33 : I==6 ? 0x34 : I==7 ? 0x35 : I==8 ? 0x36 :\
|
||||
I==9 ? 0x44 : I==10 ? 0x45 : I==11 ? 0x46 :\
|
||||
I==12 ? 0x55 : I==13 ? 0x56 : 0; }\
|
||||
template<Key_t ID> static constexpr Kernel_t GetValue() noexcept\
|
||||
{ return &kernel<(ID>>4)&0xF, ID&0xF>; }\
|
||||
};\
|
||||
static kernels::Instantiator<K##kernel##_T> K##kernel;\
|
||||
template<int T_D1D, int T_Q1D, int T_MAX> return_t kernel(__VA_ARGS__)
|
||||
|
||||
/// MFEM_LAUNCH_TMOP_KERNEL macro
|
||||
#define MFEM_LAUNCH_TMOP_KERNEL(kernel, id, ...)\
|
||||
if (K##kernel.Find(id)) { return K##kernel.At(id)(__VA_ARGS__,0,0); }\
|
||||
else {\
|
||||
constexpr int T_MAX = 4;\
|
||||
MFEM_VERIFY(D1D <= MAX_D1D && Q1D <= MAX_Q1D, "Max size error!");\
|
||||
return kernel<0,0,T_MAX>(__VA_ARGS__,D1D,Q1D); }
|
||||
|
||||
} // namespace kernels
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_TMOP_PA_HPP
|
||||
@@ -1,161 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/* // Original i-j assembly (old invariants code).
|
||||
for (int e = 0; e < NE; e++)
|
||||
{
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
el.CalcDShape(ip, DSh);
|
||||
Mult(DSh, Jrt, DS);
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
for (int r = 0; r < dim; r++)
|
||||
{
|
||||
for (int c = 0; c < dim; c++)
|
||||
{
|
||||
for (int rr = 0; rr < dim; rr++)
|
||||
{
|
||||
for (int cc = 0; cc < dim; cc++)
|
||||
{
|
||||
const double H = h(r, c, rr, cc);
|
||||
A(e, i + r*dof, j + rr*dof) +=
|
||||
weight_q * DS(i, c) * DS(j, cc) * H;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AssembleDiagonalPA_Kernel_2D,
|
||||
const int NE,
|
||||
const Array<double> &b,
|
||||
const Array<double> &g,
|
||||
const DenseTensor &j,
|
||||
const Vector &h,
|
||||
Vector &diagonal,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
const auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
const auto J = Reshape(j.Read(), DIM, DIM, Q1D, Q1D, NE);
|
||||
const auto H = Reshape(h.Read(), DIM, DIM, DIM, DIM, Q1D, Q1D, NE);
|
||||
|
||||
auto D = Reshape(diagonal.ReadWrite(), D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
|
||||
MFEM_SHARED double qd[DIM*DIM*MQ1*MD1];
|
||||
DeviceTensor<4,double> QD(qd, DIM, DIM, MQ1, MD1);
|
||||
|
||||
for (int v = 0; v < DIM; v++)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
QD(0,0,qx,dy) = 0.0;
|
||||
QD(0,1,qx,dy) = 0.0;
|
||||
QD(1,0,qx,dy) = 0.0;
|
||||
QD(1,1,qx,dy) = 0.0;
|
||||
|
||||
MFEM_UNROLL(MQ1);
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,e);
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double j[4];
|
||||
ConstDeviceMatrix Jrt(j,2,2);
|
||||
kernels::CalcInverse<2>(Jtr, j);
|
||||
|
||||
const double gg = G(qy,dy) * G(qy,dy);
|
||||
const double gb = G(qy,dy) * B(qy,dy);
|
||||
const double bb = B(qy,dy) * B(qy,dy);
|
||||
const double bgb[4] = { bb, gb, gb, gg };
|
||||
ConstDeviceMatrix BG(bgb,2,2);
|
||||
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
const double Jij = Jrt(i,i) * Jrt(j,j);
|
||||
const double alpha = Jij * BG(i,j);
|
||||
QD(i,j,qx,dy) += alpha * H(v,i,v,j,qx,qy,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double d = 0.0;
|
||||
MFEM_UNROLL(MQ1);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double gg = G(qx,dx) * G(qx,dx);
|
||||
const double gb = G(qx,dx) * B(qx,dx);
|
||||
const double bb = B(qx,dx) * B(qx,dx);
|
||||
d += gg * QD(0,0,qx,dy);
|
||||
d += gb * QD(0,1,qx,dy);
|
||||
d += gb * QD(1,0,qx,dy);
|
||||
d += bb * QD(1,1,qx,dy);
|
||||
}
|
||||
D(dx,dy,v,e) += d;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleDiagonalPA_2D(Vector &D) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
const Vector &H = PA.H;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AssembleDiagonalPA_Kernel_2D,id,N,B,G,J,H,D);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,96 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AssembleDiagonalPA_Kernel_C0_2D,
|
||||
const int NE,
|
||||
const Array<double> &b,
|
||||
const Vector &h0,
|
||||
Vector &diagonal,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
const auto H0 = Reshape(h0.Read(), DIM, DIM, Q1D, Q1D, NE);
|
||||
|
||||
auto D = Reshape(diagonal.ReadWrite(), D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
|
||||
MFEM_SHARED double qd[MQ1*MD1];
|
||||
DeviceTensor<2,double> QD(qd, MQ1, MD1);
|
||||
|
||||
for (int v = 0; v < DIM; v++)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
QD(qx,dy) = 0.0;
|
||||
MFEM_UNROLL(MQ1);
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double bb = B(qy,dy) * B(qy,dy);
|
||||
QD(qx,dy) += bb * H0(v,v,qx,qy,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double d = 0.0;
|
||||
MFEM_UNROLL(MQ1);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double bb = B(qx,dx) * B(qx,dx);
|
||||
d += bb * QD(qx,dy);
|
||||
}
|
||||
D(dx,dy,v,e) += d;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleDiagonalPA_C0_2D(Vector &D) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Vector &H0 = PA.H0;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AssembleDiagonalPA_Kernel_C0_2D,id,N,B,H0,D);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,128 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AddMultGradPA_Kernel_2D,
|
||||
const int NE,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const DenseTensor &j_,
|
||||
const Vector &h_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
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 b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, NE);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, DIM, NE);
|
||||
const auto H = Reshape(h_.Read(), DIM, DIM, DIM, DIM, Q1D, Q1D, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double XY[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[4][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[4][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X,XY);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1,NBZ>(D1D,Q1D,BG,XY,DQ);
|
||||
kernels::GradY<MD1,MQ1,NBZ>(D1D,Q1D,BG,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,e);
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[4];
|
||||
kernels::CalcInverse<2>(Jtr, Jrt);
|
||||
|
||||
// Jpr = X^T.DSh
|
||||
double Jpr[4];
|
||||
kernels::PullGrad<MQ1,NBZ>(qx,qy,QQ,Jpr);
|
||||
|
||||
// Jpt = Jpr . Jrt
|
||||
double Jpt[4];
|
||||
kernels::Mult(2,2,2, Jpr, Jrt, Jpt);
|
||||
|
||||
// B = Jpt : H
|
||||
double B[4];
|
||||
DeviceMatrix M(B,2,2);
|
||||
ConstDeviceMatrix J(Jpt,2,2);
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
M(i,j) = 0.0;
|
||||
for (int r = 0; r < DIM; r++)
|
||||
{
|
||||
for (int c = 0; c < DIM; c++)
|
||||
{
|
||||
M(i,j) += H(r,c,i,j,qx,qy,e) * J(r,c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// C = Jrt . B
|
||||
double C[4];
|
||||
kernels::MultABt(2,2,2, Jrt, B, C);
|
||||
|
||||
// Overwrite QQ = Jrt . (Jpt : H)^t
|
||||
kernels::PushGrad<MQ1,NBZ>(qx,qy, C, QQ);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
kernels::LoadBGt<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
kernels::GradYt<MD1,MQ1,NBZ>(D1D,Q1D,BG,QQ,DQ);
|
||||
kernels::GradXt<MD1,MQ1,NBZ>(D1D,Q1D,BG,DQ,Y,e);
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AddMultGradPA_2D(const Vector &R, Vector &C) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
const Vector &H = PA.H;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultGradPA_Kernel_2D,id,N,B,G,J,H,R,C);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,107 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AddMultGradPA_Kernel_C0_2D,
|
||||
const int NE,
|
||||
const Array<double> &b_,
|
||||
const Vector &h0_,
|
||||
const Vector &r_,
|
||||
Vector &c_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
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 H0 = Reshape(h0_.Read(), DIM, DIM, Q1D, Q1D, NE);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto R = Reshape(r_.Read(), D1D, D1D, DIM, NE);
|
||||
|
||||
auto Y = Reshape(c_.ReadWrite(), D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
|
||||
MFEM_SHARED double XY[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[2][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[2][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,R,XY);
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
|
||||
kernels::EvalX<MD1,MQ1,NBZ>(D1D,Q1D,B,XY,DQ);
|
||||
kernels::EvalY<MD1,MQ1,NBZ>(D1D,Q1D,B,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
// Xh = X^T . Sh
|
||||
double Xh[2];
|
||||
kernels::PullEval<MQ1,NBZ>(qx,qy,QQ,Xh);
|
||||
|
||||
double B[4];
|
||||
DeviceMatrix H(B,2,2);
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
H(i,j) = H0(i,j,qx,qy,e);
|
||||
}
|
||||
}
|
||||
|
||||
// p2 = B . Xh
|
||||
double p2[2];
|
||||
kernels::Mult(2,2,B,Xh,p2);
|
||||
kernels::PushEval<MQ1,NBZ>(qx,qy,p2,QQ);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
kernels::LoadBt<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
kernels::EvalXt<MD1,MQ1,NBZ>(D1D,Q1D,B,QQ,DQ);
|
||||
kernels::EvalYt<MD1,MQ1,NBZ>(D1D,Q1D,B,DQ,Y,e);
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AddMultGradPA_C0_2D(const Vector &X, const Vector &R,
|
||||
Vector &C) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Vector &H0 = PA.H0;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultGradPA_Kernel_C0_2D,id,N,B,H0,R,C);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,247 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
#include "../linalg/dinvariants.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
using Args = kernels::InvariantsEvaluator2D::Buffers;
|
||||
|
||||
// weight * ddI1
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalH_001(const int e, const int qx, const int qy,
|
||||
const double weight, const double *Jpt,
|
||||
DeviceTensor<7,double> H)
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
double ddI1[4];
|
||||
kernels::InvariantsEvaluator2D ie(Args().J(Jpt).ddI1(ddI1));
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
ConstDeviceMatrix ddi1(ie.Get_ddI1(i,j),DIM,DIM);
|
||||
for (int r = 0; r < DIM; r++)
|
||||
{
|
||||
for (int c = 0; c < DIM; c++)
|
||||
{
|
||||
const double h = ddi1(r,c);
|
||||
H(r,c,i,j,qx,qy,e) = weight * h;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0.5 * weight * dI1b
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalH_002(const int e, const int qx, const int qy,
|
||||
const double weight, const double *Jpt,
|
||||
DeviceTensor<7,double> H)
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
double ddI1[4], ddI1b[4], dI2b[4];
|
||||
kernels::InvariantsEvaluator2D ie(Args()
|
||||
.J(Jpt)
|
||||
.ddI1(ddI1)
|
||||
.ddI1b(ddI1b)
|
||||
.dI2b(dI2b));
|
||||
const double w = 0.5 * weight;
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
ConstDeviceMatrix ddi1b(ie.Get_ddI1b(i,j),DIM,DIM);
|
||||
for (int r = 0; r < DIM; r++)
|
||||
{
|
||||
for (int c = 0; c < DIM; c++)
|
||||
{
|
||||
const double h = ddi1b(r,c);
|
||||
H(r,c,i,j,qx,qy,e) = w * h;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalH_007(const int e, const int qx, const int qy,
|
||||
const double weight, const double *Jpt,
|
||||
DeviceTensor<7,double> H)
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
double ddI1[4], ddI2[4], dI1[4], dI2[4], dI2b[4];
|
||||
kernels::InvariantsEvaluator2D ie(Args()
|
||||
.J(Jpt)
|
||||
.ddI1(ddI1)
|
||||
.ddI2(ddI2)
|
||||
.dI1(dI1)
|
||||
.dI2(dI2)
|
||||
.dI2b(dI2b));
|
||||
const double c1 = 1./ie.Get_I2();
|
||||
const double c2 = weight*c1*c1;
|
||||
const double c3 = ie.Get_I1()*c2;
|
||||
ConstDeviceMatrix di1(ie.Get_dI1(),DIM,DIM);
|
||||
ConstDeviceMatrix di2(ie.Get_dI2(),DIM,DIM);
|
||||
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
ConstDeviceMatrix ddi1(ie.Get_ddI1(i,j),DIM,DIM);
|
||||
ConstDeviceMatrix ddi2(ie.Get_ddI2(i,j),DIM,DIM);
|
||||
for (int r = 0; r < DIM; r++)
|
||||
{
|
||||
for (int c = 0; c < DIM; c++)
|
||||
{
|
||||
H(r,c,i,j,qx,qy,e) =
|
||||
weight * (1.0 + c1) * ddi1(r,c)
|
||||
- c3 * ddi2(r,c)
|
||||
- c2 * ( di1(i,j) * di2(r,c) + di2(i,j) * di1(r,c) )
|
||||
+ 2.0 * c1 * c3 * di2(r,c) * di2(i,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalH_077(const int e, const int qx, const int qy,
|
||||
const double weight, const double *Jpt,
|
||||
DeviceTensor<7,double> H)
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
double dI2[4], dI2b[4], ddI2[4];
|
||||
kernels::InvariantsEvaluator2D ie(Args()
|
||||
.J(Jpt)
|
||||
.dI2(dI2)
|
||||
.dI2b(dI2b)
|
||||
.ddI2(ddI2));
|
||||
const double I2 = ie.Get_I2(), I2inv_sq = 1.0 / (I2 * I2);
|
||||
ConstDeviceMatrix di2(ie.Get_dI2(),DIM,DIM);
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
ConstDeviceMatrix ddi2(ie.Get_ddI2(i,j),DIM,DIM);
|
||||
for (int r = 0; r < DIM; r++)
|
||||
{
|
||||
for (int c = 0; c < DIM; c++)
|
||||
{
|
||||
H(r,c,i,j,qx,qy,e) =
|
||||
weight * 0.5 * (1.0 - I2inv_sq) * ddi2(r,c)
|
||||
+ weight * (I2inv_sq / I2) * di2(r,c) * di2(i,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, SetupGradPA_2D,
|
||||
const Vector &x_,
|
||||
const double metric_normal,
|
||||
const int mid,
|
||||
const int NE,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const DenseTensor &j_,
|
||||
Vector &h_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
MFEM_VERIFY(mid == 1 || mid == 2 || mid == 7 || mid == 77,
|
||||
"Metric not yet implemented!");
|
||||
|
||||
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 W = Reshape(w_.Read(), Q1D, Q1D);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, NE);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, DIM, NE);
|
||||
auto H = Reshape(h_.Write(), DIM, DIM, DIM, DIM, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double s_BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double s_X[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double s_DQ[4][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double s_QQ[4][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X,s_X);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D, Q1D, b, g, s_BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1,NBZ>(D1D, Q1D, s_BG, s_X, s_DQ);
|
||||
kernels::GradY<MD1,MQ1,NBZ>(D1D, Q1D, s_BG, s_DQ, s_QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,e);
|
||||
const double detJtr = kernels::Det<2>(Jtr);
|
||||
const double weight = metric_normal * W(qx,qy) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[4];
|
||||
kernels::CalcInverse<2>(Jtr, Jrt);
|
||||
|
||||
// Jpr = X^t.DSh
|
||||
double Jpr[4];
|
||||
kernels::PullGrad<MQ1,NBZ>(qx,qy,s_QQ,Jpr);
|
||||
|
||||
// Jpt = Jpr.Jrt
|
||||
double Jpt[4];
|
||||
kernels::Mult(2,2,2, Jpr, Jrt, Jpt);
|
||||
|
||||
// metric->AssembleH
|
||||
if (mid == 1) { EvalH_001(e,qx,qy,weight,Jpt,H); }
|
||||
if (mid == 2) { EvalH_002(e,qx,qy,weight,Jpt,H); }
|
||||
if (mid == 7) { EvalH_007(e,qx,qy,weight,Jpt,H); }
|
||||
if (mid == 77) { EvalH_077(e,qx,qy,weight,Jpt,H); }
|
||||
} // qx
|
||||
} // qy
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleGradPA_2D(const Vector &X) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int M = metric->Id();
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double mn = metric_normal;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
Vector &H = PA.H;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(SetupGradPA_2D,id,X,mn,M,N,W,B,G,J,H);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,125 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, SetupGradPA_C0_2D,
|
||||
const double lim_normal,
|
||||
const Vector &lim_dist,
|
||||
const Vector &c0_,
|
||||
const int NE,
|
||||
const DenseTensor &j_,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &bld_,
|
||||
Vector &h0_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
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 bool const_c0 = c0_.Size() == 1;
|
||||
const auto C0 = const_c0 ?
|
||||
Reshape(c0_.Read(), 1, 1, 1) :
|
||||
Reshape(c0_.Read(), Q1D, Q1D, NE);
|
||||
const auto LD = Reshape(lim_dist.Read(), D1D, D1D, 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);
|
||||
const auto bld = Reshape(bld_.Read(), Q1D, D1D);
|
||||
|
||||
auto H0 = Reshape(h0_.Write(), DIM, DIM, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
MFEM_SHARED double BLD[MQ1*MD1];
|
||||
|
||||
MFEM_SHARED double XY[NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,LD,XY);
|
||||
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,bld,BLD);
|
||||
|
||||
kernels::EvalX<MD1,MQ1,NBZ>(D1D,Q1D,BLD,XY,DQ);
|
||||
kernels::EvalY<MD1,MQ1,NBZ>(D1D,Q1D,BLD,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,e);
|
||||
const double detJtr = kernels::Det<2>(Jtr);
|
||||
const double weight = W(qx,qy) * detJtr;
|
||||
const double coeff0 = const_c0 ? C0(0,0,0) : C0(qx,qy,e);
|
||||
const double weight_m = weight * lim_normal * coeff0;
|
||||
|
||||
double D;
|
||||
kernels::PullEval<MQ1,NBZ>(qx,qy,QQ,D);
|
||||
const double dist = D; // GetValues, default comp set to 0
|
||||
|
||||
// lim_func->Eval_d2(p1, p0, d_vals(q), grad_grad);
|
||||
// d2.Diag(1.0 / (dist * dist), x.Size());
|
||||
const double c = 1.0 / (dist * dist);
|
||||
double grad_grad[4];
|
||||
kernels::Diag<2>(c, grad_grad);
|
||||
ConstDeviceMatrix gg(grad_grad,DIM,DIM);
|
||||
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
H0(i,j,qx,qy,e) = weight_m * gg(i,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleGradPA_C0_2D(const Vector &X) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double ln = lim_normal;
|
||||
const Vector &LD = PA.LD;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &BLD = PA.maps_lim->B;
|
||||
const Vector &C0 = PA.C0;
|
||||
Vector &H0 = PA.H0;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(SetupGradPA_C0_2D,id,ln,LD,C0,N,J,W,B,BLD,H0);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,150 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AssembleDiagonalPA_Kernel_3D,
|
||||
const int NE,
|
||||
const Array<double> &b,
|
||||
const Array<double> &g,
|
||||
const DenseTensor &j,
|
||||
const Vector &h,
|
||||
Vector &diagonal,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
const auto G = Reshape(g.Read(), Q1D, D1D);
|
||||
const auto J = Reshape(j.Read(), DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
const auto H = Reshape(h.Read(), DIM, DIM, DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
auto D = Reshape(diagonal.ReadWrite(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
|
||||
MFEM_SHARED double qqd[MQ1*MQ1*MD1];
|
||||
MFEM_SHARED double qdd[MQ1*MD1*MD1];
|
||||
DeviceTensor<3,double> QQD(qqd, MQ1, MQ1, MD1);
|
||||
DeviceTensor<3,double> QDD(qdd, MQ1, MD1, MD1);
|
||||
|
||||
for (int v = 0; v < DIM; ++v)
|
||||
{
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
// first tensor contraction, along z direction
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
QQD(qx,qy,dz) = 0.0;
|
||||
MFEM_UNROLL(MQ1);
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,qz,e);
|
||||
double jrt[9];
|
||||
ConstDeviceMatrix Jrt(jrt,3,3);
|
||||
kernels::CalcInverse<3>(Jtr, jrt);
|
||||
const double Bz = B(qz,dz);
|
||||
const double Gz = G(qz,dz);
|
||||
const double L = i==2 ? Gz : Bz;
|
||||
const double R = j==2 ? Gz : Bz;
|
||||
const double Jij = Jrt(i,i) * Jrt(j,j);
|
||||
const double h = H(v,i,v,j,qx,qy,qz,e);
|
||||
QQD(qx,qy,dz) += L * Jij * h * R;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
// second tensor contraction, along y direction
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
QDD(qx,dy,dz) = 0.0;
|
||||
MFEM_UNROLL(MQ1);
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double By = B(qy,dy);
|
||||
const double Gy = G(qy,dy);
|
||||
const double L = i==1 ? Gy : By;
|
||||
const double R = j==1 ? Gy : By;
|
||||
QDD(qx,dy,dz) += L * QQD(qx,qy,dz) * R;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
// third tensor contraction, along x direction
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double d = 0.0;
|
||||
MFEM_UNROLL(MQ1);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double Bx = B(qx,dx);
|
||||
const double Gx = G(qx,dx);
|
||||
const double L = i==0 ? Gx : Bx;
|
||||
const double R = j==0 ? Gx : Bx;
|
||||
d += L * QDD(qx,dy,dz) * R;
|
||||
}
|
||||
D(dx,dy,dz,v,e) += d;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleDiagonalPA_3D(Vector &D) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
const Vector &H = PA.H;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AssembleDiagonalPA_Kernel_3D,id,N,B,G,J,H,D);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,123 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AssembleDiagonalPA_Kernel_C0_3D,
|
||||
const int NE,
|
||||
const Array<double> &b,
|
||||
const Vector &h0,
|
||||
Vector &diagonal,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
const auto H0 = Reshape(h0.Read(), DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
auto D = Reshape(diagonal.ReadWrite(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
|
||||
MFEM_SHARED double qqd[MQ1*MQ1*MD1];
|
||||
MFEM_SHARED double qdd[MQ1*MD1*MD1];
|
||||
DeviceTensor<3,double> QQD(qqd, MQ1, MQ1, MD1);
|
||||
DeviceTensor<3,double> QDD(qdd, MQ1, MD1, MD1);
|
||||
|
||||
for (int v = 0; v < DIM; ++v)
|
||||
{
|
||||
// first tensor contraction, along z direction
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
QQD(qx,qy,dz) = 0.0;
|
||||
MFEM_UNROLL(MQ1);
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const double Bz = B(qz,dz);
|
||||
QQD(qx,qy,dz) += Bz * H0(v,v,qx,qy,qz,e) * Bz;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
// second tensor contraction, along y direction
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
QDD(qx,dy,dz) = 0.0;
|
||||
MFEM_UNROLL(MQ1);
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double By = B(qy,dy);
|
||||
QDD(qx,dy,dz) += By * QQD(qx,qy,dz) * By;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
// third tensor contraction, along x direction
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
double d = 0.0;
|
||||
MFEM_UNROLL(MQ1);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double Bx = B(qx,dx);
|
||||
d += Bx * QDD(qx,dy,dz) * Bx;
|
||||
}
|
||||
D(dx,dy,dz, v, e) += d;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleDiagonalPA_C0_3D(Vector &D) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Vector &H0 = PA.H0;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AssembleDiagonalPA_Kernel_C0_3D,id,N,B,H0,D);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,132 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AddMultGradPA_Kernel_3D,
|
||||
const int NE,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const DenseTensor &j_,
|
||||
const Vector &h_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
const auto H = Reshape(h_.Read(), DIM, DIM, DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double DDD[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[9][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[9][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[9][MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,X,DDD);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1>(D1D,Q1D,BG,DDD,DDQ);
|
||||
kernels::GradY<MD1,MQ1>(D1D,Q1D,BG,DDQ,DQQ);
|
||||
kernels::GradZ<MD1,MQ1>(D1D,Q1D,BG,DQQ,QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,qz,e);
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[9];
|
||||
kernels::CalcInverse<3>(Jtr, Jrt);
|
||||
|
||||
// Jpr = X^T.DSh
|
||||
double Jpr[9];
|
||||
kernels::PullGrad<MQ1>(qx,qy,qz, QQQ, Jpr);
|
||||
|
||||
// Jpt = X^T.DS = (X^T.DSh).Jrt = Jpr.Jrt
|
||||
double Jpt[9];
|
||||
kernels::Mult(3,3,3, Jpr, Jrt, Jpt);
|
||||
|
||||
// B = Jpt : H
|
||||
double B[9];
|
||||
DeviceMatrix M(B,3,3);
|
||||
ConstDeviceMatrix J(Jpt,3,3);
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
M(i,j) = 0.0;
|
||||
for (int r = 0; r < DIM; r++)
|
||||
{
|
||||
for (int c = 0; c < DIM; c++)
|
||||
{
|
||||
M(i,j) += H(r,c,i,j,qx,qy,qz,e) * J(r,c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Y += DS . M^t += DSh . (Jrt . M^t)
|
||||
double A[9];
|
||||
kernels::MultABt(3,3,3, Jrt, B, A);
|
||||
kernels::PushGrad<MQ1>(qx,qy,qz, A, QQQ);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
kernels::LoadBGt<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
kernels::GradZt<MD1,MQ1>(D1D,Q1D,BG,QQQ,DQQ);
|
||||
kernels::GradYt<MD1,MQ1>(D1D,Q1D,BG,DQQ,DDQ);
|
||||
kernels::GradXt<MD1,MQ1>(D1D,Q1D,BG,DDQ,Y,e);
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AddMultGradPA_3D(const Vector &X, const Vector &R,
|
||||
Vector &C) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
const Vector &H = PA.H;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultGradPA_Kernel_3D,id,N,B,G,J,H,R,C);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,111 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AddMultGradPA_Kernel_C0_3D,
|
||||
const int NE,
|
||||
const Array<double> &b_,
|
||||
const Vector &h0_,
|
||||
const Vector &r_,
|
||||
Vector &c_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto H0 = Reshape(h0_.Read(), DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto R = Reshape(r_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
auto Y = Reshape(c_.ReadWrite(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
|
||||
MFEM_SHARED double DDD[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[3][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[3][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[3][MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,R,DDD);
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
|
||||
kernels::EvalX<MD1,MQ1>(D1D,Q1D,B,DDD,DDQ);
|
||||
kernels::EvalY<MD1,MQ1>(D1D,Q1D,B,DDQ,DQQ);
|
||||
kernels::EvalZ<MD1,MQ1>(D1D,Q1D,B,DQQ,QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
// Xh = X^T . Sh
|
||||
double Xh[3];
|
||||
kernels::PullEval<MQ1>(qx,qy,qz,QQQ,Xh);
|
||||
|
||||
double B[9];
|
||||
DeviceMatrix H(B,3,3);
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
H(i,j) = H0(i,j,qx,qy,qz,e);
|
||||
}
|
||||
}
|
||||
|
||||
// p2 = B . Xh
|
||||
double p2[3];
|
||||
kernels::Mult(3,3,B,Xh,p2);
|
||||
kernels::PushEval<MQ1>(qx,qy,qz,p2,QQQ);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
kernels::LoadBt<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
kernels::EvalXt<MD1,MQ1>(D1D,Q1D,B,QQQ,DQQ);
|
||||
kernels::EvalYt<MD1,MQ1>(D1D,Q1D,B,DQQ,DDQ);
|
||||
kernels::EvalZt<MD1,MQ1>(D1D,Q1D,B,DDQ,Y,e);
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AddMultGradPA_C0_3D(const Vector &X, const Vector &R,
|
||||
Vector &C) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Vector &H0 = PA.H0;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultGradPA_Kernel_C0_3D,id,N,B,H0,R,C);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,281 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
#include "../linalg/dinvariants.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
using Args = kernels::InvariantsEvaluator3D::Buffers;
|
||||
|
||||
// dP_302 = (dI2b*dI1b + dI1b*dI2b)/9 + (I1b/9)*ddI2b + (I2b/9)*ddI1b
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalH_302(const int e, const int qx, const int qy, const int qz,
|
||||
const double weight, const double *J, DeviceTensor<8,double> dP)
|
||||
{
|
||||
double B[9];
|
||||
double dI1b[9], ddI1b[9];
|
||||
double dI2[9], dI2b[9], ddI2[9], ddI2b[9];
|
||||
double dI3b[9];
|
||||
constexpr int DIM = 3;
|
||||
kernels::InvariantsEvaluator3D ie(Args()
|
||||
.J(J).B(B)
|
||||
.dI1b(dI1b).ddI1b(ddI1b)
|
||||
.dI2(dI2).dI2b(dI2b).ddI2(ddI2).ddI2b(ddI2b)
|
||||
.dI3b(dI3b));
|
||||
const double c1 = weight/9.;
|
||||
const double I1b = ie.Get_I1b();
|
||||
const double I2b = ie.Get_I2b();
|
||||
ConstDeviceMatrix di1b(ie.Get_dI1b(),DIM,DIM);
|
||||
ConstDeviceMatrix di2b(ie.Get_dI2b(),DIM,DIM);
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
ConstDeviceMatrix ddi1b(ie.Get_ddI1b(i,j),DIM,DIM);
|
||||
ConstDeviceMatrix ddi2b(ie.Get_ddI2b(i,j),DIM,DIM);
|
||||
for (int r = 0; r < DIM; r++)
|
||||
{
|
||||
for (int c = 0; c < DIM; c++)
|
||||
{
|
||||
const double dp =
|
||||
(di2b(r,c)*di1b(i,j) + di1b(r,c)*di2b(i,j))
|
||||
+ ddi2b(r,c)*I1b
|
||||
+ ddi1b(r,c)*I2b;
|
||||
dP(r,c,i,j,qx,qy,qz,e) = c1 * dp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dP_303 = ddI1b/3
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalH_303(const int e, const int qx, const int qy, const int qz,
|
||||
const double weight, const double *J, DeviceTensor<8,double> dP)
|
||||
{
|
||||
double B[9];
|
||||
double dI1b[9], ddI1[9], ddI1b[9];
|
||||
double dI2[9], dI2b[9], ddI2[9], ddI2b[9];
|
||||
double dI3b[9], ddI3b[9];
|
||||
constexpr int DIM = 3;
|
||||
kernels::InvariantsEvaluator3D ie(Args()
|
||||
.J(J).B(B)
|
||||
.dI1b(dI1b).ddI1(ddI1).ddI1b(ddI1b)
|
||||
.dI2(dI2).dI2b(dI2b).ddI2(ddI2).ddI2b(ddI2b)
|
||||
.dI3b(dI3b).ddI3b(ddI3b));
|
||||
const double c1 = weight/3.;
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
ConstDeviceMatrix ddi1b(ie.Get_ddI1b(i,j),DIM,DIM);
|
||||
for (int r = 0; r < DIM; r++)
|
||||
{
|
||||
for (int c = 0; c < DIM; c++)
|
||||
{
|
||||
const double dp = ddi1b(r,c);
|
||||
dP(r,c,i,j,qx,qy,qz,e) = c1 * dp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dP_315 = 2*(dI3b x dI3b) + 2*(I3b - 1)*ddI3b
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalH_315(const int e, const int qx, const int qy, const int qz,
|
||||
const double weight, const double *J, DeviceTensor<8,double> dP)
|
||||
{
|
||||
double dI3b[9], ddI3b[9];
|
||||
constexpr int DIM = 3;
|
||||
kernels::InvariantsEvaluator3D ie(Args().
|
||||
J(J).
|
||||
dI3b(dI3b).ddI3b(ddI3b));
|
||||
|
||||
double sign_detJ;
|
||||
const double I3b = ie.Get_I3b(sign_detJ);
|
||||
ConstDeviceMatrix di3b(ie.Get_dI3b(sign_detJ),DIM,DIM);
|
||||
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
ConstDeviceMatrix ddi3b(ie.Get_ddI3b(i,j),DIM,DIM);
|
||||
for (int r = 0; r < DIM; r++)
|
||||
{
|
||||
for (int c = 0; c < DIM; c++)
|
||||
{
|
||||
const double dp = 2.0 * weight * (I3b - 1.0) * ddi3b(r,c) +
|
||||
2.0 * weight * di3b(r,c) * di3b(i,j);
|
||||
dP(r,c,i,j,qx,qy,qz,e) = dp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dP_321 = ddI1 + (-2/I3b^3)*(dI2 x dI3b + dI3b x dI2)
|
||||
// + (1/I3)*ddI2
|
||||
// + (6*I2/I3b^4)*(dI3b x dI3b)
|
||||
// + (-2*I2/I3b^3)*ddI3b
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalH_321(const int e, const int qx, const int qy, const int qz,
|
||||
const double weight, const double *J, DeviceTensor<8,double> dP)
|
||||
{
|
||||
double B[9];
|
||||
double dI1b[9], ddI1[9], ddI1b[9];
|
||||
double dI2[9], dI2b[9], ddI2[9], ddI2b[9];
|
||||
double dI3b[9], ddI3b[9];
|
||||
constexpr int DIM = 3;
|
||||
kernels::InvariantsEvaluator3D ie(Args()
|
||||
.J(J).B(B)
|
||||
.dI1b(dI1b).ddI1(ddI1).ddI1b(ddI1b)
|
||||
.dI2(dI2).dI2b(dI2b).ddI2(ddI2).ddI2b(ddI2b)
|
||||
.dI3b(dI3b).ddI3b(ddI3b));
|
||||
double sign_detJ;
|
||||
const double I2 = ie.Get_I2();
|
||||
const double I3b = ie.Get_I3b(sign_detJ);
|
||||
|
||||
ConstDeviceMatrix di2(ie.Get_dI2(),DIM,DIM);
|
||||
ConstDeviceMatrix di3b(ie.Get_dI3b(sign_detJ),DIM,DIM);
|
||||
|
||||
const double c0 = 1.0/I3b;
|
||||
const double c1 = weight*c0*c0;
|
||||
const double c2 = -2*c0*c1;
|
||||
const double c3 = c2*I2;
|
||||
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
ConstDeviceMatrix ddi1(ie.Get_ddI1(i,j),DIM,DIM);
|
||||
ConstDeviceMatrix ddi2(ie.Get_ddI2(i,j),DIM,DIM);
|
||||
ConstDeviceMatrix ddi3b(ie.Get_ddI3b(i,j),DIM,DIM);
|
||||
for (int r = 0; r < DIM; r++)
|
||||
{
|
||||
for (int c = 0; c < DIM; c++)
|
||||
{
|
||||
const double dp =
|
||||
weight * ddi1(r,c)
|
||||
+ c1 * ddi2(r,c)
|
||||
+ c3 * ddi3b(r,c)
|
||||
+ c2 * ((di2(r,c)*di3b(i,j) + di3b(r,c)*di2(i,j)))
|
||||
-3*c0*c3 * di3b(r,c)*di3b(i,j);
|
||||
dP(r,c,i,j,qx,qy,qz,e) = dp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, SetupGradPA_3D,
|
||||
const double metric_normal,
|
||||
const int mid,
|
||||
const Vector &x_,
|
||||
const int NE,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const DenseTensor &j_,
|
||||
Vector &h_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
MFEM_VERIFY(mid == 302 || mid == 303 || mid == 315 || mid == 321 ,
|
||||
"3D metric not yet implemented!");
|
||||
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
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);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
auto H = Reshape(h_.Write(), DIM, DIM, DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double s_BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double s_DDD[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double s_DDQ[9][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double s_DQQ[9][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double s_QQQ[9][MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,X,s_DDD);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,s_BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1>(D1D,Q1D,s_BG,s_DDD,s_DDQ);
|
||||
kernels::GradY<MD1,MQ1>(D1D,Q1D,s_BG,s_DDQ,s_DQQ);
|
||||
kernels::GradZ<MD1,MQ1>(D1D,Q1D,s_BG,s_DQQ,s_QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,qz,e);
|
||||
const double detJtr = kernels::Det<3>(Jtr);
|
||||
const double weight = metric_normal * W(qx,qy,qz) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[9];
|
||||
kernels::CalcInverse<3>(Jtr, Jrt);
|
||||
|
||||
// Jpr = X^T.DSh
|
||||
double Jpr[9];
|
||||
kernels::PullGrad<MQ1>(qx,qy,qz, s_QQQ, Jpr);
|
||||
|
||||
// Jpt = X^T . DS = (X^T.DSh) . Jrt = Jpr . Jrt
|
||||
double Jpt[9];
|
||||
kernels::Mult(3,3,3, Jpr, Jrt, Jpt);
|
||||
|
||||
// metric->AssembleH
|
||||
if (mid == 302) { EvalH_302(e,qx,qy,qz,weight,Jpt,H); }
|
||||
if (mid == 303) { EvalH_303(e,qx,qy,qz,weight,Jpt,H); }
|
||||
if (mid == 315) { EvalH_315(e,qx,qy,qz,weight,Jpt,H); }
|
||||
if (mid == 321) { EvalH_321(e,qx,qy,qz,weight,Jpt,H); }
|
||||
} // qx
|
||||
} // qy
|
||||
} // qz
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleGradPA_3D(const Vector &X) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int M = metric->Id();
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double mn = metric_normal;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
Vector &H = PA.H;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(SetupGradPA_3D,id,mn,M,X,N,W,B,G,J,H);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,129 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, SetupGradPA_Kernel_C0_3D,
|
||||
const double lim_normal,
|
||||
const Vector &lim_dist,
|
||||
const Vector &c0_,
|
||||
const int NE,
|
||||
const DenseTensor &j_,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &bld_,
|
||||
Vector &h0_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const bool const_c0 = c0_.Size() == 1;
|
||||
const auto C0 = const_c0 ?
|
||||
Reshape(c0_.Read(), 1, 1, 1, 1) :
|
||||
Reshape(c0_.Read(), Q1D, Q1D, Q1D, NE);
|
||||
const auto LD = Reshape(lim_dist.Read(), D1D, D1D, D1D, 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);
|
||||
const auto bld = Reshape(bld_.Read(), Q1D, D1D);
|
||||
|
||||
auto H0 = Reshape(h0_.Write(), DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
MFEM_SHARED double BLD[MQ1*MD1];
|
||||
|
||||
MFEM_SHARED double DDD[MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,LD,DDD);
|
||||
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,bld,BLD);
|
||||
|
||||
kernels::EvalX<MD1,MQ1>(D1D,Q1D,BLD,DDD,DDQ);
|
||||
kernels::EvalY<MD1,MQ1>(D1D,Q1D,BLD,DDQ,DQQ);
|
||||
kernels::EvalZ<MD1,MQ1>(D1D,Q1D,BLD,DQQ,QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,qz,e);
|
||||
const double detJtr = kernels::Det<3>(Jtr);
|
||||
const double weight = W(qx,qy,qz) * detJtr;
|
||||
const double coeff0 = const_c0 ? C0(0,0,0,0) : C0(qx,qy,qz,e);
|
||||
const double weight_m = weight * lim_normal * coeff0;
|
||||
|
||||
double D;
|
||||
kernels::PullEval<MQ1>(qx,qy,qz,QQQ,D);
|
||||
const double dist = D; // GetValues, default comp set to 0
|
||||
|
||||
// lim_func->Eval_d2(p1, p0, d_vals(q), grad_grad);
|
||||
// d2.Diag(1.0 / (dist * dist), x.Size());
|
||||
const double c = 1.0 / (dist * dist);
|
||||
double grad_grad[9];
|
||||
kernels::Diag<3>(c, grad_grad);
|
||||
ConstDeviceMatrix gg(grad_grad,DIM,DIM);
|
||||
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
H0(i,j,qx,qy,qz,e) = weight_m * gg(i,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleGradPA_C0_3D(const Vector &X) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double ln = lim_normal;
|
||||
const Vector &LD = PA.LD;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &BLD = PA.maps_lim->B;
|
||||
const Vector &C0 = PA.C0;
|
||||
Vector &H0 = PA.H0;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(SetupGradPA_Kernel_C0_3D,id,ln,LD,C0,N,J,W,B,BLD,H0);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,178 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "tmop_tools.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(int, CheckDetJpr_Kernel_2D,
|
||||
const int NE,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const Vector &x_,
|
||||
Vector &DetJOk,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
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 b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, DIM, NE);
|
||||
|
||||
auto E = Reshape(DetJOk.Write(), Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double XY[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[4][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[4][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X,XY);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1,NBZ>(D1D,Q1D,BG,XY,DQ);
|
||||
kernels::GradY<MD1,MQ1,NBZ>(D1D,Q1D,BG,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double J[4];
|
||||
kernels::PullGrad<MQ1,NBZ>(qx,qy,QQ,J);
|
||||
const double detJ = kernels::Det<2>(J);
|
||||
E(qx,qy,e) = (detJ <= 0.0) ? 0.0 : 1.0;
|
||||
}
|
||||
}
|
||||
});
|
||||
const double N = DetJOk.Size();
|
||||
const double D = DetJOk * DetJOk;
|
||||
return D < N ? 0 : 1;
|
||||
}
|
||||
|
||||
int TMOPNewtonSolver::CheckDetJpr_2D(const FiniteElementSpace *fes,
|
||||
const Vector &X) const
|
||||
{
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
const Operator *R = fes->GetElementRestriction(ordering);
|
||||
Vector XE(R->Height(), Device::GetDeviceMemoryType());
|
||||
XE.UseDevice(true);
|
||||
R->Mult(X, XE);
|
||||
|
||||
const DofToQuad &maps = fes->GetFE(0)->GetDofToQuad(ir, DofToQuad::TENSOR);
|
||||
const int NE = fes->GetMesh()->GetNE();
|
||||
const int NQ = ir.GetNPoints();
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const Array<double> &B = maps.B;
|
||||
const Array<double> &G = maps.G;
|
||||
|
||||
Vector E(NE*NQ);
|
||||
E.UseDevice(true);
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(CheckDetJpr_Kernel_2D,id,NE,B,G,XE,E);
|
||||
}
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(double, MinDetJpr_Kernel_2D,
|
||||
const int NE,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const Vector &x_,
|
||||
Vector &DetJ,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
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 b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, DIM, NE);
|
||||
|
||||
auto D = Reshape(DetJ.Write(), Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double XY[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[4][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[4][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X,XY);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1,NBZ>(D1D,Q1D,BG,XY,DQ);
|
||||
kernels::GradY<MD1,MQ1,NBZ>(D1D,Q1D,BG,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double Jpr[4];
|
||||
kernels::PullGrad<MQ1,NBZ>(qx,qy,QQ,Jpr);
|
||||
D(qx,qy,e) = kernels::Det<2>(Jpr);
|
||||
}
|
||||
}
|
||||
});
|
||||
return DetJ.Min();
|
||||
}
|
||||
|
||||
double TMOPNewtonSolver::MinDetJpr_2D(const FiniteElementSpace *fes,
|
||||
const Vector &X) const
|
||||
{
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
const Operator *R = fes->GetElementRestriction(ordering);
|
||||
Vector XE(R->Height(), Device::GetDeviceMemoryType());
|
||||
XE.UseDevice(true);
|
||||
R->Mult(X, XE);
|
||||
|
||||
const DofToQuad &maps = fes->GetFE(0)->GetDofToQuad(ir, DofToQuad::TENSOR);
|
||||
const int NE = fes->GetMesh()->GetNE();
|
||||
const int NQ = ir.GetNPoints();
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const Array<double> &B = maps.B;
|
||||
const Array<double> &G = maps.G;
|
||||
|
||||
Vector E(NE*NQ);
|
||||
E.UseDevice(true);
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(MinDetJpr_Kernel_2D,id,NE,B,G,XE,E);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,181 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "tmop_tools.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(int, CheckDetJpr_Kernel_3D,
|
||||
const int NE,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const Vector &x_,
|
||||
Vector &DetJOk,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
auto E = Reshape(DetJOk.Write(), Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double DDD[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[6][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[9][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[9][MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,X,DDD);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1>(D1D,Q1D,BG,DDD,DDQ);
|
||||
kernels::GradY<MD1,MQ1>(D1D,Q1D,BG,DDQ,DQQ);
|
||||
kernels::GradZ<MD1,MQ1>(D1D,Q1D,BG,DQQ,QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double J[9];
|
||||
kernels::PullGrad<MQ1>(qx,qy,qz, QQQ, J);
|
||||
const double detJ = kernels::Det<3>(J);
|
||||
E(qx,qy,qz,e) = (detJ <= 0.0) ? 0.0 : 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const double N = DetJOk.Size();
|
||||
const double D = DetJOk * DetJOk;
|
||||
return D < N ? 0 : 1;
|
||||
}
|
||||
|
||||
int TMOPNewtonSolver::CheckDetJpr_3D(const FiniteElementSpace *fes,
|
||||
const Vector &X) const
|
||||
{
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
const Operator *R = fes->GetElementRestriction(ordering);
|
||||
Vector XE(R->Height(), Device::GetDeviceMemoryType());
|
||||
XE.UseDevice(true);
|
||||
R->Mult(X, XE);
|
||||
|
||||
const DofToQuad &maps = fes->GetFE(0)->GetDofToQuad(ir, DofToQuad::TENSOR);
|
||||
const int NE = fes->GetMesh()->GetNE();
|
||||
const int NQ = ir.GetNPoints();
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const Array<double> &B = maps.B;
|
||||
const Array<double> &G = maps.G;
|
||||
|
||||
Vector E(NE*NQ);
|
||||
E.UseDevice(true);
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(CheckDetJpr_Kernel_3D,id,NE,B,G,XE,E);
|
||||
}
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(double, MinDetJpr_Kernel_3D,
|
||||
const int NE,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const Vector &x_,
|
||||
Vector &DetJ,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
auto D = Reshape(DetJ.Write(), Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double DDD[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[6][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[9][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[9][MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,X,DDD);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1>(D1D,Q1D,BG,DDD,DDQ);
|
||||
kernels::GradY<MD1,MQ1>(D1D,Q1D,BG,DDQ,DQQ);
|
||||
kernels::GradZ<MD1,MQ1>(D1D,Q1D,BG,DQQ,QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double Jpr[9];
|
||||
kernels::PullGrad<MQ1>(qx,qy,qz, QQQ, Jpr);
|
||||
D(qx,qy,qz,e) = kernels::Det<3>(Jpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return DetJ.Min();
|
||||
}
|
||||
|
||||
double TMOPNewtonSolver::MinDetJpr_3D(const FiniteElementSpace *fes,
|
||||
const Vector &X) const
|
||||
{
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
const Operator *R = fes->GetElementRestriction(ordering);
|
||||
Vector XE(R->Height(), Device::GetDeviceMemoryType());
|
||||
XE.UseDevice(true);
|
||||
R->Mult(X, XE);
|
||||
|
||||
const DofToQuad &maps = fes->GetFE(0)->GetDofToQuad(ir, DofToQuad::TENSOR);
|
||||
const int NE = fes->GetMesh()->GetNE();
|
||||
const int NQ = ir.GetNPoints();
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const Array<double> &B = maps.B;
|
||||
const Array<double> &G = maps.G;
|
||||
|
||||
Vector E(NE*NQ);
|
||||
E.UseDevice(true);
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(MinDetJpr_Kernel_3D,id,NE,B,G,XE,E);
|
||||
}
|
||||
} // namespace mfem
|
||||
@@ -1,155 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(bool, TC_IDEAL_SHAPE_UNIT_SIZE_2D_KERNEL,
|
||||
const int NE,
|
||||
const DenseMatrix w_, // copy
|
||||
DenseTensor &j_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
constexpr int NBZ = 1;
|
||||
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto W = Reshape(w_.Read(), DIM,DIM);
|
||||
auto J = Reshape(j_.Write(), DIM,DIM, Q1D,Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
kernels::Set(DIM,DIM, 1.0, &W(0,0), &J(0,0,qx,qy,e));
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(bool, TC_IDEAL_SHAPE_GIVEN_SIZE_2D_KERNEL,
|
||||
const int NE,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const DenseMatrix w_ideal_, // copy
|
||||
const Vector &x_,
|
||||
DenseTensor &j_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
constexpr int NBZ = 1;
|
||||
|
||||
const double detW = w_ideal_.Det();
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
const auto Wideal = Reshape(w_ideal_.Read(), DIM,DIM);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, DIM, NE);
|
||||
auto J = Reshape(j_.Write(), DIM,DIM, Q1D,Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double XY[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[4][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[4][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X,XY);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1,NBZ>(D1D,Q1D,BG,XY,DQ);
|
||||
kernels::GradY<MD1,MQ1,NBZ>(D1D,Q1D,BG,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double Jtr[4];
|
||||
const double *Wid = &Wideal(0,0);
|
||||
kernels::PullGrad<MQ1,NBZ>(qx,qy,QQ,Jtr);
|
||||
const double detJ = kernels::Det<2>(Jtr);
|
||||
const double alpha = std::pow(detJ/detW,1./2);
|
||||
kernels::Set(DIM,DIM,alpha,Wid,&J(0,0,qx,qy,e));
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
template<> bool
|
||||
TargetConstructor::ComputeElementTargetsPA<2>(const FiniteElementSpace *fes,
|
||||
const IntegrationRule *ir,
|
||||
DenseTensor &Jtr,
|
||||
const Vector&) const
|
||||
{
|
||||
MFEM_ASSERT(target_type == IDEAL_SHAPE_UNIT_SIZE || nodes != nullptr, "");
|
||||
MFEM_VERIFY(fes->GetFE(0)->GetGeomType() == Geometry::SQUARE, "");
|
||||
const DenseMatrix &W = Geometries.GetGeomToPerfGeomJac(Geometry::SQUARE);
|
||||
const FiniteElement *fe = fes->GetFE(0);
|
||||
const int NE = fes->GetMesh()->GetNE();
|
||||
const DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, mode);
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
|
||||
const Array<double> &B = maps.B;
|
||||
const Array<double> &G = maps.G;
|
||||
|
||||
switch (target_type)
|
||||
{
|
||||
case IDEAL_SHAPE_UNIT_SIZE: // Jtr(i) = Wideal;
|
||||
{
|
||||
MFEM_LAUNCH_TMOP_KERNEL(TC_IDEAL_SHAPE_UNIT_SIZE_2D_KERNEL,
|
||||
id,NE,W,Jtr);
|
||||
}
|
||||
case IDEAL_SHAPE_EQUAL_SIZE: return false;
|
||||
case IDEAL_SHAPE_GIVEN_SIZE:
|
||||
{
|
||||
MFEM_VERIFY(nodes, "");
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
const Operator *R = fes->GetElementRestriction(ordering);
|
||||
Vector X(R->Height(), Device::GetDeviceMemoryType());
|
||||
X.UseDevice(true);
|
||||
R->Mult(*nodes, X);
|
||||
MFEM_ASSERT(nodes->FESpace()->GetVDim() == 2, "");
|
||||
MFEM_LAUNCH_TMOP_KERNEL(TC_IDEAL_SHAPE_GIVEN_SIZE_2D_KERNEL,
|
||||
id,NE,B,G,W,X,Jtr);
|
||||
}
|
||||
case GIVEN_SHAPE_AND_SIZE: return false;
|
||||
default: return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,162 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(bool, DatcSize,
|
||||
const int NE,
|
||||
const int ncomp,
|
||||
const int sizeidx,
|
||||
const DenseMatrix w_, // Copy
|
||||
const Array<double> &b_,
|
||||
const Vector &x_,
|
||||
DenseTensor &j_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
MFEM_VERIFY(ncomp==1,"");
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_VERIFY(D1D <= Q1D, "");
|
||||
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto W = Reshape(w_.Read(), DIM,DIM);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, D1D, ncomp, NE);
|
||||
auto J = Reshape(j_.Write(), DIM,DIM, Q1D,Q1D,Q1D, NE);
|
||||
|
||||
const double infinity = std::numeric_limits<double>::infinity();
|
||||
MFEM_VERIFY(sizeidx == 0,"");
|
||||
MFEM_VERIFY(MFEM_CUDA_BLOCKS==256,"");
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
MFEM_SHARED double DDD[MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,sizeidx,X,DDD);
|
||||
|
||||
double min;
|
||||
MFEM_SHARED double min_size[MFEM_CUDA_BLOCKS];
|
||||
DeviceTensor<3,double> M((double*)(min_size),D1D,D1D,D1D);
|
||||
const DeviceTensor<3,const double> D((double*)(DDD+sizeidx),D1D,D1D,D1D);
|
||||
MFEM_FOREACH_THREAD(t,x,MFEM_CUDA_BLOCKS) { min_size[t] = infinity; }
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
M(dx,dy,dz) = D(dx,dy,dz);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
for (int wrk = MFEM_CUDA_BLOCKS >> 1; wrk > 0; wrk >>= 1)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(t,x,MFEM_CUDA_BLOCKS)
|
||||
{ if (t < wrk) { min_size[t] = fmin(min_size[t], min_size[t+wrk]); } }
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
min = min_size[0];
|
||||
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
kernels::EvalX<MD1,MQ1>(D1D,Q1D,B,DDD,DDQ);
|
||||
kernels::EvalY<MD1,MQ1>(D1D,Q1D,B,DDQ,DQQ);
|
||||
kernels::EvalZ<MD1,MQ1>(D1D,Q1D,B,DQQ,QQQ);
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
double T;
|
||||
kernels::PullEval<MQ1>(qx,qy,qz,QQQ,T);
|
||||
const double shape_par_vals = T;
|
||||
const double size = fmax(shape_par_vals, min);
|
||||
const double alpha = std::pow(size, 1.0/DIM);
|
||||
for (int i = 0; i < DIM; i++)
|
||||
{
|
||||
for (int j = 0; j < DIM; j++)
|
||||
{
|
||||
J(i,j,qx,qy,qz,e) = alpha * W(i,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// PA.Jtr Size = (dim, dim, PA.ne*PA.nq);
|
||||
bool DiscreteAdaptTC::ComputeElementTargetsPA(const FiniteElementSpace *pa_fes,
|
||||
const IntegrationRule *ir,
|
||||
DenseTensor &Jtr,
|
||||
const Vector &xe) const
|
||||
{
|
||||
MFEM_VERIFY(target_type == IDEAL_SHAPE_GIVEN_SIZE ||
|
||||
target_type == GIVEN_SHAPE_AND_SIZE,"");
|
||||
|
||||
const FiniteElementSpace *fes = tspec_fesv;
|
||||
|
||||
if (!fes) { return false;}
|
||||
|
||||
const FiniteElement &fe = *fes->GetFE(0);
|
||||
const DenseMatrix &W = Geometries.GetGeomToPerfGeomJac(fe.GetGeomType());
|
||||
const int DIM = W.Height();
|
||||
const int NE = fes->GetMesh()->GetNE();
|
||||
const DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
const DofToQuad &maps = fe.GetDofToQuad(*ir, mode);
|
||||
const Array<double> &B = maps.B;
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
|
||||
const bool SizeKernel = sizeidx != -1;
|
||||
|
||||
// Until it is not implemented, return on host
|
||||
if (skewidx != -1) { return false; }
|
||||
if (aspectratioidx != -1) { return false; }
|
||||
if (orientationidx != -1) { return false; }
|
||||
|
||||
if (DIM == 3 && SizeKernel)
|
||||
{
|
||||
Vector tspec_e;
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
const Operator *R = fes->GetElementRestriction(ordering);
|
||||
MFEM_VERIFY(R,"");
|
||||
MFEM_VERIFY(R->Height() == NE*ncomp*D1D*D1D*D1D,"");
|
||||
tspec_e.SetSize(R->Height(), Device::GetDeviceMemoryType());
|
||||
tspec_e.UseDevice(true);
|
||||
tspec.UseDevice(true);
|
||||
R->Mult(tspec, tspec_e);
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
MFEM_LAUNCH_TMOP_KERNEL(DatcSize,id,NE,ncomp,sizeidx,W,B,tspec_e,Jtr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,159 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(bool, TC_IDEAL_SHAPE_UNIT_SIZE_3D_KERNEL,
|
||||
const int NE,
|
||||
const DenseMatrix w_, // copy
|
||||
DenseTensor &j_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto W = Reshape(w_.Read(), DIM,DIM);
|
||||
auto J = Reshape(j_.Write(), DIM,DIM, Q1D,Q1D,Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
kernels::Set(DIM,DIM, 1.0, &W(0,0), &J(0,0,qx,qy,qz,e));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(bool, TC_IDEAL_SHAPE_GIVEN_SIZE_3D_KERNEL,
|
||||
const int NE,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const DenseMatrix w_ideal_, // copy
|
||||
const Vector &x_,
|
||||
DenseTensor &j_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
|
||||
const double detW = w_ideal_.Det();
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
const auto Wideal = Reshape(w_ideal_.Read(), DIM,DIM);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
auto J = Reshape(j_.Write(), DIM,DIM, Q1D,Q1D,Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double DDD[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[6][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[9][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[9][MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,X,DDD);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1>(D1D,Q1D,BG,DDD,DDQ);
|
||||
kernels::GradY<MD1,MQ1>(D1D,Q1D,BG,DDQ,DQQ);
|
||||
kernels::GradZ<MD1,MQ1>(D1D,Q1D,BG,DQQ,QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double Jtr[9];
|
||||
const double *Wid = &Wideal(0,0);
|
||||
kernels::PullGrad<MQ1>(qx,qy,qz,QQQ,Jtr);
|
||||
const double detJ = kernels::Det<3>(Jtr);
|
||||
const double alpha = std::pow(detJ/detW,1./3);
|
||||
kernels::Set(DIM,DIM,alpha,Wid,&J(0,0,qx,qy,qz,e));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
template<> bool
|
||||
TargetConstructor::ComputeElementTargetsPA<3>(const FiniteElementSpace *fes,
|
||||
const IntegrationRule *ir,
|
||||
DenseTensor &Jtr,
|
||||
const Vector&) const
|
||||
{
|
||||
MFEM_ASSERT(target_type == IDEAL_SHAPE_UNIT_SIZE || nodes != nullptr, "");
|
||||
MFEM_VERIFY(fes->GetFE(0)->GetGeomType() == Geometry::CUBE, "");
|
||||
const DenseMatrix &W = Geometries.GetGeomToPerfGeomJac(Geometry::CUBE);
|
||||
const FiniteElement *fe = fes->GetFE(0);
|
||||
const int NE = fes->GetMesh()->GetNE();
|
||||
const DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, mode);
|
||||
const Array<double> &B = maps.B;
|
||||
const Array<double> &G = maps.G;
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
|
||||
switch (target_type)
|
||||
{
|
||||
case IDEAL_SHAPE_UNIT_SIZE: // Jtr(i) = Wideal;
|
||||
{
|
||||
MFEM_LAUNCH_TMOP_KERNEL(TC_IDEAL_SHAPE_UNIT_SIZE_3D_KERNEL,
|
||||
id,NE,W,Jtr);
|
||||
}
|
||||
case IDEAL_SHAPE_EQUAL_SIZE: return false;
|
||||
case IDEAL_SHAPE_GIVEN_SIZE:
|
||||
{
|
||||
MFEM_VERIFY(nodes, "");
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
const Operator *R = fes->GetElementRestriction(ordering);
|
||||
Vector X(R->Height(), Device::GetDeviceMemoryType());
|
||||
X.UseDevice(true);
|
||||
R->Mult(*nodes, X);
|
||||
MFEM_ASSERT(nodes->FESpace()->GetVDim() == 3, "");
|
||||
MFEM_LAUNCH_TMOP_KERNEL(TC_IDEAL_SHAPE_GIVEN_SIZE_3D_KERNEL,
|
||||
id,NE,B,G,W,X,Jtr);
|
||||
}
|
||||
case GIVEN_SHAPE_AND_SIZE: return false;
|
||||
default: return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,166 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
#include "../linalg/dinvariants.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
using Args = kernels::InvariantsEvaluator2D::Buffers;
|
||||
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalP_001(const double *Jpt, double *P)
|
||||
{
|
||||
double dI1[4];
|
||||
kernels::InvariantsEvaluator2D ie(Args().J(Jpt).dI1(dI1));
|
||||
kernels::Set(2,2, 1.0, ie.Get_dI1(), P);
|
||||
}
|
||||
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalP_002(const double *Jpt, double *P)
|
||||
{
|
||||
double dI1b[4], dI2b[4];
|
||||
kernels::InvariantsEvaluator2D ie(Args().J(Jpt).dI1b(dI1b).dI2b(dI2b));
|
||||
kernels::Set(2,2, 1./2., ie.Get_dI1b(), P);
|
||||
}
|
||||
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalP_007(const double *Jpt, double *P)
|
||||
{
|
||||
double dI1[4], dI2[4], dI2b[4];
|
||||
kernels::InvariantsEvaluator2D ie(Args().J(Jpt).dI1(dI1)
|
||||
.dI2(dI2).dI2b(dI2b));
|
||||
const double I2 = ie.Get_I2();
|
||||
kernels::Add(2,2, 1.0 + 1.0 / I2, ie.Get_dI1(),
|
||||
-ie.Get_I1() / (I2*I2), ie.Get_dI2(), P);
|
||||
}
|
||||
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalP_077(const double *Jpt, double *P)
|
||||
{
|
||||
double dI2[4], dI2b[4];
|
||||
kernels::InvariantsEvaluator2D ie(Args().
|
||||
J(Jpt).
|
||||
dI2(dI2).dI2b(dI2b));
|
||||
const double I2 = ie.Get_I2();
|
||||
kernels::Set(2,2, 0.5 * (1.0 - 1.0 / (I2 * I2)), ie.Get_dI2(), P);
|
||||
}
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AddMultPA_Kernel_2D,
|
||||
const double metric_normal,
|
||||
const int mid,
|
||||
const int NE,
|
||||
const DenseTensor &j_,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
MFEM_VERIFY(mid == 1 || mid == 2 || mid == 7 || mid == 77,
|
||||
"Metric not yet implemented!");
|
||||
|
||||
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 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);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
auto X = Reshape(x_.Read(), D1D, D1D, DIM, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double XY[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[4][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[4][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X,XY);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1,NBZ>(D1D,Q1D,BG,XY,DQ);
|
||||
kernels::GradY<MD1,MQ1,NBZ>(D1D,Q1D,BG,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,e);
|
||||
const double detJtr = kernels::Det<2>(Jtr);
|
||||
const double weight = metric_normal * W(qx,qy) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[4];
|
||||
kernels::CalcInverse<2>(Jtr, Jrt);
|
||||
|
||||
// Jpr = X{^T}.DSh
|
||||
double Jpr[4];
|
||||
kernels::PullGrad<MQ1,NBZ>(qx,qy,QQ,Jpr);
|
||||
|
||||
// Jpt = X{^T}.DS = (X{^T}.DSh).Jrt = Jpr.Jrt
|
||||
double Jpt[4];
|
||||
kernels::Mult(2,2,2, Jpr, Jrt, Jpt);
|
||||
|
||||
// metric->EvalP(Jpt, P);
|
||||
double P[4];
|
||||
if (mid == 1) { EvalP_001(Jpt, P); }
|
||||
if (mid == 2) { EvalP_002(Jpt, P); }
|
||||
if (mid == 7) { EvalP_007(Jpt, P); }
|
||||
if (mid == 77) { EvalP_077(Jpt, P); }
|
||||
for (int i = 0; i < 4; i++) { P[i] *= weight; }
|
||||
|
||||
// PMatO += DS . P^t += DSh . (Jrt . P^t)
|
||||
double A[4];
|
||||
kernels::MultABt(2,2,2, Jrt, P, A);
|
||||
kernels::PushGrad<MQ1,NBZ>(qx,qy,A,QQ);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
kernels::LoadBGt<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
kernels::GradYt<MD1,MQ1,NBZ>(D1D,Q1D,BG,QQ,DQ);
|
||||
kernels::GradXt<MD1,MQ1,NBZ>(D1D,Q1D,BG,DQ,Y,e);
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AddMultPA_2D(const Vector &X, Vector &Y) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int M = metric->Id();
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
const double mn = metric_normal;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultPA_Kernel_2D,id,mn,M,N,J,W,B,G,X,Y);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,148 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AddMultPA_Kernel_C0_2D,
|
||||
const double lim_normal,
|
||||
const Vector &lim_dist,
|
||||
const Vector &c0_,
|
||||
const int NE,
|
||||
const DenseTensor &j_,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &bld_,
|
||||
const Vector &x0_,
|
||||
const Vector &x1_,
|
||||
Vector &y_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
const bool const_c0 = c0_.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 C0 = const_c0 ?
|
||||
Reshape(c0_.Read(), 1, 1, 1) :
|
||||
Reshape(c0_.Read(), Q1D, Q1D, NE);
|
||||
const auto LD = Reshape(lim_dist.Read(), D1D, D1D, NE);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, NE);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto bld = Reshape(bld_.Read(), Q1D, D1D);
|
||||
const auto W = Reshape(w_.Read(), Q1D, Q1D);
|
||||
const auto X0 = Reshape(x0_.Read(), D1D, D1D, DIM, NE);
|
||||
const auto X1 = Reshape(x1_.Read(), D1D, D1D, DIM, NE);
|
||||
|
||||
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
MFEM_SHARED double BLD[MQ1*MD1];
|
||||
|
||||
MFEM_SHARED double XY[NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[NBZ][MQ1*MQ1];
|
||||
|
||||
MFEM_SHARED double XY0[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ0[2][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ0[2][NBZ][MQ1*MQ1];
|
||||
|
||||
MFEM_SHARED double XY1[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ1[2][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ1[2][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,LD,XY);
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X0,XY0);
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X1,XY1);
|
||||
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,bld,BLD);
|
||||
|
||||
kernels::EvalX<MD1,MQ1,NBZ>(D1D,Q1D,BLD,XY,DQ);
|
||||
kernels::EvalY<MD1,MQ1,NBZ>(D1D,Q1D,BLD,DQ,QQ);
|
||||
|
||||
kernels::EvalX<MD1,MQ1,NBZ>(D1D,Q1D,B,XY0,DQ0);
|
||||
kernels::EvalY<MD1,MQ1,NBZ>(D1D,Q1D,B,DQ0,QQ0);
|
||||
|
||||
kernels::EvalX<MD1,MQ1,NBZ>(D1D,Q1D,B,XY1,DQ1);
|
||||
kernels::EvalY<MD1,MQ1,NBZ>(D1D,Q1D,B,DQ1,QQ1);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,e);
|
||||
const double detJtr = kernels::Det<2>(Jtr);
|
||||
const double weight = W(qx,qy) * detJtr;
|
||||
|
||||
double ld, p0[2], p1[2];
|
||||
const double coeff0 = const_c0 ? C0(0,0,0) : C0(qx,qy,e);
|
||||
kernels::PullEval<MQ1,NBZ>(qx,qy,QQ,ld);
|
||||
kernels::PullEval<MQ1,NBZ>(qx,qy,QQ0,p0);
|
||||
kernels::PullEval<MQ1,NBZ>(qx,qy,QQ1,p1);
|
||||
|
||||
const double dist = ld; // GetValues, default comp set to 0
|
||||
|
||||
double d1[2];
|
||||
// Eval_d1
|
||||
// subtract(1.0 / (dist * dist), x, x0, d1);
|
||||
// z = a * (x - y)
|
||||
// grad = a * (x - x0)
|
||||
const double a = 1.0 / (dist * dist);
|
||||
const double w = weight * lim_normal * coeff0;
|
||||
kernels::Subtract<2>(w*a, p1, p0, d1);
|
||||
kernels::PushEval<MQ1,NBZ>(qx,qy,d1,QQ0);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
kernels::LoadBt<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
kernels::EvalXt<MD1,MQ1,NBZ>(D1D,Q1D,B,QQ0,DQ0);
|
||||
kernels::EvalYt<MD1,MQ1,NBZ>(D1D,Q1D,B,DQ0,Y,e);
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AddMultPA_C0_2D(const Vector &X, Vector &Y) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double ln = lim_normal;
|
||||
const Vector &LD = PA.LD;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &BLD = PA.maps_lim->B;
|
||||
const Vector &X0 = PA.X0;
|
||||
const Vector &C0 = PA.C0;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultPA_Kernel_C0_2D,id,ln,LD,C0,N,J,W,B,BLD,X0,X,Y);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,186 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
#include "../linalg/dinvariants.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
using Args = kernels::InvariantsEvaluator3D::Buffers;
|
||||
|
||||
// P_302 = (I1b/9)*dI2b + (I2b/9)*dI1b
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalP_302(const double *J, double *P)
|
||||
{
|
||||
double B[9];
|
||||
double dI1b[9], dI2[9], dI2b[9], dI3b[9];
|
||||
kernels::InvariantsEvaluator3D ie(Args()
|
||||
.J(J).B(B)
|
||||
.dI1b(dI1b)
|
||||
.dI2(dI2).dI2b(dI2b)
|
||||
.dI3b(dI3b));
|
||||
const double alpha = ie.Get_I1b()/9.;
|
||||
const double beta = ie.Get_I2b()/9.;
|
||||
kernels::Add(3,3, alpha, ie.Get_dI2b(), beta, ie.Get_dI1b(), P);
|
||||
}
|
||||
|
||||
// P_303 = dI1b/3
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalP_303(const double *J, double *P)
|
||||
{
|
||||
double B[9];
|
||||
double dI1b[9], dI3b[9];
|
||||
kernels::InvariantsEvaluator3D ie(Args().J(J).B(B).dI1b(dI1b).dI3b(dI3b));
|
||||
kernels::Set(3,3, 1./3., ie.Get_dI1b(), P);
|
||||
}
|
||||
|
||||
// P_315 = 2*(I3b - 1)*dI3b
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalP_315(const double *J, double *P)
|
||||
{
|
||||
double dI3b[9];
|
||||
kernels::InvariantsEvaluator3D ie(Args().J(J).dI3b(dI3b));
|
||||
|
||||
double sign_detJ;
|
||||
const double I3b = ie.Get_I3b(sign_detJ);
|
||||
kernels::Set(3,3, 2.0 * (I3b - 1.0), ie.Get_dI3b(sign_detJ), P);
|
||||
}
|
||||
|
||||
// P_321 = dI1 + (1/I3)*dI2 - (2*I2/I3b^3)*dI3b
|
||||
static MFEM_HOST_DEVICE inline
|
||||
void EvalP_321(const double *J, double *P)
|
||||
{
|
||||
double B[9];
|
||||
double dI1[9], dI2[9], dI3b[9];
|
||||
kernels::InvariantsEvaluator3D ie(Args().J(J).B(B)
|
||||
.dI1(dI1).dI2(dI2).dI3b(dI3b));
|
||||
double sign_detJ;
|
||||
const double I3 = ie.Get_I3();
|
||||
const double alpha = 1.0/I3;
|
||||
const double beta = -2.*ie.Get_I2()/(I3*ie.Get_I3b(sign_detJ));
|
||||
kernels::Add(3,3, alpha, ie.Get_dI2(), beta, ie.Get_dI3b(sign_detJ), P);
|
||||
kernels::Add(3,3, ie.Get_dI1(), P);
|
||||
}
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AddMultPA_Kernel_3D,
|
||||
const double metric_normal,
|
||||
const int mid,
|
||||
const int NE,
|
||||
const DenseTensor &j_,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
MFEM_VERIFY(mid == 302 || mid == 303 || mid == 315 || mid == 321 ,
|
||||
"3D metric not yet implemented!");
|
||||
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
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);
|
||||
const auto g = Reshape(g_.Read(), Q1D, D1D);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double s_BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double s_DDD[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double s_DDQ[9][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double s_DQQ[9][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double s_QQQ[9][MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,X,s_DDD);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,s_BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1>(D1D,Q1D,s_BG,s_DDD,s_DDQ);
|
||||
kernels::GradY<MD1,MQ1>(D1D,Q1D,s_BG,s_DDQ,s_DQQ);
|
||||
kernels::GradZ<MD1,MQ1>(D1D,Q1D,s_BG,s_DQQ,s_QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,qz,e);
|
||||
const double detJtr = kernels::Det<3>(Jtr);
|
||||
const double weight = metric_normal * W(qx,qy,qz) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[9];
|
||||
kernels::CalcInverse<3>(Jtr, Jrt);
|
||||
|
||||
// Jpr = X^T.DSh
|
||||
double Jpr[9];
|
||||
kernels::PullGrad<MQ1>(qx,qy,qz, s_QQQ, Jpr);
|
||||
|
||||
// Jpt = X^T.DS = (X^T.DSh).Jrt = Jpr.Jrt
|
||||
double Jpt[9];
|
||||
kernels::Mult(3,3,3, Jpr, Jrt, Jpt);
|
||||
|
||||
// metric->EvalP(Jpt, P);
|
||||
double P[9];
|
||||
if (mid == 302) { EvalP_302(Jpt,P); }
|
||||
if (mid == 303) { EvalP_303(Jpt,P); }
|
||||
if (mid == 315) { EvalP_315(Jpt,P); }
|
||||
if (mid == 321) { EvalP_321(Jpt,P); }
|
||||
for (int i = 0; i < 9; i++) { P[i] *= weight; }
|
||||
|
||||
// Y += DS . P^t += DSh . (Jrt . P^t)
|
||||
double A[9];
|
||||
kernels::MultABt(3,3,3, Jrt, P, A);
|
||||
kernels::PushGrad<MQ1>(qx,qy,qz, A, s_QQQ);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
kernels::LoadBGt<MD1,MQ1>(D1D, Q1D, b, g, s_BG);
|
||||
kernels::GradZt<MD1,MQ1>(D1D,Q1D,s_BG,s_QQQ,s_DQQ);
|
||||
kernels::GradYt<MD1,MQ1>(D1D,Q1D,s_BG,s_DQQ,s_DDQ);
|
||||
kernels::GradXt<MD1,MQ1>(D1D,Q1D,s_BG,s_DDQ,Y,e);
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AddMultPA_3D(const Vector &X, Vector &Y) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int M = metric->Id();
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
const double mn = metric_normal;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultPA_Kernel_3D,id,mn,M,N,J,W,B,G,X,Y);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,154 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(void, AddMultPA_Kernel_C0_3D,
|
||||
const double lim_normal,
|
||||
const Vector &lim_dist,
|
||||
const Vector &c0_,
|
||||
const int NE,
|
||||
const DenseTensor &j_,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &bld_,
|
||||
const Vector &x0_,
|
||||
const Vector &x1_,
|
||||
Vector &y_,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
const bool const_c0 = c0_.Size() == 1;
|
||||
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto C0 = const_c0 ?
|
||||
Reshape(c0_.Read(), 1, 1, 1, 1) :
|
||||
Reshape(c0_.Read(), Q1D, Q1D, Q1D, NE);
|
||||
const auto LD = Reshape(lim_dist.Read(), D1D, D1D, D1D, NE);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto bld = Reshape(bld_.Read(), Q1D, D1D);
|
||||
const auto W = Reshape(w_.Read(), Q1D, Q1D, Q1D);
|
||||
const auto X0 = Reshape(x0_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
const auto X1 = Reshape(x1_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
MFEM_SHARED double BLD[MQ1*MD1];
|
||||
|
||||
MFEM_SHARED double DDD[MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[MQ1*MQ1*MQ1];
|
||||
|
||||
MFEM_SHARED double DDD0[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ0[3][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ0[3][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ0[3][MQ1*MQ1*MQ1];
|
||||
|
||||
MFEM_SHARED double DDD1[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ1[3][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ1[3][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ1[3][MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,LD,DDD);
|
||||
kernels::LoadX<MD1>(e,D1D,X0,DDD0);
|
||||
kernels::LoadX<MD1>(e,D1D,X1,DDD1);
|
||||
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,bld,BLD);
|
||||
|
||||
kernels::EvalX<MD1,MQ1>(D1D,Q1D,BLD,DDD,DDQ);
|
||||
kernels::EvalY<MD1,MQ1>(D1D,Q1D,BLD,DDQ,DQQ);
|
||||
kernels::EvalZ<MD1,MQ1>(D1D,Q1D,BLD,DQQ,QQQ);
|
||||
|
||||
kernels::EvalX<MD1,MQ1>(D1D,Q1D,B,DDD0,DDQ0);
|
||||
kernels::EvalY<MD1,MQ1>(D1D,Q1D,B,DDQ0,DQQ0);
|
||||
kernels::EvalZ<MD1,MQ1>(D1D,Q1D,B,DQQ0,QQQ0);
|
||||
|
||||
kernels::EvalX<MD1,MQ1>(D1D,Q1D,B,DDD1,DDQ1);
|
||||
kernels::EvalY<MD1,MQ1>(D1D,Q1D,B,DDQ1,DQQ1);
|
||||
kernels::EvalZ<MD1,MQ1>(D1D,Q1D,B,DQQ1,QQQ1);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,qz,e);
|
||||
const double detJtr = kernels::Det<3>(Jtr);
|
||||
const double weight = W(qx,qy,qz) * detJtr;
|
||||
|
||||
double D, p0[3], p1[3];
|
||||
const double coeff0 = const_c0 ? C0(0,0,0,0) : C0(qx,qy,qz,e);
|
||||
kernels::PullEval<MQ1>(qx,qy,qz,QQQ,D);
|
||||
kernels::PullEval<MQ1>(qx,qy,qz,QQQ0,p0);
|
||||
kernels::PullEval<MQ1>(qx,qy,qz,QQQ1,p1);
|
||||
|
||||
double d1[3];
|
||||
// Eval_d1
|
||||
// subtract(1.0 / (dist * dist), x, x0, d1);
|
||||
// z = a * (x - y)
|
||||
// grad = a * (x - x0)
|
||||
const double dist = D; // GetValues, default comp set to 0
|
||||
const double a = 1.0 / (dist * dist);
|
||||
const double w = weight * lim_normal * coeff0;
|
||||
kernels::Subtract<3>(w*a, p1, p0, d1);
|
||||
kernels::PushEval<MQ1>(qx,qy,qz,d1,QQQ0);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
kernels::LoadBt<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
kernels::EvalXt<MD1,MQ1>(D1D,Q1D,B,QQQ0,DQQ0);
|
||||
kernels::EvalYt<MD1,MQ1>(D1D,Q1D,B,DQQ0,DDQ0);
|
||||
kernels::EvalZt<MD1,MQ1>(D1D,Q1D,B,DDQ0,Y,e);
|
||||
});
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AddMultPA_C0_3D(const Vector &X, Vector &Y) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double ln = lim_normal;
|
||||
const Vector &LD = PA.LD;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &BLD = PA.maps_lim->B;
|
||||
const Vector &X0 = PA.X0;
|
||||
const Vector &C0 = PA.C0;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(AddMultPA_Kernel_C0_3D,id,ln,LD,C0,N,J,W,B,BLD,X0,X,Y);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,155 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
#include "../linalg/dinvariants.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
using Args = kernels::InvariantsEvaluator2D::Buffers;
|
||||
|
||||
static MFEM_HOST_DEVICE inline
|
||||
double EvalW_001(const double *Jpt)
|
||||
{
|
||||
kernels::InvariantsEvaluator2D ie(Args().J(Jpt));
|
||||
return ie.Get_I1();
|
||||
}
|
||||
|
||||
static MFEM_HOST_DEVICE inline
|
||||
double EvalW_002(const double *Jpt)
|
||||
{
|
||||
kernels::InvariantsEvaluator2D ie(Args().J(Jpt));
|
||||
return 0.5 * ie.Get_I1b() - 1.0;
|
||||
}
|
||||
|
||||
static MFEM_HOST_DEVICE inline
|
||||
double EvalW_007(const double *Jpt)
|
||||
{
|
||||
kernels::InvariantsEvaluator2D ie(Args().J(Jpt));
|
||||
return ie.Get_I1() * (1.0 + 1.0/ie.Get_I2()) - 4.0;
|
||||
}
|
||||
|
||||
static MFEM_HOST_DEVICE inline
|
||||
double EvalW_077(const double *Jpt)
|
||||
{
|
||||
kernels::InvariantsEvaluator2D ie(Args().J(Jpt));
|
||||
const double I2 = ie.Get_I2b(); // Get_I2b or Get_I2 ?
|
||||
return 0.5*(I2*I2 + 1./(I2*I2) - 2.);
|
||||
}
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(double, EnergyPA_2D,
|
||||
const double metric_normal,
|
||||
const int mid,
|
||||
const int NE,
|
||||
const DenseTensor &j_,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const Vector &x_,
|
||||
const Vector &ones,
|
||||
Vector &energy,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
MFEM_VERIFY(mid == 1 || mid == 2 || mid == 7 || mid == 77,
|
||||
"2D metric not yet implemented!");
|
||||
|
||||
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 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);
|
||||
const auto W = Reshape(w_.Read(), Q1D, Q1D);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, DIM, NE);
|
||||
|
||||
auto E = Reshape(energy.Write(), Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double XY[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[4][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[4][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X,XY);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1,NBZ>(D1D,Q1D,BG,XY,DQ);
|
||||
kernels::GradY<MD1,MQ1,NBZ>(D1D,Q1D,BG,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,e);
|
||||
const double detJtr = kernels::Det<2>(Jtr);
|
||||
const double weight = metric_normal * W(qx,qy) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[4];
|
||||
kernels::CalcInverse<2>(Jtr, Jrt);
|
||||
|
||||
// Jpr = X^t.DSh
|
||||
double Jpr[4];
|
||||
kernels::PullGrad<MQ1,NBZ>(qx,qy,QQ,Jpr);
|
||||
|
||||
// Jpt = X^T.DS = (X^T.DSh).Jrt = Jpr.Jrt
|
||||
double Jpt[4];
|
||||
kernels::Mult(2,2,2,Jpr,Jrt,Jpt);
|
||||
|
||||
// metric->EvalW(Jpt);
|
||||
const double EvalW =
|
||||
mid == 1 ? EvalW_001(Jpt) :
|
||||
mid == 2 ? EvalW_002(Jpt) :
|
||||
mid == 7 ? EvalW_007(Jpt) :
|
||||
mid == 77 ? EvalW_077(Jpt) : 0.0;
|
||||
|
||||
E(qx,qy,e) = weight * EvalW;
|
||||
}
|
||||
}
|
||||
});
|
||||
return energy * ones;
|
||||
}
|
||||
|
||||
double TMOP_Integrator::GetGridFunctionEnergyPA_2D(const Vector &X) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int M = metric->Id();
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double m = metric_normal;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
const Vector &O = PA.O;
|
||||
Vector &E = PA.E;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(EnergyPA_2D,id,m,M,N,J,W,B,G,X,O,E);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,139 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(double, EnergyPA_C0_2D,
|
||||
const double lim_normal,
|
||||
const Vector &lim_dist,
|
||||
const Vector &c0_,
|
||||
const int NE,
|
||||
const DenseTensor &j_,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &bld_,
|
||||
const Vector &x0_,
|
||||
const Vector &x1_,
|
||||
const Vector &ones,
|
||||
Vector &energy,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
const bool const_c0 = c0_.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 C0 = const_c0 ?
|
||||
Reshape(c0_.Read(), 1, 1, 1) :
|
||||
Reshape(c0_.Read(), Q1D, Q1D, NE);
|
||||
const auto LD = Reshape(lim_dist.Read(), D1D, D1D, NE);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, NE);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto bld = Reshape(bld_.Read(), Q1D, D1D);
|
||||
const auto W = Reshape(w_.Read(), Q1D, Q1D);
|
||||
const auto X0 = Reshape(x0_.Read(), D1D, D1D, DIM, NE);
|
||||
const auto X1 = Reshape(x1_.Read(), D1D, D1D, DIM, NE);
|
||||
|
||||
auto E = Reshape(energy.Write(), Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
MFEM_SHARED double BLD[MQ1*MD1];
|
||||
|
||||
MFEM_SHARED double XY[NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[NBZ][MQ1*MQ1];
|
||||
|
||||
MFEM_SHARED double XY0[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ0[2][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ0[2][NBZ][MQ1*MQ1];
|
||||
|
||||
MFEM_SHARED double XY1[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ1[2][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ1[2][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,LD,XY);
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X0,XY0);
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X1,XY1);
|
||||
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,bld,BLD);
|
||||
|
||||
kernels::EvalX<MD1,MQ1,NBZ>(D1D,Q1D,BLD,XY,DQ);
|
||||
kernels::EvalY<MD1,MQ1,NBZ>(D1D,Q1D,BLD,DQ,QQ);
|
||||
|
||||
kernels::EvalX<MD1,MQ1,NBZ>(D1D,Q1D,B,XY0,DQ0);
|
||||
kernels::EvalY<MD1,MQ1,NBZ>(D1D,Q1D,B,DQ0,QQ0);
|
||||
|
||||
kernels::EvalX<MD1,MQ1,NBZ>(D1D,Q1D,B,XY1,DQ1);
|
||||
kernels::EvalY<MD1,MQ1,NBZ>(D1D,Q1D,B,DQ1,QQ1);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double ld, p0[2], p1[2];
|
||||
const double *Jtr = &J(0,0,qx,qy,e);
|
||||
const double detJtr = kernels::Det<2>(Jtr);
|
||||
const double weight = W(qx,qy) * detJtr;
|
||||
const double coeff0 = const_c0 ? C0(0,0,0) : C0(qx,qy,e);
|
||||
kernels::PullEval<MQ1,NBZ>(qx,qy,QQ,ld);
|
||||
kernels::PullEval<MQ1,NBZ>(qx,qy,QQ0,p0);
|
||||
kernels::PullEval<MQ1,NBZ>(qx,qy,QQ1,p1);
|
||||
const double dist = ld; // GetValues, default comp set to 0
|
||||
const double id2 = 0.5 / (dist*dist);
|
||||
const double dsq = kernels::DistanceSquared<2>(p1,p0) * id2;
|
||||
E(qx,qy,e) = weight * lim_normal * dsq * coeff0;
|
||||
}
|
||||
}
|
||||
});
|
||||
return energy * ones;
|
||||
}
|
||||
|
||||
double TMOP_Integrator::GetGridFunctionEnergyPA_C0_2D(const Vector &X) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double ln = lim_normal;
|
||||
const Vector &LD = PA.LD;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &BLD = PA.maps_lim->B;
|
||||
const Vector &X0 = PA.X0;
|
||||
const Vector &C0 = PA.C0;
|
||||
const Vector &O = PA.O;
|
||||
Vector &E = PA.E;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(EnergyPA_C0_2D,id,ln,LD,C0,N,J,W,B,BLD,X0,X,O,E);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,165 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
#include "../linalg/dinvariants.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
using Args = kernels::InvariantsEvaluator3D::Buffers;
|
||||
|
||||
// mu_302 = I1b * I2b / 9 - 1
|
||||
static MFEM_HOST_DEVICE inline
|
||||
double EvalW_302(const double *J)
|
||||
{
|
||||
double B[9];
|
||||
kernels::InvariantsEvaluator3D ie(Args().J(J).B(B));
|
||||
return ie.Get_I1b()*ie.Get_I2b()/9. - 1.;
|
||||
}
|
||||
|
||||
// mu_303 = I1b/3 - 1
|
||||
static MFEM_HOST_DEVICE inline
|
||||
double EvalW_303(const double *J)
|
||||
{
|
||||
double B[9];
|
||||
kernels::InvariantsEvaluator3D ie(Args().J(J).B(B));
|
||||
return ie.Get_I1b()/3. - 1.;
|
||||
}
|
||||
|
||||
// mu_315 = (I3b - 1)^2
|
||||
static MFEM_HOST_DEVICE inline
|
||||
double EvalW_315(const double *J)
|
||||
{
|
||||
double B[9];
|
||||
kernels::InvariantsEvaluator3D ie(Args().J(J).B(B));
|
||||
const double a = ie.Get_I3b() - 1.0;
|
||||
return a*a;
|
||||
}
|
||||
|
||||
// mu_321 = I1 + I2/I3 - 6
|
||||
static MFEM_HOST_DEVICE inline
|
||||
double EvalW_321(const double *J)
|
||||
{
|
||||
double B[9];
|
||||
kernels::InvariantsEvaluator3D ie(Args().J(J).B(B));
|
||||
return ie.Get_I1() + ie.Get_I2()/ie.Get_I3() - 6.0;
|
||||
}
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(double, EnergyPA_3D,
|
||||
const double metric_normal,
|
||||
const int mid,
|
||||
const int NE,
|
||||
const DenseTensor &j_,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &g_,
|
||||
const Vector &ones,
|
||||
const Vector &x_,
|
||||
Vector &energy,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
MFEM_VERIFY(mid == 302 || mid == 303 || mid == 315 || mid == 321 ,
|
||||
"3D metric not yet implemented!");
|
||||
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
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);
|
||||
const auto W = Reshape(w_.Read(), Q1D, Q1D, Q1D);
|
||||
const auto X = Reshape(x_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
auto E = Reshape(energy.Write(), Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double DDD[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[6][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[9][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[9][MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,X,DDD);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1>(D1D,Q1D,BG,DDD,DDQ);
|
||||
kernels::GradY<MD1,MQ1>(D1D,Q1D,BG,DDQ,DQQ);
|
||||
kernels::GradZ<MD1,MQ1>(D1D,Q1D,BG,DQQ,QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double *Jtr = &J(0,0,qx,qy,qz,e);
|
||||
const double detJtr = kernels::Det<3>(Jtr);
|
||||
const double weight = metric_normal * W(qx,qy,qz) * detJtr;
|
||||
|
||||
// Jrt = Jtr^{-1}
|
||||
double Jrt[9];
|
||||
kernels::CalcInverse<3>(Jtr, Jrt);
|
||||
|
||||
// Jpr = X^t.DSh
|
||||
double Jpr[9];
|
||||
kernels::PullGrad<MQ1>(qx,qy,qz, QQQ, Jpr);
|
||||
|
||||
// Jpt = X^t.DS = (X^t.DSh).Jrt = Jpr.Jrt
|
||||
double Jpt[9];
|
||||
kernels::Mult(3,3,3, Jpr, Jrt, Jpt);
|
||||
|
||||
// metric->EvalW(Jpt);
|
||||
const double EvalW =
|
||||
mid == 302 ? EvalW_302(Jpt) :
|
||||
mid == 303 ? EvalW_303(Jpt) :
|
||||
mid == 315 ? EvalW_315(Jpt) :
|
||||
mid == 321 ? EvalW_321(Jpt) : 0.0;
|
||||
|
||||
E(qx,qy,qz,e) = weight * EvalW;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return energy * ones;
|
||||
}
|
||||
|
||||
double TMOP_Integrator::GetGridFunctionEnergyPA_3D(const Vector &X) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int M = metric->Id();
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double mn = metric_normal;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &G = PA.maps->G;
|
||||
const Vector &O = PA.O;
|
||||
Vector &E = PA.E;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(EnergyPA_3D,id,mn,M,N,J,W,B,G,O,X,E);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,148 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MFEM_REGISTER_TMOP_KERNELS(double, EnergyPA_C0_3D,
|
||||
const double lim_normal,
|
||||
const Vector &lim_dist,
|
||||
const Vector &c0_,
|
||||
const int NE,
|
||||
const DenseTensor &j_,
|
||||
const Array<double> &w_,
|
||||
const Array<double> &b_,
|
||||
const Array<double> &bld_,
|
||||
const Vector &x0_,
|
||||
const Vector &x1_,
|
||||
const Vector &ones,
|
||||
Vector &energy,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
const bool const_c0 = c0_.Size() == 1;
|
||||
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto C0 = const_c0 ?
|
||||
Reshape(c0_.Read(), 1, 1, 1, 1) :
|
||||
Reshape(c0_.Read(), Q1D, Q1D, Q1D, NE);
|
||||
const auto LD = Reshape(lim_dist.Read(), D1D, D1D, D1D, NE);
|
||||
const auto J = Reshape(j_.Read(), DIM, DIM, Q1D, Q1D, Q1D, NE);
|
||||
const auto b = Reshape(b_.Read(), Q1D, D1D);
|
||||
const auto bld = Reshape(bld_.Read(), Q1D, D1D);
|
||||
const auto W = Reshape(w_.Read(), Q1D, Q1D, Q1D);
|
||||
const auto X0 = Reshape(x0_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
const auto X1 = Reshape(x1_.Read(), D1D, D1D, D1D, DIM, NE);
|
||||
|
||||
auto E = Reshape(energy.Write(), Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
MFEM_SHARED double BLD[MQ1*MD1];
|
||||
|
||||
MFEM_SHARED double DDD[MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[MQ1*MQ1*MQ1];
|
||||
|
||||
MFEM_SHARED double DDD0[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ0[3][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ0[3][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ0[3][MQ1*MQ1*MQ1];
|
||||
|
||||
MFEM_SHARED double DDD1[3][MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ1[3][MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ1[3][MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ1[3][MQ1*MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,LD,DDD);
|
||||
kernels::LoadX<MD1>(e,D1D,X0,DDD0);
|
||||
kernels::LoadX<MD1>(e,D1D,X1,DDD1);
|
||||
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
kernels::LoadB<MD1,MQ1>(D1D,Q1D,bld,BLD);
|
||||
|
||||
kernels::EvalX<MD1,MQ1>(D1D,Q1D,BLD,DDD,DDQ);
|
||||
kernels::EvalY<MD1,MQ1>(D1D,Q1D,BLD,DDQ,DQQ);
|
||||
kernels::EvalZ<MD1,MQ1>(D1D,Q1D,BLD,DQQ,QQQ);
|
||||
|
||||
kernels::EvalX<MD1,MQ1>(D1D,Q1D,B,DDD0,DDQ0);
|
||||
kernels::EvalY<MD1,MQ1>(D1D,Q1D,B,DDQ0,DQQ0);
|
||||
kernels::EvalZ<MD1,MQ1>(D1D,Q1D,B,DQQ0,QQQ0);
|
||||
|
||||
kernels::EvalX<MD1,MQ1>(D1D,Q1D,B,DDD1,DDQ1);
|
||||
kernels::EvalY<MD1,MQ1>(D1D,Q1D,B,DDQ1,DQQ1);
|
||||
kernels::EvalZ<MD1,MQ1>(D1D,Q1D,B,DQQ1,QQQ1);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double D, p0[3], p1[3];
|
||||
const double *Jtr = &J(0,0,qx,qy,qz,e);
|
||||
const double detJtr = kernels::Det<3>(Jtr);
|
||||
const double weight = W(qx,qy,qz) * detJtr;
|
||||
const double coeff0 = const_c0 ? C0(0,0,0,0) : C0(qx,qy,qz,e);
|
||||
|
||||
kernels::PullEval<MQ1>(qx,qy,qz,QQQ,D);
|
||||
kernels::PullEval<MQ1>(qx,qy,qz,QQQ0,p0);
|
||||
kernels::PullEval<MQ1>(qx,qy,qz,QQQ1,p1);
|
||||
|
||||
const double dist = D; // GetValues, default comp set to 0
|
||||
const double id2 = 0.5 / (dist*dist);
|
||||
|
||||
const double dsq = kernels::DistanceSquared<3>(p1,p0) * id2;
|
||||
E(qx,qy,qz,e) = weight * lim_normal * dsq * coeff0;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return energy * ones;
|
||||
}
|
||||
|
||||
double TMOP_Integrator::GetGridFunctionEnergyPA_C0_3D(const Vector &X) const
|
||||
{
|
||||
const int N = PA.ne;
|
||||
const int D1D = PA.maps->ndof;
|
||||
const int Q1D = PA.maps->nqpt;
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
const double ln = lim_normal;
|
||||
const Vector &LD = PA.LD;
|
||||
const DenseTensor &J = PA.Jtr;
|
||||
const Array<double> &W = PA.ir->GetWeights();
|
||||
const Array<double> &B = PA.maps->B;
|
||||
const Array<double> &BLD = PA.maps_lim->B;
|
||||
const Vector &X0 = PA.X0;
|
||||
const Vector &C0 = PA.C0;
|
||||
const Vector &O = PA.O;
|
||||
Vector &E = PA.E;
|
||||
|
||||
MFEM_LAUNCH_TMOP_KERNEL(EnergyPA_C0_3D,id,ln,LD,C0,N,J,W,B,BLD,X0,X,O,E);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
+35
-95
@@ -33,11 +33,10 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes,
|
||||
const int pnt_cnt = new_field.Size()/ncomp;
|
||||
|
||||
new_field = field0;
|
||||
new_field.HostReadWrite();
|
||||
Vector new_field_temp;
|
||||
|
||||
for (int i = 0; i < ncomp; i++)
|
||||
{
|
||||
new_field_temp.MakeRef(new_field, i*pnt_cnt, pnt_cnt);
|
||||
Vector new_field_temp(new_field.GetData()+i*pnt_cnt, pnt_cnt);
|
||||
ComputeAtNewPositionScalar(new_nodes, new_field_temp);
|
||||
}
|
||||
|
||||
@@ -73,13 +72,13 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
|
||||
if (fes)
|
||||
{
|
||||
fess = new FiniteElementSpace(fes->GetMesh(), fes->FEColl(), 1);
|
||||
oper = new SerialAdvectorCGOper(nodes0, u, *fess, al);
|
||||
oper = new SerialAdvectorCGOper(nodes0, u, *fess);
|
||||
}
|
||||
#ifdef MFEM_USE_MPI
|
||||
else if (pfes)
|
||||
{
|
||||
pfess = new ParFiniteElementSpace(pfes->GetParMesh(), pfes->FEColl(), 1);
|
||||
oper = new ParAdvectorCGOper(nodes0, u, *pfess, al);
|
||||
oper = new ParAdvectorCGOper(nodes0, u, *pfess);
|
||||
}
|
||||
#endif
|
||||
MFEM_VERIFY(oper != NULL,
|
||||
@@ -95,7 +94,6 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
|
||||
double v_max = 0.0;
|
||||
const int s = new_field.Size();
|
||||
|
||||
u.HostReadWrite();
|
||||
for (int i = 0; i < s; i++)
|
||||
{
|
||||
double vel = 0.;
|
||||
@@ -151,7 +149,6 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
|
||||
#endif
|
||||
|
||||
// Trim the overshoots and undershoots.
|
||||
new_field.HostReadWrite();
|
||||
for (int i = 0; i < s; i++)
|
||||
{
|
||||
if (new_field(i) < glob_minv) { new_field(i) = glob_minv; }
|
||||
@@ -167,21 +164,18 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
|
||||
|
||||
SerialAdvectorCGOper::SerialAdvectorCGOper(const Vector &x_start,
|
||||
GridFunction &vel,
|
||||
FiniteElementSpace &fes,
|
||||
AssemblyLevel al)
|
||||
FiniteElementSpace &fes)
|
||||
: TimeDependentOperator(fes.GetVSize()),
|
||||
x0(x_start), x_now(*fes.GetMesh()->GetNodes()),
|
||||
u(vel), u_coeff(&u), M(&fes), K(&fes), al(al)
|
||||
u(vel), u_coeff(&u), M(&fes), K(&fes)
|
||||
{
|
||||
ConvectionIntegrator *Kinteg = new ConvectionIntegrator(u_coeff);
|
||||
K.AddDomainIntegrator(Kinteg);
|
||||
K.SetAssemblyLevel(al);
|
||||
K.Assemble(0);
|
||||
K.Finalize(0);
|
||||
|
||||
MassIntegrator *Minteg = new MassIntegrator;
|
||||
M.AddDomainIntegrator(Minteg);
|
||||
M.SetAssemblyLevel(al);
|
||||
M.Assemble();
|
||||
M.Finalize();
|
||||
}
|
||||
@@ -192,11 +186,6 @@ void SerialAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
|
||||
const double t = GetTime();
|
||||
add(x0, t, u, x_now);
|
||||
|
||||
if (al == AssemblyLevel::PARTIAL)
|
||||
{
|
||||
K.FESpace()->GetMesh()->DeleteGeometricFactors();
|
||||
}
|
||||
|
||||
// Assemble on the new mesh.
|
||||
K.BilinearForm::operator=(0.0);
|
||||
K.Assemble();
|
||||
@@ -207,45 +196,30 @@ void SerialAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
|
||||
|
||||
di_dt = 0.0;
|
||||
CGSolver lin_solver;
|
||||
Solver *prec = nullptr;
|
||||
Array<int> ess_tdof_list;
|
||||
if (al == AssemblyLevel::PARTIAL)
|
||||
{
|
||||
prec = new OperatorJacobiSmoother(M, ess_tdof_list);
|
||||
lin_solver.SetOperator(M);
|
||||
}
|
||||
else
|
||||
{
|
||||
prec = new DSmoother(M.SpMat());
|
||||
lin_solver.SetOperator(M.SpMat());
|
||||
}
|
||||
lin_solver.SetPreconditioner(*prec);
|
||||
DSmoother prec;
|
||||
lin_solver.SetPreconditioner(prec);
|
||||
lin_solver.SetOperator(M.SpMat());
|
||||
lin_solver.SetRelTol(1e-12); lin_solver.SetAbsTol(0.0);
|
||||
lin_solver.SetMaxIter(100);
|
||||
lin_solver.SetPrintLevel(0);
|
||||
lin_solver.Mult(rhs, di_dt);
|
||||
|
||||
delete prec;
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParAdvectorCGOper::ParAdvectorCGOper(const Vector &x_start,
|
||||
GridFunction &vel,
|
||||
ParFiniteElementSpace &pfes,
|
||||
AssemblyLevel al)
|
||||
ParFiniteElementSpace &pfes)
|
||||
: TimeDependentOperator(pfes.GetVSize()),
|
||||
x0(x_start), x_now(*pfes.GetMesh()->GetNodes()),
|
||||
u(vel), u_coeff(&u), M(&pfes), K(&pfes), al(al)
|
||||
u(vel), u_coeff(&u), M(&pfes), K(&pfes)
|
||||
{
|
||||
ConvectionIntegrator *Kinteg = new ConvectionIntegrator(u_coeff);
|
||||
K.AddDomainIntegrator(Kinteg);
|
||||
K.SetAssemblyLevel(al);
|
||||
K.Assemble(0);
|
||||
K.Finalize(0);
|
||||
|
||||
MassIntegrator *Minteg = new MassIntegrator;
|
||||
M.AddDomainIntegrator(Minteg);
|
||||
M.SetAssemblyLevel(al);
|
||||
M.Assemble();
|
||||
M.Finalize();
|
||||
}
|
||||
@@ -256,11 +230,6 @@ void ParAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
|
||||
const double t = GetTime();
|
||||
add(x0, t, u, x_now);
|
||||
|
||||
if (al == AssemblyLevel::PARTIAL)
|
||||
{
|
||||
K.ParFESpace()->GetParMesh()->DeleteGeometricFactors();
|
||||
}
|
||||
|
||||
// Assemble on the new mesh.
|
||||
K.BilinearForm::operator=(0.0);
|
||||
K.Assemble();
|
||||
@@ -272,25 +241,13 @@ void ParAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
|
||||
HypreParVector *RHS = rhs.ParallelAssemble();
|
||||
HypreParVector X(K.ParFESpace());
|
||||
X = 0.0;
|
||||
|
||||
OperatorHandle Mop;
|
||||
Solver *prec = nullptr;
|
||||
Array<int> ess_tdof_list;
|
||||
if (al == AssemblyLevel::PARTIAL)
|
||||
{
|
||||
M.FormSystemMatrix(ess_tdof_list, Mop);
|
||||
prec = new OperatorJacobiSmoother(M, ess_tdof_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
Mop.Reset(M.ParallelAssemble());
|
||||
prec = new HypreSmoother;
|
||||
static_cast<HypreSmoother*>(prec)->SetType(HypreSmoother::Jacobi, 1);
|
||||
}
|
||||
HypreParMatrix *Mh = M.ParallelAssemble();
|
||||
|
||||
CGSolver lin_solver(M.ParFESpace()->GetParMesh()->GetComm());
|
||||
lin_solver.SetPreconditioner(*prec);
|
||||
lin_solver.SetOperator(*Mop);
|
||||
HypreSmoother prec;
|
||||
prec.SetType(HypreSmoother::Jacobi, 1);
|
||||
lin_solver.SetPreconditioner(prec);
|
||||
lin_solver.SetOperator(*Mh);
|
||||
lin_solver.SetRelTol(1e-8);
|
||||
lin_solver.SetAbsTol(0.0);
|
||||
lin_solver.SetMaxIter(100);
|
||||
@@ -298,8 +255,8 @@ void ParAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
|
||||
lin_solver.Mult(*RHS, X);
|
||||
K.ParFESpace()->GetProlongationMatrix()->Mult(X, di_dt);
|
||||
|
||||
delete Mh;
|
||||
delete RHS;
|
||||
delete prec;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -417,26 +374,18 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
#endif
|
||||
|
||||
double min_detJ = infinity();
|
||||
if (dim == 1)
|
||||
for (int i = 0; i < NE; i++)
|
||||
{
|
||||
for (int i = 0; i < NE; i++)
|
||||
{
|
||||
fes->GetElementVDofs(i, xdofs);
|
||||
x_out_loc.GetSubVector(xdofs, posV);
|
||||
fes->GetElementVDofs(i, xdofs);
|
||||
x_out_loc.GetSubVector(xdofs, posV);
|
||||
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
|
||||
MultAtB(pos, dshape, Jpr);
|
||||
min_detJ = std::min(min_detJ, Jpr.Det());
|
||||
}
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
|
||||
MultAtB(pos, dshape, Jpr);
|
||||
min_detJ = std::min(min_detJ, Jpr.Det());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
min_detJ = dim == 2 ? MinDetJpr_2D(fes, x_out_loc) :
|
||||
dim == 3 ? MinDetJpr_3D(fes, x_out_loc) : 0.0;
|
||||
}
|
||||
double min_detJ_all = min_detJ;
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
@@ -478,26 +427,19 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
if (!untangling)
|
||||
{
|
||||
int jac_ok = 1;
|
||||
if (dim == 1)
|
||||
for (int i = 0; i < NE; i++)
|
||||
{
|
||||
for (int i = 0; i < NE; i++)
|
||||
fes->GetElementVDofs(i, xdofs);
|
||||
x_out_loc.GetSubVector(xdofs, posV);
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
fes->GetElementVDofs(i, xdofs);
|
||||
x_out_loc.GetSubVector(xdofs, posV);
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
|
||||
MultAtB(pos, dshape, Jpr);
|
||||
if (Jpr.Det() <= 0.0) { jac_ok = 0; goto break2; }
|
||||
}
|
||||
fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
|
||||
MultAtB(pos, dshape, Jpr);
|
||||
if (Jpr.Det() <= 0.0) { jac_ok = 0; goto break2; }
|
||||
}
|
||||
break2:;
|
||||
}
|
||||
else
|
||||
{
|
||||
jac_ok = dim == 2 ? CheckDetJpr_2D(fes, x_out_loc) :
|
||||
dim == 3 ? CheckDetJpr_3D(fes, x_out_loc) : 0;
|
||||
}
|
||||
|
||||
break2:
|
||||
int jac_ok_all = jac_ok;
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (parallel)
|
||||
@@ -506,6 +448,7 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
p_nlf->ParFESpace()->GetComm());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (jac_ok_all == 0)
|
||||
{
|
||||
if (print_level >= 0)
|
||||
@@ -515,7 +458,6 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
} // endif(!untangling)
|
||||
|
||||
ProcessNewState(x_out);
|
||||
|
||||
if (serial)
|
||||
{
|
||||
energy_out = nlf->GetGridFunctionEnergy(x_out_loc);
|
||||
@@ -622,7 +564,6 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
|
||||
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
|
||||
for (int j = 0; j < ati.Size(); j++)
|
||||
{
|
||||
ati[j]->UpdateAfterMeshChange(x_loc);
|
||||
ati[j]->ComputeFDh(x_loc, *pfesc);
|
||||
UpdateDiscreteTC(*ati[j], x_loc);
|
||||
}
|
||||
@@ -659,7 +600,6 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
|
||||
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
|
||||
for (int j = 0; j < ati.Size(); j++)
|
||||
{
|
||||
ati[j]->UpdateAfterMeshChange(x_loc);
|
||||
ati[j]->ComputeFDh(x_loc, *fesc);
|
||||
UpdateDiscreteTC(*ati[j], x_loc);
|
||||
}
|
||||
|
||||
+4
-14
@@ -28,14 +28,12 @@ private:
|
||||
Vector nodes0;
|
||||
Vector field0;
|
||||
const double dt_scale;
|
||||
const AssemblyLevel al;
|
||||
|
||||
void ComputeAtNewPositionScalar(const Vector &new_nodes, Vector &new_field);
|
||||
public:
|
||||
AdvectorCG(AssemblyLevel al = AssemblyLevel::LEGACYFULL,
|
||||
double timestep_scale = 0.5)
|
||||
AdvectorCG(double timestep_scale = 0.5)
|
||||
: AdaptivityEvaluator(),
|
||||
ode_solver(), nodes0(), field0(), dt_scale(timestep_scale), al(al) { }
|
||||
ode_solver(), nodes0(), field0(), dt_scale(timestep_scale) { }
|
||||
|
||||
virtual void SetInitialField(const Vector &init_nodes,
|
||||
const Vector &init_field);
|
||||
@@ -80,14 +78,12 @@ protected:
|
||||
GridFunction &u;
|
||||
VectorGridFunctionCoefficient u_coeff;
|
||||
mutable BilinearForm M, K;
|
||||
const AssemblyLevel al;
|
||||
|
||||
public:
|
||||
/** Here @a fes is the FESpace of the function that will be moved. Note
|
||||
that Mult() moves the nodes of the mesh corresponding to @a fes. */
|
||||
SerialAdvectorCGOper(const Vector &x_start, GridFunction &vel,
|
||||
FiniteElementSpace &fes,
|
||||
AssemblyLevel al = AssemblyLevel::LEGACYFULL);
|
||||
FiniteElementSpace &fes);
|
||||
|
||||
virtual void Mult(const Vector &ind, Vector &di_dt) const;
|
||||
};
|
||||
@@ -102,14 +98,12 @@ protected:
|
||||
GridFunction &u;
|
||||
VectorGridFunctionCoefficient u_coeff;
|
||||
mutable ParBilinearForm M, K;
|
||||
const AssemblyLevel al;
|
||||
|
||||
public:
|
||||
/** Here @a pfes is the ParFESpace of the function that will be moved. Note
|
||||
that Mult() moves the nodes of the mesh corresponding to @a pfes. */
|
||||
ParAdvectorCGOper(const Vector &x_start, GridFunction &vel,
|
||||
ParFiniteElementSpace &pfes,
|
||||
AssemblyLevel al = AssemblyLevel::LEGACYFULL);
|
||||
ParFiniteElementSpace &pfes);
|
||||
|
||||
virtual void Mult(const Vector &ind, Vector &di_dt) const;
|
||||
};
|
||||
@@ -165,10 +159,6 @@ public:
|
||||
else { MFEM_ABORT("Invalid type"); }
|
||||
}
|
||||
virtual void SetPreconditioner(Solver &pr) { SetSolver(pr); }
|
||||
int CheckDetJpr_2D(const FiniteElementSpace*, const Vector&) const;
|
||||
int CheckDetJpr_3D(const FiniteElementSpace*, const Vector&) const;
|
||||
double MinDetJpr_2D(const FiniteElementSpace*, const Vector&) const;
|
||||
double MinDetJpr_3D(const FiniteElementSpace*, const Vector&) const;
|
||||
};
|
||||
|
||||
void vis_tmop_metric_s(int order, TMOP_QualityMetric &qm,
|
||||
|
||||
@@ -35,7 +35,6 @@ list(APPEND HDRS
|
||||
backends.hpp
|
||||
binaryio.hpp
|
||||
cuda.hpp
|
||||
debug.hpp
|
||||
device.hpp
|
||||
error.hpp
|
||||
gecko.hpp
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
(defined(MFEM_USE_HIP) && defined(__HIP_DEVICE_COMPILE__)))
|
||||
#define MFEM_SHARED
|
||||
#define MFEM_SYNC_THREAD
|
||||
#define MFEM_BLOCK_ID(k) 0
|
||||
#define MFEM_THREAD_ID(k) 0
|
||||
#define MFEM_THREAD_SIZE(k) 1
|
||||
#define MFEM_FOREACH_THREAD(i,k,N) for(int i=0; i<N; i++)
|
||||
|
||||
+1
-31
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
@@ -61,21 +61,6 @@ void* CuMallocManaged(void** dptr, size_t bytes)
|
||||
return *dptr;
|
||||
}
|
||||
|
||||
void* CuMemAllocHostPinned(void** ptr, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
#ifdef MFEM_TRACK_CUDA_MEM
|
||||
mfem::out << "CuMemAllocHostPinned(): allocating " << bytes << " bytes ... "
|
||||
<< std::flush;
|
||||
#endif
|
||||
MFEM_GPU_CHECK(cudaMallocHost(ptr, bytes));
|
||||
#ifdef MFEM_TRACK_CUDA_MEM
|
||||
mfem::out << "done: " << *ptr << std::endl;
|
||||
#endif
|
||||
#endif
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
void* CuMemFree(void *dptr)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
@@ -91,21 +76,6 @@ void* CuMemFree(void *dptr)
|
||||
return dptr;
|
||||
}
|
||||
|
||||
void* CuMemFreeHostPinned(void *ptr)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
#ifdef MFEM_TRACK_CUDA_MEM
|
||||
mfem::out << "CuMemFreeHostPinned(): deallocating memory @ " << ptr << " ... "
|
||||
<< std::flush;
|
||||
#endif
|
||||
MFEM_GPU_CHECK(cudaFreeHost(ptr));
|
||||
#ifdef MFEM_TRACK_CUDA_MEM
|
||||
mfem::out << "done." << std::endl;
|
||||
#endif
|
||||
#endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* CuMemcpyHtoD(void* dst, const void* src, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
|
||||
+1
-7
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
@@ -63,15 +63,9 @@ void* CuMemAlloc(void **d_ptr, size_t bytes);
|
||||
/// Allocates managed device memory
|
||||
void* CuMallocManaged(void **d_ptr, size_t bytes);
|
||||
|
||||
/// Allocates page-locked (pinned) host memory
|
||||
void* CuMemAllocHostPinned(void **ptr, size_t bytes);
|
||||
|
||||
/// Frees device memory and returns destination ptr.
|
||||
void* CuMemFree(void *d_ptr);
|
||||
|
||||
/// Frees page-locked (pinned) host memory and returns destination ptr.
|
||||
void* CuMemFreeHostPinned(void *ptr);
|
||||
|
||||
/// Copies memory from Host to Device and returns destination ptr.
|
||||
void* CuMemcpyHtoD(void *d_dst, const void *h_src, size_t bytes);
|
||||
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_DEBUG_HPP
|
||||
#define MFEM_DEBUG_HPP
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include "globals.hpp"
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include <mpi.h>
|
||||
#endif
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
class Debug
|
||||
{
|
||||
const bool debug = false;
|
||||
public:
|
||||
inline Debug() {}
|
||||
|
||||
inline Debug(const int mpi_rank,
|
||||
const char *FILE, const int LINE,
|
||||
const char *FUNC, int COLOR): debug(true)
|
||||
{
|
||||
if (!debug) { return; }
|
||||
const char *base = Strrnchr(FILE,'/', 2);
|
||||
const char *file = base ? base + 1 : FILE;
|
||||
const uint8_t color = COLOR ? COLOR : 20 + Checksum8(FILE) % 210;
|
||||
mfem::out << "\033[38;5;" << std::to_string(color) << "m";
|
||||
mfem::out << mpi_rank << std::setw(30) << file << ":";
|
||||
mfem::out << "\033[2m" << std::setw(4) << LINE << "\033[22m: ";
|
||||
if (FUNC) { mfem::out << "[" << FUNC << "] "; }
|
||||
mfem::out << "\033[1m";
|
||||
}
|
||||
|
||||
~Debug()
|
||||
{
|
||||
if (!debug) { return; }
|
||||
mfem::out << "\033[m";
|
||||
mfem::out << std::endl;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void operator<<(const T &arg) const noexcept { mfem::out << arg; }
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline void operator()(const char *fmt, const T &arg,
|
||||
Args... args) const noexcept
|
||||
{
|
||||
if (!debug) { return; }
|
||||
for (; *fmt != '\0'; fmt++ )
|
||||
{
|
||||
if (*fmt == '%')
|
||||
{
|
||||
fmt++;
|
||||
const char c = *fmt;
|
||||
if (c == 'p') { operator<<(arg); }
|
||||
if (c == 's' || c == 'd' || c == 'f') { operator<<(arg); }
|
||||
if (c == 'x' || c == 'X')
|
||||
{
|
||||
mfem::out << std::hex;
|
||||
if (c == 'X') { mfem::out << std::uppercase; }
|
||||
operator<<(arg);
|
||||
mfem::out << std::nouppercase << std::dec;
|
||||
}
|
||||
if (c == '.')
|
||||
{
|
||||
fmt++;
|
||||
const char c = *fmt;
|
||||
char num[8] = { 0 };
|
||||
for (int k = 0; *fmt != '\0'; fmt++, k++)
|
||||
{
|
||||
if (*fmt == 'e' || *fmt == 'f') { break; }
|
||||
if (*fmt < 0x30 || *fmt > 0x39) { break; }
|
||||
num[k] = *fmt;
|
||||
}
|
||||
const int fx = std::atoi(num);
|
||||
if (c == 'e') { mfem::out << std::scientific; }
|
||||
if (c == 'f') { mfem::out << std::fixed; }
|
||||
mfem::out << std::setprecision(fx);
|
||||
operator<<(arg);
|
||||
mfem::out << std::setprecision(6);
|
||||
}
|
||||
return operator()(fmt + 1, args...);
|
||||
}
|
||||
operator<<(*fmt);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void operator()(const T &arg) const noexcept
|
||||
{
|
||||
if (!debug) { return; }
|
||||
operator<<(arg);
|
||||
}
|
||||
|
||||
inline void operator()() const noexcept { }
|
||||
|
||||
public:
|
||||
static const Debug Set(const char *FILE, const int LINE, const char *FUNC,
|
||||
int COLOR = 0)
|
||||
{
|
||||
static int mpi_dbg = 0, mpi_rank = 0;
|
||||
static bool env_mpi = false, env_dbg = false;
|
||||
static bool ini_dbg = false;
|
||||
if (!ini_dbg)
|
||||
{
|
||||
const char *DBG = getenv("MFEM_DEBUG");
|
||||
const char *MPI = getenv("MFEM_DEBUG_MPI");
|
||||
env_dbg = DBG != nullptr;
|
||||
env_mpi = MPI != nullptr;
|
||||
#ifdef MFEM_USE_MPI
|
||||
int mpi_ini = false;
|
||||
MPI_Initialized(&mpi_ini);
|
||||
if (mpi_ini) { MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); }
|
||||
mpi_dbg = atoi(env_mpi ? MPI : "0");
|
||||
#endif
|
||||
ini_dbg = true;
|
||||
}
|
||||
const bool debug = (env_dbg && (!env_mpi || mpi_rank == mpi_dbg));
|
||||
return debug ? Debug(mpi_rank, FILE, LINE, FUNC, COLOR) : Debug();
|
||||
}
|
||||
|
||||
private:
|
||||
inline uint8_t Checksum8(const char *bfr)
|
||||
{
|
||||
unsigned int chk = 0;
|
||||
size_t len = strlen(bfr);
|
||||
for (; len; len--,bfr++) { chk += static_cast<unsigned int>(*bfr); }
|
||||
return (uint8_t) chk;
|
||||
}
|
||||
|
||||
inline const char *Strrnchr(const char *s, const unsigned char c, int n)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
char *p = const_cast<char*>(s) + len - 1;
|
||||
for (; n; n--,p--,len--)
|
||||
{
|
||||
for (; len; p--,len--)
|
||||
if (*p == c) { break; }
|
||||
if (!len) { return nullptr; }
|
||||
if (n == 1) { return p; }
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#ifndef MFEM_DEBUG_COLOR
|
||||
#define MFEM_DEBUG_COLOR 0
|
||||
#endif
|
||||
|
||||
#define dbg(...) \
|
||||
mfem::Debug::Set(__FILE__,__LINE__,__FUNCTION__,MFEM_DEBUG_COLOR).\
|
||||
operator()(__VA_ARGS__)
|
||||
|
||||
} // mfem namespace
|
||||
|
||||
#define DBG(...) { printf("\033[33m"); \
|
||||
printf(__VA_ARGS__); \
|
||||
printf(" \n\033[m"); \
|
||||
fflush(0); }
|
||||
|
||||
#endif // MFEM_DEBUG_HPP
|
||||
+21
-92
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
@@ -12,10 +12,9 @@
|
||||
#include "forall.hpp"
|
||||
#include "occa.hpp"
|
||||
#ifdef MFEM_USE_CEED
|
||||
#include "../fem/ceed/util.hpp"
|
||||
#include <ceed.h>
|
||||
#endif
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
@@ -34,16 +33,13 @@ occa::device occaDevice;
|
||||
|
||||
#ifdef MFEM_USE_CEED
|
||||
Ceed ceed = NULL;
|
||||
|
||||
ceed::BasisMap ceed_basis_map;
|
||||
ceed::RestrMap ceed_restr_map;
|
||||
#endif
|
||||
|
||||
// Backends listed by priority, high to low:
|
||||
static const Backend::Id backend_list[Backend::NUM_BACKENDS] =
|
||||
{
|
||||
Backend::CEED_CUDA, Backend::OCCA_CUDA, Backend::RAJA_CUDA, Backend::CUDA,
|
||||
Backend::CEED_HIP, Backend::RAJA_HIP, Backend::HIP, Backend::DEBUG,
|
||||
Backend::HIP, Backend::DEBUG,
|
||||
Backend::OCCA_OMP, Backend::RAJA_OMP, Backend::OMP,
|
||||
Backend::CEED_CPU, Backend::OCCA_CPU, Backend::RAJA_CPU, Backend::CPU
|
||||
};
|
||||
@@ -52,7 +48,7 @@ static const Backend::Id backend_list[Backend::NUM_BACKENDS] =
|
||||
static const char *backend_name[Backend::NUM_BACKENDS] =
|
||||
{
|
||||
"ceed-cuda", "occa-cuda", "raja-cuda", "cuda",
|
||||
"ceed-hip", "raja-hip", "hip", "debug",
|
||||
"hip", "debug",
|
||||
"occa-omp", "raja-omp", "omp",
|
||||
"ceed-cpu", "occa-cpu", "raja-cpu", "cpu"
|
||||
};
|
||||
@@ -65,9 +61,15 @@ Device Device::device_singleton;
|
||||
bool Device::device_env = false;
|
||||
bool Device::mem_host_env = false;
|
||||
bool Device::mem_device_env = false;
|
||||
bool Device::mem_types_set = false;
|
||||
|
||||
Device::Device()
|
||||
Device::Device() : mode(Device::SEQUENTIAL),
|
||||
backends(Backend::CPU),
|
||||
destroy_mm(false),
|
||||
mpi_gpu_aware(false),
|
||||
host_mem_type(MemoryType::HOST),
|
||||
host_mem_class(MemoryClass::HOST),
|
||||
device_mem_type(MemoryType::HOST),
|
||||
device_mem_class(MemoryClass::HOST)
|
||||
{
|
||||
if (getenv("MFEM_MEMORY") && !mem_host_env && !mem_device_env)
|
||||
{
|
||||
@@ -152,18 +154,6 @@ Device::~Device()
|
||||
{
|
||||
free(device_option);
|
||||
#ifdef MFEM_USE_CEED
|
||||
// Destroy FES -> CeedBasis, CeedElemRestriction hash table contents
|
||||
for (auto entry : internal::ceed_basis_map)
|
||||
{
|
||||
CeedBasisDestroy(&entry.second);
|
||||
}
|
||||
internal::ceed_basis_map.clear();
|
||||
for (auto entry : internal::ceed_restr_map)
|
||||
{
|
||||
CeedElemRestrictionDestroy(&entry.second);
|
||||
}
|
||||
internal::ceed_restr_map.clear();
|
||||
// Destroy Ceed context
|
||||
CeedDestroy(&internal::ceed);
|
||||
#endif
|
||||
mm.Destroy();
|
||||
@@ -220,24 +210,15 @@ void Device::Configure(const std::string &device, const int dev)
|
||||
beg = end + 1;
|
||||
}
|
||||
|
||||
// OCCA_CUDA and CEED_CUDA need CUDA or RAJA_CUDA:
|
||||
if (Allows(Backend::OCCA_CUDA|Backend::CEED_CUDA) &&
|
||||
!Allows(Backend::RAJA_CUDA))
|
||||
// OCCA_CUDA needs CUDA or RAJA_CUDA:
|
||||
if (Allows(Backend::OCCA_CUDA) && !Allows(Backend::RAJA_CUDA))
|
||||
{
|
||||
Get().MarkBackend(Backend::CUDA);
|
||||
}
|
||||
// CEED_HIP needs HIP:
|
||||
if (Allows(Backend::CEED_HIP))
|
||||
if (Allows(Backend::CEED_CUDA))
|
||||
{
|
||||
Get().MarkBackend(Backend::HIP);
|
||||
Get().MarkBackend(Backend::CUDA);
|
||||
}
|
||||
// OCCA_OMP will use OMP or RAJA_OMP unless MFEM_USE_OPENMP=NO:
|
||||
#ifdef MFEM_USE_OPENMP
|
||||
if (Allows(Backend::OCCA_OMP) && !Allows(Backend::RAJA_OMP))
|
||||
{
|
||||
Get().MarkBackend(Backend::OMP);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Perform setup.
|
||||
Get().Setup(dev);
|
||||
@@ -252,30 +233,6 @@ void Device::Configure(const std::string &device, const int dev)
|
||||
destroy_mm = true;
|
||||
}
|
||||
|
||||
// static method
|
||||
void Device::SetMemoryTypes(MemoryType h_mt, MemoryType d_mt)
|
||||
{
|
||||
// If the device and/or the MemoryTypes are configured through the
|
||||
// environment (variables 'MFEM_DEVICE', 'MFEM_MEMORY'), ignore calls to this
|
||||
// method.
|
||||
if (mem_host_env || mem_device_env || device_env) { return; }
|
||||
|
||||
MFEM_VERIFY(!IsConfigured(), "the default MemoryTypes can only be set before"
|
||||
" Device construction and configuration");
|
||||
MFEM_VERIFY(IsHostMemory(h_mt),
|
||||
"invalid host MemoryType, h_mt = " << (int)h_mt);
|
||||
MFEM_VERIFY(IsDeviceMemory(d_mt) || d_mt == h_mt,
|
||||
"invalid device MemoryType, d_mt = " << (int)d_mt
|
||||
<< " (h_mt = " << (int)h_mt << ')');
|
||||
|
||||
Get().host_mem_type = h_mt;
|
||||
Get().device_mem_type = d_mt;
|
||||
mem_types_set = true;
|
||||
|
||||
// h_mt and d_mt will be set as dual to each other during configuration by
|
||||
// the call mm.Configure(...) in UpdateMemoryTypeAndClass()
|
||||
}
|
||||
|
||||
void Device::Print(std::ostream &out)
|
||||
{
|
||||
out << "Device configuration: ";
|
||||
@@ -315,14 +272,7 @@ void Device::UpdateMemoryTypeAndClass()
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
// If MFEM has been compiled with Umpire support, use it as the default
|
||||
if (!mem_host_env && !mem_types_set)
|
||||
{
|
||||
host_mem_type = MemoryType::HOST_UMPIRE;
|
||||
if (!mem_device_env)
|
||||
{
|
||||
device_mem_type = MemoryType::HOST_UMPIRE;
|
||||
}
|
||||
}
|
||||
if (!mem_host_env) { host_mem_type = MemoryType::HOST_UMPIRE; }
|
||||
#endif
|
||||
|
||||
// Enable the device memory type
|
||||
@@ -344,7 +294,7 @@ void Device::UpdateMemoryTypeAndClass()
|
||||
device_mem_type = MemoryType::DEVICE;
|
||||
}
|
||||
}
|
||||
else if (!mem_types_set)
|
||||
else
|
||||
{
|
||||
#ifndef MFEM_USE_UMPIRE
|
||||
device_mem_type = MemoryType::DEVICE;
|
||||
@@ -370,9 +320,6 @@ void Device::UpdateMemoryTypeAndClass()
|
||||
device_mem_type = MemoryType::DEVICE_DEBUG;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(!device || IsDeviceMemory(device_mem_type),
|
||||
"invalid device memory configuration!");
|
||||
|
||||
// Update the memory manager with the new settings
|
||||
mm.Configure(host_mem_type, device_mem_type);
|
||||
}
|
||||
@@ -422,8 +369,6 @@ static void RajaDeviceSetup(const int dev, int &ngpu)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (ngpu <= 0) { DeviceSetup(dev, ngpu); }
|
||||
#elif defined(MFEM_USE_HIP)
|
||||
HipDeviceSetup(dev, ngpu);
|
||||
#else
|
||||
MFEM_CONTRACT_VAR(dev);
|
||||
MFEM_CONTRACT_VAR(ngpu);
|
||||
@@ -490,8 +435,7 @@ static void CeedDeviceSetup(const char* ceed_spec)
|
||||
CeedInit(ceed_spec, &internal::ceed);
|
||||
const char *ceed_backend;
|
||||
CeedGetResource(internal::ceed, &ceed_backend);
|
||||
if (strcmp(ceed_spec, ceed_backend) && strcmp(ceed_spec, "/cpu/self") &&
|
||||
strcmp(ceed_spec, "/gpu/hip"))
|
||||
if (strcmp(ceed_spec, ceed_backend) && strcmp(ceed_spec, "/cpu/self"))
|
||||
{
|
||||
mfem::out << std::endl << "WARNING!!!\n"
|
||||
"libCEED is not using the requested backend!!!\n"
|
||||
@@ -529,16 +473,12 @@ void Device::Setup(const int device)
|
||||
MFEM_VERIFY(!Allows(Backend::CEED_MASK),
|
||||
"the CEED backends require MFEM built with MFEM_USE_CEED=YES");
|
||||
#else
|
||||
int ceed_cpu = Allows(Backend::CEED_CPU);
|
||||
int ceed_cuda = Allows(Backend::CEED_CUDA);
|
||||
int ceed_hip = Allows(Backend::CEED_HIP);
|
||||
MFEM_VERIFY(ceed_cpu + ceed_cuda + ceed_hip <= 1,
|
||||
MFEM_VERIFY(!Allows(Backend::CEED_CPU) || !Allows(Backend::CEED_CUDA),
|
||||
"Only one CEED backend can be enabled at a time!");
|
||||
#endif
|
||||
if (Allows(Backend::CUDA)) { CudaDeviceSetup(dev, ngpu); }
|
||||
if (Allows(Backend::HIP)) { HipDeviceSetup(dev, ngpu); }
|
||||
if (Allows(Backend::RAJA_CUDA) || Allows(Backend::RAJA_HIP))
|
||||
{ RajaDeviceSetup(dev, ngpu); }
|
||||
if (Allows(Backend::RAJA_CUDA)) { RajaDeviceSetup(dev, ngpu); }
|
||||
// The check for MFEM_USE_OCCA is in the function OccaDeviceSetup().
|
||||
if (Allows(Backend::OCCA_MASK)) { OccaDeviceSetup(dev); }
|
||||
if (Allows(Backend::CEED_CPU))
|
||||
@@ -564,17 +504,6 @@ void Device::Setup(const int device)
|
||||
CeedDeviceSetup(device_option);
|
||||
}
|
||||
}
|
||||
if (Allows(Backend::CEED_HIP))
|
||||
{
|
||||
if (!device_option)
|
||||
{
|
||||
CeedDeviceSetup("/gpu/hip");
|
||||
}
|
||||
else
|
||||
{
|
||||
CeedDeviceSetup(device_option);
|
||||
}
|
||||
}
|
||||
if (Allows(Backend::DEBUG)) { ngpu = 1; }
|
||||
}
|
||||
|
||||
|
||||
+35
-56
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
@@ -46,33 +46,26 @@ struct Backend
|
||||
/** @brief [device] RAJA CUDA backend. Enabled when MFEM_USE_RAJA = YES
|
||||
and MFEM_USE_CUDA = YES. */
|
||||
RAJA_CUDA = 1 << 6,
|
||||
/** @brief [device] RAJA HIP backend. Enabled when MFEM_USE_RAJA = YES
|
||||
and MFEM_USE_HIP = YES. */
|
||||
RAJA_HIP = 1 << 7,
|
||||
/** @brief [host] OCCA CPU backend: sequential execution on each MPI rank.
|
||||
Enabled when MFEM_USE_OCCA = YES. */
|
||||
OCCA_CPU = 1 << 8,
|
||||
OCCA_CPU = 1 << 7,
|
||||
/// [host] OCCA OpenMP backend. Enabled when MFEM_USE_OCCA = YES.
|
||||
OCCA_OMP = 1 << 9,
|
||||
OCCA_OMP = 1 << 8,
|
||||
/** @brief [device] OCCA CUDA backend. Enabled when MFEM_USE_OCCA = YES
|
||||
and MFEM_USE_CUDA = YES. */
|
||||
OCCA_CUDA = 1 << 10,
|
||||
OCCA_CUDA = 1 << 9,
|
||||
/** @brief [host] CEED CPU backend. GPU backends can still be used, but
|
||||
with expensive memory transfers. Enabled when MFEM_USE_CEED = YES. */
|
||||
CEED_CPU = 1 << 11,
|
||||
CEED_CPU = 1 << 10,
|
||||
/** @brief [device] CEED CUDA backend working together with the CUDA
|
||||
backend. Enabled when MFEM_USE_CEED = YES and MFEM_USE_CUDA = YES.
|
||||
NOTE: The current default libCEED CUDA backend is non-deterministic! */
|
||||
CEED_CUDA = 1 << 12,
|
||||
/** @brief [device] CEED HIP backend working together with the HIP
|
||||
backend. Enabled when MFEM_USE_CEED = YES and MFEM_USE_HIP = YES. */
|
||||
CEED_HIP = 1 << 13,
|
||||
NOTE: The current default libCEED GPU backend is non-deterministic! */
|
||||
CEED_CUDA = 1 << 11,
|
||||
/** @brief [device] Debug backend: host memory is READ/WRITE protected
|
||||
while a device is in use. It allows to test the "device" code-path
|
||||
(using separate host/device memory pools and host <-> device
|
||||
transfers) without any GPU hardware. As 'DEBUG' is sometimes used
|
||||
as a macro, `_DEVICE` has been added to avoid conflicts. */
|
||||
DEBUG = 1 << 14
|
||||
transfers) without any GPU hardware. */
|
||||
DEBUG = 1 << 12
|
||||
};
|
||||
|
||||
/** @brief Additional useful constants. For example, the *_MASK constants can
|
||||
@@ -80,23 +73,23 @@ struct Backend
|
||||
enum
|
||||
{
|
||||
/// Number of backends: from (1 << 0) to (1 << (NUM_BACKENDS-1)).
|
||||
NUM_BACKENDS = 15,
|
||||
NUM_BACKENDS = 13,
|
||||
|
||||
/// Biwise-OR of all CPU backends
|
||||
CPU_MASK = CPU | RAJA_CPU | OCCA_CPU | CEED_CPU,
|
||||
/// Biwise-OR of all CUDA backends
|
||||
CUDA_MASK = CUDA | RAJA_CUDA | OCCA_CUDA | CEED_CUDA,
|
||||
/// Biwise-OR of all HIP backends
|
||||
HIP_MASK = HIP | RAJA_HIP | CEED_HIP,
|
||||
HIP_MASK = HIP,
|
||||
/// Biwise-OR of all OpenMP backends
|
||||
OMP_MASK = OMP | RAJA_OMP | OCCA_OMP,
|
||||
/// Bitwise-OR of all CEED backends
|
||||
CEED_MASK = CEED_CPU | CEED_CUDA | CEED_HIP,
|
||||
CEED_MASK = CEED_CPU | CEED_CUDA,
|
||||
/// Biwise-OR of all device backends
|
||||
DEVICE_MASK = CUDA_MASK | HIP_MASK | DEBUG,
|
||||
|
||||
/// Biwise-OR of all RAJA backends
|
||||
RAJA_MASK = RAJA_CPU | RAJA_OMP | RAJA_CUDA | RAJA_HIP,
|
||||
RAJA_MASK = RAJA_CPU | RAJA_OMP | RAJA_CUDA,
|
||||
/// Biwise-OR of all OCCA backends
|
||||
OCCA_MASK = OCCA_CPU | OCCA_OMP | OCCA_CUDA
|
||||
};
|
||||
@@ -124,25 +117,22 @@ private:
|
||||
friend class MemoryManager;
|
||||
enum MODES {SEQUENTIAL, ACCELERATED};
|
||||
|
||||
static bool device_env, mem_host_env, mem_device_env, mem_types_set;
|
||||
static bool device_env, mem_host_env, mem_device_env;
|
||||
static Device device_singleton;
|
||||
|
||||
MODES mode = Device::SEQUENTIAL;
|
||||
int dev = 0; ///< Device ID of the configured device.
|
||||
MODES mode;
|
||||
int dev = 0; ///< Device ID of the configured device.
|
||||
int ngpu = -1; ///< Number of detected devices; -1: not initialized.
|
||||
/// Bitwise-OR of all configured backends.
|
||||
unsigned long backends = Backend::CPU;
|
||||
unsigned long backends; ///< Bitwise-OR of all configured backends.
|
||||
/// Set to true during configuration, except in 'device_singleton'.
|
||||
bool destroy_mm = false;
|
||||
bool mpi_gpu_aware = false;
|
||||
bool destroy_mm;
|
||||
bool mpi_gpu_aware;
|
||||
|
||||
MemoryType host_mem_type = MemoryType::HOST; ///< Current Host MemoryType
|
||||
MemoryClass host_mem_class = MemoryClass::HOST; ///< Current Host MemoryClass
|
||||
MemoryType host_mem_type; ///< Current Host MemoryType
|
||||
MemoryClass host_mem_class; ///< Current Host MemoryClass
|
||||
|
||||
/// Current Device MemoryType
|
||||
MemoryType device_mem_type = MemoryType::HOST;
|
||||
/// Current Device MemoryClass
|
||||
MemoryClass device_mem_class = MemoryClass::HOST;
|
||||
MemoryType device_mem_type; ///< Current Device MemoryType
|
||||
MemoryClass device_mem_class; ///< Current Device MemoryClass
|
||||
|
||||
char *device_option = NULL;
|
||||
Device(Device const&);
|
||||
@@ -183,6 +173,14 @@ public:
|
||||
@note This object should be destroyed after all other MFEM objects that
|
||||
use the Device are destroyed. */
|
||||
Device(const std::string &device, const int dev = 0)
|
||||
: mode(Device::SEQUENTIAL),
|
||||
backends(Backend::CPU),
|
||||
destroy_mm(false),
|
||||
mpi_gpu_aware(false),
|
||||
host_mem_type(MemoryType::HOST),
|
||||
host_mem_class(MemoryClass::HOST),
|
||||
device_mem_type(MemoryType::HOST),
|
||||
device_mem_class(MemoryClass::HOST)
|
||||
{ Configure(device, dev); }
|
||||
|
||||
/// Destructor.
|
||||
@@ -195,44 +193,25 @@ public:
|
||||
* The available backends are described by the Backend class.
|
||||
* The string name of a backend is the lowercase version of the
|
||||
Backend::Id enumeration constant with '_' replaced by '-', e.g. the
|
||||
string name of 'RAJA_CPU' is 'raja-cpu'. The string name of the debug
|
||||
backend (Backend::Id 'DEBUG_DEVICE') is exceptionally set to 'debug'.
|
||||
string name of 'RAJA_CPU' is 'raja-cpu'.
|
||||
* The 'cpu' backend is always enabled with lowest priority.
|
||||
* The current backend priority from highest to lowest is:
|
||||
'ceed-cuda', 'occa-cuda', 'raja-cuda', 'cuda',
|
||||
'ceed-hip', 'hip', 'debug',
|
||||
'ceed-cuda', 'occa-cuda', 'raja-cuda', 'cuda', 'hip', 'debug',
|
||||
'occa-omp', 'raja-omp', 'omp',
|
||||
'ceed-cpu', 'occa-cpu', 'raja-cpu', 'cpu'.
|
||||
* Multiple backends can be configured at the same time.
|
||||
* Only one 'occa-*' backend can be configured at a time.
|
||||
* The backend 'occa-cuda' enables the 'cuda' backend unless 'raja-cuda'
|
||||
is already enabled.
|
||||
* The backend 'occa-omp' enables the 'omp' backend (if MFEM was built
|
||||
with MFEM_USE_OPENMP=YES) unless 'raja-omp' is already enabled.
|
||||
* Only one 'ceed-*' backend can be configured at a time.
|
||||
* The backend 'ceed-cpu' delegates to a libCEED CPU backend the setup and
|
||||
evaluation of the operator.
|
||||
* The backend 'ceed-cuda' delegates to a libCEED CUDA backend the setup
|
||||
and evaluation of operators and enables the 'cuda' backend to avoid
|
||||
transfers between host and device.
|
||||
* The backend 'ceed-hip' delegates to a libCEED HIP backend the setup
|
||||
and evaluation of operators and enables the 'hip' backend to avoid
|
||||
transfers between host and device.
|
||||
and evaluation of the operator and enables the 'cuda' backend to avoid
|
||||
transfer between host and device.
|
||||
* The 'debug' backend should not be combined with other device backends.
|
||||
*/
|
||||
void Configure(const std::string &device, const int dev = 0);
|
||||
|
||||
/// Set the default host and device MemoryTypes, @a h_mt and @a d_mt.
|
||||
/** The host and device MemoryTypes are also set to be dual to each other.
|
||||
|
||||
These two MemoryType%s are used by most MFEM classes when allocating
|
||||
memory used on host and device, respectively.
|
||||
|
||||
This method can only be called before Device construction and
|
||||
configuration, and the specified memory types must be compatible with
|
||||
the subsequent Device configuration. */
|
||||
static void SetMemoryTypes(MemoryType h_mt, MemoryType d_mt);
|
||||
|
||||
/// Print the configuration of the MFEM virtual device object.
|
||||
void Print(std::ostream &out = mfem::out);
|
||||
|
||||
|
||||
+2
-11
@@ -23,8 +23,8 @@ namespace mfem
|
||||
{
|
||||
|
||||
// Maximum size of dofs and quads in 1D.
|
||||
const int MAX_D1D = 8;
|
||||
const int MAX_Q1D = 8;
|
||||
const int MAX_D1D = 14;
|
||||
const int MAX_Q1D = 14;
|
||||
|
||||
// MFEM pragma macros that can be used inside MFEM_FORALL macros.
|
||||
#define MFEM_PRAGMA(X) _Pragma(#X)
|
||||
@@ -89,11 +89,7 @@ void OmpWrap(const int N, HBODY &&h_body)
|
||||
/// RAJA Cuda backend
|
||||
#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_CUDA)
|
||||
|
||||
#if RAJA_VERSION_MAJOR == 0 && RAJA_VERSION_MINOR < 12
|
||||
using RAJA::statement::Segs;
|
||||
#else
|
||||
using RAJA::Segs;
|
||||
#endif
|
||||
|
||||
template <const int BLOCKS = MFEM_CUDA_BLOCKS, typename DBODY>
|
||||
void RajaCudaWrap1D(const int N, DBODY &&d_body)
|
||||
@@ -151,12 +147,7 @@ void RajaCudaWrap3D(const int N, DBODY &&d_body,
|
||||
/// RAJA OpenMP backend
|
||||
#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_OPENMP)
|
||||
|
||||
#if RAJA_VERSION_MAJOR == 0 && RAJA_VERSION_MINOR < 12
|
||||
using RAJA::statement::Segs;
|
||||
#else
|
||||
using RAJA::Segs;
|
||||
#endif
|
||||
|
||||
|
||||
template <typename HBODY>
|
||||
void RajaOmpWrap(const int N, HBODY &&h_body)
|
||||
|
||||
+2
-32
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
@@ -61,21 +61,6 @@ void* HipMallocManaged(void** dptr, size_t bytes)
|
||||
return *dptr;
|
||||
}
|
||||
|
||||
void* HipMemAllocHostPinned(void** ptr, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_HIP
|
||||
#ifdef MFEM_TRACK_HIP_MEM
|
||||
mfem::out << "HipMemAllocHostPinned(): allocating " << bytes << " bytes ... "
|
||||
<< std::flush;
|
||||
#endif
|
||||
MFEM_GPU_CHECK(hipHostMalloc(ptr, bytes, hipHostMallocDefault));
|
||||
#ifdef MFEM_TRACK_HIP_MEM
|
||||
mfem::out << "done: " << *ptr << std::endl;
|
||||
#endif
|
||||
#endif
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
void* HipMemFree(void *dptr)
|
||||
{
|
||||
#ifdef MFEM_USE_HIP
|
||||
@@ -91,21 +76,6 @@ void* HipMemFree(void *dptr)
|
||||
return dptr;
|
||||
}
|
||||
|
||||
void* HipMemFreeHostPinned(void *ptr)
|
||||
{
|
||||
#ifdef MFEM_USE_HIP
|
||||
#ifdef MFEM_TRACK_HIP_MEM
|
||||
mfem::out << "HipMemFreeHostPinned(): deallocating memory @ " << ptr << " ... "
|
||||
<< std::flush;
|
||||
#endif
|
||||
MFEM_GPU_CHECK(hipHostFree(ptr));
|
||||
#ifdef MFEM_TRACK_HIP_MEM
|
||||
mfem::out << "done." << std::endl;
|
||||
#endif
|
||||
#endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* HipMemcpyHtoD(void* dst, const void* src, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_HIP
|
||||
@@ -155,7 +125,7 @@ void* HipMemcpyDtoDAsync(void* dst, const void *src, size_t bytes)
|
||||
void* HipMemcpyDtoH(void *dst, const void *src, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_HIP
|
||||
#ifdef MFEM_TRACK_HIP_MEM
|
||||
#ifdef MFEM_TRACK_HPI_MEM
|
||||
mfem::out << "HipMemcpyDtoH(): copying " << bytes << " bytes from "
|
||||
<< src << " to " << dst << " ... " << std::flush;
|
||||
#endif
|
||||
|
||||
+1
-7
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
@@ -64,15 +64,9 @@ void* HipMemAlloc(void **d_ptr, size_t bytes);
|
||||
/// Allocates managed device memory
|
||||
void* HipMallocManaged(void **d_ptr, size_t bytes);
|
||||
|
||||
/// Allocates page-locked (pinned) host memory
|
||||
void* HipMemAllocHostPinned(void **ptr, size_t bytes);
|
||||
|
||||
/// Frees device memory
|
||||
void* HipMemFree(void *d_ptr);
|
||||
|
||||
/// Frees page-locked (pinned) host memory and returns destination ptr.
|
||||
void* HipMemFreeHostPinned(void *ptr);
|
||||
|
||||
/// Copies memory from Host to Device
|
||||
void* HipMemcpyHtoD(void *d_dst, const void *h_src, size_t bytes);
|
||||
|
||||
|
||||
+125
-362
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
@@ -62,39 +62,38 @@ MemoryType GetMemoryType(MemoryClass mc)
|
||||
return MemoryType::HOST;
|
||||
}
|
||||
|
||||
// We want to keep this pairs, as it is checked in MFEM_VERIFY_TYPES
|
||||
MemoryType MemoryManager::GetDualMemoryType_(MemoryType mt)
|
||||
{
|
||||
switch (mt)
|
||||
{
|
||||
case MemoryType::HOST: return MemoryType::DEVICE;
|
||||
case MemoryType::HOST_32: return MemoryType::DEVICE;
|
||||
case MemoryType::HOST_64: return MemoryType::DEVICE;
|
||||
case MemoryType::HOST_DEBUG: return MemoryType::DEVICE_DEBUG;
|
||||
case MemoryType::HOST_UMPIRE: return MemoryType::DEVICE_UMPIRE;
|
||||
case MemoryType::MANAGED: return MemoryType::MANAGED;
|
||||
case MemoryType::DEVICE: return MemoryType::HOST;
|
||||
case MemoryType::DEVICE_DEBUG: return MemoryType::HOST_DEBUG;
|
||||
case MemoryType::DEVICE_UMPIRE: return MemoryType::HOST_UMPIRE;
|
||||
default: mfem_error("Unknown memory type!");
|
||||
}
|
||||
MFEM_VERIFY(false,"");
|
||||
return MemoryType::HOST;
|
||||
}
|
||||
|
||||
static void MFEM_VERIFY_TYPES(const MemoryType h_mt, const MemoryType d_mt)
|
||||
{
|
||||
MFEM_VERIFY(IsHostMemory(h_mt), "h_mt = " << (int)h_mt);
|
||||
MFEM_VERIFY(IsDeviceMemory(d_mt) || d_mt == MemoryType::DEFAULT,
|
||||
"d_mt = " << (int)d_mt);
|
||||
// If h_mt == MemoryType::HOST_DEBUG, then d_mt == MemoryType::DEVICE_DEBUG
|
||||
// or d_mt == MemoryType::DEFAULT
|
||||
MFEM_VERIFY(h_mt != MemoryType::HOST_DEBUG ||
|
||||
d_mt == MemoryType::DEVICE_DEBUG ||
|
||||
d_mt == MemoryType::DEFAULT,
|
||||
"d_mt = " << MemoryTypeName[(int)d_mt]);
|
||||
// If d_mt == MemoryType::DEVICE_DEBUG, then h_mt == MemoryType::HOST_DEBUG
|
||||
MFEM_VERIFY(d_mt != MemoryType::DEVICE_DEBUG ||
|
||||
h_mt == MemoryType::HOST_DEBUG,
|
||||
"h_mt = " << MemoryTypeName[(int)h_mt]);
|
||||
#if 0
|
||||
MFEM_ASSERT(IsHostMemory(h_mt),"");
|
||||
MFEM_ASSERT(IsDeviceMemory(d_mt),"");
|
||||
const bool sync =
|
||||
(h_mt == MemoryType::HOST_PINNED && d_mt == MemoryType::DEVICE) ||
|
||||
(h_mt == MemoryType::HOST_PINNED && d_mt == MemoryType::DEVICE_UMPIRE) ||
|
||||
(h_mt == MemoryType::HOST_PINNED && d_mt == MemoryType::DEVICE_UMPIRE_2) ||
|
||||
(h_mt == MemoryType::HOST_UMPIRE && d_mt == MemoryType::DEVICE) ||
|
||||
(h_mt == MemoryType::HOST_UMPIRE && d_mt == MemoryType::DEVICE_UMPIRE) ||
|
||||
(h_mt == MemoryType::HOST_UMPIRE && d_mt == MemoryType::DEVICE_UMPIRE_2) ||
|
||||
(h_mt == MemoryType::HOST_DEBUG && d_mt == MemoryType::DEVICE_DEBUG) ||
|
||||
(h_mt == MemoryType::MANAGED && d_mt == MemoryType::MANAGED) ||
|
||||
(h_mt == MemoryType::HOST_64 && d_mt == MemoryType::DEVICE) ||
|
||||
(h_mt == MemoryType::HOST_32 && d_mt == MemoryType::DEVICE) ||
|
||||
(h_mt == MemoryType::HOST && d_mt == MemoryType::DEVICE) ||
|
||||
(h_mt == MemoryType::HOST && d_mt == MemoryType::DEVICE_UMPIRE) ||
|
||||
(h_mt == MemoryType::HOST && d_mt == MemoryType::DEVICE_UMPIRE_2);
|
||||
(h_mt == MemoryType::HOST && d_mt == MemoryType::DEVICE);
|
||||
MFEM_VERIFY(sync, "");
|
||||
#endif
|
||||
}
|
||||
|
||||
MemoryClass operator*(MemoryClass mc1, MemoryClass mc2)
|
||||
@@ -136,12 +135,9 @@ struct Memory
|
||||
void *const h_ptr;
|
||||
void *d_ptr;
|
||||
const size_t bytes;
|
||||
const MemoryType h_mt;
|
||||
MemoryType d_mt;
|
||||
mutable bool h_rw, d_rw;
|
||||
const MemoryType h_mt, d_mt;
|
||||
Memory(void *p, size_t b, MemoryType h, MemoryType d):
|
||||
h_ptr(p), d_ptr(nullptr), bytes(b), h_mt(h), d_mt(d),
|
||||
h_rw(true), d_rw(true) { }
|
||||
h_ptr(p), d_ptr(nullptr), bytes(b), h_mt(h), d_mt(d) { }
|
||||
};
|
||||
|
||||
/// Alias class that holds the base memory region and the offset
|
||||
@@ -177,8 +173,8 @@ public:
|
||||
virtual ~HostMemorySpace() { }
|
||||
virtual void Alloc(void **ptr, size_t bytes) { *ptr = std::malloc(bytes); }
|
||||
virtual void Dealloc(void *ptr) { std::free(ptr); }
|
||||
virtual void Protect(const Memory&, size_t) { }
|
||||
virtual void Unprotect(const Memory&, size_t) { }
|
||||
virtual void Protect(const void*, size_t) { }
|
||||
virtual void Unprotect(const void*, size_t) { }
|
||||
virtual void AliasProtect(const void*, size_t) { }
|
||||
virtual void AliasUnprotect(const void*, size_t) { }
|
||||
};
|
||||
@@ -356,10 +352,8 @@ public:
|
||||
MmuHostMemorySpace(): HostMemorySpace() { MmuInit(); }
|
||||
void Alloc(void **ptr, size_t bytes) { MmuAlloc(ptr, bytes); }
|
||||
void Dealloc(void *ptr) { MmuDealloc(ptr, maps->memories.at(ptr).bytes); }
|
||||
void Protect(const Memory& mem, size_t bytes)
|
||||
{ if (mem.h_rw) { mem.h_rw = false; MmuProtect(mem.h_ptr, bytes); } }
|
||||
void Unprotect(const Memory &mem, size_t bytes)
|
||||
{ if (!mem.h_rw) { mem.h_rw = true; MmuAllow(mem.h_ptr, bytes); } }
|
||||
void Protect(const void *ptr, size_t bytes) { MmuProtect(ptr, bytes); }
|
||||
void Unprotect(const void *ptr, size_t bytes) { MmuAllow(ptr, bytes); }
|
||||
/// Aliases need to be restricted during protection
|
||||
void AliasProtect(const void *ptr, size_t bytes)
|
||||
{ MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
|
||||
@@ -406,31 +400,6 @@ public:
|
||||
{ return CuMemcpyDtoH(dst, src, bytes); }
|
||||
};
|
||||
|
||||
/// The CUDA/HIP page-locked host memory space
|
||||
class HostPinnedMemorySpace: public HostMemorySpace
|
||||
{
|
||||
public:
|
||||
HostPinnedMemorySpace(): HostMemorySpace() { }
|
||||
void Alloc(void ** ptr, size_t bytes) override
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
CuMemAllocHostPinned(ptr, bytes);
|
||||
#endif
|
||||
#ifdef MFEM_USE_HIP
|
||||
HipMemAllocHostPinned(ptr, bytes);
|
||||
#endif
|
||||
}
|
||||
void Dealloc(void *ptr) override
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
CuMemFreeHostPinned(ptr);
|
||||
#endif
|
||||
#ifdef MFEM_USE_HIP
|
||||
HipMemFreeHostPinned(ptr);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/// The HIP device memory space
|
||||
class HipDeviceMemorySpace: public DeviceMemorySpace
|
||||
{
|
||||
@@ -473,10 +442,8 @@ public:
|
||||
MmuDeviceMemorySpace(): DeviceMemorySpace() { }
|
||||
void Alloc(Memory &m) { MmuAlloc(&m.d_ptr, m.bytes); }
|
||||
void Dealloc(Memory &m) { MmuDealloc(m.d_ptr, m.bytes); }
|
||||
void Protect(const Memory &m)
|
||||
{ if (m.d_rw) { m.d_rw = false; MmuProtect(m.d_ptr, m.bytes); } }
|
||||
void Unprotect(const Memory &m)
|
||||
{ if (!m.d_rw) { m.d_rw = true; MmuAllow(m.d_ptr, m.bytes); } }
|
||||
void Protect(const Memory &m) { MmuProtect(m.d_ptr, m.bytes); }
|
||||
void Unprotect(const Memory &m) { MmuAllow(m.d_ptr, m.bytes); }
|
||||
/// Aliases need to be restricted during protection
|
||||
void AliasProtect(const void *ptr, size_t bytes)
|
||||
{ MmuProtect(MmuAddrR(ptr), MmuLengthR(ptr, bytes)); }
|
||||
@@ -491,64 +458,54 @@ public:
|
||||
{ return std::memcpy(dst, src, bytes); }
|
||||
};
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
class UmpireMemorySpace
|
||||
{
|
||||
protected:
|
||||
umpire::ResourceManager &rm;
|
||||
umpire::Allocator allocator;
|
||||
bool owns_allocator{false};
|
||||
|
||||
public:
|
||||
// TODO: this only releases unused memory
|
||||
virtual ~UmpireMemorySpace() { if (owns_allocator) { allocator.release(); } }
|
||||
UmpireMemorySpace(const char * name, const char * space)
|
||||
: rm(umpire::ResourceManager::getInstance())
|
||||
{
|
||||
if (!rm.isAllocator(name))
|
||||
{
|
||||
allocator = rm.makeAllocator<umpire::strategy::DynamicPool>(
|
||||
name, rm.getAllocator(space));
|
||||
owns_allocator = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
allocator = rm.getAllocator(name);
|
||||
owns_allocator = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef MFEM_USE_UMPIRE
|
||||
class UmpireHostMemorySpace : public NoHostMemorySpace { };
|
||||
class UmpireDeviceMemorySpace : public NoDeviceMemorySpace { };
|
||||
#else
|
||||
/// The Umpire host memory space
|
||||
class UmpireHostMemorySpace : public HostMemorySpace, public UmpireMemorySpace
|
||||
class UmpireHostMemorySpace : public HostMemorySpace
|
||||
{
|
||||
private:
|
||||
const char *name;
|
||||
umpire::ResourceManager &rm;
|
||||
umpire::Allocator h_allocator;
|
||||
umpire::strategy::AllocationStrategy *strat;
|
||||
public:
|
||||
UmpireHostMemorySpace(const char * name)
|
||||
: HostMemorySpace(),
|
||||
UmpireMemorySpace(name, "HOST"),
|
||||
strat(allocator.getAllocationStrategy()) {}
|
||||
void Alloc(void **ptr, size_t bytes) override
|
||||
{ *ptr = allocator.allocate(bytes); }
|
||||
void Dealloc(void *ptr) override { allocator.deallocate(ptr); }
|
||||
~UmpireHostMemorySpace() { h_allocator.release(); }
|
||||
UmpireHostMemorySpace():
|
||||
HostMemorySpace(),
|
||||
name(mm.GetUmpireAllocatorHostName()),
|
||||
rm(umpire::ResourceManager::getInstance()),
|
||||
h_allocator(rm.isAllocator(name)? rm.getAllocator(name):
|
||||
rm.makeAllocator<umpire::strategy::DynamicPool>
|
||||
(name, rm.getAllocator("HOST"))),
|
||||
strat(h_allocator.getAllocationStrategy()) { }
|
||||
void Alloc(void **ptr, size_t bytes) { *ptr = h_allocator.allocate(bytes); }
|
||||
void Dealloc(void *ptr) { h_allocator.deallocate(ptr); }
|
||||
void Insert(void *ptr, size_t bytes)
|
||||
{ rm.registerAllocation(ptr, {ptr, bytes, strat}); }
|
||||
};
|
||||
|
||||
/// The Umpire device memory space
|
||||
#if defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP)
|
||||
class UmpireDeviceMemorySpace : public DeviceMemorySpace,
|
||||
public UmpireMemorySpace
|
||||
#ifdef MFEM_USE_CUDA
|
||||
class UmpireDeviceMemorySpace : public DeviceMemorySpace
|
||||
{
|
||||
private:
|
||||
const char *name;
|
||||
umpire::ResourceManager &rm;
|
||||
umpire::Allocator d_allocator;
|
||||
public:
|
||||
UmpireDeviceMemorySpace(const char * name)
|
||||
: DeviceMemorySpace(),
|
||||
UmpireMemorySpace(name, "DEVICE") {}
|
||||
void Alloc(Memory &base) override
|
||||
{ base.d_ptr = allocator.allocate(base.bytes); }
|
||||
void Dealloc(Memory &base) override { rm.deallocate(base.d_ptr); }
|
||||
void *HtoD(void *dst, const void *src, size_t bytes) override
|
||||
~UmpireDeviceMemorySpace() { d_allocator.release(); }
|
||||
UmpireDeviceMemorySpace():
|
||||
DeviceMemorySpace(),
|
||||
name(mm.GetUmpireAllocatorDeviceName()),
|
||||
rm(umpire::ResourceManager::getInstance()),
|
||||
d_allocator(rm.isAllocator(name)? rm.getAllocator(name):
|
||||
rm.makeAllocator<umpire::strategy::DynamicPool>
|
||||
(name, rm.getAllocator("DEVICE"))) { }
|
||||
void Alloc(Memory &base) { base.d_ptr = d_allocator.allocate(base.bytes); }
|
||||
void Dealloc(Memory &base) { d_allocator.deallocate(base.d_ptr); }
|
||||
void *HtoD(void *dst, const void *src, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
return CuMemcpyHtoD(dst, src, bytes);
|
||||
@@ -558,7 +515,7 @@ public:
|
||||
#endif
|
||||
//rm.copy(dst, const_cast<void*>(src), bytes); return dst;
|
||||
}
|
||||
void *DtoD(void* dst, const void* src, size_t bytes) override
|
||||
void *DtoD(void* dst, const void* src, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
return CuMemcpyDtoD(dst, src, bytes);
|
||||
@@ -568,7 +525,7 @@ public:
|
||||
#endif
|
||||
//rm.copy(dst, const_cast<void*>(src), bytes); return dst;
|
||||
}
|
||||
void *DtoH(void *dst, const void *src, size_t bytes) override
|
||||
void *DtoH(void *dst, const void *src, size_t bytes)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
return CuMemcpyDtoH(dst, src, bytes);
|
||||
@@ -580,12 +537,8 @@ public:
|
||||
}
|
||||
};
|
||||
#else
|
||||
class UmpireDeviceMemorySpace : public NoDeviceMemorySpace
|
||||
{
|
||||
public:
|
||||
UmpireDeviceMemorySpace(const char * /*unused*/) {}
|
||||
};
|
||||
#endif // MFEM_USE_CUDA || MFEM_USE_HIP
|
||||
class UmpireDeviceMemorySpace : public NoDeviceMemorySpace { };
|
||||
#endif // MFEM_USE_CUDA
|
||||
#endif // MFEM_USE_UMPIRE
|
||||
|
||||
/// Memory space controller class
|
||||
@@ -615,7 +568,7 @@ public:
|
||||
host[static_cast<int>(MT::HOST_64)] = new Aligned64HostMemorySpace();
|
||||
// HOST_DEBUG is delayed, as it reroutes signals
|
||||
host[static_cast<int>(MT::HOST_DEBUG)] = nullptr;
|
||||
host[static_cast<int>(MT::HOST_UMPIRE)] = nullptr;
|
||||
host[static_cast<int>(MT::HOST_UMPIRE)] = new UmpireHostMemorySpace();
|
||||
host[static_cast<int>(MT::MANAGED)] = new UvmHostMemorySpace();
|
||||
|
||||
// Filling the device memory backends, shifting with the device size
|
||||
@@ -625,7 +578,6 @@ public:
|
||||
device[static_cast<int>(MemoryType::DEVICE)-shift] = nullptr;
|
||||
device[static_cast<int>(MT::DEVICE_DEBUG)-shift] = nullptr;
|
||||
device[static_cast<int>(MT::DEVICE_UMPIRE)-shift] = nullptr;
|
||||
device[static_cast<int>(MT::DEVICE_UMPIRE_2)-shift] = nullptr;
|
||||
}
|
||||
|
||||
HostMemorySpace* Host(const MemoryType mt)
|
||||
@@ -658,19 +610,8 @@ public:
|
||||
private:
|
||||
HostMemorySpace* NewHostCtrl(const MemoryType mt)
|
||||
{
|
||||
switch (mt)
|
||||
{
|
||||
case MT::HOST_DEBUG: return new MmuHostMemorySpace();
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
case MT::HOST_UMPIRE:
|
||||
return new UmpireHostMemorySpace(
|
||||
MemoryManager::GetUmpireHostAllocatorName());
|
||||
#else
|
||||
case MT::HOST_UMPIRE: return new NoHostMemorySpace();
|
||||
#endif
|
||||
case MT::HOST_PINNED: return new HostPinnedMemorySpace();
|
||||
default: MFEM_ABORT("Unknown host memory controller!");
|
||||
}
|
||||
if (mt == MT::HOST_DEBUG) { return new MmuHostMemorySpace(); }
|
||||
MFEM_ABORT("Unknown host memory controller!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -678,17 +619,7 @@ private:
|
||||
{
|
||||
switch (mt)
|
||||
{
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
case MT::DEVICE_UMPIRE:
|
||||
return new UmpireDeviceMemorySpace(
|
||||
MemoryManager::GetUmpireDeviceAllocatorName());
|
||||
case MT::DEVICE_UMPIRE_2:
|
||||
return new UmpireDeviceMemorySpace(
|
||||
MemoryManager::GetUmpireDevice2AllocatorName());
|
||||
#else
|
||||
case MT::DEVICE_UMPIRE: return new NoDeviceMemorySpace();
|
||||
case MT::DEVICE_UMPIRE_2: return new NoDeviceMemorySpace();
|
||||
#endif
|
||||
case MT::DEVICE_UMPIRE: return new UmpireDeviceMemorySpace();
|
||||
case MT::DEVICE_DEBUG: return new MmuDeviceMemorySpace();
|
||||
case MT::DEVICE:
|
||||
{
|
||||
@@ -715,50 +646,20 @@ void *MemoryManager::New_(void *h_tmp, size_t bytes, MemoryType mt,
|
||||
unsigned &flags)
|
||||
{
|
||||
MFEM_ASSERT(exists, "Internal error!");
|
||||
if (IsHostMemory(mt))
|
||||
{
|
||||
MFEM_ASSERT(mt != MemoryType::HOST && h_tmp == nullptr,
|
||||
"Internal error!");
|
||||
// d_mt = MemoryType::DEFAULT means d_mt = GetDualMemoryType(h_mt),
|
||||
// evaluated at the time when the device pointer is allocated, see
|
||||
// GetDevicePtr() and GetAliasDevicePtr()
|
||||
const MemoryType d_mt = MemoryType::DEFAULT;
|
||||
// We rely on the next call using lazy dev alloc
|
||||
return New_(h_tmp, bytes, mt, d_mt, Mem::VALID_HOST, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
const MemoryType h_mt = GetDualMemoryType(mt);
|
||||
return New_(h_tmp, bytes, h_mt, mt, Mem::VALID_DEVICE, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void *MemoryManager::New_(void *h_tmp, size_t bytes, MemoryType h_mt,
|
||||
MemoryType d_mt, unsigned valid_flags,
|
||||
unsigned &flags)
|
||||
{
|
||||
MFEM_ASSERT(exists, "Internal error!");
|
||||
MFEM_ASSERT(IsHostMemory(h_mt), "h_mt must be host type");
|
||||
MFEM_ASSERT(IsDeviceMemory(d_mt) || d_mt == h_mt ||
|
||||
d_mt == MemoryType::DEFAULT,
|
||||
"d_mt must be device type, the same is h_mt, or DEFAULT");
|
||||
MFEM_ASSERT((h_mt != MemoryType::HOST || h_tmp != nullptr) &&
|
||||
(h_mt == MemoryType::HOST || h_tmp == nullptr),
|
||||
"Internal error");
|
||||
MFEM_ASSERT((valid_flags & ~(Mem::VALID_HOST | Mem::VALID_DEVICE)) == 0,
|
||||
"Internal error");
|
||||
void *h_ptr;
|
||||
MFEM_ASSERT(mt != MemoryType::HOST, "Internal error!");
|
||||
const bool is_host_mem = IsHostMemory(mt);
|
||||
const MemType dual_mt = GetDualMemoryType_(mt);
|
||||
const MemType h_mt = is_host_mem ? mt : dual_mt;
|
||||
const MemType d_mt = is_host_mem ? dual_mt : mt;
|
||||
MFEM_VERIFY_TYPES(h_mt, d_mt);
|
||||
void *h_ptr = h_tmp;
|
||||
if (h_tmp == nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
|
||||
else { h_ptr = h_tmp; }
|
||||
flags = Mem::REGISTERED | Mem::OWNS_INTERNAL | Mem::OWNS_HOST |
|
||||
Mem::OWNS_DEVICE | valid_flags;
|
||||
// The other New_() method relies on this lazy allocation behavior.
|
||||
mm.Insert(h_ptr, bytes, h_mt, d_mt); // lazy dev alloc
|
||||
// mm.InsertDevice(nullptr, h_ptr, bytes, h_mt, d_mt); // non-lazy dev alloc
|
||||
|
||||
// MFEM_VERIFY_TYPES(h_mt, mt); // done by mm.Insert() above
|
||||
flags = Mem::REGISTERED;
|
||||
flags |= Mem::OWNS_INTERNAL | Mem::OWNS_HOST | Mem::OWNS_DEVICE;
|
||||
flags |= is_host_mem ? Mem::VALID_HOST : Mem::VALID_DEVICE;
|
||||
if (is_host_mem) { mm.Insert(h_ptr, bytes, h_mt, d_mt); }
|
||||
else { mm.InsertDevice(nullptr, h_ptr, bytes, h_mt, d_mt); }
|
||||
CheckHostMemoryType_(h_mt, h_ptr);
|
||||
|
||||
return h_ptr;
|
||||
}
|
||||
|
||||
@@ -770,12 +671,9 @@ void *MemoryManager::Register_(void *ptr, void *h_tmp, size_t bytes,
|
||||
MFEM_ASSERT(exists, "Internal error!");
|
||||
MFEM_ASSERT(!alias, "Cannot register an alias!");
|
||||
const bool is_host_mem = IsHostMemory(mt);
|
||||
const MemType h_mt = is_host_mem ? mt : GetDualMemoryType(mt);
|
||||
const MemType d_mt = is_host_mem ? MemoryType::DEFAULT : mt;
|
||||
// d_mt = MemoryType::DEFAULT means d_mt = GetDualMemoryType(h_mt),
|
||||
// evaluated at the time when the device pointer is allocated, see
|
||||
// GetDevicePtr() and GetAliasDevicePtr()
|
||||
|
||||
const MemType dual_mt = GetDualMemoryType_(mt);
|
||||
const MemType h_mt = is_host_mem ? mt : dual_mt;
|
||||
const MemType d_mt = is_host_mem ? dual_mt : mt;
|
||||
MFEM_VERIFY_TYPES(h_mt, d_mt);
|
||||
|
||||
if (ptr == nullptr && h_tmp == nullptr)
|
||||
@@ -796,42 +694,17 @@ void *MemoryManager::Register_(void *ptr, void *h_tmp, size_t bytes,
|
||||
}
|
||||
else // DEVICE TYPES
|
||||
{
|
||||
MFEM_VERIFY(ptr, "cannot register NULL device pointer");
|
||||
if (h_tmp == nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
|
||||
else { h_ptr = h_tmp; }
|
||||
h_ptr = h_tmp;
|
||||
if (own && h_tmp == nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
|
||||
mm.InsertDevice(ptr, h_ptr, bytes, h_mt, d_mt);
|
||||
flags = own ? flags | Mem::OWNS_DEVICE : flags & ~Mem::OWNS_DEVICE;
|
||||
flags |= (Mem::OWNS_HOST | Mem::VALID_DEVICE);
|
||||
flags = own ? flags | Mem::OWNS_HOST : flags & ~Mem::OWNS_HOST;
|
||||
flags |= Mem::VALID_DEVICE;
|
||||
}
|
||||
CheckHostMemoryType_(h_mt, h_ptr);
|
||||
return h_ptr;
|
||||
}
|
||||
|
||||
void MemoryManager::Register_(void *h_ptr, void *d_ptr, size_t bytes,
|
||||
MemoryType h_mt, MemoryType d_mt,
|
||||
bool own, bool alias, unsigned &flags)
|
||||
{
|
||||
MFEM_CONTRACT_VAR(alias);
|
||||
MFEM_ASSERT(exists, "Internal error!");
|
||||
MFEM_ASSERT(!alias, "Cannot register an alias!");
|
||||
MFEM_VERIFY_TYPES(h_mt, d_mt);
|
||||
|
||||
if (h_ptr == nullptr && d_ptr == nullptr)
|
||||
{
|
||||
MFEM_VERIFY(bytes == 0, "internal error");
|
||||
return;
|
||||
}
|
||||
|
||||
flags |= Mem::REGISTERED | Mem::OWNS_INTERNAL;
|
||||
|
||||
mm.InsertDevice(d_ptr, h_ptr, bytes, h_mt, d_mt);
|
||||
flags = (own ? flags | (Mem::OWNS_HOST | Mem::OWNS_DEVICE) :
|
||||
flags & ~(Mem::OWNS_HOST | Mem::OWNS_DEVICE)) |
|
||||
Mem::VALID_HOST;
|
||||
|
||||
CheckHostMemoryType_(h_mt, h_ptr);
|
||||
}
|
||||
|
||||
void MemoryManager::Alias_(void *base_h_ptr, size_t offset, size_t bytes,
|
||||
unsigned base_flags, unsigned &flags)
|
||||
{
|
||||
@@ -841,34 +714,6 @@ void MemoryManager::Alias_(void *base_h_ptr, size_t offset, size_t bytes,
|
||||
~(Mem::OWNS_HOST | Mem::OWNS_DEVICE);
|
||||
}
|
||||
|
||||
void MemoryManager::SetDeviceMemoryType_(void *h_ptr, unsigned flags,
|
||||
MemoryType d_mt)
|
||||
{
|
||||
MFEM_VERIFY(h_ptr, "cannot set the device memory type: Memory is empty!");
|
||||
if (!(flags & Mem::ALIAS))
|
||||
{
|
||||
auto mem_iter = maps->memories.find(h_ptr);
|
||||
MFEM_VERIFY(mem_iter != maps->memories.end(), "internal error");
|
||||
internal::Memory &mem = mem_iter->second;
|
||||
if (mem.d_mt == d_mt) { return; }
|
||||
MFEM_VERIFY(mem.d_ptr == nullptr, "cannot set the device memory type:"
|
||||
" device memory is allocated!");
|
||||
mem.d_mt = d_mt;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto alias_iter = maps->aliases.find(h_ptr);
|
||||
MFEM_VERIFY(alias_iter != maps->aliases.end(), "internal error");
|
||||
internal::Alias &alias = alias_iter->second;
|
||||
internal::Memory &base_mem = *alias.mem;
|
||||
if (base_mem.d_mt == d_mt) { return; }
|
||||
MFEM_VERIFY(base_mem.d_ptr == nullptr,
|
||||
"cannot set the device memory type:"
|
||||
" alias' base device memory is allocated!");
|
||||
base_mem.d_mt = d_mt;
|
||||
}
|
||||
}
|
||||
|
||||
MemoryType MemoryManager::Delete_(void *h_ptr, MemoryType mt, unsigned flags)
|
||||
{
|
||||
const bool alias = flags & Mem::ALIAS;
|
||||
@@ -902,16 +747,6 @@ MemoryType MemoryManager::Delete_(void *h_ptr, MemoryType mt, unsigned flags)
|
||||
return mt;
|
||||
}
|
||||
|
||||
void MemoryManager::DeleteDevice_(void *h_ptr, unsigned & flags)
|
||||
{
|
||||
const bool owns_device = flags & Mem::OWNS_DEVICE;
|
||||
if (owns_device)
|
||||
{
|
||||
mm.EraseDevice(h_ptr);
|
||||
flags = (flags | Mem::VALID_HOST) & ~Mem::VALID_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
bool MemoryManager::MemoryClassCheck_(MemoryClass mc, void *h_ptr,
|
||||
MemoryType h_mt, size_t bytes,
|
||||
unsigned flags)
|
||||
@@ -925,12 +760,11 @@ bool MemoryManager::MemoryClassCheck_(MemoryClass mc, void *h_ptr,
|
||||
const bool known = mm.IsKnown(h_ptr);
|
||||
const bool alias = mm.IsAlias(h_ptr);
|
||||
const bool check = known || ((flags & Mem::ALIAS) && alias);
|
||||
MFEM_VERIFY(check, "Unknown host pointer: " << h_ptr);
|
||||
MFEM_VERIFY(check,"");
|
||||
const internal::Memory &mem =
|
||||
(flags & Mem::ALIAS) ?
|
||||
*maps->aliases.at(h_ptr).mem : maps->memories.at(h_ptr);
|
||||
MemoryType d_mt = mem.d_mt;
|
||||
if (d_mt == MemoryType::DEFAULT) { d_mt = GetDualMemoryType(h_mt); }
|
||||
const MemoryType &d_mt = mem.d_mt;
|
||||
switch (mc)
|
||||
{
|
||||
case MemoryClass::HOST_32:
|
||||
@@ -949,7 +783,6 @@ bool MemoryManager::MemoryClassCheck_(MemoryClass mc, void *h_ptr,
|
||||
MFEM_VERIFY(d_mt == MemoryType::DEVICE ||
|
||||
d_mt == MemoryType::DEVICE_DEBUG ||
|
||||
d_mt == MemoryType::DEVICE_UMPIRE ||
|
||||
d_mt == MemoryType::DEVICE_UMPIRE_2 ||
|
||||
d_mt == MemoryType::MANAGED,"");
|
||||
return true;
|
||||
}
|
||||
@@ -1031,6 +864,7 @@ void *MemoryManager::Write_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
|
||||
if (flags & Mem::ALIAS)
|
||||
{ return mm.GetAliasDevicePtr(h_ptr, bytes, false); }
|
||||
else { return mm.GetDevicePtr(h_ptr, bytes, false); }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1135,8 +969,11 @@ void MemoryManager::Copy_(void *dst_h_ptr, const void *src_h_ptr,
|
||||
{
|
||||
if (dst_h_ptr != src_d_ptr && bytes != 0)
|
||||
{
|
||||
internal::Memory &dst_h_base = maps->memories.at(dst_h_ptr);
|
||||
internal::Memory &src_d_base = maps->memories.at(src_d_ptr);
|
||||
MemoryType dst_h_mt = dst_h_base.h_mt;
|
||||
MemoryType src_d_mt = src_d_base.d_mt;
|
||||
ctrl->Host(dst_h_mt)->Unprotect(dst_h_ptr, bytes);
|
||||
ctrl->Device(src_d_mt)->DtoH(dst_h_ptr, src_d_ptr, bytes);
|
||||
}
|
||||
}
|
||||
@@ -1261,7 +1098,7 @@ void MemoryManager::Insert(void *h_ptr, size_t bytes,
|
||||
void MemoryManager::InsertDevice(void *d_ptr, void *h_ptr, size_t bytes,
|
||||
MemoryType h_mt, MemoryType d_mt)
|
||||
{
|
||||
// MFEM_VERIFY_TYPES(h_mt, d_mt); // done by Insert() below
|
||||
MFEM_VERIFY_TYPES(h_mt, d_mt);
|
||||
MFEM_ASSERT(h_ptr != NULL, "internal error");
|
||||
Insert(h_ptr, bytes, h_mt, d_mt);
|
||||
internal::Memory &mem = maps->memories.at(h_ptr);
|
||||
@@ -1314,22 +1151,6 @@ void MemoryManager::Erase(void *h_ptr, bool free_dev_ptr)
|
||||
maps->memories.erase(mem_map_iter);
|
||||
}
|
||||
|
||||
void MemoryManager::EraseDevice(void *h_ptr)
|
||||
{
|
||||
if (!h_ptr) { return; }
|
||||
auto mem_map_iter = maps->memories.find(h_ptr);
|
||||
if (mem_map_iter == maps->memories.end()) { mfem_error("Unknown pointer!"); }
|
||||
auto it = maps->aliases.find(h_ptr);
|
||||
if (it != maps->aliases.end())
|
||||
{
|
||||
fprintf(stderr, "count = %lu\n", it->second.counter);
|
||||
mfem_error("cannot delete aliased obj!");
|
||||
}
|
||||
internal::Memory &mem = mem_map_iter->second;
|
||||
if (mem.d_ptr) { ctrl->Device(mem.d_mt)->Dealloc(mem);}
|
||||
mem.d_ptr = nullptr;
|
||||
}
|
||||
|
||||
void MemoryManager::EraseAlias(void *alias_ptr)
|
||||
{
|
||||
if (!alias_ptr) { return; }
|
||||
@@ -1350,21 +1171,16 @@ void *MemoryManager::GetDevicePtr(const void *h_ptr, size_t bytes,
|
||||
}
|
||||
internal::Memory &mem = maps->memories.at(h_ptr);
|
||||
const MemoryType &h_mt = mem.h_mt;
|
||||
MemoryType &d_mt = mem.d_mt;
|
||||
const MemoryType &d_mt = mem.d_mt;
|
||||
MFEM_VERIFY_TYPES(h_mt, d_mt);
|
||||
if (!mem.d_ptr)
|
||||
{
|
||||
if (d_mt == MemoryType::DEFAULT) { d_mt = GetDualMemoryType(h_mt); }
|
||||
ctrl->Device(d_mt)->Alloc(mem);
|
||||
}
|
||||
// Aliases might have done some protections
|
||||
if (!mem.d_ptr) { ctrl->Device(d_mt)->Alloc(mem); }
|
||||
ctrl->Device(d_mt)->Unprotect(mem);
|
||||
if (copy_data)
|
||||
{
|
||||
MFEM_ASSERT(bytes <= mem.bytes, "invalid copy size");
|
||||
ctrl->Device(d_mt)->HtoD(mem.d_ptr, h_ptr, bytes);
|
||||
}
|
||||
ctrl->Host(h_mt)->Protect(mem, bytes);
|
||||
ctrl->Host(h_mt)->Protect(h_ptr, bytes);
|
||||
return mem.d_ptr;
|
||||
}
|
||||
|
||||
@@ -1383,18 +1199,13 @@ void *MemoryManager::GetAliasDevicePtr(const void *alias_ptr, size_t bytes,
|
||||
const size_t offset = alias.offset;
|
||||
internal::Memory &mem = *alias.mem;
|
||||
const MemoryType &h_mt = mem.h_mt;
|
||||
MemoryType &d_mt = mem.d_mt;
|
||||
const MemoryType &d_mt = mem.d_mt;
|
||||
MFEM_VERIFY_TYPES(h_mt, d_mt);
|
||||
if (!mem.d_ptr)
|
||||
{
|
||||
if (d_mt == MemoryType::DEFAULT) { d_mt = GetDualMemoryType(h_mt); }
|
||||
ctrl->Device(d_mt)->Alloc(mem);
|
||||
}
|
||||
if (!mem.d_ptr) { ctrl->Device(d_mt)->Alloc(mem); }
|
||||
void *alias_h_ptr = static_cast<char*>(mem.h_ptr) + offset;
|
||||
void *alias_d_ptr = static_cast<char*>(mem.d_ptr) + offset;
|
||||
MFEM_ASSERT(alias_h_ptr == alias_ptr, "internal error");
|
||||
MFEM_ASSERT(bytes <= alias.bytes, "internal error");
|
||||
mem.d_rw = false;
|
||||
ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes);
|
||||
ctrl->Host(h_mt)->AliasUnprotect(alias_ptr, bytes);
|
||||
if (copy) { ctrl->Device(d_mt)->HtoD(alias_d_ptr, alias_h_ptr, bytes); }
|
||||
@@ -1410,8 +1221,8 @@ void *MemoryManager::GetHostPtr(const void *ptr, size_t bytes, bool copy)
|
||||
const MemoryType &h_mt = mem.h_mt;
|
||||
const MemoryType &d_mt = mem.d_mt;
|
||||
MFEM_VERIFY_TYPES(h_mt, d_mt);
|
||||
ctrl->Host(h_mt)->Unprotect(mem.h_ptr, bytes);
|
||||
// Aliases might have done some protections
|
||||
ctrl->Host(h_mt)->Unprotect(mem, bytes);
|
||||
if (mem.d_ptr) { ctrl->Device(d_mt)->Unprotect(mem); }
|
||||
if (copy && mem.d_ptr) { ctrl->Device(d_mt)->DtoH(mem.h_ptr, mem.d_ptr, bytes); }
|
||||
if (mem.d_ptr) { ctrl->Device(d_mt)->Protect(mem); }
|
||||
@@ -1429,7 +1240,6 @@ void *MemoryManager::GetAliasHostPtr(const void *ptr, size_t bytes,
|
||||
void *alias_h_ptr = static_cast<char*>(mem->h_ptr) + alias.offset;
|
||||
void *alias_d_ptr = static_cast<char*>(mem->d_ptr) + alias.offset;
|
||||
MFEM_ASSERT(alias_h_ptr == ptr, "internal error");
|
||||
mem->h_rw = false;
|
||||
ctrl->Host(h_mt)->AliasUnprotect(alias_h_ptr, bytes);
|
||||
if (mem->d_ptr) { ctrl->Device(d_mt)->AliasUnprotect(alias_d_ptr, bytes); }
|
||||
if (copy_data && mem->d_ptr)
|
||||
@@ -1451,48 +1261,23 @@ MemoryManager::MemoryManager() { Init(); }
|
||||
|
||||
MemoryManager::~MemoryManager() { if (exists) { Destroy(); } }
|
||||
|
||||
void MemoryManager::SetDualMemoryType(MemoryType mt, MemoryType dual_mt)
|
||||
{
|
||||
MFEM_VERIFY(!configured, "changing the dual MemoryTypes is not allowed after"
|
||||
" MemoryManager configuration!");
|
||||
UpdateDualMemoryType(mt, dual_mt);
|
||||
}
|
||||
|
||||
void MemoryManager::UpdateDualMemoryType(MemoryType mt, MemoryType dual_mt)
|
||||
{
|
||||
MFEM_VERIFY((int)mt < MemoryTypeSize,
|
||||
"invalid MemoryType, mt = " << (int)mt);
|
||||
MFEM_VERIFY((int)dual_mt < MemoryTypeSize,
|
||||
"invalid dual MemoryType, dual_mt = " << (int)dual_mt);
|
||||
|
||||
if ((IsHostMemory(mt) && IsDeviceMemory(dual_mt)) ||
|
||||
(IsDeviceMemory(mt) && IsHostMemory(dual_mt)))
|
||||
{
|
||||
dual_map[(int)mt] = dual_mt;
|
||||
}
|
||||
else
|
||||
{
|
||||
// mt + dual_mt is not a pair of host + device types: this is only allowed
|
||||
// when mt == dual_mt and mt is a host type; in this case we do not
|
||||
// actually update the dual
|
||||
MFEM_VERIFY(mt == dual_mt && IsHostMemory(mt),
|
||||
"invalid (mt, dual_mt) pair: ("
|
||||
<< MemoryTypeName[(int)mt] << ", "
|
||||
<< MemoryTypeName[(int)dual_mt] << ')');
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::Configure(const MemoryType host_mt,
|
||||
const MemoryType device_mt)
|
||||
{
|
||||
MemoryManager::UpdateDualMemoryType(host_mt, device_mt);
|
||||
MemoryManager::UpdateDualMemoryType(device_mt, host_mt);
|
||||
Init();
|
||||
host_mem_type = host_mt;
|
||||
device_mem_type = device_mt;
|
||||
configured = true;
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
void MemoryManager::SetUmpireAllocatorNames(const char *h_name,
|
||||
const char *d_name)
|
||||
{
|
||||
h_umpire_name = h_name;
|
||||
d_umpire_name = d_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
void MemoryManager::Destroy()
|
||||
{
|
||||
MFEM_VERIFY(exists, "MemoryManager has already been destroyed!");
|
||||
@@ -1508,7 +1293,6 @@ void MemoryManager::Destroy()
|
||||
host_mem_type = MemoryType::HOST;
|
||||
device_mem_type = MemoryType::HOST;
|
||||
exists = false;
|
||||
configured = false;
|
||||
}
|
||||
|
||||
void MemoryManager::RegisterCheck(void *ptr)
|
||||
@@ -1595,36 +1379,18 @@ void MemoryManager::CheckHostMemoryType_(MemoryType h_mt, void *h_ptr)
|
||||
MemoryManager mm;
|
||||
|
||||
bool MemoryManager::exists = false;
|
||||
bool MemoryManager::configured = false;
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
const char* MemoryManager::h_umpire_name = "HOST";
|
||||
const char* MemoryManager::d_umpire_name = "DEVICE";
|
||||
#endif
|
||||
|
||||
MemoryType MemoryManager::host_mem_type = MemoryType::HOST;
|
||||
MemoryType MemoryManager::device_mem_type = MemoryType::HOST;
|
||||
|
||||
MemoryType MemoryManager::dual_map[MemoryTypeSize] =
|
||||
{
|
||||
/* HOST */ MemoryType::DEVICE,
|
||||
/* HOST_32 */ MemoryType::DEVICE,
|
||||
/* HOST_64 */ MemoryType::DEVICE,
|
||||
/* HOST_DEBUG */ MemoryType::DEVICE_DEBUG,
|
||||
/* HOST_UMPIRE */ MemoryType::DEVICE_UMPIRE,
|
||||
/* HOST_PINNED */ MemoryType::DEVICE,
|
||||
/* MANAGED */ MemoryType::MANAGED,
|
||||
/* DEVICE */ MemoryType::HOST,
|
||||
/* DEVICE_DEBUG */ MemoryType::HOST_DEBUG,
|
||||
/* DEVICE_UMPIRE */ MemoryType::HOST_UMPIRE,
|
||||
/* DEVICE_UMPIRE_2 */ MemoryType::HOST_UMPIRE
|
||||
};
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
const char * MemoryManager::h_umpire_name = "MFEM_HOST";
|
||||
const char * MemoryManager::d_umpire_name = "MFEM_DEVICE";
|
||||
const char * MemoryManager::d_umpire_2_name = "MFEM_DEVICE_2";
|
||||
#endif
|
||||
|
||||
|
||||
const char *MemoryTypeName[MemoryTypeSize] =
|
||||
{
|
||||
"host-std", "host-32", "host-64", "host-debug", "host-umpire", "host-pinned",
|
||||
"host-std", "host-32", "host-64", "host-debug", "host-umpire",
|
||||
#if defined(MFEM_USE_CUDA)
|
||||
"cuda-uvm",
|
||||
"cuda",
|
||||
@@ -1637,14 +1403,11 @@ const char *MemoryTypeName[MemoryTypeSize] =
|
||||
#endif
|
||||
"device-debug",
|
||||
#if defined(MFEM_USE_CUDA)
|
||||
"cuda-umpire",
|
||||
"cuda-umpire-2",
|
||||
"cuda-umpire"
|
||||
#elif defined(MFEM_USE_HIP)
|
||||
"hip-umpire",
|
||||
"hip-umpire-2",
|
||||
"hip-umpire"
|
||||
#else
|
||||
"device-umpire",
|
||||
"device-umpire-2",
|
||||
"device-umpire"
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
+37
-199
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
@@ -31,26 +31,14 @@ enum class MemoryType
|
||||
HOST_32, ///< Host memory; aligned at 32 bytes
|
||||
HOST_64, ///< Host memory; aligned at 64 bytes
|
||||
HOST_DEBUG, ///< Host memory; allocated from a "host-debug" pool
|
||||
HOST_UMPIRE, /**< Host memory; using an Umpire allocator which can be set
|
||||
with MemoryManager::SetUmpireHostAllocatorName */
|
||||
HOST_PINNED, ///< Host memory: pinned (page-locked)
|
||||
HOST_UMPIRE, ///< Host memory; using Umpire
|
||||
MANAGED, /**< Managed memory; using CUDA or HIP *MallocManaged
|
||||
and *Free */
|
||||
DEVICE, ///< Device memory; using CUDA or HIP *Malloc and *Free
|
||||
DEVICE_DEBUG, /**< Pseudo-device memory; allocated on host from a
|
||||
"device-debug" pool */
|
||||
DEVICE_UMPIRE, /**< Device memory; using an Umpire allocator which can be
|
||||
set with MemoryManager::SetUmpireDeviceAllocatorName */
|
||||
DEVICE_UMPIRE_2, /**< Device memory; using a second Umpire allocator settable
|
||||
with MemoryManager::SetUmpireDevice2AllocatorName */
|
||||
SIZE, ///< Number of host and device memory types
|
||||
|
||||
PRESERVE, /**< Pseudo-MemoryType used as default value for MemoryType
|
||||
parameters to request preservation of existing
|
||||
MemoryType, e.g. in copy constructors. */
|
||||
DEFAULT /**< Pseudo-MemoryType used as default value for MemoryType
|
||||
parameters to request the use of the default host or
|
||||
device MemoryType. */
|
||||
DEVICE_UMPIRE, ///< Device memory; using Umpire
|
||||
SIZE ///< Number of host and device memory types
|
||||
};
|
||||
|
||||
/// Static casts to 'int' and sizes of some useful memory types.
|
||||
@@ -70,22 +58,16 @@ extern const char *MemoryTypeName[MemoryTypeSize];
|
||||
enum class MemoryClass
|
||||
{
|
||||
HOST, /**< Memory types: { HOST, HOST_32, HOST_64, HOST_DEBUG,
|
||||
HOST_UMPIRE, HOST_PINNED, MANAGED } */
|
||||
HOST_UMPIRE, MANAGED } */
|
||||
HOST_32, ///< Memory types: { HOST_32, HOST_64, HOST_DEBUG }
|
||||
HOST_64, ///< Memory types: { HOST_64, HOST_DEBUG }
|
||||
DEVICE, /**< Memory types: { DEVICE, DEVICE_DEBUG, DEVICE_UMPIRE,
|
||||
DEVICE_UMPIRE_2, MANAGED } */
|
||||
DEVICE, ///< Memory types: { DEVICE, DEVICE_DEBUG, DEVICE_UMPIRE, MANAGED }
|
||||
MANAGED ///< Memory types: { MANAGED }
|
||||
};
|
||||
|
||||
/// Return true if the given memory type is in MemoryClass::HOST.
|
||||
inline bool IsHostMemory(MemoryType mt) { return mt <= MemoryType::MANAGED; }
|
||||
|
||||
/// Return true if the given memory type is in MemoryClass::DEVICE
|
||||
inline bool IsDeviceMemory(MemoryType mt)
|
||||
{
|
||||
return mt >= MemoryType::MANAGED && mt < MemoryType::SIZE;
|
||||
}
|
||||
inline bool IsDeviceMemory(MemoryType mt) { return mt >= MemoryType::MANAGED; }
|
||||
|
||||
/// Return a suitable MemoryType for a given MemoryClass.
|
||||
MemoryType GetMemoryType(MemoryClass mc);
|
||||
@@ -195,12 +177,6 @@ public:
|
||||
MemoryType is still set as valid. */
|
||||
Memory(int size, MemoryType mt) { New(size, mt); }
|
||||
|
||||
/** @brief Allocate memory for @a size entries with the given host MemoryType
|
||||
@a h_mt and device MemoryType @a d_mt. */
|
||||
/** The newly allocated memory is not initialized. The host pointer is set as
|
||||
valid. */
|
||||
Memory(int size, MemoryType h_mt, MemoryType d_mt) { New(size, h_mt, d_mt); }
|
||||
|
||||
/** @brief Wrap an externally allocated host pointer, @a ptr with the current
|
||||
host memory type returned by MemoryManager::GetHostMemoryType(). */
|
||||
/** The parameter @a own determines whether @a ptr will be deleted when the
|
||||
@@ -285,24 +261,9 @@ public:
|
||||
/** The newly allocated memory is not initialized, however the given
|
||||
MemoryType is still set as valid.
|
||||
|
||||
When @a mt is a host type, the device MemoryType will be set later, if
|
||||
requested, using the dual type of @a mt, see
|
||||
MemoryManager::GetDualMemoryType().
|
||||
|
||||
When @a mt is a device type, the host MemoryType will be set immediately
|
||||
to be the dual of @a mt, see MemoryManager::GetDualMemoryType().
|
||||
|
||||
@note The current memory is NOT deleted by this method. */
|
||||
inline void New(int size, MemoryType mt);
|
||||
|
||||
/** @brief Allocate memory for @a size entries with the given host MemoryType
|
||||
@a h_mt and device MemoryType @a d_mt. */
|
||||
/** The newly allocated memory is not initialized. The host pointer is set as
|
||||
valid.
|
||||
|
||||
@note The current memory is NOT deleted by this method. */
|
||||
inline void New(int size, MemoryType h_mt, MemoryType d_mt);
|
||||
|
||||
/** @brief Wrap an externally allocated host pointer, @a ptr with the current
|
||||
host memory type returned by MemoryManager::GetHostMemoryType(). */
|
||||
/** The parameter @a own determines whether @a ptr will be deleted when the
|
||||
@@ -323,18 +284,21 @@ public:
|
||||
@note The current memory is NOT deleted by this method. */
|
||||
inline void Wrap(T *ptr, int size, MemoryType mt, bool own);
|
||||
|
||||
/** Wrap an externally pair of allocated pointers, @a h_ptr and @a d_ptr,
|
||||
/** Wrap an externally pair of allocated pointers, @a h_ptr and @ d_ptr,
|
||||
of the given host MemoryType @a h_mt. */
|
||||
/** The new memory object will have the device MemoryType set as valid.
|
||||
|
||||
The given @a h_ptr and @a d_ptr must be allocated appropriately for the
|
||||
given host MemoryType and its dual device MemoryType as defined by
|
||||
MemoryManager::GetDualMemoryType().
|
||||
given host MemoryType and its associated device MemoryType:
|
||||
- MANAGED => MANAGED,
|
||||
- HOST_DEBUG => DEVICE_DEBUG,
|
||||
- HOST_UMPIRE => DEVICE_UMPIRE,
|
||||
- HOST, HOST_32, HOST_64 => DEVICE.
|
||||
|
||||
The parameter @a own determines whether both @a h_ptr and @a d_ptr will
|
||||
be deleted when the method Delete() is called.
|
||||
|
||||
@note Ownership can also be controlled by using the following methods:
|
||||
@note Ownership can also be controled by using the folowing methods:
|
||||
- ClearOwnerFlags,
|
||||
- SetHostPtrOwner,
|
||||
- SetDevicePtrOwner.
|
||||
@@ -348,29 +312,10 @@ public:
|
||||
@note The current memory is NOT deleted by this method. */
|
||||
inline void MakeAlias(const Memory &base, int offset, int size);
|
||||
|
||||
/// Set the device MemoryType to be used by the Memory object.
|
||||
/** If the specified @a d_mt is not a device MemoryType, i.e. not one of the
|
||||
types in MemoryClass::DEVICE, then this method will return immediately.
|
||||
|
||||
If the device MemoryType has been previously set to a different type and
|
||||
the actual device memory has been allocated, this method will trigger an
|
||||
error. This method will not perform the actual device memory allocation,
|
||||
however, the allocation may already exist if the MemoryType is the same
|
||||
as the current one.
|
||||
|
||||
If the Memory is an alias Memory, the device MemoryType of its base will
|
||||
be updated as described above. */
|
||||
inline void SetDeviceMemoryType(MemoryType d_mt);
|
||||
|
||||
/** @brief Delete the owned pointers. The Memory is not reset by this method,
|
||||
i.e. it will, generally, not be Empty() after this call. */
|
||||
inline void Delete();
|
||||
|
||||
/** @brief Delete the device pointer, if owned. If @a copy_to_host is true
|
||||
and the data is valid only on device, move it to host before deleting.
|
||||
Invalidates the device memory. */
|
||||
inline void DeleteDevice(bool copy_to_host = true);
|
||||
|
||||
/// Array subscript operator for host memory.
|
||||
inline T &operator[](int idx);
|
||||
|
||||
@@ -523,12 +468,6 @@ private:
|
||||
static inline T *New(std::size_t size) { return new T[size]; }
|
||||
};
|
||||
#endif
|
||||
|
||||
// Shortcut for Alloc<new_align_bytes>::New(size)
|
||||
static inline T *NewHOST(std::size_t size)
|
||||
{
|
||||
return Alloc<new_align_bytes>::New(size);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -556,22 +495,10 @@ private:
|
||||
/// Return true if the global memory manager instance exists.
|
||||
static bool Exists() { return exists; }
|
||||
|
||||
/// Array defining the dual MemoryType for each MemoryType
|
||||
/** The dual of a host MemoryType is a device MemoryType and vice versa: the
|
||||
dual of a device MemoryType is a host MemoryType. */
|
||||
static MemoryType dual_map[MemoryTypeSize];
|
||||
|
||||
/// Update the dual memory type of @a mt to be @a dual_mt.
|
||||
static void UpdateDualMemoryType(MemoryType mt, MemoryType dual_mt);
|
||||
|
||||
/// True if Configure() was called.
|
||||
static bool configured;
|
||||
|
||||
/// Host and device allocator names for Umpire.
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
static const char * h_umpire_name;
|
||||
static const char * d_umpire_name;
|
||||
static const char * d_umpire_2_name;
|
||||
static const char *h_umpire_name;
|
||||
static const char *d_umpire_name;
|
||||
#endif
|
||||
|
||||
private: // Static methods used by the Memory<T> class
|
||||
@@ -581,37 +508,26 @@ private: // Static methods used by the Memory<T> class
|
||||
/// memory type, e.g. CUDA (mt will not be HOST).
|
||||
static void *New_(void *h_tmp, size_t bytes, MemoryType mt, unsigned &flags);
|
||||
|
||||
static void *New_(void *h_tmp, size_t bytes, MemoryType h_mt,
|
||||
MemoryType d_mt, unsigned valid_flags, unsigned &flags);
|
||||
|
||||
/// Register an external pointer of the given MemoryType.
|
||||
/// Return the host pointer.
|
||||
static void *Register_(void *ptr, void *h_ptr, size_t bytes, MemoryType mt,
|
||||
bool own, bool alias, unsigned &flags);
|
||||
|
||||
/// Register a pair of external host and device pointers
|
||||
static void Register_(void *h_ptr, void *d_ptr, size_t bytes,
|
||||
MemoryType h_mt, MemoryType d_mt,
|
||||
bool own, bool alias, unsigned &flags);
|
||||
|
||||
/// Register an alias. Note: base_h_ptr may be an alias.
|
||||
static void Alias_(void *base_h_ptr, size_t offset, size_t bytes,
|
||||
unsigned base_flags, unsigned &flags);
|
||||
|
||||
static void SetDeviceMemoryType_(void *h_ptr, unsigned flags,
|
||||
MemoryType d_mt);
|
||||
|
||||
/// Un-register and free memory identified by its host pointer. Returns the
|
||||
/// memory type of the host pointer.
|
||||
static MemoryType Delete_(void *h_ptr, MemoryType mt, unsigned flags);
|
||||
|
||||
/// Free device memory identified by its host pointer
|
||||
static void DeleteDevice_(void *h_ptr, unsigned & flags);
|
||||
|
||||
/// Check if the memory types given the memory class are valid
|
||||
static bool MemoryClassCheck_(MemoryClass mc, void *h_ptr,
|
||||
MemoryType h_mt, size_t bytes, unsigned flags);
|
||||
|
||||
/// Return the dual memory type of the given one.
|
||||
static MemoryType GetDualMemoryType_(MemoryType mt);
|
||||
|
||||
/// Return a pointer to the memory identified by the host pointer h_ptr for
|
||||
/// access with the given MemoryClass.
|
||||
static void *ReadWrite_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
|
||||
@@ -679,9 +595,6 @@ private:
|
||||
/// Erase an address from the memory map, as well as all its aliases
|
||||
void Erase(void *h_ptr, bool free_dev_ptr = true);
|
||||
|
||||
/// Erase device memory for a given host address
|
||||
void EraseDevice(void *h_ptr);
|
||||
|
||||
/// Erase an alias from the aliases map
|
||||
void EraseAlias(void *alias_ptr);
|
||||
|
||||
@@ -708,59 +621,15 @@ public:
|
||||
/// Initialize the memory manager.
|
||||
void Init();
|
||||
|
||||
/// Return the dual MemoryType of the given one, @a mt.
|
||||
/** The default dual memory types are:
|
||||
|
||||
memory type | dual type
|
||||
--------------- | ---------
|
||||
HOST | DEVICE
|
||||
HOST_32 | DEVICE
|
||||
HOST_64 | DEVICE
|
||||
HOST_DEBUG | DEVICE_DEBUG
|
||||
HOST_UMPIRE | DEVICE_UMPIRE
|
||||
HOST_PINNED | DEVICE
|
||||
MANAGED | MANAGED
|
||||
DEVICE | HOST
|
||||
DEVICE_DEBUG | HOST_DEBUG
|
||||
DEVICE_UMPIRE | HOST_UMPIRE
|
||||
DEVICE_UMPIRE_2 | HOST_UMPIRE
|
||||
|
||||
The dual types can be modified before device configuration using the
|
||||
method SetDualMemoryType() or by calling Device::SetMemoryTypes(). */
|
||||
static inline MemoryType GetDualMemoryType(MemoryType mt)
|
||||
{ return dual_map[(int)mt]; }
|
||||
|
||||
/// Set the dual memory type of @a mt to be @a dual_mt.
|
||||
/** This method can only be called before configuration, i.e. before calling
|
||||
Configure(), which is typically done during Device construction.
|
||||
|
||||
One of the types must be a host MemoryType and the other must be a device
|
||||
MemoryType or both types must be the same host memory type. The latter
|
||||
case is only allowed for convenience in setting up pure host execution,
|
||||
so the actual dual is not updated. */
|
||||
static void SetDualMemoryType(MemoryType mt, MemoryType dual_mt);
|
||||
|
||||
/** @brief Configure the Memory manager with given default host and device
|
||||
types. This method will be called when configuring a device.
|
||||
|
||||
The host and device MemoryType%s, @a h_mt and @a d_mt, are set to be dual
|
||||
to each other. */
|
||||
/// Configure the Memory manager with given default host and device types
|
||||
/// This method will be called when configuring a device.
|
||||
void Configure(const MemoryType h_mt, const MemoryType d_mt);
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
/// Set the host Umpire allocator name used with MemoryType::HOST_UMPIRE
|
||||
static void SetUmpireHostAllocatorName(const char * h_name) { h_umpire_name = h_name; }
|
||||
/// Set the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE
|
||||
static void SetUmpireDeviceAllocatorName(const char * d_name) { d_umpire_name = d_name; }
|
||||
/// Set the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE_2
|
||||
static void SetUmpireDevice2AllocatorName(const char * d_name) { d_umpire_2_name = d_name; }
|
||||
|
||||
/// Get the host Umpire allocator name used with MemoryType::HOST_UMPIRE
|
||||
static const char * GetUmpireHostAllocatorName() { return h_umpire_name; }
|
||||
/// Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE
|
||||
static const char * GetUmpireDeviceAllocatorName() { return d_umpire_name; }
|
||||
/// Get the device Umpire allocator name used with MemoryType::DEVICE_UMPIRE_2
|
||||
static const char * GetUmpireDevice2AllocatorName() { return d_umpire_2_name; }
|
||||
/// Set the host and device UMpire allocator names
|
||||
void SetUmpireAllocatorNames(const char *h_name, const char *d_name);
|
||||
const char *GetUmpireAllocatorHostName() { return h_umpire_name; }
|
||||
const char *GetUmpireAllocatorDeviceName() { return d_umpire_name; }
|
||||
#endif
|
||||
|
||||
/// Free all the device memories
|
||||
@@ -794,7 +663,7 @@ template <typename T>
|
||||
inline void Memory<T>::Reset()
|
||||
{
|
||||
h_ptr = NULL;
|
||||
h_mt = MemoryManager::GetHostMemoryType();
|
||||
h_mt = MemoryManager::host_mem_type;
|
||||
capacity = 0;
|
||||
flags = 0;
|
||||
}
|
||||
@@ -813,8 +682,8 @@ inline void Memory<T>::New(int size)
|
||||
{
|
||||
capacity = size;
|
||||
flags = OWNS_HOST | VALID_HOST;
|
||||
h_mt = MemoryManager::GetHostMemoryType();
|
||||
h_ptr = (h_mt == MemoryType::HOST) ? NewHOST(size) :
|
||||
h_mt = MemoryManager::host_mem_type;
|
||||
h_ptr = (h_mt == MemoryType::HOST) ? Alloc<new_align_bytes>::New(size) :
|
||||
(T*)MemoryManager::New_(nullptr, size*sizeof(T), h_mt, flags);
|
||||
}
|
||||
|
||||
@@ -825,21 +694,12 @@ inline void Memory<T>::New(int size, MemoryType mt)
|
||||
const size_t bytes = size*sizeof(T);
|
||||
const bool mt_host = mt == MemoryType::HOST;
|
||||
if (mt_host) { flags = OWNS_HOST | VALID_HOST; }
|
||||
h_mt = IsHostMemory(mt) ? mt : MemoryManager::GetDualMemoryType(mt);
|
||||
T *h_tmp = (h_mt == MemoryType::HOST) ? NewHOST(size) : nullptr;
|
||||
h_mt = IsHostMemory(mt) ? mt : MemoryManager::GetDualMemoryType_(mt);
|
||||
T *h_tmp = (h_mt == MemoryType::HOST) ?
|
||||
Alloc<new_align_bytes>::New(size) : nullptr;
|
||||
h_ptr = (mt_host) ? h_tmp : (T*)MemoryManager::New_(h_tmp, bytes, mt, flags);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Memory<T>::New(int size, MemoryType h_mt, MemoryType d_mt)
|
||||
{
|
||||
capacity = size;
|
||||
const size_t bytes = size*sizeof(T);
|
||||
this->h_mt = h_mt;
|
||||
T *h_tmp = (h_mt == MemoryType::HOST) ? NewHOST(size) : nullptr;
|
||||
h_ptr = (T*)MemoryManager::New_(h_tmp, bytes, h_mt, d_mt, VALID_HOST, flags);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Memory<T>::Wrap(T *ptr, int size, bool own)
|
||||
{
|
||||
@@ -847,7 +707,7 @@ inline void Memory<T>::Wrap(T *ptr, int size, bool own)
|
||||
capacity = size;
|
||||
const size_t bytes = size*sizeof(T);
|
||||
flags = (own ? OWNS_HOST : 0) | VALID_HOST;
|
||||
h_mt = MemoryManager::GetHostMemoryType();
|
||||
h_mt = MemoryManager::host_mem_type;
|
||||
#ifdef MFEM_DEBUG
|
||||
if (own && MemoryManager::Exists())
|
||||
{ MFEM_VERIFY(h_mt == MemoryManager::GetHostMemoryType_(h_ptr),""); }
|
||||
@@ -866,14 +726,14 @@ inline void Memory<T>::Wrap(T *ptr, int size, MemoryType mt, bool own)
|
||||
h_ptr = ptr;
|
||||
if (mt == MemoryType::HOST || !own)
|
||||
{
|
||||
// Skip registration
|
||||
// Skip restration
|
||||
flags = (own ? OWNS_HOST : 0) | VALID_HOST;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
h_mt = MemoryManager::GetDualMemoryType(mt);
|
||||
h_mt = MemoryManager::GetDualMemoryType_(mt);
|
||||
h_ptr = (h_mt == MemoryType::HOST) ? new T[size] : nullptr;
|
||||
}
|
||||
flags = 0;
|
||||
@@ -890,8 +750,8 @@ inline void Memory<T>::Wrap(T *ptr, T *d_ptr, int size, MemoryType mt, bool own)
|
||||
capacity = size;
|
||||
MFEM_ASSERT(IsHostMemory(h_mt),"");
|
||||
const size_t bytes = size*sizeof(T);
|
||||
const MemoryType d_mt = MemoryManager::GetDualMemoryType(h_mt);
|
||||
MemoryManager::Register_(h_ptr, d_ptr, bytes, h_mt, d_mt, own, false, flags);
|
||||
const MemoryType d_mt = MemoryManager::GetDualMemoryType_(h_mt);
|
||||
MemoryManager::Register_(d_ptr, h_ptr, bytes, d_mt, own, false, flags);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -910,18 +770,6 @@ inline void Memory<T>::MakeAlias(const Memory &base, int offset, int size)
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Memory<T>::SetDeviceMemoryType(MemoryType d_mt)
|
||||
{
|
||||
if (!IsDeviceMemory(d_mt)) { return; }
|
||||
if (!(flags & REGISTERED))
|
||||
{
|
||||
MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
|
||||
flags & OWNS_HOST, flags & ALIAS, flags);
|
||||
}
|
||||
MemoryManager::SetDeviceMemoryType_(h_ptr, flags, d_mt);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Memory<T>::Delete()
|
||||
{
|
||||
@@ -936,16 +784,6 @@ inline void Memory<T>::Delete()
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Memory<T>::DeleteDevice(bool copy_to_host)
|
||||
{
|
||||
if (flags & REGISTERED)
|
||||
{
|
||||
if (copy_to_host) { Read(MemoryClass::HOST, capacity); }
|
||||
MemoryManager::DeleteDevice_((void*)h_ptr, flags);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T &Memory<T>::operator[](int idx)
|
||||
{
|
||||
@@ -1073,7 +911,7 @@ inline void Memory<T>::CopyFrom(const Memory &src, int size)
|
||||
{
|
||||
if (h_ptr != src.h_ptr && size != 0)
|
||||
{
|
||||
MFEM_ASSERT(h_ptr + size <= src.h_ptr || src.h_ptr + size <= h_ptr,
|
||||
MFEM_ASSERT(h_ptr + size <= src || src + size <= h_ptr,
|
||||
"data overlaps!");
|
||||
std::memcpy(h_ptr, src, size*sizeof(T));
|
||||
}
|
||||
|
||||
+11
-112
@@ -587,7 +587,11 @@ DenseMatrix &DenseMatrix::operator=(const DenseMatrix &m)
|
||||
|
||||
DenseMatrix &DenseMatrix::operator+=(const double *m)
|
||||
{
|
||||
kernels::Add(Height(), Width(), m, (double*)data);
|
||||
const int hw = Height()*Width();
|
||||
for (int i = 0; i < hw; i++)
|
||||
{
|
||||
data[i] += m[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1930,7 +1934,12 @@ void Add(const DenseMatrix &A, const DenseMatrix &B,
|
||||
void Add(double alpha, const double *A,
|
||||
double beta, const double *B, DenseMatrix &C)
|
||||
{
|
||||
kernels::Add(C.Height(), C.Width(), alpha, A, beta, B, C.Data());
|
||||
const int m = C.Height()*C.Width();
|
||||
double *C_data = C.GetData();
|
||||
for (int i = 0; i < m; i++)
|
||||
{
|
||||
C_data[i] = alpha*A[i] + beta*B[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Add(double alpha, const DenseMatrix &A,
|
||||
@@ -3586,114 +3595,4 @@ void BatchLUSolve(const DenseTensor &Mlu, const Array<int> &P, Vector &X)
|
||||
|
||||
}
|
||||
|
||||
void BatchLUFactor(Vector &Minv,const int m,const int NE, Array<int> &P)
|
||||
{
|
||||
P.SetSize(m*NE);
|
||||
auto data_all = mfem::Reshape(Minv.ReadWrite(), m, m, NE);
|
||||
auto piv_all = mfem::Reshape(P.Write(), m, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
|
||||
double *data = &data_all(0,0,e);
|
||||
int *ipiv = &piv_all(0,e);
|
||||
for (int i = 0; i < m; i++)
|
||||
{
|
||||
|
||||
// pivoting
|
||||
{
|
||||
int piv = i;
|
||||
double a = fabs(data[piv+i*m]);
|
||||
for (int j = i+1; j < m; j++)
|
||||
{
|
||||
const double b = fabs(data[j+i*m]);
|
||||
if (b > a)
|
||||
{
|
||||
a = b;
|
||||
piv = j;
|
||||
}
|
||||
}
|
||||
ipiv[i] = piv;
|
||||
if (piv != i)
|
||||
{
|
||||
// swap rows i and piv in both L and U parts
|
||||
for (int j = 0; j < m; j++)
|
||||
{
|
||||
mfem::kernels::internal::Swap<double>(data[i+j*m], data[piv+j*m]);
|
||||
}
|
||||
}
|
||||
}//pivot end
|
||||
|
||||
//Q: How to check for errors?
|
||||
//if (abs(data[i + i*m]) <= TOL)
|
||||
//{
|
||||
//return false; // failed
|
||||
//}
|
||||
|
||||
const double a_ii_inv = 1.0 / data[i+i*m];
|
||||
for (int j = i+1; j < m; j++)
|
||||
{
|
||||
data[j+i*m] *= a_ii_inv;
|
||||
}
|
||||
|
||||
for (int k = i+1; k < m; k++)
|
||||
{
|
||||
const double a_ik = data[i+k*m];
|
||||
for (int j = i+1; j < m; j++)
|
||||
{
|
||||
data[j+k*m] -= a_ik * data[j+i*m];
|
||||
}
|
||||
}
|
||||
|
||||
}//m loop
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void BatchLUSolve(Vector &Minv, int m, int NE,
|
||||
Array<int> &P, Vector &X)
|
||||
{
|
||||
|
||||
auto data_all = mfem::Reshape(Minv.Read(), m, m, NE);
|
||||
auto piv_all = mfem::Reshape(P.Read(), m, NE);
|
||||
auto x_all = mfem::Reshape(X.ReadWrite(), m, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
|
||||
const double *data = &data_all(0,0,e);
|
||||
const int *ipiv = &piv_all(0,e);
|
||||
double *x = &x_all(0,e);
|
||||
|
||||
// X <- P X
|
||||
for (int i = 0; i < m; i++)
|
||||
{
|
||||
mfem::kernels::internal::Swap<double>(x[i], x[ipiv[i]]);
|
||||
}
|
||||
|
||||
// X <- L^{-1} X
|
||||
for (int j = 0; j < m; j++)
|
||||
{
|
||||
const double x_j = x[j];
|
||||
for (int i = j+1; i < m; i++)
|
||||
{
|
||||
x[i] -= data[i+j*m] * x_j;
|
||||
}
|
||||
}
|
||||
|
||||
// X <- U^{-1} X
|
||||
for (int j = m-1; j >= 0; j--)
|
||||
{
|
||||
const double x_j = ( x[j] /= data[j+j*m] );
|
||||
for (int i = 0; i < j; i++)
|
||||
{
|
||||
x[i] -= data[i+j*m] * x_j;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+2
-13
@@ -746,13 +746,6 @@ public:
|
||||
tdata.New(i*j*k);
|
||||
}
|
||||
|
||||
DenseTensor(int i, int j, int k, MemoryType mt)
|
||||
: Mk(NULL, i, j)
|
||||
{
|
||||
nk = k;
|
||||
tdata.New(i*j*k, mt);
|
||||
}
|
||||
|
||||
/// Copy constructor: deep copy
|
||||
DenseTensor(const DenseTensor &other)
|
||||
: Mk(NULL, other.Mk.height, other.Mk.width), nk(other.nk)
|
||||
@@ -775,9 +768,9 @@ public:
|
||||
|
||||
int TotalSize() const { return SizeI()*SizeJ()*SizeK(); }
|
||||
|
||||
void SetSize(int i, int j, int k, MemoryType mt_ = MemoryType::SIZE)
|
||||
void SetSize(int i, int j, int k)
|
||||
{
|
||||
const MemoryType mt = mt_ == MemoryType::SIZE ? tdata.GetMemoryType() : mt_;
|
||||
const MemoryType mt = tdata.GetMemoryType();
|
||||
tdata.Delete();
|
||||
Mk.UseExternalData(NULL, i, j);
|
||||
nk = k;
|
||||
@@ -891,10 +884,6 @@ void BatchLUFactor(DenseTensor &Mlu, Array<int> &P, const double TOL = 0.0);
|
||||
dimension m x n. */
|
||||
void BatchLUSolve(const DenseTensor &Mlu, const Array<int> &P, Vector &X);
|
||||
|
||||
void BatchLUFactor(Vector &Minv,int m,int NE, Array<int> &P);
|
||||
|
||||
void BatchLUSolve(Vector &Minv, int m, int NE,
|
||||
Array<int> &P, Vector &X);
|
||||
|
||||
// Inline methods
|
||||
|
||||
|
||||
@@ -1,699 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_DINVARIANTS_HPP
|
||||
#define MFEM_DINVARIANTS_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "../general/cuda.hpp"
|
||||
#include "dtensor.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace kernels
|
||||
{
|
||||
|
||||
class InvariantsEvaluator2D
|
||||
{
|
||||
public:
|
||||
class Buffers
|
||||
{
|
||||
friend class InvariantsEvaluator2D;
|
||||
private:
|
||||
const double * J_ = nullptr;
|
||||
double * dI1_ = nullptr;
|
||||
double * dI1b_ = nullptr;
|
||||
double * ddI1_ = nullptr;
|
||||
double * ddI1b_ = nullptr;
|
||||
double * dI2_ = nullptr;
|
||||
double * dI2b_ = nullptr;
|
||||
double * ddI2_ = nullptr;
|
||||
double * ddI2b_ = nullptr;
|
||||
public:
|
||||
MFEM_HOST_DEVICE Buffers() {}
|
||||
MFEM_HOST_DEVICE Buffers &J(const double *b) { J_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &dI1(double *b) { dI1_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &dI1b(double *b) { dI1b_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &ddI1(double *b) { ddI1_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &ddI1b(double *b) { ddI1b_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &dI2(double *b) { dI2_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &dI2b(double *b) { dI2b_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &ddI2(double *b) { ddI2_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &ddI2b(double *b) { ddI2b_ = b; return *this; }
|
||||
};
|
||||
|
||||
private:
|
||||
double const * const J;
|
||||
double * const dI1, * const dI1b, * const ddI1, * const ddI1b;
|
||||
double * const dI2, * const dI2b, * const ddI2, * const ddI2b;
|
||||
|
||||
public:
|
||||
MFEM_HOST_DEVICE
|
||||
InvariantsEvaluator2D(Buffers b):
|
||||
J(b.J_),
|
||||
dI1(b.dI1_), dI1b(b.dI1b_), ddI1(b.ddI1_), ddI1b(b.ddI1b_),
|
||||
dI2(b.dI2_), dI2b(b.dI2b_), ddI2(b.ddI2_), ddI2b(b.ddI2b_) { }
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I2b(double &sign_detJ) // det(J) + sign
|
||||
{
|
||||
const double I2b = J[0]*J[3] - J[1]*J[2];
|
||||
sign_detJ = I2b >= 0.0 ? 1.0 : -1.0;
|
||||
return sign_detJ * I2b;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I2b() // det(J)
|
||||
{
|
||||
double sign_detJ;
|
||||
return Get_I2b(sign_detJ);
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I2() // det(J)^{2}
|
||||
{
|
||||
const double I2b = Get_I2b();
|
||||
return I2b * I2b;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I1() // I1 = ||J||_F^2
|
||||
{
|
||||
return J[0]*J[0] + J[1]*J[1] + J[2]*J[2] + J[3]*J[3];
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I1b() // I1b = I1/det(J)
|
||||
{
|
||||
return Get_I1() / Get_I2b();
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double *Get_dI1()
|
||||
{
|
||||
dI1[0] = 2*J[0]; dI1[2] = 2*J[2];
|
||||
dI1[1] = 2*J[1]; dI1[3] = 2*J[3];
|
||||
return dI1;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double *Get_dI1b()
|
||||
{
|
||||
// I1b = I1/I2b
|
||||
// dI1b = (1/I2b)*dI1 - (I1/I2b^2)*dI2b = (2/I2b)*[J - (I1b/2)*dI2b]
|
||||
const double c1 = 2.0/Get_I2b();
|
||||
const double c2 = Get_I1b()/2.0;
|
||||
Get_dI2b();
|
||||
dI1b[0] = c1*(J[0] - c2*dI2b[0]);
|
||||
dI1b[1] = c1*(J[1] - c2*dI2b[1]);
|
||||
dI1b[2] = c1*(J[2] - c2*dI2b[2]);
|
||||
dI1b[3] = c1*(J[3] - c2*dI2b[3]);
|
||||
return dI1b;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double *Get_dI2()
|
||||
{
|
||||
// I2 = I2b^2
|
||||
// dI2 = 2*I2b*dI2b = 2*det(J)*adj(J)^T
|
||||
const double c1 = 2*Get_I2b();
|
||||
Get_dI2b();
|
||||
dI2[0] = c1*dI2b[0];
|
||||
dI2[1] = c1*dI2b[1];
|
||||
dI2[2] = c1*dI2b[2];
|
||||
dI2[3] = c1*dI2b[3];
|
||||
return dI2;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double *Get_dI2b()
|
||||
{
|
||||
// I2b = det(J)
|
||||
// dI2b = adj(J)^T
|
||||
double sign_detJ;
|
||||
Get_I2b(sign_detJ);
|
||||
dI2b[0] = sign_detJ*J[3];
|
||||
dI2b[1] = -sign_detJ*J[2];
|
||||
dI2b[2] = -sign_detJ*J[1];
|
||||
dI2b[3] = sign_detJ*J[0];
|
||||
return dI2b;
|
||||
}
|
||||
|
||||
// ddI1_ijkl = 2 I_ijkl = 2 δ_ik δ_jl
|
||||
MFEM_HOST_DEVICE inline double *Get_ddI1(int i, int j)
|
||||
{
|
||||
// ddI1_ijkl = 2 I_ijkl = 2 δ_ik δ_jl
|
||||
DeviceMatrix ddi1(ddI1,2,2);
|
||||
for (int k=0; k<2; k++)
|
||||
{
|
||||
for (int l=0; l<2; l++)
|
||||
{
|
||||
ddi1(k,l) = (i==k && j==l) ? 2.0 : 0.0;
|
||||
}
|
||||
}
|
||||
return ddI1;
|
||||
}
|
||||
|
||||
// ddI1b = X1 + X2 + X3, where
|
||||
// X1_ijkl = (I1b/I2) [ dI2b_ij dI2b_kl + dI2b_kj dI2b_il ]
|
||||
// X2_ijkl = (1/I2b) ddI1_ijkl
|
||||
// X3_ijkl = -(2/I2) (J_ij dI2b_kl + dI2b_ij J_kl)
|
||||
MFEM_HOST_DEVICE inline double *Get_ddI1b(int i, int j)
|
||||
{
|
||||
double X1_p[4], X2_p[4], X3_p[4];
|
||||
|
||||
// X1_ijkl = (I1b/I2) [ dI2b_ij dI2b_kl + dI2b_kj dI2b_il ]
|
||||
const double I2 = Get_I2();
|
||||
const double I1b = Get_I1b();
|
||||
ConstDeviceMatrix di2b(Get_dI2b(),2,2);
|
||||
const double alpha = I1b / I2;
|
||||
DeviceMatrix X1(X1_p,2,2);
|
||||
for (int k=0; k<2; k++)
|
||||
{
|
||||
for (int l=0; l<2; l++)
|
||||
{
|
||||
X1(k,l) = alpha * (di2b(i,j)*di2b(k,l) + di2b(k,j)*di2b(i,l));
|
||||
}
|
||||
}
|
||||
// X2_ijkl = (1/I2b) ddI1_ijkl
|
||||
DeviceMatrix X2(X2_p,2,2);
|
||||
const double beta = 1.0 / Get_I2b();
|
||||
ConstDeviceMatrix ddi1(Get_ddI1(i,j),2,2);
|
||||
for (int k=0; k<2; k++)
|
||||
{
|
||||
for (int l=0; l<2; l++)
|
||||
{
|
||||
X2(k,l) = beta * ddi1(k,l);
|
||||
}
|
||||
}
|
||||
// X3_ijkl = -(2/I2) (J_ij dI2b_kl + dI2b_ij J_kl)
|
||||
DeviceMatrix X3(X3_p,2,2);
|
||||
const double gamma = -2.0/Get_I2();
|
||||
ConstDeviceMatrix Jpt(J,2,2);
|
||||
for (int k=0; k<2; k++)
|
||||
{
|
||||
for (int l=0; l<2; l++)
|
||||
{
|
||||
X3(k,l) = gamma * (Jpt(i,j)*di2b(k,l) + di2b(i,j)*Jpt(k,l));
|
||||
}
|
||||
}
|
||||
DeviceMatrix ddi1b(ddI1b,2,2);
|
||||
for (int k=0; k<2; k++)
|
||||
{
|
||||
for (int l=0; l<2; l++)
|
||||
{
|
||||
ddi1b(k,l) = X1(k,l) + X2(k,l) + X3(k,l);
|
||||
}
|
||||
}
|
||||
return ddI1b;
|
||||
}
|
||||
|
||||
// ddI2_ijkl = 2 dI2b_ij dI2b_kl + 2 (dI2b_ij dI2b_kl - dI2b_kj dI2b_il)
|
||||
MFEM_HOST_DEVICE inline double *Get_ddI2(int i, int j)
|
||||
{
|
||||
DeviceMatrix ddi2(ddI2,2,2);
|
||||
ConstDeviceMatrix di2b(Get_dI2b(),2,2);
|
||||
for (int k=0; k<2; k++)
|
||||
{
|
||||
for (int l=0; l<2; l++)
|
||||
{
|
||||
ddi2(k,l) = 2*di2b(i,j)*di2b(k,l)
|
||||
+ 2*(di2b(i,j)*di2b(k,l) - di2b(k,j)*di2b(i,l));
|
||||
}
|
||||
}
|
||||
return ddI2;
|
||||
}
|
||||
|
||||
// ddI2b_ijkl = (1/I2b) (δ_ks δ_it - δ_kt δ_si) dI2b_tj dI2b_sl
|
||||
MFEM_HOST_DEVICE inline double *Get_ddI2b(int i, int j)
|
||||
{
|
||||
DeviceMatrix ddi2b(ddI2b,2,2);
|
||||
const double alpha = 1.0/Get_I2b();
|
||||
ConstDeviceMatrix di2b(Get_dI2b(),2,2);
|
||||
for (int k=0; k<2; k++)
|
||||
{
|
||||
for (int l=0; l<2; l++)
|
||||
{
|
||||
ddi2b(k,l) = 0.0;
|
||||
for (int s=0; s<2; s++)
|
||||
{
|
||||
for (int t=0; t<2; t++)
|
||||
{
|
||||
const double ks_it = k==s && i==t ? 1.0 : 0.0;
|
||||
const double kt_si = k==t && s==i ? 1.0 : 0.0;
|
||||
ddi2b(k,l) += alpha * (ks_it - kt_si) * di2b(t,j) * di2b(s,l);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ddI2b;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class InvariantsEvaluator3D
|
||||
{
|
||||
public:
|
||||
class Buffers
|
||||
{
|
||||
friend class InvariantsEvaluator3D;
|
||||
private:
|
||||
const double * J_ = nullptr;
|
||||
double * B_ = nullptr;
|
||||
double * dI1_ = nullptr;
|
||||
double * dI1b_ = nullptr;
|
||||
double * ddI1_ = nullptr;
|
||||
double * ddI1b_ = nullptr;
|
||||
double * dI2_ = nullptr;
|
||||
double * dI2b_ = nullptr;
|
||||
double * ddI2_ = nullptr;
|
||||
double * ddI2b_ = nullptr;
|
||||
double * dI3b_ = nullptr;
|
||||
double * ddI3b_ = nullptr;
|
||||
public:
|
||||
MFEM_HOST_DEVICE Buffers() {}
|
||||
MFEM_HOST_DEVICE Buffers &J(const double *b) { J_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &B(double *b) { B_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &dI1(double *b) { dI1_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &dI1b(double *b) { dI1b_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &ddI1(double *b) { ddI1_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &ddI1b(double *b) { ddI1b_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &dI2(double *b) { dI2_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &dI2b(double *b) { dI2b_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &ddI2(double *b) { ddI2_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &ddI2b(double *b) { ddI2b_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &dI3b(double *b) { dI3b_ = b; return *this; }
|
||||
MFEM_HOST_DEVICE Buffers &ddI3b(double *b) { ddI3b_ = b; return *this; }
|
||||
};
|
||||
|
||||
private:
|
||||
double const * const J;
|
||||
double * const B;
|
||||
double * const dI1, * const dI1b, * const ddI1, * const ddI1b;
|
||||
double * const dI2, * const dI2b, * const ddI2, * const ddI2b;
|
||||
double * const dI3b, * const ddI3b;
|
||||
|
||||
public:
|
||||
MFEM_HOST_DEVICE
|
||||
InvariantsEvaluator3D(Buffers b):
|
||||
J(b.J_), B(b.B_),
|
||||
dI1(b.dI1_), dI1b(b.dI1b_), ddI1(b.ddI1_), ddI1b(b.ddI1b_),
|
||||
dI2(b.dI2_), dI2b(b.dI2b_), ddI2(b.ddI2_), ddI2b(b.ddI2b_),
|
||||
dI3b(b.dI3b_), ddI3b(b.ddI3b_) { }
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I3b(double &sign_detJ) // det(J) + sign
|
||||
{
|
||||
const double I3b = + J[0]*(J[4]*J[8] - J[7]*J[5])
|
||||
- J[1]*(J[3]*J[8] - J[5]*J[6])
|
||||
+ J[2]*(J[3]*J[7] - J[4]*J[6]);
|
||||
sign_detJ = I3b >= 0.0 ? 1.0 : -1.0;
|
||||
return sign_detJ * I3b;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I3b() // det(J)
|
||||
{
|
||||
const double I3b = + J[0]*(J[4]*J[8] - J[7]*J[5])
|
||||
- J[1]*(J[3]*J[8] - J[5]*J[6])
|
||||
+ J[2]*(J[3]*J[7] - J[4]*J[6]);
|
||||
return I3b;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I3() // det(J)^{2}
|
||||
{
|
||||
const double I3b = Get_I3b();
|
||||
return I3b * I3b;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I3b_p() // I3b^{-2/3}
|
||||
{
|
||||
double sign_detJ;
|
||||
const double i3b = Get_I3b(sign_detJ);
|
||||
return sign_detJ * std::pow(i3b, -2./3.);
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I3b_p(double &sign_detJ) // I3b^{-2/3}
|
||||
{
|
||||
const double i3b = Get_I3b(sign_detJ);
|
||||
return sign_detJ * std::pow(i3b, -2./3.);
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I1()
|
||||
{
|
||||
B[0] = J[0]*J[0] + J[3]*J[3] + J[6]*J[6];
|
||||
B[1] = J[1]*J[1] + J[4]*J[4] + J[7]*J[7];
|
||||
B[2] = J[2]*J[2] + J[5]*J[5] + J[8]*J[8];
|
||||
const double I1 = B[0] + B[1] + B[2];
|
||||
return I1;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline
|
||||
double Get_I1b() // det(J)^{-2/3}*I_1 = I_1/I_3^{1/3}
|
||||
{
|
||||
const double I1b = Get_I1() * Get_I3b_p();
|
||||
return I1b;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline void Get_B_offd()
|
||||
{
|
||||
// B = J J^t
|
||||
// B[3]=B(0,1), B[4]=B(0,2), B[5]=B(1,2)
|
||||
B[3] = J[0]*J[1] + J[3]*J[4] + J[6]*J[7]; // B(0,1)
|
||||
B[4] = J[0]*J[2] + J[3]*J[5] + J[6]*J[8]; // B(0,2)
|
||||
B[5] = J[1]*J[2] + J[4]*J[5] + J[7]*J[8]; // B(1,2)
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I2()
|
||||
{
|
||||
Get_B_offd();
|
||||
const double I1 = Get_I1();
|
||||
const double BF2 = B[0]*B[0] + B[1]*B[1] + B[2]*B[2] +
|
||||
2*(B[3]*B[3] + B[4]*B[4] + B[5]*B[5]);
|
||||
const double I2 = (I1*I1 - BF2)/2;
|
||||
return I2;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double Get_I2b() // I2b = I2*I3b^{-4/3}
|
||||
{
|
||||
const double I3b_p = Get_I3b_p();
|
||||
return Get_I2() * I3b_p * I3b_p;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double *Get_dI1()
|
||||
{
|
||||
for (int i = 0; i < 9; i++) { dI1[i] = 2*J[i]; }
|
||||
return dI1;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double *Get_dI1b()
|
||||
{
|
||||
// I1b = I3b^{-2/3}*I1
|
||||
// dI1b = 2*I3b^{-2/3}*(J - (1/3)*I1/I3b*dI3b)
|
||||
double sign_detJ;
|
||||
const double I3b = Get_I3b(sign_detJ);
|
||||
const double I3b_p = Get_I3b_p();
|
||||
const double c1 = 2.0 * I3b_p;
|
||||
const double c2 = Get_I1()/(3.0 * I3b);
|
||||
Get_dI3b(sign_detJ);
|
||||
for (int i = 0; i < 9; i++) { dI1b[i] = c1*(J[i] - c2*dI3b[i]); }
|
||||
return dI1b;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double *Get_dI2()
|
||||
{
|
||||
// dI2 = 2 I_1 J - 2 J J^t J = 2 (I_1 I - B) J
|
||||
const double I1 = Get_I1();
|
||||
Get_B_offd();
|
||||
// B[0]=B(0,0), B[1]=B(1,1), B[2]=B(2,2)
|
||||
// B[3]=B(0,1), B[4]=B(0,2), B[5]=B(1,2)
|
||||
const double C[6] =
|
||||
{
|
||||
2*(I1 - B[0]), 2*(I1 - B[1]), 2*(I1 - B[2]),
|
||||
-2*B[3], -2*B[4], -2*B[5]
|
||||
};
|
||||
// | C[0] C[3] C[4] | | J[0] J[3] J[6] |
|
||||
// dI2 = | C[3] C[1] C[5] | | J[1] J[4] J[7] |
|
||||
// | C[4] C[5] C[2] | | J[2] J[5] J[8] |
|
||||
dI2[0] = C[0]*J[0] + C[3]*J[1] + C[4]*J[2];
|
||||
dI2[1] = C[3]*J[0] + C[1]*J[1] + C[5]*J[2];
|
||||
dI2[2] = C[4]*J[0] + C[5]*J[1] + C[2]*J[2];
|
||||
|
||||
dI2[3] = C[0]*J[3] + C[3]*J[4] + C[4]*J[5];
|
||||
dI2[4] = C[3]*J[3] + C[1]*J[4] + C[5]*J[5];
|
||||
dI2[5] = C[4]*J[3] + C[5]*J[4] + C[2]*J[5];
|
||||
|
||||
dI2[6] = C[0]*J[6] + C[3]*J[7] + C[4]*J[8];
|
||||
dI2[7] = C[3]*J[6] + C[1]*J[7] + C[5]*J[8];
|
||||
dI2[8] = C[4]*J[6] + C[5]*J[7] + C[2]*J[8];
|
||||
return dI2;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double *Get_dI2b()
|
||||
{
|
||||
// I2b = det(J)^{-4/3}*I2 = I3b^{-4/3}*I2
|
||||
// dI2b = (-4/3)*I3b^{-7/3}*I2*dI3b + I3b^{-4/3}*dI2
|
||||
// = I3b^{-4/3} * [ dI2 - (4/3)*I2/I3b*dI3b ]
|
||||
double sign_detJ;
|
||||
const double I2 = Get_I2();
|
||||
const double I3b_p = Get_I3b_p();
|
||||
const double I3b = Get_I3b(sign_detJ);
|
||||
const double c1 = I3b_p*I3b_p;
|
||||
const double c2 = (4*I2/I3b)/3;
|
||||
Get_dI2();
|
||||
Get_dI3b(sign_detJ);
|
||||
for (int i = 0; i < 9; i++) { dI2b[i] = c1*(dI2[i] - c2*dI3b[i]); }
|
||||
return dI2b;
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline double *Get_dI3b(const double sign_detJ)
|
||||
{
|
||||
// I3b = det(J)
|
||||
// dI3b = adj(J)^T
|
||||
dI3b[0] = sign_detJ*(J[4]*J[8] - J[5]*J[7]); // 0 3 6
|
||||
dI3b[1] = sign_detJ*(J[5]*J[6] - J[3]*J[8]); // 1 4 7
|
||||
dI3b[2] = sign_detJ*(J[3]*J[7] - J[4]*J[6]); // 2 5 8
|
||||
dI3b[3] = sign_detJ*(J[2]*J[7] - J[1]*J[8]);
|
||||
dI3b[4] = sign_detJ*(J[0]*J[8] - J[2]*J[6]);
|
||||
dI3b[5] = sign_detJ*(J[1]*J[6] - J[0]*J[7]);
|
||||
dI3b[6] = sign_detJ*(J[1]*J[5] - J[2]*J[4]);
|
||||
dI3b[7] = sign_detJ*(J[2]*J[3] - J[0]*J[5]);
|
||||
dI3b[8] = sign_detJ*(J[0]*J[4] - J[1]*J[3]);
|
||||
return dI3b;
|
||||
}
|
||||
|
||||
// ddI1_ijkl = 2 I_ijkl = 2 δ_ik δ_jl
|
||||
MFEM_HOST_DEVICE inline double *Get_ddI1(int i, int j)
|
||||
{
|
||||
DeviceMatrix ddi1(ddI1,3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
const double I_ijkl = (i==k && j==l) ? 1.0 : 0.0;
|
||||
ddi1(k,l) = 2.0 * I_ijkl;
|
||||
}
|
||||
}
|
||||
return ddI1;
|
||||
}
|
||||
|
||||
// ddI1b = X1 + X2 + X3, where
|
||||
// X1_ijkl = (2/3*I1b/I3) [ 2/3 dI3b_ij dI3b_kl + dI3b_kj dI3b_il ]
|
||||
// X2_ijkl = (I3b^{-2/3}) ddI1_ijkl
|
||||
// X3_ijkl = -(4/3*I3b^{-5/3}) (J_ij dI3b_kl + dI3b_ij J_kl)
|
||||
MFEM_HOST_DEVICE inline double *Get_ddI1b(int i, int j)
|
||||
{
|
||||
// X1_ijkl = (2/3*I1b/I3) [ 2/3 dI3b_ij dI3b_kl + dI3b_kj dI3b_il ]
|
||||
double sign_detJ;
|
||||
Get_I3b(sign_detJ);
|
||||
double X1_p[9], X2_p[9], X3_p[9];
|
||||
DeviceMatrix X1(X1_p,3,3);
|
||||
const double I3 = Get_I3();
|
||||
const double I1b = Get_I1b();
|
||||
const double alpha = (2./3.)*I1b/I3;
|
||||
ConstDeviceMatrix di3b(Get_dI3b(sign_detJ),3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
X1(k,l) = alpha * ((2./3.)*di3b(i,j) * di3b(k,l) +
|
||||
di3b(k,j)*di3b(i,l));
|
||||
}
|
||||
}
|
||||
// ddI1_ijkl = 2 δ_ik δ_jl
|
||||
// X2_ijkl = (I3b^{-2/3}) ddI1_ijkl
|
||||
DeviceMatrix X2(X2_p,3,3);
|
||||
const double beta = Get_I3b_p();
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
const double ddI1_ijkl = (i==k && j==l) ? 2.0 : 0.0;
|
||||
X2(k,l) = beta * ddI1_ijkl;
|
||||
}
|
||||
}
|
||||
// X3_ijkl = -(4/3*I3b^{-5/3}) (J_ij dI3b_kl + dI3b_ij J_kl)
|
||||
DeviceMatrix X3(X3_p,3,3);
|
||||
const double I3b = Get_I3b();
|
||||
const double gamma = -(4./3.)*Get_I3b_p()/I3b;
|
||||
ConstDeviceMatrix Jpt(J,3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
X3(k,l) = gamma * (Jpt(i,j) * di3b(k,l) + di3b(i,j) * Jpt(k,l));
|
||||
}
|
||||
}
|
||||
DeviceMatrix ddi1b(ddI1b,3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
ddi1b(k,l) = X1(k,l) + X2(k,l) + X3(k,l);
|
||||
}
|
||||
}
|
||||
return ddI1b;
|
||||
}
|
||||
|
||||
// ddI2 = x1 + x2 + x3
|
||||
// x1_ijkl = (2 I1) δ_ik δ_jl
|
||||
// x2_ijkl = 2 ( 2 δ_ku δ_iv - δ_ik δ_uv - δ_kv δ_iu ) J_vj J_ul
|
||||
// x3_ijkl = -2 (J J^t)_ik δ_jl = -2 B_ik δ_jl
|
||||
MFEM_HOST_DEVICE inline double *Get_ddI2(int i, int j)
|
||||
{
|
||||
double x1_p[9], x2_p[9], x3_p[9];
|
||||
DeviceMatrix x1(x1_p,3,3), x2(x2_p,3,3), x3(x3_p,3,3);
|
||||
// x1_ijkl = (2 I1) δ_ik δ_jl
|
||||
const double I1 = Get_I1();
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
const double ik_jl = (i==k && j==l) ? 1.0 : 0.0;
|
||||
x1(k,l) = 2.0 * I1 * ik_jl;
|
||||
}
|
||||
}
|
||||
// x2_ijkl = 2 ( 2 δ_ku δ_iv - δ_ik δ_uv - δ_kv δ_iu ) J_vj J_ul
|
||||
ConstDeviceMatrix Jpt(J,3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
x2(k,l) = 0.0;
|
||||
for (int u=0; u<3; u++)
|
||||
{
|
||||
for (int v=0; v<3; v++)
|
||||
{
|
||||
const double ku_iv = k==u && i==v ? 1.0 : 0.0;
|
||||
const double ik_uv = i==k && u==v ? 1.0 : 0.0;
|
||||
const double kv_iu = k==v && i==u ? 1.0 : 0.0;
|
||||
x2(k,l) += 2.0*(2.*ku_iv-ik_uv-kv_iu)*Jpt(v,j)*Jpt(u,l);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// x3_ijkl = -2 B_ik δ_jl
|
||||
B[0] = J[0]*J[0] + J[3]*J[3] + J[6]*J[6];
|
||||
B[1] = J[1]*J[1] + J[4]*J[4] + J[7]*J[7];
|
||||
B[2] = J[2]*J[2] + J[5]*J[5] + J[8]*J[8];
|
||||
B[3] = J[0]*J[1] + J[3]*J[4] + J[6]*J[7]; // B(0,1)
|
||||
B[4] = J[0]*J[2] + J[3]*J[5] + J[6]*J[8]; // B(0,2)
|
||||
B[5] = J[1]*J[2] + J[4]*J[5] + J[7]*J[8]; // B(1,2)
|
||||
const double b_p[9] =
|
||||
{
|
||||
B[0], B[3], B[4],
|
||||
B[3], B[1], B[5],
|
||||
B[4], B[5], B[2]
|
||||
};
|
||||
ConstDeviceMatrix b(b_p,3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
const double jl = j==l ? 1.0 : 0.0;
|
||||
x3(k,l) = -2.0 * b(i,k) * jl;
|
||||
}
|
||||
}
|
||||
// ddI2 = x1 + x2 + x3
|
||||
DeviceMatrix ddi2(ddI2,3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
ddi2(k,l) = x1(k,l) + x2(k,l) + x3(k,l);
|
||||
}
|
||||
}
|
||||
return ddI2;
|
||||
}
|
||||
|
||||
// ddI2b = X1 + X2 + X3
|
||||
// X1_ijkl = 16/9 det(J)^{-10/3} I2 dI3b_ij dI3b_kl +
|
||||
// 4/3 det(J)^{-10/3} I2 dI3b_il dI3b_kj
|
||||
// X2_ijkl = -4/3 det(J)^{-7/3} (dI2_ij dI3b_kl + dI2_kl dI3b_ij)
|
||||
// X3_ijkl = det(J)^{-4/3} ddI2_ijkl
|
||||
MFEM_HOST_DEVICE inline double *Get_ddI2b(int i, int j)
|
||||
{
|
||||
double X1_p[9], X2_p[9], X3_p[9];
|
||||
// X1_ijkl = 16/9 det(J)^{-10/3} I2 dI3b_ij dI3b_kl +
|
||||
// 4/3 det(J)^{-10/3} I2 dI3b_il dI3b_kj
|
||||
double sign_detJ;
|
||||
DeviceMatrix X1(X1_p,3,3);
|
||||
const double I3b_p = Get_I3b_p(); // I3b^{-2/3}
|
||||
const double I3b = Get_I3b(sign_detJ); // det(J)
|
||||
const double I2 = Get_I2();
|
||||
const double I3b_p43 = I3b_p*I3b_p;
|
||||
const double I3b_p73 = I3b_p*I3b_p/I3b;
|
||||
const double I3b_p103 = I3b_p*I3b_p/(I3b*I3b);
|
||||
ConstDeviceMatrix di3b(Get_dI3b(sign_detJ),3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
const double up = (16./9.)*I3b_p103*I2*di3b(i,j)*di3b(k,l);
|
||||
const double down = (4./3.)*I3b_p103*I2*di3b(i,l)*di3b(k,j);
|
||||
X1(k,l) = up + down;
|
||||
}
|
||||
}
|
||||
// X2_ijkl = -4/3 det(J)^{-7/3} (dI2_ij dI3b_kl + dI2_kl dI3b_ij)
|
||||
DeviceMatrix X2(X2_p,3,3);
|
||||
ConstDeviceMatrix di2(Get_dI2(),3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
X2(k,l) = -(4./3.)*I3b_p73*(di2(i,j)*di3b(k,l)+di2(k,l)*di3b(i,j));
|
||||
}
|
||||
}
|
||||
// X3_ijkl = det(J)^{-4/3} ddI2_ijkl
|
||||
DeviceMatrix X3(X3_p,3,3);
|
||||
ConstDeviceMatrix ddi2(Get_ddI2(i,j),3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
X3(k,l) = I3b_p43 * ddi2(k,l);
|
||||
}
|
||||
}
|
||||
// ddI2b = X1 + X2 + X3
|
||||
DeviceMatrix ddi2b(ddI2b,3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
ddi2b(k,l) = X1(k,l) + X2(k,l) + X3(k,l);
|
||||
}
|
||||
}
|
||||
return ddI2b;
|
||||
}
|
||||
|
||||
// dI3b = adj(J)^T
|
||||
// ddI3b_ijkl = (1/I3b) (δ_ks δ_it - δ_kt δ_si) dI3b_tj dI3b_sl
|
||||
MFEM_HOST_DEVICE inline double *Get_ddI3b(int i, int j)
|
||||
{
|
||||
const double c1 = 1./Get_I3b();
|
||||
ConstDeviceMatrix di3b(dI3b,3,3);
|
||||
DeviceMatrix ddi3b(ddI3b,3,3);
|
||||
for (int k=0; k<3; k++)
|
||||
{
|
||||
for (int l=0; l<3; l++)
|
||||
{
|
||||
ddi3b(k,l) = 0.0;
|
||||
for (int s=0; s<3; s++)
|
||||
{
|
||||
for (int t=0; t<3; t++)
|
||||
{
|
||||
const double ks_it = k==s && i==t ? 1.0 : 0.0;
|
||||
const double kt_si = k==t && s==i ? 1.0 : 0.0;
|
||||
ddi3b(k,l) += c1*(ks_it-kt_si)*di3b(t,j)*di3b(s,l);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ddI3b;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace kernels
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_DINVARIANTS_HPP
|
||||
+2
-12
@@ -54,7 +54,6 @@ template <int N, int Dim, typename T, typename... Args>
|
||||
class Init
|
||||
{
|
||||
public:
|
||||
MFEM_HOST_DEVICE
|
||||
static inline int result(int* sizes, T first, Args... args)
|
||||
{
|
||||
sizes[N - 1] = first;
|
||||
@@ -67,7 +66,6 @@ template <int Dim, typename T, typename... Args>
|
||||
class Init<Dim, Dim, T, Args...>
|
||||
{
|
||||
public:
|
||||
MFEM_HOST_DEVICE
|
||||
static inline int result(int* sizes, T first, Args... args)
|
||||
{
|
||||
sizes[Dim - 1] = first;
|
||||
@@ -90,7 +88,7 @@ public:
|
||||
DeviceTensor() = delete;
|
||||
|
||||
/// Constructor to initialize a tensor from the Scalar array _data
|
||||
template <typename... Args> MFEM_HOST_DEVICE
|
||||
template <typename... Args>
|
||||
DeviceTensor(Scalar* _data, Args... args)
|
||||
{
|
||||
static_assert(sizeof...(args) == Dim, "Wrong number of arguments");
|
||||
@@ -112,7 +110,7 @@ public:
|
||||
}
|
||||
|
||||
/// Conversion to `Scalar *`.
|
||||
MFEM_HOST_DEVICE inline operator Scalar *() const { return data; }
|
||||
inline operator Scalar *() const { return data; }
|
||||
|
||||
/// Const accessor for the data
|
||||
template <typename... Args> MFEM_HOST_DEVICE inline
|
||||
@@ -140,16 +138,8 @@ inline DeviceTensor<sizeof...(Dims),T> Reshape(T *ptr, Dims... dims)
|
||||
|
||||
|
||||
typedef DeviceTensor<1,int> DeviceArray;
|
||||
typedef DeviceTensor<1,const int> ConstDeviceArray;
|
||||
|
||||
typedef DeviceTensor<1,double> DeviceVector;
|
||||
typedef DeviceTensor<1,const double> ConstDeviceVector;
|
||||
|
||||
typedef DeviceTensor<2,double> DeviceMatrix;
|
||||
typedef DeviceTensor<2,const double> ConstDeviceMatrix;
|
||||
|
||||
typedef DeviceTensor<3,double> DeviceCube;
|
||||
typedef DeviceTensor<3,const double> ConstDeviceCube;
|
||||
|
||||
} // mfem namespace
|
||||
|
||||
|
||||
@@ -0,0 +1,628 @@
|
||||
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
||||
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
||||
// reserved. See file COPYRIGHT for details.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability see http://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU Lesser General Public License (as published by the Free
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
|
||||
#ifndef FDUAL_H
|
||||
#define FDUAL_H
|
||||
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace ad
|
||||
{
|
||||
// Forward AD - simple class for automatic differentiation
|
||||
template<typename tbase>
|
||||
class FDual
|
||||
{
|
||||
private:
|
||||
tbase pr;
|
||||
tbase du;
|
||||
|
||||
public:
|
||||
|
||||
FDual():pr(0),du(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <class fltyp, class = typename
|
||||
std::enable_if<std::is_arithmetic<fltyp>::value>::type>
|
||||
FDual(fltyp& f):pr(f),du(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template <class fltyp, class = typename
|
||||
std::enable_if<std::is_arithmetic<fltyp>::value>::type>
|
||||
FDual(const fltyp& f):pr(f),du(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FDual(tbase& pr_,tbase& du_):pr(pr_),du(du_)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FDual(const tbase& pr_,const tbase& du_):pr(pr_),du(du_)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FDual(FDual<tbase>& nm):pr(nm.pr),du(nm.du)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FDual(const FDual<tbase>& nm):pr(nm.pr),du(nm.du)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
tbase prim() const
|
||||
{
|
||||
return pr;
|
||||
}
|
||||
|
||||
tbase real() const
|
||||
{
|
||||
return pr;
|
||||
}
|
||||
|
||||
tbase dual() const
|
||||
{
|
||||
return du;
|
||||
}
|
||||
|
||||
void set(const tbase& pr_,const tbase& du_)
|
||||
{
|
||||
pr=pr_;
|
||||
du=du_;
|
||||
}
|
||||
|
||||
void prim(const tbase& pr_)
|
||||
{
|
||||
pr=pr_;
|
||||
}
|
||||
|
||||
void real(const tbase& pr_)
|
||||
{
|
||||
pr=pr_;
|
||||
}
|
||||
|
||||
void dual(const tbase& du_)
|
||||
{
|
||||
du=du_;
|
||||
}
|
||||
|
||||
FDual<tbase> & operator=(tbase sc_)
|
||||
{
|
||||
pr=sc_;
|
||||
du=tbase(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FDual<tbase> & operator+=(tbase sc_)
|
||||
{
|
||||
pr=pr+sc_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FDual<tbase> & operator-=(tbase sc_)
|
||||
{
|
||||
pr=pr-sc_;
|
||||
return *this;
|
||||
|
||||
}
|
||||
|
||||
FDual<tbase> & operator*=(tbase sc_)
|
||||
{
|
||||
pr=pr*sc_;
|
||||
du=du*sc_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FDual<tbase>& operator/=(tbase sc_)
|
||||
{
|
||||
pr=pr/sc_;
|
||||
du=du/sc_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
FDual<tbase>& operator=(const FDual<tbase> & f)
|
||||
{
|
||||
pr = f.real();
|
||||
du = f.dual();
|
||||
return *this;
|
||||
}
|
||||
|
||||
FDual<tbase>& operator+=(const FDual<tbase>& f)
|
||||
{
|
||||
pr += f.real();
|
||||
du += f.dual();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
FDual<tbase>& operator-=(const FDual<tbase>& f)
|
||||
{
|
||||
pr -= f.real();
|
||||
du -= f.dual();
|
||||
return *this;
|
||||
}
|
||||
|
||||
FDual<tbase>& operator*=(const FDual<tbase>& f)
|
||||
{
|
||||
du = du * f.real();
|
||||
du = du+ pr * f.dual();
|
||||
pr = pr * f.real();
|
||||
return *this;
|
||||
}
|
||||
|
||||
FDual<tbase>& operator/=(const FDual<tbase>& f_)
|
||||
{
|
||||
pr = pr / f_.real();
|
||||
du = du - pr * f_.dual();
|
||||
du = du / f_.real();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// non-member functions
|
||||
// boolean operations
|
||||
template <typename tbase>
|
||||
inline
|
||||
bool operator==(const FDual<tbase>& a1, const FDual<tbase>& a2)
|
||||
{
|
||||
return a1.real() == a2.real();
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
bool operator==(tbase a, const FDual<tbase>& f_)
|
||||
{
|
||||
return a == f_.real();
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
bool operator==(const FDual<tbase>& a, tbase b)
|
||||
{
|
||||
return a.real() == b;
|
||||
}
|
||||
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
bool operator<(const FDual<tbase>& f1, const FDual<tbase>& f2)
|
||||
{
|
||||
return f1.real() < f2.real();
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
bool operator<(const FDual<tbase>& f, tbase a)
|
||||
{
|
||||
return f.real() < a;
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
bool operator<(tbase a, const FDual<tbase>& f)
|
||||
{
|
||||
return a < f.real();
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
bool operator>(const FDual<tbase>& f1, const FDual<tbase>& f2)
|
||||
{
|
||||
return f1.real() > f2.real();
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
bool operator>(const FDual<tbase>& f, tbase a)
|
||||
{
|
||||
return f.real() > a;
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
bool operator>(tbase a, const FDual<tbase>& f)
|
||||
{
|
||||
return (a > f.real());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator-(const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(-f.real(), -f.dual());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator-(const FDual<tbase>& f, tbase a)
|
||||
{
|
||||
return FDual<tbase>(f.real() - a, f.dual());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<FDual<tbase>> operator-(const FDual<FDual<tbase>>& f, tbase a)
|
||||
{
|
||||
return FDual<FDual<tbase>>(f.real() - a, f.dual());
|
||||
}
|
||||
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator+(const FDual<tbase>& f, tbase a)
|
||||
{
|
||||
return FDual<tbase>(f.real() + a, f.dual());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<FDual<tbase>> operator+(const FDual<FDual<tbase>>& f, tbase a)
|
||||
{
|
||||
return FDual<FDual<tbase>>(f.real() + a, f.dual());
|
||||
}
|
||||
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator*(const FDual<tbase>& f, tbase a)
|
||||
{
|
||||
return FDual<tbase>(f.real() * a, f.dual() * a);
|
||||
}
|
||||
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator/(const FDual<tbase>& f, tbase a)
|
||||
{
|
||||
return FDual<tbase>(f.real() / a, f.dual() / a);
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<FDual<tbase>> operator/(const FDual<FDual<tbase>>& f, tbase a)
|
||||
{
|
||||
return FDual<FDual<tbase>>(f.real() / a, f.dual() / a);
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator+(tbase a, const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(a + f.real(), f.dual());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<FDual<tbase>> operator+(tbase a, const FDual<FDual<tbase>>& f)
|
||||
{
|
||||
return FDual<FDual<tbase>>(a + f.real(), f.dual());
|
||||
}
|
||||
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator-(tbase a, const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(a - f.real(), -f.dual());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<FDual<tbase>> operator-(tbase a, const FDual<FDual<tbase>>& f)
|
||||
{
|
||||
return FDual<FDual<tbase>>(a - f.real(), -f.dual());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator*(tbase a, const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(f.real() * a, f.dual() *a);
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<FDual<tbase>> operator*(tbase a, const FDual<FDual<tbase>>& f)
|
||||
{
|
||||
return FDual<FDual<tbase>>(f.real() * a, f.dual() *a);
|
||||
}
|
||||
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator/(tbase a, const FDual<tbase>& f)
|
||||
{
|
||||
a = a / f.real();
|
||||
return FDual<tbase>(a, -a * f.dual() / f.real());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator+(const FDual<tbase>& f1, const FDual<tbase>& f2)
|
||||
{
|
||||
return FDual<tbase>(f1.real() + f2.real(), f1.dual() + f2.dual());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator-(const FDual<tbase>& f1, const FDual<tbase>& f2)
|
||||
{
|
||||
return FDual<tbase>(f1.real() - f2.real(), f1.dual() - f2.dual());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator*(const FDual<tbase>& f1, const FDual<tbase>& f2)
|
||||
{
|
||||
return FDual<tbase>(f1.real() * f2.real(),
|
||||
f1.real() * f2.dual() + f1.dual() * f2.real());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> operator/(const FDual<tbase>& f1, const FDual<tbase>& f2)
|
||||
{
|
||||
tbase a=tbase(1)/f2.real();
|
||||
tbase b=f1.real()*a;
|
||||
return FDual<tbase>(b, (f1.dual() - f2.dual()*b)*a);
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> acos(const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(acos(f.real()),
|
||||
-f.dual() / sqrt(tbase(1) - f.real() * f.real()));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> acos(const FDual<double>& f)
|
||||
{
|
||||
return FDual<double>(std::acos(f.real()),
|
||||
-f.dual() / std::sqrt(double(1) - f.real() * f.real()));
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> asin(const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(asin(f.real()),
|
||||
f.dual() / sqrt(tbase(1) - f.real() * f.real()));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> asin(const FDual<double>& f)
|
||||
{
|
||||
return FDual<double>(std::asin(f.real()),
|
||||
f.dual() / std::sqrt(double(1) - f.real() * f.real()));
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> atan(const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(atan(f.real()),
|
||||
f.dual() / (tbase(1) + f.real() * f.real()));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> atan(const FDual<double>& f)
|
||||
{
|
||||
return FDual<double>(std::atan(f.real()),
|
||||
f.dual() / (double(1) + f.real() * f.real()));
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> cos(const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(cos(f.real()), -f.dual() * sin(f.real()));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> cos(const FDual<double>& f)
|
||||
{
|
||||
return FDual<double>(std::cos(f.real()), -f.dual() * std::sin(f.real()));
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> cosh(const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(cosh(f.real()), f.dual() * sinh(f.real()));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> cosh(const FDual<double>& f)
|
||||
{
|
||||
return FDual<double>(std::cosh(f.real()), f.dual() * std::sinh(f.real()));
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> exp(const FDual<tbase>& f)
|
||||
{
|
||||
tbase x = exp(f.real());
|
||||
return FDual<tbase>(x, f.dual() * x);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> exp(const FDual<double>& f)
|
||||
{
|
||||
double x = std::exp(f.real());
|
||||
return FDual<double>(x, f.dual() * x);
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> log(const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(log(f.real()), f.dual() / f.real());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> log(const FDual<double>& f)
|
||||
{
|
||||
return FDual<double>(std::log(f.real()), f.dual() / f.real());
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> log10(const FDual<tbase>& f)
|
||||
{
|
||||
return log(f) / log(tbase(10));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> log10(const FDual<double>& f)
|
||||
{
|
||||
return log(f) / std::log(double(10));
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> pow(const FDual<tbase>& a, const FDual<tbase>& b)
|
||||
{
|
||||
return exp(log(a) * b);
|
||||
}
|
||||
|
||||
template <typename tbase, typename tbase1>
|
||||
inline
|
||||
FDual<tbase> pow(const FDual<tbase>& a, const tbase1& b)
|
||||
{
|
||||
return exp(log(a) * tbase(b));
|
||||
}
|
||||
|
||||
|
||||
template <typename tbase, typename tbase1>
|
||||
inline
|
||||
FDual<tbase> pow(const tbase1& a, const FDual<tbase>& b)
|
||||
{
|
||||
return exp(log(tbase(a)) * b);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> pow(const double& a, const FDual<double>& b)
|
||||
{
|
||||
return exp(std::log(a) * b);
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> sin(const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(sin(f.real()), f.dual() * cos(f.real()));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> sin(const FDual<double>& f)
|
||||
{
|
||||
return FDual<double>(std::sin(f.real()), f.dual() * std::cos(f.real()));
|
||||
}
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> sinh(const FDual<tbase>& f)
|
||||
{
|
||||
return FDual<tbase>(sinh(f.real()), f.dual() * cosh(f.real()));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> sinh(const FDual<double>& f)
|
||||
{
|
||||
return FDual<double>(std::sinh(f.real()), f.dual() * std::cosh(f.real()));
|
||||
}
|
||||
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> sqrt(const FDual<tbase>& f)
|
||||
{
|
||||
tbase a = sqrt(f.real());
|
||||
return FDual<tbase>(a, f.dual() / (tbase(2) * a));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> sqrt(const FDual<double>& f)
|
||||
{
|
||||
double a = std::sqrt(f.real());
|
||||
return FDual<double>(a, f.dual() / (double(2) * a));
|
||||
}
|
||||
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> tan(const FDual<tbase>& f)
|
||||
{
|
||||
tbase a = tan(f.real());
|
||||
return FDual<tbase>(a,f.dual() * (tbase(1) + a * a));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> tan(const FDual<double>& f)
|
||||
{
|
||||
double a = std::tan(f.real());
|
||||
return FDual<double>(a,f.dual() * (double(1) + a * a));
|
||||
}
|
||||
|
||||
|
||||
template <typename tbase>
|
||||
inline
|
||||
FDual<tbase> tanh(const FDual<tbase>& f)
|
||||
{
|
||||
tbase a = tanh(f.real());
|
||||
return FDual<tbase>(a, f.dual() * (tbase(1) - a * a));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
FDual<double> tanh(const FDual<double>& f)
|
||||
{
|
||||
double a = std::tanh(f.real());
|
||||
return FDual<double>(a, f.dual() * (double(1) - a * a));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1249,7 +1249,6 @@ void HypreParMatrix::operator*=(double s)
|
||||
static void get_sorted_rows_cols(const Array<int> &rows_cols,
|
||||
Array<HYPRE_Int> &hypre_sorted)
|
||||
{
|
||||
rows_cols.HostRead();
|
||||
hypre_sorted.SetSize(rows_cols.Size());
|
||||
bool sorted = true;
|
||||
for (int i = 0; i < rows_cols.Size(); i++)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user