Compare commits

..
51 Commits
Author SHA1 Message Date
lazarov 98cf6b0817 filter implementation and test 2020-08-11 11:36:40 -07:00
lazarov 97ec9f4cf2 Merge branch 'master' into fadg 2020-08-06 20:02:02 -07:00
lazarov 6c794b6eac makefile clean 2020-08-05 19:45:20 -07:00
lazarov ee09690f4f .gitignore 2020-08-05 19:21:45 -07:00
lazarov 309429fdfc clean-up 2020-08-05 19:16:02 -07:00
lazarov 7128a065b3 .gitignore 2020-08-05 19:15:16 -07:00
lazarov a6ba35ff36 gitignore 2020-08-05 17:27:44 -07:00
lazarov 4845624368 gitignore 2020-08-05 16:52:42 -07:00
lazarov 354a61e4b9 gitignore 2020-08-05 16:49:01 -07:00
lazarov 9c156c0b66 gitignore 2020-08-05 16:28:31 -07:00
lazarov ae3af1214f style 2020-08-05 16:25:54 -07:00
lazarov 9c5dc1464d replace pLap Example71 2020-08-05 16:04:58 -07:00
lazarov eb88fddeea clean ex71p 2020-08-05 16:01:58 -07:00
lazarov cb6770a4e6 additional clean-up 2020-08-05 15:16:02 -07:00
lazarov e67c98e9a2 clean 2020-08-05 14:25:58 -07:00
lazarov 5f6c164316 remove unused variables 2020-08-05 13:48:47 -07:00
lazarov c6dfc01dd8 small corrections 2020-08-05 09:44:22 -07:00
lazarov 9676db3664 remove const qulifier for energy evaluation 2020-07-26 22:39:29 -07:00
lazarov b7691bba5f bug fix in tadvector 2020-07-26 21:30:44 -07:00
lazarov d7f5aec642 clean examples 2020-07-24 22:02:31 -07:00
lazarov 989e341572 gitignore 2020-07-24 00:34:24 -07:00
lazarov f21f9ace69 gitignore 2020-07-23 23:46:24 -07:00
lazarov 26d36fe267 .gitignore 2020-07-23 23:28:35 -07:00
lazarov fe8fe5968e remove user.mk 2020-07-23 23:06:24 -07:00
lazarov d849d810b6 delete user.cmake 2020-07-23 22:53:20 -07:00
lazarov fc63a4720f Merge branch 'master' into fadg 2020-07-23 22:17:41 -07:00
lazarov 835d5ddc9d - 2020-07-23 22:13:26 -07:00
lazarov ee85bed9bd style 2020-07-23 22:11:04 -07:00
lazarov 386d0b262b cosmetic changes 2020-07-23 22:07:43 -07:00
lazarov 76d3923425 cleaner code 2020-07-23 19:23:15 -07:00
lazarov 4bd5a4e3d0 Remiving all virtual classes for AD 2020-07-23 18:56:04 -07:00
lazarov ba1a296d36 ../config/user.cmake 2020-07-23 18:40:17 -07:00
lazarov 9d4845d1a3 examples/ex71.hpp 2020-07-23 18:37:03 -07:00
lazarov 46470cd320 Memory leak fix for ../fem/nonlinearform.cpp 2020-07-22 12:00:41 -07:00
lazarov aeaf936552 Added AD implementation based on functors instead of virtual methods 2020-07-20 00:10:44 -07:00
lazarov b9219c5941 makefile system 2020-07-10 18:27:28 -07:00
lazarov 4435c8284f Small modifications 2020-07-08 19:48:31 -07:00
lazarov ad857589a0 Removed CODIPACK dependency 2020-07-08 19:23:06 -07:00
lazarov cda243493a New descriptions for ex71 and ex71p 2020-07-08 19:13:23 -07:00
lazarov 85e140bfcf Serial example 2020-07-08 18:32:30 -07:00
lazarov 53ff1a2bf8 Merge branch 'master' into fad 2020-07-08 16:07:25 -07:00
lazarov 4b47d0eb63 Added support for FADBAD++ 2020-07-08 16:04:37 -07:00
lazarov 72aeb54227 The name of ADQIntegratorJ/H class is changed to ADQFunctionJ/H 2020-06-30 22:37:07 -07:00
lazarov 22c33cbdf6 Added:
*AD integrator for pLaplacian
*Select between AD integrator and hond coded integrator
2020-06-26 10:13:24 -07:00
lazarov 5287c9f509 Added configuration for CODIPACK 2020-06-18 18:13:09 -07:00
lazarov fa2db9abf2 Intermediate updates 2020-06-18 18:12:22 -07:00
lazarov a8a7bc4e40 Native implementation before adding adept 2020-06-18 16:20:59 -07:00
lazarov 1e04cf7798 Merge branch 'master' into fad 2020-06-12 19:30:04 -07:00
bslazarov fa718bab9a modified: ../../examples/CMakeLists.txt
new file:   ../../examples/ex23.cpp
	modified:   ../../fem/CMakeLists.txt
	new file:   ../../fem/adnonlininteg.cpp
	new file:   ../../fem/adnonlininteg.hpp
	modified:   ../../fem/fem.hpp
	modified:   ../../linalg/fdual.hpp
	new file:   ../../linalg/taddensemat.hpp
	new file:   ../../linalg/tadvector.hpp
