Compare commits

..
Author SHA1 Message Date
Will Pazner 35cea24e21 Move face map logic from restriction.cpp into FiniteElement derived classes
Use inheritance instead of switch statement to dispatch
2023-01-09 20:46:51 -08:00
Will Pazner 9732e4dc6f Make SupportsDevice const
In both LinearFormIntegrator and LinearForm classes
2023-01-09 19:40:21 -08:00
Will Pazner 035301c212 Comment 2023-01-09 19:35:51 -08:00
Will Pazner f6efd6e56b Fix comment 2023-01-09 19:17:26 -08:00
Will Pazner 896922fbe4 Update CHANGELOG 2023-01-08 17:14:57 -08:00
Will Pazner f726606b96 Add GetFaceNormal3D to help manage 3D hexahedron face cases 2023-01-05 08:55:45 -08:00
Will Pazner 02fa406807 Refactor FillFaceMap and add explanatory comment 2023-01-05 08:55:20 -08:00
Will Pazner 1e34a98337 ND face restriction 2023-01-05 08:55:19 -08:00
Will Pazner bbd28f5f45 VectorFEBoundaryFluxLFIntegrator kernel in 3D 2023-01-04 18:49:04 -08:00
Will Pazner f413481bff RT face restriction in 3D 2023-01-04 18:49:04 -08:00
Will Pazner 61a922a812 Fix Mesh::FaceInformation output with operator<<
Newline was missing after face topology.

Also use '\n' instead of std::endl for all but last newline since there is no
reason to flush the buffer before then.
2023-01-04 18:48:46 -08:00
Will Pazner 25ba954475 Test device kernel for VectorFEBoundaryFluxLFIntegrator in 2D 2023-01-04 18:48:46 -08:00
Will Pazner a9829da2cb Add device kernel for VectorFEBoundaryFluxLFIntegrator 2023-01-04 18:48:46 -08:00
Will Pazner 1b2ab9253b Add test case for 2D RT face restriction 2023-01-04 18:48:44 -08:00
Will Pazner 067f571dc4 Support 2D RT elements in H1_ND_RT_FaceRestriction 2023-01-04 14:18:27 -08:00
Will Pazner 452cf127c6 Rename H1FaceRestriction to H1_ND_RT_FaceRestriction
The same class should be able to be used for H1, ND, and RT spaces
2023-01-04 14:18:27 -08:00
Will Pazner 328df07f5d Refactor GetFaceDofs to use offset and strides 2023-01-04 14:18:27 -08:00
145 changed files with 1899 additions and 9196 deletions
+1 -1
View File
@@ -141,7 +141,7 @@ jobs:
- name: get MPI (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
uses: mpi4py/setup-mpi@v1.1.4
uses: mpi4py/setup-mpi@v1.1.2
# Get Hypre through cache, or build it.
# Install will only run on cache miss.
-11
View File
@@ -131,12 +131,6 @@ examples/hiop/ex9-mesh.*
examples/hiop/ex9-init.*
examples/hiop/ex9-final.*
examples/ipopt/exContactBlockTL
examples/ipopt/exContactBlockTL.mesh
examples/ipopt/exContactBlockTL-mesh.*
examples/ipopt/exContactBlockTL-init.*
examples/ipopt/exContactBlockTL-final.*
examples/petsc/ex[1-69]p
examples/petsc/ex1[0-1]p
examples/petsc/mesh.*
@@ -209,7 +203,6 @@ miniapps/meshing/mesh-explorer
miniapps/meshing/shaper
miniapps/meshing/extruder
miniapps/meshing/trimmer
miniapps/meshing/reflector
miniapps/meshing/mesh-optimizer
miniapps/meshing/pmesh-optimizer
miniapps/meshing/minimal-surface
@@ -221,12 +214,9 @@ miniapps/meshing/toroid-*.mesh
miniapps/meshing/twist-*.mesh
miniapps/meshing/mesh-explorer.mesh
miniapps/meshing/partitioning.txt
miniapps/meshing/mesh-explorer-visit*
miniapps/meshing/mesh-explorer-paraview/
miniapps/meshing/shaper.mesh
miniapps/meshing/extruder.mesh
miniapps/meshing/trimmer.mesh
miniapps/meshing/reflected.mesh
miniapps/meshing/optimized*
miniapps/meshing/perturbed*
miniapps/meshing/polar-nc.mesh
@@ -286,7 +276,6 @@ miniapps/tools/convert-dc
miniapps/tools/lor-transfer
miniapps/tools/get-values
miniapps/tools/check-tmop-metric
miniapps/tools/tmop-metric-magnitude
miniapps/toys/automata
miniapps/toys/life
+1 -1
View File
@@ -93,7 +93,7 @@ report_baseline:
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
-41
View File
@@ -1,41 +0,0 @@
#!/bin/bash
# Copyright (c) 2010-2022, 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.
# Try to push to the remote 5 times. If the push fails, and the local and remote
# have diverged, then pull from the remote to merge changes, and try pushing
# again. If some other failure happens
for i in {1..5}; do
git push origin master && exit 0
# Wait for 20 seconds in case someone else is pushing to the remote
# concurrently
sleep 20
# Fetch any updates from the remote
git remote update
# Get the latest commit on the local branch
LOCAL=$(git rev-parse @)
# Get the latest commit on the remote
REMOTE=$(git rev-parse @{u})
# Get the common ancestor
BASE=$(git merge-base @ @{u})
# Have the local and remote diverged?
if [[ $LOCAL != $REMOTE && $LOCAL != $BASE && $REMOTE != $BASE ]]; then
git pull
if [[ $? == 0 ]]; then
continue
else
exit 1 # Something else went wrong trying to pull
fi
fi
done
exit 1 # Did not succeed in 5 attempts
@@ -32,7 +32,7 @@ if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
@@ -29,7 +29,7 @@ if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
+5 -24
View File
@@ -10,26 +10,18 @@
Version 4.5.1 (development)
===========================
- When using discontinuous (L2) spaces, use local (element-wise) L2 projection
as the coarsening operator for non-conforming AMR meshes.
Meshing improvements
--------------------
- Added support for pyramids in non-conforming meshes. Currently only isotropic
refinement is supported in this case.
- Updated logic in FindPointsGSLIB to ignore points found near (but outside) the
domain boundary.
- Added support for pyramids in Gmsh meshes.
- Fixed a bug in TMOP metric 301.
- Added an option to auto-balance compound TMOP metrics.
Discretization improvements
---------------------------
- TBD
- Face restriction operators for Nedelec and Raviart-Thomas finite element
spaces are now supported through the H1_ND_RT_FaceRestriction class.
- VectorFEBoundaryFluxLFIntegrator is now supported on device/GPU.
Linear and nonlinear solvers
----------------------------
@@ -38,12 +30,7 @@ Linear and nonlinear solvers
New and updated examples and miniapps
-------------------------------------
- Added a new meshing miniapp, reflector, which reflects a high-order or NURBS
hexahedral mesh about a plane.
- The mesh-explorer miniapp can now save mesh files in the VisIt or ParaView
formats using the corresponding DataCollection objects. See option 'D' in the
main menu.
- TBD
Integrations, testing and documentation
---------------------------------------
@@ -69,9 +56,6 @@ API changes
have been deprecated and generate deprecation warnings if used. They will be
removed in a future release.
- The methods Mesh::GetFaceBaseGeometry and Mesh::GetFaceGeometryType have been
deprecated, and Mesh::GetFaceGeometry (which provides identical functionality)
should be used instead.
Version 4.5, released on October 22, 2022
=========================================
@@ -116,9 +100,6 @@ Discretization improvements
- Added a class CoefficientVector for efficient access of variable coefficient
values at quadrature points (in particular for GPU/device kernels).
- Added support for GridFunction::GetGradients() and
GriFunction::GetVectorGradient() on face-neighbor elements.
- Added WhiteGaussianNoiseDomainLFIntegrator: a LinearFormIntegrator class for
spatial Gaussian white noise.
+4 -16
View File
@@ -134,7 +134,8 @@ if (MFEM_USE_CUDA)
set(CUDA_FLAGS "-ccbin=${CMAKE_CXX_COMPILER} ${CUDA_FLAGS}")
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CMAKE_CXX_COMPILER})
endif()
set(CMAKE_CUDA_FLAGS ${CMAKE_CUDA_FLAGS} ${CUDA_FLAGS})
set(CMAKE_CUDA_FLAGS "${CUDA_FLAGS}" CACHE STRING
"CUDA flags set for MFEM" FORCE)
set(CUSPARSE_FOUND TRUE)
set(CUSPARSE_LIBRARIES "cusparse")
set(CUBLAS_FOUND TRUE)
@@ -404,15 +405,6 @@ if (MFEM_USE_HIOP)
# find_package updates HIOP_FOUND, HIOP_INCLUDE_DIRS, HIOP_LIBRARIES
endif()
# IpOpt optimizer
if (MFEM_USE_IPOPT)
find_package(IPOPT REQUIRED)
message(
STATUS
"IPOPT_INCLUDE_DIRS=${IPOPT_INCLUDE_DIRS}, IPOPT_LIBRARIES=${IPOPT_LIBRARIES}, IPOPT_DIR=${IPOPT_DIR}")
# find_package updates IPOPT_FOUND, IPOPT_INCLUDE_DIRS, IPOPT_LIBRARIES
endif()
# CoDiPack package
if (MFEM_USE_CODIPACK)
find_package(CODIPACK REQUIRED)
@@ -508,7 +500,7 @@ find_package(Threads REQUIRED)
# be before SuiteSparse.
set(MFEM_TPLS OPENMP HYPRE LAPACK BLAS SuperLUDist STRUMPACK METIS SuiteSparse
SUNDIALS PETSC SLEPC MUMPS AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB
NETCDF MPFR PUMI HIOP IPOPT POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
ADIOS2 CUBLAS CUSPARSE MKL_CPARDISO AMGX CALIPER CODIPACK BENCHMARK PARELAG
MPI_CXX HIP HIPSPARSE MOONOLITH BLITZ ALGOIM ENZYME)
@@ -706,8 +698,6 @@ add_subdirectory(doc)
message(STATUS "CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}")
set(INSTALL_INCLUDE_DIR include
CACHE PATH "Relative path for installing header files.")
set(INSTALL_BIN_DIR bin
CACHE PATH "Relative path for installing the binaries.")
set(INSTALL_LIB_DIR lib
CACHE PATH "Relative path for installing the library.")
# other options: "share/mfem/cmake", "lib/mfem/cmake"
@@ -726,9 +716,7 @@ set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Development)
# Install the library
install(TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME_UC}Targets
RUNTIME DESTINATION ${INSTALL_BIN_DIR}
LIBRARY DESTINATION ${INSTALL_LIB_DIR}
ARCHIVE DESTINATION ${INSTALL_LIB_DIR})
DESTINATION ${INSTALL_LIB_DIR})
# Install the master headers
foreach(Header mfem.hpp mfem-performance.hpp)
-1
View File
@@ -112,7 +112,6 @@ The MFEM source code has the following structure:
│ ├── caliper
│ ├── ginkgo
│ ├── hiop
│ ├── ipopt
│ ├── jupyter
│ ├── moonolith
│ ├── petsc
-10
View File
@@ -471,9 +471,6 @@ 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_IPOPT = YES/NO
Enable the usage of Ipopt in MFEM.
MFEM_USE_CODIPACK = YES/NO
Enable automatic differentiation using the CoDiPack library.
www.scicomp.uni-kl.de/codi/
@@ -741,11 +738,6 @@ The specific libraries and their options are:
Options: HIOP_OPT, HIOP_LIB.
Versions: HIOP >= 0.4.6.
- Ipopt (optional), used when MFEM_USE_IPOPT = YES.
URL: https://github.com/coin-or/Ipopt
Options: IPOPT_OPT, IPOPT_LIB.
Versions: IPOPT >= 3.14
- CoDiPack (optional), used with MFEM_USE_CODIPACK = YES
URL: https://www.scicomp.uni-kl.de/codi/
Options: CODIPACK_OPT
@@ -980,7 +972,6 @@ MFEM_USE_MPFR
MFEM_USE_ZLIB
MFEM_USE_PUMI
MFEM_USE_HIOP
MFEM_USE_IPOPT
MFEM_USE_CODIPACK
MFEM_USE_ADFORWARD
MFEM_USE_CUDA
@@ -1044,7 +1035,6 @@ The CMake build system adds auto-detection for the following packages/libraries:
- POSIXCLOCKS
- PUMI
- HIOP
- IPOPT
- CoDiPack
- OCCA
- RAJA
-1
View File
@@ -36,7 +36,6 @@ set(MFEM_USE_STRUMPACK @MFEM_USE_STRUMPACK@)
set(MFEM_USE_GINKGO @MFEM_USE_GINKGO@)
set(MFEM_USE_AMGX @MFEM_USE_AMGX@)
set(MFEM_USE_HIOP @MFEM_USE_HIOP@)
set(MFEM_USE_IPOPT @MFEM_USE_IPOPT@)
set(MFEM_USE_GNUTLS @MFEM_USE_GNUTLS@)
set(MFEM_USE_GSLIB @MFEM_USE_GSLIB@)
set(MFEM_USE_NETCDF @MFEM_USE_NETCDF@)
-3
View File
@@ -131,9 +131,6 @@
// Enable MFEM functionality based on the HiOp library
#cmakedefine MFEM_USE_HIOP
// Enable MFEM functionality based on the Ipopt library
#cmakedefine MFEM_USE_IPOPT
// Build the GPU/CUDA-enabled version of the MFEM library.
// Requires a CUDA compiler (nvcc).
#cmakedefine MFEM_USE_CUDA
+3 -3
View File
@@ -16,7 +16,7 @@
include(MfemCmakeUtilities)
mfem_find_package(Algoim ALGOIM ALGOIM_DIR
"include;src" "algoim_quad.hpp"
"include" "algoim_quad.hpp"
"" ""
"Paths to headers required by Algoim."
"Libraries required by Algoim.")
"Paths to headers required by Algoim."
"Libraries required by Algoim.")
-23
View File
@@ -1,23 +0,0 @@
# Copyright (c) 2010-2022, 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.
# Sets the following variables:
# - IPOPT_FOUND
# - IPOPT_INCLUDE_DIRS
# - IPOPT_LIBRARIES
include(MfemCmakeUtilities)
mfem_find_package(IPOPT IPOPT IPOPT_DIR
"include" "IpTNLP.hpp"
"lib" "ipopt"
"Paths to headers required by IPOPT."
"Libraries required by IPOPT.")
@@ -869,7 +869,7 @@ function(mfem_export_mk_files)
MFEM_USE_SUPERLU MFEM_USE_SUPERLU5 MFEM_USE_MUMPS MFEM_USE_STRUMPACK
MFEM_USE_GINKGO MFEM_USE_AMGX MFEM_USE_GNUTLS MFEM_USE_NETCDF
MFEM_USE_PETSC MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_FMS
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_IPOPT MFEM_USE_GSLIB MFEM_USE_CUDA
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA
MFEM_USE_HIP MFEM_USE_RAJA MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_CALIPER
MFEM_USE_UMPIRE MFEM_USE_SIMD MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO
MFEM_USE_ADFORWARD MFEM_USE_CODIPACK MFEM_USE_BENCHMARK MFEM_USE_PARELAG
-3
View File
@@ -141,9 +141,6 @@
// Enable MFEM functionality based on the HIOP library.
// #define MFEM_USE_HIOP
// Enable MFEM functionality based on the IPOPT library.
// #define MFEM_USE_IPOPT
// Enable MFEM functionality based on the GSLIB library
// #define MFEM_USE_GSLIB
-1
View File
@@ -46,7 +46,6 @@ MFEM_USE_FMS = @MFEM_USE_FMS@
MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@
MFEM_USE_PUMI = @MFEM_USE_PUMI@
MFEM_USE_HIOP = @MFEM_USE_HIOP@
MFEM_USE_IPOPT = @MFEM_USE_IPOPT@
MFEM_USE_GSLIB = @MFEM_USE_GSLIB@
MFEM_USE_CUDA = @MFEM_USE_CUDA@
MFEM_USE_HIP = @MFEM_USE_HIP@
+1 -6
View File
@@ -48,7 +48,6 @@ option(MFEM_USE_FMS "Enable FMS usage" OFF)
option(MFEM_USE_CONDUIT "Enable Conduit usage" OFF)
option(MFEM_USE_PUMI "Enable PUMI" OFF)
option(MFEM_USE_HIOP "Enable HiOp" OFF)
option(MFEM_USE_IPOPT "Enable Ipopt" OFF)
option(MFEM_USE_CUDA "Enable CUDA" OFF)
option(MFEM_USE_HIP "Enable HIP" OFF)
option(MFEM_USE_OCCA "Enable OCCA" OFF)
@@ -221,10 +220,6 @@ set(HIOP_DIR "${MFEM_DIR}/../hiop/install" CACHE STRING
"Directory where HiOp is installed")
set(HIOP_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
"Packages that HiOp depends on.")
set(IPOPT_DIR "${MFEM_DIR}/../ipopt/install" CACHE STRING
"Directory where IpOpt is installed")
set(IPOPT_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
"Packages that IpOpt depends on.")
set(MKL_CPARDISO_DIR "" CACHE STRING "MKL installation path.")
set(MKL_MPI_WRAPPER_LIB "mkl_blacs_mpich_lp64" CACHE STRING "MKL MPI wrapper library")
@@ -237,7 +232,7 @@ set(UMPIRE_DIR "${MFEM_DIR}/../umpire" CACHE PATH "Path to Umpire")
set(CALIPER_DIR "${MFEM_DIR}/../caliper" CACHE PATH "Path to Caliper")
set(BLITZ_DIR "${MFEM_DIR}/../blitz" CACHE PATH "Path to Blitz")
set(ALGOIM_DIR "${MFEM_DIR}/../algoim" CACHE PATH "Path to Algoim")
set(Algoim_REQUIRED_PACKAGES "Blitz" CACHE STRING
set(ALGOIM_REQUIRED_PACKAGES "BLITZ" CACHE STRING
"Packages that ALGOIM depends on.")
set(BENCHMARK_DIR "${MFEM_DIR}/../google-benchmark" CACHE PATH
-6
View File
@@ -148,7 +148,6 @@ MFEM_USE_FMS = NO
MFEM_USE_CONDUIT = NO
MFEM_USE_PUMI = NO
MFEM_USE_HIOP = NO
MFEM_USE_IPOPT = NO
MFEM_USE_GSLIB = NO
MFEM_USE_CUDA = NO
MFEM_USE_HIP = NO
@@ -448,11 +447,6 @@ HIOP_DIR = @MFEM_DIR@/../hiop/install
HIOP_OPT = -I$(HIOP_DIR)/include
HIOP_LIB = -L$(HIOP_DIR)/lib -lhiop $(LAPACK_LIB)
# IPOPT
IPOPT_DIR = @MFEM_DIR@/../ipopt/install
IPOPT_OPT = -I$(IPOPT_DIR)/include
IPOPT_LIB = -L$(IPOPT_DIR)/lib -lipopt $(LAPACK_LIB)
# CoDiPack
CODIPACK_DIR = @MFEM_DIR@/../CoDiPack
CODIPACK_OPT = -I$(CODIPACK_DIR)
-8
View File
@@ -58,10 +58,6 @@ groups_serial=(
"HiOp examples:"
"examples/hiop"
"ex9.cpp"'
'"ipopt"
"IpOpt examples:"
"examples/ipopt"
"ex10.cpp"'
'"pumi"
"PUMI examples:"
"examples/pumi"
@@ -219,10 +215,6 @@ groups_all=(
"HiOp examples:"
"examples/hiop"
"ex9.cpp ex9p.cpp"'
'"ipopt"
"IpOpt examples:"
"examples/ipopt"
"ex10.cpp"'
'"pumi"
"PUMI examples:"
"examples/pumi"
-1
View File
@@ -785,7 +785,6 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/examples/caliper \
@MFEM_SOURCE_DIR@/examples/ginkgo \
@MFEM_SOURCE_DIR@/examples/hiop \
@MFEM_SOURCE_DIR@/examples/ipopt \
@MFEM_SOURCE_DIR@/examples/moonolith \
@MFEM_SOURCE_DIR@/examples/petsc \
@MFEM_SOURCE_DIR@/examples/pumi \
-5
View File
@@ -178,11 +178,6 @@ if (MFEM_USE_HIOP)
add_subdirectory(hiop)
endif()
# Include the examples/ipopt directory if IpOpt is enabled
if (MFEM_USE_IPOPT)
add_subdirectory(ipopt)
endif()
# Include the examples/petsc directory if PETSc is enabled.
if (MFEM_USE_PETSC)
add_subdirectory(petsc)
-810
View File
@@ -1,810 +0,0 @@
// Contact example
//
// Compile with: make contact
//
// Sample runs: ./contact -m1 block1.mesh -m2 block2.mesh -at "5 6 7 8"
// Sample runs: ./contact -m1 block1_d.mesh -m2 block2_d.mesh -at "5 6 7 8"
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include "nodepair.hpp"
using namespace std;
using namespace mfem;
bool ifequalarray(const Array<int> a1, const Array<int> a2)
{
if (a1.Size()!=a2.Size())
{
return false;
}
for (int i=0; i<a1.Size(); i++)
{
if (a1[i] != a2[i])
{
return false;
}
}
return true;
}
void FindSurfaceToProject(Mesh& mesh, const int elem, int& cbdrface)
{
Array<int> attr;
attr.Append(2);
Array<int> faces;
Array<int> ori;
std::vector<Array<int> > facesVertices;
std::vector<int > faceid;
mesh.GetElementFaces(elem, faces, ori);
int face = -1;
for (int i=0; i<faces.Size(); i++)
{
face = faces[i];
Array<int> faceVert;
if (!mesh.FaceIsInterior(face)) // if on the boundary
{
mesh.GetFaceVertices(face, faceVert);
faceVert.Sort();
facesVertices.push_back(faceVert);
faceid.push_back(face);
}
}
int bdrface = facesVertices.size();
Array<int> bdryFaces;
// This shoulnd't need to be rebuilt
std::vector<Array<int> > bdryVerts;
for (int b=0; b<mesh.GetNBE(); ++b)
{
if (attr.FindSorted(mesh.GetBdrAttribute(b)) >= 0) // found the contact surface
{
bdryFaces.Append(b);
Array<int> vert;
mesh.GetBdrElementVertices(b, vert);
vert.Sort();
bdryVerts.push_back(vert);
}
}
int bdrvert = bdryVerts.size();
cbdrface = -1; // the face number of the contact surface element
int count_cbdrface = 0; // the number of matching surfaces, used for checks
for (int i=0; i<bdrface; i++)
{
for (int j=0; j<bdrvert; j++)
{
if (ifequalarray(facesVertices[i], bdryVerts[j]))
{
cbdrface = faceid[i];
count_cbdrface += 1;
}
}
}
MFEM_VERIFY(count_cbdrface == 1,"projection surface not found");
};
Vector GetNormalVector(Mesh & mesh, const int elem, const double *ref,
int & refFace, int & refNormal, bool & interior)
{
ElementTransformation *trans = mesh.GetElementTransformation(elem);
const int dim = mesh.Dimension();
const int spaceDim = trans->GetSpaceDim();
MFEM_VERIFY(spaceDim == 3, "");
Vector n(spaceDim);
IntegrationPoint ip;
ip.Set(ref, dim);
trans->SetIntPoint(&ip);
//CalcOrtho(trans->Jacobian(), n); // Works only for face transformations
const DenseMatrix jac = trans->Jacobian();
int dimNormal = -1;
int normalSide = -1;
const double tol = 1.0e-8;
for (int i=0; i<dim; ++i)
{
const double d0 = std::abs(ref[i]);
const double d1 = std::abs(ref[i] - 1.0);
const double d = std::min(d0, d1);
// TODO: this works only for hexahedral meshes!
if (d < tol)
{
MFEM_VERIFY(dimNormal == -1, "");
dimNormal = i;
if (d0 < tol)
{
normalSide = 0;
}
else
{
normalSide = 1;
}
}
}
// closest point on the boundary
if (dimNormal < 0 || normalSide < 0) // node is inside the element
{
interior = 1;
Vector n(3);
n = 0.0;
return n;
}
MFEM_VERIFY(dimNormal >= 0 && normalSide >= 0, "");
refNormal = dimNormal;
MFEM_VERIFY(dim == 3, "");
{
// Find the reference face
if (dimNormal == 0)
{
refFace = (normalSide == 1) ? 2 : 4;
}
else if (dimNormal == 1)
{
refFace = (normalSide == 1) ? 3 : 1;
}
else
{
refFace = (normalSide == 1) ? 5 : 0;
}
}
std::vector<Vector> tang(2);
int tangDir[2] = {-1, -1};
{
int t = 0;
for (int i=0; i<dim; ++i)
{
if (i != dimNormal)
{
tangDir[t] = i;
t++;
}
}
MFEM_VERIFY(t == 2, "");
}
for (int i=0; i<2; ++i)
{
tang[i].SetSize(3);
Vector tangRef(3);
tangRef = 0.0;
tangRef[tangDir[i]] = 1.0;
jac.Mult(tangRef, tang[i]);
}
Vector c(3); // Cross product
c[0] = (tang[0][1] * tang[1][2]) - (tang[0][2] * tang[1][1]);
c[1] = (tang[0][2] * tang[1][0]) - (tang[0][0] * tang[1][2]);
c[2] = (tang[0][0] * tang[1][1]) - (tang[0][1] * tang[1][0]);
c /= c.Norml2();
Vector nref(3);
nref = 0.0;
nref[dimNormal] = 1.0;
Vector ndir(3);
jac.Mult(nref, ndir);
ndir /= ndir.Norml2();
const double dp = ndir * c;
// TODO: eliminate c?
n = c;
if (dp < 0.0)
{
n *= -1.0;
}
interior = 0;
return n;
}
// WARNING: global variable, just for this little example.
std::array<std::array<int, 3>, 8> HEX_VERT =
{
{ {0,0,0},
{1,0,0},
{1,1,0},
{0,1,0},
{0,0,1},
{1,0,1},
{1,1,1},
{0,1,1}
}
};
int GetHexVertex(int cdim, int c, int fa, int fb, Vector & refCrd)
{
int ref[3];
ref[cdim] = c;
ref[cdim == 0 ? 1 : 0] = fa;
ref[cdim == 2 ? 1 : 2] = fb;
for (int i=0; i<3; ++i) { refCrd[i] = ref[i]; }
int refv = -1;
for (int i=0; i<8; ++i)
{
bool match = true;
for (int j=0; j<3; ++j)
{
if (ref[j] != HEX_VERT[i][j]) { match = false; }
}
if (match) { refv = i; }
}
MFEM_VERIFY(refv >= 0, "");
return refv;
}
// Coordinates in xyz are assumed to be ordered as [X, Y, Z]
// where X is the list of x-coordinates for all points and so on.
// conn: connectivity of the target surface elements
// xi: surface reference cooridnates for the cloest point, involves a linear transformation from [0,1] to [-1,1]
void FindPointsInMesh(Mesh & mesh, Vector const& xyz, Array<int>& conn,
Vector& xi)
{
const int dim = mesh.Dimension();
const int np = xyz.Size() / dim;
MFEM_VERIFY(np * dim == xyz.Size(), "");
mesh.EnsureNodes();
//FindPointsGSLIB finder(MPI_COMM_WORLD);
FindPointsGSLIB finder;
finder.SetDistanceToleranceForPointsFoundOnBoundary(0.5);
const double bb_t = 0.5;
finder.Setup(mesh, bb_t);
finder.FindPoints(xyz);
/// Return code for each point searched by FindPoints: inside element (0), on
/// element boundary (1), or not found (2).
Array<unsigned int> codes = finder.GetCode();
/// Return element number for each point found by FindPoints.
Array<unsigned int> elems = finder.GetElem();
/// Return reference coordinates for each point found by FindPoints.
Vector refcrd = finder.GetReferencePosition();
/// Return distance between the sought and the found point in physical space,
/// for each point found by FindPoints.
Vector dist = finder.GetDist();
MFEM_VERIFY(dist.Size() == np, "");
MFEM_VERIFY(refcrd.Size() == np * dim, "");
MFEM_VERIFY(elems.Size() == np, "");
MFEM_VERIFY(codes.Size() == np, "");
bool allfound = true;
for (auto code : codes)
if (code == 2) { allfound = false; }
MFEM_VERIFY(allfound, "A point was not found");
cout << "Maximum distance of projected points: " << dist.Max() << endl;
// extract information
for (int i=0; i<np; ++i)
{
/*cout << "Point " << i << ": (";
for (int j=0; j<dim; ++j)
{
cout << xyz[i + (j*np)];
if (j == dim-1) {cout << ")" << endl;}
else{cout << ", ";}
}*/
//cout << " element: " << elems[i] << endl;
//cout << " element " << elems[i] << " vertices:" << endl;
//Array<int> vert;
//mesh.GetElementVertices(elems[i], vert);
//for (auto v : vert)
//{
// cout << " " << v << endl;
//}
/*cout << " reference coordinates: (";
for (int j=0; j<dim; ++j)
{
cout << refcrd[(i*dim) + j];
if (j == dim-1)
{
cout << ")" << endl;
}
else
{
cout << ", ";
}
}*/
int refFace, refNormal, refNormalSide;
bool is_interior = -1;
Vector normal = GetNormalVector(mesh, elems[i], refcrd.GetData() + (i*dim),
refFace, refNormal, is_interior);
int phyFace;
if (is_interior)
{
phyFace = -1; // the id of the face that has the closest point
FindSurfaceToProject(mesh, elems[i], phyFace);
Array<int> cbdrVert;
mesh.GetFaceVertices(phyFace, cbdrVert);
Vector xs(dim);
xs[0] = xyz[i + 0*np];
xs[1] = xyz[i + 1*np];
xs[2] = xyz[i + 2*np];
Vector xi_tmp(dim-1);
// get nodes!
GridFunction *nodes = mesh.GetNodes();
DenseMatrix coords(4,3);
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
coords(i,j) = (*nodes)[cbdrVert[i]*3+j];
}
}
SlaveToMaster(coords, xs, xi_tmp);
for (int j=0; j<dim-1; ++j)
{
xi[i*(dim-1)+j] = xi_tmp[j];
}
// now get get the projection to the surface
}
else
{
Vector faceRefCrd(dim-1);
{
int fd = 0;
for (int j=0; j<dim; ++j)
{
if (j == refNormal)
{
refNormalSide = (refcrd[(i*dim) + j] > 0.5);
}
else
{
faceRefCrd[fd] = refcrd[(i*dim) + j];
fd++;
}
}
MFEM_VERIFY(fd == dim-1, "");
}
for (int j=0; j<dim-1; ++j)
{
xi[i*(dim-1)+j] = faceRefCrd[j]*2.0 - 1.0;
}
//cout << " face reference coordinates: (";
/*for (int j=0; j<dim-1; ++j)
{
cout << faceRefCrd[j];
if (j == dim-2){cout << ")" << endl;}
else{cout << ", ";}
}*/
}
//cout << " normal vector: ";
//normal.Print();
// ask, does this do anything?
/*
IntegrationPoint ip;
ip.Set(refcrd.GetData() + (i*dim), dim);
ElementTransformation *trans = mesh.GetElementTransformation(elems[i]);
Vector phys(trans->GetSpaceDim());
trans->Transform(ip, phys);
cout << " physical coordinates: ";
phys.Print();
*/
// Get the element face
Array<int> faces;
Array<int> ori;
int face;
if (is_interior)
{
face = phyFace;
}
else
{
mesh.GetElementFaces(elems[i], faces, ori);
face = faces[refFace];
}
Array<int> faceVert;
mesh.GetFaceVertices(face, faceVert);
//cout << " face " << face << " vertices:" << endl;
//for (auto v : faceVert){ cout << " " << v << endl;}
for (int p=0; p<4; p++)
{
conn[4*i+p] = faceVert[p];
}
/*
Vector ref(dim);
for (int p=0; p<2; ++p)
for (int q=0; q<2; ++q)
{
const int refv = GetHexVertex(refNormal, refNormalSide, p, q, ref);
cout << " face reference vertex (" << p << "," << q
<< ") is global vertex " << vert[refv] << endl;
{
// Sanity check
ip.Set(ref.GetData(), dim);
trans->Transform(ip, phys);
for (int j=0; j<dim; ++j)
{
phys[j] -= mesh.GetVertex(vert[refv])[j];
}
phys.Print();
cout<<vert[refv]<<endl;
cout<<mesh.GetVertex(vert[refv])[0]<<endl;
cout<<mesh.GetVertex(vert[refv])[1]<<endl;
cout<<mesh.GetVertex(vert[refv])[2]<<endl;
MFEM_VERIFY(phys.Norml2() < 1.0e-12, "Sanity check failed");
}
}*/
}
}
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file1 = "block1.mesh";
const char *mesh_file2 = "block2.mesh";
Array<int> attr;
Array<int> m_attr;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file1, "-m1", "--mesh1",
"First mesh file to use.");
args.AddOption(&mesh_file2, "-m2", "--mesh2",
"Second mesh file to use.");
args.AddOption(&attr, "-at", "--attributes-surf",
"Attributes of boundary faces on contact surface for mesh 2.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
Mesh mesh1(mesh_file1, 1, 1);
Mesh mesh2(mesh_file2, 1, 1);
{
char vishost[] = "localhost";
int visport = 19916;
socketstream mesh1a_sock(vishost, visport);
mesh1a_sock.precision(8);
mesh1a_sock << "mesh\n" << mesh1 << flush;
socketstream mesh2a_sock(vishost, visport);
mesh2a_sock.precision(8);
mesh2a_sock << "mesh\n" << mesh2 << flush;
}
const int dim = mesh1.Dimension();
MFEM_VERIFY(dim == mesh2.Dimension(), "");
// boundary attribute 2 is the potential contact surface of nodes
attr.Append(2);
// boundary attribute 2 is the potential contact surface for master surface
m_attr.Append(2);
// Define a finite element space on the mesh. Here we use vector finite
// elements, i.e. dim copies of a scalar finite element space. The vector
// dimension is specified by the last argument of the FiniteElementSpace
// constructor.
FiniteElementCollection *fec1;
FiniteElementSpace *fespace1;
fec1 = new H1_FECollection(1, dim);
fespace1 = new FiniteElementSpace(&mesh1, fec1, dim, Ordering::byVDIM);
cout << "Number of finite element unknowns for mesh1: "
<< fespace1->GetTrueVSize() << endl;
mesh1.SetNodalFESpace(fespace1);
GridFunction nodes0 = *mesh1.GetNodes(); // undeformed mesh1 nodal grid function
GridFunction *nodes1 = mesh1.GetNodes();
FiniteElementCollection *fec2 = new H1_FECollection(1, dim);
FiniteElementSpace *fespace2 = new FiniteElementSpace(&mesh2, fec2, dim,
Ordering::byVDIM);
cout << "Number of finite element unknowns for mesh2: "
<< fespace2->GetTrueVSize() << endl;
// degrees of freedom of both meshes
int ndof_1 = fespace1->GetTrueVSize();
int ndof_2 = fespace2->GetTrueVSize();
int ndofs = ndof_1 + ndof_2;
// number of nodes for each mesh
int nnd_1 = mesh1.GetNV();
int nnd_2 = mesh2.GetNV();
int nnd = nnd_1 + nnd_2;
// Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking only
// boundary attribute 1 from the mesh as essential and converting it to a
// list of true dofs.
Array<int> ess_tdof_list1, ess_bdr1(mesh1.bdr_attributes.Max());
ess_bdr1 = 0;
//ess_bdr1[0] = 1;
// Not ready to be passed on yet
// fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
Array<int> ess_tdof_list2, ess_bdr2(mesh2.bdr_attributes.Max());
ess_bdr2 = 0;
//ess_bdr2[0] = 1;
// Define the displacement vector x as a finite element grid function
// corresponding to fespace. GridFunction is a derived class of Vector.
GridFunction x1(fespace1);
x1 = 0.0;
GridFunction x2(fespace2);
x2 = 0.0;
// Generate force
LinearForm *b1 = new LinearForm(fespace1);
b1->Assemble();
LinearForm *b2 = new LinearForm(fespace2);
b2->Assemble();
// Set up the bilinear form a(.,.) on the finite element space
// corresponding to the linear elasticity integrator with piece-wise
// constants coefficient lambda and mu.
Vector lambda1(mesh1.attributes.Max());
lambda1 = 57.6923076923;
PWConstCoefficient lambda1_func(lambda1);
Vector mu1(mesh1.attributes.Max());
mu1 = 38.4615384615;
PWConstCoefficient mu1_func(mu1);
BilinearForm *a1 = new BilinearForm(fespace1);
a1->AddDomainIntegrator(new ElasticityIntegrator(lambda1_func,mu1_func));
Vector lambda2(mesh2.attributes.Max());
lambda2 = 57.6923076923;
PWConstCoefficient lambda2_func(lambda2);
Vector mu2(mesh2.attributes.Max());
mu2 = 38.4615384615;
PWConstCoefficient mu2_func(mu2);
BilinearForm *a2 = new BilinearForm(fespace2);
a2->AddDomainIntegrator(new ElasticityIntegrator(lambda2_func,mu2_func));
a1->Assemble();
SparseMatrix A1;
Vector B1, X1;
a1->FormLinearSystem(ess_tdof_list1, x1, *b1, A1, X1, B1);
a2->Assemble();
SparseMatrix A2;
Vector B2, X2;
a2->FormLinearSystem(ess_tdof_list2, x2, *b2, A2, X2, B2);
// Combine elasticity operator for two meshes into one.
// Block Matrix
SparseMatrix K(ndofs,ndofs);
for (int i=0; i<A1.Height(); i++)
{
Array<int> col_tmp;
Vector v_tmp;
col_tmp = 0;
v_tmp = 0.0;
A1.GetRow(i, col_tmp, v_tmp);
K.SetRow(i, col_tmp, v_tmp);
}
for (int i=0; i<A2.Height(); i++)
{
Array<int> col_tmp;
Vector v_tmp;
col_tmp = 0;
v_tmp = 0.0;
A2.GetRow(i, col_tmp, v_tmp);
for (int j=0; j<col_tmp.Size(); j++)
{
col_tmp[j] += ndof_1;
}
K.SetRow(i+ndof_1, col_tmp, v_tmp); // mesh1 top left corner
}
// Construct node to segment contact constraint.
attr.Sort();
cout << "Boundary attributes for contact surface faces in mesh 2" << endl;
for (auto a : attr) { cout << a << endl; }
Array<int> bdryFaces2; // TODO: remove this?
std::set<int> bdryVerts2;
for (int b=0; b<mesh2.GetNBE(); ++b)
{
if (attr.FindSorted(mesh2.GetBdrAttribute(b)) >= 0)
{
bdryFaces2.Append(b);
Array<int> vert;
mesh2.GetBdrElementVertices(b, vert);
for (auto v : vert)
{
bdryVerts2.insert(v);
}
}
}
int npoints = bdryVerts2.size();
Array<int> s_conn(npoints); // connectivity of the second/slave mesh
Vector xyz(dim * npoints);
xyz = 0.0;
cout << "Boundary vertices for contact surface vertices in mesh 2" << endl;
// construct the nodal coordinates on mesh2 to be projected, including displacement
int count = 0;
for (auto v : bdryVerts2)
{
cout << v << ": " << mesh2.GetVertex(v)[0] << ", "
<< mesh2.GetVertex(v)[1] << ", "
<< mesh2.GetVertex(v)[2] << endl;
for (int i=0; i<dim; ++i)
{
xyz[count + (i * npoints)] = mesh2.GetVertex(v)[i] + x2[v*dim+i];
}
s_conn[count] = v + nnd_1; // dof1 is the master
count++;
}
MFEM_VERIFY(count == npoints, "");
// gap function
Vector g(npoints*dim);
g = -1.0;
// segment reference coordinates of the closest point
Vector m_xi(npoints*(dim-1));
m_xi = -1.0;
Vector xs(dim*npoints);
xs = 0.0;
for (int i=0; i<npoints; i++)
{
for (int j=0; j<dim; j++)
{
xs[i*dim+j] = xyz[i + (j*npoints)];
}
}
Array<int> m_conn(
npoints*4); // only works for linear elements that have 4 vertices!
DenseMatrix coordsm(npoints*4, dim);
// adding displacement to mesh1 using a fixed grid function from mesh1
x1 = 1e-4; // x1 order: [xyz xyz... xyz]
add(nodes0, x1, *nodes1);
FindPointsInMesh(mesh1, xyz, m_conn, m_xi);
for (int i=0; i<npoints; i++)
{
for (int j=0; j<4; j++)
{
for (int k=0; k<dim; k++)
{
coordsm(i*4+j,k) = mesh1.GetVertex(m_conn[i*4+j])[k]+x1[dim*m_conn[i*4+j]+k];
}
}
}
//coordsm.Print();
SparseMatrix M(nnd,ndofs);
std::vector<SparseMatrix> dM(nnd, SparseMatrix(ndofs,ndofs));
Assemble_Contact(nnd, npoints, ndofs, xs, m_xi, coordsm,
s_conn, m_conn, g, M, dM);
std::set<int> dirbdryv2;
for (int b=0; b<mesh2.GetNBE(); ++b)
{
if (mesh2.GetBdrAttribute(b) == 1)
{
Array<int> vert;
mesh2.GetBdrElementVertices(b, vert);
for (auto v : vert)
{
dirbdryv2.insert(v);
}
}
}
std::set<int> dirbdryv1;
for (int b=0; b<mesh1.GetNBE(); ++b)
{
if (mesh1.GetBdrAttribute(b) == 1)
{
Array<int> vert;
mesh1.GetBdrElementVertices(b, vert);
for (auto v : vert)
{
dirbdryv1.insert(v);
}
}
}
Array<int> Dirichlet_dof;
Array<double> Dirichlet_val;
for (auto v : dirbdryv2)
{
for (int i=0; i<dim; ++i)
{
Dirichlet_dof.Append(v*dim + i + ndof_1);
Dirichlet_val.Append(0.);
}
}
double delta = 0.1;
for (auto v : dirbdryv1)
{
Dirichlet_dof.Append(v*dim + 0);
Dirichlet_val.Append(delta);
Dirichlet_dof.Append(v*dim + 1);
Dirichlet_val.Append(0.);
Dirichlet_dof.Append(v*dim + 2);
Dirichlet_val.Append(0.);
}
{
char vishost[] = "localhost";
int visport = 19916;
socketstream mesh1_sock(vishost, visport);
mesh1_sock.precision(8);
mesh1_sock << "mesh\n" << mesh1 << flush;
socketstream mesh2_sock(vishost, visport);
mesh2_sock.precision(8);
mesh2_sock << "mesh\n" << mesh2 << flush;
}
//M.Print();
/*Vector eps(ndofs);
Vector sol(ndofs); sol = 0.;
for(int i=0;i<ndofs;i++) eps[i] = 1e-5 * i ;
for(int i=0;i<9;i++)
{
cout<<i<<endl;
dM[s_conn[i]].Mult(eps,sol);
sol.Print();
}
*/
return 0;
}
-60
View File
@@ -1,60 +0,0 @@
# Copyright (c) 2010-2022, 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.
set(IPOPT_EXAMPLES_SRCS)
list(APPEND IPOPT_EXAMPLES_SRCS exContactBlockTL.cpp)
# Include the source directory where mfem.hpp and mfem-performance.hpp are.
include_directories(BEFORE ${PROJECT_BINARY_DIR})
# Add "test_ipopt" target, see below.
add_custom_target(test_ipopt
${CMAKE_CTEST_COMMAND} -R ipopt USES_TERMINAL)
# Add one executable per cpp file, adding "ipopt_" as prefix. Sets
# "test_ipopt" as a target that depends on the given examples.
set(PFX ipopt_)
add_mfem_examples(IPOPT_EXAMPLES_SRCS ${PFX} "" test_ipopt)
# Testing.
# The IPOPT tests can be run separately using the target "test_ipopt"
# which builds the examples and runs:
# ctest -R ipopt
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 9:
set(EXCONTACTBTL_COMMON_OPTS -m ../../data/periodic-segment.mesh -p 0 -dt 0.005)
set(EXCONTACTBTL_TEST_OPTS ${EXCONTACTBTL_COMMON_OPTS} -r 2 )
# Add the tests: one test per source file.
foreach(SRC_FILE ${IPOPT_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
-19
View File
@@ -1,19 +0,0 @@
Finite Element Discretization Library
__
_ __ ___ / _| ___ _ __ ___
| '_ ` _ \ | |_ / _ \| '_ ` _ \
| | | | | || _|| __/| | | | | |
|_| |_| |_||_| \___||_| |_| |_|
https://mfem.org
This directory contains modifications of the example codes that illustrate the
use of MFEM for solving nonlinear constrained optimization problems, including
features based on the IpOpt, a lightweight HPC solver for nonlinear optimization
problems.
To use the Ipopt features, make sure that MFEM is configured with the option
"MFEM_USE_IPOPT = YES", see the top-level INSTALL file for details.
We recommend comparing the original example codes with the corresponding files
in the current directory.
-103
View File
@@ -1,103 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
3
elements
9
1 5 0 1 3 2 8 9 11 10
1 5 2 3 5 4 10 11 13 12
1 5 4 5 7 6 12 13 15 14
1 5 8 9 11 10 16 17 19 18
1 5 10 11 13 12 18 19 21 20
1 5 12 13 15 14 20 21 23 22
1 5 16 17 19 18 24 25 27 26
1 5 18 19 21 20 26 27 29 28
1 5 20 21 23 22 28 29 31 30
# 0 nothing
# 1 dirichlet bc
# 2 contact
boundary
30
0 3 1 0 2 3
0 3 3 2 4 5
0 3 5 4 6 7
0 3 24 25 27 26
0 3 26 27 29 28
0 3 28 29 31 30
1 3 2 0 8 10
1 3 4 2 10 12
1 3 6 4 12 14
1 3 10 8 16 18
1 3 12 10 18 20
1 3 14 12 20 22
1 3 18 16 24 26
1 3 20 18 26 28
1 3 22 20 28 30
2 3 1 3 11 9
2 3 3 5 13 11
2 3 5 7 15 13
2 3 9 11 19 17
2 3 11 13 21 19
2 3 13 15 23 21
2 3 17 19 27 25
2 3 19 21 29 27
2 3 21 23 31 29
0 3 8 0 1 9
0 3 16 8 9 17
0 3 24 16 17 25
0 3 6 14 15 7
0 3 14 22 23 15
0 3 22 30 31 23
vertices
32
3
-1.0000 0 0
0 0 0
-1.0000 0.3333 0
0 0.3333 0
-1.0000 0.6667 0
0 0.6667 0
-1.0000 1.0000 0
0 1.0000 0
-1.0000 0 0.3333
0 0 0.3333
-1.0000 0.3333 0.3333
0 0.3333 0.3333
-1.0000 0.6667 0.3333
0 0.6667 0.3333
-1.0000 1.0000 0.3333
0 1.0000 0.3333
-1.0000 0 0.6667
0 0 0.6667
-1.0000 0.3333 0.6667
0 0.3333 0.6667
-1.0000 0.6667 0.6667
0 0.6667 0.6667
-1.0000 1.0000 0.6667
0 1.0000 0.6667
-1.0000 0 1.0000
0 0 1.0000
-1.0000 0.3333 1.0000
0 0.3333 1.0000
-1.0000 0.6667 1.0000
0 0.6667 1.0000
-1.0000 1.0000 1.0000
0 1.0000 1.0000
-68
View File
@@ -1,68 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
3
# 1 nothing
elements
4
1 5 0 1 3 2 6 7 9 8
1 5 2 3 5 4 8 9 11 10
1 5 6 7 9 8 12 13 15 14
1 5 8 9 11 10 14 15 17 16
# 0 nothing
# 1 dirichlet bc
# 2 contact
boundary
16
0 3 1 0 2 3
0 3 3 2 4 5
0 3 12 13 15 14
0 3 14 15 17 16
2 3 2 0 6 8
2 3 4 2 8 10
2 3 8 6 12 14
2 3 10 8 14 16
1 3 1 3 9 7
1 3 3 5 11 9
1 3 7 9 15 13
1 3 9 11 17 15
0 3 6 0 1 7
0 3 12 6 7 13
0 3 4 10 11 5
0 3 10 16 17 11
vertices
18
3
0 0.2464 0.2464
0.5071 0.2464 0.2464
0 0.5000 0.2464
0.5071 0.5000 0.2464
0 0.7536 0.2464
0.5071 0.7536 0.2464
0 0.2464 0.5000
0.5071 0.2464 0.5000
0 0.5000 0.5000
0.5071 0.5000 0.5000
0 0.7536 0.5000
0.5071 0.7536 0.5000
0 0.2464 0.7536
0.5071 0.2464 0.7536
0 0.5000 0.7536
0.5071 0.5000 0.7536
0 0.7536 0.7536
0.5071 0.7536 0.7536
-742
View File
@@ -1,742 +0,0 @@
// Contact example
//
// Compile with: make contact
//
// Sample runs: ./contact -m1 block1.mesh -m2 block2.mesh -at "5 6 7 8"
// Sample runs: ./contact -m1 block1_d.mesh -m2 block2_d.mesh -at "5 6 7 8"
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include "nodepair.hpp"
using namespace std;
using namespace mfem;
bool ifequalarray(const Array<int> a1, const Array<int> a2)
{
if (a1.Size()!=a2.Size())
{
return false;
}
for (int i=0; i<a1.Size(); i++)
{
if (a1[i] != a2[i])
{
return false;
}
}
return true;
}
void FindSurfaceToProject(Mesh& mesh, const int elem, int& cbdrface)
{
Array<int> attr;
attr.Append(2);
Array<int> faces;
Array<int> ori;
std::vector<Array<int> > facesVertices;
std::vector<int > faceid;
mesh.GetElementFaces(elem, faces, ori);
int face = -1;
for (int i=0; i<faces.Size(); i++)
{
face = faces[i];
Array<int> faceVert;
if (!mesh.FaceIsInterior(face)) // if on the boundary
{
mesh.GetFaceVertices(face, faceVert);
faceVert.Sort();
facesVertices.push_back(faceVert);
faceid.push_back(face);
}
}
int bdrface = facesVertices.size();
Array<int> bdryFaces;
// This shoulnd't need to be rebuilt
std::vector<Array<int> > bdryVerts;
for (int b=0; b<mesh.GetNBE(); ++b)
{
if (attr.FindSorted(mesh.GetBdrAttribute(b)) >= 0) // found the contact surface
{
bdryFaces.Append(b);
Array<int> vert;
mesh.GetBdrElementVertices(b, vert);
vert.Sort();
bdryVerts.push_back(vert);
}
}
int bdrvert = bdryVerts.size();
cbdrface = -1; // the face number of the contact surface element
int count_cbdrface = 0; // the number of matching surfaces, used for checks
for (int i=0; i<bdrface; i++)
{
for (int j=0; j<bdrvert; j++)
{
if (ifequalarray(facesVertices[i], bdryVerts[j]))
{
cbdrface = faceid[i];
count_cbdrface += 1;
}
}
}
MFEM_VERIFY(count_cbdrface == 1,"projection surface not found");
};
Vector GetNormalVector(Mesh & mesh, const int elem, const double *ref,
int & refFace, int & refNormal, bool & interior)
{
ElementTransformation *trans = mesh.GetElementTransformation(elem);
const int dim = mesh.Dimension();
const int spaceDim = trans->GetSpaceDim();
MFEM_VERIFY(spaceDim == 3, "");
Vector n(spaceDim);
IntegrationPoint ip;
ip.Set(ref, dim);
trans->SetIntPoint(&ip);
//CalcOrtho(trans->Jacobian(), n); // Works only for face transformations
const DenseMatrix jac = trans->Jacobian();
int dimNormal = -1;
int normalSide = -1;
const double tol = 1.0e-8;
for (int i=0; i<dim; ++i)
{
const double d0 = std::abs(ref[i]);
const double d1 = std::abs(ref[i] - 1.0);
const double d = std::min(d0, d1);
// TODO: this works only for hexahedral meshes!
if (d < tol)
{
MFEM_VERIFY(dimNormal == -1, "");
dimNormal = i;
if (d0 < tol)
{
normalSide = 0;
}
else
{
normalSide = 1;
}
}
}
// closest point on the boundary
if (dimNormal < 0 || normalSide < 0) // node is inside the element
{
interior = 1;
Vector n(3);
n = 0.0;
return n;
}
MFEM_VERIFY(dimNormal >= 0 && normalSide >= 0, "");
refNormal = dimNormal;
MFEM_VERIFY(dim == 3, "");
{
// Find the reference face
if (dimNormal == 0)
{
refFace = (normalSide == 1) ? 2 : 4;
}
else if (dimNormal == 1)
{
refFace = (normalSide == 1) ? 3 : 1;
}
else
{
refFace = (normalSide == 1) ? 5 : 0;
}
}
std::vector<Vector> tang(2);
int tangDir[2] = {-1, -1};
{
int t = 0;
for (int i=0; i<dim; ++i)
{
if (i != dimNormal)
{
tangDir[t] = i;
t++;
}
}
MFEM_VERIFY(t == 2, "");
}
for (int i=0; i<2; ++i)
{
tang[i].SetSize(3);
Vector tangRef(3);
tangRef = 0.0;
tangRef[tangDir[i]] = 1.0;
jac.Mult(tangRef, tang[i]);
}
Vector c(3); // Cross product
c[0] = (tang[0][1] * tang[1][2]) - (tang[0][2] * tang[1][1]);
c[1] = (tang[0][2] * tang[1][0]) - (tang[0][0] * tang[1][2]);
c[2] = (tang[0][0] * tang[1][1]) - (tang[0][1] * tang[1][0]);
c /= c.Norml2();
Vector nref(3);
nref = 0.0;
nref[dimNormal] = 1.0;
Vector ndir(3);
jac.Mult(nref, ndir);
ndir /= ndir.Norml2();
const double dp = ndir * c;
// TODO: eliminate c?
n = c;
if (dp < 0.0)
{
n *= -1.0;
}
interior = 0;
return n;
}
// WARNING: global variable, just for this little example.
std::array<std::array<int, 3>, 8> HEX_VERT =
{
{ {0,0,0},
{1,0,0},
{1,1,0},
{0,1,0},
{0,0,1},
{1,0,1},
{1,1,1},
{0,1,1}
}
};
int GetHexVertex(int cdim, int c, int fa, int fb, Vector & refCrd)
{
int ref[3];
ref[cdim] = c;
ref[cdim == 0 ? 1 : 0] = fa;
ref[cdim == 2 ? 1 : 2] = fb;
for (int i=0; i<3; ++i) { refCrd[i] = ref[i]; }
int refv = -1;
for (int i=0; i<8; ++i)
{
bool match = true;
for (int j=0; j<3; ++j)
{
if (ref[j] != HEX_VERT[i][j]) { match = false; }
}
if (match) { refv = i; }
}
MFEM_VERIFY(refv >= 0, "");
return refv;
}
// Coordinates in xyz are assumed to be ordered as [X, Y, Z]
// where X is the list of x-coordinates for all points and so on.
// conn: connectivity of the target surface elements
// xi: surface reference cooridnates for the cloest point, involves a linear transformation from [0,1] to [-1,1]
void FindPointsInMesh(Mesh & mesh, Vector const& xyz, Array<int>& conn,
Vector& xi)
{
const int dim = mesh.Dimension();
const int np = xyz.Size() / dim;
MFEM_VERIFY(np * dim == xyz.Size(), "");
mesh.EnsureNodes();
//FindPointsGSLIB finder(MPI_COMM_WORLD);
FindPointsGSLIB finder;
finder.SetDistanceToleranceForPointsFoundOnBoundary(0.5);
const double bb_t = 0.5;
finder.Setup(mesh, bb_t);
finder.FindPoints(xyz);
/// Return code for each point searched by FindPoints: inside element (0), on
/// element boundary (1), or not found (2).
Array<unsigned int> codes = finder.GetCode();
/// Return element number for each point found by FindPoints.
Array<unsigned int> elems = finder.GetElem();
/// Return reference coordinates for each point found by FindPoints.
Vector refcrd = finder.GetReferencePosition();
/// Return distance between the sought and the found point in physical space,
/// for each point found by FindPoints.
Vector dist = finder.GetDist();
MFEM_VERIFY(dist.Size() == np, "");
MFEM_VERIFY(refcrd.Size() == np * dim, "");
MFEM_VERIFY(elems.Size() == np, "");
MFEM_VERIFY(codes.Size() == np, "");
bool allfound = true;
for (auto code : codes)
if (code == 2) { allfound = false; }
MFEM_VERIFY(allfound, "A point was not found");
cout << "Maximum distance of projected points: " << dist.Max() << endl;
// extract information
for (int i=0; i<np; ++i)
{
cout << "Point " << i << ": (";
for (int j=0; j<dim; ++j)
{
cout << xyz[i + (j*np)];
if (j == dim-1) {cout << ")" << endl;}
else {cout << ", ";}
}
//cout << " element: " << elems[i] << endl;
//cout << " element " << elems[i] << " vertices:" << endl;
//Array<int> vert;
//mesh.GetElementVertices(elems[i], vert);
//for (auto v : vert)
//{
// cout << " " << v << endl;
//}
/*cout << " reference coordinates: (";
for (int j=0; j<dim; ++j)
{
cout << refcrd[(i*dim) + j];
if (j == dim-1)
{
cout << ")" << endl;
}
else
{
cout << ", ";
}
}*/
int refFace, refNormal, refNormalSide;
bool is_interior = -1;
Vector normal = GetNormalVector(mesh, elems[i], refcrd.GetData() + (i*dim),
refFace, refNormal, is_interior);
int phyFace;
if (is_interior)
{
phyFace = -1; // the id of the face that has the closest point
FindSurfaceToProject(mesh, elems[i], phyFace);
Array<int> cbdrVert;
mesh.GetFaceVertices(phyFace, cbdrVert);
Vector xs(dim);
xs[0] = xyz[i + 0*np];
xs[1] = xyz[i + 1*np];
xs[2] = xyz[i + 2*np];
Vector xi_tmp(dim-1);
// get nodes!
GridFunction *nodes = mesh.GetNodes();
DenseMatrix coords(4,3);
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
coords(i,j) = (*nodes)[cbdrVert[i]*3+j];
}
}
SlaveToMaster(coords, xs, xi_tmp);
for (int j=0; j<dim-1; ++j)
{
xi[i*(dim-1)+j] = xi_tmp[j];
}
// now get get the projection to the surface
}
else
{
Vector faceRefCrd(dim-1);
{
int fd = 0;
for (int j=0; j<dim; ++j)
{
if (j == refNormal)
{
refNormalSide = (refcrd[(i*dim) + j] > 0.5);
}
else
{
faceRefCrd[fd] = refcrd[(i*dim) + j];
fd++;
}
}
MFEM_VERIFY(fd == dim-1, "");
}
for (int j=0; j<dim-1; ++j)
{
xi[i*(dim-1)+j] = faceRefCrd[j]*2.0 - 1.0;
}
//cout << " face reference coordinates: (";
for (int j=0; j<dim-1; ++j)
{
cout << faceRefCrd[j];
if (j == dim-2) {cout << ")" << endl;}
else {cout << ", ";}
}
}
//cout << " normal vector: ";
//normal.Print();
// ask, does this do anything?
/*
IntegrationPoint ip;
ip.Set(refcrd.GetData() + (i*dim), dim);
ElementTransformation *trans = mesh.GetElementTransformation(elems[i]);
Vector phys(trans->GetSpaceDim());
trans->Transform(ip, phys);
cout << " physical coordinates: ";
phys.Print();
*/
// Get the element face
Array<int> faces;
Array<int> ori;
int face;
if (is_interior)
{
face = phyFace;
}
else
{
mesh.GetElementFaces(elems[i], faces, ori);
face = faces[refFace];
}
Array<int> faceVert;
mesh.GetFaceVertices(face, faceVert);
//cout << " face " << face << " vertices:" << endl;
//for (auto v : faceVert){ cout << " " << v << endl;}
for (int p=0; p<4; p++)
{
conn[4*i+p] = faceVert[p];
}
/*
Vector ref(dim);
for (int p=0; p<2; ++p)
for (int q=0; q<2; ++q)
{
const int refv = GetHexVertex(refNormal, refNormalSide, p, q, ref);
cout << " face reference vertex (" << p << "," << q
<< ") is global vertex " << vert[refv] << endl;
{
// Sanity check
ip.Set(ref.GetData(), dim);
trans->Transform(ip, phys);
for (int j=0; j<dim; ++j)
{
phys[j] -= mesh.GetVertex(vert[refv])[j];
}
phys.Print();
cout<<vert[refv]<<endl;
cout<<mesh.GetVertex(vert[refv])[0]<<endl;
cout<<mesh.GetVertex(vert[refv])[1]<<endl;
cout<<mesh.GetVertex(vert[refv])[2]<<endl;
MFEM_VERIFY(phys.Norml2() < 1.0e-12, "Sanity check failed");
}
}*/
}
}
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file1 = "block1.mesh";
const char *mesh_file2 = "block2.mesh";
Array<int> attr;
Array<int> m_attr;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file1, "-m1", "--mesh1",
"First mesh file to use.");
args.AddOption(&mesh_file2, "-m2", "--mesh2",
"Second mesh file to use.");
args.AddOption(&attr, "-at", "--attributes-surf",
"Attributes of boundary faces on contact surface for mesh 2.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
Mesh mesh1(mesh_file1, 1, 1);
Mesh mesh2(mesh_file2, 1, 1);
const int dim = mesh1.Dimension();
MFEM_VERIFY(dim == mesh2.Dimension(), "");
// boundary attribute 2 is the potential contact surface of nodes
attr.Append(2);
// boundary attribute 2 is the potential contact surface for master surface
m_attr.Append(2);
// Define a finite element space on the mesh. Here we use vector finite
// elements, i.e. dim copies of a scalar finite element space. The vector
// dimension is specified by the last argument of the FiniteElementSpace
// constructor.
FiniteElementCollection *fec1;
FiniteElementSpace *fespace1;
fec1 = new H1_FECollection(1, dim);
fespace1 = new FiniteElementSpace(&mesh1, fec1, dim, Ordering::byVDIM);
cout << "Number of finite element unknowns for mesh1: "
<< fespace1->GetTrueVSize() << endl;
mesh1.SetNodalFESpace(fespace1);
GridFunction nodes0 = *mesh1.GetNodes(); // undeformed mesh1 nodal grid function
GridFunction *nodes1 = mesh1.GetNodes();
FiniteElementCollection *fec2 = new H1_FECollection(1, dim);
FiniteElementSpace *fespace2 = new FiniteElementSpace(&mesh2, fec2, dim,
Ordering::byVDIM);
cout << "Number of finite element unknowns for mesh2: "
<< fespace2->GetTrueVSize() << endl;
// degrees of freedom of both meshes
int ndof_1 = fespace1->GetTrueVSize();
int ndof_2 = fespace2->GetTrueVSize();
int ndofs = ndof_1 + ndof_2;
// number of nodes for each mesh
int nnd_1 = mesh1.GetNV();
int nnd_2 = mesh2.GetNV();
int nnd = nnd_1 + nnd_2;
// Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking only
// boundary attribute 1 from the mesh as essential and converting it to a
// list of true dofs.
Array<int> ess_tdof_list1, ess_bdr1(mesh1.bdr_attributes.Max());
cout<<mesh1.bdr_attributes.Max()<<endl;
ess_bdr1 = 0;
//ess_bdr1[0] = 1;
// Not ready to be passed on yet
// fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
Array<int> ess_tdof_list2, ess_bdr2(mesh2.bdr_attributes.Max());
ess_bdr2 = 0;
//ess_bdr2[0] = 1;
// Define the displacement vector x as a finite element grid function
// corresponding to fespace. GridFunction is a derived class of Vector.
GridFunction x1(fespace1);
x1 = 0.0;
GridFunction x2(fespace2);
x2 = 0.0;
// Generate force
LinearForm *b1 = new LinearForm(fespace1);
b1->Assemble();
LinearForm *b2 = new LinearForm(fespace2);
b2->Assemble();
// Set up the bilinear form a(.,.) on the finite element space
// corresponding to the linear elasticity integrator with piece-wise
// constants coefficient lambda and mu.
Vector lambda1(mesh1.attributes.Max());
lambda1 = 57.6923076923;
PWConstCoefficient lambda1_func(lambda1);
Vector mu1(mesh1.attributes.Max());
mu1 = 38.4615384615;
PWConstCoefficient mu1_func(mu1);
BilinearForm *a1 = new BilinearForm(fespace1);
a1->AddDomainIntegrator(new ElasticityIntegrator(lambda1_func,mu1_func));
Vector lambda2(mesh2.attributes.Max());
lambda2 = 57.6923076923;
PWConstCoefficient lambda2_func(lambda2);
Vector mu2(mesh2.attributes.Max());
mu2 = 38.4615384615;
PWConstCoefficient mu2_func(mu2);
BilinearForm *a2 = new BilinearForm(fespace2);
a2->AddDomainIntegrator(new ElasticityIntegrator(lambda2_func,mu2_func));
a1->Assemble();
SparseMatrix A1;
Vector B1, X1;
a1->FormLinearSystem(ess_tdof_list1, x1, *b1, A1, X1, B1);
a2->Assemble();
SparseMatrix A2;
Vector B2, X2;
a2->FormLinearSystem(ess_tdof_list2, x2, *b2, A2, X2, B2);
// Combine elasticity operator for two meshes into one.
// Block Matrix
SparseMatrix K(ndofs,ndofs);
for (int i=0; i<A1.Height(); i++)
{
Array<int> col_tmp;
Vector v_tmp;
col_tmp = 0;
v_tmp = 0.0;
A1.GetRow(i, col_tmp, v_tmp);
K.SetRow(i, col_tmp, v_tmp);
}
for (int i=0; i<A2.Height(); i++)
{
Array<int> col_tmp;
Vector v_tmp;
col_tmp = 0;
v_tmp = 0.0;
A2.GetRow(i, col_tmp, v_tmp);
for (int j=0; j<col_tmp.Size(); j++)
{
col_tmp[j] += ndof_1;
}
K.SetRow(i+ndof_1, col_tmp, v_tmp); // mesh1 top left corner
}
// Construct node to segment contact constraint.
attr.Sort();
cout << "Boundary attributes for contact surface faces in mesh 2" << endl;
for (auto a : attr)
{
cout << a << endl;
}
Array<int> bdryFaces2; // TODO: remove this?
std::set<int> bdryVerts2;
for (int b=0; b<mesh2.GetNBE(); ++b)
{
if (attr.FindSorted(mesh2.GetBdrAttribute(b)) >= 0)
{
bdryFaces2.Append(b);
Array<int> vert;
mesh2.GetBdrElementVertices(b, vert);
for (auto v : vert)
{
bdryVerts2.insert(v);
}
}
}
int npoints = bdryVerts2.size();
Array<int> s_conn(npoints); // connectivity of the second/slave mesh
Vector xyz(dim * npoints);
xyz = 0.0;
cout << "Boundary vertices for contact surface vertices in mesh 2" << endl;
// construct the nodal coordinates on mesh2 to be projected, including displacement
int count = 0;
for (auto v : bdryVerts2)
{
cout << v << ": " << mesh2.GetVertex(v)[0] << ", "
<< mesh2.GetVertex(v)[1] << ", "
<< mesh2.GetVertex(v)[2] << endl;
for (int i=0; i<dim; ++i)
{
xyz[count + (i * npoints)] = mesh2.GetVertex(v)[i] + x2[v*dim+i];
}
s_conn[count] = v + nnd_1; // dof1 is the master
count++;
}
MFEM_VERIFY(count == npoints, "");
// gap function
Vector g(npoints*dim);
g = -1.0;
// segment reference coordinates of the closest point
Vector m_xi(npoints*(dim-1));
m_xi = -1.0;
Vector xs(dim*npoints);
xs = 0.0;
for (int i=0; i<npoints; i++)
{
for (int j=0; j<dim; j++)
{
xs[i*dim+j] = xyz[i + (j*npoints)];
}
}
Array<int> m_conn(
npoints*4); // only works for linear elements that have 4 vertices!
DenseMatrix coordsm(npoints*4, dim);
// adding displacement to mesh1 using a fixed grid function from mesh1
x1 = 1e-4; // x1 order: [xyz xyz... xyz]
add(nodes0, x1, *nodes1);
FindPointsInMesh(mesh1, xyz, m_conn, m_xi);
for (int i=0; i<npoints; i++)
{
for (int j=0; j<4; j++)
{
for (int k=0; k<dim; k++)
{
coordsm(i*4+j,k) = mesh1.GetVertex(m_conn[i*4+j])[k]+x1[dim*m_conn[i*4+j]+k];
}
}
}
//coordsm.Print();
SparseMatrix M(nnd,ndofs);
std::vector<SparseMatrix> dM(nnd, SparseMatrix(ndofs,ndofs));
Assemble_Contact(nnd, npoints, ndofs, xs, m_xi, coordsm,
s_conn, m_conn, g, M, dM);
//M.Print();
/*Vector eps(ndofs);
Vector sol(ndofs); sol = 0.;
for(int i=0;i<ndofs;i++) eps[i] = 1e-5 * i ;
for(int i=0;i<9;i++)
{
cout<<i<<endl;
dM[s_conn[i]].Mult(eps,sol);
sol.Print();
}
*/
return 0;
}
File diff suppressed because it is too large Load Diff
-230
View File
@@ -1,230 +0,0 @@
// Contact example
//
// Compile with: make exContactBlockTL
//
// Sample runs: ./exContactBlockTL -m1 block1.mesh -m2 block2.mesh -at "5 6 7 8"
// Sample runs: ./exContactBlockTL -m1 block1_d.mesh -m2 block2_d.mesh -at "5 6 7 8"
#ifndef EXCONTACTBLOCKTL_HPP
#define EXCONTACTBLOCKTL_HPP
#include "mfem.hpp"
#include "IpTNLP.hpp"
using namespace std;
using namespace mfem;
using namespace Ipopt;
class ExContactBlockTL: public TNLP
{
public:
/** default constructor */
ExContactBlockTL(int argc, char *argv[]);
/** default destructor */
virtual ~ExContactBlockTL();
/**@name Overloaded from TNLP */
/** Method to return some info about the nlp */
virtual bool get_nlp_info(
Index& n,
Index& m,
Index& nnz_jac_g,
Index& nnz_h_lag,
IndexStyleEnum& index_style
);
/** Method to return the bounds for my problem */
virtual bool get_bounds_info(
Index n,
Number* x_l,
Number* x_u,
Index m,
Number* g_l,
Number* g_u
);
/** Method to return the starting point for the algorithm */
virtual bool get_starting_point(
Index n,
bool init_x,
Number* x,
bool init_z,
Number* z_L,
Number* z_U,
Index m,
bool init_lambda,
Number* lambda
);
/** Method to return the objective value */
virtual bool eval_f(
Index n,
const Number* x,
bool new_x,
Number& obj_value
);
/** Method to return the gradient of the objective */
virtual bool eval_grad_f(
Index n,
const Number* x,
bool new_x,
Number* grad_f
);
/** Method to return the constraint residuals */
virtual bool eval_g(
Index n,
const Number* x,
bool new_x,
Index m,
Number* cons
);
/** Method to return:
* 1) The structure of the Jacobian (if "values" is NULL)
* 2) The values of the Jacobian (if "values" is not NULL)
*/
virtual bool eval_jac_g(
Index n,
const Number* x,
bool new_x,
Index m,
Index nele_jac,
Index* iRow,
Index* jCol,
Number* values
);
/** Method to return:
* 1) The structure of the Hessian of the Lagrangian (if "values" is NULL)
* 2) The values of the Hessian of the Lagrangian (if "values" is not NULL)
*/
virtual bool eval_h(
Index n,
const Number* x,
bool new_x,
Number obj_factor,
Index m,
const Number* lambda,
bool new_lambda,
Index nele_hess,
Index* iRow,
Index* jCol,
Number* values
);
/** This method is called when the algorithm is complete so the TNLP can store/write the solution */
virtual void finalize_solution(
SolverReturn status,
Index n,
const Number* x,
const Number* z_L,
const Number* z_U,
Index m,
const Number* g,
const Number* lambda,
Number obj_value,
const IpoptData* ip_data,
IpoptCalculatedQuantities* ip_cq
);
private:
void update_g();
void update_jac();
void update_hess();
private:
/**@name Methods to block default compiler methods.
*
* The compiler automatically generates the following three methods.
* Since the default compiler implementation is generally not what
* you want (for all but the most simple classes), we usually
* put the declarations of these methods in the private section
* and never implement them. This prevents the compiler from
* implementing an incorrect "default" behavior without us
* knowing. (See Scott Meyers book, "Effective C++")
*/
ExContactBlockTL(
const ExContactBlockTL&
);
ExContactBlockTL& operator=(
const ExContactBlockTL&
);
Array<int> attr;
Array<int> m_attr;
Array<int> s_conn; // connectivity of the second/slave mesh
std::string mesh_file1;
std::string mesh_file2;
Mesh* mesh1;
Mesh* mesh2;
FiniteElementCollection* fec1;
FiniteElementCollection* fec2;
FiniteElementSpace* fespace1;
FiniteElementSpace* fespace2;
Array<int> ess_tdof_list1;
Array<int> ess_tdof_list2;
GridFunction nodes0;
GridFunction* nodes1;
GridFunction* nodes2;
GridFunction* x1;
GridFunction* x2;
LinearForm* b1;
LinearForm* b2;
PWConstCoefficient* lambda1_func;
PWConstCoefficient* lambda2_func;
PWConstCoefficient* mu1_func;
PWConstCoefficient* mu2_func;
BilinearForm* a1;
BilinearForm* a2;
mfem::Vector lambda1;
mfem::Vector lambda2;
mfem::Vector mu1;
mfem::Vector mu2;
mfem::Vector xyz;
std::set<int> bdryVerts2;
int dim;
// degrees of freedom of both meshes
int ndof_1;
int ndof_2;
int ndofs;
// number of nodes for each mesh
int nnd_1;
int nnd_2;
int nnd;
int npoints;
SparseMatrix A1;
mfem::Vector B1, X1;
SparseMatrix A2;
mfem::Vector B2, X2;
SparseMatrix* K;
mfem::Vector g;
mfem::Vector m_xi;
mfem::Vector xs;
Array<int> m_conn; // only works for linear elements that have 4 vertices!
DenseMatrix* coordsm;
SparseMatrix* M;
std::vector<SparseMatrix>* dM;
Array<int> Dirichlet_dof;
Array<double> Dirichlet_val;
public:
Mesh * GetMesh1() {return mesh1;}
Mesh * GetMesh2() {return mesh2;}
};
#endif
-68
View File
@@ -1,68 +0,0 @@
# Copyright (c) 2010-2022, 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.
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/ipopt/,)
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_EXAMPLES = exContactBlockTL
EXAMPLES = $(SEQ_EXAMPLES)
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all clean clean-build clean-exec
# Remove built-in rule
%: %.cpp
# Replace the default implicit rule for *.cpp files
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
all: $(EXAMPLES)
ifeq ($(MFEM_USE_IPOPT),NO)
$(EXAMPLES):
$(error MFEM is not configured with IPOPT)
endif
MFEM_TESTS = EXAMPLES
include $(MFEM_TEST_MK)
# Testing: Parallel vs. serial runs
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
%-test-par: %
@$(call mfem-test,$<, $(RUN_MPI), Parallel example)
%-test-seq: %
@$(call mfem-test,$<,, Serial example)
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
# Generate an error message if the MFEM library is not built and exit
$(MFEM_LIB_FILE):
$(error The MFEM library is not built)
clean: clean-build clean-exec
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -f exContactBlockTL.mesh exContactBlockTL-mesh.* exContactBlockTL-init.* exContactBlockTL-final.* ExampleContactBlockTL*
-888
View File
@@ -1,888 +0,0 @@
using namespace std;
using namespace mfem;
void BasisEval(const Vector xi, Vector &N, DenseMatrix &dNdxi) // dNdxi is 2*4
{
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi(0,0) = 0.25*(-1+xi[1]);
dNdxi(0,1) = 0.25*(1-xi[1]);
dNdxi(0,2) = 0.25*(1+xi[1]);
dNdxi(0,3) = 0.25*(-1-xi[1]);
dNdxi(1,0) = 0.25*(-1+xi[0]);
dNdxi(1,1) = 0.25*(-1-xi[0]);
dNdxi(1,2) = 0.25*(1+xi[0]);
dNdxi(1,3) = 0.25*(1-xi[0]);
}
void BasisEvalDerivs(const Vector xi, Vector& N, DenseMatrix& dNdxi,
DenseMatrix& dN2dxi)
{
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi.SetSize(2,4); dNdxi = 0.0;
dN2dxi.SetSize(3,4);
dN2dxi = 0.0; // first row dxi2, second detadxi, third deta2
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,1) = 0.25*(1-xi[1]);
dNdxi(0,2) = 0.25*(1+xi[1]); dNdxi(0,3) = 0.25*(-1-xi[1]);
dNdxi(1,0) = 0.25*(-1+xi[0]); dNdxi(1,1) = 0.25*(-1-xi[0]);
dNdxi(1,2) = 0.25*(1+xi[0]); dNdxi(1,3) = 0.25*(1-xi[0]);
dN2dxi(1,0) = 0.25; dN2dxi(1,1) = -0.25; dN2dxi(1,2) = 0.25;
dN2dxi(1,3) = -0.25;
}
// returns the vector and matrix form of the shape functions and its derivative
void BasisVectorDerivs(const Vector xi, DenseMatrix& N, DenseMatrix& dNdxi,
DenseMatrix& ddNdxi)
{
N.SetSize(3,12); N = 0.0;
N(0,0) = 0.25*(1-xi[0])*(1-xi[1]); N(0,3) = 0.25*(1+xi[0])*(1-xi[1]);
N(0,6) = 0.25*(1+xi[0])*(1+xi[1]); N(0,9) = 0.25*(1-xi[0])*(1+xi[1]);
N(1,1) = 0.25*(1-xi[0])*(1-xi[1]); N(1,4) = 0.25*(1+xi[0])*(1-xi[1]);
N(1,7) = 0.25*(1+xi[0])*(1+xi[1]); N(1,10) = 0.25*(1-xi[0])*(1+xi[1]);
N(2,2) = 0.25*(1-xi[0])*(1-xi[1]); N(2,5) = 0.25*(1+xi[0])*(1-xi[1]);
N(2,8) = 0.25*(1+xi[0])*(1+xi[1]); N(2,11) = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi.SetSize(3*2, 3*4); dNdxi = 0.0;
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,3) = 0.25*(1-xi[1]);
dNdxi(0,6) = 0.25*(1+xi[1]); dNdxi(0,9) = 0.25*(-1-xi[1]);
dNdxi(1,1) = 0.25*(-1+xi[1]); dNdxi(1,4) = 0.25*(1-xi[1]);
dNdxi(1,7) = 0.25*(1+xi[1]); dNdxi(1,10) = 0.25*(-1-xi[1]);
dNdxi(2,2) = 0.25*(-1+xi[1]); dNdxi(2,5) = 0.25*(1-xi[1]);
dNdxi(2,8) = 0.25*(1+xi[1]); dNdxi(2,11) = 0.25*(-1-xi[1]);
dNdxi(3,0) = 0.25*(-1+xi[0]); dNdxi(3,3) = 0.25*(-1-xi[0]);
dNdxi(3,6) = 0.25*(1+xi[0]); dNdxi(3,9) = 0.25*(1-xi[0]);
dNdxi(4,1) = 0.25*(-1+xi[0]); dNdxi(4,4) = 0.25*(-1-xi[0]);
dNdxi(4,7) = 0.25*(1+xi[0]); dNdxi(4,10) = 0.25*(1-xi[0]);
dNdxi(5,2) = 0.25*(-1+xi[0]); dNdxi(5,5) = 0.25*(-1-xi[0]);
dNdxi(5,8) = 0.25*(1+xi[0]); dNdxi(5,11) = 0.25*(1-xi[0]);
ddNdxi.SetSize(3*4, 3*4); ddNdxi = 0.0;
ddNdxi(3,0) = 0.25; ddNdxi(3,3) = -0.25;
ddNdxi(3,6) = 0.25; ddNdxi(3,9) = -0.25;
ddNdxi(4,1) = 0.25; ddNdxi(4,4) = -0.25;
ddNdxi(4,7) = 0.25; ddNdxi(4,10) = -0.25;
ddNdxi(5,2) = 0.25; ddNdxi(5,5) = -0.25;
ddNdxi(5,8) = 0.25; ddNdxi(5,11) = -0.25;
ddNdxi(6,0) = 0.25; ddNdxi(6,3) = -0.25;
ddNdxi(6,6) = 0.25; ddNdxi(6,9) = -0.25;
ddNdxi(7,1) = 0.25; ddNdxi(7,4) = -0.25;
ddNdxi(7,7) = 0.25; ddNdxi(7,10) = -0.25;
ddNdxi(8,2) = 0.25; ddNdxi(8,5) = -0.25;
ddNdxi(8,8) = 0.25; ddNdxi(8,11) = -0.25;
}
void cross(const Vector a, const Vector b, Vector& c)
{
assert(a.Size()==3);
c.SetSize(3);
c[0] = a[1]*b[2] - a[2]*b[1];
c[1] = -a[0]*b[2] + b[0]*a[2];
c[2] = a[0]*b[1] - a[1]*b[0];
}
// a outer b
void outer(const Vector a, const Vector b, DenseMatrix& c)
{
int m = a.Size();
int n = b.Size();
assert(c.Height()==m);
assert(c.Width() ==n);
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
{
c(i,j) = a[i]*b[j];
}
}
}
// dphidxi 2*4
// coords 4*3
void ComputeNormal(const DenseMatrix& dphidxi, const DenseMatrix& coords,
Vector& normal, double& nnorm)
{
DenseMatrix dxdxi(2,3);
Mult(dphidxi, coords, dxdxi);
Vector dxdxi1(3);
Vector dxdxi2(3);
dxdxi.GetRow(0,dxdxi1);
dxdxi.GetRow(1,dxdxi2);
cross(dxdxi1, dxdxi2, normal); // is there a cross product? no
// VectorCrossProductCoefficient::Eval has hard-coded cross product
nnorm = normal.Norml2( );
normal /= nnorm;
}
void SlaveToMaster(const DenseMatrix& m_coords, const Vector& s_x, Vector& xi)
{
bool converged = false;
bool pt_on_elem = false;
int dim = 3;
xi.SetSize(dim-1);
xi = 0.0;
double r = 1e10;
int max_iter = 15;
double off_el_xi = 1e-2;
double proj_newton_tol = 1e-13;
double proj_max_gap = 0.5;
Vector gap_v(dim);
// warm start from linear solution
for (int it=0; it<max_iter; it++)
{
//cout<<it<<endl;
Vector m_N(4);
m_N = 0.;
DenseMatrix m_dN(2,4);
m_dN = 0.;
DenseMatrix m_dN2(3,4);
m_dN2 = 0.;
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
Vector x_c(dim);
m_coords.MultTranspose(m_N, x_c);
gap_v = s_x;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
m_dx = 0.;
Mult(m_dN, m_coords, m_dx);
Vector r(dim-1);
r = 0.0;
m_dx.Mult(gap_v, r);
if (r.Normlinf() < proj_newton_tol)
{
converged = true;
break;
}
DenseMatrix drdxi(dim-1,dim-1);
drdxi = 0.;
MultABt(m_dx, m_dx, drdxi); // m_dx * m_dx.T
drdxi *= -1.0;
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
Mult(m_dN2,m_coords, m_dx2);
//m_d2x = m_dN(:,:,2) * m_elem_coords(1:4,:); //m_dN(:,:,2) is 3*4
for (int d=0; d<3; d++)
{
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
drdxi.Add(gap_v[d], Mtemp);
}
//cond_num = rcond(drdxi); condition number?
//drdxi.TestInversion();
DenseMatrixInverse drdxi_inv(drdxi);
Vector xi_tmp(dim-1);
drdxi_inv.Mult(r,xi_tmp);
xi -= xi_tmp;
}
if (!converged)
{
xi = 0.0;
}
off_el_xi += 1 ; // tolerance of offset of xi outside [-1,1]
//cout<<gap_v.Norml2()<<" " <<xi.Normlinf()<<endl;
if (gap_v.Norml2() < proj_max_gap && xi.Normlinf() <= off_el_xi)
{
pt_on_elem = true;
}
MFEM_VERIFY(pt_on_elem == true, "xi went out of bounds");
MFEM_VERIFY(converged == true, "projection didn't converge");
}
// m_coords is expected to be 4 * 3
void ComputeGapJacobian(const Vector x_s, const Vector xi,
const DenseMatrix m_coords,
double& gap, Vector& normal, Vector& dgdxm, Vector& dgdxs)
{
Vector m_N(4);
DenseMatrix m_dN(2,4);
DenseMatrix m_dN2(3,4);
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
Vector x_c(3);
m_coords.MultTranspose(m_N, x_c);
Vector gap_v(3); gap_v = 0.0;
gap_v = x_s;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
Mult(m_dN, m_coords, m_dx);
double nnorm = 0;
ComputeNormal(m_dN, m_coords, normal, nnorm);
gap = gap_v * normal; // gap function value, dot product between vectors
//dr_dx = zeros(2,4,3); % nsegment, nodes in quad, ndim
DenseMatrix dr_dx_res1(4,3); dr_dx_res1 = 0.;
DenseMatrix dr_dx_res2(4,3); dr_dx_res2 = 0.;
Vector m_dxrow1(3);
m_dx.GetRow(0, m_dxrow1);
outer(m_N, m_dxrow1, dr_dx_res1);// 4*1 times 1*3
dr_dx_res1 *= -1.0;
Vector m_dxrow2(3);
m_dx.GetRow(1, m_dxrow2);
outer(m_N, m_dxrow2, dr_dx_res2);// 4*1 times 1*3
dr_dx_res2 *= -1.0;
Vector m_dNrow1(4); m_dN.GetRow(0, m_dNrow1);
Vector m_dNrow2(4); m_dN.GetRow(1, m_dNrow2);
DenseMatrix dr_dx_res1_tmp(4,3); dr_dx_res1_tmp = 0.;
DenseMatrix dr_dx_res2_tmp(4,3); dr_dx_res2_tmp = 0.;
outer(m_dNrow1, gap_v, dr_dx_res1_tmp);// 4*1 times 1*3
outer(m_dNrow2, gap_v, dr_dx_res2_tmp);// 4*1 times 1*3
dr_dx_res1 += dr_dx_res1_tmp; // outer product in vector?
dr_dx_res2 += dr_dx_res2_tmp;
DenseMatrix K_dxidx1(2,2); // 2*2
K_dxidx1 = 0.;
MultABt(m_dx, m_dx, K_dxidx1); // m_dx * m_dx.T
Vector v_dxidx2(4);
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
// how to get 2nd order? multidimensional matrix?
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
DenseMatrix K_dxidx(2,2);
K_dxidx -= K_dxidx1;
K_dxidx += K_dxidx2;
// resize the vectors and matrices
Vector dxidx(24); dxidx = 0.0;
Vector drdx_r(24); drdx_r = 0.0;
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
drdx_r[4*j+i] = dr_dx_res1(i,j);
drdx_r[4*j+i+12] = dr_dx_res2(i,j);
}
}
//drdx_r(1:4*3,1) = reshape(dr_dx_res(:,:,1),4*3,1);
//drdx_r(4*3+1:2*4*3,1) = reshape(dr_dx_res(:,:,2),4*3,1);
DenseMatrix drdx_K(24,24); drdx_K = 0.;
for (int i =0; i<12; i++)
{
drdx_K(i,i) = K_dxidx(0,0);
drdx_K(i,12+i) = K_dxidx(0,1);
drdx_K(12+i,i) = K_dxidx(1,0);
drdx_K(12+i,12+i) = K_dxidx(1,1);
}
DenseMatrixInverse drdxK_inv(drdx_K);
drdxK_inv.Mult(drdx_r,dxidx);
// LinearSolve (drdx_K,drdx_r, dxidx) ; //???
dxidx *= -1.0;
Vector drdxs_r(6);
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
for (int i=0; i<3; i++)
{
drdxs_K(i,i) = K_dxidx(0,0);
drdxs_K(i,3+i) = K_dxidx(0,1);
drdxs_K(i+3,i) = K_dxidx(1,0);
drdxs_K(i+3,i+3) = K_dxidx(1,1);
}
Vector dxidxs(6); dxidxs = 0.0;
DenseMatrixInverse drdxsK_inv(drdxs_K);
drdxsK_inv.Mult(drdxs_r,dxidxs);
dxidxs *= -1.0;
//dxidxs = -drdxs_K\drdxs_r;
//dxidx = reshape(dxidx, 4,3,2); dxidxs = reshape(dxidxs, 1,3,2);
dgdxm.SetSize(12); dgdxm = 0.;
DenseMatrix dgdxm_tmp(4,3);
outer(m_N, normal,dgdxm_tmp);
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
dgdxm[3*i+j] = -dgdxm_tmp(i,j);
}
}
//dxidx_M = -m_dN(1:2,:,1) * (m_coords(1:4,:)*normal'); % this turns out to be 0
dgdxs.SetSize(3);
dgdxs += normal;
//dgdxs = dgdxs + dxidx_M(1) * dxidxs(:,:,1) + dxidx_M(2) * dxidxs(:,:,2);
};
void ComputeGapHessian(const Vector x_s, const Vector xi,
const DenseMatrix m_coords,
DenseMatrix& dg2dx)
{
Vector m_N(4);
DenseMatrix m_dN(2,4);
DenseMatrix m_dN2(3,4);
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
int dim = 3;
int num_dofs1 = dim;
int num_dofs2 = 4*dim;
int num_dofs = num_dofs1 + num_dofs2;
dg2dx.SetSize(num_dofs,num_dofs); dg2dx = 0.0;
Vector x_c(3);
m_coords.MultTranspose(m_N,x_c);
Vector gap_v(3); gap_v = 0.0;
gap_v = x_s;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
Mult(m_dN, m_coords, m_dx);
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
Mult(m_dN2,m_coords, m_dx2);
double nnorm = 0.0;
Vector normal(3); normal = 0.0;
ComputeNormal(m_dN, m_coords, normal, nnorm);
double gap = gap_v * normal; // gap function value, dot product between vectors
DenseMatrix M(2,2); M = 0.0;
MultABt(m_dx, m_dx, M);
DenseMatrix f(2, num_dofs2); f = 0.0;
for (int d=0; d<3; d++)
{
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
M.Add(-gap_v[d], Mtemp);
Vector m_dxcol(2); m_dx.GetColumn(d, m_dxcol);
DenseMatrix ftmp(2,4);
outer(m_dxcol, m_N, ftmp);
ftmp *= -1;
ftmp.Add( gap_v[d], m_dN); // 2*4
for (int j=0; j<4; j++)
{
assert(d+3*j<num_dofs2);
f(0,d+j*3) = ftmp(0,j);
f(1,d+j*3) = ftmp(1,j);
}
}
//fprintf('hess dxidxm\n');
DenseMatrixInverse Minv(M);
DenseMatrix dxidxm(2,num_dofs2); dxidxm = 0.0;
Minv.Mult(f, dxidxm);
//LinearSolve??
//dxidxm = M\f;
DenseMatrix nde2(2,2); nde2 = 0.0;
DenseMatrix Nndx2(2,num_dofs2); Nndx2 = 0.0;
for (int d=0; d<3; d++)
{
DenseMatrix ndetmp(2,2); ndetmp = 0.0;
ndetmp(0,0) = normal(d)*m_dx2(0,d); ndetmp(0,1) = normal(d)*m_dx2(1,d);
ndetmp(1,0) = normal(d)*m_dx2(1,d); ndetmp(1,1) = normal(d)*m_dx2(2,d);
nde2 += ndetmp;
for (int j=0; j<4; j++)
{
assert(d+3*j<num_dofs2);
Nndx2(0,d+j*3) = normal[d]*m_dN(0,j);
Nndx2(1,d+j*3) = normal[d]*m_dN(1,j);
}
}
DenseMatrix Ndn(2,num_dofs2); Ndn = 0.0;
Ndn += Nndx2;
AddMult(nde2, dxidxm, Ndn);
DenseMatrix M2(2,2); M2 = 0.0;
MultABt(m_dx, m_dx, M2);
DenseMatrixInverse M2inv(M2);
DenseMatrix diag2(2,2); diag2(0,0) = 1.0; diag2(1,1) = 1.0;
DenseMatrix m_con(2,2); m_con = 0.0;
M2inv.Mult(diag2, m_con);
DenseMatrix dg2dxm(num_dofs2, num_dofs2); dg2dxm = 0.0;
DenseMatrix dg2dxm_tmp(num_dofs2,2); dg2dxm_tmp = 0.0;
MultAtB(Ndn, m_con, dg2dxm_tmp);
Mult(dg2dxm_tmp, Ndn, dg2dxm);
dg2dxm *= gap;
DenseMatrix dg2dxm_tmp2(num_dofs2,num_dofs2); dg2dxm_tmp2 = 0.0;
MultAtB(Nndx2, dxidxm, dg2dxm_tmp2);
dg2dxm.Add(-1.0, dg2dxm_tmp2);
dg2dxm_tmp = 0.0;
MultAtB(dxidxm, nde2, dg2dxm_tmp);
AddMult_a(-1.0, dg2dxm_tmp, dxidxm, dg2dxm);
dg2dxm_tmp2 = 0.0;
MultAtB(dxidxm, Nndx2, dg2dxm_tmp2);
dg2dxm.Add(-1.0, dg2dxm_tmp2);
Vector v_dxidx2(4);
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
DenseMatrix K_dxidx(2,2);
K_dxidx -= M2;
K_dxidx += K_dxidx2;
Vector drdxs_r(6);
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
for (int i=0; i<3; i++)
{
drdxs_K(i,i) = K_dxidx(0,0);
drdxs_K(i,3+i) = K_dxidx(0,1);
drdxs_K(i+3,i) = K_dxidx(1,0);
drdxs_K(i+3,i+3) = K_dxidx(1,1);
}
Vector dxidxs(6);
DenseMatrixInverse drdxsK_inv(drdxs_K);
drdxsK_inv.Mult(drdxs_r,dxidxs);
dxidxs *= -1.0;
//dxidxs = -drdxs_K\drdxs_r;
DenseMatrix dxidxs_m(2,3); dxidxs_m = 0.0;
dxidxs_m(0,0) = dxidxs[0]; dxidxs_m(0,1) = dxidxs[1]; dxidxs_m(0,2) = dxidxs[2];
dxidxs_m(1,0) = dxidxs[3]; dxidxs_m(1,1) = dxidxs[4]; dxidxs_m(1,2) = dxidxs[5];
DenseMatrix dtao1dxs(3,3); dtao1dxs = 0.0;
DenseMatrix dtao2dxs(3,3); dtao2dxs = 0.0;
Vector dxidxs_row1(3); dxidxs_row1 = 0.0; Vector dxidxs_row2(3);
dxidxs_row2 = 0.0;
Vector mdx2_row1(3); mdx2_row1 = 0.0; Vector mdx2_row2(3); mdx2_row2 = 0.0;
Vector mdx2_row3(3); mdx2_row3 = 0.0;
dxidxs_m.GetRow(0,dxidxs_row1);
dxidxs_m.GetRow(1,dxidxs_row2);
m_dx2.GetRow(0,mdx2_row1);
m_dx2.GetRow(1,mdx2_row2);
m_dx2.GetRow(2,mdx2_row3);
DenseMatrix dtaotmp(3,3); dtaotmp = 0.0;
outer(mdx2_row1, dxidxs_row1,dtaotmp);
dtao1dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row2, dxidxs_row1,dtaotmp);
dtao1dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row2, dxidxs_row2, dtaotmp);
dtao2dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row3, dxidxs_row2, dtaotmp);
dtao2dxs += dtaotmp; dtaotmp = 0.0;
DenseMatrix dtaodxs(3,3); dtaodxs = 0.0; //tao = tao1 cross tao2
for (int d=0; d<3; d++)
{
Vector dtao1dxs_tmp(3); dtao1dxs_tmp = 0.0;
dtao1dxs.GetColumn(d,dtao1dxs_tmp);
Vector m_dxrow(3); m_dx.GetRow(1, m_dxrow);
Vector dtaodxs_tmp(3); dtaodxs_tmp = 0.0;
cross(dtao1dxs_tmp, m_dxrow, dtaodxs_tmp);
Vector dtaodxs_tmp2(3); dtaodxs_tmp2 = 0.0;
m_dx.GetRow(0, m_dxrow);
dtao1dxs_tmp = 0.0; // reuse the same vector for dtao2
dtao2dxs.GetColumn(d,dtao1dxs_tmp);
cross(m_dxrow, dtao1dxs_tmp, dtaodxs_tmp2);
dtaodxs_tmp2 += dtaodxs_tmp;
dtaodxs.SetCol(d, dtaodxs_tmp2);
}
DenseMatrix dndxs(3,3); dndxs = 0.0; dndxs += dtaodxs; dndxs *= 1.0/nnorm;
DenseMatrix dndxs_tmp(3,3); dndxs_tmp = 0.0;
outer(normal, normal, dndxs_tmp);
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxs, dndxs);
DenseMatrix dgvdxs(3,3); dgvdxs = 0.0;
MultAtB(m_dx, dxidxs_m, dgvdxs);
dgvdxs *= -1;
for (int d=0; d<3; d++)
{
dgvdxs(d,d) += 1.0;
}
//dxidxs: 2*3
DenseMatrix dg2dxs(3,3); dg2dxs = 0.0;
DenseMatrix dg2dxs_tmp(3,2); dg2dxs_tmp = 0.0;
MultAtB(dxidxs_m, nde2, dg2dxs_tmp);
AddMult_a(-1.0, dg2dxs_tmp, dxidxs_m, dg2dxs);
DenseMatrix dg2dxs_tmp2(3,3); dg2dxs_tmp2 = 0.0;
MultAtB(dgvdxs, dndxs, dg2dxs_tmp2);
dg2dxs += dg2dxs_tmp2;
dg2dxs_tmp2 = 0.0;
MultAtB(dndxs, dndxs_tmp, dg2dxs_tmp2);
AddMult(dg2dxs_tmp2, dgvdxs, dg2dxs);
DenseMatrix Ne(3,12), Be(6,12), dBe(12,12);
BasisVectorDerivs(xi, Ne, Be, dBe);
DenseMatrix dtao1dxm(3,12); dtao1dxm.CopyRows(Be, 0, 2);
DenseMatrix dtao2dxm(3,12); dtao2dxm.CopyRows(Be, 3, 5);
Vector m_coords_v(12);
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
m_coords_v[i*3+j] = m_coords(i,j);
}
}
for (int i=0; i<2; i++)
{
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
dxidxm.GetRow(i,dxidxm_tmp);
DenseMatrix dBe_tmp(3,12);
dBe_tmp.CopyRows(dBe,i*3,(i+1)*3-1);
DenseMatrix dtaodxm_tmp(12,12); dtaodxm_tmp = 0.0;
outer(m_coords_v, dxidxm_tmp, dtaodxm_tmp);
AddMult(dBe_tmp, dtaodxm_tmp, dtao1dxm);
//dtao1dxm += dBe(:,:,i)*reshape(m_coords(1:4,:)',12,1)*reshape(dxidxm(i,:),1,12); % 3*12
dBe_tmp = 0.0;
dBe_tmp.CopyRows(dBe,(i+2)*3,(i+3)*3-1);
AddMult(dBe_tmp, dtaodxm_tmp, dtao2dxm);
}
DenseMatrix dtaodxm(3,12); dtaodxm = 0.0;//tao = tao1 cross tao2
for (int d=0; d<12; d++)
{
Vector dtaodxm_tmp(3); dtaodxm_tmp = 0.0;
Vector dtaodxm_tmp2(3); dtaodxm_tmp2 = 0.0;
Vector tmp1(3); tmp1 = 0.0; dtao1dxm.GetColumn(d,tmp1);
Vector m_dxrow2(3); m_dx.GetRow(1, m_dxrow2);
Vector m_dxrow1(3); m_dx.GetRow(0, m_dxrow1);
Vector tmp2(3); tmp2 = 0.0; dtao2dxm.GetColumn(d,tmp2);
cross(tmp1, m_dxrow2, dtaodxm_tmp);
cross(m_dxrow1,tmp2, dtaodxm_tmp2);
dtaodxm_tmp += dtaodxm_tmp2;
dtaodxm.SetCol(d, dtaodxm_tmp);
}
DenseMatrix dndxm(3,12); dndxm = 0.0;
dndxm += dtaodxm;
dndxm *= 1.0/nnorm;
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxm, dndxm); //dndxs_tmp = normal'*normal
DenseMatrix dgvdxm(3,12); dgvdxm = 0.0;
dgvdxm -= Ne;
for (int i=0; i<2; i++)
{
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
dxidxm.GetRow(i,dxidxm_tmp);
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
DenseMatrix dgvdxm_tmp(12,12); dgvdxm_tmp = 0.0;
outer(m_coords_v, dxidxm_tmp, dgvdxm_tmp);
AddMult_a(-1.0, Be_tmp, dgvdxm_tmp, dgvdxm);
}
DenseMatrix dg2dxsxm(3,12); dg2dxsxm = 0.0;
DenseMatrix dg2dxsxm_tmp(3,3); dg2dxsxm_tmp = 0.0;
MultAtB(dgvdxs, dndxm, dg2dxsxm);
MultAtB(dndxs, dndxs_tmp, dg2dxsxm_tmp);
AddMult(dg2dxsxm_tmp, dgvdxm, dg2dxsxm); // += dndxs'*normal'*normal*dgvdxm;
DenseMatrix dgvdxsxmn(3,12); dgvdxsxmn = 0.0;
DenseMatrix dgvdxsxmn_tmp(3,2); dgvdxsxmn_tmp = 0.0;
MultAtB(dxidxs_m, nde2, dgvdxsxmn_tmp); //dxidxs_m: 2*3
AddMult_a(-1.0, dgvdxsxmn_tmp, dxidxm, dgvdxsxmn);
for (int i =0; i<2; i++)
{
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
DenseMatrix dgvdxsxmn_tmp2(3,3); dgvdxsxmn_tmp2 = 0.0;
outer(dxidxs_row, normal, dgvdxsxmn_tmp2);
AddMult_a(-1.0, dgvdxsxmn_tmp2, Be_tmp, dgvdxsxmn);
}
dg2dxsxm += dgvdxsxmn;
DenseMatrix dg2dxmxs(12,3); dg2dxmxs = 0.0;
DenseMatrix dg2dxmxs_tmp(12,3); dg2dxmxs_tmp = 0.0;
MultAtB(dgvdxm, dndxs, dg2dxmxs);
MultAtB(dndxm, dndxs_tmp, dg2dxmxs_tmp);
AddMult(dg2dxmxs_tmp, dgvdxs, dg2dxmxs);
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
DenseMatrix dgvdxmxsn_tmp(12,2); dgvdxmxsn_tmp = 0.0;
MultAtB(dxidxm, nde2, dgvdxmxsn_tmp);
dgvdxmxsn_tmp *= -1.0;
AddMult(dgvdxmxsn_tmp, dxidxs_m, dgvdxmxsn);
for (int i =0; i<2; i++)
{
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
Be_tmp.Transpose(); // Be is now 12*3
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
DenseMatrix dgvdxmxsn_tmp2(3,3); dgvdxmxsn_tmp2 = 0.0;
outer(normal, dxidxs_row, dgvdxmxsn_tmp2);
AddMult_a(-1.0, Be_tmp, dgvdxmxsn_tmp2, dgvdxmxsn);
}
dg2dxmxs += dgvdxmxsn;
dg2dx.CopyMN(dg2dxs, 0, 0);
dg2dx.CopyMN(dg2dxm, 3, 3);
dg2dx.CopyMN(dg2dxsxm, 0, 3);
dg2dx.CopyMN(dg2dxmxs, 3, 0);
};
void NodeSegConPairs(const Vector x1, const Vector xi2,
const DenseMatrix coords2,
double& node_g, Vector& node_dg, DenseMatrix& node_dg2)
{
double gap = 0.0;
Vector normal(3); normal = 0.0;
Vector dgdxm(12); dgdxm = 0.0;
Vector dgdxs(3); dgdxs = 0.0;
ComputeGapJacobian(x1, xi2, coords2, gap, normal, dgdxm, dgdxs);
node_g = gap;
node_dg.SetSize(12+3);
for (int i=0; i<3; i++) { node_dg[i] = dgdxs[i]; }
for (int i=0; i<12; i++) { node_dg[i+3] = dgdxm[i]; }
DenseMatrix dg2dx(15,15); dg2dx = 0.0;
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
ComputeGapHessian(x1, xi2, coords2, dg2dx);
node_dg2.SetSize(15,15);
node_dg2 = dg2dx;
/*
if(obj.space1.conns{e1}(i)==150) % for debugging purpose
v1 = 1:3;
v2 = 1:12;
%v1 = ones(1,3)
%v2 = ones(1,12)
v2 = reshape(v2,4,3);
x1n1 = x1 + 0.01*v1;
coords2n1 = coords2 + 0.001*v2;
[xi2n1, gapv1, ~, ~] = SlaveToMaster(obj, coords2n1, x1n1);
[gapn1, n1,dgdxmn1, dgdxsn1] = ComputeGapJacobian(obj, x1n1, xi2n1, coords2n1);
x1n2 = x1 - 0.01*v1;
coords2n2 = coords2 - 0.001*v2;
[xi2n2, gapv2, ~, ~] = SlaveToMaster(obj, coords2n2, x1n2);
[gapn2, n2,dgdxmn2, dgdxsn2] = ComputeGapJacobian(obj, x1n2, xi2n2, coords2n2);
fprintf('fd\n');
%gapv1-gapv2
[dgdxsn1(:)',dgdxmn1(:)'] - [dgdxsn2(:)',dgdxmn2(:)']
%dgdxsn1-dgdxsn2
fprintf('code\n');
v2n = v2';
%dg2dx(1:3,1:3)*0.04*ones(3,1)
temp = zeros(12,3);
for i = 1:4
temp1 = dg2dx(3+(i-1)*3+1:3+i*3,1:3);
temp((i-1)*3+1:i*3,:) = temp1';
end
temp2 = zeros(3,12);
for i = 1:4
temp3 = dg2dx(1:3,3+(i-1)*3+1:3+i*3);
temp2(:,(i-1)*3+1:i*3) = temp3';
end
%dg2dx
%dg2dx(4:end,1:3) = temp;
%dg2dx(1:3,4:end) = temp2;
%dgvdxm * 0.002*v2n(:)
(dg2dx*[0.02*v1(:)',0.002*v2n(:)']')'
%dg2dx(4:end,1:3)
end*/
};
// coordsm : (npoints*4, 3) use what class?
// m_conn: (npoints*4)
void Assemble_Contact(const int m, const int npoints, const int ndofs,
const Vector x_s,
const Vector xi, const DenseMatrix coordsm, const Array<int> s_conn,
const Array<int> m_conn, Vector& g, SparseMatrix& M,
std::vector<SparseMatrix>& dM)
{
int n = ndofs;
int ndim = 3;
g.SetSize(m);
g = 0.0;
//SparseMatrix M(m, n); // M needs to be the correct size
//dM.resize(m); // needs to clear?
double g_tmp = 0.;
Vector dg(4*ndim+ndim);
dg = 0.;
DenseMatrix dg2(4*ndim+ndim,4*ndim+ndim);
dg2 = 0.;
for (int i=0; i<npoints; i++)
{
Vector x1(ndim);
x1[0] = x_s[i*ndim];
x1[1] = x_s[i*ndim+1];
x1[2] = x_s[i*ndim+2];
Vector xi2(ndim-1);
xi2[0] = xi[i*(ndim-1)];
xi2[1] = xi[i*(ndim-1)+1];
DenseMatrix coords2(4,3);
coords2.CopyRows(coordsm, i*4,(i+1)*4-1);
//how to get coords2?
dg = 0.0;
dg2 = 0.;
NodeSegConPairs(x1, xi2, coords2, g_tmp, dg, dg2);
//x1.Print();
//xi2.Print();
//coords2.Print();
g[s_conn[i]] = g_tmp; // should be unique
Array<int> m_conn_i(4);
m_conn.GetSubArray(4*i, 4, m_conn_i);
Array<int> node_conn(5);
node_conn[0] = s_conn[i];
for (int j=0; j<4; j++)
{
node_conn[j+1] = m_conn_i[j];
}
Array<int> M_i_tmp(1);
M_i_tmp[0] = s_conn[i];
//j_idx = (node_conn-1)*obj.disp_field.num_components +repmat((1:obj.disp_field.num_components)', 1, length(node_conn{i}));
Array<int> j_idx(5*ndim); j_idx = 0;
for (int j=0; j< 5; j++)
{
for (int k=0; k<ndim; k++)
{
j_idx[j*ndim+k] = node_conn[j]*ndim+k;
}
}
DenseMatrix M_v_tmp(1, ndim*(4+1)); // SetData now?
M_v_tmp.SetRow(0, dg);
M.AddSubMatrix(M_i_tmp, j_idx, M_v_tmp);
Array<int> dM_i(ndim*(4+1));
Array<int> dM_j(ndim*(4+1));
for (int j=0; j< ndim*(4+1); j++)
{
dM_i[j] = j_idx[j];
dM_j[j] = j_idx[j];
}
//dg2.Print();
//dM[s_conn[i]].Print();
dM[s_conn[i]].AddSubMatrix(dM_i,dM_j, dg2);
}
};
-3
View File
@@ -46,9 +46,6 @@ endif
ifeq ($(MFEM_USE_HIOP),YES)
SUBDIRS += hiop
endif
ifeq ($(MFEM_USE_IPOPT),YES)
SUBDIRS += ipopt
endif
ifeq ($(MFEM_USE_PETSC),YES)
SUBDIRS += petsc
endif
-888
View File
@@ -1,888 +0,0 @@
using namespace std;
using namespace mfem;
void BasisEval(const Vector xi, Vector &N, DenseMatrix &dNdxi) // dNdxi is 2*4
{
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi(0,0) = 0.25*(-1+xi[1]);
dNdxi(0,1) = 0.25*(1-xi[1]);
dNdxi(0,2) = 0.25*(1+xi[1]);
dNdxi(0,3) = 0.25*(-1-xi[1]);
dNdxi(1,0) = 0.25*(-1+xi[0]);
dNdxi(1,1) = 0.25*(-1-xi[0]);
dNdxi(1,2) = 0.25*(1+xi[0]);
dNdxi(1,3) = 0.25*(1-xi[0]);
}
void BasisEvalDerivs(const Vector xi, Vector& N, DenseMatrix& dNdxi,
DenseMatrix& dN2dxi)
{
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi.SetSize(2,4); dNdxi = 0.0;
dN2dxi.SetSize(3,4);
dN2dxi = 0.0; // first row dxi2, second detadxi, third deta2
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,1) = 0.25*(1-xi[1]);
dNdxi(0,2) = 0.25*(1+xi[1]); dNdxi(0,3) = 0.25*(-1-xi[1]);
dNdxi(1,0) = 0.25*(-1+xi[0]); dNdxi(1,1) = 0.25*(-1-xi[0]);
dNdxi(1,2) = 0.25*(1+xi[0]); dNdxi(1,3) = 0.25*(1-xi[0]);
dN2dxi(1,0) = 0.25; dN2dxi(1,1) = -0.25; dN2dxi(1,2) = 0.25;
dN2dxi(1,3) = -0.25;
}
// returns the vector and matrix form of the shape functions and its derivative
void BasisVectorDerivs(const Vector xi, DenseMatrix& N, DenseMatrix& dNdxi,
DenseMatrix& ddNdxi)
{
N.SetSize(3,12); N = 0.0;
N(0,0) = 0.25*(1-xi[0])*(1-xi[1]); N(0,3) = 0.25*(1+xi[0])*(1-xi[1]);
N(0,6) = 0.25*(1+xi[0])*(1+xi[1]); N(0,9) = 0.25*(1-xi[0])*(1+xi[1]);
N(1,1) = 0.25*(1-xi[0])*(1-xi[1]); N(1,4) = 0.25*(1+xi[0])*(1-xi[1]);
N(1,7) = 0.25*(1+xi[0])*(1+xi[1]); N(1,10) = 0.25*(1-xi[0])*(1+xi[1]);
N(2,2) = 0.25*(1-xi[0])*(1-xi[1]); N(2,5) = 0.25*(1+xi[0])*(1-xi[1]);
N(2,8) = 0.25*(1+xi[0])*(1+xi[1]); N(2,11) = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi.SetSize(3*2, 3*4); dNdxi = 0.0;
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,3) = 0.25*(1-xi[1]);
dNdxi(0,6) = 0.25*(1+xi[1]); dNdxi(0,9) = 0.25*(-1-xi[1]);
dNdxi(1,1) = 0.25*(-1+xi[1]); dNdxi(1,4) = 0.25*(1-xi[1]);
dNdxi(1,7) = 0.25*(1+xi[1]); dNdxi(1,10) = 0.25*(-1-xi[1]);
dNdxi(2,2) = 0.25*(-1+xi[1]); dNdxi(2,5) = 0.25*(1-xi[1]);
dNdxi(2,8) = 0.25*(1+xi[1]); dNdxi(2,11) = 0.25*(-1-xi[1]);
dNdxi(3,0) = 0.25*(-1+xi[0]); dNdxi(3,3) = 0.25*(-1-xi[0]);
dNdxi(3,6) = 0.25*(1+xi[0]); dNdxi(3,9) = 0.25*(1-xi[0]);
dNdxi(4,1) = 0.25*(-1+xi[0]); dNdxi(4,4) = 0.25*(-1-xi[0]);
dNdxi(4,7) = 0.25*(1+xi[0]); dNdxi(4,10) = 0.25*(1-xi[0]);
dNdxi(5,2) = 0.25*(-1+xi[0]); dNdxi(5,5) = 0.25*(-1-xi[0]);
dNdxi(5,8) = 0.25*(1+xi[0]); dNdxi(5,11) = 0.25*(1-xi[0]);
ddNdxi.SetSize(3*4, 3*4); ddNdxi = 0.0;
ddNdxi(3,0) = 0.25; ddNdxi(3,3) = -0.25;
ddNdxi(3,6) = 0.25; ddNdxi(3,9) = -0.25;
ddNdxi(4,1) = 0.25; ddNdxi(4,4) = -0.25;
ddNdxi(4,7) = 0.25; ddNdxi(4,10) = -0.25;
ddNdxi(5,2) = 0.25; ddNdxi(5,5) = -0.25;
ddNdxi(5,8) = 0.25; ddNdxi(5,11) = -0.25;
ddNdxi(6,0) = 0.25; ddNdxi(6,3) = -0.25;
ddNdxi(6,6) = 0.25; ddNdxi(6,9) = -0.25;
ddNdxi(7,1) = 0.25; ddNdxi(7,4) = -0.25;
ddNdxi(7,7) = 0.25; ddNdxi(7,10) = -0.25;
ddNdxi(8,2) = 0.25; ddNdxi(8,5) = -0.25;
ddNdxi(8,8) = 0.25; ddNdxi(8,11) = -0.25;
}
void cross(const Vector a, const Vector b, Vector& c)
{
assert(a.Size()==3);
c.SetSize(3);
c[0] = a[1]*b[2] - a[2]*b[1];
c[1] = -a[0]*b[2] + b[0]*a[2];
c[2] = a[0]*b[1] - a[1]*b[0];
}
// a outer b
void outer(const Vector a, const Vector b, DenseMatrix& c)
{
int m = a.Size();
int n = b.Size();
assert(c.Height()==m);
assert(c.Width() ==n);
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
{
c(i,j) = a[i]*b[j];
}
}
}
// dphidxi 2*4
// coords 4*3
void ComputeNormal(const DenseMatrix& dphidxi, const DenseMatrix& coords,
Vector& normal, double& nnorm)
{
DenseMatrix dxdxi(2,3);
Mult(dphidxi, coords, dxdxi);
Vector dxdxi1(3);
Vector dxdxi2(3);
dxdxi.GetRow(0,dxdxi1);
dxdxi.GetRow(1,dxdxi2);
cross(dxdxi1, dxdxi2, normal); // is there a cross product? no
// VectorCrossProductCoefficient::Eval has hard-coded cross product
nnorm = normal.Norml2( );
normal /= nnorm;
}
void SlaveToMaster(const DenseMatrix& m_coords, const Vector& s_x, Vector& xi)
{
bool converged = false;
bool pt_on_elem = false;
int dim = 3;
xi.SetSize(dim-1);
xi = 0.0;
double r = 1e10;
int max_iter = 15;
double off_el_xi = 1e-2;
double proj_newton_tol = 1e-13;
double proj_max_gap = 0.5;
Vector gap_v(dim);
// warm start from linear solution
for (int it=0; it<max_iter; it++)
{
//cout<<it<<endl;
Vector m_N(4);
m_N = 0.;
DenseMatrix m_dN(2,4);
m_dN = 0.;
DenseMatrix m_dN2(3,4);
m_dN2 = 0.;
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
Vector x_c(dim);
m_coords.MultTranspose(m_N, x_c);
gap_v = s_x;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
m_dx = 0.;
Mult(m_dN, m_coords, m_dx);
Vector r(dim-1);
r = 0.0;
m_dx.Mult(gap_v, r);
if (r.Normlinf() < proj_newton_tol)
{
converged = true;
break;
}
DenseMatrix drdxi(dim-1,dim-1);
drdxi = 0.;
MultABt(m_dx, m_dx, drdxi); // m_dx * m_dx.T
drdxi *= -1.0;
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
Mult(m_dN2,m_coords, m_dx2);
//m_d2x = m_dN(:,:,2) * m_elem_coords(1:4,:); //m_dN(:,:,2) is 3*4
for (int d=0; d<3; d++)
{
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
drdxi.Add(gap_v[d], Mtemp);
}
//cond_num = rcond(drdxi); condition number?
//drdxi.TestInversion();
DenseMatrixInverse drdxi_inv(drdxi);
Vector xi_tmp(dim-1);
drdxi_inv.Mult(r,xi_tmp);
xi -= xi_tmp;
}
if (!converged)
{
xi = 0.0;
}
off_el_xi += 1 ; // tolerance of offset of xi outside [-1,1]
//cout<<gap_v.Norml2()<<" " <<xi.Normlinf()<<endl;
if (gap_v.Norml2() < proj_max_gap && xi.Normlinf() <= off_el_xi)
{
pt_on_elem = true;
}
MFEM_VERIFY(pt_on_elem == true, "xi went out of bounds");
MFEM_VERIFY(converged == true, "projection didn't converge");
}
// m_coords is expected to be 4 * 3
void ComputeGapJacobian(const Vector x_s, const Vector xi,
const DenseMatrix m_coords,
double& gap, Vector& normal, Vector& dgdxm, Vector& dgdxs)
{
Vector m_N(4);
DenseMatrix m_dN(2,4);
DenseMatrix m_dN2(3,4);
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
Vector x_c(3);
m_coords.MultTranspose(m_N, x_c);
Vector gap_v(3); gap_v = 0.0;
gap_v = x_s;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
Mult(m_dN, m_coords, m_dx);
double nnorm = 0;
ComputeNormal(m_dN, m_coords, normal, nnorm);
gap = gap_v * normal; // gap function value, dot product between vectors
//dr_dx = zeros(2,4,3); % nsegment, nodes in quad, ndim
DenseMatrix dr_dx_res1(4,3); dr_dx_res1 = 0.;
DenseMatrix dr_dx_res2(4,3); dr_dx_res2 = 0.;
Vector m_dxrow1(3);
m_dx.GetRow(0, m_dxrow1);
outer(m_N, m_dxrow1, dr_dx_res1);// 4*1 times 1*3
dr_dx_res1 *= -1.0;
Vector m_dxrow2(3);
m_dx.GetRow(1, m_dxrow2);
outer(m_N, m_dxrow2, dr_dx_res2);// 4*1 times 1*3
dr_dx_res2 *= -1.0;
Vector m_dNrow1(4); m_dN.GetRow(0, m_dNrow1);
Vector m_dNrow2(4); m_dN.GetRow(1, m_dNrow2);
DenseMatrix dr_dx_res1_tmp(4,3); dr_dx_res1_tmp = 0.;
DenseMatrix dr_dx_res2_tmp(4,3); dr_dx_res2_tmp = 0.;
outer(m_dNrow1, gap_v, dr_dx_res1_tmp);// 4*1 times 1*3
outer(m_dNrow2, gap_v, dr_dx_res2_tmp);// 4*1 times 1*3
dr_dx_res1 += dr_dx_res1_tmp; // outer product in vector?
dr_dx_res2 += dr_dx_res2_tmp;
DenseMatrix K_dxidx1(2,2); // 2*2
K_dxidx1 = 0.;
MultABt(m_dx, m_dx, K_dxidx1); // m_dx * m_dx.T
Vector v_dxidx2(4);
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
// how to get 2nd order? multidimensional matrix?
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
DenseMatrix K_dxidx(2,2);
K_dxidx -= K_dxidx1;
K_dxidx += K_dxidx2;
// resize the vectors and matrices
Vector dxidx(24); dxidx = 0.0;
Vector drdx_r(24); drdx_r = 0.0;
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
drdx_r[4*j+i] = dr_dx_res1(i,j);
drdx_r[4*j+i+12] = dr_dx_res2(i,j);
}
}
//drdx_r(1:4*3,1) = reshape(dr_dx_res(:,:,1),4*3,1);
//drdx_r(4*3+1:2*4*3,1) = reshape(dr_dx_res(:,:,2),4*3,1);
DenseMatrix drdx_K(24,24); drdx_K = 0.;
for (int i =0; i<12; i++)
{
drdx_K(i,i) = K_dxidx(0,0);
drdx_K(i,12+i) = K_dxidx(0,1);
drdx_K(12+i,i) = K_dxidx(1,0);
drdx_K(12+i,12+i) = K_dxidx(1,1);
}
DenseMatrixInverse drdxK_inv(drdx_K);
drdxK_inv.Mult(drdx_r,dxidx);
// LinearSolve (drdx_K,drdx_r, dxidx) ; //???
dxidx *= -1.0;
Vector drdxs_r(6);
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
for (int i=0; i<3; i++)
{
drdxs_K(i,i) = K_dxidx(0,0);
drdxs_K(i,3+i) = K_dxidx(0,1);
drdxs_K(i+3,i) = K_dxidx(1,0);
drdxs_K(i+3,i+3) = K_dxidx(1,1);
}
Vector dxidxs(6); dxidxs = 0.0;
DenseMatrixInverse drdxsK_inv(drdxs_K);
drdxsK_inv.Mult(drdxs_r,dxidxs);
dxidxs *= -1.0;
//dxidxs = -drdxs_K\drdxs_r;
//dxidx = reshape(dxidx, 4,3,2); dxidxs = reshape(dxidxs, 1,3,2);
dgdxm.SetSize(12); dgdxm = 0.;
DenseMatrix dgdxm_tmp(4,3);
outer(m_N, normal,dgdxm_tmp);
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
dgdxm[3*i+j] = -dgdxm_tmp(i,j);
}
}
//dxidx_M = -m_dN(1:2,:,1) * (m_coords(1:4,:)*normal'); % this turns out to be 0
dgdxs.SetSize(3);
dgdxs += normal;
//dgdxs = dgdxs + dxidx_M(1) * dxidxs(:,:,1) + dxidx_M(2) * dxidxs(:,:,2);
};
void ComputeGapHessian(const Vector x_s, const Vector xi,
const DenseMatrix m_coords,
DenseMatrix& dg2dx)
{
Vector m_N(4);
DenseMatrix m_dN(2,4);
DenseMatrix m_dN2(3,4);
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
int dim = 3;
int num_dofs1 = dim;
int num_dofs2 = 4*dim;
int num_dofs = num_dofs1 + num_dofs2;
dg2dx.SetSize(num_dofs,num_dofs); dg2dx = 0.0;
Vector x_c(3);
m_coords.MultTranspose(m_N,x_c);
Vector gap_v(3); gap_v = 0.0;
gap_v = x_s;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
Mult(m_dN, m_coords, m_dx);
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
Mult(m_dN2,m_coords, m_dx2);
double nnorm = 0.0;
Vector normal(3); normal = 0.0;
ComputeNormal(m_dN, m_coords, normal, nnorm);
double gap = gap_v * normal; // gap function value, dot product between vectors
DenseMatrix M(2,2); M = 0.0;
MultABt(m_dx, m_dx, M);
DenseMatrix f(2, num_dofs2); f = 0.0;
for (int d=0; d<3; d++)
{
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
M.Add(-gap_v[d], Mtemp);
Vector m_dxcol(2); m_dx.GetColumn(d, m_dxcol);
DenseMatrix ftmp(2,4);
outer(m_dxcol, m_N, ftmp);
ftmp *= -1;
ftmp.Add( gap_v[d], m_dN); // 2*4
for (int j=0; j<4; j++)
{
assert(d+3*j<num_dofs2);
f(0,d+j*3) = ftmp(0,j);
f(1,d+j*3) = ftmp(1,j);
}
}
//fprintf('hess dxidxm\n');
DenseMatrixInverse Minv(M);
DenseMatrix dxidxm(2,num_dofs2); dxidxm = 0.0;
Minv.Mult(f, dxidxm);
//LinearSolve??
//dxidxm = M\f;
DenseMatrix nde2(2,2); nde2 = 0.0;
DenseMatrix Nndx2(2,num_dofs2); Nndx2 = 0.0;
for (int d=0; d<3; d++)
{
DenseMatrix ndetmp(2,2); ndetmp = 0.0;
ndetmp(0,0) = normal(d)*m_dx2(0,d); ndetmp(0,1) = normal(d)*m_dx2(1,d);
ndetmp(1,0) = normal(d)*m_dx2(1,d); ndetmp(1,1) = normal(d)*m_dx2(2,d);
nde2 += ndetmp;
for (int j=0; j<4; j++)
{
assert(d+3*j<num_dofs2);
Nndx2(0,d+j*3) = normal[d]*m_dN(0,j);
Nndx2(1,d+j*3) = normal[d]*m_dN(1,j);
}
}
DenseMatrix Ndn(2,num_dofs2); Ndn = 0.0;
Ndn += Nndx2;
AddMult(nde2, dxidxm, Ndn);
DenseMatrix M2(2,2); M2 = 0.0;
MultABt(m_dx, m_dx, M2);
DenseMatrixInverse M2inv(M2);
DenseMatrix diag2(2,2); diag2(0,0) = 1.0; diag2(1,1) = 1.0;
DenseMatrix m_con(2,2); m_con = 0.0;
M2inv.Mult(diag2, m_con);
DenseMatrix dg2dxm(num_dofs2, num_dofs2); dg2dxm = 0.0;
DenseMatrix dg2dxm_tmp(num_dofs2,2); dg2dxm_tmp = 0.0;
MultAtB(Ndn, m_con, dg2dxm_tmp);
Mult(dg2dxm_tmp, Ndn, dg2dxm);
dg2dxm *= gap;
DenseMatrix dg2dxm_tmp2(num_dofs2,num_dofs2); dg2dxm_tmp2 = 0.0;
MultAtB(Nndx2, dxidxm, dg2dxm_tmp2);
dg2dxm.Add(-1.0, dg2dxm_tmp2);
dg2dxm_tmp = 0.0;
MultAtB(dxidxm, nde2, dg2dxm_tmp);
AddMult_a(-1.0, dg2dxm_tmp, dxidxm, dg2dxm);
dg2dxm_tmp2 = 0.0;
MultAtB(dxidxm, Nndx2, dg2dxm_tmp2);
dg2dxm.Add(-1.0, dg2dxm_tmp2);
Vector v_dxidx2(4);
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
DenseMatrix K_dxidx(2,2);
K_dxidx -= M2;
K_dxidx += K_dxidx2;
Vector drdxs_r(6);
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
for (int i=0; i<3; i++)
{
drdxs_K(i,i) = K_dxidx(0,0);
drdxs_K(i,3+i) = K_dxidx(0,1);
drdxs_K(i+3,i) = K_dxidx(1,0);
drdxs_K(i+3,i+3) = K_dxidx(1,1);
}
Vector dxidxs(6);
DenseMatrixInverse drdxsK_inv(drdxs_K);
drdxsK_inv.Mult(drdxs_r,dxidxs);
dxidxs *= -1.0;
//dxidxs = -drdxs_K\drdxs_r;
DenseMatrix dxidxs_m(2,3); dxidxs_m = 0.0;
dxidxs_m(0,0) = dxidxs[0]; dxidxs_m(0,1) = dxidxs[1]; dxidxs_m(0,2) = dxidxs[2];
dxidxs_m(1,0) = dxidxs[3]; dxidxs_m(1,1) = dxidxs[4]; dxidxs_m(1,2) = dxidxs[5];
DenseMatrix dtao1dxs(3,3); dtao1dxs = 0.0;
DenseMatrix dtao2dxs(3,3); dtao2dxs = 0.0;
Vector dxidxs_row1(3); dxidxs_row1 = 0.0; Vector dxidxs_row2(3);
dxidxs_row2 = 0.0;
Vector mdx2_row1(3); mdx2_row1 = 0.0; Vector mdx2_row2(3); mdx2_row2 = 0.0;
Vector mdx2_row3(3); mdx2_row3 = 0.0;
dxidxs_m.GetRow(0,dxidxs_row1);
dxidxs_m.GetRow(1,dxidxs_row2);
m_dx2.GetRow(0,mdx2_row1);
m_dx2.GetRow(1,mdx2_row2);
m_dx2.GetRow(2,mdx2_row3);
DenseMatrix dtaotmp(3,3); dtaotmp = 0.0;
outer(mdx2_row1, dxidxs_row1,dtaotmp);
dtao1dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row2, dxidxs_row1,dtaotmp);
dtao1dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row2, dxidxs_row2, dtaotmp);
dtao2dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row3, dxidxs_row2, dtaotmp);
dtao2dxs += dtaotmp; dtaotmp = 0.0;
DenseMatrix dtaodxs(3,3); dtaodxs = 0.0; //tao = tao1 cross tao2
for (int d=0; d<3; d++)
{
Vector dtao1dxs_tmp(3); dtao1dxs_tmp = 0.0;
dtao1dxs.GetColumn(d,dtao1dxs_tmp);
Vector m_dxrow(3); m_dx.GetRow(1, m_dxrow);
Vector dtaodxs_tmp(3); dtaodxs_tmp = 0.0;
cross(dtao1dxs_tmp, m_dxrow, dtaodxs_tmp);
Vector dtaodxs_tmp2(3); dtaodxs_tmp2 = 0.0;
m_dx.GetRow(0, m_dxrow);
dtao1dxs_tmp = 0.0; // reuse the same vector for dtao2
dtao2dxs.GetColumn(d,dtao1dxs_tmp);
cross(m_dxrow, dtao1dxs_tmp, dtaodxs_tmp2);
dtaodxs_tmp2 += dtaodxs_tmp;
dtaodxs.SetCol(d, dtaodxs_tmp2);
}
DenseMatrix dndxs(3,3); dndxs = 0.0; dndxs += dtaodxs; dndxs *= 1.0/nnorm;
DenseMatrix dndxs_tmp(3,3); dndxs_tmp = 0.0;
outer(normal, normal, dndxs_tmp);
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxs, dndxs);
DenseMatrix dgvdxs(3,3); dgvdxs = 0.0;
MultAtB(m_dx, dxidxs_m, dgvdxs);
dgvdxs *= -1;
for (int d=0; d<3; d++)
{
dgvdxs(d,d) += 1.0;
}
//dxidxs: 2*3
DenseMatrix dg2dxs(3,3); dg2dxs = 0.0;
DenseMatrix dg2dxs_tmp(3,2); dg2dxs_tmp = 0.0;
MultAtB(dxidxs_m, nde2, dg2dxs_tmp);
AddMult_a(-1.0, dg2dxs_tmp, dxidxs_m, dg2dxs);
DenseMatrix dg2dxs_tmp2(3,3); dg2dxs_tmp2 = 0.0;
MultAtB(dgvdxs, dndxs, dg2dxs_tmp2);
dg2dxs += dg2dxs_tmp2;
dg2dxs_tmp2 = 0.0;
MultAtB(dndxs, dndxs_tmp, dg2dxs_tmp2);
AddMult(dg2dxs_tmp2, dgvdxs, dg2dxs);
DenseMatrix Ne(3,12), Be(6,12), dBe(12,12);
BasisVectorDerivs(xi, Ne, Be, dBe);
DenseMatrix dtao1dxm(3,12); dtao1dxm.CopyRows(Be, 0, 2);
DenseMatrix dtao2dxm(3,12); dtao2dxm.CopyRows(Be, 3, 5);
Vector m_coords_v(12);
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
m_coords_v[i*3+j] = m_coords(i,j);
}
}
for (int i=0; i<2; i++)
{
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
dxidxm.GetRow(i,dxidxm_tmp);
DenseMatrix dBe_tmp(3,12);
dBe_tmp.CopyRows(dBe,i*3,(i+1)*3-1);
DenseMatrix dtaodxm_tmp(12,12); dtaodxm_tmp = 0.0;
outer(m_coords_v, dxidxm_tmp, dtaodxm_tmp);
AddMult(dBe_tmp, dtaodxm_tmp, dtao1dxm);
//dtao1dxm += dBe(:,:,i)*reshape(m_coords(1:4,:)',12,1)*reshape(dxidxm(i,:),1,12); % 3*12
dBe_tmp = 0.0;
dBe_tmp.CopyRows(dBe,(i+2)*3,(i+3)*3-1);
AddMult(dBe_tmp, dtaodxm_tmp, dtao2dxm);
}
DenseMatrix dtaodxm(3,12); dtaodxm = 0.0;//tao = tao1 cross tao2
for (int d=0; d<12; d++)
{
Vector dtaodxm_tmp(3); dtaodxm_tmp = 0.0;
Vector dtaodxm_tmp2(3); dtaodxm_tmp2 = 0.0;
Vector tmp1(3); tmp1 = 0.0; dtao1dxm.GetColumn(d,tmp1);
Vector m_dxrow2(3); m_dx.GetRow(1, m_dxrow2);
Vector m_dxrow1(3); m_dx.GetRow(0, m_dxrow1);
Vector tmp2(3); tmp2 = 0.0; dtao2dxm.GetColumn(d,tmp2);
cross(tmp1, m_dxrow2, dtaodxm_tmp);
cross(m_dxrow1,tmp2, dtaodxm_tmp2);
dtaodxm_tmp += dtaodxm_tmp2;
dtaodxm.SetCol(d, dtaodxm_tmp);
}
DenseMatrix dndxm(3,12); dndxm = 0.0;
dndxm += dtaodxm;
dndxm *= 1.0/nnorm;
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxm, dndxm); //dndxs_tmp = normal'*normal
DenseMatrix dgvdxm(3,12); dgvdxm = 0.0;
dgvdxm -= Ne;
for (int i=0; i<2; i++)
{
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
dxidxm.GetRow(i,dxidxm_tmp);
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
DenseMatrix dgvdxm_tmp(12,12); dgvdxm_tmp = 0.0;
outer(m_coords_v, dxidxm_tmp, dgvdxm_tmp);
AddMult_a(-1.0, Be_tmp, dgvdxm_tmp, dgvdxm);
}
DenseMatrix dg2dxsxm(3,12); dg2dxsxm = 0.0;
DenseMatrix dg2dxsxm_tmp(3,3); dg2dxsxm_tmp = 0.0;
MultAtB(dgvdxs, dndxm, dg2dxsxm);
MultAtB(dndxs, dndxs_tmp, dg2dxsxm_tmp);
AddMult(dg2dxsxm_tmp, dgvdxm, dg2dxsxm); // += dndxs'*normal'*normal*dgvdxm;
DenseMatrix dgvdxsxmn(3,12); dgvdxsxmn = 0.0;
DenseMatrix dgvdxsxmn_tmp(3,2); dgvdxsxmn_tmp = 0.0;
MultAtB(dxidxs_m, nde2, dgvdxsxmn_tmp); //dxidxs_m: 2*3
AddMult_a(-1.0, dgvdxsxmn_tmp, dxidxm, dgvdxsxmn);
for (int i =0; i<2; i++)
{
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
DenseMatrix dgvdxsxmn_tmp2(3,3); dgvdxsxmn_tmp2 = 0.0;
outer(dxidxs_row, normal, dgvdxsxmn_tmp2);
AddMult_a(-1.0, dgvdxsxmn_tmp2, Be_tmp, dgvdxsxmn);
}
dg2dxsxm += dgvdxsxmn;
DenseMatrix dg2dxmxs(12,3); dg2dxmxs = 0.0;
DenseMatrix dg2dxmxs_tmp(12,3); dg2dxmxs_tmp = 0.0;
MultAtB(dgvdxm, dndxs, dg2dxmxs);
MultAtB(dndxm, dndxs_tmp, dg2dxmxs_tmp);
AddMult(dg2dxmxs_tmp, dgvdxs, dg2dxmxs);
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
DenseMatrix dgvdxmxsn_tmp(12,2); dgvdxmxsn_tmp = 0.0;
MultAtB(dxidxm, nde2, dgvdxmxsn_tmp);
dgvdxmxsn_tmp *= -1.0;
AddMult(dgvdxmxsn_tmp, dxidxs_m, dgvdxmxsn);
for (int i =0; i<2; i++)
{
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
Be_tmp.Transpose(); // Be is now 12*3
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
DenseMatrix dgvdxmxsn_tmp2(3,3); dgvdxmxsn_tmp2 = 0.0;
outer(normal, dxidxs_row, dgvdxmxsn_tmp2);
AddMult_a(-1.0, Be_tmp, dgvdxmxsn_tmp2, dgvdxmxsn);
}
dg2dxmxs += dgvdxmxsn;
dg2dx.CopyMN(dg2dxs, 0, 0);
dg2dx.CopyMN(dg2dxm, 3, 3);
dg2dx.CopyMN(dg2dxsxm, 0, 3);
dg2dx.CopyMN(dg2dxmxs, 3, 0);
};
void NodeSegConPairs(const Vector x1, const Vector xi2,
const DenseMatrix coords2,
double& node_g, Vector& node_dg, DenseMatrix& node_dg2)
{
double gap = 0.0;
Vector normal(3); normal = 0.0;
Vector dgdxm(12); dgdxm = 0.0;
Vector dgdxs(3); dgdxs = 0.0;
ComputeGapJacobian(x1, xi2, coords2, gap, normal, dgdxm, dgdxs);
node_g = gap;
node_dg.SetSize(12+3);
for (int i=0; i<3; i++) { node_dg[i] = dgdxs[i]; }
for (int i=0; i<12; i++) { node_dg[i+3] = dgdxm[i]; }
DenseMatrix dg2dx(15,15); dg2dx = 0.0;
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
ComputeGapHessian(x1, xi2, coords2, dg2dx);
node_dg2.SetSize(15,15);
node_dg2 = dg2dx;
/*
if(obj.space1.conns{e1}(i)==150) % for debugging purpose
v1 = 1:3;
v2 = 1:12;
%v1 = ones(1,3)
%v2 = ones(1,12)
v2 = reshape(v2,4,3);
x1n1 = x1 + 0.01*v1;
coords2n1 = coords2 + 0.001*v2;
[xi2n1, gapv1, ~, ~] = SlaveToMaster(obj, coords2n1, x1n1);
[gapn1, n1,dgdxmn1, dgdxsn1] = ComputeGapJacobian(obj, x1n1, xi2n1, coords2n1);
x1n2 = x1 - 0.01*v1;
coords2n2 = coords2 - 0.001*v2;
[xi2n2, gapv2, ~, ~] = SlaveToMaster(obj, coords2n2, x1n2);
[gapn2, n2,dgdxmn2, dgdxsn2] = ComputeGapJacobian(obj, x1n2, xi2n2, coords2n2);
fprintf('fd\n');
%gapv1-gapv2
[dgdxsn1(:)',dgdxmn1(:)'] - [dgdxsn2(:)',dgdxmn2(:)']
%dgdxsn1-dgdxsn2
fprintf('code\n');
v2n = v2';
%dg2dx(1:3,1:3)*0.04*ones(3,1)
temp = zeros(12,3);
for i = 1:4
temp1 = dg2dx(3+(i-1)*3+1:3+i*3,1:3);
temp((i-1)*3+1:i*3,:) = temp1';
end
temp2 = zeros(3,12);
for i = 1:4
temp3 = dg2dx(1:3,3+(i-1)*3+1:3+i*3);
temp2(:,(i-1)*3+1:i*3) = temp3';
end
%dg2dx
%dg2dx(4:end,1:3) = temp;
%dg2dx(1:3,4:end) = temp2;
%dgvdxm * 0.002*v2n(:)
(dg2dx*[0.02*v1(:)',0.002*v2n(:)']')'
%dg2dx(4:end,1:3)
end*/
};
// coordsm : (npoints*4, 3) use what class?
// m_conn: (npoints*4)
void Assemble_Contact(const int m, const int npoints, const int ndofs,
const Vector x_s,
const Vector xi, const DenseMatrix coordsm, const Array<int> s_conn,
const Array<int> m_conn, Vector& g, SparseMatrix& M,
std::vector<SparseMatrix>& dM)
{
int n = ndofs;
int ndim = 3;
g.SetSize(m);
g = 0.0;
//SparseMatrix M(m, n); // M needs to be the correct size
//dM.resize(m); // needs to clear?
double g_tmp = 0.;
Vector dg(4*ndim+ndim);
dg = 0.;
DenseMatrix dg2(4*ndim+ndim,4*ndim+ndim);
dg2 = 0.;
for (int i=0; i<npoints; i++)
{
Vector x1(ndim);
x1[0] = x_s[i*ndim];
x1[1] = x_s[i*ndim+1];
x1[2] = x_s[i*ndim+2];
Vector xi2(ndim-1);
xi2[0] = xi[i*(ndim-1)];
xi2[1] = xi[i*(ndim-1)+1];
DenseMatrix coords2(4,3);
coords2.CopyRows(coordsm, i*4,(i+1)*4-1);
//how to get coords2?
dg = 0.0;
dg2 = 0.;
NodeSegConPairs(x1, xi2, coords2, g_tmp, dg, dg2);
//x1.Print();
//xi2.Print();
//coords2.Print();
g[s_conn[i]] = g_tmp; // should be unique
Array<int> m_conn_i(4);
m_conn.GetSubArray(4*i, 4, m_conn_i);
Array<int> node_conn(5);
node_conn[0] = s_conn[i];
for (int j=0; j<4; j++)
{
node_conn[j+1] = m_conn_i[j];
}
Array<int> M_i_tmp(1);
M_i_tmp[0] = s_conn[i];
//j_idx = (node_conn-1)*obj.disp_field.num_components +repmat((1:obj.disp_field.num_components)', 1, length(node_conn{i}));
Array<int> j_idx(5*ndim); j_idx = 0;
for (int j=0; j< 5; j++)
{
for (int k=0; k<ndim; k++)
{
j_idx[j*ndim+k] = node_conn[j]*ndim+k;
}
}
DenseMatrix M_v_tmp(1, ndim*(4+1)); // SetData now?
M_v_tmp.SetRow(0, dg);
M.AddSubMatrix(M_i_tmp, j_idx, M_v_tmp);
Array<int> dM_i(ndim*(4+1));
Array<int> dM_j(ndim*(4+1));
for (int j=0; j< ndim*(4+1); j++)
{
dM_i[j] = j_idx[j];
dM_j[j] = j_idx[j];
}
//dg2.Print();
//dM[s_conn[i]].Print();
dM[s_conn[i]].AddSubMatrix(dM_i,dM_j, dg2);
}
};
+3
View File
@@ -44,6 +44,7 @@ set(SRCS
eltrans.cpp
estimators.cpp
fe.cpp
fe/face_map_utils.cpp
fe/fe_base.cpp
fe/fe_fixed_order.cpp
fe/fe_h1.cpp
@@ -74,6 +75,7 @@ set(SRCS
linearform_ext.cpp
lininteg.cpp
lininteg_boundary.cpp
lininteg_boundary_flux.cpp
lininteg_domain.cpp
lininteg_domain_grad.cpp
lor/lor.cpp
@@ -151,6 +153,7 @@ set(HDRS
eltrans.hpp
estimators.hpp
fe.hpp
fe/face_map_utils.hpp
fe/fe_base.hpp
fe/fe_fixed_order.hpp
fe/fe_h1.hpp
+1 -1
View File
@@ -529,7 +529,7 @@ void EABilinearFormExtension::Assemble()
}
faceDofs = trial_fes ->
GetTraceElement(0, trial_fes->GetMesh()->GetFaceGeometry(0)) ->
GetTraceElement(0, trial_fes->GetMesh()->GetFaceBaseGeometry(0)) ->
GetDof();
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
+5 -1
View File
@@ -208,6 +208,10 @@ public:
Vector &x, Vector &b,
OperatorHandle &A, Vector &X, Vector &B) = 0;
virtual void AddMult(const Vector &x, Vector &y, const double c=1.0) const = 0;
virtual void AddMultTranspose(const Vector &x, Vector &y,
const double c=1.0) const = 0;
virtual void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const = 0;
virtual void Update() = 0;
@@ -283,7 +287,7 @@ public:
/// Partial assembly of all internal integrators
void Assemble();
void AddMult(const Vector &x, Vector &y, const double c=1.0) const;
void AddMult(const Vector &x, Vector &y, const double c) const;
void AddMultTranspose(const Vector &x, Vector &y, const double c=1.0) const;
+1 -1
View File
@@ -145,7 +145,7 @@ void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement &el =
*fes.GetTraceElement(0, fes.GetMesh()->GetFaceGeometry(0));
*fes.GetTraceElement(0, fes.GetMesh()->GetFaceBaseGeometry(0));
FaceElementTransformations &T0 =
*fes.GetMesh()->GetFaceElementTransformations(0);
const IntegrationRule *ir = IntRule?
+21 -5
View File
@@ -56,7 +56,8 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
dim = mesh->Dimension();
ne = fes.GetMesh()->GetNE();
nq = ir->GetNPoints();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::DETERMINANTS, mt);
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::COORDINATES |
GeometricFactors::JACOBIANS, mt);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
@@ -73,7 +74,7 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
const auto J = Reshape(geom->detJ.Read(), Q1D,Q1D,NE);
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,2,2,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D, NE);
@@ -83,7 +84,11 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double detJ = J(qx,qy,e);
const double J11 = J(qx,qy,0,0,e);
const double J12 = J(qx,qy,1,0,e);
const double J21 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double detJ = (J11*J22)-(J21*J12);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
v(qx,qy,e) = W(qx,qy) * coeff * (by_val ? detJ : 1.0/detJ);
}
@@ -97,7 +102,7 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(geom->detJ.Read(), Q1D,Q1D,Q1D,NE);
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);
@@ -109,7 +114,18 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double detJ = J(qx,qy,qz,e);
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);
v(qx,qy,qz,e) = W(qx,qy,qz) * coeff * (by_val ? detJ : 1.0/detJ);
}
+4 -4
View File
@@ -75,7 +75,7 @@ void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector ea_data_ext_tmp(ea_data_ext.Size());
bfi->AssembleEAInteriorFaces(fes, ea_data_int_tmp, ea_data_ext_tmp, false);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_int = Reshape(ea_data_int_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
@@ -102,7 +102,7 @@ void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
{
bfi->AssembleEAInteriorFaces(fes, ea_data_int, ea_data_ext, false);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
auto A_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
MFEM_FORALL(f, nf,
@@ -146,7 +146,7 @@ void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector ea_data_bdr_tmp(ea_data_bdr.Size());
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr_tmp, false);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
MFEM_FORALL(f, nf,
@@ -165,7 +165,7 @@ void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
{
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr, false);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
MFEM_FORALL(f, nf,
{
+1 -3
View File
@@ -69,11 +69,9 @@ void Operator::Mult(const mfem::Vector &x, mfem::Vector &y) const
#endif
}
void Operator::AddMult(const mfem::Vector &x, mfem::Vector &y,
const double a) const
void Operator::AddMult(const mfem::Vector &x, mfem::Vector &y) const
{
#ifdef MFEM_USE_CEED
MFEM_VERIFY(a == 1.0, "General coefficient case is not yet supported!");
const CeedScalar *x_ptr;
CeedScalar *y_ptr;
CeedMemType mem;
+1 -2
View File
@@ -38,8 +38,7 @@ public:
Operator(CeedOperator op);
#endif
void Mult(const mfem::Vector &x, mfem::Vector &y) const override;
void AddMult(const mfem::Vector &x, mfem::Vector &y,
const double a = 1.0) const override;
void AddMult(const mfem::Vector &x, mfem::Vector &y) const;
void GetDiagonal(mfem::Vector &diag) const;
using mfem::Operator::SetupRAP;
virtual ~Operator()
+3
View File
@@ -1319,6 +1319,7 @@ public:
virtual void Eval(DenseSymmetricMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip) = 0;
using MatrixCoefficient::Eval;
/** @brief Evaluate the matrix coefficient in the element described by @a T
at the point @a ip, storing the result as a dense matrix @a K. */
/** This function allows the use of SymmetricMatrixCoefficient in situations
@@ -1347,6 +1348,7 @@ public:
///Construct using matrix @a m for the constant.
SymmetricMatrixConstantCoefficient(const DenseSymmetricMatrix &m)
: SymmetricMatrixCoefficient(m.Height()), mat(m) { }
using MatrixCoefficient::Eval;
using SymmetricMatrixCoefficient::Eval;
/// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseSymmetricMatrix &M, ElementTransformation &T,
@@ -1398,6 +1400,7 @@ public:
/// Set the time for internally stored coefficients
void SetTime(double t);
using MatrixCoefficient::Eval;
using SymmetricMatrixCoefficient::Eval;
/// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseSymmetricMatrix &K, ElementTransformation &T,
+17 -20
View File
@@ -110,8 +110,8 @@ DataCollection::DataCollection(const std::string& collection_name, Mesh *mesh_)
precision = precision_default;
pad_digits_cycle = pad_digits_rank = pad_digits_default;
format = SERIAL_FORMAT; // use serial mesh format
compression = 0;
error = No_Error;
compression = false;
error = NO_ERROR;
}
void DataCollection::SetMesh(Mesh *new_mesh)
@@ -494,7 +494,7 @@ void VisItDataCollection::Load(int cycle_)
{
DeleteAll();
time_step = 0.0;
error = No_Error;
error = NO_ERROR;
cycle = cycle_;
std::string root_name = prefix_path + name + "_" +
to_padded_string(cycle, pad_digits_cycle) +
@@ -767,13 +767,10 @@ ParaViewDataCollection::ParaViewDataCollection(const std::string&
high_order_output(false),
restart_mode(false)
{
cycle = 0; // always include a valid cycle index in file names
compression_level = -1; // default zlib compression level, equivalent to 6
#ifdef MFEM_USE_ZLIB
compression = true; // if we have zlib, enable compression
compression = -1; // default zlib compression level, equivalent to 6
#else
compression = false; // otherwise, disable compression
compression = 0;
#endif
}
@@ -922,7 +919,7 @@ void ParaViewDataCollection::Save()
{
const std::string &field_name = qfield.first;
std::ofstream os(vtu_prefix + GenerateVTUFileName(field_name, myid));
qfield.second->SaveVTU(os, pv_data_format, GetCompressionLevel());
qfield.second->SaveVTU(os, pv_data_format, compression);
}
// MPI rank 0 also creates a "PVTU" file that points to all of the separately
@@ -1036,13 +1033,13 @@ void ParaViewDataCollection::WritePVTUFooter(std::ostream &os,
void ParaViewDataCollection::SaveDataVTU(std::ostream &os, int ref)
{
os << "<VTKFile type=\"UnstructuredGrid\"";
if (GetCompressionLevel() != 0)
if (compression != 0)
{
os << " compressor=\"vtkZLibDataCompressor\"";
}
os << " version=\"0.1\" byte_order=\"" << VTKByteOrder() << "\">\n";
os << "<UnstructuredGrid>\n";
mesh->PrintVTU(os,ref,pv_data_format,high_order_output,GetCompressionLevel());
mesh->PrintVTU(os,ref,pv_data_format,high_order_output,compression);
// dump out the grid functions as point data
os << "<PointData >\n";
@@ -1106,7 +1103,7 @@ void ParaViewDataCollection::SaveGFieldVTU(std::ostream &os, int ref_,
if (IsBinaryFormat())
{
WriteVTKEncodedCompressed(os,buf.data(),buf.size(),GetCompressionLevel());
WriteVTKEncodedCompressed(os,buf.data(),buf.size(),compression);
os << '\n';
}
os << "</DataArray>" << std::endl;
@@ -1131,13 +1128,18 @@ void ParaViewDataCollection::SetCompressionLevel(int compression_level_)
{
MFEM_ASSERT(compression_level_ >= -1 && compression_level_ <= 9,
"Compression level must be between -1 and 9 (inclusive).");
compression_level = compression_level_;
compression = compression_level_ != 0;
compression = compression_level_;
}
void ParaViewDataCollection::SetCompression(bool compression_)
{
compression = compression_;
// If we are enabling compression, and it was disabled previously, use the
// default compression level. Otherwise, leave the compression level
// unchanged.
if (compression_ && compression == 0)
{
SetCompressionLevel(-1);
}
}
void ParaViewDataCollection::UseRestartMode(bool restart_mode_)
@@ -1169,9 +1171,4 @@ const char *ParaViewDataCollection::GetDataTypeString() const
}
}
int ParaViewDataCollection::GetCompressionLevel() const
{
return compression ? compression_level : 0;
}
} // end namespace MFEM
+9 -36
View File
@@ -378,24 +378,12 @@ public:
virtual ~DataCollection();
/// Errors returned by Error()
enum
{
// Workaround for use with headers that define NO_ERROR as a macro,
// e.g. winerror.h (which is included by Windows.h):
#ifndef NO_ERROR
NO_ERROR = 0,
#endif
// Use the following identifier if NO_ERROR is defined as a macro,
// e.g. winerror.h (which is included by Windows.h):
No_Error = 0,
READ_ERROR = 1,
WRITE_ERROR = 2
};
enum { NO_ERROR = 0, READ_ERROR = 1, WRITE_ERROR = 2 };
/// Get the current error state
int Error() const { return error; }
/// Reset the error state
void ResetError(int err_state = No_Error) { error = err_state; }
void ResetError(int err_state = NO_ERROR) { error = err_state; }
#ifdef MFEM_USE_MPI
friend class ParMesh;
@@ -507,7 +495,6 @@ class ParaViewDataCollection : public DataCollection
{
private:
int levels_of_detail;
int compression_level;
std::fstream pvd_stream;
VTKFormat pv_data_format;
bool high_order_output;
@@ -520,9 +507,6 @@ protected:
void SaveGFieldVTU(std::ostream& out, int ref_, const FieldMapIterator& it);
const char *GetDataFormatString() const;
const char *GetDataTypeString() const;
/// @brief If compression is enabled, return the compression level, otherwise
/// return 0.
int GetCompressionLevel() const;
std::string GenerateCollectionPath();
std::string GenerateVTUFileName(const std::string &prefix, int rank);
@@ -541,7 +525,7 @@ public:
mfem::Mesh *mesh_ = NULL);
/// Set refinement levels - every element is uniformly split based on
/// levels_of_detail_. The initial value is 1.
/// levels_of_detail_
void SetLevelsOfDetail(int levels_of_detail_);
/// Save the collection - the directory name is constructed based on the
@@ -552,27 +536,18 @@ public:
/// VTKFormat::ASCII, VTKFormat::BINARY, and VTKFormat::BINARY32.
/// The ASCII and BINARY options output double precision data, whereas the
/// BINARY32 option outputs single precision data.
///
/// The initial format is VTKFormat::BINARY.
void SetDataFormat(VTKFormat fmt);
/// @brief Set the zlib compression level.
///
/// 0 indicates no compression, -1 indicates the default compression level.
/// Otherwise, specify a number between 1 and 9, 1 being the fastest, and 9
/// being the best compression. Compression only takes effect if the output
/// format is BINARY or BINARY32. MFEM must be compiled with MFEM_USE_ZLIB =
/// YES.
///
/// The initial compression level is 0 if MFEM is compiled with MFEM_USE_ZLIB
/// turned off, and -1 otherwise.
///
/// Any nonzero compression level will enable compression.
/// Set the zlib compression level. 0 indicates no compression, -1 indicates
/// the default compression level. Otherwise, specify a number between 1 and
/// 9, 1 being the fastest, and 9 being the best compression. Compression
/// only takes effect if the output format is BINARY or BINARY32. MFEM must
/// be compiled with MFEM_USE_ZLIB = YES.
void SetCompressionLevel(int compression_level_);
/// Enable or disable zlib compression. If the input is true, use the default
/// zlib compression level (unless the compression level has previously been
/// set by calling SetCompressionLevel()).
/// set by calling SetCompressionLevel).
void SetCompression(bool compression_) override;
/// Returns true if the output format is BINARY or BINARY32, false if ASCII.
@@ -585,8 +560,6 @@ public:
/// Enable or disable restart mode. If restart is enabled, new writes will
/// preserve timestep metadata for any solutions prior to the currently
/// defined time.
///
/// Initially, restart mode is disabled.
void UseRestartMode(bool restart_mode_);
/// Load the collection - not implemented in the ParaView writer
+60
View File
@@ -0,0 +1,60 @@
// Copyright (c) 2010-2022, 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.
// Finite Element Base classes
#include "face_map_utils.hpp"
namespace mfem
{
std::pair<int,int> GetFaceNormal3D(const int face_id)
{
switch (face_id)
{
case 0: return std::make_pair(2, 0); // z = 0
case 1: return std::make_pair(1, 0); // y = 0
case 2: return std::make_pair(0, 1); // x = 1
case 3: return std::make_pair(1, 1); // y = 1
case 4: return std::make_pair(0, 0); // x = 0
case 5: return std::make_pair(2, 1); // z = 1
default: MFEM_ABORT("Invalid face ID.")
}
return std::make_pair(-1, -1); // invalid
}
void FillFaceMap(const int n_face_dofs_per_component,
const std::vector<int> offsets,
const std::vector<int> &strides,
const std::vector<int> &n_dofs_per_dim,
Array<int> &face_map)
{
const int n_components = offsets.size();
const int face_dim = strides.size() / n_components;
for (int comp = 0; comp < n_components; ++comp)
{
const int offset = offsets[comp];
for (int i = 0; i < n_face_dofs_per_component; ++i)
{
int idx = offset;
int j = i;
for (int d = 0; d < face_dim; ++d)
{
const int dof1d = n_dofs_per_dim[comp*(face_dim) + d];
idx += strides[comp*(face_dim) + d]*(j % dof1d);
j /= dof1d;
}
face_map[comp*n_face_dofs_per_component + i] = idx;
}
}
}
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright (c) 2010-2022, 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_FACE_MAP_UTILS_HPP
#define MFEM_FACE_MAP_UTILS_HPP
#include "../../general/array.hpp"
#include <utility> // std::pair
#include <vector>
namespace mfem
{
/// Each face of a hexahedron is given by a level set x_i = l, where x_i is one
/// of x, y, or z (corresponding to i = 0, i=1, i = 3), and l is either 0 or 1.
/// Returns i and level.
std::pair<int,int> GetFaceNormal3D(const int face_id);
/// @brief Fills in the entries of the lexicographic face_map.
///
/// For use in FiniteElement::GetFaceMap.
///
/// n_face_dofs_per_component is the number of DOFs for each vector component
/// on the face (there is only one vector component in all cases except for 3D
/// Nedelec elements, where the face DOFs have two components to span the
/// tangent space).
///
/// The DOFs for the i-th vector component begin at offsets[i] (i.e. the number
/// of vector components is given by offsets.size()).
///
/// The DOFs for each vector component are arranged in a Cartesian grid defined
/// by strides and n_dofs_per_dim.
void FillFaceMap(const int n_face_dofs_per_component,
const std::vector<int> offsets,
const std::vector<int> &strides,
const std::vector<int> &n_dofs_per_dim,
Array<int> &face_map);
} // namespace mfem
#endif
+274 -219
View File
@@ -12,6 +12,7 @@
// Finite Element Base classes
#include "fe_base.hpp"
#include "face_map_utils.hpp"
#include "../coefficient.hpp"
namespace mfem
@@ -36,19 +37,19 @@ FiniteElement::FiniteElement(int D, Geometry::Type G,
#endif
}
void FiniteElement::CalcVShape(
void FiniteElement::CalcVShape (
const IntegrationPoint &ip, DenseMatrix &shape) const
{
MFEM_ABORT("method is not implemented for this class");
}
void FiniteElement::CalcVShape(
void FiniteElement::CalcVShape (
ElementTransformation &Trans, DenseMatrix &shape) const
{
MFEM_ABORT("method is not implemented for this class");
}
void FiniteElement::CalcDivShape(
void FiniteElement::CalcDivShape (
const IntegrationPoint &ip, Vector &divshape) const
{
MFEM_ABORT("method is not implemented for this class");
@@ -97,14 +98,14 @@ void FiniteElement::GetFaceDofs(int face, int **dofs, int *ndofs) const
MFEM_ABORT("method is not overloaded");
}
void FiniteElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &h) const
void FiniteElement::CalcHessian (const IntegrationPoint &ip,
DenseMatrix &h) const
{
MFEM_ABORT("method is not overloaded");
}
void FiniteElement::GetLocalInterpolation(ElementTransformation &Trans,
DenseMatrix &I) const
void FiniteElement::GetLocalInterpolation (ElementTransformation &Trans,
DenseMatrix &I) const
{
MFEM_ABORT("method is not overloaded");
}
@@ -122,13 +123,13 @@ void FiniteElement::GetTransferMatrix(const FiniteElement &fe,
MFEM_ABORT("method is not overloaded");
}
void FiniteElement::Project(
void FiniteElement::Project (
Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
{
MFEM_ABORT("method is not overloaded");
}
void FiniteElement::Project(
void FiniteElement::Project (
VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
{
MFEM_ABORT("method is not overloaded");
@@ -137,7 +138,7 @@ void FiniteElement::Project(
void FiniteElement::ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
Vector &dofs) const
{
mfem_error("FiniteElement::ProjectFromNodes() (vector) is not overloaded!");
mfem_error ("FiniteElement::ProjectFromNodes() (vector) is not overloaded!");
}
void FiniteElement::ProjectMatrixCoefficient(
@@ -239,6 +240,7 @@ void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans,
}
}
// Assume a linear mapping
void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
Vector &Laplacian) const
@@ -249,7 +251,7 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
DenseMatrix Gij(dim,dim);
Vector scale(size);
CalcHessian(Trans.GetIntPoint(), hess);
CalcHessian (Trans.GetIntPoint(), hess);
MultAAt(Trans.InverseJacobian(), Gij);
if (dim == 3)
@@ -282,6 +284,7 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
Laplacian[nd] += hess(nd,ii)*scale[ii];
}
}
}
void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
@@ -361,128 +364,17 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
Mult( hess, lhm, Hessian);
}
const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode) const
const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &,
DofToQuad::Mode) const
{
MFEM_VERIFY(mode == DofToQuad::FULL, "invalid mode requested");
MFEM_ABORT("method is not implemented for this element");
return *dof2quad_array[0]; // suppress a warning
}
for (int i = 0; i < dof2quad_array.Size(); i++)
{
const DofToQuad &d2q = *dof2quad_array[i];
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
}
#ifdef MFEM_THREAD_SAFE
DenseMatrix vshape(dof, dim);
#endif
DofToQuad *d2q = new DofToQuad;
const int nqpt = ir.GetNPoints();
d2q->FE = this;
d2q->IntRule = &ir;
d2q->mode = mode;
d2q->ndof = dof;
d2q->nqpt = nqpt;
if (range_type == SCALAR)
{
d2q->B.SetSize(nqpt*dof);
d2q->Bt.SetSize(dof*nqpt);
Vector shape;
vshape.GetColumnReference(0, shape);
for (int i = 0; i < nqpt; i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
CalcShape(ip, shape);
for (int j = 0; j < dof; j++)
{
d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = shape(j);
}
}
}
else
{
d2q->B.SetSize(nqpt*dim*dof);
d2q->Bt.SetSize(dof*nqpt*dim);
for (int i = 0; i < nqpt; i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
CalcVShape(ip, vshape);
for (int d = 0; d < dim; d++)
{
for (int j = 0; j < dof; j++)
{
d2q->B[i+nqpt*(d+dim*j)] = d2q->Bt[j+dof*(i+nqpt*d)] = vshape(j, d);
}
}
}
}
switch (deriv_type)
{
case GRAD:
{
d2q->G.SetSize(nqpt*dim*dof);
d2q->Gt.SetSize(dof*nqpt*dim);
for (int i = 0; i < nqpt; i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
CalcDShape(ip, vshape);
for (int d = 0; d < dim; d++)
{
for (int j = 0; j < dof; j++)
{
d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j, d);
}
}
}
break;
}
case DIV:
{
d2q->G.SetSize(nqpt*dof);
d2q->Gt.SetSize(dof*nqpt);
Vector divshape;
vshape.GetColumnReference(0, divshape);
for (int i = 0; i < nqpt; i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
CalcDivShape(ip, divshape);
for (int j = 0; j < dof; j++)
{
d2q->G[i+nqpt*j] = d2q->Gt[j+dof*i] = divshape(j);
}
}
break;
}
case CURL:
{
d2q->G.SetSize(nqpt*cdim*dof);
d2q->Gt.SetSize(dof*nqpt*cdim);
DenseMatrix curlshape(vshape.GetData(), dof, cdim); // cdim <= dim
for (int i = 0; i < nqpt; i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
CalcCurlShape(ip, curlshape);
for (int d = 0; d < cdim; d++)
{
for (int j = 0; j < dof; j++)
{
d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = curlshape(j, d);
}
}
}
break;
}
case NONE:
default:
MFEM_ABORT("invalid finite element derivative type");
}
dof2quad_array.Append(d2q);
return *d2q;
void FiniteElement::GetFaceMap(const int face_id,
Array<int> &face_map) const
{
MFEM_ABORT("method is not implemented for this element");
}
FiniteElement::~FiniteElement()
@@ -494,19 +386,16 @@ FiniteElement::~FiniteElement()
}
void ScalarFiniteElement::NodalLocalInterpolation(
void ScalarFiniteElement::NodalLocalInterpolation (
ElementTransformation &Trans, DenseMatrix &I,
const ScalarFiniteElement &fine_fe) const
{
double v[Geometry::MaxDim];
Vector vv(v, dim);
Vector vv (v, dim);
IntegrationPoint f_ip;
#ifdef MFEM_THREAD_SAFE
Vector shape(dof);
#else
Vector shape;
vshape.GetColumnReference(0, shape);
Vector c_shape(dof);
#endif
MFEM_ASSERT(map_type == fine_fe.GetMapType(), "");
@@ -516,10 +405,10 @@ void ScalarFiniteElement::NodalLocalInterpolation(
{
Trans.Transform(fine_fe.Nodes.IntPoint(i), vv);
f_ip.Set(v, dim);
CalcShape(f_ip, shape);
CalcShape(f_ip, c_shape);
for (int j = 0; j < dof; j++)
{
if (fabs(I(i,j) = shape(j)) < 1.0e-12)
if (fabs(I(i,j) = c_shape(j)) < 1.0e-12)
{
I(i,j) = 0.0;
}
@@ -540,7 +429,7 @@ void ScalarFiniteElement::ScalarLocalInterpolation(
// General "interpolation", defined by L2 projection
double v[Geometry::MaxDim];
Vector vv(v, dim);
Vector vv (v, dim);
IntegrationPoint f_ip;
const int fs = fine_fe.GetDof(), cs = this->GetDof();
@@ -574,13 +463,14 @@ void ScalarFiniteElement::ScalarLocalInterpolation(
}
}
void ScalarFiniteElement::ScalarLocalL2Restriction(
void ScalarFiniteElement::ScalarLocalRestriction(
ElementTransformation &Trans, DenseMatrix &R,
const ScalarFiniteElement &coarse_fe) const
{
// General "restriction", defined by L2 projection
double v[Geometry::MaxDim];
Vector vv(v, dim);
Vector vv (v, dim);
IntegrationPoint f_ip;
const int cs = coarse_fe.GetDof(), fs = this->GetDof();
R.SetSize(cs, fs);
@@ -589,27 +479,16 @@ void ScalarFiniteElement::ScalarLocalL2Restriction(
const int ir_order = GetOrder() + coarse_fe.GetOrder();
const IntegrationRule &ir = IntRules.Get(coarse_fe.GetGeomType(), ir_order);
// integrate coarse_mass in the coarse space
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &c_ip = ir.IntPoint(i);
coarse_fe.CalcShape(c_ip, coarse_shape);
AddMult_a_VVt(c_ip.weight, coarse_shape, coarse_mass);
}
const IntegrationPoint &ip = ir.IntPoint(i);
this->CalcShape(ip, fine_shape);
Trans.Transform(ip, vv);
f_ip.Set(v, dim);
coarse_fe.CalcShape(f_ip, coarse_shape);
// integrate coarse_fine_mass in the fine space
Trans.SetIntPoint(&Geometries.GetCenter(geom_type));
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &f_ip = ir.IntPoint(i);
this->CalcShape(f_ip, fine_shape);
Trans.Transform(f_ip, vv);
IntegrationPoint c_ip;
c_ip.Set(v, dim);
coarse_fe.CalcShape(c_ip, coarse_shape);
AddMult_a_VWt(f_ip.weight*Trans.Weight(), coarse_shape, fine_shape,
coarse_fine_mass);
AddMult_a_VVt(ip.weight, coarse_shape, coarse_mass);
AddMult_a_VWt(ip.weight, coarse_shape, fine_shape, coarse_fine_mass);
}
DenseMatrixInverse coarse_mass_inv(coarse_mass);
@@ -622,6 +501,95 @@ void ScalarFiniteElement::ScalarLocalL2Restriction(
R *= 1.0 / Trans.Weight();
}
}
const DofToQuad &ScalarFiniteElement::GetDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode) const
{
MFEM_VERIFY(mode == DofToQuad::FULL, "invalid mode requested");
for (int i = 0; i < dof2quad_array.Size(); i++)
{
const DofToQuad &d2q = *dof2quad_array[i];
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
}
DofToQuad *d2q = new DofToQuad;
const int nqpt = ir.GetNPoints();
d2q->FE = this;
d2q->IntRule = &ir;
d2q->mode = mode;
d2q->ndof = dof;
d2q->nqpt = nqpt;
d2q->B.SetSize(nqpt*dof);
d2q->Bt.SetSize(dof*nqpt);
d2q->G.SetSize(nqpt*dim*dof);
d2q->Gt.SetSize(dof*nqpt*dim);
#ifdef MFEM_THREAD_SAFE
Vector c_shape(dof);
DenseMatrix vshape(dof, dim);
#endif
for (int i = 0; i < nqpt; i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
CalcShape(ip, c_shape);
for (int j = 0; j < dof; j++)
{
d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = c_shape(j);
}
CalcDShape(ip, vshape);
for (int d = 0; d < dim; d++)
{
for (int j = 0; j < dof; j++)
{
d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j,d);
}
}
}
dof2quad_array.Append(d2q);
return *d2q;
}
// protected method
const DofToQuad &ScalarFiniteElement::GetTensorDofToQuad(
const TensorBasisElement &tb,
const IntegrationRule &ir, DofToQuad::Mode mode) const
{
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
for (int i = 0; i < dof2quad_array.Size(); i++)
{
const DofToQuad &d2q = *dof2quad_array[i];
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
}
DofToQuad *d2q = new DofToQuad;
const Poly_1D::Basis &basis_1d = tb.GetBasis1D();
const int ndof = order + 1;
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5);
d2q->FE = this;
d2q->IntRule = &ir;
d2q->mode = mode;
d2q->ndof = ndof;
d2q->nqpt = nqpt;
d2q->B.SetSize(nqpt*ndof);
d2q->Bt.SetSize(ndof*nqpt);
d2q->G.SetSize(nqpt*ndof);
d2q->Gt.SetSize(ndof*nqpt);
Vector val(ndof), grad(ndof);
for (int i = 0; i < nqpt; i++)
{
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
// of the 1D rule.
basis_1d.Eval(ir.IntPoint(i).x, val, grad);
for (int j = 0; j < ndof; j++)
{
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
}
}
dof2quad_array.Append(d2q);
return *d2q;
}
void NodalFiniteElement::ProjectCurl_2D(
const FiniteElement &fe, ElementTransformation &Trans,
@@ -670,10 +638,7 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans,
Vector pt(&ipt.x, dim);
#ifdef MFEM_THREAD_SAFE
Vector shape(dof);
#else
Vector shape;
vshape.GetColumnReference(0, shape);
Vector c_shape(dof);
#endif
Trans.SetIntPoint(&Nodes[0]);
@@ -683,8 +648,8 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans,
InvertLinearTrans(Trans, Nodes[j], pt);
if (Geometries.CheckPoint(geom_type, ipt)) // do we need an epsilon here?
{
CalcShape(ipt, shape);
R.SetRow(j, shape);
CalcShape(ipt, c_shape);
R.SetRow(j, c_shape);
}
else
{
@@ -695,7 +660,7 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans,
R.Threshold(1e-12);
}
void NodalFiniteElement::Project(
void NodalFiniteElement::Project (
Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
{
for (int i = 0; i < dof; i++)
@@ -704,7 +669,7 @@ void NodalFiniteElement::Project(
// some coefficients expect that Trans.IntPoint is the same
// as the second argument of Eval
Trans.SetIntPoint(&ip);
dofs(i) = coeff.Eval(Trans, ip);
dofs(i) = coeff.Eval (Trans, ip);
if (map_type == INTEGRAL)
{
dofs(i) *= Trans.Weight();
@@ -712,7 +677,7 @@ void NodalFiniteElement::Project(
}
}
void NodalFiniteElement::Project(
void NodalFiniteElement::Project (
VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
{
MFEM_ASSERT(dofs.Size() == vc.GetVDim()*dof, "");
@@ -891,18 +856,18 @@ VectorFiniteElement::VectorFiniteElement(int D, Geometry::Type G,
}
}
void VectorFiniteElement::CalcShape(
void VectorFiniteElement::CalcShape (
const IntegrationPoint &ip, Vector &shape ) const
{
mfem_error("Error: Cannot use scalar CalcShape(...) function with\n"
" VectorFiniteElements!");
mfem_error ("Error: Cannot use scalar CalcShape(...) function with\n"
" VectorFiniteElements!");
}
void VectorFiniteElement::CalcDShape(
void VectorFiniteElement::CalcDShape (
const IntegrationPoint &ip, DenseMatrix &dshape ) const
{
mfem_error("Error: Cannot use scalar CalcDShape(...) function with\n"
" VectorFiniteElements!");
mfem_error ("Error: Cannot use scalar CalcDShape(...) function with\n"
" VectorFiniteElements!");
}
void VectorFiniteElement::SetDerivMembers()
@@ -942,7 +907,7 @@ void VectorFiniteElement::SetDerivMembers()
}
}
void VectorFiniteElement::CalcVShape_RT(
void VectorFiniteElement::CalcVShape_RT (
ElementTransformation &Trans, DenseMatrix &shape) const
{
MFEM_ASSERT(map_type == H_DIV, "");
@@ -954,7 +919,7 @@ void VectorFiniteElement::CalcVShape_RT(
shape *= (1.0 / Trans.Weight());
}
void VectorFiniteElement::CalcVShape_ND(
void VectorFiniteElement::CalcVShape_ND (
ElementTransformation &Trans, DenseMatrix &shape) const
{
MFEM_ASSERT(map_type == H_CURL, "");
@@ -2444,46 +2409,6 @@ TensorBasisElement::TensorBasisElement(const int dims, const int p,
}
}
const DofToQuad &TensorBasisElement::GetTensorDofToQuad(
const FiniteElement &fe, const IntegrationRule &ir,
DofToQuad::Mode mode, const Poly_1D::Basis &basis, bool closed,
Array<DofToQuad*> &dof2quad_array)
{
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
for (int i = 0; i < dof2quad_array.Size(); i++)
{
const DofToQuad &d2q = *dof2quad_array[i];
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
}
DofToQuad *d2q = new DofToQuad;
const int ndof = closed ? fe.GetOrder() + 1 : fe.GetOrder();
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/fe.GetDim()) + 0.5);
d2q->FE = &fe;
d2q->IntRule = &ir;
d2q->mode = mode;
d2q->ndof = ndof;
d2q->nqpt = nqpt;
d2q->B.SetSize(nqpt*ndof);
d2q->Bt.SetSize(ndof*nqpt);
d2q->G.SetSize(nqpt*ndof);
d2q->Gt.SetSize(ndof*nqpt);
Vector val(ndof), grad(ndof);
for (int i = 0; i < nqpt; i++)
{
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
// of the 1D rule.
basis.Eval(ir.IntPoint(i).x, val, grad);
for (int j = 0; j < ndof; j++)
{
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
}
}
dof2quad_array.Append(d2q);
return *d2q;
}
NodalTensorFiniteElement::NodalTensorFiniteElement(const int dims,
const int p,
@@ -2509,6 +2434,55 @@ void NodalTensorFiniteElement::SetMapType(const int map_type)
}
}
void NodalTensorFiniteElement::GetFaceMap(const int face_id,
Array<int> &face_map) const
{
const int dof1d = order + 1;
int n_face_dofs = pow(dof1d, dim - 1);
std::vector<int> offsets, strides;
switch (dim)
{
case 1:
offsets = {(face_id == 0) ? 0 : dof1d - 1};
break;
case 2:
strides = {(face_id == 0 || face_id == 2) ? 1 : dof1d};
switch (face_id)
{
case 0: offsets = {0}; break; // y = 0
case 1: offsets = {dof1d - 1}; break; // x = 1
case 2: offsets = {(dof1d-1)*dof1d}; break; // y = 1
case 3: offsets = {0}; break; // x = 0
}
break;
case 3:
{
const auto f = GetFaceNormal3D(face_id);
const int face_normal = f.first, level = f.second;
if (face_normal == 0) // x-normal
{
offsets = {level ? dof1d-1 : 0};
strides = {dof1d, dof1d*dof1d};
}
else if (face_normal == 1) // y-normal
{
offsets = {level ? (dof1d-1)*dof1d : 0};
strides = {1, dof1d*dof1d};
}
else if (face_normal == 2) // z-normal
{
offsets = {level ? (dof1d-1)*dof1d*dof1d : 0};
strides = {1, dof1d};
}
break;
}
}
// same number of DOFs in each dimension, repeat dof1d (dim - 1) times
std::vector<int> n_dofs(dim - 1, dof1d);
FillFaceMap(n_face_dofs, offsets, strides, n_dofs, face_map);
}
VectorTensorFiniteElement::VectorTensorFiniteElement(const int dims,
const int d,
const int p,
@@ -2518,7 +2492,8 @@ VectorTensorFiniteElement::VectorTensorFiniteElement(const int dims,
const DofMapType dmtype)
: VectorFiniteElement(dims, GetTensorProductGeometry(dims), d,
p, M, FunctionSpace::Qk),
TensorBasisElement(dims, p, VerifyNodal(VerifyClosed(cbtype)), dmtype),
TensorBasisElement(dims, p, VerifyNodal(cbtype), dmtype),
cbasis1d(poly1d.GetBasis(p, VerifyClosed(cbtype))),
obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(obtype)))
{
MFEM_VERIFY(dims > 1, "Constructor for VectorTensorFiniteElement with both "
@@ -2533,13 +2508,93 @@ VectorTensorFiniteElement::VectorTensorFiniteElement(const int dims,
const DofMapType dmtype)
: VectorFiniteElement(dims, GetTensorProductGeometry(dims), d,
p, M, FunctionSpace::Pk),
TensorBasisElement(dims, p, VerifyOpen(obtype), dmtype),
TensorBasisElement(dims, p, obtype, dmtype),
cbasis1d(poly1d.GetBasis(p, VerifyOpen(obtype))),
obasis1d(poly1d.GetBasis(p, VerifyOpen(obtype)))
{
MFEM_VERIFY(dims == 1, "Constructor for VectorTensorFiniteElement without "
"closed basis is only valid for 1D elements.");
}
const DofToQuad &VectorTensorFiniteElement::GetDofToQuad(
const IntegrationRule &ir,
DofToQuad::Mode mode) const
{
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
return GetTensorDofToQuad(ir, mode, true);
}
const DofToQuad &VectorTensorFiniteElement::GetDofToQuadOpen(
const IntegrationRule &ir,
DofToQuad::Mode mode) const
{
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
return GetTensorDofToQuad(ir, mode, false);
}
const DofToQuad &VectorTensorFiniteElement::GetTensorDofToQuad(
const IntegrationRule &ir,
DofToQuad::Mode mode,
const bool closed) const
{
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
for (int i = 0;
i < (closed ? dof2quad_array.Size() : dof2quad_array_open.Size());
i++)
{
const DofToQuad &d2q = closed ? *dof2quad_array[i] : *dof2quad_array_open[i];
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
}
DofToQuad *d2q = new DofToQuad;
const int ndof = closed ? order + 1 : order;
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5);
d2q->FE = this;
d2q->IntRule = &ir;
d2q->mode = mode;
d2q->ndof = ndof;
d2q->nqpt = nqpt;
d2q->B.SetSize(nqpt*ndof);
d2q->Bt.SetSize(ndof*nqpt);
d2q->G.SetSize(nqpt*ndof);
d2q->Gt.SetSize(ndof*nqpt);
Vector val(ndof), grad(ndof);
for (int i = 0; i < nqpt; i++)
{
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
// of the 1D rule.
if (closed)
{
cbasis1d.Eval(ir.IntPoint(i).x, val, grad);
}
else
{
obasis1d.Eval(ir.IntPoint(i).x, val, grad);
}
for (int j = 0; j < ndof; j++)
{
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
}
}
if (closed)
{
dof2quad_array.Append(d2q);
}
else
{
dof2quad_array_open.Append(d2q);
}
return *d2q;
}
VectorTensorFiniteElement::~VectorTensorFiniteElement()
{
for (int i = 0; i < dof2quad_array_open.Size(); i++)
+86 -67
View File
@@ -127,6 +127,7 @@ public:
}
};
/** @brief Structure representing the matrices/tensors needed to evaluate (in
reference space) the values, gradients, divergences, or curls of a
FiniteElement at a the quadrature points of a given IntegrationRule. */
@@ -156,7 +157,8 @@ public:
dimensions using 1D number of quadrature points and degrees of
freedom. */
/** When representing a vector-valued FiniteElement, two DofToQuad objects
are used to describe the "closed" and "open" 1D basis functions. */
are used to describe the "closed" and "open" 1D basis functions
(TODO). */
TENSOR
};
@@ -174,7 +176,7 @@ public:
/// Basis functions evaluated at quadrature points.
/** The storage layout is column-major with dimensions:
- #nqpt x #ndof, for scalar elements, or
- #nqpt x dim x #ndof, for vector elements,
- #nqpt x dim x #ndof, for vector elements, (TODO)
where
@@ -185,15 +187,15 @@ public:
/// Transpose of #B.
/** The storage layout is column-major with dimensions:
- #ndof x #nqpt, for scalar elements, or
- #ndof x #nqpt x dim, for vector elements. */
- #ndof x #nqpt x dim, for vector elements (TODO). */
Array<double> Bt;
/** @brief Gradients/divergences/curls of basis functions evaluated at
quadrature points. */
/** The storage layout is column-major with dimensions:
- #nqpt x dim x #ndof, for scalar elements, or
- #nqpt x #ndof, for H(div) vector elements, or
- #nqpt x cdim x #ndof, for H(curl) vector elements,
- #nqpt x #ndof, for H(div) vector elements (TODO), or
- #nqpt x cdim x #ndof, for H(curl) vector elements (TODO),
where
@@ -206,11 +208,12 @@ public:
/// Transpose of #G.
/** The storage layout is column-major with dimensions:
- #ndof x #nqpt x dim, for scalar elements, or
- #ndof x #nqpt, for H(div) vector elements, or
- #ndof x #nqpt x cdim, for H(curl) vector elements. */
- #ndof x #nqpt, for H(div) vector elements (TODO), or
- #ndof x #nqpt x cdim, for H(curl) vector elements (TODO). */
Array<double> Gt;
};
/// Describes the function space on each element
class FunctionSpace
{
@@ -244,7 +247,7 @@ protected:
mutable int orders[Geometry::MaxDim]; ///< Anisotropic orders
IntegrationRule Nodes;
#ifndef MFEM_THREAD_SAFE
mutable DenseMatrix vshape; // Dof x Dim
mutable DenseMatrix vshape; // Dof x VDim
#endif
/// Container for all DofToQuad objects created by the FiniteElement.
/** Multiple DofToQuad objects may be needed when different quadrature rules
@@ -347,6 +350,7 @@ public:
H_DIV, H_CURL}. */
int GetMapType() const { return map_type; }
/** @brief Returns the FiniteElement::DerivType of the element describing the
spatial derivative method implemented, one of {NONE, GRAD,
DIV, CURL}. */
@@ -453,8 +457,8 @@ public:
part of the Hessian of one shape function.
The order in 2D is {u_xx, u_xy, u_yy}.
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
virtual void CalcHessian (const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
@@ -576,6 +580,9 @@ public:
virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode) const;
virtual void GetFaceMap(const int face_id,
Array<int> &face_map) const;
/// Deconstruct the FiniteElement
virtual ~FiniteElement();
@@ -622,11 +629,16 @@ public:
}
};
/** @brief Class for finite elements with basis functions
that return scalar values. */
class ScalarFiniteElement : public FiniteElement
{
protected:
#ifndef MFEM_THREAD_SAFE
mutable Vector c_shape;
#endif
static const ScalarFiniteElement &CheckScalarFE(const FiniteElement &fe)
{
MFEM_VERIFY(fe.GetRangeType() == SCALAR,
@@ -634,6 +646,10 @@ protected:
return static_cast<const ScalarFiniteElement &>(fe);
}
const DofToQuad &GetTensorDofToQuad(const class TensorBasisElement &tb,
const IntegrationRule &ir,
DofToQuad::Mode mode) const;
public:
/** @brief Construct ScalarFiniteElement with given
@param D Reference space dimension
@@ -644,8 +660,13 @@ public:
*/
ScalarFiniteElement(int D, Geometry::Type G, int Do, int O,
int F = FunctionSpace::Pk)
#ifdef MFEM_THREAD_SAFE
: FiniteElement(D, G, Do, O, F)
{ deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; }
#else
: FiniteElement(D, G, Do, O, F), c_shape(dof)
{ deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; }
#endif
/** @brief Set the FiniteElement::MapType of the element to either VALUE or
INTEGRAL. Also sets the FiniteElement::DerivType to GRAD if the
@@ -657,6 +678,7 @@ public:
deriv_type = (M == VALUE) ? GRAD : NONE;
}
/** @brief Get the matrix @a I that defines nodal interpolation
@a between this element and the refined element @a fine_fe. */
void NodalLocalInterpolation(ElementTransformation &Trans,
@@ -677,11 +699,15 @@ public:
/** If the "fine" elements cannot represent all basis functions of the
"coarse" element, then boundary values from different sub-elements are
generally different. */
void ScalarLocalL2Restriction(ElementTransformation &Trans,
DenseMatrix &R,
const ScalarFiniteElement &coarse_fe) const;
void ScalarLocalRestriction(ElementTransformation &Trans,
DenseMatrix &R,
const ScalarFiniteElement &coarse_fe) const;
virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode) const;
};
/// Class for standard nodal finite elements.
class NodalFiniteElement : public ScalarFiniteElement
{
@@ -703,38 +729,38 @@ public:
int F = FunctionSpace::Pk)
: ScalarFiniteElement(D, G, Do, O, F) { }
void GetLocalInterpolation(ElementTransformation &Trans,
DenseMatrix &I) const override
virtual void GetLocalInterpolation(ElementTransformation &Trans,
DenseMatrix &I) const
{ NodalLocalInterpolation(Trans, I, *this); }
void GetLocalRestriction(ElementTransformation &Trans,
DenseMatrix &R) const override;
virtual void GetLocalRestriction(ElementTransformation &Trans,
DenseMatrix &R) const;
void GetTransferMatrix(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &I) const override
virtual void GetTransferMatrix(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &I) const
{ CheckScalarFE(fe).NodalLocalInterpolation(Trans, I, *this); }
void Project(Coefficient &coeff,
ElementTransformation &Trans, Vector &dofs) const override;
virtual void Project (Coefficient &coeff,
ElementTransformation &Trans, Vector &dofs) const;
void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const override;
virtual void Project (VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const;
// (mc.height x mc.width) @ DOFs -> (Dof x mc.width x mc.height) in dofs
void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const override;
virtual void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
void Project(const FiniteElement &fe, ElementTransformation &Trans,
DenseMatrix &I) const override;
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
DenseMatrix &I) const;
void ProjectGrad(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &grad) const override;
virtual void ProjectGrad(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &grad) const;
void ProjectDiv(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &div) const override;
virtual void ProjectDiv(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &div) const;
/** @brief Get an Array<int> that maps lexicographically ordered indices to
the indices of the respective nodes/dofs/basis functions.
@@ -768,12 +794,12 @@ class VectorFiniteElement : public FiniteElement
// Hide the scalar functions CalcShape and CalcDShape.
private:
/// Overrides the scalar CalcShape function to print an error.
void CalcShape(const IntegrationPoint &ip,
Vector &shape) const override;
virtual void CalcShape(const IntegrationPoint &ip,
Vector &shape) const;
/// Overrides the scalar CalcDShape function to print an error.
void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const override;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
protected:
bool is_nodal;
@@ -932,10 +958,11 @@ protected:
}
public:
VectorFiniteElement(int D, Geometry::Type G, int Do, int O, int M,
int F = FunctionSpace::Pk);
VectorFiniteElement (int D, Geometry::Type G, int Do, int O, int M,
int F = FunctionSpace::Pk);
};
/// @brief Class for computing 1D special polynomials and their associated basis
/// functions
class Poly_1D
@@ -1156,6 +1183,7 @@ public:
extern Poly_1D poly1d;
/// An element defined as an ND tensor product of 1D elements on a segment,
/// square, or cube
class TensorBasisElement
@@ -1179,7 +1207,7 @@ public:
int GetBasisType() const { return b_type; }
const Poly_1D::Basis &GetBasis1D() const { return basis1d; }
const Poly_1D::Basis& GetBasis1D() const { return basis1d; }
/** @brief Get an Array<int> that maps lexicographically ordered indices to
the indices of the respective nodes/dofs/basis functions. If the dofs are
@@ -1211,11 +1239,6 @@ public:
default: MFEM_ABORT("invalid dimension: " << dim); return -1;
}
}
static const DofToQuad &GetTensorDofToQuad(
const FiniteElement &fe, const IntegrationRule &ir,
DofToQuad::Mode mode, const Poly_1D::Basis &basis, bool closed,
Array<DofToQuad*> &dof2quad_array);
};
class NodalTensorFiniteElement : public NodalFiniteElement,
@@ -1226,18 +1249,18 @@ public:
const DofMapType dmtype);
const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode) const override
DofToQuad::Mode mode) const
{
return (mode == DofToQuad::FULL) ?
FiniteElement::GetDofToQuad(ir, mode) :
GetTensorDofToQuad(*this, ir, mode, basis1d, true, dof2quad_array);
ScalarFiniteElement::GetDofToQuad(ir, mode) :
ScalarFiniteElement::GetTensorDofToQuad(*this, ir, mode);
}
void SetMapType(const int map_type_) override;
virtual void SetMapType(const int map_type_);
void GetTransferMatrix(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &I) const override
virtual void GetTransferMatrix(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &I) const
{
if (basis1d.IsIntegratedType())
{
@@ -1248,6 +1271,8 @@ public:
NodalFiniteElement::GetTransferMatrix(fe, Trans, I);
}
}
virtual void GetFaceMap(const int face_id, Array<int> &face_map) const;
};
class VectorTensorFiniteElement : public VectorFiniteElement,
@@ -1257,7 +1282,7 @@ private:
mutable Array<DofToQuad*> dof2quad_array_open;
protected:
Poly_1D::Basis &obasis1d;
Poly_1D::Basis &cbasis1d, &obasis1d;
public:
VectorTensorFiniteElement(const int dims, const int d, const int p,
@@ -1270,22 +1295,16 @@ public:
const DofMapType dmtype);
const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode) const override
{
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
return GetTensorDofToQuad(*this, ir, mode, basis1d, true,
dof2quad_array);
}
DofToQuad::Mode mode) const;
const DofToQuad &GetDofToQuadOpen(const IntegrationRule &ir,
DofToQuad::Mode mode) const
{
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
return GetTensorDofToQuad(*this, ir, mode, obasis1d, false,
dof2quad_array_open);
}
DofToQuad::Mode mode) const;
virtual ~VectorTensorFiniteElement();
const DofToQuad &GetTensorDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode,
const bool closed) const;
~VectorTensorFiniteElement();
};
void InvertLinearTrans(ElementTransformation &trans,
-25
View File
@@ -32,11 +32,6 @@ public:
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const;
virtual void GetLocalRestriction(ElementTransformation &Trans,
DenseMatrix &R) const
{ ScalarLocalL2Restriction(Trans, R, *this); }
};
@@ -60,11 +55,6 @@ public:
ElementTransformation &Trans,
DenseMatrix &curl) const
{ ProjectCurl_2D(fe, Trans, curl); }
virtual void GetLocalRestriction(ElementTransformation &Trans,
DenseMatrix &R) const
{ ScalarLocalL2Restriction(Trans, R, *this); }
using FiniteElement::Project;
virtual void ProjectDiv(const FiniteElement &fe,
ElementTransformation &Trans,
@@ -90,11 +80,6 @@ public:
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const;
virtual void GetLocalRestriction(ElementTransformation &Trans,
DenseMatrix &R) const
{ ScalarLocalL2Restriction(Trans, R, *this); }
using FiniteElement::Project;
virtual void ProjectDiv(const FiniteElement &fe,
ElementTransformation &Trans,
@@ -126,11 +111,6 @@ public:
ElementTransformation &Trans,
DenseMatrix &curl) const
{ ProjectCurl_2D(fe, Trans, curl); }
virtual void GetLocalRestriction(ElementTransformation &Trans,
DenseMatrix &R) const
{ ScalarLocalL2Restriction(Trans, R, *this); }
};
@@ -153,11 +133,6 @@ public:
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const;
virtual void GetLocalRestriction(ElementTransformation &Trans,
DenseMatrix &R) const
{ ScalarLocalL2Restriction(Trans, R, *this); }
};
+79 -15
View File
@@ -12,6 +12,7 @@
// Nedelec Finite Element classes
#include "fe_nd.hpp"
#include "face_map_utils.hpp"
#include "../coefficient.hpp"
namespace mfem
@@ -321,9 +322,9 @@ void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
#ifdef MFEM_THREAD_SAFE
Vector dshape_cx(p + 1), dshape_cy(p + 1), dshape_cz(p + 1);
#endif
basis1d.Eval(ip.x, shape_cx, dshape_cx);
basis1d.Eval(ip.y, shape_cy, dshape_cy);
basis1d.Eval(ip.z, shape_cz, dshape_cz);
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
@@ -331,9 +332,9 @@ void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
}
else
{
basis1d.Eval(ip.x, shape_cx);
basis1d.Eval(ip.y, shape_cy);
basis1d.Eval(ip.z, shape_cz);
cbasis1d.Eval(ip.x, shape_cx);
cbasis1d.Eval(ip.y, shape_cy);
cbasis1d.Eval(ip.z, shape_cz);
obasis1d.Eval(ip.x, shape_ox);
obasis1d.Eval(ip.y, shape_oy);
obasis1d.Eval(ip.z, shape_oz);
@@ -407,9 +408,9 @@ void ND_HexahedronElement::CalcCurlShape(const IntegrationPoint &ip,
Vector dshape_cx(p + 1), dshape_cy(p + 1), dshape_cz(p + 1);
#endif
basis1d.Eval(ip.x, shape_cx, dshape_cx);
basis1d.Eval(ip.y, shape_cy, dshape_cy);
basis1d.Eval(ip.z, shape_cz, dshape_cz);
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
if (obasis1d.IsIntegratedType())
{
obasis1d.ScaleIntegrated(false);
@@ -481,6 +482,50 @@ void ND_HexahedronElement::CalcCurlShape(const IntegrationPoint &ip,
}
}
void ND_HexahedronElement::GetFaceMap(const int face_id,
Array<int> &face_map) const
{
const int p = order;
const int pp1 = p + 1;
const int n_face_dofs_per_component = p*pp1;
const int n_dof_per_dim = p*pp1*pp1;
std::vector<int> n_dofs = {p, pp1, pp1, p};
std::vector<int> offsets, strides;
const auto f = GetFaceNormal3D(face_id);
const int face_normal = f.first, level = f.second;
if (face_normal == 0) // x-normal
{
offsets =
{
n_dof_per_dim + (level ? pp1 - 1 : 0),
2*n_dof_per_dim + (level ? pp1 - 1 : 0)
};
strides = {pp1, p*pp1, pp1, pp1*pp1};
}
else if (face_normal == 1) // y-normal
{
offsets =
{
level ? p*(pp1 - 1) : 0,
2*n_dof_per_dim + (level ? pp1*(pp1 - 1) : 0)
};
strides = {1, p*pp1, 1, pp1*pp1};
}
else if (face_normal == 2) // z-normal
{
offsets =
{
level ? p*pp1*(pp1 - 1) : 0,
n_dof_per_dim + (level ? p*pp1*(pp1 - 1) : 0)
};
strides = {1, p, 1, pp1};
}
FillFaceMap(n_face_dofs_per_component, offsets, strides, n_dofs, face_map);
}
const double ND_QuadrilateralElement::tk[8] =
{ 1.,0., 0.,1., -1.,0., 0.,-1. };
@@ -665,16 +710,16 @@ void ND_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip,
#ifdef MFEM_THREAD_SAFE
Vector dshape_cx(p + 1), dshape_cy(p + 1);
#endif
basis1d.Eval(ip.x, shape_cx, dshape_cx);
basis1d.Eval(ip.y, shape_cy, dshape_cy);
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
}
else
{
basis1d.Eval(ip.x, shape_cx);
basis1d.Eval(ip.y, shape_cy);
cbasis1d.Eval(ip.x, shape_cx);
cbasis1d.Eval(ip.y, shape_cy);
obasis1d.Eval(ip.x, shape_ox);
obasis1d.Eval(ip.y, shape_oy);
}
@@ -724,8 +769,8 @@ void ND_QuadrilateralElement::CalcCurlShape(const IntegrationPoint &ip,
Vector dshape_cx(p + 1), dshape_cy(p + 1);
#endif
basis1d.Eval(ip.x, shape_cx, dshape_cx);
basis1d.Eval(ip.y, shape_cy, dshape_cy);
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
if (obasis1d.IsIntegratedType())
{
obasis1d.ScaleIntegrated(false);
@@ -771,6 +816,25 @@ void ND_QuadrilateralElement::CalcCurlShape(const IntegrationPoint &ip,
}
}
void ND_QuadrilateralElement::GetFaceMap(const int face_id,
Array<int> &face_map) const
{
const int p = order;
const int pp1 = order + 1;
const int n_face_dofs_per_component = p;
std::vector<int> strides = {(face_id == 0 || face_id == 2) ? 1 : pp1};
std::vector<int> n_dofs = {p};
std::vector<int> offsets;
switch (face_id)
{
case 0: offsets = {0}; break; // y = 0
case 1: offsets = {p*pp1 + pp1 - 1}; break; // x = 1
case 2: offsets = {p*(pp1 - 1)}; break; // y = 1
case 3: offsets = {p*pp1}; break; // x = 0
}
FillFaceMap(n_face_dofs_per_component, offsets, strides, n_dofs, face_map);
}
const double ND_TetrahedronElement::tk[18] =
{ 1.,0.,0., 0.,1.,0., 0.,0.,1., -1.,1.,0., -1.,0.,1., 0.,-1.,1. };
+4
View File
@@ -91,6 +91,8 @@ public:
DenseMatrix &curl) const
{ ProjectCurl_ND(tk, dof2tk, fe, Trans, curl); }
virtual void GetFaceMap(const int face_id, Array<int> &face_map) const;
protected:
void ProjectIntegrated(VectorCoefficient &vc,
ElementTransformation &Trans,
@@ -155,6 +157,8 @@ public:
DenseMatrix &grad) const
{ ProjectGrad_ND(tk, dof2tk, fe, Trans, grad); }
virtual void GetFaceMap(const int face_id, Array<int> &face_map) const;
protected:
void ProjectIntegrated(VectorCoefficient &vc,
ElementTransformation &Trans,
-1
View File
@@ -13,7 +13,6 @@
#include "fe_pos.hpp"
#include "../bilininteg.hpp"
#include "../lininteg.hpp"
#include "../coefficient.hpp"
namespace mfem
+3 -3
View File
@@ -40,7 +40,7 @@ public:
virtual void GetLocalRestriction(ElementTransformation &Trans,
DenseMatrix &R) const
{ ScalarLocalL2Restriction(Trans, R, *this); }
{ ScalarLocalRestriction(Trans, R, *this); }
virtual void GetTransferMatrix(const FiniteElement &fe,
ElementTransformation &Trans,
@@ -73,8 +73,8 @@ public:
DofToQuad::Mode mode) const
{
return (mode == DofToQuad::FULL) ?
FiniteElement::GetDofToQuad(ir, mode) :
GetTensorDofToQuad(*this, ir, mode, basis1d, true, dof2quad_array);
ScalarFiniteElement::GetDofToQuad(ir, mode) :
ScalarFiniteElement::GetTensorDofToQuad(*this, ir, mode);
}
};
+66 -15
View File
@@ -12,6 +12,7 @@
// Raviart-Thomas Finite Element classes
#include "fe_rt.hpp"
#include "face_map_utils.hpp"
#include "../coefficient.hpp"
namespace mfem
@@ -152,16 +153,16 @@ void RT_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip,
#ifdef MFEM_THREAD_SAFE
Vector dshape_cx(pp1 + 1), dshape_cy(pp1 + 1);
#endif
basis1d.Eval(ip.x, shape_cx, dshape_cx);
basis1d.Eval(ip.y, shape_cy, dshape_cy);
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
}
else
{
basis1d.Eval(ip.x, shape_cx);
basis1d.Eval(ip.y, shape_cy);
cbasis1d.Eval(ip.x, shape_cx);
cbasis1d.Eval(ip.y, shape_cy);
obasis1d.Eval(ip.x, shape_ox);
obasis1d.Eval(ip.y, shape_oy);
}
@@ -209,8 +210,8 @@ void RT_QuadrilateralElement::CalcDivShape(const IntegrationPoint &ip,
Vector dshape_cx(pp1 + 1), dshape_cy(pp1 + 1);
#endif
basis1d.Eval(ip.x, shape_cx, dshape_cx);
basis1d.Eval(ip.y, shape_cy, dshape_cy);
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
if (obasis1d.IsIntegratedType())
{
obasis1d.ScaleIntegrated(false);
@@ -297,6 +298,27 @@ void RT_QuadrilateralElement::ProjectIntegrated(VectorCoefficient &vc,
}
}
void RT_QuadrilateralElement::GetFaceMap(const int face_id,
Array<int> &face_map) const
{
const int p = order;
const int pp1 = p + 1;
const int n_face_dofs = p;
std::vector<int> offsets;
std::vector<int> strides = {(face_id == 0 || face_id == 2) ? 1 : pp1};
switch (face_id)
{
case 0: offsets = {p*pp1}; break; // y = 0
case 1: offsets = {pp1 - 1}; break; // x = 1
case 2: offsets = {p*pp1 + p*(pp1 - 1)}; break; // y = 1
case 3: offsets = {0}; break; // x = 0
}
std::vector<int> n_dofs(dim - 1, p);
FillFaceMap(n_face_dofs, offsets, strides, n_dofs, face_map);
}
const double RT_HexahedronElement::nk[18] =
{ 0.,0.,-1., 0.,-1.,0., 1.,0.,0., 0.,1.,0., -1.,0.,0., 0.,0.,1. };
@@ -482,9 +504,9 @@ void RT_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
#ifdef MFEM_THREAD_SAFE
Vector dshape_cx(pp1 + 1), dshape_cy(pp1 + 1), dshape_cz(pp1 + 1);
#endif
basis1d.Eval(ip.x, shape_cx, dshape_cx);
basis1d.Eval(ip.y, shape_cy, dshape_cy);
basis1d.Eval(ip.z, shape_cz, dshape_cz);
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
@@ -492,9 +514,9 @@ void RT_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
}
else
{
basis1d.Eval(ip.x, shape_cx);
basis1d.Eval(ip.y, shape_cy);
basis1d.Eval(ip.z, shape_cz);
cbasis1d.Eval(ip.x, shape_cx);
cbasis1d.Eval(ip.y, shape_cy);
cbasis1d.Eval(ip.z, shape_cz);
obasis1d.Eval(ip.x, shape_ox);
obasis1d.Eval(ip.y, shape_oy);
obasis1d.Eval(ip.z, shape_oz);
@@ -568,9 +590,9 @@ void RT_HexahedronElement::CalcDivShape(const IntegrationPoint &ip,
Vector dshape_cx(pp1 + 1), dshape_cy(pp1 + 1), dshape_cz(pp1 + 1);
#endif
basis1d.Eval(ip.x, shape_cx, dshape_cx);
basis1d.Eval(ip.y, shape_cy, dshape_cy);
basis1d.Eval(ip.z, shape_cz, dshape_cz);
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
if (obasis1d.IsIntegratedType())
{
obasis1d.ScaleIntegrated(false);
@@ -686,6 +708,35 @@ void RT_HexahedronElement::ProjectIntegrated(VectorCoefficient &vc,
}
}
void RT_HexahedronElement::GetFaceMap(const int face_id,
Array<int> &face_map) const
{
const int p = order;
const int pp1 = p + 1;
int n_face_dofs = p*p;
std::vector<int> strides, offsets;
const int n_dof_per_dim = p*p*pp1;
const auto f = GetFaceNormal3D(face_id);
const int face_normal = f.first, level = f.second;
if (face_normal == 0) // x-normal
{
offsets = {level ? pp1 - 1 : 0};
strides = {pp1, p*pp1};
}
else if (face_normal == 1) // y-normal
{
offsets = {n_dof_per_dim + (level ? p*(pp1 - 1) : 0)};
strides = {1, p*pp1};
}
else if (face_normal == 2) // z-normal
{
offsets = {2*n_dof_per_dim + (level ? p*p*(pp1 - 1) : 0)};
strides = {1, p};
}
std::vector<int> n_dofs = {p, p};
FillFaceMap(n_face_dofs, offsets, strides, n_dofs, face_map);
}
const double RT_TriangleElement::nk[6] =
{ 0., -1., 1., 1., -1., 0. };
+6
View File
@@ -82,6 +82,8 @@ public:
DenseMatrix &curl) const
{ ProjectGrad_RT(nk, dof2nk, fe, Trans, curl); }
virtual void GetFaceMap(const int face_id, Array<int> &face_map) const;
protected:
void ProjectIntegrated(VectorCoefficient &vc, ElementTransformation &Trans,
Vector &dofs) const;
@@ -145,6 +147,10 @@ public:
DenseMatrix &curl) const
{ ProjectCurl_RT(nk, dof2nk, fe, Trans, curl); }
/// @brief Return the mapping from lexicographically ordered DOFs to face
/// DOFs corresponding to local face @a face_id.
virtual void GetFaceMap(const int face_id, Array<int> &face_map) const;
protected:
void ProjectIntegrated(VectorCoefficient &vc,
ElementTransformation &Trans,
+6 -36
View File
@@ -25,16 +25,15 @@ using namespace std;
const FiniteElement *
FiniteElementCollection::FiniteElementForDim(int dim) const
{
ErrorMode save_error_mode = error_mode;
error_mode = RETURN_NULL;
const FiniteElement *fe = nullptr;
for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
{
fe = FiniteElementForGeometry((Geometry::Type)g);
if (fe != nullptr) { break; }
const FiniteElement *fe = FiniteElementForGeometry((Geometry::Type)g);
if (fe != NULL)
{
return fe;
}
}
error_mode = save_error_mode;
return fe;
return NULL;
}
int FiniteElementCollection::GetRangeType(int dim) const
@@ -644,7 +643,6 @@ LinearFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::PRISM: return &WedgeFE;
case Geometry::PYRAMID: return &PyramidFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("LinearFECollection: unknown geometry type.");
}
return &SegmentFE; // Make some compilers happy
@@ -688,7 +686,6 @@ QuadraticFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::CUBE: return &ParallelepipedFE;
case Geometry::PRISM: return &WedgeFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("QuadraticFECollection: unknown geometry type.");
}
return &SegmentFE; // Make some compilers happy
@@ -729,7 +726,6 @@ QuadraticPosFECollection::FiniteElementForGeometry(
case Geometry::SEGMENT: return &SegmentFE;
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("QuadraticPosFECollection: unknown geometry type.");
}
return NULL; // Make some compilers happy
@@ -770,7 +766,6 @@ CubicFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::CUBE: return &ParallelepipedFE;
case Geometry::PRISM: return &WedgeFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("CubicFECollection: unknown geometry type.");
}
return &SegmentFE; // Make some compilers happy
@@ -837,7 +832,6 @@ CrouzeixRaviartFECollection::FiniteElementForGeometry(
case Geometry::TRIANGLE: return &TriangleFE;
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("CrouzeixRaviartFECollection: unknown geometry type.");
}
return &SegmentFE; // Make some compilers happy
@@ -875,7 +869,6 @@ RT0_2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::TRIANGLE: return &TriangleFE;
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("RT0_2DFECollection: unknown geometry type.");
}
return &SegmentFE; // Make some compilers happy
@@ -918,7 +911,6 @@ RT1_2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::TRIANGLE: return &TriangleFE;
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("RT1_2DFECollection: unknown geometry type.");
}
return &SegmentFE; // Make some compilers happy
@@ -960,7 +952,6 @@ RT2_2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::TRIANGLE: return &TriangleFE;
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("RT2_2DFECollection: unknown geometry type.");
}
return &SegmentFE; // Make some compilers happy
@@ -1002,7 +993,6 @@ Const2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::TRIANGLE: return &TriangleFE;
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("Const2DFECollection: unknown geometry type.");
}
return &TriangleFE; // Make some compilers happy
@@ -1038,7 +1028,6 @@ LinearDiscont2DFECollection::FiniteElementForGeometry(
case Geometry::TRIANGLE: return &TriangleFE;
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("LinearDiscont2DFECollection: unknown geometry type.");
}
return &TriangleFE; // Make some compilers happy
@@ -1074,7 +1063,6 @@ GaussLinearDiscont2DFECollection::FiniteElementForGeometry(
case Geometry::TRIANGLE: return &TriangleFE;
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("GaussLinearDiscont2DFECollection:"
" unknown geometry type.");
}
@@ -1109,7 +1097,6 @@ P1OnQuadFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
if (GeomType != Geometry::SQUARE)
{
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("P1OnQuadFECollection: unknown geometry type.");
}
return &QuadrilateralFE;
@@ -1144,7 +1131,6 @@ QuadraticDiscont2DFECollection::FiniteElementForGeometry(
case Geometry::TRIANGLE: return &TriangleFE;
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("QuadraticDiscont2DFECollection: unknown geometry type.");
}
return &TriangleFE; // Make some compilers happy
@@ -1180,7 +1166,6 @@ QuadraticPosDiscont2DFECollection::FiniteElementForGeometry(
{
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("QuadraticPosDiscont2DFECollection: unknown geometry type.");
}
return NULL; // Make some compilers happy
@@ -1211,7 +1196,6 @@ const
case Geometry::TRIANGLE: return &TriangleFE;
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("GaussQuadraticDiscont2DFECollection:"
" unknown geometry type.");
}
@@ -1250,7 +1234,6 @@ CubicDiscont2DFECollection::FiniteElementForGeometry(
case Geometry::TRIANGLE: return &TriangleFE;
case Geometry::SQUARE: return &QuadrilateralFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("CubicDiscont2DFECollection: unknown geometry type.");
}
return &TriangleFE; // Make some compilers happy
@@ -1288,7 +1271,6 @@ LinearNonConf3DFECollection::FiniteElementForGeometry(
case Geometry::TETRAHEDRON: return &TetrahedronFE;
case Geometry::CUBE: return &ParallelepipedFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("LinearNonConf3DFECollection: unknown geometry type.");
}
return &TriangleFE; // Make some compilers happy
@@ -1329,7 +1311,6 @@ Const3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::PRISM: return &WedgeFE;
case Geometry::PYRAMID: return &PyramidFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("Const3DFECollection: unknown geometry type.");
}
return &TetrahedronFE; // Make some compilers happy
@@ -1371,7 +1352,6 @@ LinearDiscont3DFECollection::FiniteElementForGeometry(
case Geometry::PRISM: return &WedgeFE;
case Geometry::CUBE: return &ParallelepipedFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("LinearDiscont3DFECollection: unknown geometry type.");
}
return &TetrahedronFE; // Make some compilers happy
@@ -1411,7 +1391,6 @@ QuadraticDiscont3DFECollection::FiniteElementForGeometry(
case Geometry::TETRAHEDRON: return &TetrahedronFE;
case Geometry::CUBE: return &ParallelepipedFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("QuadraticDiscont3DFECollection: unknown geometry type.");
}
return &TetrahedronFE; // Make some compilers happy
@@ -1453,7 +1432,6 @@ RefinedLinearFECollection::FiniteElementForGeometry(
case Geometry::TETRAHEDRON: return &TetrahedronFE;
case Geometry::CUBE: return &ParallelepipedFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("RefinedLinearFECollection: unknown geometry type.");
}
return &SegmentFE; // Make some compilers happy
@@ -1494,7 +1472,6 @@ ND1_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::PRISM: return &WedgeFE;
case Geometry::PYRAMID: return &PyramidFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("ND1_3DFECollection: unknown geometry type.");
}
return &HexahedronFE; // Make some compilers happy
@@ -1544,7 +1521,6 @@ RT0_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::PRISM: return &WedgeFE;
case Geometry::PYRAMID: return &PyramidFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("RT0_3DFECollection: unknown geometry type.");
}
return &HexahedronFE; // Make some compilers happy
@@ -1594,7 +1570,6 @@ RT1_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::SQUARE: return &QuadrilateralFE;
case Geometry::CUBE: return &HexahedronFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("RT1_3DFECollection: unknown geometry type.");
}
return &HexahedronFE; // Make some compilers happy
@@ -1956,7 +1931,6 @@ H1_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
}
else
{
if (error_mode == RETURN_NULL) { return nullptr; }
MFEM_ABORT("H1 Pyramid basis functions are not yet supported "
"for order > 1.");
return NULL;
@@ -2337,7 +2311,6 @@ L2_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
}
else
{
if (error_mode == RETURN_NULL) { return nullptr; }
MFEM_ABORT("L2 Pyramid basis functions are not yet supported "
"for order > 0.");
return NULL;
@@ -2593,7 +2566,6 @@ RT_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
}
else
{
if (error_mode == RETURN_NULL) { return nullptr; }
MFEM_ABORT("RT Pyramid basis functions are not yet supported "
"for order > 0.");
return NULL;
@@ -2879,7 +2851,6 @@ ND_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
}
else
{
if (error_mode == RETURN_NULL) { return nullptr; }
MFEM_ABORT("ND Pyramid basis functions are not yet supported "
"for order > 1.");
return NULL;
@@ -3482,7 +3453,6 @@ NURBSFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::SQUARE: return QuadrilateralFE;
case Geometry::CUBE: return ParallelepipedFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("NURBSFECollection: unknown geometry type.");
}
return SegmentFE; // Make some compilers happy
-13
View File
@@ -233,19 +233,6 @@ protected:
void InitVarOrder(int p) const;
mutable Array<FiniteElementCollection*> var_orders;
/// How to treat errors in FiniteElementForGeometry() calls.
enum ErrorMode
{
RETURN_NULL, ///< Return NULL on errors
RAISE_MFEM_ERROR /**< Raise an MFEM error (default in base class).
Sub-classes can ignore this and return NULL. */
};
/// How to treat errors in FiniteElementForGeometry() calls.
/** The typical error in derived classes is that no FiniteElement is defined
for the given Geometry, or the input is not a valid Geometry. */
mutable ErrorMode error_mode = RAISE_MFEM_ERROR;
};
/// Arbitrary order H1-conforming (continuous) finite elements.
+11 -13
View File
@@ -1317,7 +1317,7 @@ const FaceRestriction *FiniteElementSpace::GetFaceRestriction(
}
else
{
res = new H1FaceRestriction(*this, e_ordering, type);
res = new H1_ND_RT_FaceRestriction(*this, e_ordering, type);
}
L2F[key] = res;
return res;
@@ -1958,7 +1958,7 @@ FiniteElementSpace::DerefinementOperator::DerefinementOperator(
DenseMatrix &lM = localM[g](mi[s]);
DenseMatrix &lR = localR[g](lR_offset+s);
MultAtB(lP, lM, lR); // lR = lP^T lM
mfem::AddMult(lR, lP, lPtMP); // lPtMP += lP^T lM lP
AddMult(lR, lP, lPtMP); // lPtMP += lP^T lM lP
}
DenseMatrixInverse lPtMP_inv(lPtMP);
for (int s = 0; s < nm; s++)
@@ -2005,7 +2005,7 @@ void FiniteElementSpace::DerefinementOperator
x.GetSubVector(f_vdofs, loc_x);
loc_x_mat.UseExternalData(loc_x.GetData(), f_vdofs.Size()/fine_vdim,
fine_vdim);
mfem::AddMult(lR, loc_x_mat, loc_y_mat);
AddMult(lR, loc_x_mat, loc_y_mat);
}
y.SetSubVector(c_vdofs, loc_y);
}
@@ -2056,7 +2056,10 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
}
SparseMatrix *R = new SparseMatrix(ndofs*vdim, old_ndofs*vdim);
SparseMatrix *R = (elem_geoms.Size() != 1)
? new SparseMatrix(ndofs*vdim, old_ndofs*vdim) // variable row size
: new SparseMatrix(ndofs*vdim, old_ndofs*vdim,
localR[elem_geoms[0]].SizeI());
Array<int> mark(R->Height());
mark = 0;
@@ -2066,7 +2069,6 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
MFEM_ASSERT(dtrans.embeddings.Size() == old_elem_dof->Size(), "");
bool is_dg = FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS;
int num_marked = 0;
for (int k = 0; k < dtrans.embeddings.Size(); k++)
{
@@ -2089,11 +2091,10 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
int r = DofToVDof(dofs[i], vd);
int m = (r >= 0) ? r : (-1 - r);
if (is_dg || !mark[m])
if (!mark[m])
{
lR.GetRow(i, row);
R->SetRow(r, old_vdofs, row);
mark[m] = 1;
num_marked++;
}
@@ -2101,11 +2102,8 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
}
}
if (!is_dg)
{
MFEM_VERIFY(num_marked == R->Height(),
"internal error: not all rows of R were set.");
}
MFEM_VERIFY(num_marked == R->Height(),
"internal error: not all rows of R were set.");
R->Finalize(); // no-op if fixed width
return R;
@@ -3147,7 +3145,7 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const
break;
case 3:
default:
fe = fec->FiniteElementForGeometry(mesh->GetFaceGeometry(i));
fe = fec->FiniteElementForGeometry(mesh->GetFaceBaseGeometry(i));
}
if (NURBSext)
+1 -2
View File
@@ -38,7 +38,7 @@ public:
/// Construct an empty finite element space hierarchy. This is useful if the
/// hierarchy is constructed by coarsening a fine space, rather than refining
/// a coarse space.
FiniteElementSpaceHierarchy() = default;
FiniteElementSpaceHierarchy() { }
/// @brief Constructs a space hierarchy with the given mesh and space on the
/// coarsest level.
@@ -91,7 +91,6 @@ public:
class ParFiniteElementSpaceHierarchy : public FiniteElementSpaceHierarchy
{
public:
ParFiniteElementSpaceHierarchy() = default;
/// @brief Constructs a parallel space hierarchy with the given mesh and spaces
/// on level zero.
/** The ownership of the mesh and space may be transferred to the
+17 -5
View File
@@ -1441,13 +1441,21 @@ void GridFunction::GetDerivative(int comp, int der_comp, GridFunction &der)
}
}
void GridFunction::GetVectorGradientHat(
ElementTransformation &T, DenseMatrix &gh) const
{
const FiniteElement *FElem = fes->GetFE(T.ElementNo);
int elNo = T.ElementNo;
const FiniteElement *FElem = fes->GetFE(elNo);
int dim = FElem->GetDim(), dof = FElem->GetDof();
Array<int> vdofs;
DofTransformation * doftrans = fes->GetElementVDofs(elNo, vdofs);
Vector loc_data;
GetElementDofValues(T.ElementNo, loc_data);
GetSubVector(vdofs, loc_data);
if (doftrans)
{
doftrans->InvTransformPrimal(loc_data);
}
// assuming scalar FE
int vdim = fes->GetVDim();
DenseMatrix dshape(dof, dim);
@@ -1652,7 +1660,6 @@ void GridFunction::GetGradient(ElementTransformation &T, Vector &grad) const
const FiniteElement *fe = fes->GetFE(T.ElementNo);
MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
"invalid FE map type");
MFEM_ASSERT(fes->GetVDim() == 1, "Defined for scalar functions.");
int spaceDim = fes->GetMesh()->SpaceDimension();
int dim = fe->GetDim(), dof = fe->GetDof();
DenseMatrix dshape(dof, dim);
@@ -1721,8 +1728,13 @@ void GridFunction::GetGradients(ElementTransformation &tr,
MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type");
DenseMatrix dshape(fe->GetDof(), fe->GetDim());
Vector lval, gh(fe->GetDim()), gcol;
GetElementDofValues(tr.ElementNo, lval);
Array<int> dofs;
DofTransformation * doftrans = fes->GetElementDofs(elNo, dofs);
GetSubVector(dofs, lval);
if (doftrans)
{
doftrans->InvTransformPrimal(lval);
}
grad.SetSize(fe->GetDim(), ir.GetNPoints());
for (int i = 0; i < ir.GetNPoints(); i++)
{
+2 -17
View File
@@ -48,6 +48,8 @@ protected:
void SaveSTLTri(std::ostream &out, double p1[], double p2[], double p3[]);
void GetVectorGradientHat(ElementTransformation &T, DenseMatrix &gh) const;
// Project the delta coefficient without scaling and return the (local)
// integral of the projection.
void ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff,
@@ -327,34 +329,17 @@ public:
void GetCurl(ElementTransformation &tr, Vector &curl) const;
/** @brief Gradient of a scalar function at a quadrature point.
@note It is assumed that the IntegrationPoint of interest has been
specified by ElementTransformation::SetIntPoint() before calling
GetGradient().
@note Can be used from a ParGridFunction when @a tr is an
ElementTransformation of a face-neighbor element and face-neighbor data
has been exchanged. */
void GetGradient(ElementTransformation &tr, Vector &grad) const;
/// Extension of GetGradient(...) for a collection of IntegrationPoints.
void GetGradients(ElementTransformation &tr, const IntegrationRule &ir,
DenseMatrix &grad) const;
/// Extension of GetGradient(...) for a collection of IntegrationPoints.
void GetGradients(const int elem, const IntegrationRule &ir,
DenseMatrix &grad) const
{ GetGradients(*fes->GetElementTransformation(elem), ir, grad); }
/** @brief Compute the vector gradient with respect to the physical element
variable. */
void GetVectorGradient(ElementTransformation &tr, DenseMatrix &grad) const;
/** @brief Compute the vector gradient with respect to the reference element
variable. */
void GetVectorGradientHat(ElementTransformation &T, DenseMatrix &gh) const;
/** Compute \f$ (\int_{\Omega} (*this) \psi_i)/(\int_{\Omega} \psi_i) \f$,
where \f$ \psi_i \f$ are the basis functions for the FE space of avgs.
Both FE spaces should be scalar and on the same mesh. */
+6 -10
View File
@@ -37,7 +37,7 @@ FindPointsGSLIB::FindPointsGSLIB()
fec_map_lin(NULL),
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
avgtype(AvgType::ARITHMETIC)
{
mesh_split.SetSize(4);
ir_split.SetSize(4);
@@ -84,7 +84,7 @@ FindPointsGSLIB::FindPointsGSLIB(MPI_Comm comm_)
fec_map_lin(NULL),
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
avgtype(AvgType::ARITHMETIC)
{
mesh_split.SetSize(4);
ir_split.SetSize(4);
@@ -223,12 +223,10 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos,
// Set the element number and reference position to 0 for points not found
for (int i = 0; i < points_cnt; i++)
{
if (gsl_code[i] == 2 ||
(gsl_code[i] == 1 && gsl_dist(i) > bdr_tol))
if (gsl_code[i] == 2)
{
gsl_elem[i] = 0;
for (int d = 0; d < dim; d++) { gsl_ref(i*dim + d) = -1.; }
gsl_code[i] = 2;
}
}
@@ -573,7 +571,7 @@ void FindPointsGSLIB::GetNodalValues(const GridFunction *gf_in,
const int pts_el = std::pow(dof_1D, dim);
const int pts_cnt = NE_split_total * pts_el;
node_vals.SetSize(vdim * pts_cnt);
node_vals = 0.0;
node_vals *= 0;
int gsl_mesh_pt_index = 0;
@@ -1155,7 +1153,7 @@ void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
distfint.SetSize(pts_cnt);
if (!gfmax)
{
distfint = 0.0;
distfint = 0.;
}
else
{
@@ -1250,12 +1248,10 @@ void OversetFindPointsGSLIB::FindPoints(const Vector &point_pos,
// Set the element number and reference position to 0 for points not found
for (int i = 0; i < points_cnt; i++)
{
if (gsl_code[i] == 2 ||
(gsl_code[i] == 1 && gsl_dist(i) > bdr_tol))
if (gsl_code[i] == 2)
{
gsl_elem[i] = 0;
for (int d = 0; d < dim; d++) { gsl_ref(i*dim + d) = -1.; }
gsl_code[i] = 2;
}
}
-15
View File
@@ -38,11 +38,6 @@ namespace mfem
* coordinates inside the element that each point is located in. gslib also
* returns a code that indicates whether the point was found inside an
* element, on element border, or not found in the domain.
* For points returned as found on `element border`, the point is either
* on an element edge/face or near the domain boundary, and gslib also
* returns a distance to the border. Points near (but outside) the domain
* boundary must then be marked as not found using the distance returned
* by gslib.
*
* 3. Interpolate - Interpolates any grid function at the points found using 2.
*
@@ -75,8 +70,6 @@ protected:
Array<int> split_element_map;
Array<int> split_element_index;
int NE_split_total;
// Tolerance to ignore points just outside elements at the boundary.
double bdr_tol;
/// Use GSLIB for communication and interpolation
virtual void InterpolateH1(const GridFunction &field_in, Vector &field_out);
@@ -188,14 +181,6 @@ public:
default_interp_value = interp_value_;
}
/// Set the tolerance for detecting points outside the 'curvilinear' boundary
/// that gslib may return as found on the boundary. Points found on boundary
/// with distance greater than @ bdr_tol are marked as not found.
virtual void SetDistanceToleranceForPointsFoundOnBoundary(double bdr_tol_)
{
bdr_tol = bdr_tol_;
}
/** Cleans up memory allocated internally by gslib.
Note that in parallel, this must be called before MPI_Finalize(), as it
calls MPI_Comm_free() for internal gslib communicators. */
+1 -1
View File
@@ -101,7 +101,7 @@ void LinearForm::AddInteriorFaceIntegrator(LinearFormIntegrator *lfi)
interior_face_integs.Append(lfi);
}
bool LinearForm::SupportsDevice()
bool LinearForm::SupportsDevice() const
{
// return false for NURBS meshes, so we dont convert it to non-NURBS
// through Assemble, AssembleDevice, GetGeometricFactors and EnsureNodes
+1 -1
View File
@@ -203,7 +203,7 @@ public:
void Assemble();
/// Return true if assembly on device is supported, false otherwise.
virtual bool SupportsDevice();
virtual bool SupportsDevice() const;
/// Assembles delta functions of the linear form
void AssembleDelta();
+13 -7
View File
@@ -31,7 +31,7 @@ protected:
public:
/// Method probing for assembly on device
virtual bool SupportsDevice() { return false; }
virtual bool SupportsDevice() const { return false; }
/// Method defining assembly on device
virtual void AssembleDevice(const FiniteElementSpace &fes,
@@ -121,7 +121,7 @@ public:
DomainLFIntegrator(Coefficient &QF, const IntegrationRule *ir)
: DeltaLFIntegrator(QF, ir), Q(QF), oa(1), ob(1) { }
virtual bool SupportsDevice() { return true; }
virtual bool SupportsDevice() const { return true; }
/// Method defining assembly on device
virtual void AssembleDevice(const FiniteElementSpace &fes,
@@ -154,7 +154,7 @@ public:
DomainLFGradIntegrator(VectorCoefficient &QF)
: DeltaLFIntegrator(QF), Q(QF) { }
virtual bool SupportsDevice() { return true; }
virtual bool SupportsDevice() const { return true; }
/// Method defining assembly on device
virtual void AssembleDevice(const FiniteElementSpace &fes,
@@ -187,7 +187,7 @@ public:
BoundaryLFIntegrator(Coefficient &QG, int a = 1, int b = 1)
: Q(QG), oa(a), ob(b) { }
virtual bool SupportsDevice() { return true; }
virtual bool SupportsDevice() const { return true; }
/// Method defining assembly on device
virtual void AssembleDevice(const FiniteElementSpace &fes,
@@ -217,7 +217,7 @@ public:
BoundaryNormalLFIntegrator(VectorCoefficient &QG, int a = 1, int b = 1)
: Q(QG), oa(a), ob(b) { }
virtual bool SupportsDevice() { return true; }
virtual bool SupportsDevice() const { return true; }
/// Method defining assembly on device
virtual void AssembleDevice(const FiniteElementSpace &fes,
@@ -262,7 +262,7 @@ public:
VectorDomainLFIntegrator(VectorCoefficient &QF)
: DeltaLFIntegrator(QF), Q(QF) { }
virtual bool SupportsDevice() { return true; }
virtual bool SupportsDevice() const { return true; }
/// Method defining assembly on device
virtual void AssembleDevice(const FiniteElementSpace &fes,
@@ -296,7 +296,7 @@ public:
VectorDomainLFGradIntegrator(VectorCoefficient &QF)
: DeltaLFIntegrator(QF), Q(QF) { }
virtual bool SupportsDevice() override { return true; }
virtual bool SupportsDevice() const override { return true; }
/// Method defining assembly on device
virtual void AssembleDevice(const FiniteElementSpace &fes,
@@ -456,6 +456,12 @@ public:
Vector &elvect);
using LinearFormIntegrator::AssembleRHSElementVect;
virtual bool SupportsDevice() const { return true; }
virtual void AssembleDevice(const FiniteElementSpace &fes,
const Array<int> &markers,
Vector &b);
};
/// Class for boundary integration \f$ L(v) = (n \times f, v) \f$
+180
View File
@@ -0,0 +1,180 @@
// Copyright (c) 2010-2022, 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 "fem.hpp"
#include "../fem/kernels.hpp"
#include "../general/forall.hpp"
namespace mfem
{
template<int T_D1D = 0, int T_Q1D = 0> static
void BFLFEvalAssemble2D(const int nbe, const int d, const int q,
const int *markers, const double *b,
const double *weights, const Vector &coeff, double *y)
{
const auto F = coeff.Read();
const auto M = Reshape(markers, nbe);
const auto B = Reshape(b, q, d);
const auto W = Reshape(weights, q);
const bool const_coeff = coeff.Size() == 1;
const auto C = const_coeff ? Reshape(F,1,1) : Reshape(F,q,nbe);
auto Y = Reshape(y, d, nbe);
MFEM_FORALL(e, nbe,
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
double QQ[Q];
for (int qx = 0; qx < q; ++qx)
{
const double coeff_val = const_coeff ? C(0,0) : C(qx,e);
QQ[qx] = W(qx) * coeff_val;
}
for (int dx = 0; dx < d; ++dx)
{
double u = 0;
for (int qx = 0; qx < q; ++qx) { u += QQ[qx] * B(qx,dx); }
Y(dx,e) += u;
}
});
}
template<int T_D1D = 0, int T_Q1D = 0> static
void BFLFEvalAssemble3D(const int nbe, const int d, const int q,
const int *markers, const double *b,
const double *weights, const Vector &coeff, double *y)
{
const auto F = coeff.Read();
const auto M = Reshape(markers, nbe);
const auto B = Reshape(b, q, d);
const auto W = Reshape(weights, q, q);
const bool const_coeff = coeff.Size() == 1;
const auto C = const_coeff ? Reshape(F,1,1,1) : Reshape(F,q,q,nbe);
auto Y = Reshape(y, d, d, nbe);
MFEM_FORALL_2D(e, nbe, q, q, 1,
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
MFEM_SHARED double sBt[Q*D];
MFEM_SHARED double sQQ[Q*Q];
MFEM_SHARED double sQD[Q*D];
const DeviceMatrix Bt(sBt, d, q);
kernels::internal::LoadB<D,Q>(d, q, B, sBt);
const DeviceMatrix QQ(sQQ, q, q);
const DeviceMatrix QD(sQD, q, d);
MFEM_FOREACH_THREAD(x,x,q)
{
MFEM_FOREACH_THREAD(y,y,q)
{
const double coeff_val = const_coeff ? C(0,0,0) : C(x,y,e);
QQ(y,x) = W(x,y) * coeff_val;
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy,y,q)
{
MFEM_FOREACH_THREAD(dx,x,d)
{
double u = 0.0;
for (int qx = 0; qx < q; ++qx) { u += QQ(qy,qx) * Bt(dx,qx); }
QD(qy,dx) = u;
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,d)
{
MFEM_FOREACH_THREAD(dx,x,d)
{
double u = 0.0;
for (int qy = 0; qy < q; ++qy) { u += QD(qy,dx) * Bt(dy,qy); }
Y(dx,dy,e) += u;
}
}
MFEM_SYNC_THREAD;
});
}
static void BFLFEvalAssemble(const FiniteElementSpace &fes,
const IntegrationRule &ir,
const Array<int> &markers,
const Vector &coeff,
Vector &y)
{
Mesh &mesh = *fes.GetMesh();
const int dim = mesh.Dimension();
const FiniteElement &el = *fes.GetBE(0);
const DofToQuad &maps = el.GetDofToQuad(ir, DofToQuad::TENSOR);
const int d = maps.ndof, q = maps.nqpt;
auto ker = (dim == 2) ? BFLFEvalAssemble2D<> : BFLFEvalAssemble3D<>;
if (dim==2)
{
if (d==1 && q==1) { ker=BFLFEvalAssemble2D<1,1>; }
if (d==2 && q==2) { ker=BFLFEvalAssemble2D<2,2>; }
if (d==3 && q==3) { ker=BFLFEvalAssemble2D<3,3>; }
if (d==4 && q==4) { ker=BFLFEvalAssemble2D<4,4>; }
if (d==5 && q==5) { ker=BFLFEvalAssemble2D<5,5>; }
if (d==2 && q==3) { ker=BFLFEvalAssemble2D<2,3>; }
if (d==3 && q==4) { ker=BFLFEvalAssemble2D<3,4>; }
if (d==4 && q==5) { ker=BFLFEvalAssemble2D<4,5>; }
if (d==5 && q==6) { ker=BFLFEvalAssemble2D<5,6>; }
}
if (dim==3)
{
if (d==1 && q==1) { ker=BFLFEvalAssemble3D<1,1>; }
if (d==2 && q==2) { ker=BFLFEvalAssemble3D<2,2>; }
if (d==3 && q==3) { ker=BFLFEvalAssemble3D<3,3>; }
if (d==4 && q==4) { ker=BFLFEvalAssemble3D<4,4>; }
if (d==5 && q==5) { ker=BFLFEvalAssemble3D<5,5>; }
if (d==2 && q==3) { ker=BFLFEvalAssemble3D<2,3>; }
if (d==3 && q==4) { ker=BFLFEvalAssemble3D<3,4>; }
if (d==4 && q==5) { ker=BFLFEvalAssemble3D<4,5>; }
if (d==5 && q==6) { ker=BFLFEvalAssemble3D<5,6>; }
}
MFEM_VERIFY(ker, "No kernel ndof " << d << " nqpt " << q);
const int nbe = fes.GetMesh()->GetNFbyType(FaceType::Boundary);
const int *M = markers.Read();
const double *B = maps.B.Read();
const double *W = ir.GetWeights().Read();
double *Y = y.ReadWrite();
ker(nbe, d, q, M, B, W, coeff, Y);
}
void VectorFEBoundaryFluxLFIntegrator::AssembleDevice(
const FiniteElementSpace &fes,
const Array<int> &markers,
Vector &b)
{
const FiniteElement &fe = *fes.GetBE(0);
const int qorder = oa * fe.GetOrder() + ob;
const Geometry::Type gtype = fe.GetGeomType();
const IntegrationRule &ir = IntRule ? *IntRule : IntRules.Get(gtype, qorder);
Mesh &mesh = *fes.GetMesh();
FaceQuadratureSpace qs(mesh, ir, FaceType::Boundary);
CoefficientVector coeff(F, qs, CoefficientStorage::COMPRESSED);
BFLFEvalAssemble(fes, ir, markers, coeff, b);
}
} // namespace mfem
+190 -217
View File
@@ -14,26 +14,41 @@
namespace mfem
{
MultigridBase::MultigridBase()
: cycleType(CycleType::VCYCLE), preSmoothingSteps(1), postSmoothingSteps(1),
nrhs(0)
Multigrid::Multigrid()
: cycleType(CycleType::VCYCLE), preSmoothingSteps(1), postSmoothingSteps(1)
{}
MultigridBase::MultigridBase(const Array<Operator*>& operators_,
const Array<Solver*>& smoothers_,
const Array<bool>& ownedOperators_,
const Array<bool>& ownedSmoothers_)
: Solver(operators_.Last()->Height(), operators_.Last()->Width()),
cycleType(CycleType::VCYCLE), preSmoothingSteps(1), postSmoothingSteps(1),
nrhs(0)
Multigrid::Multigrid(const Array<Operator*>& operators_,
const Array<Solver*>& smoothers_,
const Array<Operator*>& prolongations_,
const Array<bool>& ownedOperators_,
const Array<bool>& ownedSmoothers_,
const Array<bool>& ownedProlongations_)
: Solver(operators_.Last()->NumRows()), cycleType(CycleType::VCYCLE),
preSmoothingSteps(1), postSmoothingSteps(1),
X(operators_.Size()), Y(X.Size()), R(X.Size()), Z(X.Size())
{
operators_.Copy(operators);
smoothers_.Copy(smoothers);
prolongations_.Copy(prolongations);
ownedOperators_.Copy(ownedOperators);
ownedSmoothers_.Copy(ownedSmoothers);
ownedProlongations_.Copy(ownedProlongations);
for (int level = 0; level < operators.Size(); ++level)
{
X[level] = new Vector(operators[level]->NumRows());
*X[level] = 0.0;
Y[level] = new Vector(operators[level]->NumRows());
*Y[level] = 0.0;
R[level] = new Vector(operators[level]->NumRows());
*R[level] = 0.0;
Z[level] = new Vector(operators[level]->NumRows());
*Z[level] = 0.0;
}
}
MultigridBase::~MultigridBase()
Multigrid::~Multigrid()
{
for (int i = 0; i < operators.Size(); ++i)
{
@@ -45,210 +60,12 @@ MultigridBase::~MultigridBase()
{
delete smoothers[i];
}
}
EraseVectors();
}
void MultigridBase::InitVectors() const
{
if (X.NumRows() > 0 && X.NumCols() > 0) { EraseVectors(); }
const int M = NumLevels();
X.SetSize(M, nrhs);
Y.SetSize(M, nrhs);
R.SetSize(M, nrhs);
Z.SetSize(M, nrhs);
for (int i = 0; i < X.NumRows(); ++i)
{
const int n = operators[i]->Height();
for (int j = 0; j < X.NumCols(); ++j)
{
X(i, j) = new Vector(n);
Y(i, j) = new Vector(n);
R(i, j) = new Vector(n);
Z(i, j) = new Vector(n);
}
}
}
void MultigridBase::EraseVectors() const
{
for (int i = 0; i < X.NumRows(); ++i)
{
for (int j = 0; j < X.NumCols(); ++j)
{
delete X(i, j);
delete Y(i, j);
delete R(i, j);
delete Z(i, j);
}
}
}
void MultigridBase::AddLevel(Operator* op, Solver* smoother,
bool ownOperator, bool ownSmoother)
{
height = op->Height();
width = op->Width();
operators.Append(op);
smoothers.Append(smoother);
ownedOperators.Append(ownOperator);
ownedSmoothers.Append(ownSmoother);
}
void MultigridBase::SetCycleType(CycleType cycleType_, int preSmoothingSteps_,
int postSmoothingSteps_)
{
cycleType = cycleType_;
preSmoothingSteps = preSmoothingSteps_;
postSmoothingSteps = postSmoothingSteps_;
}
void MultigridBase::Mult(const Vector& x, Vector& y) const
{
Array<const Vector*> X_(1);
Array<Vector*> Y_(1);
X_[0] = &x;
Y_[0] = &y;
ArrayMult(X_, Y_);
}
void MultigridBase::ArrayMult(const Array<const Vector*>& X_,
Array<Vector*>& Y_) const
{
MFEM_ASSERT(operators.Size() > 0,
"Multigrid solver does not have operators set!");
MFEM_ASSERT(X_.Size() == Y_.Size(),
"Number of columns mismatch in MultigridBase::Mult!");
if (iterative_mode)
{
MFEM_WARNING("Multigrid solver does not use iterative_mode and ignores "
"the initial guess!");
delete X[i];
delete Y[i];
delete R[i];
delete Z[i];
}
// Add capacity as necessary
nrhs = X_.Size();
if (X.NumCols() < nrhs) { InitVectors(); }
// Perform a single cycle
const int M = NumLevels();
for (int j = 0; j < nrhs; ++j)
{
MFEM_ASSERT(X_[j] && Y_[j], "Missing Vector in MultigridBase::Mult!");
*X(M - 1, j) = *X_[j];
*Y(M - 1, j) = 0.0;
}
Cycle(M - 1);
for (int j = 0; j < nrhs; ++j)
{
*Y_[j] = *Y(M - 1, j);
}
}
void MultigridBase::SmoothingStep(int level, bool zero, bool transpose) const
{
// y = y + S (x - A y) or y = y + S^T (x - A y)
if (zero)
{
Array<Vector *> X_(X[level], nrhs), Y_(Y[level], nrhs);
GetSmootherAtLevel(level)->ArrayMult(X_, Y_);
}
else
{
Array<Vector *> Y_(Y[level], nrhs), R_(R[level], nrhs),
Z_(Z[level], nrhs);
for (int j = 0; j < nrhs; ++j)
{
*R_[j] = *X(level, j);
}
GetOperatorAtLevel(level)->ArrayAddMult(Y_, R_, -1.0);
if (transpose)
{
GetSmootherAtLevel(level)->ArrayMultTranspose(R_, Z_);
}
else
{
GetSmootherAtLevel(level)->ArrayMult(R_, Z_);
}
for (int j = 0; j < nrhs; ++j)
{
*Y_[j] += *Z_[j];
}
}
}
void MultigridBase::Cycle(int level) const
{
// Coarse solve
if (level == 0)
{
SmoothingStep(0, true, false);
return;
}
// Pre-smooth
for (int i = 0; i < preSmoothingSteps; ++i)
{
SmoothingStep(level, (cycleType == CycleType::VCYCLE && i == 0), false);
}
// Compute residual and restrict
{
Array<Vector *> Y_(Y[level], nrhs), R_(R[level], nrhs),
X_(X[level - 1], nrhs);
for (int j = 0; j < nrhs; ++j)
{
*R_[j] = *X(level, j);
}
GetOperatorAtLevel(level)->ArrayAddMult(Y_, R_, -1.0);
GetProlongationAtLevel(level - 1)->ArrayMultTranspose(R_, X_);
for (int j = 0; j < nrhs; ++j)
{
*Y(level - 1, j) = 0.0;
}
}
// Corrections
Cycle(level - 1);
if (cycleType == CycleType::WCYCLE)
{
Cycle(level - 1);
}
// Prolongate and add
{
Array<Vector *> Y_(Y[level - 1], nrhs), Z_(Z[level], nrhs);
GetProlongationAtLevel(level - 1)->ArrayMult(Y_, Z_);
for (int j = 0; j < nrhs; ++j)
{
*Y(level, j) += *Z_[j];
}
}
// Post-smooth
for (int i = 0; i < postSmoothingSteps; ++i)
{
SmoothingStep(level, false, true);
}
}
Multigrid::Multigrid()
: MultigridBase()
{}
Multigrid::Multigrid(const Array<Operator*>& operators_,
const Array<Solver*>& smoothers_,
const Array<Operator*>& prolongations_,
const Array<bool>& ownedOperators_,
const Array<bool>& ownedSmoothers_,
const Array<bool>& ownedProlongations_)
: MultigridBase(operators_, smoothers_, ownedOperators_, ownedSmoothers_)
{
prolongations_.Copy(prolongations);
ownedProlongations_.Copy(ownedProlongations);
}
Multigrid::~Multigrid()
{
for (int i = 0; i < prolongations.Size(); ++i)
{
if (ownedProlongations[i])
@@ -256,12 +73,158 @@ Multigrid::~Multigrid()
delete prolongations[i];
}
}
operators.DeleteAll();
smoothers.DeleteAll();
prolongations.DeleteAll();
X.DeleteAll();
Y.DeleteAll();
R.DeleteAll();
Z.DeleteAll();
}
GeometricMultigrid::
GeometricMultigrid(const FiniteElementSpaceHierarchy& fespaces_)
: MultigridBase(), fespaces(fespaces_)
{}
void Multigrid::AddLevel(Operator* opr, Solver* smoother, bool ownOperator,
bool ownSmoother)
{
operators.Append(opr);
smoothers.Append(smoother);
ownedOperators.Append(ownOperator);
ownedSmoothers.Append(ownSmoother);
width = opr->Width();
height = opr->Height();
X.Append(new Vector(height));
*X.Last() = 0.0;
Y.Append(new Vector(height));
*Y.Last() = 0.0;
R.Append(new Vector(height));
*R.Last() = 0.0;
Z.Append(new Vector(height));
*Z.Last() = 0.0;
}
int Multigrid::NumLevels() const { return operators.Size(); }
int Multigrid::GetFinestLevelIndex() const { return NumLevels() - 1; }
const Operator* Multigrid::GetOperatorAtLevel(int level) const
{
return operators[level];
}
Operator* Multigrid::GetOperatorAtLevel(int level)
{
return operators[level];
}
const Operator* Multigrid::GetOperatorAtFinestLevel() const
{
return GetOperatorAtLevel(operators.Size() - 1);
}
Operator* Multigrid::GetOperatorAtFinestLevel()
{
return GetOperatorAtLevel(operators.Size() - 1);
}
Solver* Multigrid::GetSmootherAtLevel(int level) const
{
return smoothers[level];
}
Solver* Multigrid::GetSmootherAtLevel(int level)
{
return smoothers[level];
}
void Multigrid::SetCycleType(CycleType cycleType_, int preSmoothingSteps_,
int postSmoothingSteps_)
{
cycleType = cycleType_;
preSmoothingSteps = preSmoothingSteps_;
postSmoothingSteps = postSmoothingSteps_;
}
void Multigrid::Mult(const Vector& x, Vector& y) const
{
MFEM_ASSERT(NumLevels() > 0, "");
*X.Last() = x;
*Y.Last() = 0.0;
Cycle(GetFinestLevelIndex());
y = *Y.Last();
}
void Multigrid::SetOperator(const Operator& op)
{
MFEM_ABORT("SetOperator not supported in Multigrid");
}
void Multigrid::SmoothingStep(int level, bool transpose) const
{
GetOperatorAtLevel(level)->Mult(*Y[level], *R[level]); // r = A x
subtract(*X[level], *R[level], *R[level]); // r = b - A x
if (transpose)
{
GetSmootherAtLevel(level)->MultTranspose(*R[level], *Z[level]); // z = S r
}
else
{
GetSmootherAtLevel(level)->Mult(*R[level], *Z[level]); // z = S r
}
add(*Y[level], 1.0, *Z[level], *Y[level]); // x = x + S (b - A x)
}
void Multigrid::Cycle(int level) const
{
if (level == 0)
{
GetSmootherAtLevel(level)->Mult(*X[level], *Y[level]);
return;
}
for (int i = 0; i < preSmoothingSteps; i++)
{
SmoothingStep(level, false);
}
// Compute residual
GetOperatorAtLevel(level)->Mult(*Y[level], *R[level]);
subtract(*X[level], *R[level], *R[level]);
// Restrict residual
GetProlongationAtLevel(level - 1)->MultTranspose(*R[level], *X[level - 1]);
// Init zeros
*Y[level - 1] = 0.0;
// Corrections
int corrections = 1;
if (cycleType == CycleType::WCYCLE)
{
corrections = 2;
}
for (int correction = 0; correction < corrections; ++correction)
{
Cycle(level - 1);
}
// Prolongate
GetProlongationAtLevel(level - 1)->Mult(*Y[level - 1], *R[level]);
// Add update
*Y[level] += *R[level];
// Post-smooth
for (int i = 0; i < postSmoothingSteps; i++)
{
SmoothingStep(level, true);
}
}
const Operator* Multigrid::GetProlongationAtLevel(int level) const
{
return prolongations[level];
}
GeometricMultigrid::~GeometricMultigrid()
{
@@ -269,10 +232,15 @@ GeometricMultigrid::~GeometricMultigrid()
{
delete bfs[i];
}
bfs.DeleteAll();
for (int i = 0; i < essentialTrueDofs.Size(); ++i)
{
delete essentialTrueDofs[i];
}
essentialTrueDofs.DeleteAll();
}
void GeometricMultigrid::FormFineLinearSystem(Vector& x, Vector& b,
@@ -288,4 +256,9 @@ void GeometricMultigrid::RecoverFineFEMSolution(const Vector& X,
bfs.Last()->RecoverFEMSolution(X, b, x);
}
const Operator* GeometricMultigrid::GetProlongationAtLevel(int level) const
{
return fespaces.GetProlongationAtLevel(level);
}
} // namespace mfem
+63 -111
View File
@@ -21,8 +21,8 @@
namespace mfem
{
/// Abstract base class for Multigrid solvers
class MultigridBase : public Solver
/// Multigrid solver class
class Multigrid : public Solver
{
public:
enum class CycleType
@@ -34,118 +34,29 @@ public:
protected:
Array<Operator*> operators;
Array<Solver*> smoothers;
Array<Operator*> prolongations;
Array<bool> ownedOperators;
Array<bool> ownedSmoothers;
Array<bool> ownedProlongations;
CycleType cycleType;
int preSmoothingSteps;
int postSmoothingSteps;
mutable Array2D<Vector*> X, Y, R, Z;
mutable int nrhs;
mutable Array<Vector*> X;
mutable Array<Vector*> Y;
mutable Array<Vector*> R;
mutable Array<Vector*> Z;
public:
/// Constructs an empty multigrid hierarchy
MultigridBase();
/// Constructs a multigrid hierarchy from the given inputs
/** Inputs include operators and smoothers on all levels, and ownership of
the given operators and smoothers */
MultigridBase(const Array<Operator*>& operators_,
const Array<Solver*>& smoothers_,
const Array<bool>& ownedOperators_,
const Array<bool>& ownedSmoothers_);
/// Destructor
virtual ~MultigridBase();
/// Adds a level to the multigrid operator hierarchy
/** The ownership of the operators and solvers/smoothers may be transferred
to the Multigrid by setting the according boolean variables */
void AddLevel(Operator* op, Solver* smoother, bool ownOperator,
bool ownSmoother);
/// Returns the number of levels
int NumLevels() const { return operators.Size(); }
/// Returns the index of the finest level
int GetFinestLevelIndex() const { return NumLevels() - 1; }
/// Returns operator at given level
const Operator* GetOperatorAtLevel(int level) const
{
return operators[level];
}
Operator* GetOperatorAtLevel(int level)
{
return operators[level];
}
/// Returns operator at finest level
const Operator* GetOperatorAtFinestLevel() const
{
return GetOperatorAtLevel(GetFinestLevelIndex());
}
Operator* GetOperatorAtFinestLevel()
{
return GetOperatorAtLevel(GetFinestLevelIndex());
}
/// Returns smoother at given level
const Solver* GetSmootherAtLevel(int level) const
{
return smoothers[level];
}
Solver* GetSmootherAtLevel(int level)
{
return smoothers[level];
}
/// Set cycle type and number of pre- and post-smoothing steps used by Mult
void SetCycleType(CycleType cycleType_, int preSmoothingSteps_,
int postSmoothingSteps_);
/// Application of the multigrid as a preconditioner
virtual void Mult(const Vector& x, Vector& y) const override;
virtual void ArrayMult(const Array<const Vector*>& X_,
Array<Vector*>& Y_) const override;
/// Not supported for multigrid
virtual void SetOperator(const Operator& op) override
{
MFEM_ABORT("SetOperator is not supported in Multigrid!");
}
private:
/// Application of a multigrid cycle at particular level
void Cycle(int level) const;
/// Application of a pre-/post-smoothing step at particular level
void SmoothingStep(int level, bool zero, bool transpose) const;
/// Allocate or destroy temporary storage
void InitVectors() const;
void EraseVectors() const;
/// Returns prolongation operator at given level
virtual const Operator* GetProlongationAtLevel(int level) const = 0;
};
/// Multigrid solver class
class Multigrid : public MultigridBase
{
protected:
Array<Operator*> prolongations;
Array<bool> ownedProlongations;
public:
/// Constructs an empty multigrid hierarchy
/// Constructs an empty multigrid hierarchy.
Multigrid();
/// Constructs a multigrid hierarchy from the given inputs
/// Constructs a multigrid hierarchy from the given inputs.
/** Inputs include operators and smoothers on all levels, prolongation
operators that go from coarser to finer levels, and ownership of the
given operators, smoothers, and prolongations */
given operators, smoothers, and prolongations. */
Multigrid(const Array<Operator*>& operators_, const Array<Solver*>& smoothers_,
const Array<Operator*>& prolongations_, const Array<bool>& ownedOperators_,
const Array<bool>& ownedSmoothers_, const Array<bool>& ownedProlongations_);
@@ -153,16 +64,59 @@ public:
/// Destructor
virtual ~Multigrid();
/// Adds a level to the multigrid operator hierarchy.
/** The ownership of the operators and solvers/smoothers may be transferred
to the Multigrid by setting the according boolean variables. */
void AddLevel(Operator* opr, Solver* smoother, bool ownOperator,
bool ownSmoother);
/// Returns the number of levels
int NumLevels() const;
/// Returns the index of the finest level
int GetFinestLevelIndex() const;
/// Returns operator at given level
const Operator* GetOperatorAtLevel(int level) const;
/// Returns operator at given level
Operator* GetOperatorAtLevel(int level);
/// Returns operator at finest level
const Operator* GetOperatorAtFinestLevel() const;
/// Returns operator at finest level
Operator* GetOperatorAtFinestLevel();
/// Returns smoother at given level
Solver* GetSmootherAtLevel(int level) const;
/// Returns smoother at given level
Solver* GetSmootherAtLevel(int level);
/// Set cycle type and number of pre- and post-smoothing steps used by Mult
void SetCycleType(CycleType cycleType_, int preSmoothingSteps_,
int postSmoothingSteps_);
/// Application of the multigrid as a preconditioner
virtual void Mult(const Vector& x, Vector& y) const override;
/// Not supported for multigrid
virtual void SetOperator(const Operator& op) override;
private:
/// Application of a smoothing step at particular level
void SmoothingStep(int level, bool transpose) const;
/// Application of a multigrid cycle at particular level
void Cycle(int level) const;
/// Returns prolongation operator at given level
virtual const Operator* GetProlongationAtLevel(int level) const override
{
return prolongations[level];
}
virtual const Operator* GetProlongationAtLevel(int level) const;
};
/// Geometric multigrid associated with a hierarchy of finite element spaces
class GeometricMultigrid : public MultigridBase
class GeometricMultigrid : public Multigrid
{
protected:
const FiniteElementSpaceHierarchy& fespaces;
@@ -172,7 +126,8 @@ protected:
public:
/** Construct an empty multigrid object for the given finite element space
hierarchy @a fespaces_ */
GeometricMultigrid(const FiniteElementSpaceHierarchy& fespaces_);
GeometricMultigrid(const FiniteElementSpaceHierarchy& fespaces_)
: Multigrid(), fespaces(fespaces_) { }
/// Destructor
virtual ~GeometricMultigrid();
@@ -187,10 +142,7 @@ public:
private:
/// Returns prolongation operator at given level
virtual const Operator* GetProlongationAtLevel(int level) const override
{
return fespaces.GetProlongationAtLevel(level);
}
virtual const Operator* GetProlongationAtLevel(int level) const override;
};
} // namespace mfem
+9 -7
View File
@@ -347,12 +347,14 @@ ParallelEliminateEssentialBC(const Array<int> &bdr_attr_is_ess,
void ParBilinearForm::TrueAddMult(const Vector &x, Vector &y, const double a)
const
{
const Operator *P = pfes->GetProlongationMatrix();
Xaux.SetSize(P->Height());
Yaux.SetSize(P->Height());
Ytmp.SetSize(P->Width());
if (Xaux.ParFESpace() != pfes)
{
Xaux.SetSpace(pfes);
Yaux.SetSpace(pfes);
Ytmp.SetSize(pfes->GetTrueVSize());
}
P->Mult(x, Xaux);
Xaux.Distribute(&x);
if (ext)
{
ext->Mult(Xaux, Yaux);
@@ -364,8 +366,8 @@ const
" implemented");
mat->Mult(Xaux, Yaux);
}
P->MultTranspose(Yaux, Ytmp);
y.Add(a, Ytmp);
pfes->GetProlongationMatrix()->MultTranspose(Yaux, Ytmp);
y.Add(a,Ytmp);
}
void ParBilinearForm::FormLinearSystem(
+3 -2
View File
@@ -31,8 +31,9 @@ class ParBilinearForm : public BilinearForm
protected:
ParFiniteElementSpace *pfes; ///< Points to the same object as #fes
/// Auxiliary vectors used in TrueAddMult(): L-, L-, and T-vector, resp.
mutable Vector Xaux, Yaux, Ytmp;
/// Auxiliary objects used in TrueAddMult().
mutable ParGridFunction Xaux, Yaux;
mutable Vector Ytmp;
OperatorHandle p_mat, p_mat_e;
+4 -7
View File
@@ -569,7 +569,7 @@ const FaceRestriction *ParFiniteElementSpace::GetFaceRestriction(
{
if (Conforming())
{
res = new H1FaceRestriction(*this, e_ordering, type);
res = new H1_ND_RT_FaceRestriction(*this, e_ordering, type);
}
else
{
@@ -1536,7 +1536,7 @@ const FiniteElement *ParFiniteElementSpace::GetFaceNbrFaceFE(int i) const
// Works in tandem with GetFaceNbrFaceVDofs() defined above.
MFEM_ASSERT(Nonconforming() && !NURBSext, "");
Geometry::Type face_geom = pmesh->GetFaceGeometry(i);
Geometry::Type face_geom = pmesh->GetFaceGeometryType(i);
return fec->FiniteElementForGeometry(face_geom);
}
@@ -3025,8 +3025,6 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
Array<char> mark(diag->Height());
mark = 0;
bool is_dg = FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS;
for (int k = 0; k < dtrans.embeddings.Size(); k++)
{
const Embedding &emb = dtrans.embeddings[k];
@@ -3055,7 +3053,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
int r = DofToVDof(dofs[i], vd);
int m = (r >= 0) ? r : (-1 - r);
if (is_dg || !mark[m])
if (!mark[m])
{
lR.GetRow(i, row);
diag->SetRow(r, old_vdofs, row);
@@ -3107,7 +3105,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
int r = DofToVDof(dofs[i], vd);
int m = (r >= 0) ? r : (-1 - r);
if (is_dg || !mark[m])
if (!mark[m])
{
lR.GetRow(i, row);
MFEM_ASSERT(ldof[geom] == row.Size(), "");
@@ -3124,7 +3122,6 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
}
}
}
messages.clear();
offd->Finalize(0);
offd->SetWidth(col_map.size());
+1 -1
View File
@@ -54,7 +54,7 @@ void ParLinearForm::Assemble()
}
}
bool ParLinearForm::SupportsDevice()
bool ParLinearForm::SupportsDevice() const
{
bool parallel;
bool local = LinearForm::SupportsDevice();
+1 -1
View File
@@ -120,7 +120,7 @@ public:
void Assemble();
/// Return true if assembly on device is supported, false otherwise.
virtual bool SupportsDevice();
virtual bool SupportsDevice() const;
void AssembleSharedFaces();
+2 -6
View File
@@ -91,10 +91,8 @@ void ParNCH1FaceRestriction::NonconformingInterpolation(Vector& y) const
});
}
void ParNCH1FaceRestriction::AddMultTranspose(const Vector &x, Vector &y,
const double a) const
void ParNCH1FaceRestriction::AddMultTranspose(const Vector &x, Vector &y) const
{
MFEM_VERIFY(a == 1.0, "General coefficient case is not yet supported!");
if (nf==0) { return; }
NonconformingTransposeInterpolation(x);
H1FaceRestriction::AddMultTranspose(x_interp, y);
@@ -776,10 +774,8 @@ void ParNCL2FaceRestriction::Mult(const Vector& x, Vector& y) const
}
}
void ParNCL2FaceRestriction::AddMultTranspose(const Vector &x, Vector &y,
const double a) const
void ParNCL2FaceRestriction::AddMultTranspose(const Vector &x, Vector &y) const
{
MFEM_VERIFY(a == 1.0, "General coefficient case is not yet supported!");
if (nf==0) { return; }
if (type==FaceType::Interior)
{
+4 -8
View File
@@ -65,10 +65,8 @@ public:
requested by @a type in the constructor.
The face_dofs should be ordered according to the given
ElementDofOrdering.
@param[in,out] y The L-vector degrees of freedom.
@param[in] a Scalar coefficient for addition. */
void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const override;
@param[in,out] y The L-vector degrees of freedom. */
void AddMultTranspose(const Vector &x, Vector &y) const override;
/** @brief Gather the degrees of freedom, i.e. goes from face E-Vector to
L-Vector.
@@ -304,10 +302,8 @@ public:
requested by @a type in the constructor.
The face_dofs should be ordered according to the given
ElementDofOrdering
@param[in,out] y The L-vector degrees of freedom.
@param[in] a Scalar coefficient for addition. */
void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const override;
@param[in,out] y The L-vector degrees of freedom. */
void AddMultTranspose(const Vector &x, Vector &y) const override;
/** @brief Gather the degrees of freedom, i.e. goes from face E-Vector to
L-Vector.
+1 -1
View File
@@ -588,7 +588,7 @@ void FaceQuadratureInterpolator::Mult(
const int vdim = fespace->GetVDim();
const int dim = fespace->GetMesh()->Dimension();
const FiniteElement *fe =
fespace->GetTraceElement(0, fespace->GetMesh()->GetFaceGeometry(0));
fespace->GetTraceElement(0, fespace->GetMesh()->GetFaceBaseGeometry(0));
const IntegrationRule *ir = IntRule;
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::TENSOR);
const int nd1d = maps.ndof;
+84 -189
View File
@@ -148,7 +148,7 @@ void ElementRestriction::MultUnsigned(const Vector& x, Vector& y) const
}
template <bool ADD>
void ElementRestriction::TAddMultTranspose(const Vector& x, Vector& y) const
void ElementRestriction::AddMultTranspose(const Vector& x, Vector& y) const
{
// Assumes all elements have the same number of dofs
const int nd = dof;
@@ -180,15 +180,13 @@ void ElementRestriction::TAddMultTranspose(const Vector& x, Vector& y) const
void ElementRestriction::MultTranspose(const Vector& x, Vector& y) const
{
constexpr bool ADD = false;
TAddMultTranspose<ADD>(x, y);
AddMultTranspose<ADD>(x, y);
}
void ElementRestriction::AddMultTranspose(const Vector& x, Vector& y,
const double a) const
void ElementRestriction::AddMultTranspose(const Vector& x, Vector& y) const
{
MFEM_VERIFY(a == 1.0, "General coefficient case is not yet supported!");
constexpr bool ADD = true;
TAddMultTranspose<ADD>(x, y);
AddMultTranspose<ADD>(x, y);
}
void ElementRestriction::MultTransposeUnsigned(const Vector& x, Vector& y) const
@@ -523,7 +521,7 @@ void L2ElementRestriction::Mult(const Vector &x, Vector &y) const
}
template <bool ADD>
void L2ElementRestriction::TAddMultTranspose(const Vector &x, Vector &y) const
void L2ElementRestriction::AddMultTranspose(const Vector &x, Vector &y) const
{
const int nd = ndof;
const int vd = vdim;
@@ -546,15 +544,13 @@ void L2ElementRestriction::TAddMultTranspose(const Vector &x, Vector &y) const
void L2ElementRestriction::MultTranspose(const Vector &x, Vector &y) const
{
constexpr bool ADD = false;
TAddMultTranspose<ADD>(x, y);
AddMultTranspose<ADD>(x, y);
}
void L2ElementRestriction::AddMultTranspose(const Vector &x, Vector &y,
const double a) const
void L2ElementRestriction::AddMultTranspose(const Vector &x, Vector &y) const
{
MFEM_VERIFY(a == 1.0, "General coefficient case is not yet supported!");
constexpr bool ADD = true;
TAddMultTranspose<ADD>(x, y);
AddMultTranspose<ADD>(x, y);
}
void L2ElementRestriction::FillI(SparseMatrix &mat) const
@@ -598,119 +594,11 @@ void L2ElementRestriction::FillJAndData(const Vector &ea_data,
});
}
/** Return the face degrees of freedom returned in Lexicographic order.
Note: Only for quad and hex */
void GetFaceDofs(const int dim, const int face_id,
const int dof1d, Array<int> &face_map)
{
switch (dim)
{
case 1:
switch (face_id)
{
case 0: // WEST
face_map[0] = 0;
break;
case 1: // EAST
face_map[0] = dof1d-1;
break;
}
break;
case 2:
switch (face_id)
{
case 0: // SOUTH
for (int i = 0; i < dof1d; ++i)
{
face_map[i] = i;
}
break;
case 1: // EAST
for (int i = 0; i < dof1d; ++i)
{
face_map[i] = dof1d-1 + i*dof1d;
}
break;
case 2: // NORTH
for (int i = 0; i < dof1d; ++i)
{
face_map[i] = (dof1d-1)*dof1d + i;
}
break;
case 3: // WEST
for (int i = 0; i < dof1d; ++i)
{
face_map[i] = i*dof1d;
}
break;
}
break;
case 3:
switch (face_id)
{
case 0: // BOTTOM
for (int i = 0; i < dof1d; ++i)
{
for (int j = 0; j < dof1d; ++j)
{
face_map[i+j*dof1d] = i + j*dof1d;
}
}
break;
case 1: // SOUTH
for (int i = 0; i < dof1d; ++i)
{
for (int j = 0; j < dof1d; ++j)
{
face_map[i+j*dof1d] = i + j*dof1d*dof1d;
}
}
break;
case 2: // EAST
for (int i = 0; i < dof1d; ++i)
{
for (int j = 0; j < dof1d; ++j)
{
face_map[i+j*dof1d] = dof1d-1 + i*dof1d + j*dof1d*dof1d;
}
}
break;
case 3: // NORTH
for (int i = 0; i < dof1d; ++i)
{
for (int j = 0; j < dof1d; ++j)
{
face_map[i+j*dof1d] = (dof1d-1)*dof1d + i + j*dof1d*dof1d;
}
}
break;
case 4: // WEST
for (int i = 0; i < dof1d; ++i)
{
for (int j = 0; j < dof1d; ++j)
{
face_map[i+j*dof1d] = i*dof1d + j*dof1d*dof1d;
}
}
break;
case 5: // TOP
for (int i = 0; i < dof1d; ++i)
{
for (int j = 0; j < dof1d; ++j)
{
face_map[i+j*dof1d] = (dof1d-1)*dof1d*dof1d + i + j*dof1d;
}
}
break;
}
break;
}
}
H1FaceRestriction::H1FaceRestriction(const FiniteElementSpace &fes,
const ElementDofOrdering e_ordering,
const FaceType type,
bool build)
H1_ND_RT_FaceRestriction::H1_ND_RT_FaceRestriction(
const FiniteElementSpace &fes,
const ElementDofOrdering e_ordering,
const FaceType type,
bool build)
: fes(fes),
nf(fes.GetNFbyType(type)),
vdim(fes.GetVDim()),
@@ -731,18 +619,36 @@ H1FaceRestriction::H1FaceRestriction(const FiniteElementSpace &fes,
CheckFESpace(e_ordering);
ComputeScatterIndicesAndOffsets(e_ordering, type);
// Get the mapping from native DOF ordering to lexicographic ordering.
const FiniteElement *fe = fes.GetFE(0);
const TensorBasisElement* el =
dynamic_cast<const TensorBasisElement*>(fe);
const Array<int> &dof_map_ = el->GetDofMap();
if (dof_map_.Size() > 0)
{
dof_map.MakeRef(dof_map_);
}
else
{
// For certain types of elements dof_map_ is empty, in this case that
// means the element is already ordered lexicographically, so the
// permutation is the identity.
dof_map.SetSize(elem_dofs);
for (int i = 0; i < elem_dofs; ++i) { dof_map[i] = i; }
}
ComputeScatterIndicesAndOffsets(e_ordering, type);
ComputeGatherIndices(e_ordering,type);
}
H1FaceRestriction::H1FaceRestriction(const FiniteElementSpace &fes,
const ElementDofOrdering e_ordering,
const FaceType type)
: H1FaceRestriction(fes, e_ordering, type, true)
H1_ND_RT_FaceRestriction::H1_ND_RT_FaceRestriction(
const FiniteElementSpace &fes,
const ElementDofOrdering e_ordering,
const FaceType type)
: H1_ND_RT_FaceRestriction(fes, e_ordering, type, true)
{ }
void H1FaceRestriction::Mult(const Vector& x, Vector& y) const
void H1_ND_RT_FaceRestriction::Mult(const Vector& x, Vector& y) const
{
if (nf==0) { return; }
// Assumes all elements have the same number of dofs
@@ -754,20 +660,21 @@ void H1FaceRestriction::Mult(const Vector& x, Vector& y) const
auto d_y = Reshape(y.Write(), nface_dofs, vd, nf);
MFEM_FORALL(i, nfdofs,
{
const int idx = d_indices[i];
const int s_idx = d_indices[i];
const int sgn = (s_idx >= 0) ? 1 : -1;
const int idx = (s_idx >= 0) ? s_idx : -1 - s_idx;
const int dof = i % nface_dofs;
const int face = i / nface_dofs;
for (int c = 0; c < vd; ++c)
{
d_y(dof, c, face) = d_x(t?c:idx, t?idx:c);
d_y(dof, c, face) = sgn*d_x(t?c:idx, t?idx:c);
}
});
}
void H1FaceRestriction::AddMultTranspose(const Vector& x, Vector& y,
const double a) const
void H1_ND_RT_FaceRestriction::AddMultTranspose(
const Vector& x, Vector& y) const
{
MFEM_VERIFY(a == 1.0, "General coefficient case is not yet supported!");
if (nf==0) { return; }
// Assumes all elements have the same number of dofs
const int nface_dofs = face_dofs;
@@ -786,15 +693,17 @@ void H1FaceRestriction::AddMultTranspose(const Vector& x, Vector& y,
double dof_value = 0;
for (int j = offset; j < next_offset; ++j)
{
const int idx_j = d_indices[j];
dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
const int s_idx_j = d_indices[j];
const int sgn = (s_idx_j >= 0) ? 1 : -1;
const int idx_j = (s_idx_j >= 0) ? s_idx_j : -1 - s_idx_j;
dof_value += sgn*d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
}
d_y(t?c:i,t?i:c) += dof_value;
}
});
}
void H1FaceRestriction::CheckFESpace(const ElementDofOrdering e_ordering)
void H1_ND_RT_FaceRestriction::CheckFESpace(const ElementDofOrdering e_ordering)
{
#ifdef MFEM_USE_MPI
@@ -816,7 +725,7 @@ void H1FaceRestriction::CheckFESpace(const ElementDofOrdering e_ordering)
(tfe->GetBasisType()==BasisType::GaussLobatto ||
tfe->GetBasisType()==BasisType::Positive),
"Only Gauss-Lobatto and Bernstein basis are supported in "
"H1FaceRestriction.");
"H1_ND_RT_FaceRestriction.");
// Assuming all finite elements are using Gauss-Lobatto.
const bool dof_reorder = (e_ordering == ElementDofOrdering::LEXICOGRAPHIC);
@@ -830,16 +739,11 @@ void H1FaceRestriction::CheckFESpace(const ElementDofOrdering e_ordering)
if (el) { continue; }
MFEM_ABORT("Finite element not suitable for lexicographic ordering");
}
const FiniteElement *fe = fes.GetFaceElement(0);
const TensorBasisElement* el =
dynamic_cast<const TensorBasisElement*>(fe);
const Array<int> &fe_dof_map = el->GetDofMap();
MFEM_VERIFY(fe_dof_map.Size() > 0, "invalid dof map");
}
#endif
}
void H1FaceRestriction::ComputeScatterIndicesAndOffsets(
void H1_ND_RT_FaceRestriction::ComputeScatterIndicesAndOffsets(
const ElementDofOrdering ordering,
const FaceType type)
{
@@ -877,7 +781,7 @@ void H1FaceRestriction::ComputeScatterIndicesAndOffsets(
}
}
void H1FaceRestriction::ComputeGatherIndices(
void H1_ND_RT_FaceRestriction::ComputeGatherIndices(
const ElementDofOrdering ordering,
const FaceType type)
{
@@ -910,7 +814,9 @@ void H1FaceRestriction::ComputeGatherIndices(
gather_offsets[0] = 0;
}
void H1FaceRestriction::SetFaceDofsScatterIndices(
static inline int absdof(int i) { return i < 0 ? -1-i : i; }
void H1_ND_RT_FaceRestriction::SetFaceDofsScatterIndices(
const Mesh::FaceInformation &face,
const int face_index,
const ElementDofOrdering ordering)
@@ -920,32 +826,29 @@ void H1FaceRestriction::SetFaceDofsScatterIndices(
MFEM_ASSERT(face.element[0].orientation==0,
"FaceRestriction used on degenerated mesh.");
const TensorBasisElement* el =
dynamic_cast<const TensorBasisElement*>(fes.GetFE(0));
const int *dof_map = el->GetDofMap().GetData();
fes.GetFE(0)->GetFaceMap(face.element[0].local_face_id, face_map);
const Table& e2dTable = fes.GetElementToDofTable();
const int* elem_map = e2dTable.GetJ();
const int face_id = face.element[0].local_face_id;
const int dim = fes.GetMesh()->Dimension();
const int dof1d = fes.GetFE(0)->GetOrder()+1;
const int elem_index = face.element[0].index;
const bool dof_reorder = (ordering == ElementDofOrdering::LEXICOGRAPHIC);
GetFaceDofs(dim, face_id, dof1d, face_map); // Only for quad and hex
for (int face_dof = 0; face_dof < face_dofs; ++face_dof)
{
const int nat_volume_dof = face_map[face_dof];
const int volume_dof = (!dof_reorder)?
nat_volume_dof:
dof_map[nat_volume_dof];
const int global_dof = elem_map[elem_index*elem_dofs + volume_dof];
const int s_volume_dof = (!dof_reorder) ?
nat_volume_dof :
dof_map[nat_volume_dof]; // signed
const int volume_dof = absdof(s_volume_dof);
const int s_global_dof = elem_map[elem_index*elem_dofs + volume_dof];
const int global_dof = absdof(s_global_dof);
const int restriction_dof = face_dofs*face_index + face_dof;
scatter_indices[restriction_dof] = global_dof;
scatter_indices[restriction_dof] = s_global_dof;
++gather_offsets[global_dof + 1];
}
}
void H1FaceRestriction::SetFaceDofsGatherIndices(
void H1_ND_RT_FaceRestriction::SetFaceDofsGatherIndices(
const Mesh::FaceInformation &face,
const int face_index,
const ElementDofOrdering ordering)
@@ -953,25 +856,25 @@ void H1FaceRestriction::SetFaceDofsGatherIndices(
MFEM_ASSERT(!(face.IsNonconformingCoarse()),
"This method should not be used on nonconforming coarse faces.");
const TensorBasisElement* el =
dynamic_cast<const TensorBasisElement*>(fes.GetFE(0));
const int *dof_map = el->GetDofMap().GetData();
fes.GetFE(0)->GetFaceMap(face.element[0].local_face_id, face_map);
const Table& e2dTable = fes.GetElementToDofTable();
const int* elem_map = e2dTable.GetJ();
const int face_id = face.element[0].local_face_id;
const int dim = fes.GetMesh()->Dimension();
const int dof1d = fes.GetFE(0)->GetOrder()+1;
const int elem_index = face.element[0].index;
const bool dof_reorder = (ordering == ElementDofOrdering::LEXICOGRAPHIC);
GetFaceDofs(dim, face_id, dof1d, face_map); // Only for quad and hex
for (int face_dof = 0; face_dof < face_dofs; ++face_dof)
{
const int nat_volume_dof = face_map[face_dof];
const int volume_dof = (!dof_reorder)?nat_volume_dof:dof_map[nat_volume_dof];
const int global_dof = elem_map[elem_index*elem_dofs + volume_dof];
const int s_volume_dof = (!dof_reorder)?nat_volume_dof:dof_map[nat_volume_dof];
const int volume_dof = absdof(s_volume_dof);
const int s_global_dof = elem_map[elem_index*elem_dofs + volume_dof];
const int sgn = (s_global_dof >= 0) ? 1 : -1;
const int global_dof = absdof(s_global_dof);
const int restriction_dof = face_dofs*face_index + face_dof;
gather_indices[gather_offsets[global_dof]++] = restriction_dof;
const int s_restriction_dof = (sgn >= 0) ? restriction_dof : -1 -
restriction_dof;
gather_indices[gather_offsets[global_dof]++] = s_restriction_dof;
}
}
@@ -1111,7 +1014,7 @@ L2FaceRestriction::L2FaceRestriction(const FiniteElementSpace &fes,
vdim(fes.GetVDim()),
byvdim(fes.GetOrdering() == Ordering::byVDIM),
face_dofs(nf > 0 ?
fes.GetTraceElement(0, fes.GetMesh()->GetFaceGeometry(0))->GetDof()
fes.GetTraceElement(0, fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof()
: 0),
elem_dofs(fes.GetFE(0)->GetDof()),
nfdofs(nf*face_dofs),
@@ -1272,10 +1175,8 @@ void L2FaceRestriction::DoubleValuedConformingAddMultTranspose(
});
}
void L2FaceRestriction::AddMultTranspose(const Vector& x, Vector& y,
const double a) const
void L2FaceRestriction::AddMultTranspose(const Vector& x, Vector& y) const
{
MFEM_VERIFY(a == 1.0, "General coefficient case is not yet supported!");
if (nf==0) { return; }
if (m == L2FaceValues::DoubleValued)
{
@@ -1428,7 +1329,7 @@ void L2FaceRestriction::CheckFESpace(const ElementDofOrdering e_ordering)
for (int f = 0; f < fes.GetNF(); ++f)
{
const FiniteElement *fe =
fes.GetTraceElement(f, fes.GetMesh()->GetFaceGeometry(f));
fes.GetTraceElement(f, fes.GetMesh()->GetFaceBaseGeometry(f));
const TensorBasisElement* el =
dynamic_cast<const TensorBasisElement*>(fe);
if (el) { continue; }
@@ -1525,10 +1426,8 @@ void L2FaceRestriction::SetFaceDofsScatterIndices1(
const Table& e2dTable = fes.GetElementToDofTable();
const int* elem_map = e2dTable.GetJ();
const int face_id1 = face.element[0].local_face_id;
const int dim = fes.GetMesh()->Dimension();
const int dof1d = fes.GetFE(0)->GetOrder()+1;
const int elem_index = face.element[0].index;
GetFaceDofs(dim, face_id1, dof1d, face_map); // Only for quad and hex
fes.GetFE(0)->GetFaceMap(face_id1, face_map);
for (int face_dof_elem1 = 0; face_dof_elem1 < face_dofs; ++face_dof_elem1)
{
@@ -1554,7 +1453,7 @@ void L2FaceRestriction::PermuteAndSetFaceDofsScatterIndices2(
const int orientation = face.element[1].orientation;
const int dim = fes.GetMesh()->Dimension();
const int dof1d = fes.GetFE(0)->GetOrder()+1;
GetFaceDofs(dim, face_id2, dof1d, face_map); // Only for quad and hex
fes.GetFE(0)->GetFaceMap(face_id2, face_map);
for (int face_dof_elem1 = 0; face_dof_elem1 < face_dofs; ++face_dof_elem1)
{
@@ -1582,7 +1481,7 @@ void L2FaceRestriction::PermuteAndSetSharedFaceDofsScatterIndices2(
const int orientation = face.element[1].orientation;
const int dim = fes.GetMesh()->Dimension();
const int dof1d = fes.GetFE(0)->GetOrder()+1;
GetFaceDofs(dim, face_id2, dof1d, face_map); // Only for quad and hex
fes.GetFE(0)->GetFaceMap(face_id2, face_map);
Array<int> face_nbr_dofs;
const ParFiniteElementSpace &pfes =
static_cast<const ParFiniteElementSpace&>(this->fes);
@@ -1624,10 +1523,8 @@ void L2FaceRestriction::SetFaceDofsGatherIndices1(
const Table& e2dTable = fes.GetElementToDofTable();
const int* elem_map = e2dTable.GetJ();
const int face_id1 = face.element[0].local_face_id;
const int dim = fes.GetMesh()->Dimension();
const int dof1d = fes.GetFE(0)->GetOrder()+1;
const int elem_index = face.element[0].index;
GetFaceDofs(dim, face_id1, dof1d, face_map); // Only for quad and hex
fes.GetFE(0)->GetFaceMap(face_id1, face_map);
for (int face_dof_elem1 = 0; face_dof_elem1 < face_dofs; ++face_dof_elem1)
{
@@ -1653,7 +1550,7 @@ void L2FaceRestriction::PermuteAndSetFaceDofsGatherIndices2(
const int orientation = face.element[1].orientation;
const int dim = fes.GetMesh()->Dimension();
const int dof1d = fes.GetFE(0)->GetOrder()+1;
GetFaceDofs(dim, face_id2, dof1d, face_map); // Only for quad and hex
fes.GetFE(0)->GetFaceMap(face_id2, face_map);
for (int face_dof_elem1 = 0; face_dof_elem1 < face_dofs; ++face_dof_elem1)
{
@@ -1788,7 +1685,7 @@ void InterpolationManager::LinearizeInterpolatorMapIntoVector()
{
// Assumes all trace elements are the same.
const FiniteElement *trace_fe =
fes.GetTraceElement(0, fes.GetMesh()->GetFaceGeometry(0));
fes.GetTraceElement(0, fes.GetMesh()->GetFaceBaseGeometry(0));
const int face_dofs = trace_fe->GetDof();
const int nc_size = interp_map.size();
MFEM_VERIFY(nc_cpt==nc_size, "Unexpected number of interpolators.");
@@ -2058,10 +1955,8 @@ void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolationInPlace
});
}
void NCL2FaceRestriction::AddMultTranspose(const Vector& x, Vector& y,
const double a) const
void NCL2FaceRestriction::AddMultTranspose(const Vector& x, Vector& y) const
{
MFEM_VERIFY(a == 1.0, "General coefficient case is not yet supported!");
if (nf==0) { return; }
if (type==FaceType::Interior)
{
+33 -39
View File
@@ -27,8 +27,7 @@ class ElementRestrictionOperator : public Operator
public:
/// @brief Add the E-vector degrees of freedom @a x to the L-vector degrees
/// of freedom @a y.
void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const override = 0;
virtual void AddMultTranspose(const Vector &x, Vector &y) const = 0;
};
/// Operator that converts FiniteElementSpace L-vectors to E-vectors.
@@ -66,10 +65,9 @@ protected:
public:
ElementRestriction(const FiniteElementSpace&, ElementDofOrdering);
void Mult(const Vector &x, Vector &y) const override;
void MultTranspose(const Vector &x, Vector &y) const override;
void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const override;
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const;
void AddMultTranspose(const Vector &x, Vector &y) const;
/// Compute Mult without applying signs based on DOF orientations.
void MultUnsigned(const Vector &x, Vector &y) const;
@@ -101,7 +99,7 @@ public:
///
/// Performs either MultTranspose or AddMultTranspose depending on the
/// boolean template parameter @a ADD.
template <bool ADD> void TAddMultTranspose(const Vector &x, Vector &y) const;
template <bool ADD> void AddMultTranspose(const Vector &x, Vector &y) const;
};
/// Operator that converts L2 FiniteElementSpace L-vectors to E-vectors.
@@ -118,10 +116,9 @@ class L2ElementRestriction : public ElementRestrictionOperator
const int ndofs;
public:
L2ElementRestriction(const FiniteElementSpace&);
void Mult(const Vector &x, Vector &y) const override;
void MultTranspose(const Vector &x, Vector &y) const override;
void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const override;
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const;
void AddMultTranspose(const Vector &x, Vector &y) const;
/** Fill the I array of SparseMatrix corresponding to the sparsity pattern
given by this ElementRestriction. */
void FillI(SparseMatrix &mat) const;
@@ -132,7 +129,7 @@ public:
///
/// Performs either MultTranspose or AddMultTranspose depending on the
/// boolean template parameter @a ADD.
template <bool ADD> void TAddMultTranspose(const Vector &x, Vector &y) const;
template <bool ADD> void AddMultTranspose(const Vector &x, Vector &y) const;
};
/** An enum type to specify if only e1 value is requested (SingleValued) or both
@@ -183,10 +180,8 @@ public:
@param[in] x The face degrees of freedom on the face.
@param[in,out] y The L-vector of degrees of freedom to which we add the
face degrees of freedom.
@param[in] a Scalar coefficient for addition.
*/
virtual void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const override = 0;
virtual void AddMultTranspose(const Vector &x, Vector &y) const = 0;
/** @brief Add the face degrees of freedom @a x to the element degrees of
freedom @a y. Perform the same computation as AddMultTranspose, but
@@ -221,7 +216,7 @@ public:
/// Operator that extracts Face degrees of freedom for H1 FiniteElementSpaces.
/** Objects of this type are typically created and owned by FiniteElementSpace
objects, see FiniteElementSpace::GetFaceRestriction(). */
class H1FaceRestriction : public FaceRestriction
class H1_ND_RT_FaceRestriction : public FaceRestriction
{
protected:
const FiniteElementSpace &fes;
@@ -235,29 +230,30 @@ protected:
Array<int> scatter_indices; // Scattering indices for element 1 on each face
Array<int> gather_offsets; // offsets for the gathering indices of each dof
Array<int> gather_indices; // gathering indices for each dof
Array<int> dof_map; // mapping to lexicographic ordering
/** @brief Construct an H1FaceRestriction.
/** @brief Construct an H1_ND_RT_FaceRestriction.
@param[in] fes The FiniteElementSpace on which this operates
@param[in] ordering Request a specific element ordering
@param[in] type Request internal or boundary faces dofs
@param[in] build Request the NCL2FaceRestriction to compute the
scatter/gather indices. False should only be used
when inheriting from H1FaceRestriction.
when inheriting from H1_ND_RT_FaceRestriction.
*/
H1FaceRestriction(const FiniteElementSpace& fes,
const ElementDofOrdering ordering,
const FaceType type,
bool build);
H1_ND_RT_FaceRestriction(const FiniteElementSpace& fes,
const ElementDofOrdering ordering,
const FaceType type,
bool build);
public:
/** @brief Construct an H1FaceRestriction.
/** @brief Construct an H1_ND_RT_FaceRestriction.
@param[in] fes The FiniteElementSpace on which this operates
@param[in] ordering Request a specific element ordering
@param[in] type Request internal or boundary faces dofs */
H1FaceRestriction(const FiniteElementSpace& fes,
const ElementDofOrdering ordering,
const FaceType type);
H1_ND_RT_FaceRestriction(const FiniteElementSpace& fes,
const ElementDofOrdering ordering,
const FaceType type);
/** @brief Scatter the degrees of freedom, i.e. goes from L-Vector to
face E-Vector.
@@ -282,10 +278,8 @@ public:
requested by @a type in the constructor.
The face_dofs should be ordered according to the given
ElementDofOrdering
@param[in,out] y The L-vector degrees of freedom.
@param[in] a Scalar coefficient for addition. */
void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const override;
@param[in,out] y The L-vector degrees of freedom. */
void AddMultTranspose(const Vector &x, Vector &y) const override;
private:
/** @brief Compute the scatter indices: L-vector to E-vector, and the offsets
@@ -310,7 +304,7 @@ private:
protected:
mutable Array<int> face_map; // Used in the computation of GetFaceDofs
/** @brief Verify that H1FaceRestriction is build from an H1 FESpace.
/** @brief Verify that H1_ND_RT_FaceRestriction is build from an H1 FESpace.
@param[in] ordering The FESpace element ordering.
*/
@@ -339,6 +333,10 @@ protected:
const ElementDofOrdering ordering);
};
/// @brief Alias for H1_ND_RT_FaceRestriction, for backwards compatibility and
/// as base class for ParNCH1FaceRestriction.
using H1FaceRestriction = H1_ND_RT_FaceRestriction;
/// Operator that extracts Face degrees of freedom for L2 spaces.
/** Objects of this type are typically created and owned by FiniteElementSpace
objects, see FiniteElementSpace::GetFaceRestriction(). */
@@ -416,10 +414,8 @@ public:
requested by @a type in the constructor.
The face_dofs should be ordered according to the given
ElementDofOrdering
@param[in,out] y The L-vector degrees of freedom.
@param[in] a Scalar coefficient for addition. */
void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const override;
@param[in,out] y The L-vector degrees of freedom. */
void AddMultTranspose(const Vector &x, Vector &y) const override;
/** @brief Fill the I array of SparseMatrix corresponding to the sparsity
pattern given by this L2FaceRestriction.
@@ -840,10 +836,8 @@ public:
requested by @a type in the constructor.
The face_dofs should be ordered according to the given
ElementDofOrdering
@param[in,out] y The L-vector degrees of freedom.
@param[in] a Scalar coefficient for addition. */
void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const override;
@param[in,out] y The L-vector degrees of freedom. */
void AddMultTranspose(const Vector &x, Vector &y) const override;
/** @brief Gather the degrees of freedom, i.e. goes from face E-Vector to
L-Vector.
-1
View File
@@ -615,7 +615,6 @@ public:
solFES.VectorAssemble(y_dof.layout, y_dof, solVecLayoutLoc, y);
}
}
using Operator::AddMult;
};
} // namespace mfem
+19 -132
View File
@@ -48,7 +48,8 @@ void TMOP_Combo_QualityMetric::EvalP(const DenseMatrix &Jpt,
for (int i = 0; i < tmop_q_arr.Size(); i++)
{
tmop_q_arr[i]->EvalP(Jpt, Pt);
P.Add(wt_arr[i], Pt);
Pt *= wt_arr[i];
P += Pt;
}
}
@@ -61,109 +62,12 @@ void TMOP_Combo_QualityMetric::AssembleH(const DenseMatrix &Jpt,
for (int i = 0; i < tmop_q_arr.Size(); i++)
{
At = 0.0;
tmop_q_arr[i]->AssembleH(Jpt, DS, weight * wt_arr[i], At);
tmop_q_arr[i]->AssembleH(Jpt, DS, weight, At);
At *= wt_arr[i];
A += At;
}
}
void TMOP_Combo_QualityMetric::
ComputeBalancedWeights(const GridFunction &nodes,
const TargetConstructor &tc, Vector &weights) const
{
const int m_cnt = tmop_q_arr.Size();
Vector averages;
ComputeAvgMetrics(nodes, tc, averages);
weights.SetSize(m_cnt);
// For [ combo_A_B_C = a m_A + b m_B + c m_C ] we would have:
// a = BC / (AB + AC + BC), b = AC / (AB + AC + BC), c = AB / (AB + AC + BC),
// where A = avg_m_A, B = avg_m_B, C = avg_m_C.
// Nested loop to avoid division, as some avg may be 0.
Vector products_no_m(m_cnt); products_no_m = 1.0;
for (int m_p = 0; m_p < m_cnt; m_p++)
{
for (int m_a = 0; m_a < m_cnt; m_a++)
{
if (m_p != m_a) { products_no_m(m_p) *= averages(m_a); }
}
}
const double pnm_sum = products_no_m.Sum();
if (pnm_sum == 0.0) { weights = 1.0 / m_cnt; return; }
for (int m = 0; m < m_cnt; m++) { weights(m) = products_no_m(m) / pnm_sum; }
MFEM_ASSERT(fabs(weights.Sum() - 1.0) < 1e-14,
"Error: sum should be 1 always: " << weights.Sum());
}
void TMOP_Combo_QualityMetric::ComputeAvgMetrics(const GridFunction &nodes,
const TargetConstructor &tc,
Vector &averages) const
{
const int m_cnt = tmop_q_arr.Size(),
NE = nodes.FESpace()->GetNE(),
dim = nodes.FESpace()->GetMesh()->Dimension();
averages.SetSize(m_cnt);
// Integrals of all metrics.
Array<int> pos_dofs;
averages = 0.0;
double volume = 0.0;
for (int e = 0; e < NE; e++)
{
const FiniteElement &fe_pos = *nodes.FESpace()->GetFE(e);
const IntegrationRule &ir = IntRules.Get(fe_pos.GetGeomType(),
2 * fe_pos.GetOrder());
const int nsp = ir.GetNPoints(), dof = fe_pos.GetDof();
DenseMatrix dshape(dof, dim);
DenseMatrix pos(dof, dim);
pos.SetSize(dof, dim);
Vector posV(pos.Data(), dof * dim);
nodes.FESpace()->GetElementVDofs(e, pos_dofs);
nodes.GetSubVector(pos_dofs, posV);
DenseTensor W(dim, dim, nsp);
DenseMatrix Winv(dim), T(dim), A(dim);
tc.ComputeElementTargets(e, fe_pos, ir, posV, W);
for (int q = 0; q < nsp; q++)
{
const DenseMatrix &Wj = W(q);
CalcInverse(Wj, Winv);
const IntegrationPoint &ip = ir.IntPoint(q);
fe_pos.CalcDShape(ip, dshape);
MultAtB(pos, dshape, A);
Mult(A, Winv, T);
const double w_detA = ip.weight * A.Det();
for (int m = 0; m < m_cnt; m++)
{
tmop_q_arr[m]->SetTargetJacobian(Wj);
averages(m) += tmop_q_arr[m]->EvalW(T) * w_detA;
}
volume += w_detA;
}
}
// Parallel case.
#ifdef MFEM_USE_MPI
auto par_nodes = dynamic_cast<const ParGridFunction *>(&nodes);
if (par_nodes)
{
MPI_Allreduce(MPI_IN_PLACE, averages.GetData(), m_cnt,
MPI_DOUBLE, MPI_SUM, par_nodes->ParFESpace()->GetComm());
MPI_Allreduce(MPI_IN_PLACE, &volume, 1, MPI_DOUBLE, MPI_SUM,
par_nodes->ParFESpace()->GetComm());
}
#endif
averages /= volume;
}
double TMOP_WorstCaseUntangleOptimizer_Metric::EvalW(const DenseMatrix &Jpt)
const
{
@@ -824,30 +728,30 @@ void TMOP_Metric_301::AssembleH(const DenseMatrix &Jpt,
// dW = (1/6)*[z2*dI1b + z1*dI2b], z1 = sqrt(I1b/I2b), z2 = sqrt(I2b/I1b)
// ddW = (1/6)*[dI1b x dz2 + z2*ddI1b + dI2b x dz1 + z1*ddI2b]
//
// dz1 = (1/2)*sqrt(I2b/I1b) [ (1/I2b)*dI1b - (I1b/(I2b*I2b))*dI2b ]
// = (1/2)/sqrt(I1b*I2b) [ dI1b - (I1b/I2b)*dI2b ]
// dz2 = (1/2)/sqrt(I1b*I2b) [ dI2b - (I2b/I1b)*dI1b ]
// dz1 = (1/2)*sqrt(I2b/I1b) [ (1/I2b)*dI1b + (I1b/(I2b*I2b))*dI2b ]
// = (1/2)/sqrt(I1b*I2b) [ dI1b + (I1b/I2b)*dI2b ]
// dz2 = (1/2)/sqrt(I1b*I2b) [ (I2b/I1b)*dI1b + dI2b ]
//
// dI1b x dz2 + dI2b x dz1 =
// (1/2)/sqrt(I1b*I2b) dI1b x [ dI2b - (I2b/I1b)*dI1b ] +
// (1/2)/sqrt(I1b*I2b) dI2b x [ dI1b - (I1b/I2b)*dI2b ] =
// (1/2)/sqrt(I1b*I2b) [sqrt(I1b/I2b)*dI2b - sqrt(I2b/I1b)*dI1b] x
// [sqrt(I2b/I1b)*dI1b - sqrt(I1b/I2b)*dI2b] =
// (1/2)*(I1b*I2b)^{-3/2} (I1b*dI2b - I2b*dI1b) x (I2b*dI1b - I1b*dI2b)
// and the last two parentheses are the same up to a sign.
// (1/2)/sqrt(I1b*I2b) dI1b x [ (I2b/I1b)*dI1b + dI2b ] +
// (1/2)/sqrt(I1b*I2b) dI2b x [ dI1b + (I1b/I2b)*dI2b ] =
// (1/2)/sqrt(I1b*I2b) [sqrt(I2b/I1b)*dI1b + sqrt(I1b/I2b)*dI2b] x
// [sqrt(I2b/I1b)*dI1b + sqrt(I1b/I2b)*dI2b] =
// (1/2)/sqrt(I1b*I2b) [ 6*dW x 6*dW ] =
// (1/2)*(I1b*I2b)^{-3/2} (I2b*dI1b + I1b*dI2b) x (I2b*dI1b + I1b*dI2b)
//
// z1 = I1b/sqrt(I1b*I2b), z2 = I2b/sqrt(I1b*I2b)
ie.SetJacobian(Jpt.GetData());
ie.SetDerivativeMatrix(DS.Height(), DS.GetData());
double X_data[9];
DenseMatrix X(X_data, 3, 3);
Add(- ie.Get_I2b(), ie.Get_dI1b(), ie.Get_I1b(), ie.Get_dI2b(), X);
double d_I1b_I2b_data[9];
DenseMatrix d_I1b_I2b(d_I1b_I2b_data, 3, 3);
Add(ie.Get_I2b(), ie.Get_dI1b(), ie.Get_I1b(), ie.Get_dI2b(), d_I1b_I2b);
const double I1b_I2b = ie.Get_I1b()*ie.Get_I2b();
const double a = weight/(6*std::sqrt(I1b_I2b));
ie.Assemble_ddI1b(a*ie.Get_I2b(), A.GetData());
ie.Assemble_ddI2b(a*ie.Get_I1b(), A.GetData());
ie.Assemble_TProd(-a/(2*I1b_I2b), X_data, A.GetData());
ie.Assemble_TProd(a/(2*I1b_I2b), d_I1b_I2b_data, A.GetData());
}
double TMOP_Metric_302::EvalWMatrixForm(const DenseMatrix &Jpt) const
@@ -2894,6 +2798,8 @@ void TMOP_Integrator::GetSurfaceFittingErrors(double &err_avg, double &err_max)
loc_sum += std::abs((*surf_fit_gf)(i));
}
}
err_avg = loc_sum / loc_cnt;
err_max = loc_max;
#ifdef MFEM_USE_MPI
if (targetC->Parallel() == false) { return; }
@@ -2903,9 +2809,6 @@ void TMOP_Integrator::GetSurfaceFittingErrors(double &err_avg, double &err_max)
MPI_Allreduce(&loc_cnt, &glob_cnt, 1, MPI_INT, MPI_SUM, comm);
MPI_Allreduce(&loc_sum, &err_avg, 1, MPI_DOUBLE, MPI_SUM, comm);
err_avg = err_avg / glob_cnt;
#else
err_avg = loc_sum / loc_cnt;
err_max = loc_max;
#endif
}
@@ -4094,14 +3997,6 @@ void TMOP_Integrator::EnableFiniteDifferences(const GridFunction &x)
ComputeFDh(x,*fes);
if (discr_tc)
{
#ifdef MFEM_USE_GSLIB
const AdaptivityEvaluator *ae = discr_tc->GetAdaptivityEvaluator();
if (dynamic_cast<const InterpolatorFP *>(ae))
{
MFEM_ABORT("Using GSLIB-based interpolation with finite differences"
"requires careful consideration. Contact TMOP team.");
}
#endif
discr_tc->UpdateTargetSpecification(x, false, fes->GetOrdering());
discr_tc->UpdateGradientTargetSpecification(x, dx, false, fes->GetOrdering());
discr_tc->UpdateHessianTargetSpecification(x, dx, false, fes->GetOrdering());
@@ -4116,14 +4011,6 @@ void TMOP_Integrator::EnableFiniteDifferences(const ParGridFunction &x)
ComputeFDh(x,*pfes);
if (discr_tc)
{
#ifdef MFEM_USE_GSLIB
const AdaptivityEvaluator *ae = discr_tc->GetAdaptivityEvaluator();
if (dynamic_cast<const InterpolatorFP *>(ae))
{
MFEM_ABORT("Using GSLIB-based interpolation with finite differences"
"requires careful consideration. Contact TMOP team.");
}
#endif
discr_tc->UpdateTargetSpecification(x, false, pfes->GetOrdering());
discr_tc->UpdateGradientTargetSpecification(x, dx, false, pfes->GetOrdering());
discr_tc->UpdateHessianTargetSpecification(x, dx, false, pfes->GetOrdering());
+56 -76
View File
@@ -78,14 +78,11 @@ public:
virtual int Id() const { return 0; }
};
class TargetConstructor;
/// Abstract class used to define explicit combination of metrics with constant
/// coefficients.
/// Abstract class used to define combination of metrics with constant coefficients.
class TMOP_Combo_QualityMetric : public TMOP_QualityMetric
{
protected:
Array<TMOP_QualityMetric *> tmop_q_arr; //the metrics are not owned
Array<TMOP_QualityMetric *> tmop_q_arr; //not owned
Array<double> wt_arr;
public:
@@ -111,25 +108,6 @@ public:
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
const double weight, DenseMatrix &A) const;
/// Computes the averages of all metrics (integral of metric / volume).
/// Works in parallel when called with a ParGridFunction.
void ComputeAvgMetrics(const GridFunction &nodes,
const TargetConstructor &tc,
Vector &averages) const;
/// Computes weights so that the averages of all metrics are equal, and the
/// weights sum to one. Works in parallel when called with a ParGridFunction.
void ComputeBalancedWeights(const GridFunction &nodes,
const TargetConstructor &tc,
Vector &weights) const;
/// Changes the weights of the metrics in the combination.
void SetWeights(const Vector &weights)
{
MFEM_VERIFY(tmop_q_arr.Size() == weights.Size(), "Incorrect #weights");
for (int i = 0; i < tmop_q_arr.Size(); i++) { wt_arr[i] = weights(i); }
}
};
/// Simultaneous Untangler + Worst Case Improvement Metric
@@ -294,7 +272,6 @@ public:
};
/// 2D barrier shape (S) metric (polyconvex).
/// Grade - A.
class TMOP_Metric_002 : public TMOP_QualityMetric
{
protected:
@@ -316,7 +293,6 @@ public:
};
/// 2D non-barrier shape (S) metric.
/// Grade - F.
class TMOP_Metric_004 : public TMOP_QualityMetric
{
protected:
@@ -402,8 +378,7 @@ public:
const double weight, DenseMatrix &A) const;
};
/// 2D barrier shape metric (polyconvex).
/// Grade - A.
/// 2D barrier (not a shape) metric (polyconvex).
class TMOP_Metric_050 : public TMOP_QualityMetric
{
protected:
@@ -420,7 +395,6 @@ public:
};
/// 2D non-barrier size (V) metric (not polyconvex).
/// Grade - F.
class TMOP_Metric_055 : public TMOP_QualityMetric
{
protected:
@@ -438,7 +412,6 @@ public:
};
/// 2D barrier size (V) metric (polyconvex).
/// Grade - C.
class TMOP_Metric_056 : public TMOP_QualityMetric
{
protected:
@@ -476,29 +449,29 @@ public:
};
/// 2D non-barrier Shape+Size (VS) metric.
/// Grade - F.
class TMOP_Metric_066 : public TMOP_Combo_QualityMetric
{
protected:
mutable InvariantsEvaluator2D<double> ie;
double gamma;
TMOP_QualityMetric *sh_metric, *sz_metric;
public:
TMOP_Metric_066(double gamma)
: sh_metric(new TMOP_Metric_004), sz_metric(new TMOP_Metric_055)
TMOP_Metric_066(double gamma_) : gamma(gamma_),
sh_metric(new TMOP_Metric_004),
sz_metric(new TMOP_Metric_055)
{
// (1-gamma) mu_4 + gamma mu_55
AddQualityMetric(sh_metric, 1.-gamma);
AddQualityMetric(sz_metric, gamma);
AddQualityMetric(sh_metric, 1.-gamma_);
AddQualityMetric(sz_metric, gamma_);
}
virtual int Id() const { return 66; }
double GetGamma() const { return wt_arr[1]; }
double GetGamma() const { return gamma; }
virtual ~TMOP_Metric_066() { delete sh_metric; delete sz_metric; }
};
/// 2D barrier size (V) metric (polyconvex).
/// Grade - C.
class TMOP_Metric_077 : public TMOP_QualityMetric
{
protected:
@@ -517,24 +490,24 @@ public:
};
/// 2D barrier Shape+Size (VS) metric (polyconvex).
/// Grade - A.
class TMOP_Metric_080 : public TMOP_Combo_QualityMetric
{
protected:
mutable InvariantsEvaluator2D<double> ie;
double gamma;
TMOP_QualityMetric *sh_metric, *sz_metric;
public:
TMOP_Metric_080(double gamma)
: sh_metric(new TMOP_Metric_002), sz_metric(new TMOP_Metric_077)
TMOP_Metric_080(double gamma_) : gamma(gamma_),
sh_metric(new TMOP_Metric_002),
sz_metric(new TMOP_Metric_077)
{
// (1-gamma) mu_2 + gamma mu_77
AddQualityMetric(sh_metric, 1.0 - gamma);
AddQualityMetric(sz_metric, gamma);
AddQualityMetric(sh_metric, 1.-gamma_);
AddQualityMetric(sz_metric, gamma_);
}
virtual int Id() const { return 80; }
double GetGamma() const { return wt_arr[1]; }
double GetGamma() const { return gamma; }
virtual ~TMOP_Metric_080() { delete sh_metric; delete sz_metric; }
};
@@ -835,15 +808,17 @@ class TMOP_Metric_328 : public TMOP_Combo_QualityMetric
{
protected:
mutable InvariantsEvaluator2D<double> ie;
double gamma;
TMOP_QualityMetric *sh_metric, *sz_metric;
public:
TMOP_Metric_328(double gamma)
: sh_metric(new TMOP_Metric_301), sz_metric(new TMOP_Metric_316)
TMOP_Metric_328(double gamma_) : gamma(gamma_),
sh_metric(new TMOP_Metric_301),
sz_metric(new TMOP_Metric_316)
{
// (1-gamma) mu_301 + gamma mu_316
AddQualityMetric(sh_metric, 1.-gamma);
AddQualityMetric(sz_metric, gamma);
AddQualityMetric(sh_metric, 1.-gamma_);
AddQualityMetric(sz_metric, gamma_);
}
virtual ~TMOP_Metric_328() { delete sh_metric; delete sz_metric; }
@@ -853,19 +828,21 @@ public:
class TMOP_Metric_332 : public TMOP_Combo_QualityMetric
{
protected:
double gamma;
TMOP_QualityMetric *sh_metric, *sz_metric;
public:
TMOP_Metric_332(double gamma)
: sh_metric(new TMOP_Metric_302), sz_metric(new TMOP_Metric_315)
TMOP_Metric_332(double gamma_) : gamma(gamma_),
sh_metric(new TMOP_Metric_302),
sz_metric(new TMOP_Metric_315)
{
// (1-gamma) mu_302 + gamma mu_315
AddQualityMetric(sh_metric, 1.-gamma);
AddQualityMetric(sz_metric, gamma);
AddQualityMetric(sh_metric, 1.-gamma_);
AddQualityMetric(sz_metric, gamma_);
}
virtual int Id() const { return 332; }
double GetGamma() const { return wt_arr[1]; }
double GetGamma() const { return gamma; }
virtual ~TMOP_Metric_332() { delete sh_metric; delete sz_metric; }
};
@@ -875,15 +852,17 @@ class TMOP_Metric_333 : public TMOP_Combo_QualityMetric
{
protected:
mutable InvariantsEvaluator2D<double> ie;
double gamma;
TMOP_QualityMetric *sh_metric, *sz_metric;
public:
TMOP_Metric_333(double gamma)
: sh_metric(new TMOP_Metric_302), sz_metric(new TMOP_Metric_316)
TMOP_Metric_333(double gamma_) : gamma(gamma_),
sh_metric(new TMOP_Metric_302),
sz_metric(new TMOP_Metric_316)
{
// (1-gamma) mu_302 + gamma mu_316
AddQualityMetric(sh_metric, 1.-gamma);
AddQualityMetric(sz_metric, gamma);
AddQualityMetric(sh_metric, 1.-gamma_);
AddQualityMetric(sz_metric, gamma_);
}
virtual ~TMOP_Metric_333() { delete sh_metric; delete sz_metric; }
@@ -894,19 +873,21 @@ class TMOP_Metric_334 : public TMOP_Combo_QualityMetric
{
protected:
mutable InvariantsEvaluator2D<double> ie;
double gamma;
TMOP_QualityMetric *sh_metric, *sz_metric;
public:
TMOP_Metric_334(double gamma)
: sh_metric(new TMOP_Metric_303), sz_metric(new TMOP_Metric_316)
TMOP_Metric_334(double gamma_) : gamma(gamma_),
sh_metric(new TMOP_Metric_303),
sz_metric(new TMOP_Metric_316)
{
// (1-gamma) mu_303 + gamma mu_316
AddQualityMetric(sh_metric, 1.-gamma);
AddQualityMetric(sz_metric, gamma);
AddQualityMetric(sh_metric, 1.-gamma_);
AddQualityMetric(sz_metric, gamma_);
}
virtual int Id() const { return 334; }
double GetGamma() const { return wt_arr[1]; }
double GetGamma() const { return gamma; }
virtual ~TMOP_Metric_334() { delete sh_metric; delete sz_metric; }
};
@@ -916,19 +897,21 @@ class TMOP_Metric_347 : public TMOP_Combo_QualityMetric
{
protected:
mutable InvariantsEvaluator2D<double> ie;
double gamma;
TMOP_QualityMetric *sh_metric, *sz_metric;
public:
TMOP_Metric_347(double gamma)
: sh_metric(new TMOP_Metric_304), sz_metric(new TMOP_Metric_316)
TMOP_Metric_347(double gamma_) : gamma(gamma_),
sh_metric(new TMOP_Metric_304),
sz_metric(new TMOP_Metric_316)
{
// (1-gamma) mu_304 + gamma mu_316
AddQualityMetric(sh_metric, 1.-gamma);
AddQualityMetric(sz_metric, gamma);
AddQualityMetric(sh_metric, 1.-gamma_);
AddQualityMetric(sz_metric, gamma_);
}
virtual int Id() const { return 347; }
double GetGamma() const { return wt_arr[1]; }
double GetGamma() const { return gamma; }
virtual ~TMOP_Metric_347() { delete sh_metric; delete sz_metric; }
};
@@ -1051,15 +1034,17 @@ class TMOP_AMetric_126 : public TMOP_Combo_QualityMetric
{
protected:
mutable InvariantsEvaluator2D<double> ie;
double gamma;
TMOP_QualityMetric *sh_metric, *sz_metric;
public:
TMOP_AMetric_126(double gamma)
: sh_metric(new TMOP_AMetric_011), sz_metric(new TMOP_AMetric_014a)
TMOP_AMetric_126(double gamma_) : gamma(gamma_),
sh_metric(new TMOP_AMetric_011),
sz_metric(new TMOP_AMetric_014a)
{
// (1-gamma) nu_11 + gamma nu_14
AddQualityMetric(sh_metric, 1.-gamma);
AddQualityMetric(sz_metric, gamma);
AddQualityMetric(sh_metric, 1.-gamma_);
AddQualityMetric(sz_metric, gamma_);
}
virtual ~TMOP_AMetric_126() { delete sh_metric; delete sz_metric; }
@@ -1566,11 +1551,6 @@ public:
adapt_eval = ae;
}
const AdaptivityEvaluator *GetAdaptivityEvaluator() const
{
return adapt_eval;
}
const Vector &GetTspecPert1H() { return tspec_pert1h; }
const Vector &GetTspecPert2H() { return tspec_pert2h; }
const Vector &GetTspecPertMixH() { return tspec_pertmix; }
-5
View File
@@ -68,11 +68,6 @@ public:
Vector &new_field,
int new_nodes_ordering = Ordering::byNODES);
const FindPointsGSLIB *GetFindPointsGSLIB() const
{
return finder;
}
~InterpolatorFP()
{
finder->FreeData();
+7 -27
View File
@@ -291,10 +291,6 @@ L2ProjectionGridTransfer::L2ProjectionL2Space::L2ProjectionL2Space(
int nel_ho = mesh_ho->GetNE();
int nel_lor = mesh_lor->GetNE();
// The prolongation operation is only well-defined when the LOR space has at
// least as many DOFs as the high-order space.
const bool build_P = fes_lor.GetTrueVSize() >= fes_ho.GetTrueVSize();
// If the local mesh is empty, skip all computations
if (nel_ho == 0) { return; }
@@ -323,11 +319,8 @@ L2ProjectionGridTransfer::L2ProjectionL2Space::L2ProjectionL2Space(
// R will contain the restriction (L^2 projection operator) defined on each
// coarse HO element (and corresponding patch of LOR elements)
R.SetSize(offsets[nel_ho]);
if (build_P)
{
// P will contain the corresponding prolongation operator
P.SetSize(offsets[nel_ho]);
}
// P will contain the corresponding prolongation operator
P.SetSize(offsets[nel_ho]);
IntegrationPointTransformation ip_tr;
IsoparametricTransformation &emb_tr = ip_tr.Transf;
@@ -348,6 +341,7 @@ L2ProjectionGridTransfer::L2ProjectionL2Space::L2ProjectionL2Space(
const DenseTensor &pmats = cf_tr.point_matrices[geom];
DenseMatrix R_iho(&R[offsets[iho]], ndof_lor*nref, ndof_ho);
DenseMatrix P_iho(&P[offsets[iho]], ndof_ho, ndof_lor*nref);
DenseMatrix Minv_lor(ndof_lor*nref, ndof_lor*nref);
DenseMatrix M_mixed(ndof_lor*nref, ndof_ho);
@@ -391,15 +385,10 @@ L2ProjectionGridTransfer::L2ProjectionL2Space::L2ProjectionL2Space(
}
mfem::Mult(Minv_lor, M_mixed, R_iho);
if (build_P)
{
DenseMatrix P_iho(&P[offsets[iho]], ndof_ho, ndof_lor*nref);
mfem::MultAtB(R_iho, M_lor, RtMlor);
mfem::Mult(RtMlor, R_iho, RtMlorR);
RtMlorR_inv.Factor();
RtMlorR_inv.Mult(RtMlor, P_iho);
}
mfem::MultAtB(R_iho, M_lor, RtMlor);
mfem::Mult(RtMlor, R_iho, RtMlorR);
RtMlorR_inv.Factor();
RtMlorR_inv.Mult(RtMlor, P_iho);
}
}
@@ -473,8 +462,6 @@ void L2ProjectionGridTransfer::L2ProjectionL2Space::MultTranspose(
void L2ProjectionGridTransfer::L2ProjectionL2Space::Prolongate(
const Vector &x, Vector &y) const
{
if (fes_ho.GetNE() == 0) { return; }
MFEM_VERIFY(P.Size() > 0, "Prolongation not supported for these spaces.")
int vdim = fes_ho.GetVDim();
Array<int> vdofs;
DenseMatrix xel_mat,yel_mat;
@@ -510,8 +497,6 @@ void L2ProjectionGridTransfer::L2ProjectionL2Space::Prolongate(
void L2ProjectionGridTransfer::L2ProjectionL2Space::ProlongateTranspose(
const Vector &x, Vector &y) const
{
if (fes_ho.GetNE() == 0) { return; }
MFEM_VERIFY(P.Size() > 0, "Prolongation not supported for these spaces.")
int vdim = fes_ho.GetVDim();
Array<int> vdofs;
DenseMatrix xel_mat,yel_mat;
@@ -913,11 +898,6 @@ void L2ProjectionGridTransfer::BuildF()
}
}
bool L2ProjectionGridTransfer::SupportsBackwardsOperator() const
{
return ran_fes.GetTrueVSize() >= dom_fes.GetTrueVSize();
}
TransferOperator::TransferOperator(const FiniteElementSpace& lFESpace_,
const FiniteElementSpace& hFESpace_)
-4
View File
@@ -98,8 +98,6 @@ public:
{
return MakeTrueOperator(ran_fes, dom_fes, BackwardOperator(), bw_t_oper);
}
virtual bool SupportsBackwardsOperator() const { return true; }
};
@@ -348,8 +346,6 @@ public:
virtual const Operator &ForwardOperator();
virtual const Operator &BackwardOperator();
virtual bool SupportsBackwardsOperator() const;
private:
void BuildF();
};
-3
View File
@@ -92,9 +92,6 @@ public:
template <typename CT, int N>
explicit inline Array(const CT (&values)[N]);
/// Move constructor ("steals" data from 'src')
inline Array(Array<T> &&src) { Swap(src, *this); }
/// Destructor
inline ~Array() { TypeAssert(); data.Delete(); }
+1 -1
View File
@@ -65,7 +65,7 @@
// 'double' atomicAdd implementation for previous versions of CUDA
#if defined(MFEM_USE_CUDA) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600
MFEM_DEVICE inline double atomicAdd(double *add, double val)
MFEM_DEVICE double atomicAdd(double *add, double val)
{
unsigned long long int *ptr = (unsigned long long int *) add;
unsigned long long int old = *ptr, reg;
+12 -12
View File
@@ -786,7 +786,7 @@ void *MemoryManager::New_(void *h_tmp, size_t bytes, MemoryType h_mt,
void *h_ptr;
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 |
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
@@ -820,7 +820,7 @@ void *MemoryManager::Register_(void *ptr, void *h_tmp, size_t bytes,
return nullptr;
}
flags |= Mem::Registered | Mem::OWNS_INTERNAL;
flags |= Mem::REGISTERED | Mem::OWNS_INTERNAL;
void *h_ptr;
if (is_host_mem) // HOST TYPES + MANAGED
@@ -859,7 +859,7 @@ void MemoryManager::Register2_(void *h_ptr, void *d_ptr, size_t bytes,
return;
}
flags |= Mem::Registered | Mem::OWNS_INTERNAL;
flags |= Mem::REGISTERED | Mem::OWNS_INTERNAL;
MFEM_VERIFY(d_ptr || bytes == 0,
"cannot register NULL device pointer with bytes = " << bytes);
@@ -911,7 +911,7 @@ void MemoryManager::SetDeviceMemoryType_(void *h_ptr, unsigned flags,
void MemoryManager::Delete_(void *h_ptr, MemoryType h_mt, unsigned flags)
{
const bool alias = flags & Mem::ALIAS;
const bool registered = flags & Mem::Registered;
const bool registered = flags & Mem::REGISTERED;
const bool owns_host = flags & Mem::OWNS_HOST;
const bool owns_device = flags & Mem::OWNS_DEVICE;
const bool owns_internal = flags & Mem::OWNS_INTERNAL;
@@ -1018,7 +1018,7 @@ void *MemoryManager::ReadWrite_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
size_t bytes, unsigned &flags)
{
if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
if (bytes > 0) { MFEM_VERIFY(flags & Mem::Registered,""); }
if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,""); }
MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),"");
if (IsHostMemory(GetMemoryType(mc)) && mc < MemoryClass::DEVICE)
{
@@ -1042,7 +1042,7 @@ const void *MemoryManager::Read_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
size_t bytes, unsigned &flags)
{
if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
if (bytes > 0) { MFEM_VERIFY(flags & Mem::Registered,""); }
if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,""); }
MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),"");
if (IsHostMemory(GetMemoryType(mc)) && mc < MemoryClass::DEVICE)
{
@@ -1066,7 +1066,7 @@ void *MemoryManager::Write_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
size_t bytes, unsigned &flags)
{
if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
if (bytes > 0) { MFEM_VERIFY(flags & Mem::Registered,""); }
if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,""); }
MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),"");
if (IsHostMemory(GetMemoryType(mc)) && mc < MemoryClass::DEVICE)
{
@@ -1088,8 +1088,8 @@ void MemoryManager::SyncAlias_(const void *base_h_ptr, void *alias_h_ptr,
size_t alias_bytes, unsigned base_flags,
unsigned &alias_flags)
{
// This is called only when (base_flags & Mem::Registered) is true.
// Note that (alias_flags & Registered) may not be true.
// This is called only when (base_flags & Mem::REGISTERED) is true.
// Note that (alias_flags & REGISTERED) may not be true.
MFEM_ASSERT(alias_flags & Mem::ALIAS, "not an alias");
if ((base_flags & Mem::VALID_HOST) && !(alias_flags & Mem::VALID_HOST))
{
@@ -1097,10 +1097,10 @@ void MemoryManager::SyncAlias_(const void *base_h_ptr, void *alias_h_ptr,
}
if ((base_flags & Mem::VALID_DEVICE) && !(alias_flags & Mem::VALID_DEVICE))
{
if (!(alias_flags & Mem::Registered))
if (!(alias_flags & Mem::REGISTERED))
{
mm.InsertAlias(base_h_ptr, alias_h_ptr, alias_bytes, base_flags & Mem::ALIAS);
alias_flags = (alias_flags | Mem::Registered | Mem::OWNS_INTERNAL) &
alias_flags = (alias_flags | Mem::REGISTERED | Mem::OWNS_INTERNAL) &
~(Mem::OWNS_HOST | Mem::OWNS_DEVICE);
}
mm.GetAliasDevicePtr(alias_h_ptr, alias_bytes, true);
@@ -1671,7 +1671,7 @@ void MemoryPrintFlags(unsigned flags)
{
typedef Memory<int> Mem;
mfem::out
<< "\n registered = " << bool(flags & Mem::Registered)
<< "\n registered = " << bool(flags & Mem::REGISTERED)
<< "\n owns host = " << bool(flags & Mem::OWNS_HOST)
<< "\n owns device = " << bool(flags & Mem::OWNS_DEVICE)
<< "\n owns internal = " << bool(flags & Mem::OWNS_INTERNAL)
+15 -25
View File
@@ -165,16 +165,8 @@ protected:
enum FlagMask: unsigned
{
// Workaround for use with headers that define REGISTERED as a macro,
// e.g. nb30.h (which is included by Windows.h):
#ifndef REGISTERED
REGISTERED = 1 << 0, /**< The host pointer is registered with the
MemoryManager */
#endif
// Use the following identifier if REGISTERED is defined as a macro,
// e.g. nb30.h (which is included by Windows.h):
Registered = 1 << 0, /**< The host pointer is registered with the
MemoryManager */
OWNS_HOST = 1 << 1, ///< The host pointer will be deleted by Delete()
OWNS_DEVICE = 1 << 2, /**< The device pointer will be deleted by
Delete() */
@@ -219,8 +211,6 @@ public:
validity flags of @a *this to those of @a other. Resets @a other. */
Memory &operator=(Memory &&orig)
{
// Guard self-assignment:
if (this == &orig) { return *this; }
*this = orig;
orig.Reset();
return *this;
@@ -982,7 +972,7 @@ inline void Memory<T>::MakeAlias(const Memory &base, int offset, int size)
capacity = size;
h_mt = base.h_mt;
h_ptr = base.h_ptr + offset;
if (!(base.flags & Registered))
if (!(base.flags & REGISTERED))
{
if (
#if !defined(HYPRE_USING_GPU)
@@ -1018,7 +1008,7 @@ template <typename T>
inline void Memory<T>::SetDeviceMemoryType(MemoryType d_mt)
{
if (!IsDeviceMemory(d_mt)) { return; }
if (!(flags & Registered))
if (!(flags & REGISTERED))
{
MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
flags & OWNS_HOST, flags & ALIAS, flags);
@@ -1029,7 +1019,7 @@ inline void Memory<T>::SetDeviceMemoryType(MemoryType d_mt)
template <typename T>
inline void Memory<T>::Delete()
{
const bool registered = flags & Registered;
const bool registered = flags & REGISTERED;
const bool mt_host = h_mt == MemoryType::HOST;
const bool std_delete = !registered && mt_host;
@@ -1048,7 +1038,7 @@ inline void Memory<T>::Delete()
template <typename T>
inline void Memory<T>::DeleteDevice(bool copy_to_host)
{
if (flags & Registered)
if (flags & REGISTERED)
{
if (copy_to_host) { Read(MemoryClass::HOST, capacity); }
MemoryManager::DeleteDevice_((void*)h_ptr, flags);
@@ -1108,7 +1098,7 @@ template <typename T>
inline T *Memory<T>::ReadWrite(MemoryClass mc, int size)
{
const size_t bytes = size * sizeof(T);
if (!(flags & Registered))
if (!(flags & REGISTERED))
{
if (mc == MemoryClass::HOST) { return h_ptr; }
MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
@@ -1121,7 +1111,7 @@ template <typename T>
inline const T *Memory<T>::Read(MemoryClass mc, int size) const
{
const size_t bytes = size * sizeof(T);
if (!(flags & Registered))
if (!(flags & REGISTERED))
{
if (mc == MemoryClass::HOST) { return h_ptr; }
MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
@@ -1134,7 +1124,7 @@ template <typename T>
inline T *Memory<T>::Write(MemoryClass mc, int size)
{
const size_t bytes = size * sizeof(T);
if (!(flags & Registered))
if (!(flags & REGISTERED))
{
if (mc == MemoryClass::HOST) { return h_ptr; }
MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
@@ -1146,12 +1136,12 @@ inline T *Memory<T>::Write(MemoryClass mc, int size)
template <typename T>
inline void Memory<T>::Sync(const Memory &other) const
{
if (!(flags & Registered) && (other.flags & Registered))
if (!(flags & REGISTERED) && (other.flags & REGISTERED))
{
MFEM_ASSERT(h_ptr == other.h_ptr &&
(flags & ALIAS) == (other.flags & ALIAS),
"invalid input");
flags = (flags | Registered) & ~(OWNS_DEVICE | OWNS_INTERNAL);
flags = (flags | REGISTERED) & ~(OWNS_DEVICE | OWNS_INTERNAL);
}
flags = (flags & ~(VALID_HOST | VALID_DEVICE)) |
(other.flags & (VALID_HOST | VALID_DEVICE));
@@ -1161,9 +1151,9 @@ template <typename T>
inline void Memory<T>::SyncAlias(const Memory &base, int alias_size) const
{
// Assuming that if *this is registered then base is also registered.
MFEM_ASSERT(!(flags & Registered) || (base.flags & Registered),
MFEM_ASSERT(!(flags & REGISTERED) || (base.flags & REGISTERED),
"invalid base state");
if (!(base.flags & Registered)) { return; }
if (!(base.flags & REGISTERED)) { return; }
MemoryManager::SyncAlias_(base.h_ptr, h_ptr, alias_size*sizeof(T),
base.flags, flags);
}
@@ -1178,7 +1168,7 @@ inline MemoryType Memory<T>::GetMemoryType() const
template <typename T>
inline MemoryType Memory<T>::GetDeviceMemoryType() const
{
if (!(flags & Registered)) { return MemoryType::DEFAULT; }
if (!(flags & REGISTERED)) { return MemoryType::DEFAULT; }
return MemoryManager::GetDeviceMemoryType_(h_ptr, flags & ALIAS);
}
@@ -1198,7 +1188,7 @@ template <typename T>
inline void Memory<T>::CopyFrom(const Memory &src, int size)
{
MFEM_VERIFY(src.capacity>=size && capacity>=size, "Incorrect size");
if (!(flags & Registered) && !(src.flags & Registered))
if (!(flags & REGISTERED) && !(src.flags & REGISTERED))
{
if (h_ptr != src.h_ptr && size != 0)
{
@@ -1218,7 +1208,7 @@ template <typename T>
inline void Memory<T>::CopyFromHost(const T *src, int size)
{
MFEM_VERIFY(capacity>=size, "Incorrect size");
if (!(flags & Registered))
if (!(flags & REGISTERED))
{
if (h_ptr != src && size != 0)
{
@@ -1245,7 +1235,7 @@ template <typename T>
inline void Memory<T>::CopyToHost(T *dest, int size) const
{
MFEM_VERIFY(capacity>=size, "Incorrect size");
if (!(flags & Registered))
if (!(flags & REGISTERED))
{
if (h_ptr != dest && size != 0)
{
-3
View File
@@ -97,9 +97,6 @@ const char *GetConfigStr()
#ifdef MFEM_USE_HIOP
"MFEM_USE_HIOP\n"
#endif
#ifdef MFEM_USE_IPOPT
"MFEM_USE_IPOPT\n"
#endif
#ifdef MFEM_USE_HIP
"MFEM_USE_HIP\n"
#endif
-2
View File
@@ -35,8 +35,6 @@
#ifndef __ZSTR_HPP
#define __ZSTR_HPP
#include "../config/config.hpp"
#include <cassert>
#include <fstream>
#include <sstream>
-3
View File
@@ -111,9 +111,6 @@ public:
virtual void Mult(const Vector &x, Vector &y) const;
virtual void MultTranspose(const Vector &x, Vector &y) const;
using Operator::Mult;
using Operator::MultTranspose;
virtual Type GetType() const { return Complex_Operator; }
Convention GetConvention() const { return convention_; }
-3
View File
@@ -352,7 +352,6 @@ void EliminationSolver::Mult(const Vector& rhs, Vector& sol) const
reducedsol = 0.0;
krylov->Mult(reducedrhs, reducedsol);
final_iter = krylov->GetNumIterations();
initial_norm = krylov->GetInitialNorm();
final_norm = krylov->GetFinalNorm();
converged = krylov->GetConverged();
@@ -486,7 +485,6 @@ void PenaltyConstrainedSolver::Mult(const Vector& b, Vector& x) const
krylov->SetPrintLevel(print_options);
krylov->Mult(penalized_rhs, x);
final_iter = krylov->GetNumIterations();
initial_norm = krylov->GetInitialNorm();
final_norm = krylov->GetFinalNorm();
converged = krylov->GetConverged();
@@ -618,7 +616,6 @@ void SchurConstrainedSolver::LagrangeSystemMult(const Vector& x,
gmres->Mult(x, y);
final_iter = gmres->GetNumIterations();
converged = gmres->GetConverged();
initial_norm = gmres->GetInitialNorm();
final_norm = gmres->GetFinalNorm();
delete gmres;
}
+2 -13
View File
@@ -249,13 +249,8 @@ void DenseMatrix::MultTranspose(const Vector &x, Vector &y) const
MultTranspose(x.GetData(), y.GetData());
}
void DenseMatrix::AddMult(const Vector &x, Vector &y, const double a) const
void DenseMatrix::AddMult(const Vector &x, Vector &y) const
{
if (a != 1.0)
{
AddMult_a(a, x, y);
return;
}
MFEM_ASSERT(height == y.Size() && width == x.Size(),
"incompatible dimensions");
@@ -272,14 +267,8 @@ void DenseMatrix::AddMult(const Vector &x, Vector &y, const double a) const
}
}
void DenseMatrix::AddMultTranspose(const Vector &x, Vector &y,
const double a) const
void DenseMatrix::AddMultTranspose(const Vector &x, Vector &y) const
{
if (a != 1.0)
{
AddMultTranspose_a(a, x, y);
return;
}
MFEM_ASSERT(height == x.Size() && width == y.Size(),
"incompatible dimensions");
+4 -10
View File
@@ -162,15 +162,11 @@ public:
/// Multiply a vector with the transpose matrix.
virtual void MultTranspose(const Vector &x, Vector &y) const;
using Operator::Mult;
using Operator::MultTranspose;
/// y += A.x
void AddMult(const Vector &x, Vector &y) const;
/// y += a * A.x
virtual void AddMult(const Vector &x, Vector &y, const double a = 1.0) const;
/// y += a * A^t x
virtual void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const;
/// y += A^t x
void AddMultTranspose(const Vector &x, Vector &y) const;
/// y += a * A.x
void AddMult_a(double a, const Vector &x, Vector &y) const;
@@ -862,8 +858,6 @@ public:
/// Multiply the inverse matrix by another matrix: X <- A^{-1} X.
void Mult(DenseMatrix &X) const {factors->Solve(width, X.Width(), X.Data());}
using Operator::Mult;
/// Compute and return the inverse matrix in Ainv.
void GetInverseMatrix(DenseMatrix &Ainv) const;
+5 -6
View File
@@ -292,14 +292,13 @@ HypreParVector& HypreParVector::operator=(const HypreParVector &y)
HypreParVector& HypreParVector::operator=(HypreParVector &&y)
{
Vector::operator=(std::move(y));
// Self-assignment-safe way to move for 'own_ParVector' and 'x':
const auto own_tmp = y.own_ParVector;
// If the argument vector owns its data, then the calling vector will as well
WrapHypreParVector(static_cast<hypre_ParVector*>(y), y.own_ParVector);
// Either way the argument vector will no longer own its data
y.own_ParVector = 0;
own_ParVector = own_tmp;
const auto x_tmp = y.x;
y.x = nullptr;
x = x_tmp;
y.data.Reset();
y.size = 0;
return *this;
}
+4 -15
View File
@@ -599,7 +599,7 @@ public:
void MergeDiagAndOffd(SparseMatrix &merged);
/// Return the diagonal of the matrix (Operator interface).
void AssembleDiagonal(Vector &diag) const override { GetDiag(diag); }
virtual void AssembleDiagonal(Vector &diag) const { GetDiag(diag); }
/** Split the matrix into M x N equally sized blocks of parallel matrices.
The size of 'blocks' must already be set to M x N. */
@@ -649,7 +649,7 @@ public:
partitioning array. */
HYPRE_BigInt *GetColStarts() const { return hypre_ParCSRMatrixColStarts(A); }
MemoryClass GetMemoryClass() const override { return GetHypreMemoryClass(); }
virtual MemoryClass GetMemoryClass() const { return GetHypreMemoryClass(); }
/// Ensure the action of the transpose is performed fast.
/** When HYPRE is built for GPUs, this method will construct and store the
@@ -691,25 +691,16 @@ public:
transpose. */
void MultTranspose(double a, const Vector &x, double b, Vector &y) const;
void Mult(const Vector &x, Vector &y) const override
virtual void Mult(const Vector &x, Vector &y) const
{ Mult(1.0, x, 0.0, y); }
/// Computes y = A^t * x
/** If the matrix is modified, call ResetTranspose() and optionally
EnsureMultTranspose() to make sure this method uses the correct updated
transpose. */
void MultTranspose(const Vector &x, Vector &y) const override
virtual void MultTranspose(const Vector &x, Vector &y) const
{ MultTranspose(1.0, x, 0.0, y); }
void AddMult(const Vector &x, Vector &y, const double a = 1.0) const override
{ Mult(a, x, 1.0, y); }
void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const override
{ MultTranspose(a, x, 1.0, y); }
using Operator::Mult;
using Operator::MultTranspose;
/** @brief Computes y = a * |A| * x + b * y, using entry-wise absolute values
of the matrix A. */
void AbsMult(double a, const Vector &x, double b, Vector &y) const;
@@ -1089,7 +1080,6 @@ public:
/// Relax the linear system Ax=b
virtual void Mult(const HypreParVector &b, HypreParVector &x) const;
virtual void Mult(const Vector &b, Vector &x) const;
using Operator::Mult;
/// Apply transpose of the smoother to relax the linear system Ax=b
virtual void MultTranspose(const Vector &b, Vector &x) const;
@@ -1166,7 +1156,6 @@ public:
virtual void Mult(const HypreParVector &b, HypreParVector &x) const;
/// Solve the linear system Ax=b
virtual void Mult(const Vector &b, Vector &x) const;
using Operator::Mult;
///@}
-63
View File
@@ -48,69 +48,6 @@ void Operator::InitTVectors(const Operator *Po, const Operator *Ri,
}
}
void Operator::AddMult(const Vector &x, Vector &y, const double a) const
{
mfem::Vector z(y.Size());
Mult(x, z);
y.Add(a, z);
}
void Operator::AddMultTranspose(const Vector &x, Vector &y,
const double a) const
{
mfem::Vector z(y.Size());
MultTranspose(x, z);
y.Add(a, z);
}
void Operator::ArrayMult(const Array<const Vector *> &X,
Array<Vector *> &Y) const
{
MFEM_ASSERT(X.Size() == Y.Size(),
"Number of columns mismatch in Operator::Mult!");
for (int i = 0; i < X.Size(); i++)
{
MFEM_ASSERT(X[i] && Y[i], "Missing Vector in Operator::Mult!");
Mult(*X[i], *Y[i]);
}
}
void Operator::ArrayMultTranspose(const Array<const Vector *> &X,
Array<Vector *> &Y) const
{
MFEM_ASSERT(X.Size() == Y.Size(),
"Number of columns mismatch in Operator::MultTranspose!");
for (int i = 0; i < X.Size(); i++)
{
MFEM_ASSERT(X[i] && Y[i], "Missing Vector in Operator::MultTranspose!");
MultTranspose(*X[i], *Y[i]);
}
}
void Operator::ArrayAddMult(const Array<const Vector *> &X, Array<Vector *> &Y,
const double a) const
{
MFEM_ASSERT(X.Size() == Y.Size(),
"Number of columns mismatch in Operator::AddMult!");
for (int i = 0; i < X.Size(); i++)
{
MFEM_ASSERT(X[i] && Y[i], "Missing Vector in Operator::AddMult!");
AddMult(*X[i], *Y[i], a);
}
}
void Operator::ArrayAddMultTranspose(const Array<const Vector *> &X,
Array<Vector *> &Y, const double a) const
{
MFEM_ASSERT(X.Size() == Y.Size(),
"Number of columns mismatch in Operator::AddMultTranspose!");
for (int i = 0; i < X.Size(); i++)
{
MFEM_ASSERT(X[i] && Y[i], "Missing Vector in Operator::AddMultTranspose!");
AddMultTranspose(*X[i], *Y[i], a);
}
}
void Operator::FormLinearSystem(const Array<int> &ess_tdof_list,
Vector &x, Vector &b,
Operator* &Aout, Vector &X, Vector &B,
+4 -31
View File
@@ -53,7 +53,8 @@ public:
/// Initializes memory for true vectors of linear system
void InitTVectors(const Operator *Po, const Operator *Ri, const Operator *Pi,
Vector &x, Vector &b, Vector &X, Vector &B) const;
Vector &x, Vector &b,
Vector &X, Vector &B) const;
/// Construct a square Operator with given size s (default 0).
explicit Operator(int s = 0) { height = width = s; }
@@ -91,37 +92,13 @@ public:
/** @brief Action of the transpose operator: `y=A^t(x)`. The default behavior
in class Operator is to generate an error. */
virtual void MultTranspose(const Vector &x, Vector &y) const
{ mfem_error("Operator::MultTranspose() is not overridden!"); }
/// Operator application: `y+=A(x)` (default) or `y+=a*A(x)`.
virtual void AddMult(const Vector &x, Vector &y, const double a = 1.0) const;
/// Operator transpose application: `y+=A^t(x)` (default) or `y+=a*A^t(x)`.
virtual void AddMultTranspose(const Vector &x, Vector &y,
const double a = 1.0) const;
/// Operator application on a matrix: `Y=A(X)`.
virtual void ArrayMult(const Array<const Vector *> &X,
Array<Vector *> &Y) const;
/// Action of the transpose operator on a matrix: `Y=A^t(X)`.
virtual void ArrayMultTranspose(const Array<const Vector *> &X,
Array<Vector *> &Y) const;
/// Operator application on a matrix: `Y+=A(X)` (default) or `Y+=a*A(X)`.
virtual void ArrayAddMult(const Array<const Vector *> &X, Array<Vector *> &Y,
const double a = 1.0) const;
/** @brief Operator transpose application on a matrix: `Y+=A^t(X)` (default)
or `Y+=a*A^t(X)`. */
virtual void ArrayAddMultTranspose(const Array<const Vector *> &X,
Array<Vector *> &Y, const double a = 1.0) const;
{ mfem_error("Operator::MultTranspose() is not overloaded!"); }
/** @brief Evaluate the gradient operator at the point @a x. The default
behavior in class Operator is to generate an error. */
virtual Operator &GetGradient(const Vector &x) const
{
mfem_error("Operator::GetGradient() is not overridden!");
mfem_error("Operator::GetGradient() is not overloaded!");
return const_cast<Operator &>(*this);
}
@@ -137,24 +114,20 @@ public:
/** @brief Prolongation operator from linear algebra (linear system) vectors,
to input vectors for the operator. `NULL` means identity. */
virtual const Operator *GetProlongation() const { return NULL; }
/** @brief Restriction operator from input vectors for the operator to linear
algebra (linear system) vectors. `NULL` means identity. */
virtual const Operator *GetRestriction() const { return NULL; }
/** @brief Prolongation operator from linear algebra (linear system) vectors,
to output vectors for the operator. `NULL` means identity. */
virtual const Operator *GetOutputProlongation() const
{
return GetProlongation(); // Assume square unless specialized
}
/** @brief Transpose of GetOutputRestriction, directly available in this
form to facilitate matrix-free RAP-type operators.
`NULL` means identity. */
virtual const Operator *GetOutputRestrictionTranspose() const { return NULL; }
/** @brief Restriction operator from output vectors for the operator to linear
algebra (linear system) vectors. `NULL` means identity. */
virtual const Operator *GetOutputRestriction() const

Some files were not shown because too many files have changed in this diff Show More