2020-02-25 20:27:28 -08:00
bslazarov 84209babd2 modified: fdual.hpp
modified:   ../tests/unit/linalg/test_fdual.cpp
2020-02-16 23:34:17 -08:00
bslazarov e940331e39 new file: ../../linalg/fdual.hpp
modified:   ../../linalg/linalg.hpp
	modified:   ../../tests/unit/CMakeLists.txt
	new file:   ../../tests/unit/linalg/test_fdual.cpp
2020-02-14 17:48:25 -08:00
135 changed files with 6479 additions and 12766 deletions
+5 -9
View File
@@ -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
-5
View File
@@ -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
View File
@@ -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 "")
+28
View File
@@ -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
+3
View File
@@ -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@")
+9
View File
@@ -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
+23
View File
@@ -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.")
+23
View File
@@ -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)
+10
View File
@@ -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
+3
View File
@@ -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@
+10
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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()
+348
View File
@@ -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;
}
+587
View File
@@ -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
+401
View File
@@ -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
View File
@@ -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
View File
@@ -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
)
+402
View File
@@ -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
+73 -275
View File
@@ -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);
+40 -49
View File
@@ -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
View File
@@ -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.");
}
-8
View File
@@ -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)
{
-27
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+10 -52
View File
@@ -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");
-10
View File
@@ -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
View File
@@ -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
+9 -41
View File
@@ -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
-21
View File
@@ -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)
-9
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+15 -33
View File
@@ -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,
-208
View File
@@ -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
-233
View File
@@ -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
-110
View File
@@ -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
-79
View File
@@ -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
+2 -3
View File
@@ -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);
-282
View File
@@ -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
-109
View File
@@ -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
-76
View File
@@ -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
-303
View File
@@ -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
-110
View File
@@ -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
-101
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-161
View File
@@ -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
-96
View File
@@ -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
-128
View File
@@ -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
-107
View File
@@ -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
-247
View File
@@ -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
-125
View File
@@ -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
-150
View File
@@ -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
-123
View File
@@ -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
-132
View File
@@ -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
-111
View File
@@ -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
-281
View File
@@ -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
-129
View File
@@ -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
-178
View File
@@ -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
-181
View File
@@ -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
-155
View File
@@ -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
-162
View File
@@ -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
-159
View File
@@ -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
-166
View File
@@ -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
-148
View File
@@ -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
-186
View File
@@ -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
-154
View File
@@ -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
-155
View File
@@ -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
-139
View File
@@ -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
-165
View File
@@ -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
-148
View File
@@ -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
View File
@@ -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
View File
@@ -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,
-1
View File
@@ -35,7 +35,6 @@ list(APPEND HDRS
backends.hpp
binaryio.hpp
cuda.hpp
debug.hpp
device.hpp
error.hpp
gecko.hpp
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
-178
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-699
View File
@@ -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
View File
@@ -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
+628
View File
@@ -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
-1
View File
@@ -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