Compare commits

..
Author SHA1 Message Date
Will Pazner a7c92ac238 RZ example with Robin conditions 2023-10-09 14:57:28 -07:00
Will Pazner 2462e7d591 Add check using IsIdentityProlongation 2023-04-03 15:24:08 -07:00
Will Pazner d80e3d796b Fix issue in grad-div mode with map type VALUE 2023-04-03 15:21:47 -07:00
Will Pazner cdacbfb827 Add rz coordinate Darcy example 2023-03-15 13:00:13 -07:00
Will Pazner 9bcd366d28 Add Robin condition to Darcy example 2023-03-14 15:18:36 -07:00
Will Pazner 957109fe78 Add support for Robin-type conditions
Temporarily this means disabling partial assembly for the RT mass term.

The PA functionality is implemented in PR #3539.
2023-03-14 15:18:20 -07:00
Will Pazner 789a8dea13 Don't require SetBC on partitions with no boundary DOFs 2023-03-08 21:02:56 -08:00
Will Pazner 2aa41a06dc Fix parallel bug in HdivSaddlePointSolver::EliminateBC 2023-03-08 16:56:05 -08:00
Will Pazner 4ea8e8a208 Make sure to reset size of intermediate vector
HdivSaddlePointSolver::EliminateBC was resizing the temporary vector z. When no
basis change is required, the line

basis_l2.Mult(z, xE);

would set xE = z. If z had the wrong size, this would resize xE. But xE needed
to be an alias (view) into the global x vector, so this was a bug.
2023-03-07 16:05:59 -08:00
Will Pazner 67b7caeb2c Properly handle map type VALUE in Darcy solver
The diagonal L_diag_unweighted (added to the approximate Schur complement) needs
to incorporate the mesh Jacobian determinant.
2023-03-07 16:04:07 -08:00
Will Pazner 908e025f7a Use less oscillatory coefficients in residual example 2023-02-25 16:01:38 -08:00
Will Pazner fd6363cd57 Fix degraded convergence in grad-div mode 2023-02-25 15:54:05 -08:00
Will Pazner aec5511c7c Improve the H(div) solver residual example 2023-02-25 15:48:12 -08:00
Will Pazner d7e9c426e7 Add H(div) solver residual example 2023-02-25 15:34:31 -08:00
Will Pazner 2a6153c640 Improve conversion from map type VALUE to INTEGRAL 2023-02-25 15:25:56 -08:00
Will Pazner 8fbcda2419 Support map type VALUE in H(div) saddle-point solver 2023-02-17 14:06:43 -08:00
Will Pazner a21d9b4895 Support non-nodal basis types in ChangeOfBasis_RT 2023-02-07 14:45:08 -08:00
Will Pazner 4a0a0e9d25 Handle non-nodal basis in ChangeOfBasis_L2 2023-02-07 14:29:49 -08:00
Will Pazner da802fc1ca Construct diagonal matrix directly on device 2023-01-31 16:55:36 -08:00
Will Pazner 968858dec2 Better handle variable L2 coefficients in Darcy mode HdivSaddlePointSolver 2023-01-27 12:45:06 -08:00
Will Pazner 65b6aa3a86 Add DGMassInverse::MultTranspose 2023-01-27 12:16:07 -08:00
Will Pazner d41f5d8f04 Improve HdivSaddlePointSolver comments 2023-01-26 20:46:24 -08:00
Will Pazner 227a3c2c98 Add H(div) saddle-point solver miniapps
Included are grad-div and Darcy/Poisson miniapps.
2023-01-26 19:19:11 -08:00
Will Pazner 7a7355643a Parameterize lor_mms coefficients using std::function 2023-01-26 19:17:36 -08:00
Will Pazner 6d58074dd4 Make ElementRestriction low-level array accessors public 2023-01-26 19:17:15 -08:00
110 changed files with 3077 additions and 8296 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.
+6 -9
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
@@ -226,7 +219,6 @@ 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 +278,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
@@ -316,6 +307,12 @@ miniapps/solvers/ParaView
miniapps/solvers/mesh.*
miniapps/solvers/sol.*
miniapps/hdiv-linear-solver/darcy
miniapps/hdiv-linear-solver/grad_div
miniapps/hdiv-linear-solver/residual
miniapps/hdiv-linear-solver/rz
miniapps/hdiv-linear-solver/ParaView
miniapps/parelag/MultilevelHcurlHdivSolver
miniapps/parelag/*.mesh
+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 "------------------------------"
-17
View File
@@ -10,23 +10,12 @@
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
@@ -38,9 +27,6 @@ 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.
@@ -116,9 +102,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.
+3 -11
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)
-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
-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@
-5
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")
-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
-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);
}
};
+2 -2
View File
@@ -111,7 +111,7 @@ DataCollection::DataCollection(const std::string& collection_name, Mesh *mesh_)
pad_digits_cycle = pad_digits_rank = pad_digits_default;
format = SERIAL_FORMAT; // use serial mesh format
compression = 0;
error = No_Error;
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) +
+2 -14
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;
+2
View File
@@ -87,6 +87,8 @@ public:
///
/// If @ref iterative_mode is @a true, @a u is used as an initial guess.
void Mult(const Vector &b, Vector &u) const;
/// Same as Mult() since the mass matrix is symmetric.
void MultTranspose(const Vector &b, Vector &u) const { Mult(b, u); }
/// Not implemented. Aborts.
void SetOperator(const Operator &op);
/// Set the relative tolerance.
+219 -220
View File
@@ -36,19 +36,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 +97,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 +122,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 +137,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 +239,7 @@ void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans,
}
}
// Assume a linear mapping
void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
Vector &Laplacian) const
@@ -249,7 +250,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 +283,7 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
Laplacian[nd] += hess(nd,ii)*scale[ii];
}
}
}
void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
@@ -361,128 +363,11 @@ 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");
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;
MFEM_ABORT("method is not implemented for this element");
return *dof2quad_array[0]; // suppress a warning
}
FiniteElement::~FiniteElement()
@@ -494,19 +379,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 +398,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 +422,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 +456,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 +472,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 +494,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 +631,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 +641,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 +653,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 +662,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 +670,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 +849,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 +900,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 +912,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 +2402,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,
@@ -2518,7 +2436,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 +2452,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++)
+81 -68
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. */
@@ -575,7 +579,6 @@ public:
/** See the documentation for DofToQuad for more details. */
virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode) const;
/// Deconstruct the FiniteElement
virtual ~FiniteElement();
@@ -622,11 +625,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 +642,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 +656,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 +674,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 +695,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 +725,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 +790,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 +954,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 +1179,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 +1203,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 +1235,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 +1245,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())
{
@@ -1257,7 +1276,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 +1289,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); }
};
+15 -15
View File
@@ -321,9 +321,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 +331,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 +407,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);
@@ -665,16 +665,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 +724,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);
-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);
}
};
+15 -15
View File
@@ -152,16 +152,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 +209,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);
@@ -482,9 +482,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 +492,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 +568,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);
+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.
+7 -9
View File
@@ -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;
+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. */
+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;
+2 -5
View File
@@ -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());
+7 -11
View File
@@ -53,17 +53,6 @@ protected:
Array<int> indices;
Array<int> gather_map;
friend class BatchedLORAssembly;
friend class BatchedLOR_ADS;
friend class BatchedLOR_AMS;
/// @name Low-level access to the underlying element-dof mappings
///@{
const Array<int> &GatherMap() const { return gather_map; }
const Array<int> &Indices() const { return indices; }
const Array<int> &Offsets() const { return offsets; }
///@}
public:
ElementRestriction(const FiniteElementSpace&, ElementDofOrdering);
void Mult(const Vector &x, Vector &y) const override;
@@ -102,6 +91,13 @@ 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;
/// @name Low-level access to the underlying element-dof mappings
///@{
const Array<int> &GatherMap() const { return gather_map; }
const Array<int> &Indices() const { return indices; }
const Array<int> &Offsets() const { return offsets; }
///@}
};
/// Operator that converts L2 FiniteElementSpace L-vectors to E-vectors.
+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();
};
+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
-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;
}
+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;
}
+7 -10
View File
@@ -583,7 +583,6 @@ void SLISolver::Mult(const Vector &b, Vector &x) const
{
nom0 = nom = sqrt(Dot(r, r));
}
initial_norm = nom0;
if (print_options.iterations | print_options.first_and_last)
{
@@ -736,7 +735,6 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
d = r;
}
nom0 = nom = Dot(d, r);
if (nom0 >= 0.0) { initial_norm = sqrt(nom0); }
MFEM_ASSERT(IsFinite(nom), "nom = " << nom);
if (print_options.iterations || print_options.first_and_last)
{
@@ -754,7 +752,6 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
}
converged = false;
final_iter = 0;
initial_norm = nom;
final_norm = nom;
return;
}
@@ -1018,7 +1015,7 @@ void GMRESSolver::Mult(const Vector &b, Vector &x) const
r = b;
}
}
double beta = initial_norm = Norm(r); // beta = ||r||
double beta = Norm(r); // beta = ||r||
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
final_norm = std::max(rel_tol*beta, abs_tol);
@@ -1178,7 +1175,7 @@ void FGMRESSolver::Mult(const Vector &b, Vector &x) const
x = 0.;
r = b;
}
double beta = initial_norm = Norm(r); // beta = ||r||
double beta = Norm(r); // beta = ||r||
// We need to preallocate this to report the correct result in the case of
// no convergence.
double resid;
@@ -1394,7 +1391,7 @@ void BiCGSTABSolver::Mult(const Vector &b, Vector &x) const
}
rtilde = r;
resid = initial_norm = Norm(r);
resid = Norm(r);
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
if (print_options.iterations || print_options.first_and_last)
{
@@ -1641,7 +1638,7 @@ void MINRESSolver::Mult(const Vector &b, Vector &x) const
{
prec->Mult(v1, u1);
}
eta = beta = initial_norm = sqrt(Dot(*z, v1));
eta = beta = sqrt(Dot(*z, v1));
MFEM_ASSERT(IsFinite(eta), "eta = " << eta);
gamma0 = gamma1 = 1.;
sigma0 = sigma1 = 0.;
@@ -1836,7 +1833,7 @@ void NewtonSolver::Mult(const Vector &b, Vector &x) const
r -= b;
}
norm0 = norm = initial_norm = Norm(r);
norm0 = norm = Norm(r);
if (print_options.first_and_last && !print_options.iterations)
{
mfem::out << "Newton iteration " << setw(2) << 0
@@ -2034,7 +2031,7 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const
c = r; // initial descent direction
norm0 = norm = initial_norm = Norm(r);
norm0 = norm = Norm(r);
if (print_options.first_and_last && !print_options.iterations)
{
mfem::out << "LBFGS iteration " << setw(2) << 0
@@ -2407,7 +2404,7 @@ void SLBQPOptimizer::Mult(const Vector& xt, Vector& x) const
}
// Solve QP with fixed Lagrange multiplier
r = initial_norm = solve(l,xt,x,nclip);
r = solve(l,xt,x,nclip);
print_iteration(nclip, r, l);
+4 -32
View File
@@ -159,12 +159,11 @@ protected:
///@}
/// @name Solver statistics (protected attributes)
/// Every IterativeSolver is expected to define these in its Mult() call.
///@{
mutable int final_iter = -1;
mutable bool converged = false;
mutable double initial_norm = -1.0, final_norm = -1.0;
mutable int final_iter;
mutable bool converged;
mutable double final_norm;
///@}
@@ -242,38 +241,11 @@ public:
virtual void SetPrintLevel(PrintLevel);
///@}
/// @name Solver statistics.
/// These are valid after the call to Mult().
/// @name Solver statistics
///@{
/// Returns the number of iterations taken during the last call to Mult()
int GetNumIterations() const { return final_iter; }
/// Returns true if the last call to Mult() converged successfully.
bool GetConverged() const { return converged; }
/// @brief Returns the initial residual norm from the last call to Mult().
///
/// This function returns the norm of the residual (or preconditioned
/// residual, depending on the solver), computed before the start of the
/// iteration.
double GetInitialNorm() const { return initial_norm; }
/// @brief Returns the final residual norm after termination of the solver
/// during the last call to Mult().
///
/// This function returns the norm of the residual (or preconditioned
/// residual, depending on the solver), corresponding to the returned
/// solution.
double GetFinalNorm() const { return final_norm; }
/// @brief Returns the final residual norm after termination of the solver
/// during the last call to Mult(), divided by the initial residual norm.
/// Returns -1 if one of these norms is left undefined by the solver.
///
/// @sa GetFinalNorm(), GetInitialNorm()
double GetFinalRelNorm() const
{
if (final_norm < 0.0 || initial_norm < 0.0) { return -1.0; }
return final_norm / initial_norm;
}
///@}
/// This should be called before SetOperator
+5 -6
View File
@@ -149,10 +149,9 @@ Vector &Vector::operator=(const Vector &v)
Vector &Vector::operator=(Vector &&v)
{
data = std::move(v.data);
// Self-assignment-safe way to move v.size to size:
const auto size_tmp = v.size;
size = v.size;
v.data.Reset();
v.size = 0;
size = size_tmp;
return *this;
}
@@ -594,7 +593,7 @@ void Vector::SetSubVector(const Array<int> &dofs, const double value)
void Vector::SetSubVector(const Array<int> &dofs, const Vector &elemvect)
{
MFEM_ASSERT(dofs.Size() <= elemvect.Size(),
MFEM_ASSERT(dofs.Size() == elemvect.Size(),
"Size mismatch: length of dofs is " << dofs.Size()
<< ", length of elemvect is " << elemvect.Size());
@@ -639,7 +638,7 @@ void Vector::SetSubVector(const Array<int> &dofs, double *elem_data)
void Vector::AddElementVector(const Array<int> &dofs, const Vector &elemvect)
{
MFEM_ASSERT(dofs.Size() <= elemvect.Size(), "Size mismatch: "
MFEM_ASSERT(dofs.Size() == elemvect.Size(), "Size mismatch: "
"length of dofs is " << dofs.Size() <<
", length of elemvect is " << elemvect.Size());
@@ -683,7 +682,7 @@ void Vector::AddElementVector(const Array<int> &dofs, double *elem_data)
void Vector::AddElementVector(const Array<int> &dofs, const double a,
const Vector &elemvect)
{
MFEM_ASSERT(dofs.Size() <= elemvect.Size(), "Size mismatch: "
MFEM_ASSERT(dofs.Size() == elemvect.Size(), "Size mismatch: "
"length of dofs is " << dofs.Size() <<
", length of elemvect is " << elemvect.Size());
+3 -4
View File
@@ -119,7 +119,7 @@ $(if $(word 2,$(SRC)),$(error Spaces in SRC = "$(SRC)" are not supported))
MFEM_GIT_STRING = $(shell [ -d $(MFEM_DIR)/.git ] && git -C $(MFEM_DIR) \
describe --all --long --abbrev=40 --dirty --always 2> /dev/null)
EXAMPLE_SUBDIRS = amgx caliper ginkgo hiop ipopt petsc pumi sundials superlu moonolith
EXAMPLE_SUBDIRS = amgx caliper ginkgo hiop petsc pumi sundials superlu moonolith
EXAMPLE_DIRS := examples $(addprefix examples/,$(EXAMPLE_SUBDIRS))
EXAMPLE_TEST_DIRS := examples
@@ -275,7 +275,7 @@ endif
# List of MFEM dependencies, that require the *_LIB variable to be non-empty
MFEM_REQ_LIB_DEPS = ENZYME SUPERLU MUMPS METIS FMS CONDUIT SIDRE LAPACK SUNDIALS\
SUITESPARSE STRUMPACK GINKGO GNUTLS NETCDF PETSC SLEPC MPFR PUMI HIOP IPOPT\
SUITESPARSE STRUMPACK GINKGO GNUTLS NETCDF PETSC SLEPC MPFR PUMI HIOP\
GSLIB OCCA CEED RAJA UMPIRE MKL_CPARDISO AMGX CALIPER PARELAG BENCHMARK\
MOONOLITH ALGOIM
@@ -341,7 +341,7 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\
MFEM_USE_SUITESPARSE MFEM_USE_GINKGO MFEM_USE_SUPERLU MFEM_USE_SUPERLU5\
MFEM_USE_STRUMPACK 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_HIP\
MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\
MFEM_USE_OCCA MFEM_USE_MOONOLITH MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE\
MFEM_USE_SIMD MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO MFEM_USE_AMGX\
MFEM_USE_MUMPS MFEM_USE_ADFORWARD MFEM_USE_CODIPACK MFEM_USE_CALIPER\
@@ -690,7 +690,6 @@ status info:
$(info MFEM_USE_CONDUIT = $(MFEM_USE_CONDUIT))
$(info MFEM_USE_PUMI = $(MFEM_USE_PUMI))
$(info MFEM_USE_HIOP = $(MFEM_USE_HIOP))
$(info MFEM_USE_IPOPT = $(MFEM_USE_IPOPT))
$(info MFEM_USE_GSLIB = $(MFEM_USE_GSLIB))
$(info MFEM_USE_CUDA = $(MFEM_USE_CUDA))
$(info MFEM_USE_HIP = $(MFEM_USE_HIP))
+2 -38
View File
@@ -1467,7 +1467,6 @@ void Mesh::InitTables()
{
el_to_edge =
el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
face_to_elem = NULL;
}
void Mesh::SetEmpty()
@@ -1490,9 +1489,6 @@ void Mesh::DestroyTables()
delete face_edge;
delete edge_vertex;
delete face_to_elem;
face_to_elem = NULL;
}
void Mesh::DestroyPointers()
@@ -1554,7 +1550,6 @@ void Mesh::ResetLazyData()
{
delete el_to_el; el_to_el = NULL;
delete face_edge; face_edge = NULL;
delete face_to_elem; face_to_elem = NULL;
delete edge_vertex; edge_vertex = NULL;
DeleteGeometricFactors();
nbInteriorFaces = -1;
@@ -3637,7 +3632,6 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
// Do NOT copy the face-to-edge Table, face_edge
face_edge = NULL;
face_to_elem = NULL;
// Copy the edge-to-vertex Table, edge_vertex
edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
@@ -6181,34 +6175,6 @@ void Mesh::GetElementFaces(int i, Array<int> &el_faces, Array<int> &ori) const
}
}
Array<int> Mesh::FindFaceNeighbors(const int elem) const
{
if (face_to_elem == NULL)
{
face_to_elem = GetFaceToElementTable();
}
Array<int> elem_faces;
Array<int> ori;
GetElementFaces(elem, elem_faces, ori);
Array<int> nghb;
for (auto f : elem_faces)
{
Array<int> row;
face_to_elem->GetRow(f, row);
for (auto r : row)
{
nghb.Append(r);
}
}
nghb.Sort();
nghb.Unique();
return nghb;
}
void Mesh::GetBdrElementFace(int i, int *f, int *o) const
{
const int *bv, *fv;
@@ -9186,9 +9152,8 @@ void Mesh::NonconformingRefinement(const Array<Refinement> &refinements,
double Mesh::AggregateError(const Array<double> &elem_error,
const int *fine, int nfine, int op)
{
double error = elem_error[fine[0]];
for (int i = 1; i < nfine; i++)
double error = 0.0;
for (int i = 0; i < nfine; i++)
{
MFEM_VERIFY(fine[i] < elem_error.Size(), "");
@@ -9352,7 +9317,6 @@ void Mesh::Swap(Mesh& other, bool non_geometry)
mfem::Swap(bel_to_edge, other.bel_to_edge);
mfem::Swap(be_to_face, other.be_to_face);
mfem::Swap(face_edge, other.face_edge);
mfem::Swap(face_to_elem, other.face_to_elem);
mfem::Swap(edge_vertex, other.edge_vertex);
mfem::Swap(attributes, other.attributes);
+22 -60
View File
@@ -223,13 +223,8 @@ protected:
Array<int> be_to_edge; // for 2D
Table *bel_to_edge; // for 3D
Array<int> be_to_face;
// Note that the following tables are owned by this class and should not be
// deleted by the caller. Of these three tables, only face_edge and
// edge_vertex are returned by access functions.
mutable Table *face_to_elem; // Used by FindFaceNeighbors, not returned.
mutable Table *face_edge; // Returned by GetFaceEdgeTable().
mutable Table *edge_vertex; // Returned by GetEdgeVertexTable().
mutable Table *face_edge;
mutable Table *edge_vertex;
IsoparametricTransformation Transformation, Transformation2;
IsoparametricTransformation BdrTransformation;
@@ -1187,10 +1182,6 @@ public:
/// Return the indices and the orientations of all faces of element i.
void GetElementFaces(int i, Array<int> &faces, Array<int> &ori) const;
/** @brief Returns the sorted, unique indices of elements sharing a face with
element @a elem, including @a elem. */
Array<int> FindFaceNeighbors(const int elem) const;
/// Return the index and the orientation of the face of bdr element i. (3D)
void GetBdrElementFace(int i, int *f, int *o) const;
@@ -1235,32 +1226,24 @@ public:
static FiniteElement *GetTransformationFEforElementType(Element::Type);
/// Builds the transformation defining the i-th element in @a ElTr.
/// @a ElTr must be allocated in advance and will be owned by the caller.
/** Builds the transformation defining the i-th element in the user-defined
variable. */
void GetElementTransformation(int i, IsoparametricTransformation *ElTr);
/// Returns a pointer to the transformation defining the i-th element.
/// Note that the pointer is owned by the class and is shared, i.e., calling
/// this function resets pointers obtained from previous calls.
/// Returns the transformation defining the i-th element
ElementTransformation *GetElementTransformation(int i);
/// Builds the transformation defining the i-th element in @a ElTr
/// assuming position of the vertices/nodes are given by @a nodes.
/// @a ElTr must be allocated in advance and will be owned by the caller.
/** Return the transformation defining the i-th element assuming
the position of the vertices/nodes are given by 'nodes'. */
void GetElementTransformation(int i, const Vector &nodes,
IsoparametricTransformation *ElTr);
/// Returns a pointer to the transformation defining the i-th boundary
/// element. Note that the pointer is owned by the class and is shared, i.e.,
/// calling this function resets pointers obtained from previous calls.
ElementTransformation *GetBdrElementTransformation(int i);
/// Builds the transformation defining the i-th boundary element in @a ElTr.
/// @a ElTr must be allocated in advance and will be owned by the caller.
/// Returns the transformation defining the i-th boundary element
ElementTransformation * GetBdrElementTransformation(int i);
void GetBdrElementTransformation(int i, IsoparametricTransformation *ElTr);
/// Builds the transformation defining the i-th face element in @a FTr.
/// @a FTr must be allocated in advance and will be owned by the caller.
/** @brief Returns the transformation defining the given face element in a
user-defined variable. */
void GetFaceTransformation(int i, IsoparametricTransformation *FTr);
/** @brief A helper method that constructs a transformation from the
@@ -1272,18 +1255,14 @@ public:
IsoparametricTransformation &Transf,
int info);
/// Returns a pointer to the transformation defining the given face element.
/// Note that the pointer is owned by the class and is shared, i.e., calling
/// this function resets pointers obtained from previous calls.
/// Returns the transformation defining the given face element
ElementTransformation *GetFaceTransformation(int FaceNo);
/// Builds the transformation defining the i-th edge element in @a EdTr.
/// @a EdTr must be allocated in advance and will be owned by the caller.
/** Returns the transformation defining the given edge element.
The transformation is stored in a user-defined variable. */
void GetEdgeTransformation(int i, IsoparametricTransformation *EdTr);
/// Returns a pointer to the transformation defining the given edge element.
/// Note that the pointer is owned by the class and is shared, i.e., calling
/// this function resets pointers obtained from previous calls.
/// Returns the transformation defining the given face element
ElementTransformation *GetEdgeTransformation(int EdgeNo);
/// Returns (a pointer to an object containing) the following data:
@@ -1316,22 +1295,16 @@ public:
/// mask & 4 - Loc1, mask & 8 - Loc2, mask & 16 - Face.
/// These mask values are defined in the ConfigMasks enum type as part of the
/// FaceElementTransformations class in fem/eltrans.hpp.
///
/// Note that the pointer is owned by the class and is shared, i.e., calling
/// this function resets pointers obtained from previous calls.
virtual FaceElementTransformations *GetFaceElementTransformations(
int FaceNo,
int mask = 31);
/// See GetFaceElementTransformations().
FaceElementTransformations *GetInteriorFaceTransformations (int FaceNo)
{
if (faces_info[FaceNo].Elem2No < 0) { return NULL; }
return GetFaceElementTransformations (FaceNo);
}
/// Builds the transformation defining the given boundary face.
/// The returned pointer is owned by the caller.
FaceElementTransformations *GetBdrFaceTransformations (int BdrElemNo);
/// Return the local face index for the given boundary face.
@@ -1603,10 +1576,6 @@ public:
void SetNodes(const Vector &node_coord);
/// Return a pointer to the internal node GridFunction (may be NULL).
/** If the mesh is straight-sided (low-order), it may not have a GridFunction
for the nodes, in which case this function returns NULL. To ensure that
the nodal GridFunction exists, call EnsureNodes().
@sa SetCurvature(). */
GridFunction *GetNodes() { return Nodes; }
const GridFunction *GetNodes() const { return Nodes; }
/// Return the mesh nodes ownership flag.
@@ -1634,22 +1603,15 @@ public:
/** Return the FiniteElementSpace on which the current mesh nodes are
defined or NULL if the mesh does not have nodes. */
const FiniteElementSpace *GetNodalFESpace() const;
/** @brief Make sure that the mesh has valid nodes, i.e. its geometry is
described by a vector finite element grid function (even if it is a
low-order mesh with straight edges).
@sa GetNodes(). */
/** Make sure that the mesh has valid nodes, i.e. its geometry is described
by a vector finite element grid function (even if it is a low-order mesh
with straight edges). */
void EnsureNodes();
/// Set the curvature of the mesh nodes using the given polynomial degree.
/** Creates a nodal GridFunction if one doesn't already exist.
@param[in] order Polynomial degree of the nodal FE space.
@param[in] discont Whether to use a discontinuous or continuous
finite element space (continuous is default).
@param[in] space_dim The space dimension (optional).
@param[in] ordering The Ordering of the finite element space
(Ordering::byVDIM is the default). */
/** Set the curvature of the mesh nodes using the given polynomial degree,
'order', and optionally: discontinuous or continuous FE space, 'discont',
new space dimension, 'space_dim' (if != -1), and 'ordering' (byVDim by
default). */
virtual void SetCurvature(int order, bool discont = false, int space_dim = -1,
int ordering = 1);
+18 -12
View File
@@ -2107,6 +2107,8 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
}
break;
}
/*
// MFEM does not support pyramids yet
case 7: el_order--; // 5-node pyramid
case 14: el_order--; // 14-node pyramid (2nd order)
case 118: el_order--; // 30-node pyramid (3rd order)
@@ -2119,7 +2121,7 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
{
el_order--; // Gmsh does not define an order 10 pyr
elements_3D.push_back(
new Pyramid(&vert_indices[0], phys_domain));
new Pyramid(&vert_indices[0], phys_domain));
if (el_order > 1)
{
Array<int> * hov = new Array<int>;
@@ -2129,6 +2131,7 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
}
break;
}
*/
case 15: // 1-node point
{
elements_0D.push_back(
@@ -2333,6 +2336,8 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
}
break;
}
/*
// MFEM does not support pyramids yet
case 7: el_order--; // 5-node pyramid
case 14: el_order--; // 14-node pyramid (2nd order)
case 118: el_order--; // 30-node pyramid (3rd order)
@@ -2345,7 +2350,7 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
{
el_order--;
elements_3D.push_back(
new Pyramid(&vert_indices[0], phys_domain));
new Pyramid(&vert_indices[0], phys_domain));
if (el_order > 1)
{
Array<int> * hov = new Array<int>;
@@ -2355,6 +2360,7 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
}
break;
}
*/
case 15: // 1-node point
{
elements_0D.push_back(
@@ -2557,16 +2563,16 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
}
vm = ho_wdg[el_order];
break;
case Element::PYRAMID:
ho_verts = ho_verts_3D[el];
el_order = ho_el_order_3D[el];
if (!ho_pyr[el_order])
{
ho_pyr[el_order] = new int[ho_verts->Size()];
GmshHOPyramidMapping(el_order, ho_pyr[el_order]);
}
vm = ho_pyr[el_order];
break;
// case Element::PYRAMID:
// ho_verts = ho_verts_3D[el];
// el_order = ho_el_order_3D[el];
// if (ho_pyr[el_order])
// {
// ho_pyr[el_order] = new int[ho_verts->Size()];
// GmshHOPyramidMapping(el_order, ho_pyr[el_order]);
// }
// vm = ho_pyr[el_order];
// break;
default: // Any other element type
MFEM_WARNING("Unsupported Gmsh element type.");
break;
+12 -33
View File
@@ -3706,28 +3706,20 @@ void NCMesh::FindSetNeighbors(const Array<char> &elem_set,
static bool sorted_lists_intersect(const int* a, const int* b, int na, int nb)
{
// pointers to "end" sentinel, not last entry. Not for dereferencing.
const int * const a_end = a + na;
const int * const b_end = b + nb;
while (a != a_end && b != b_end)
{
if (*a < *b)
{
++a;
}
else if (*b < *a)
{
++b;
}
else
{
return true; // neither *a < *b nor *b < *a thus a == b
}
}
return false; // no common element found
if (!na || !nb) { return false; }
int a_last = a[na-1], b_last = b[nb-1];
if (*b < *a) { goto l2; } // woo-hoo! I always wanted to use a goto! :)
l1:
if (a_last < *b) { return false; }
while (*a < *b) { a++; }
if (*a == *b) { return true; }
l2:
if (b_last < *a) { return false; }
while (*b < *a) { b++; }
if (*a == *b) { return true; }
goto l1;
}
void NCMesh::FindNeighbors(int elem, Array<int> &neighbors,
const Array<int> *search_set)
{
@@ -4488,19 +4480,6 @@ void NCMesh::GetPointMatrix(Geometry::Type geom, const char* ref_path,
pm = PointMatrix(mid12, mid20, mid01);
}
}
else if (geom == Geometry::SEGMENT)
{
Point mid01(pm(0), pm(1));
if (child == 0)
{
pm = PointMatrix(pm(0), mid01);
}
else if (child == 1)
{
pm = PointMatrix(mid01, pm(1));
}
}
}
// write the points to the matrix
-69
View File
@@ -2689,20 +2689,6 @@ STable3D *ParMesh::GetSharedFacesTable()
}
break;
}
case Element::PYRAMID:
{
for (int j = 0; j < 1; j++)
{
const int *fv = pyr_t::FaceVert[j];
sfaces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
}
for (int j = 1; j < 5; j++)
{
const int *fv = pyr_t::FaceVert[j];
sfaces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
}
break;
}
case Element::HEXAHEDRON:
{
// find the face by the vertices with the smallest 3 numbers
@@ -2810,61 +2796,6 @@ STable3D *ParMesh::GetFaceNbrElementToFaceTable(int ret_ftbl)
}
break;
}
case Element::PYRAMID:
{
for (int j = 0; j < 1; j++)
{
const int *fv = pyr_t::FaceVert[j];
int k = 0;
int max = v[fv[0]];
if (max < v[fv[1]]) { max = v[fv[1]], k = 1; }
if (max < v[fv[2]]) { max = v[fv[2]], k = 2; }
if (max < v[fv[3]]) { k = 3; }
int v0 = -1, v1 = -1, v2 = -1;
switch (k)
{
case 0:
v0 = v[fv[1]]; v1 = v[fv[2]]; v2 = v[fv[3]];
break;
case 1:
v0 = v[fv[0]]; v1 = v[fv[2]]; v2 = v[fv[3]];
break;
case 2:
v0 = v[fv[0]]; v1 = v[fv[1]]; v2 = v[fv[3]];
break;
case 3:
v0 = v[fv[0]]; v1 = v[fv[1]]; v2 = v[fv[2]];
break;
}
int lf = faces_tbl->Index(v0, v1, v2);
if (lf < 0)
{
lf = sfaces_tbl->Index(v0, v1, v2);
if (lf >= 0)
{
lf += NumOfFaces;
}
}
face_nbr_el_to_face->Push(i, lf);
}
for (int j = 1; j < 5; j++)
{
const int *fv = pyr_t::FaceVert[j];
int lf = faces_tbl->Index(v[fv[0]], v[fv[1]], v[fv[2]]);
if (lf < 0)
{
lf = sfaces_tbl->Index(v[fv[0]], v[fv[1]], v[fv[2]]);
if (lf >= 0)
{
lf += NumOfFaces;
}
}
face_nbr_el_to_face->Push(i, lf);
}
break;
}
case Element::HEXAHEDRON:
{
// find the face by the vertices with the smallest 3 numbers
+4 -13
View File
@@ -501,9 +501,6 @@ public:
/// mask & 4 - Loc1, mask & 8 - Loc2, mask & 16 - Face.
/// These mask values are defined in the ConfigMasks enum type as part of the
/// FaceElementTransformations class in fem/eltrans.hpp.
///
/// Note that the pointer is owned by the class and is shared, i.e., calling
/// this function resets pointers obtained from previous calls.
FaceElementTransformations *GetFaceElementTransformations(
int FaceNo,
int mask = 31) override;
@@ -512,9 +509,7 @@ public:
using the shared face index @a sf. @a fill2 specify if the information
for elem2 of the face should be computed or not.
In the returned object, 1 and 2 refer to the local and the neighbor
elements, respectively.
Note that the pointer is owned by the class and is shared, i.e., calling
this function resets pointers obtained from previous calls. */
elements, respectively. */
FaceElementTransformations *
GetSharedFaceTransformations(int sf, bool fill2 = true);
@@ -522,16 +517,12 @@ public:
using the face index @a FaceNo. @a fill2 specify if the information
for elem2 of the face should be computed or not.
In the returned object, 1 and 2 refer to the local and the neighbor
elements, respectively.
Note that the pointer is owned by the class and is shared, i.e., calling
this function resets pointers obtained from previous calls. */
elements, respectively. */
FaceElementTransformations *
GetSharedFaceTransformationsByLocalIndex(int FaceNo, bool fill2 = true);
/// Returns a pointer to the transformation defining the i-th face neighbor.
/// Note that the pointer is owned by the class and is shared, i.e., calling
/// this function resets pointers obtained from previous calls.
ElementTransformation *GetFaceNbrElementTransformation(int i)
ElementTransformation *
GetFaceNbrElementTransformation(int i)
{
GetFaceNbrElementTransformation(i, &FaceNbrTransformation);
@@ -0,0 +1,359 @@
// 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 "change_basis.hpp"
#include "fem/qinterp/dispatch.hpp"
#include "general/forall.hpp"
#include "linalg/dtensor.hpp"
namespace mfem
{
/// @brief Compute the inverse of the matrix A and store the result in Ainv.
///
/// The input A is an array of size n*n, interpreted as a matrix with column
/// major ordering.
void ComputeInverse(const Array<double> &A, Array<double> &Ainv)
{
Array<double> A2 = A;
const int n2 = A.Size();
const int n = sqrt(n2);
Array<int> ipiv(n);
LUFactors lu(A2.GetData(), ipiv.GetData());
lu.Factor(n);
Ainv.SetSize(n2);
lu.GetInverseMatrix(n, Ainv.GetData());
}
void SubcellIntegrals(int n, const Poly_1D::Basis &basis, Array<double> &B)
{
const IntegrationRule &ir = IntRules.Get(Geometry::SEGMENT, n);
const double *gll_pts = poly1d.GetPoints(n, BasisType::GaussLobatto);
Vector u(n);
B.SetSize(n*n);
B = 0.0;
for (int i = 0; i < n; ++i)
{
const double h = gll_pts[i+1] - gll_pts[i];
// Loop over subcell quadrature points
for (int iq = 0; iq < ir.Size(); ++iq)
{
const IntegrationPoint &ip = ir[iq];
const double x = gll_pts[i] + h*ip.x;
const double w = h*ip.weight;
basis.Eval(x, u);
for (int j = 0; j < n; ++j)
{
B[i + j*n] += w*u[j];
}
}
}
}
void Transpose(const Array<double> &B, Array<double> &Bt)
{
const int n = sqrt(B.Size());
Bt.SetSize(n*n);
for (int i=0; i<n; ++i) for (int j=0; j<n; ++j) { Bt[i+j*n] = B[j+i*n]; }
}
ChangeOfBasis_L2::ChangeOfBasis_L2(FiniteElementSpace &fes)
: Operator(fes.GetTrueVSize()),
ne(fes.GetNE())
{
auto *fec1 = dynamic_cast<const L2_FECollection*>(fes.FEColl());
MFEM_VERIFY(fec1, "Must be L2 finite element space");
const int btype = fec1->GetBasisType();
// If the basis types are the same, don't need to perform change of basis.
no_op = (btype == BasisType::IntegratedGLL);
if (no_op) { return; }
// Convert from the given basis to the "integrated GLL basis".
// The degrees of freedom are integrals over subcells.
const FiniteElement *fe = fes.GetFE(0);
auto *tbe = dynamic_cast<const TensorBasisElement*>(fe);
MFEM_VERIFY(tbe != nullptr, "Must be a tensor element.");
const Poly_1D::Basis &basis = tbe->GetBasis1D();
const int p = fes.GetMaxElementOrder();
const int pp1 = p + 1;
Array<double> B_inv;
SubcellIntegrals(pp1, basis, B_inv);
ComputeInverse(B_inv, B_1d);
Transpose(B_1d, Bt_1d);
// Set up the DofToQuad object, used in TensorValues
dof2quad.FE = fe;
dof2quad.mode = DofToQuad::TENSOR;
dof2quad.ndof = pp1;
dof2quad.nqpt = pp1;
}
void ChangeOfBasis_L2::Mult(const Vector &x, Vector &y) const
{
if (no_op) { y = x; return; }
using namespace internal::quadrature_interpolator;
dof2quad.B.MakeRef(B_1d);
TensorValues<QVectorLayout::byVDIM>(ne, 1, dof2quad, x, y);
}
void ChangeOfBasis_L2::MultTranspose(const Vector &x, Vector &y) const
{
if (no_op) { y = x; return; }
using namespace internal::quadrature_interpolator;
dof2quad.B.MakeRef(Bt_1d);
TensorValues<QVectorLayout::byVDIM>(ne, 1, dof2quad, x, y);
}
ChangeOfBasis_RT::ChangeOfBasis_RT(FiniteElementSpace &fes)
: Operator(fes.GetTrueVSize()),
fes(fes),
dim(fes.GetMesh()->Dimension()),
ne(fes.GetNE()),
p(fes.GetMaxElementOrder())
{
auto op = fes.GetElementRestriction(ElementDofOrdering::LEXICOGRAPHIC);
elem_restr = dynamic_cast<const ElementRestriction*>(op);
MFEM_VERIFY(elem_restr != NULL, "Missing element restriciton.");
const auto *rt_fec = dynamic_cast<const RT_FECollection*>(fes.FEColl());
MFEM_VERIFY(rt_fec, "Must be RT finite element space.");
const int cb_type = rt_fec->GetClosedBasisType();
const int ob_type = rt_fec->GetOpenBasisType();
no_op = (cb_type == BasisType::GaussLobatto &&
ob_type == BasisType::IntegratedGLL);
if (no_op) { return; }
const int pp1 = p + 1;
Poly_1D::Basis &cbasis = poly1d.GetBasis(p, cb_type);
Poly_1D::Basis &obasis = poly1d.GetBasis(p-1, ob_type);
const double *cpts2 = poly1d.GetPoints(p, BasisType::GaussLobatto);
Bci_1d.SetSize(pp1*pp1);
Vector b(pp1);
for (int i = 0; i < pp1; ++i)
{
cbasis.Eval(cpts2[i], b);
for (int j = 0; j < pp1; ++j)
{
Bci_1d[i + j*pp1] = b[j];
}
}
SubcellIntegrals(p, obasis, Boi_1d);
ComputeInverse(Boi_1d, Bo_1d);
Transpose(Bo_1d, Bot_1d);
ComputeInverse(Bci_1d, Bc_1d);
Transpose(Bc_1d, Bct_1d);
}
const double *ChangeOfBasis_RT::GetOpenMap(Mode mode) const
{
switch (mode)
{
case NORMAL: return Bo_1d.Read();
case TRANSPOSE: return Bot_1d.Read();
case INVERSE: return Boi_1d.Read();
}
return nullptr;
}
const double *ChangeOfBasis_RT::GetClosedMap(Mode mode) const
{
switch (mode)
{
case NORMAL: return Bc_1d.Read();
case TRANSPOSE: return Bct_1d.Read();
case INVERSE: return Bci_1d.Read();
}
return nullptr;
}
void ChangeOfBasis_RT::MultRT_2D(const Vector &x, Vector &y, Mode mode) const
{
const int DIM = dim;
const int NE = ne;
const int D1D = p + 1;
const int ND = (p+1)*p;
const double *BC = GetClosedMap(mode);
const double *BO = GetOpenMap(mode);
const auto X = Reshape(x.Read(), DIM*ND, ne);
auto Y = Reshape(y.Write(), DIM*ND, ne);
MFEM_FORALL(e, NE,
{
for (int c = 0; c < DIM; ++c)
{
const int nx = (c == 0) ? D1D : D1D-1;
const int ny = (c == 1) ? D1D : D1D-1;
const double *Bx = (c == 0) ? BC : BO;
const double *By = (c == 1) ? BC : BO;
for (int i = 0; i < ND; ++i)
{
Y(i + c*ND, e) = 0.0;
}
for (int iy = 0; iy < ny; ++ iy)
{
double xx[MAX_D1D];
for (int ix = 0; ix < nx; ++ix) { xx[ix] = 0.0; }
for (int jx = 0; jx < nx; ++jx)
{
const double val = X(jx + iy*nx + c*nx*ny, e);
for (int ix = 0; ix < nx; ++ix)
{
xx[ix] += val*Bx[ix + jx*nx];
}
}
for (int jy = 0; jy < ny; ++jy)
{
const double b = By[jy + iy*ny];
for (int ix = 0; ix < nx; ++ix)
{
Y(ix + jy*nx + c*nx*ny, e) += xx[ix]*b;
}
}
}
}
});
}
void ChangeOfBasis_RT::MultRT_3D(const Vector &x, Vector &y, Mode mode) const
{
const int DIM = dim;
const int NE = ne;
const int D1D = p + 1;
const int ND = (p+1)*p*p;
const double *BC = GetClosedMap(mode);
const double *BO = GetOpenMap(mode);
const auto X = Reshape(x.Read(), DIM*ND, ne);
auto Y = Reshape(y.Write(), DIM*ND, ne);
MFEM_FORALL(e, NE,
{
for (int c = 0; c < DIM; ++c)
{
const int nx = (c == 0) ? D1D : D1D-1;
const int ny = (c == 1) ? D1D : D1D-1;
const int nz = (c == 2) ? D1D : D1D-1;
const double *Bx = (c == 0) ? BC : BO;
const double *By = (c == 1) ? BC : BO;
const double *Bz = (c == 2) ? BC : BO;
for (int i = 0; i < ND; ++i)
{
Y(i + c*ND, e) = 0.0;
}
for (int iz = 0; iz < nz; ++ iz)
{
double xy[MAX_D1D][MAX_D1D];
for (int iy = 0; iy < ny; ++iy)
{
for (int ix = 0; ix < nx; ++ix)
{
xy[iy][ix] = 0.0;
}
}
for (int iy = 0; iy < ny; ++iy)
{
double xx[MAX_D1D];
for (int ix = 0; ix < nx; ++ix) { xx[ix] = 0.0; }
for (int ix = 0; ix < nx; ++ix)
{
const double val = X(ix + iy*nx + iz*nx*ny + c*ND, e);
for (int jx = 0; jx < nx; ++jx)
{
xx[jx] += val*Bx[jx + ix*nx];
}
}
for (int jy = 0; jy < ny; ++jy)
{
const double b = By[jy + iy*ny];
for (int jx = 0; jx < nx; ++jx)
{
xy[jy][jx] += xx[jx] * b;
}
}
}
for (int jz = 0; jz < nz; ++jz)
{
const double b = Bz[jz + iz*nz];
for (int jy = 0; jy < ny; ++jy)
{
for (int jx = 0; jx < nx; ++jx)
{
Y(jx + jy*nx + jz*nx*ny + c*ND, e) += xy[jy][jx] * b;
}
}
}
}
}
});
}
void ChangeOfBasis_RT::Mult(const Vector &x, Vector &y, Mode mode) const
{
if (no_op) { y = x; return; }
const Operator *P = fes.GetProlongationMatrix();
if (IsIdentityProlongation(P))
{
x_l.MakeRef(const_cast<Vector&>(x), 0, fes.GetVSize());
y_l.MakeRef(y, 0, fes.GetVSize());
}
else
{
x_l.SetSize(fes.GetVSize());
y_l.SetSize(fes.GetVSize());
P->Mult(x, x_l);
}
x_e.SetSize(elem_restr->Height());
y_e.SetSize(elem_restr->Height());
elem_restr->Mult(x_l, x_e);
if (dim == 2) { MultRT_2D(x_e, y_e, mode); }
else { MultRT_3D(x_e, y_e, mode); }
elem_restr->MultLeftInverse(y_e, y_l);
const Operator *R = fes.GetRestrictionOperator();
if (R) { R->Mult(y_l, y); }
else { MFEM_VERIFY(P == NULL, "Invalid state."); }
}
void ChangeOfBasis_RT::Mult(const Vector &x, Vector &y) const
{
Mult(x, y, NORMAL);
}
void ChangeOfBasis_RT::MultTranspose(const Vector &x, Vector &y) const
{
Mult(x, y, TRANSPOSE);
}
void ChangeOfBasis_RT::MultInverse(const Vector &x, Vector &y) const
{
Mult(x, y, INVERSE);
}
} // namespace mfem
@@ -0,0 +1,87 @@
// 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 CHANGE_BASIS_HPP
#define CHANGE_BASIS_HPP
#include "mfem.hpp"
namespace mfem
{
/// @brief Change of basis operator between L2 spaces.
///
/// This represents the change-of-basis operator from the given L2 space to a
/// space using the IntegratedGLL basis.
class ChangeOfBasis_L2 : public Operator
{
private:
const int ne; ///< Number of elements in the mesh.
mutable DofToQuad dof2quad; ///< 1D basis transformation.
Array<double> B_1d; ///< 1D basis transformation matrix.
Array<double> Bt_1d; ///< 1D basis transformation matrix traspose.
bool no_op; ///< If the basis types are the same, the operation is a no-op.
public:
ChangeOfBasis_L2(FiniteElementSpace &fes);
void Mult(const Vector &x, Vector &y) const override;
void MultTranspose(const Vector &x, Vector &y) const override;
};
/// Change of basis operator between RT spaces.
///
/// This represents the change-of-basis operator from the given RT space to a
/// space using Gauss-Lobatto as the "open" basis and IntegratedGLL as the
/// "closed" basis.
class ChangeOfBasis_RT : public Operator
{
public:
// Should be private, nvcc limitation...
enum Mode
{
NORMAL,
TRANSPOSE,
INVERSE
};
private:
FiniteElementSpace &fes; ///< The finite element space.
const int dim; ///< Dimension of the mesh.
const int ne; ///< Number of elements.
const int p; ///< Polynomial degree.
const ElementRestriction *elem_restr; ///< Element restriction operator.
Array<double> Bc_1d; ///< 1D closed basis transformation matrix.
Array<double> Bci_1d; ///< 1D closed basis transformation matrix inverse.
Array<double> Bct_1d; ///< 1D closed basis transformation matrix transpose.
Array<double> Bo_1d; ///< 1D open basis transformation matrix.
Array<double> Boi_1d; ///< 1D open basis transformation matrix inverse.
Array<double> Bot_1d; ///< 1D open basis transformation matrix transpose.
mutable Vector x_l, y_l; ///< L-vector layout
mutable Vector x_e, y_e; ///< E-vector layout
bool no_op; ///< If the spaces are the same, the operation is a no-op.
void Mult(const Vector &x, Vector &y, Mode mode) const;
const double *GetOpenMap(Mode mode) const;
const double *GetClosedMap(Mode mode) const;
public:
ChangeOfBasis_RT(FiniteElementSpace &fes);
void Mult(const Vector &x, Vector &y) const override;
void MultTranspose(const Vector &x, Vector &y) const override;
void MultInverse(const Vector &x, Vector &y) const;
// The following should be considered private, public because of compiler
// limitations
void MultRT_2D(const Vector &x, Vector &y, Mode mode) const;
void MultRT_3D(const Vector &x, Vector &y, Mode mode) const;
};
} // namespace mfem
#endif
+212
View File
@@ -0,0 +1,212 @@
// 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.
//
// ---------------------------------
// Poisson/Darcy Mixed Method Solver
// ---------------------------------
//
// Solves a Poisson problem -Delta p = f using a mixed finite element
// formulation). The right-hand side of the Poisson problem is the same as that
// used in the LOR Solvers miniapp (see miniapps/solvers). Dirichlet boundary
// conditions are enforced on all domain boundaries.
//
// Optionally, the equation alpha*p - Delta p = f can be solved by setting the
// alpha parameter to a nonzero value.
// This can be written in the form of a Darcy problem
//
// -u - grad(p) = 0
// alpha*p + div(u) = f
//
// where natural boundary conditions are enforced on the flux u, and the
// Dirichlet condition on p is enforced by modifying the right-hand side.
//
// The resulting saddle-point system is solved using MINRES with a matrix-free
// block-diagonal preconditioner.
//
// See also example 5 and its parallel version.
//
// Sample runs:
//
// darcy
// mpirun -np 4 darcy -m ../../data/fichera-q2.mesh
#include "mfem.hpp"
#include <iostream>
#include <memory>
#include "discrete_divergence.hpp"
#include "hdiv_linear_solver.hpp"
#include "../solvers/lor_mms.hpp"
using namespace std;
using namespace mfem;
ParMesh LoadParMesh(const char *mesh_file, int ser_ref = 0, int par_ref = 0);
class RobinCoefficient : public Coefficient
{
double Eval(ElementTransformation &T, const IntegrationPoint &ip) override
{
double xdata[3];
Vector xvec(xdata, 3);
T.Transform(ip, xvec);
const int dim = xvec.Size();
Vector n(dim);
CalcOrtho(T.Jacobian(), n);
n /= n.Norml2();
const double p_val = u(xvec);
const double x = pi*xvec[0];
const double y = pi*xvec[1];
if (dim == 2)
{
const double u_val = -pi*(n[0]*cos(x)*sin(y) + n[1]*sin(x)*cos(y));
return p_val - u_val;
}
else
{
MFEM_ABORT("Not implemented");
}
return 0.0;
}
};
int main(int argc, char *argv[])
{
Mpi::Init(argc, argv);
Hypre::Init();
const char *mesh_file = "../../data/star.mesh";
const char *device_config = "cpu";
int ser_ref = 1;
int par_ref = 1;
int order = 3;
double alpha = 0.0;
OptionsParser args(argc, argv);
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
args.AddOption(&ser_ref, "-rs", "--serial-refine",
"Number of times to refine the mesh in serial.");
args.AddOption(&par_ref, "-rp", "--parallel-refine",
"Number of times to refine the mesh in parallel.");
args.AddOption(&order, "-o", "--order", "Polynomial degree.");
args.AddOption(&alpha, "-a", "--alpha", "Value of alpha coefficient.");
args.ParseCheck();
Device device(device_config);
if (Mpi::Root()) { device.Print(); }
ParMesh mesh = LoadParMesh(mesh_file, ser_ref, par_ref);
const int dim = mesh.Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "Spatial dimension must be 2 or 3.");
const int b1 = BasisType::GaussLobatto, b2 = BasisType::GaussLegendre;
const int mt = FiniteElement::VALUE;
RT_FECollection fec_rt(order-1, dim, b1, b2);
L2_FECollection fec_l2(order-1, dim, b2, mt);
ParFiniteElementSpace fes_rt(&mesh, &fec_rt);
ParFiniteElementSpace fes_l2(&mesh, &fec_l2);
HYPRE_BigInt ndofs_rt = fes_rt.GlobalTrueVSize();
HYPRE_BigInt ndofs_l2 = fes_l2.GlobalTrueVSize();
if (Mpi::Root())
{
cout << "\nRT DOFs: " << ndofs_rt << "\nL2 DOFs: " << ndofs_l2 << endl;
}
Array<int> ess_rt_dofs; // empty
// f is the RHS, u is the exact solution
FunctionCoefficient f_coeff(f(alpha)), u_coeff(u);
// Coefficient to enforce Robin boundary condition
RobinCoefficient bc_coeff;
// Assemble the right-hand side for the scalar (L2) unknown.
ParLinearForm b_l2(&fes_l2);
b_l2.AddDomainIntegrator(new DomainLFIntegrator(f_coeff));
b_l2.UseFastAssembly(true);
b_l2.Assemble();
// Enforce Dirichlet boundary conditions on the scalar unknown by adding
// the boundary term to the flux equation.
ParLinearForm b_rt(&fes_rt);
b_rt.AddBoundaryIntegrator(new VectorFEBoundaryFluxLFIntegrator(bc_coeff));
b_rt.UseFastAssembly(true);
b_rt.Assemble();
if (Mpi::Root()) { cout << "\nSaddle point solver... " << flush; }
tic_toc.Clear(); tic_toc.Start();
// Set up the block system of the form
//
// [ W D ][ u ] = [ f ]
// [ D^T -M ][ q ] = [ g_D ]
//
// where W is the L2 mass matrix, D is the discrete divergence, and M is
// the RT mass matrix.
//
// If the coefficient alpha is set to zero, the system takes the form
//
// [ 0 D ][ u ] = [ f ]
// [ D^T -M ][ q ] = [ g_D ]
//
// u is the scalar unknown, and q is the flux. f is the right-hand side from
// the Poisson problem, and g_D is the contribution to the right-hand side
// from the Dirichlet boundary condition.
ConstantCoefficient one(1.0);
ConstantCoefficient alpha_coeff(alpha);
const auto solver_mode = HdivSaddlePointSolver::Mode::DARCY;
HdivSaddlePointSolver saddle_point_solver(
mesh, fes_rt, fes_l2, alpha_coeff, one, one, ess_rt_dofs, solver_mode);
const Array<int> &offsets = saddle_point_solver.GetOffsets();
BlockVector X_block(offsets), B_block(offsets);
b_l2.ParallelAssemble(B_block.GetBlock(0));
b_rt.ParallelAssemble(B_block.GetBlock(1));
B_block.SyncFromBlocks();
X_block = 0.0;
saddle_point_solver.Mult(B_block, X_block);
X_block.SyncToBlocks();
if (Mpi::Root())
{
cout << "Done.\nIterations: "
<< saddle_point_solver.GetNumIterations()
<< "\nElapsed: " << tic_toc.RealTime() << endl;
}
ParGridFunction x(&fes_l2);
x.SetFromTrueDofs(X_block.GetBlock(0));
const double error = x.ComputeL2Error(u_coeff);
if (Mpi::Root()) { cout << "L2 error: " << error << endl; }
return 0;
}
ParMesh LoadParMesh(const char *mesh_file, int ser_ref, int par_ref)
{
Mesh serial_mesh = Mesh::LoadFromFile(mesh_file);
for (int i = 0; i < ser_ref; ++i) { serial_mesh.UniformRefinement(); }
ParMesh mesh(MPI_COMM_WORLD, serial_mesh);
serial_mesh.Clear();
for (int i = 0; i < par_ref; ++i) { mesh.UniformRefinement(); }
return mesh;
}
@@ -0,0 +1,276 @@
// 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 "mfem.hpp"
#include "general/forall.hpp"
#include "discrete_divergence.hpp"
namespace mfem
{
/// @brief Eliminates columns in the given HypreParMatrix.
///
/// This is similar to HypreParMatrix::EliminateBC, except that only the columns
/// are eliminated.
void EliminateColumns(HypreParMatrix &D, const Array<int> &ess_dofs)
{
hypre_ParCSRMatrix *A_hypre = D;
D.HypreReadWrite();
hypre_CSRMatrix *diag = hypre_ParCSRMatrixDiag(A_hypre);
hypre_CSRMatrix *offd = hypre_ParCSRMatrixOffd(A_hypre);
HYPRE_Int diag_ncols = hypre_CSRMatrixNumCols(diag);
HYPRE_Int offd_ncols = hypre_CSRMatrixNumCols(offd);
const int n_ess_dofs = ess_dofs.Size();
// Start communication to figure out which columns need to be eliminated in
// the off-diagonal block
hypre_ParCSRCommHandle *comm_handle;
HYPRE_Int *int_buf_data, *eliminate_col_diag, *eliminate_col_offd;
{
eliminate_col_diag = mfem_hypre_CTAlloc_host(HYPRE_Int, diag_ncols);
eliminate_col_offd = mfem_hypre_CTAlloc_host(HYPRE_Int, offd_ncols);
// Make sure A has a communication package
hypre_ParCSRCommPkg *comm_pkg = hypre_ParCSRMatrixCommPkg(A_hypre);
if (!comm_pkg)
{
hypre_MatvecCommPkgCreate(A_hypre);
comm_pkg = hypre_ParCSRMatrixCommPkg(A_hypre);
}
// Which of the local columns are to be eliminated?
for (int i = 0; i < diag_ncols; i++)
{
eliminate_col_diag[i] = 0;
}
ess_dofs.HostRead();
for (int i = 0; i < n_ess_dofs; i++)
{
eliminate_col_diag[ess_dofs[i]] = 1;
}
// Use a matvec communication pattern to find (in eliminate_col_offd)
// which of the local offd columns are to be eliminated
HYPRE_Int num_sends = hypre_ParCSRCommPkgNumSends(comm_pkg);
HYPRE_Int int_buf_sz = hypre_ParCSRCommPkgSendMapStart(comm_pkg, num_sends);
int_buf_data = mfem_hypre_CTAlloc_host(HYPRE_Int, int_buf_sz);
HYPRE_Int *send_map_elmts = hypre_ParCSRCommPkgSendMapElmts(comm_pkg);
for (int i = 0; i < int_buf_sz; ++i)
{
const int k = send_map_elmts[i];
int_buf_data[i] = eliminate_col_diag[k];
}
comm_handle = hypre_ParCSRCommHandleCreate(
11, comm_pkg, int_buf_data, eliminate_col_offd);
}
// Eliminate columns in the diagonal block
{
Memory<HYPRE_Int> col_mem(eliminate_col_diag, diag_ncols, false);
const auto cols = col_mem.Read(GetHypreMemoryClass(), diag_ncols);
const int nrows_diag = hypre_CSRMatrixNumRows(diag);
const auto I = diag->i;
const auto J = diag->j;
auto data = diag->data;
MFEM_HYPRE_FORALL(i, nrows_diag,
{
for (int jj=I[i]; jj<I[i+1]; ++jj)
{
const int j = J[jj];
data[jj] *= 1 - cols[j];
}
});
col_mem.Delete();
}
// Wait for MPI communication to finish
hypre_ParCSRCommHandleDestroy(comm_handle);
mfem_hypre_TFree_host(int_buf_data);
mfem_hypre_TFree_host(eliminate_col_diag);
// Eliminate columns in the off-diagonal block
{
Memory<HYPRE_Int> col_mem(eliminate_col_offd, offd_ncols, false);
const auto cols = col_mem.Read(GetHypreMemoryClass(), offd_ncols);
const int nrows_offd = hypre_CSRMatrixNumRows(offd);
const auto I = offd->i;
const auto J = offd->j;
auto data = offd->data;
MFEM_HYPRE_FORALL(i, nrows_offd,
{
for (int jj=I[i]; jj<I[i+1]; ++jj)
{
const int j = J[jj];
data[jj] *= 1 - cols[j];
}
});
col_mem.Delete();
}
mfem_hypre_TFree_host(eliminate_col_offd);
}
void FormElementToFace2D(int order, Array<int> &element2face)
{
const int o = order;
const int op1 = order + 1;
for (int iy = 0; iy < o; ++iy)
{
for (int ix = 0; ix < o; ++ix)
{
const int ivol = ix + iy*o;
element2face[0 + 4*ivol] = -1 - (ix + iy*op1); // left, x = 0
element2face[1 + 4*ivol] = ix+1 + iy*op1; // right, x = 1
element2face[2 + 4*ivol] = -1 - (ix + iy*o + o*op1); // bottom, y = 0
element2face[3 + 4*ivol] = ix + (iy+1)*o + o*op1; // top, y = 1
}
}
}
void FormElementToFace3D(int order, Array<int> &element2face)
{
const int o = order;
const int op1 = order + 1;
const int n = o*o*op1; // number of faces per dimension
for (int iz = 0; iz < o; ++iz)
{
for (int iy = 0; iy < o; ++iy)
{
for (int ix = 0; ix < o; ++ix)
{
const int ivol = ix + iy*o + iz*o*o;
element2face[0 + 6*ivol] = -1 - (ix + iy*op1 + iz*o*op1); // x = 0
element2face[1 + 6*ivol] = ix+1 + iy*op1 + iz*o*op1; // x = 1
element2face[2 + 6*ivol] = -1 - (ix + iy*o + iz*o*op1 + n); // y = 0
element2face[3 + 6*ivol] = ix + (iy+1)*o + iz*o*op1 + n; // y = 1
element2face[4 + 6*ivol] = -1 - (ix + iy*o + iz*o*o + 2*n); // z = 0
element2face[5 + 6*ivol] = ix + iy*o + (iz+1)*o*o + 2*n; // z = 1
}
}
}
}
HypreParMatrix *FormDiscreteDivergenceMatrix(ParFiniteElementSpace &fes_rt,
ParFiniteElementSpace &fes_l2,
const Array<int> &ess_dofs)
{
const Mesh &mesh = *fes_rt.GetMesh();
const int dim = mesh.Dimension();
const int order = fes_rt.GetMaxElementOrder();
const int n_rt = fes_rt.GetNDofs();
const int n_l2 = fes_l2.GetNDofs();
SparseMatrix D_local;
D_local.OverrideSize(n_l2, n_rt);
D_local.GetMemoryI().New(n_l2 + 1);
// Each row always has 2*dim nonzeros (one for each face of the element)
const int nnz = n_l2*2*dim;
auto I = D_local.WriteI();
MFEM_FORALL(i, n_l2+1, I[i] = 2*dim*i; );
const int nel_ho = mesh.GetNE();
const int nface_per_el = dim*pow(order, dim-1)*(order+1);
const int nvol_per_el = pow(order, dim);
// element2face is a mapping of size (2*dim, nvol_per_el) such that with a
// macro element, subelement i (in lexicographic ordering) has faces (also
// in lexicographic order) given by the entries (j, i).
Array<int> element2face;
element2face.SetSize(2*dim*nvol_per_el);
if (dim == 2) { FormElementToFace2D(order, element2face); }
else if (dim == 3) { FormElementToFace3D(order, element2face); }
else { MFEM_ABORT("Unsupported dimension.") }
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
const auto *R_rt = dynamic_cast<const ElementRestriction*>(
fes_rt.GetElementRestriction(ordering));
const auto gather_rt = Reshape(R_rt->GatherMap().Read(), nface_per_el, nel_ho);
const auto e2f = Reshape(element2face.Read(), 2*dim, nvol_per_el);
// Fill J and data
D_local.GetMemoryJ().New(nnz);
D_local.GetMemoryData().New(nnz);
auto J = D_local.WriteJ();
auto V = D_local.WriteData();
// Loop over L2 DOFs
MFEM_FORALL(i, n_l2,
{
const int i_loc = i%nvol_per_el;
const int i_el = i/nvol_per_el;
for (int k = 0; k < 2*dim; ++k)
{
const int sjv_loc = e2f(k, i_loc);
const int jv_loc = (sjv_loc >= 0) ? sjv_loc : -1 - sjv_loc;
const int sgn1 = (sjv_loc >= 0) ? 1 : -1;
const int sj = gather_rt(jv_loc, i_el);
const int j = (sj >= 0) ? sj : -1 - sj;
const int sgn2 = (sj >= 0) ? 1 : -1;
J[k + 2*dim*i] = j;
V[k + 2*dim*i] = sgn1*sgn2;
}
});
// Create a block diagonal parallel matrix
OperatorHandle D_diag(Operator::Hypre_ParCSR);
D_diag.MakeRectangularBlockDiag(fes_rt.GetComm(),
fes_l2.GlobalVSize(),
fes_rt.GlobalVSize(),
fes_l2.GetDofOffsets(),
fes_rt.GetDofOffsets(),
&D_local);
HypreParMatrix *D;
// Assemble the parallel gradient matrix, must be deleted by the caller
if (IsIdentityProlongation(fes_rt.GetProlongationMatrix()))
{
D = D_diag.As<HypreParMatrix>();
D_diag.SetOperatorOwner(false);
HypreStealOwnership(*D, D_local);
}
else
{
OperatorHandle Rt(Transpose(*fes_l2.GetRestrictionMatrix()));
OperatorHandle Rt_diag(Operator::Hypre_ParCSR);
Rt_diag.MakeRectangularBlockDiag(fes_l2.GetComm(),
fes_l2.GlobalVSize(),
fes_l2.GlobalTrueVSize(),
fes_l2.GetDofOffsets(),
fes_l2.GetTrueDofOffsets(),
Rt.As<SparseMatrix>());
D = RAP(Rt_diag.As<HypreParMatrix>(),
D_diag.As<HypreParMatrix>(),
fes_rt.Dof_TrueDof_Matrix());
}
D->CopyRowStarts();
D->CopyColStarts();
// Eliminate the boundary conditions
EliminateColumns(*D, ess_dofs);
return D;
}
} // namespace mfem
@@ -0,0 +1,32 @@
// 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_DISCRETE_DIVERGENCE_HPP
#define MFEM_DISCRETE_DIVERGENCE_HPP
#include "mfem.hpp"
namespace mfem
{
/// @brief Eliminates columns in the given HypreParMatrix.
///
/// This is similar to HypreParMatrix::EliminateBC, except that only the columns
/// are eliminated.
void EliminateColumns(HypreParMatrix &D, const Array<int> &ess_dofs);
HypreParMatrix *FormDiscreteDivergenceMatrix(ParFiniteElementSpace &fes_rt,
ParFiniteElementSpace &fes_l2,
const Array<int> &ess_dofs);
} // namespace mfem
#endif
+280
View File
@@ -0,0 +1,280 @@
// 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.
//
// ---------------------------------
// H(div) saddle-point system solver
// ---------------------------------
//
// Solves the grad-div problem u - grad(div(u)) = f using a variety of solver
// techniques. This miniapp supports solving this problem using a variety of
// matrix-free and matrix-based preconditioning methods, inclding:
//
// * Matrix-free block-diagonal preconditioning for the saddle-point system.
// * ADS-AMG preconditioning.
// * Low-order-refined ADS-AMG preconditioning (matrix-free).
// * Hybridization with AMG preconditioning.
//
// The problem setup is the same as in the LOR solvers miniapps (in the
// miniapps/solvers directory). Dirichlet conditions are enforced on the normal
// component of u.
//
// Sample runs:
//
// grad_div -sp -ams -lor -hb
// mpirun -np 4 grad_div -sp -ams -lor -hb -m ../../data/fichera-q2.mesh -rp 0
#include "mfem.hpp"
#include <iostream>
#include <memory>
#include "hdiv_linear_solver.hpp"
#include "../solvers/lor_mms.hpp"
using namespace std;
using namespace mfem;
ParMesh LoadParMesh(const char *mesh_file, int ser_ref = 0, int par_ref = 0);
void SolveCG(Operator &A, Solver &P, const Vector &B, Vector &X);
int main(int argc, char *argv[])
{
Mpi::Init(argc, argv);
Hypre::Init();
const char *mesh_file = "../../data/star.mesh";
const char *device_config = "cpu";
int ser_ref = 1;
int par_ref = 1;
int order = 3;
bool use_saddle_point = false;
bool use_ams = false;
bool use_lor_ams = false;
bool use_hybridization = false;
OptionsParser args(argc, argv);
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
args.AddOption(&ser_ref, "-rs", "--serial-refine",
"Number of times to refine the mesh in serial.");
args.AddOption(&par_ref, "-rp", "--parallel-refine",
"Number of times to refine the mesh in parallel.");
args.AddOption(&order, "-o", "--order", "Polynomial degree.");
args.AddOption(&use_saddle_point,
"-sp", "--saddle-point", "-no-sp", "--no-saddle-point",
"Enable or disable saddle-point solver.");
args.AddOption(&use_ams, "-ams", "--ams", "-no-ams", "--no-ams",
"Enable or disable AMS solver.");
args.AddOption(&use_lor_ams, "-lor", "--lor-ams", "-no-lor", "--no-lor-ams",
"Enable or disable LOR-AMS solver.");
args.AddOption(&use_hybridization,
"-hb", "--hybridization", "-no-hb", "--no-hybridization",
"Enable or disable hybridization solver.");
args.ParseCheck();
if (!use_saddle_point && !use_ams && !use_lor_ams && !use_hybridization)
{
if (Mpi::Root()) { cout << "No solver enabled. Exiting.\n"; }
return 0;
}
Device device(device_config);
if (Mpi::Root()) { device.Print(); }
ParMesh mesh = LoadParMesh(mesh_file, ser_ref, par_ref);
const int dim = mesh.Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "Spatial dimension must be 2 or 3.");
const int b1 = BasisType::GaussLobatto, b2 = BasisType::GaussLegendre;
RT_FECollection fec_rt(order-1, dim, b1, b2);
ParFiniteElementSpace fes_rt(&mesh, &fec_rt);
Array<int> ess_rt_dofs;
fes_rt.GetBoundaryTrueDofs(ess_rt_dofs);
VectorFunctionCoefficient f_vec_coeff(dim, f_vec(true)), u_vec_coeff(dim, u_vec);
ParLinearForm b(&fes_rt);
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(f_vec_coeff));
b.UseFastAssembly(true);
b.Assemble();
ConstantCoefficient alpha_coeff(1.0);
ConstantCoefficient beta_coeff(1.0);
ParGridFunction x(&fes_rt);
x.ProjectCoefficient(u_vec_coeff);
cout.precision(4);
cout << scientific;
if (use_saddle_point)
{
if (Mpi::Root()) { cout << "\nSaddle point solver... " << flush; }
tic_toc.Clear(); tic_toc.Start();
const int mt = FiniteElement::INTEGRAL;
L2_FECollection fec_l2(order-1, dim, b2, mt);
ParFiniteElementSpace fes_l2(&mesh, &fec_l2);
HdivSaddlePointSolver saddle_point_solver(
mesh, fes_rt, fes_l2, alpha_coeff, beta_coeff, ess_rt_dofs,
HdivSaddlePointSolver::Mode::GRAD_DIV);
const Array<int> &offsets = saddle_point_solver.GetOffsets();
BlockVector X_block(offsets), B_block(offsets);
B_block.GetBlock(0) = 0.0;
b.ParallelAssemble(B_block.GetBlock(1));
B_block.GetBlock(1) *= -1.0;
B_block.SyncFromBlocks();
x.ParallelProject(X_block.GetBlock(1));
saddle_point_solver.SetBC(X_block.GetBlock(1));
X_block = 0.0;
saddle_point_solver.Mult(B_block, X_block);
if (Mpi::Root())
{
cout << "Done.\nIterations: "
<< saddle_point_solver.GetNumIterations()
<< "\nElapsed: " << tic_toc.RealTime() << endl;
}
X_block.SyncToBlocks();
x.SetFromTrueDofs(X_block.GetBlock(1));
const double error = x.ComputeL2Error(u_vec_coeff);
if (Mpi::Root()) { cout << "L2 error: " << error << endl; }
}
if (use_ams)
{
if (Mpi::Root()) { cout << "\nAMS solver... " << flush; }
tic_toc.Clear(); tic_toc.Start();
ParBilinearForm a(&fes_rt);
a.AddDomainIntegrator(new DivDivIntegrator(alpha_coeff));
a.AddDomainIntegrator(new VectorFEMassIntegrator(beta_coeff));
a.Assemble();
OperatorHandle A;
Vector B, X;
b.Assemble();
x.ProjectCoefficient(u_vec_coeff);
a.FormLinearSystem(ess_rt_dofs, x, b, A, X, B);
HypreParMatrix &Ah = *A.As<HypreParMatrix>();
std::unique_ptr<Solver> prec;
if (dim == 2) { prec.reset(new HypreAMS(Ah, &fes_rt)); }
else { prec.reset(new HypreADS(Ah, &fes_rt)); }
SolveCG(Ah, *prec, B, X);
x.SetFromTrueDofs(X);
const double error = x.ComputeL2Error(u_vec_coeff);
if (Mpi::Root()) { cout << "L2 error: " << error << endl; }
}
if (use_lor_ams)
{
const int b2_lor = BasisType::IntegratedGLL;
RT_FECollection fec_rt_lor(order-1, dim, b1, b2_lor);
ParFiniteElementSpace fes_rt_lor(&mesh, &fec_rt_lor);
ParLinearForm b_lor(&fes_rt_lor);
b_lor.AddDomainIntegrator(new VectorFEDomainLFIntegrator(f_vec_coeff));
b_lor.UseFastAssembly(true);
b_lor.Assemble();
if (Mpi::Root()) { cout << "\nLOR-AMS solver... " << flush; }
tic_toc.Clear(); tic_toc.Start();
ParBilinearForm a(&fes_rt_lor);
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a.AddDomainIntegrator(new DivDivIntegrator(alpha_coeff));
a.AddDomainIntegrator(new VectorFEMassIntegrator(beta_coeff));
a.Assemble();
ParGridFunction x_lor(&fes_rt_lor);
x_lor.ProjectCoefficient(u_vec_coeff);
OperatorHandle A;
Vector B, X;
a.FormLinearSystem(ess_rt_dofs, x_lor, b_lor, A, X, B);
std::unique_ptr<Solver> prec;
if (dim == 2) { prec.reset(new LORSolver<HypreAMS>(a, ess_rt_dofs)); }
else { prec.reset(new LORSolver<HypreADS>(a, ess_rt_dofs)); }
SolveCG(*A, *prec, B, X);
a.RecoverFEMSolution(X, b_lor, x_lor);
const double error = x_lor.ComputeL2Error(u_vec_coeff);
if (Mpi::Root()) { cout << "L2 error: " << error << endl; }
}
if (use_hybridization)
{
if (Mpi::Root()) { cout << "\nHybridization solver... " << flush; }
tic_toc.Clear(); tic_toc.Start();
DG_Interface_FECollection fec_hb(order-1, dim);
ParFiniteElementSpace fes_hb(&mesh, &fec_hb);
ParBilinearForm a(&fes_rt);
a.AddDomainIntegrator(new DivDivIntegrator(alpha_coeff));
a.AddDomainIntegrator(new VectorFEMassIntegrator(beta_coeff));
a.EnableHybridization(&fes_hb, new NormalTraceJumpIntegrator, ess_rt_dofs);
a.Assemble();
OperatorHandle A;
Vector B, X;
b.Assemble();
x.ProjectCoefficient(u_vec_coeff);
a.FormLinearSystem(ess_rt_dofs, x, b, A, X, B);
HypreBoomerAMG amg_hb(*A.As<HypreParMatrix>());
amg_hb.SetPrintLevel(0);
SolveCG(*A, amg_hb, B, X);
a.RecoverFEMSolution(X, b, x);
const double error = x.ComputeL2Error(u_vec_coeff);
if (Mpi::Root()) { cout << "L2 error: " << error << endl; }
}
return 0;
}
ParMesh LoadParMesh(const char *mesh_file, int ser_ref, int par_ref)
{
Mesh serial_mesh = Mesh::LoadFromFile(mesh_file);
for (int i = 0; i < ser_ref; ++i) { serial_mesh.UniformRefinement(); }
ParMesh mesh(MPI_COMM_WORLD, serial_mesh);
serial_mesh.Clear();
for (int i = 0; i < par_ref; ++i) { mesh.UniformRefinement(); }
return mesh;
}
void SolveCG(Operator &A, Solver &P, const Vector &B, Vector &X)
{
CGSolver cg(MPI_COMM_WORLD);
cg.SetAbsTol(0.0);
cg.SetRelTol(1e-12);
cg.SetMaxIter(500);
cg.SetPrintLevel(0);
cg.SetOperator(A);
cg.SetPreconditioner(P);
X = 0.0;
cg.Mult(B, X);
if (Mpi::Root())
{
cout << "Done.\nIterations: " << cg.GetNumIterations()
<< "\nElapsed: " << tic_toc.RealTime() << endl;
}
};
@@ -0,0 +1,387 @@
// 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 "general/forall.hpp"
#include "hdiv_linear_solver.hpp"
#include "discrete_divergence.hpp"
namespace mfem
{
/// Replace x[i] with 1.0/x[i] for all i.
void Reciprocal(Vector &x)
{
const int n = x.Size();
double *d_x = x.ReadWrite();
MFEM_FORALL(i, n, d_x[i] = 1.0/d_x[i]; );
}
/// Return a new HypreParMatrix with given diagonal entries
HypreParMatrix *MakeDiagonalMatrix(Vector &diag,
const ParFiniteElementSpace &fes)
{
const int n = diag.Size();
SparseMatrix diag_spmat;
diag_spmat.OverrideSize(n, n);
diag_spmat.GetMemoryI().New(n+1, Device::GetDeviceMemoryType());
diag_spmat.GetMemoryJ().New(n, Device::GetDeviceMemoryType());
diag_spmat.GetMemoryData().New(n, Device::GetDeviceMemoryType());
{
int *I = diag_spmat.WriteI();
int *J = diag_spmat.WriteJ();
double *A = diag_spmat.WriteData();
const double *d_diag = diag.Read();
MFEM_FORALL(i, n+1, I[i] = i;);
MFEM_FORALL(i, n,
{
J[i] = i;
A[i] = d_diag[i];
});
}
HYPRE_BigInt global_size = fes.GlobalTrueVSize();
HYPRE_BigInt *row_starts = fes.GetTrueDofOffsets();
HypreParMatrix D(MPI_COMM_WORLD, global_size, row_starts, &diag_spmat);
return new HypreParMatrix(D); // make a deep copy
}
const IntegrationRule &GetMassIntRule(FiniteElementSpace &fes_l2)
{
Mesh *mesh = fes_l2.GetMesh();
const FiniteElement *fe = fes_l2.GetFE(0);
return MassIntegrator::GetRule(*fe, *fe, *mesh->GetElementTransformation(0));
}
HdivSaddlePointSolver::HdivSaddlePointSolver(
ParMesh &mesh, ParFiniteElementSpace &fes_rt_, ParFiniteElementSpace &fes_l2_,
Coefficient &L_coeff_, Coefficient &R_coeff_, Coefficient &B_coeff_,
const Array<int> &ess_rt_dofs_, Mode mode_)
: minres(mesh.GetComm()),
order(fes_rt_.GetMaxElementOrder()),
fec_l2(order - 1, mesh.Dimension(), b2, mt),
fes_l2(&mesh, &fec_l2),
fec_rt(order - 1, mesh.Dimension(), b1, b2),
fes_rt(&mesh, &fec_rt),
ess_rt_dofs(ess_rt_dofs_),
basis_l2(fes_l2_),
basis_rt(fes_rt_),
convert_map_type(fes_l2_.GetFE(0)->GetMapType() == FiniteElement::VALUE),
mass_l2(&fes_l2),
mass_rt(&fes_rt),
L_coeff(L_coeff_),
R_coeff(R_coeff_),
B_coeff(B_coeff_),
mode(mode_),
qs(mesh, GetMassIntRule(fes_l2)),
W_coeff_qf(qs),
W_mix_coeff_qf(qs),
W_coeff(W_coeff_qf),
W_mix_coeff(W_mix_coeff_qf)
{
// If the user gives zero L coefficient, switch mode to DARCY_ZERO
auto *L_const_coeff = dynamic_cast<ConstantCoefficient*>(&L_coeff);
zero_l2_block = (L_const_coeff && L_const_coeff->constant == 0.0);
if (mode == Mode::GRAD_DIV)
{
MFEM_VERIFY(!zero_l2_block,
"Mode::GRAD_DIV incompatible with zero coefficient.");
}
mass_l2.AddDomainIntegrator(new MassIntegrator(W_coeff));
mass_l2.SetAssemblyLevel(AssemblyLevel::PARTIAL);
mass_rt.AddDomainIntegrator(new VectorFEMassIntegrator(&R_coeff));
mass_rt.AddBoundaryIntegrator(new MassIntegrator(B_coeff));
// mass_rt.SetAssemblyLevel(AssemblyLevel::PARTIAL);
D.reset(FormDiscreteDivergenceMatrix(fes_rt, fes_l2, ess_rt_dofs));
Dt.reset(D->Transpose());
// Versions without BCs needed for elimination
D_e.reset(FormDiscreteDivergenceMatrix(fes_rt, fes_l2, empty));
mass_rt.FormSystemMatrix(empty, R_e);
offsets.SetSize(3);
offsets[0] = 0;
offsets[1] = fes_l2.GetTrueVSize();
offsets[2] = offsets[1] + fes_rt.GetTrueVSize();
minres.SetAbsTol(0.0);
minres.SetRelTol(1e-12);
minres.SetMaxIter(500);
minres.SetPrintLevel(IterativeSolver::PrintLevel().None());
minres.iterative_mode = false;
R_diag.SetSize(fes_rt.GetTrueVSize());
L_diag.SetSize(fes_l2.GetTrueVSize());
S_inv.SetPrintLevel(0);
if (mode == Mode::DARCY && !zero_l2_block)
{
ParBilinearForm mass_l2_unweighted(&fes_l2);
QuadratureFunction det_J_qf(qs);
QuadratureFunctionCoefficient det_J_coeff(det_J_qf);
if (convert_map_type)
{
const auto flags = GeometricFactors::DETERMINANTS;
auto *geom = fes_l2.GetMesh()->GetGeometricFactors(qs.GetIntRule(0), flags);
det_J_qf = geom->detJ;
mass_l2_unweighted.AddDomainIntegrator(new MassIntegrator(det_J_coeff));
}
else
{
mass_l2_unweighted.AddDomainIntegrator(new MassIntegrator);
}
mass_l2_unweighted.SetAssemblyLevel(AssemblyLevel::PARTIAL);
mass_l2_unweighted.Assemble();
const int n_l2 = fes_l2.GetTrueVSize();
L_diag_unweighted.SetSize(n_l2);
mass_l2_unweighted.AssembleDiagonal(L_diag_unweighted);
}
Setup();
}
HdivSaddlePointSolver::HdivSaddlePointSolver(
ParMesh &mesh_, ParFiniteElementSpace &fes_rt_,
ParFiniteElementSpace &fes_l2_, Coefficient &L_coeff_, Coefficient &R_coeff_,
const Array<int> &ess_rt_dofs_, Mode mode_)
: HdivSaddlePointSolver(mesh_, fes_rt_, fes_l2_, L_coeff_, R_coeff_, zero,
ess_rt_dofs_, mode_)
{ }
HdivSaddlePointSolver::HdivSaddlePointSolver(
ParMesh &mesh, ParFiniteElementSpace &fes_rt_, ParFiniteElementSpace &fes_l2_,
Coefficient &R_coeff_, const Array<int> &ess_rt_dofs_)
: HdivSaddlePointSolver(mesh, fes_rt_, fes_l2_, zero, R_coeff_, zero,
ess_rt_dofs_, Mode::DARCY)
{ }
void HdivSaddlePointSolver::Setup()
{
const auto flags = GeometricFactors::DETERMINANTS;
auto *geom = fes_l2.GetMesh()->GetGeometricFactors(qs.GetIntRule(0), flags);
if (!zero_l2_block) { L_coeff.Project(W_coeff_qf); }
// In "grad-div mode", the transformation matrix is scaled by the coefficient
// of the mass and divergence matrices.
// In "Darcy mode", the transformation matrix is unweighted.
if (mode == Mode::GRAD_DIV) { W_mix_coeff_qf = W_coeff_qf; }
else { W_mix_coeff_qf = 1.0; }
// The transformation matrix has to be "mixed" value and integral map type,
// which means that the coefficient has to be scaled like the Jacobian
// determinant.
if (convert_map_type)
{
const int n = W_mix_coeff_qf.Size();
const double *d_detJ = geom->detJ.Read();
double *d_w_mix = W_mix_coeff_qf.ReadWrite();
double *d_w = W_coeff_qf.ReadWrite();
const bool zero_l2 = zero_l2_block;
MFEM_FORALL(i, n,
{
const double detJ = d_detJ[i];
if (!zero_l2) { d_w[i] *= detJ*detJ; }
d_w_mix[i] *= detJ;
});
}
L_inv.reset(new DGMassInverse(fes_l2, W_mix_coeff));
if (zero_l2_block)
{
A_11.reset();
}
else
{
mass_l2.Assemble();
mass_l2.AssembleDiagonal(L_diag);
mass_l2.FormSystemMatrix(empty, L);
A_11.reset(new RAPOperator(*L_inv, *L, *L_inv));
if (mode == GRAD_DIV)
{
L_diag_unweighted.SetSize(L_diag.Size());
BilinearForm mass_l2_mix(&fes_l2);
mass_l2_mix.AddDomainIntegrator(new MassIntegrator(W_mix_coeff));
mass_l2_mix.SetAssemblyLevel(AssemblyLevel::PARTIAL);
mass_l2_mix.Assemble();
mass_l2_mix.AssembleDiagonal(L_diag_unweighted);
}
const double *d_L_diag_unweighted = L_diag_unweighted.Read();
double *d_L_diag = L_diag.ReadWrite();
MFEM_FORALL(i, L_diag.Size(),
{
const double d = d_L_diag_unweighted[i];
d_L_diag[i] /= d*d;
});
}
// Reassmble the RT mass operator with the new coefficient
mass_rt.Update();
mass_rt.Assemble();
mass_rt.FormSystemMatrix(ess_rt_dofs, R);
// Form the updated approximate Schur complement
mass_rt.AssembleDiagonal(R_diag);
// Update the mass RT diagonal for essential DOFs
{
const int *d_I = ess_rt_dofs.Read();
double *d_R_diag = R_diag.ReadWrite();
MFEM_FORALL(i, ess_rt_dofs.Size(), d_R_diag[d_I[i]] = 1.0;);
}
// Form the approximate Schur complement
{
Reciprocal(R_diag);
std::unique_ptr<HypreParMatrix> R_diag_inv(MakeDiagonalMatrix(R_diag, fes_rt));
if (zero_l2_block)
{
S.reset(RAP(R_diag_inv.get(), Dt.get()));
}
else
{
std::unique_ptr<HypreParMatrix> D_Minv_Dt(RAP(R_diag_inv.get(), Dt.get()));
std::unique_ptr<HypreParMatrix> L_diag_inv(MakeDiagonalMatrix(L_diag, fes_l2));
S.reset(ParAdd(D_Minv_Dt.get(), L_diag_inv.get()));
}
}
// Reassemble the preconditioners
R_inv.reset(new OperatorJacobiSmoother(mass_rt, ess_rt_dofs));
S_inv.SetOperator(*S);
// Set up the block operators
A_block.reset(new BlockOperator(offsets));
// Omit the (1,1)-block when the L coefficient is identically zero.
if (A_11) { A_block->SetBlock(0, 0, A_11.get()); }
A_block->SetBlock(0, 1, D.get());
A_block->SetBlock(1, 0, Dt.get());
A_block->SetBlock(1, 1, R.Ptr(), -1.0);
D_prec.reset(new BlockDiagonalPreconditioner(offsets));
D_prec->SetDiagonalBlock(0, &S_inv);
D_prec->SetDiagonalBlock(1, R_inv.get());
minres.SetPreconditioner(*D_prec);
minres.SetOperator(*A_block);
}
void HdivSaddlePointSolver::EliminateBC(Vector &b) const
{
const int n_ess_dofs = ess_rt_dofs.Size();
if (fes_l2.GetParMesh()->ReduceInt(n_ess_dofs) == 0) { return; }
const int n_l2 = offsets[1];
const int n_rt = offsets[2]-offsets[1];
Vector bE(b, 0, n_l2);
Vector bF(b, n_l2, n_rt);
// SetBC must be called first
MFEM_VERIFY(x_bc.Size() == n_rt || n_ess_dofs == 0, "BCs not set");
// Create a vector z that has the BC values at essential DOFs, zero elsewhere
z.SetSize(n_rt);
z.UseDevice(true);
z = 0.0;
const int *d_I = ess_rt_dofs.Read();
const double *d_x_bc = x_bc.Read();
double *d_z = z.ReadWrite();
MFEM_FORALL(i, n_ess_dofs,
{
const int j = d_I[i];
d_z[j] = d_x_bc[j];
});
// Convert to the IntegratedGLL basis used internally
w.SetSize(n_rt);
basis_rt.MultInverse(z, w);
// Eliminate the BCs in the L2 RHS
D_e->Mult(-1.0, w, 1.0, bE);
// Eliminate the BCs in the RT RHS
// Flip the sign because the R block appears with multiplier -1
z.SetSize(n_rt);
R_e->Mult(w, z);
bF += z;
// Insert the RT BCs into the RHS at the essential DOFs.
const double *d_w = w.Read();
double *d_bF = bF.ReadWrite(); // Need read-write access to set subvector
MFEM_FORALL(i, n_ess_dofs,
{
const int j = d_I[i];
d_bF[j] = -d_w[j];
});
// Make sure the monolithic RHS is updated
bE.SyncAliasMemory(b);
bF.SyncAliasMemory(b);
}
void HdivSaddlePointSolver::Mult(const Vector &b, Vector &x) const
{
w.SetSize(fes_l2.GetTrueVSize());
b_prime.SetSize(b.Size());
x_prime.SetSize(x.Size());
// Transform RHS to the IntegratedGLL basis
Vector bE_prime(b_prime, offsets[0], offsets[1]-offsets[0]);
Vector bF_prime(b_prime, offsets[1], offsets[2]-offsets[1]);
const Vector bE(const_cast<Vector&>(b), offsets[0], offsets[1]-offsets[0]);
const Vector bF(const_cast<Vector&>(b), offsets[1], offsets[2]-offsets[1]);
z.SetSize(bE.Size());
basis_l2.MultTranspose(bE, z);
basis_rt.MultTranspose(bF, bF_prime);
// Transform by the inverse of the L2 mass matrix
L_inv->Mult(z, bE_prime);
// Update the monolithic transformed RHS
bE_prime.SyncAliasMemory(b_prime);
bF_prime.SyncAliasMemory(b_prime);
// Eliminate the RT essential BCs
EliminateBC(b_prime);
// Solve the transformed system
minres.Mult(b_prime, x_prime);
// Transform the solution back to the user's basis
Vector xE_prime(x_prime, offsets[0], offsets[1]-offsets[0]);
Vector xF_prime(x_prime, offsets[1], offsets[2]-offsets[1]);
Vector xE(x, offsets[0], offsets[1]-offsets[0]);
Vector xF(x, offsets[1], offsets[2]-offsets[1]);
z.SetSize(bE.Size()); // Size of z may have changed in EliminateBC
L_inv->Mult(xE_prime, z);
basis_l2.Mult(z, xE);
basis_rt.Mult(xF_prime, xF);
// Update the monolithic solution vector
xE.SyncAliasMemory(x);
xF.SyncAliasMemory(x);
}
} // namespace mfem
@@ -0,0 +1,190 @@
// 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 HDIV_LINEAR_SOLVER_HPP
#define HDIV_LINEAR_SOLVER_HPP
#include "mfem.hpp"
#include "change_basis.hpp"
#include <memory>
namespace mfem
{
/// @brief Solve the H(div) saddle-point system using MINRES with matrix-free
/// block-diagonal preconditioning.
///
/// See HdivSaddlePointSolver::HdivSaddlePointSolver for the problem
/// description.
class HdivSaddlePointSolver : public Solver
{
public:
/// Which type of saddle-point problem is being solved?
enum Mode
{
GRAD_DIV, ///< Grad-div problem.
DARCY ///< Darcy/mixed Poisson problem.
};
private:
MINRESSolver minres;
static constexpr int b1 = BasisType::GaussLobatto;
static constexpr int b2 = BasisType::IntegratedGLL;
static constexpr int mt = FiniteElement::INTEGRAL;
const int order;
// L2 and RT spaces, using the interpolation-histopolation bases
L2_FECollection fec_l2;
ParFiniteElementSpace fes_l2;
RT_FECollection fec_rt;
ParFiniteElementSpace fes_rt;
const Array<int> &ess_rt_dofs; ///< Essential BCs (in the RT space only).
// Change of basis operators
ChangeOfBasis_L2 basis_l2;
ChangeOfBasis_RT basis_rt;
/// Whether conversion from map type VALUE to INTEGRAL is required.
const bool convert_map_type;
ParBilinearForm mass_l2, mass_rt;
// Components needed for the block operator
OperatorHandle L, R, R_e; ///< Mass matrices.
std::unique_ptr<HypreParMatrix> D, Dt, D_e; ///< Divergence matrices.
std::shared_ptr<DGMassInverse> L_inv; ///< Inverse of the DG mass matrix.
std::shared_ptr<Operator> A_11; ///< (1,1)-block of the matrix
/// Diagonals of the mass matrices
Vector L_diag, R_diag, L_diag_unweighted;
// Components needed for the preconditioner
/// Jacobi preconditioner for the RT mass matrix.
std::unique_ptr<OperatorJacobiSmoother> R_inv;
std::unique_ptr<HypreParMatrix> S; ///< Approximate Schur complement.
HypreBoomerAMG S_inv; ///< AMG preconditioner for #S.
Array<int> offsets, empty;
/// The 2x2 block operator.
std::unique_ptr<BlockOperator> A_block;
/// The block-diagonal preconditioner.
std::unique_ptr<BlockDiagonalPreconditioner> D_prec;
Coefficient &L_coeff, &R_coeff, &B_coeff;
const Mode mode;
bool zero_l2_block = false;
QuadratureSpace qs;
QuadratureFunction W_coeff_qf, W_mix_coeff_qf;
QuadratureFunctionCoefficient W_coeff, W_mix_coeff;
ConstantCoefficient zero = ConstantCoefficient(0.0);
// Work vectors
mutable Vector b_prime, x_prime, x_bc, w, z;
public:
/// @brief Creates a solver for the H(div) saddle-point system.
///
/// The associated matrix is given by
///
/// [ L B ]
/// [ B^T -R ]
///
/// where L is the L2 mass matrix, R is the RT mass matrix, and B is the
/// divergence form (VectorFEDivergenceIntegrator).
///
/// Essential boundary conditions in the RT space are given by @a
/// ess_rt_dofs_. (Rows and columns are eliminated from R and columns are
/// eliminated from B).
///
/// The L block has coefficient @a L_coeff_ and the R block has coefficient
/// @a R_coeff_.
///
/// The parameter @a mode_ determines whether the block system corresponds to
/// a grad-div problem or a Darcy problem. Specifically, if @a mode_ is
/// Mode::GRAD_DIV, then the B and B^T blocks are also scaled by @a L_coeff_,
/// and if @a mode_ is Mode::DARCY, then the B and B^T blocks are unweighted.
///
/// Mode::GRAD_DIV corresponds to the grad-div problem
///
/// alpha u - grad ( beta div ( u )) = f,
///
/// where alpha is @a R_coeff_ and beta is @a L_coeff_.
///
/// Mode::DARCY corresponds to the Darcy-type problem
///
/// alpha p - div ( beta grad ( p )) = f,
///
/// where alpha is @a L_coeff and beta is @a R_coeff_. In this case, the
/// coefficient alpha is allowed to be zero (see also @link
/// HdivSaddlePointSolver(ParMesh&, ParFiniteElementSpace&,
/// ParFiniteElementSpace&, Coefficient&, const Array<int>&) the zero-block
/// HdivSaddlePointSolver constructor@endlink).
HdivSaddlePointSolver(ParMesh &mesh_,
ParFiniteElementSpace &fes_rt_,
ParFiniteElementSpace &fes_l2_,
Coefficient &L_coeff_,
Coefficient &R_coeff_,
Coefficient &B_coeff_,
const Array<int> &ess_rt_dofs_,
Mode mode_);
/// Same as the main constructor, but with B_coeff set to zero.
HdivSaddlePointSolver(ParMesh &mesh_,
ParFiniteElementSpace &fes_rt_,
ParFiniteElementSpace &fes_l2_,
Coefficient &L_coeff_,
Coefficient &R_coeff_,
const Array<int> &ess_rt_dofs_,
Mode mode_);
/// @brief Creates a linear solver for the case when the L2 diagonal block is
/// zero (for Darcy problems).
///
/// Equivalent to passing ConstantCoefficient(0.0) as @a L_coeff_ and
/// Mode::DARCY as @a mode_ to the @link HdivSaddlePointSolver(ParMesh&,
/// ParFiniteElementSpace&, ParFiniteElementSpace&, Coefficient &,
/// Coefficient&, const Array<int>&, Mode) the primary constructor@endlink.
HdivSaddlePointSolver(ParMesh &mesh_,
ParFiniteElementSpace &fes_rt_,
ParFiniteElementSpace &fes_l2_,
Coefficient &R_coeff_,
const Array<int> &ess_rt_dofs_);
/// @brief Build the linear operator and solver. Must be called when the
/// coefficients change.
void Setup();
/// Sets the Dirichlet boundary conditions at the RT essential DOFs.
void SetBC(const Vector &x_rt) { x_bc = x_rt; }
/// @brief Solve the linear system for L2 (scalar) and RT (flux) unknowns.
///
/// If the problem has essential boundary conditions (i.e. if @a ess_rt_dofs
/// is not empty), then SetBC() must be called before Mult().
void Mult(const Vector &b, Vector &x) const override;
/// No-op.
void SetOperator(const Operator &op) override { }
/// Get the number of MINRES iterations.
int GetNumIterations() const { return minres.GetNumIterations(); }
/// Eliminates the BCs (called internally, not public interface).
void EliminateBC(Vector &) const;
/// Return the offsets of the block system.
const Array<int> &GetOffsets() const { return offsets; }
/// Returns the internal MINRES solver.
MINRESSolver &GetMINRES() { return minres; }
};
} // namespace mfem
#endif
@@ -12,7 +12,7 @@
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/ipopt/,)
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/hdiv-linear-solver/,)
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
@@ -21,38 +21,29 @@ CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_EXAMPLES = exContactBlockTL
EXAMPLES = $(SEQ_EXAMPLES)
HDIV_HEADERS = hdiv_linear_solver.hpp discrete_divergence.hpp change_basis.hpp \
../solvers/lor_mms.hpp
HDIV_SRC = hdiv_linear_solver.cpp change_basis.cpp discrete_divergence.cpp
HDIV_OBJ = $(HDIV_SRC:.cpp=.o)
MINIAPPS = grad_div darcy residual rz
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all clean clean-build clean-exec
.PRECIOUS: %.o
# Remove built-in rule
all: $(MINIAPPS)
# Remove built-in rules
%: %.cpp
%.o: %.cpp
# Replace the default implicit rule for *.cpp files
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
$(MINIAPPS):%: %.o $(HDIV_OBJ)
$(MFEM_CXX) $(MFEM_LINK_FLAGS) $(HDIV_OBJ) -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
%.o: $(SRC)%.cpp $(HDIV_HEADERS) $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@
# Generate an error message if the MFEM library is not built and exit
$(MFEM_LIB_FILE):
@@ -61,8 +52,8 @@ $(MFEM_LIB_FILE):
clean: clean-build clean-exec
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES)
rm -f *.o *~ $(MINIAPPS)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -f exContactBlockTL.mesh exContactBlockTL-mesh.* exContactBlockTL-init.* exContactBlockTL-final.* ExampleContactBlockTL*
@rm -rf mesh.* sol.* ParaView
+205
View File
@@ -0,0 +1,205 @@
#include "mfem.hpp"
#include <iostream>
#include "hdiv_linear_solver.hpp"
#include "discrete_divergence.hpp"
using namespace std;
using namespace mfem;
ParMesh LoadParMesh(const char *mesh_file, int ser_ref = 0, int par_ref = 0);
double f(const Vector &xvec);
double g(const Vector &xvec);
int main(int argc, char *argv[])
{
Mpi::Init(argc, argv);
Hypre::Init();
const char *mesh_file = "../../data/star.mesh";
const char *device_config = "cpu";
int ser_ref = 1;
int par_ref = 1;
int order = 3;
bool mt_value = true;
bool darcy = true;
OptionsParser args(argc, argv);
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
args.AddOption(&ser_ref, "-rs", "--serial-refine",
"Number of times to refine the mesh in serial.");
args.AddOption(&par_ref, "-rp", "--parallel-refine",
"Number of times to refine the mesh in parallel.");
args.AddOption(&order, "-o", "--order", "Polynomial degree.");
args.AddOption(&mt_value, "-val", "--value", "-int", "--integral",
"Map type integral or value.");
args.AddOption(&darcy, "-da", "--darcy", "-g", "--grad-div",
"Grad-div or Darcy problem");
args.ParseCheck();
Device device(device_config);
if (Mpi::Root()) { device.Print(); }
ParMesh mesh = LoadParMesh(mesh_file, ser_ref, par_ref);
const int dim = mesh.Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "Spatial dimension must be 2 or 3.");
const int b1 = BasisType::GaussLobatto, b2 = BasisType::GaussLegendre;
const int mt = mt_value ? FiniteElement::VALUE : FiniteElement::INTEGRAL;
RT_FECollection fec_rt(order-1, dim, b1, b2);
L2_FECollection fec_l2(order-1, dim, b2, mt);
ParFiniteElementSpace fes_rt(&mesh, &fec_rt);
ParFiniteElementSpace fes_l2(&mesh, &fec_l2);
HYPRE_BigInt ndofs_rt = fes_rt.GlobalTrueVSize();
HYPRE_BigInt ndofs_l2 = fes_l2.GlobalTrueVSize();
if (Mpi::Root())
{
cout << "\nRT DOFs: " << ndofs_rt << "\nL2 DOFs: " << ndofs_l2 << endl;
}
Array<int> ess_rt_dofs;
FunctionCoefficient a_coeff(f);
FunctionCoefficient b_coeff(g);
ConstantCoefficient one(1.0);
Coefficient &div_coeff = darcy ? (Coefficient&)one : (Coefficient&)a_coeff;
// Solve the system with the saddle-point solver
const auto solver_mode = darcy ? HdivSaddlePointSolver::Mode::DARCY
: HdivSaddlePointSolver::Mode::GRAD_DIV;
HdivSaddlePointSolver saddle_point_solver(
mesh, fes_rt, fes_l2, a_coeff, b_coeff, ess_rt_dofs, solver_mode);
const Array<int> &offsets = saddle_point_solver.GetOffsets();
BlockVector X_block(offsets), B_block(offsets);
saddle_point_solver.GetMINRES().SetAbsTol(1e-18);
saddle_point_solver.GetMINRES().SetRelTol(1e-20);
saddle_point_solver.GetMINRES().SetPrintLevel(
IterativeSolver::PrintLevel().FirstAndLast());
X_block = 0.0;
B_block.Randomize(1);
B_block.GetBlock(0) = 0.0;
if (Mpi::Root()) { std::cout << "Saddle point solver... " << std::endl; }
saddle_point_solver.Mult(B_block, X_block);
// Form the matrix-based system
ParBilinearForm w(&fes_l2);
w.AddDomainIntegrator(new MassIntegrator(a_coeff));
w.Assemble();
w.Finalize();
std::unique_ptr<HypreParMatrix> W(w.ParallelAssemble());
ParMixedBilinearForm b(&fes_rt, &fes_l2);
b.AddDomainIntegrator(new VectorFEDivergenceIntegrator(div_coeff));
b.Assemble();
b.Finalize();
std::unique_ptr<HypreParMatrix> B(b.ParallelAssemble());
std::unique_ptr<HypreParMatrix> Bt(B->Transpose());
ParBilinearForm m(&fes_rt);
m.AddDomainIntegrator(new VectorFEMassIntegrator(b_coeff));
m.Assemble();
m.Finalize();
std::unique_ptr<HypreParMatrix> M(m.ParallelAssemble());
BlockOperator A(offsets);
A.SetBlock(0, 0, W.get());
A.SetBlock(0, 1, B.get());
A.SetBlock(1, 0, Bt.get());
A.SetBlock(1, 1, M.get(), -1.0);
// Compute the residual
BlockVector Y_block(offsets);
A.Mult(X_block, Y_block);
Y_block -= B_block;
auto nrm2 = [](const Vector &x)
{
return sqrt(InnerProduct(MPI_COMM_WORLD, x, x));
};
const double resnorm1 = nrm2(Y_block)/nrm2(B_block);
if (Mpi::Root()) { std::cout << "Linear residual norm: " << resnorm1 << "\n\n"; }
// Solve the system with a matrix-based solver (see ex5p)
HypreParVector Md(MPI_COMM_WORLD, M->GetGlobalNumRows(),
M->GetRowStarts());
M->GetDiag(Md);
std::unique_ptr<HypreParMatrix> MinvBt(B->Transpose());
MinvBt->InvScaleRows(Md);
std::unique_ptr<HypreParMatrix> S(ParMult(B.get(), MinvBt.get()));
HypreDiagScale M_inv(*M);
HypreBoomerAMG S_inv(*S);
S_inv.SetPrintLevel(0);
BlockDiagonalPreconditioner D(offsets);
D.SetDiagonalBlock(0, &S_inv);
D.SetDiagonalBlock(1, &M_inv);
X_block = 0.0;
MINRESSolver minres(MPI_COMM_WORLD);
minres.SetAbsTol(1e-18);
minres.SetRelTol(1e-20);
minres.SetMaxIter(500);
minres.SetOperator(A);
minres.SetPreconditioner(D);
minres.SetPrintLevel(IterativeSolver::PrintLevel().FirstAndLast());
if (Mpi::Root()) { std::cout << "Matrix-based solver... " << std::endl; }
minres.Mult(B_block, X_block);
A.Mult(X_block, Y_block);
Y_block -= B_block;
const double resnorm2 = nrm2(Y_block)/nrm2(B_block);
if (Mpi::Root()) { std::cout << "Linear residual norm: " << resnorm2 << "\n\n"; }
return 0;
}
ParMesh LoadParMesh(const char *mesh_file, int ser_ref, int par_ref)
{
Mesh serial_mesh = Mesh::LoadFromFile(mesh_file);
for (int i = 0; i < ser_ref; ++i) { serial_mesh.UniformRefinement(); }
ParMesh mesh(MPI_COMM_WORLD, serial_mesh);
serial_mesh.Clear();
for (int i = 0; i < par_ref; ++i) { mesh.UniformRefinement(); }
return mesh;
}
double f(const Vector &xvec)
{
const int dim = xvec.Size();
const double x = xvec[0], y = xvec[1];
if (dim == 2)
{
return 2*(2.0 + sin(x)*sin(y));
}
else // dim == 3
{
const double z = xvec[2];
return 3*(2.0 + sin(x)*sin(y)*sin(z));
}
}
double g(const Vector &xvec)
{
const int dim = xvec.Size();
const double x = xvec[0], y = xvec[1];
if (dim == 2)
{
return 2*(2.0 + cos(x)*cos(y));
}
else // dim == 3
{
const double z = xvec[2];
return 3*(2.0 + cos(x)*cos(y)*cos(z));
}
}
+207
View File
@@ -0,0 +1,207 @@
#include "mfem.hpp"
#include <iostream>
#include <memory>
#include "discrete_divergence.hpp"
#include "hdiv_linear_solver.hpp"
#include "../solvers/lor_mms.hpp"
using namespace std;
using namespace mfem;
ParMesh LoadParMesh(const char *mesh_file, int ser_ref = 0, int par_ref = 0);
double one_over_r(const Vector &xvec)
{
// xvec = [z, r]
const double r = xvec[1];
return r == 0.0 ? 0.0 : 1.0/r;
}
double f_rz(const Vector &xvec)
{
const double z = xvec[0];
const double r = xvec[1];
// alpha is the coefficient in the equation -Delta(u) + alpha*u = f
const double alpha = 1.0;
const double f = -cos(z)*(4*sin(r) + 5*r*cos(r) - (2 + alpha)*r*r*sin(r));
// scale integral by r because of coordinate transformation
return r*f;
}
double u_rz(const Vector &xvec)
{
const double z = xvec[0];
const double r = xvec[1];
return r*r*sin(r)*cos(z);
}
class RobinCoefficient : public Coefficient
{
double Eval(ElementTransformation &T, const IntegrationPoint &ip) override
{
double xdata[3];
Vector xvec(xdata, 3);
T.Transform(ip, xvec);
const int dim = xvec.Size();
Vector n(dim);
CalcOrtho(T.Jacobian(), n);
n /= n.Norml2();
const double p_val = u_rz(xvec);
const double z = xvec[0];
const double r = xvec[1];
if (dim == 2)
{
const double dpdz = -r*r*sin(r)*sin(z);
const double dpdr = r*cos(z)*(r*cos(r) + 2*sin(r));
const double u_val = n[0]*dpdz + n[1]*dpdr;
return p_val + u_val;
}
else
{
MFEM_ABORT("Not implemented");
}
return 0.0;
}
};
int main(int argc, char *argv[])
{
Mpi::Init(argc, argv);
Hypre::Init();
const char *mesh_file = "rz.mesh";
const char *device_config = "cpu";
int ser_ref = 1;
int par_ref = 1;
int order = 3;
OptionsParser args(argc, argv);
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
args.AddOption(&ser_ref, "-rs", "--serial-refine",
"Number of times to refine the mesh in serial.");
args.AddOption(&par_ref, "-rp", "--parallel-refine",
"Number of times to refine the mesh in parallel.");
args.AddOption(&order, "-o", "--order", "Polynomial degree.");
args.ParseCheck();
Device device(device_config);
if (Mpi::Root()) { device.Print(); }
ParMesh mesh = LoadParMesh(mesh_file, ser_ref, par_ref);
const int dim = mesh.Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "Spatial dimension must be 2 or 3.");
const int b1 = BasisType::GaussLobatto, b2 = BasisType::GaussLegendre;
const int mt = FiniteElement::VALUE;
RT_FECollection fec_rt(order-1, dim, b1, b2);
L2_FECollection fec_l2(order-1, dim, b2, mt);
ParFiniteElementSpace fes_rt(&mesh, &fec_rt);
ParFiniteElementSpace fes_l2(&mesh, &fec_l2);
HYPRE_BigInt ndofs_rt = fes_rt.GlobalTrueVSize();
HYPRE_BigInt ndofs_l2 = fes_l2.GlobalTrueVSize();
if (Mpi::Root())
{
cout << "\nRT DOFs: " << ndofs_rt << "\nL2 DOFs: " << ndofs_l2 << endl;
}
Array<int> ess_rt_dofs; // empty
// f is the RHS, u is the exact solution
FunctionCoefficient f_coeff(f_rz), u_coeff(u_rz);
// Assemble the right-hand side for the scalar (L2) unknown.
ParLinearForm b_l2(&fes_l2);
// f_coeff has to include the r scaling for the coordinate transformation
b_l2.AddDomainIntegrator(new DomainLFIntegrator(f_coeff));
b_l2.UseFastAssembly(true);
b_l2.Assemble();
// Coefficient to enforce Robin boundary condition
RobinCoefficient bc_coeff;
// Enforce Robin boundary conditions by adding the boundary term to the flux
// equation.
ParLinearForm b_rt(&fes_rt);
b_rt.AddBoundaryIntegrator(new VectorFEBoundaryFluxLFIntegrator(bc_coeff));
b_rt.UseFastAssembly(true);
b_rt.Assemble();
if (Mpi::Root()) { cout << "\nSaddle point solver... " << flush; }
tic_toc.Clear(); tic_toc.Start();
// Have to scale the RT mass matrix by (1/r)
FunctionCoefficient r_recip_coeff(one_over_r);
// Have to scale the L2 mass matrix by r
FunctionCoefficient r_coeff([](const Vector &xvec) { return xvec[1]; });
const auto solver_mode = HdivSaddlePointSolver::Mode::DARCY;
HdivSaddlePointSolver saddle_point_solver(
mesh, fes_rt, fes_l2, r_coeff, r_recip_coeff, r_recip_coeff, ess_rt_dofs, solver_mode);
const Array<int> &offsets = saddle_point_solver.GetOffsets();
BlockVector X_block(offsets), B_block(offsets);
b_l2.ParallelAssemble(B_block.GetBlock(0));
b_rt.ParallelAssemble(B_block.GetBlock(1));
B_block.SyncFromBlocks();
X_block = 0.0;
saddle_point_solver.Mult(B_block, X_block);
X_block.SyncToBlocks();
if (Mpi::Root())
{
cout << "Done.\nIterations: "
<< saddle_point_solver.GetNumIterations()
<< "\nElapsed: " << tic_toc.RealTime() << endl;
}
ParGridFunction x(&fes_l2);
x.SetFromTrueDofs(X_block.GetBlock(0));
ParGridFunction flux(&fes_rt);
flux.SetFromTrueDofs(X_block.GetBlock(1));
const double error = x.ComputeL2Error(u_coeff);
if (Mpi::Root()) { cout << "L2 error: " << error << endl; }
ParGridFunction u_ex(&fes_l2), er(&fes_l2);
u_ex.ProjectCoefficient(u_coeff);
er = x;
er -= u_ex;
ParaViewDataCollection pv("RZ", &mesh);
pv.SetPrefixPath("ParaView");
pv.SetHighOrderOutput(true);
pv.SetLevelsOfDetail(order + 1);
pv.RegisterField("u", &x);
pv.RegisterField("flux", &flux);
pv.RegisterField("exact", &u_ex);
pv.RegisterField("error", &er);
pv.SetCycle(0);
pv.SetTime(0);
pv.Save();
return 0;
}
ParMesh LoadParMesh(const char *mesh_file, int ser_ref, int par_ref)
{
Mesh serial_mesh = Mesh::LoadFromFile(mesh_file);
for (int i = 0; i < ser_ref; ++i) { serial_mesh.UniformRefinement(); }
ParMesh mesh(MPI_COMM_WORLD, serial_mesh);
serial_mesh.Clear();
for (int i = 0; i < par_ref; ++i) { mesh.UniformRefinement(); }
return mesh;
}
+35
View File
@@ -0,0 +1,35 @@
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
2
elements
1
1 3 0 1 2 3
boundary
4
1 1 0 1
2 1 1 2
3 1 2 3
4 1 3 0
vertices
4
2
0 0
12 0
12 7.5
0 7.5
-4
View File
@@ -62,10 +62,6 @@ add_mfem_miniapp(minimal-surface
MAIN minimal-surface.cpp
LIBRARIES mfem)
add_mfem_miniapp(reflector
MAIN reflector.cpp
LIBRARIES mfem)
add_mfem_miniapp(toroid
MAIN toroid.cpp
LIBRARIES mfem)
+3 -5
View File
@@ -26,7 +26,7 @@ MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_MINIAPPS = mobius-strip klein-bottle toroid trimmer twist mesh-explorer\
shaper extruder mesh-optimizer minimal-surface polar-nc reflector
shaper extruder mesh-optimizer minimal-surface polar-nc
PAR_MINIAPPS = pmesh-optimizer pminimal-surface
ifeq ($(MFEM_USE_MPI),NO)
MINIAPPS = $(SEQ_MINIAPPS)
@@ -91,8 +91,6 @@ minimal-surface-test-seq: minimal-surface
@$(call mfem-test,$<,, Meshing miniapp)
pminimal-surface-test-par: pminimal-surface
@$(call mfem-test,$<, $(RUN_MPI), Parallel meshing miniapp)
reflector-test-seq: reflector
@$(call mfem-test-file,$<,, Meshing miniapp,reflected.mesh)
# Testing: Specific execution options
mesh-explorer-test-seq:
@@ -110,14 +108,14 @@ clean: clean-build clean-exec
clean-build:
rm -f *.o *~ mobius-strip klein-bottle toroid twist
rm -f mesh-explorer shaper extruder trimmer reflector
rm -f mesh-explorer shaper extruder trimmer
rm -f mesh-optimizer pmesh-optimizer polar-nc
rm -f minimal-surface pminimal-surface
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -f mobius-strip.mesh klein-bottle.mesh mesh-explorer.mesh
@rm -f toroid-*.mesh twist-*.mesh trimmer.mesh reflected.mesh
@rm -f toroid-*.mesh twist-*.mesh trimmer.mesh
@rm -f partitioning.txt shaper.mesh extruder.mesh
@rm -f optimized* perturbed* polar-nc.mesh
@rm -rf mesh-explorer-{visit,paraview}*
+22 -24
View File
@@ -57,8 +57,10 @@
// Adapted discrete size+aspect_ratio:
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -qo 6 -ex -st 1 -nor
// Adapted discrete size+orientation:
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -fd -nor
// Adapted discrete size+orientation (requires GSLIB):
// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -fd -ae 1 -nor
// Adapted discrete aspect-ratio+orientation (requires GSLIB):
// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 8 -ni 10 -bnd -qt 1 -qo 8 -fd -ae 1
// Adapted discrete aspect ratio (3D):
// mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -bnd -qt 1 -qo 8
//
@@ -84,7 +86,7 @@
// Blade limited shape:
// mesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -bnd -qt 1 -qo 8 -lc 5000
// ICF shape and equal size:
// mesh-optimizer -o 3 -mid 80 -bec -tid 2 -ni 25 -ls 3 -art 2 -qo 5
// mesh-optimizer -o 3 -mid 9 -tid 2 -ni 25 -ls 3 -art 2 -qo 5
// ICF shape and initial size:
// mesh-optimizer -o 3 -mid 9 -tid 3 -ni 30 -ls 3 -bnd -qt 1 -qo 8
// ICF shape:
@@ -138,7 +140,6 @@ int main(int argc, char *argv[])
int max_lin_iter = 100;
bool move_bnd = true;
int combomet = 0;
bool bal_expl_combo = false;
bool hradaptivity = false;
int h_metric_id = -1;
bool normalization = false;
@@ -257,9 +258,6 @@ int main(int argc, char *argv[])
"0: Use single metric\n\t"
"1: Shape + space-dependent size given analytically\n\t"
"2: Shape + adapted size given discretely; shared target");
args.AddOption(&bal_expl_combo, "-bec", "--balance-explicit-combo",
"-no-bec", "--balance-explicit-combo",
"Automatic balancing of explicit combo metrics.");
args.AddOption(&hradaptivity, "-hr", "--hr-adaptivity", "-no-hr",
"--no-hr-adaptivity",
"Enable hr-adaptivity.");
@@ -742,9 +740,20 @@ int main(int argc, char *argv[])
#endif
}
ConstantCoefficient size_coeff(0.1*0.1);
size.ProjectCoefficient(size_coeff);
tc->SetSerialDiscreteTargetSize(size);
if (metric_id == 14 || metric_id == 36)
{
ConstantCoefficient size_coeff(0.1*0.1);
size.ProjectCoefficient(size_coeff);
tc->SetSerialDiscreteTargetSize(size);
}
if (metric_id == 85)
{
FunctionCoefficient aspr_coeff(discrete_aspr_2d);
aspr.ProjectCoefficient(aspr_coeff);
DiffuseField(aspr,2);
tc->SetSerialDiscreteTargetAspectRatio(aspr);
}
FunctionCoefficient ori_coeff(discrete_ori_2d);
ori.ProjectCoefficient(ori_coeff);
@@ -771,16 +780,6 @@ int main(int argc, char *argv[])
target_c = new TargetConstructor(target_t);
}
target_c->SetNodes(x0);
// Automatically balanced gamma in composite metrics.
auto metric_combo = dynamic_cast<TMOP_Combo_QualityMetric *>(metric);
if (metric_combo && bal_expl_combo)
{
Vector bal_weights;
metric_combo->ComputeBalancedWeights(x, *target_c, bal_weights);
metric_combo->SetWeights(bal_weights);
}
TMOP_QualityMetric *metric_to_use = barrier_type > 0 || worst_case_type > 0
? untangler_metric
: metric;
@@ -791,6 +790,7 @@ int main(int argc, char *argv[])
tmop_integ->ComputeUntangleMetricQuantiles(x, *fespace);
}
// Finite differences for computations of derivatives.
if (fdscheme)
{
@@ -1208,7 +1208,6 @@ int main(int argc, char *argv[])
mesh->Print(mesh_ofs);
}
// Report the final energy of the functional.
const double fin_energy = a.GetGridFunctionEnergy(x) /
(hradaptivity ? mesh->GetNE() : 1);
double fin_metric_energy = fin_energy;
@@ -1233,7 +1232,7 @@ int main(int argc, char *argv[])
cout << "The strain energy decreased by: "
<< (init_energy - fin_energy) * 100.0 / init_energy << " %." << endl;
// Visualize the final mesh and metric values.
// 16. Visualize the final mesh and metric values.
if (visualization)
{
char title[] = "Final metric values";
@@ -1247,7 +1246,6 @@ int main(int argc, char *argv[])
600, 600, 300, 300);
}
// Visualize fitting surfaces and report fitting errors.
if (surface_fit_const > 0.0)
{
if (visualization)
@@ -1264,7 +1262,7 @@ int main(int argc, char *argv[])
<< "Max fitting error: " << err_max << std::endl;
}
// Visualize the mesh displacement.
// 17. Visualize the mesh displacement.
if (visualization)
{
osockstream sock(19916, "localhost");
+18
View File
@@ -84,6 +84,24 @@ double discrete_ori_2d(const Vector &x)
return M_PI * x(1) * (1.0 - x(1)) * cos(2 * M_PI * x(0));
}
double discrete_aspr_2d(const Vector &x)
{
double xc = x(0)-0.5, yc = x(1)-0.5;
double th = 22.5*M_PI/180.;
double xn = cos(th)*xc + sin(th)*yc;
double yn = -sin(th)*xc + cos(th)*yc;
xc = xn; yc = yn;
double tfac = 20;
double s1 = 3;
double s2 = 2;
double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1)
- std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1);
if (wgt > 1) { wgt = 1; }
if (wgt < 0) { wgt = 0; }
return 0.1 + 1*(1-wgt)*(1-wgt);
}
void discrete_aspr_3d(const Vector &x, Vector &v)
{
int dim = x.Size();
+8 -12
View File
@@ -77,6 +77,7 @@ constexpr Element::Type QUAD = Element::QUADRILATERAL;
constexpr double NL_DMAX = std::numeric_limits<double>::max();
// Static variables for GLVis
static socketstream glvis;
constexpr int GLVIZ_W = 1024;
constexpr int GLVIZ_H = 1024;
constexpr int visport = 19916;
@@ -117,10 +118,8 @@ protected:
Opt &opt;
Mesh *mesh;
Array<int> bc;
socketstream glvis;
H1_FECollection *fec;
FiniteElementSpace *fes;
public:
// Reading from mesh file
Surface(Opt &opt, const char *file): Mesh(file, true), opt(opt) { }
@@ -158,7 +157,7 @@ public:
// Initialize GLVis server if 'visualization' is set
if (opt.vis) { opt.vis = glvis.open(vishost, visport) == 0; }
// Send to GLVis the first mesh
if (opt.vis) { Visualize(glvis, opt, mesh, GLVIZ_W, GLVIZ_H); }
if (opt.vis) { Visualize(opt, mesh, GLVIZ_W, GLVIZ_H); }
// Create and launch the surface solver
if (opt.by_vdim)
{
@@ -171,7 +170,7 @@ public:
if (opt.vis && opt.snapshot)
{
opt.keys = "Sq";
Visualize(glvis, opt, mesh, mesh->GetNodes());
Visualize(opt, mesh, mesh->GetNodes());
}
return 0;
}
@@ -244,8 +243,7 @@ public:
}
// Initialize visualization of some given mesh
static void Visualize(socketstream &glvis,
Opt &opt, const Mesh *mesh,
static void Visualize(Opt &opt, const Mesh *mesh,
const int w, const int h,
const GridFunction *sol = nullptr)
{
@@ -261,8 +259,7 @@ public:
}
// Visualize some solution on the given mesh
static void Visualize(socketstream &glvis,
const Opt &opt, const Mesh *mesh,
static void Visualize(const Opt &opt, const Mesh *mesh,
const GridFunction *sol = nullptr)
{
const GridFunction &solution = sol ? *sol : *mesh->GetNodes();
@@ -327,7 +324,7 @@ public:
for (int i=0; i < opt.niters; ++i)
{
if (opt.amr) { Amr(); }
if (opt.vis) { Surface::Visualize(S.glvis, opt, S.mesh); }
if (opt.vis) { Surface::Visualize(opt, S.mesh); }
if (!opt.id) { mfem::out << "Iteration " << i << ": "; }
S.mesh->NodesUpdated();
a.Update();
@@ -1240,9 +1237,8 @@ static int Problem1(Opt &opt)
GridFunction uold(&fes), u(&fes), b(&fes);
FunctionCoefficient u0_fc(u0);
u.ProjectCoefficient(u0_fc);
socketstream glvis;
if (opt.vis) { opt.vis = glvis.open(vishost, visport) == 0; }
if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, GLVIZ_W, GLVIZ_H, &u); }
if (opt.vis) { Surface::Visualize(opt, &mesh, GLVIZ_W, GLVIZ_H, &u); }
CGSolver cg;
cg.SetRelTol(EPS);
cg.SetAbsTol(EPS*EPS);
@@ -1274,7 +1270,7 @@ static int Problem1(Opt &opt)
mfem::out << "Iteration " << i << ", norm: " << norm
<< ", area: " << area << std::endl;
}
if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, &u); }
if (opt.vis) { Surface::Visualize(opt, &mesh, &u); }
if (opt.print) { Surface::Print(opt, &mesh, &u); }
if (norm < NRM) { break; }
}
+28 -24
View File
@@ -57,8 +57,10 @@
// Adapted discrete size+aspect_ratio:
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -qo 6 -ex -st 1 -nor
// Adapted discrete size+orientation:
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -fd -nor
// Adapted discrete size+orientation (requires GSLIB):
// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -fd -ae 1 -nor
// Adapted discrete aspect-ratio+orientation (requires GSLIB):
// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 8 -ni 10 -bnd -qt 1 -qo 8 -fd -ae 1
// Adapted discrete aspect ratio (3D):
// mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -bnd -qt 1 -qo 8
//
@@ -84,7 +86,7 @@
// Blade limited shape:
// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -bnd -qt 1 -qo 8 -lc 5000
// ICF shape and equal size:
// mpirun -np 4 pmesh-optimizer -o 3 -mid 80 -bec -tid 2 -ni 25 -ls 3 -art 2 -qo 5
// mpirun -np 4 pmesh-optimizer -o 3 -mid 9 -tid 2 -ni 25 -ls 3 -art 2 -qo 5
// ICF shape and initial size:
// mpirun -np 4 pmesh-optimizer -o 3 -mid 9 -tid 3 -ni 30 -ls 3 -bnd -qt 1 -qo 8
// ICF shape:
@@ -148,7 +150,6 @@ int main (int argc, char *argv[])
int max_lin_iter = 100;
bool move_bnd = true;
int combomet = 0;
bool bal_expl_combo = false;
bool hradaptivity = false;
int h_metric_id = -1;
bool normalization = false;
@@ -269,9 +270,6 @@ int main (int argc, char *argv[])
"0: Use single metric\n\t"
"1: Shape + space-dependent size given analytically\n\t"
"2: Shape + adapted size given discretely; shared target");
args.AddOption(&bal_expl_combo, "-bec", "--balance-explicit-combo",
"-no-bec", "--balance-explicit-combo",
"Automatic balancing of explicit combo metrics.");
args.AddOption(&hradaptivity, "-hr", "--hr-adaptivity", "-no-hr",
"--no-hr-adaptivity",
"Enable hr-adaptivity.");
@@ -374,6 +372,9 @@ int main (int argc, char *argv[])
// transformation of the reference element.
pmesh->SetNodalFESpace(pfespace);
// 6. Set up an empty right-hand side vector b, which is equivalent to b=0.
Vector b(0);
// 7. Get the mesh nodes (vertices and other degrees of freedom in the finite
// element space) as a finite element grid function in fespace. Note that
// changing x automatically changes the shapes of the mesh elements.
@@ -773,9 +774,20 @@ int main (int argc, char *argv[])
#endif
}
ConstantCoefficient size_coeff(0.1*0.1);
size.ProjectCoefficient(size_coeff);
tc->SetParDiscreteTargetSize(size);
if (metric_id == 14 || metric_id == 36)
{
ConstantCoefficient size_coeff(0.1*0.1);
size.ProjectCoefficient(size_coeff);
tc->SetParDiscreteTargetSize(size);
}
if (metric_id == 85)
{
FunctionCoefficient aspr_coeff(discrete_aspr_2d);
aspr.ProjectCoefficient(aspr_coeff);
DiffuseField(aspr,2);
tc->SetParDiscreteTargetAspectRatio(aspr);
}
FunctionCoefficient ori_coeff(discrete_ori_2d);
ori.ProjectCoefficient(ori_coeff);
@@ -799,21 +811,12 @@ int main (int argc, char *argv[])
if (myid == 0) { cout << "Unknown target_id: " << target_id << endl; }
return 3;
}
if (target_c == NULL)
{
target_c = new TargetConstructor(target_t, MPI_COMM_WORLD);
}
target_c->SetNodes(x0);
// Automatically balanced gamma in composite metrics.
auto metric_combo = dynamic_cast<TMOP_Combo_QualityMetric *>(metric);
if (metric_combo && bal_expl_combo)
{
Vector bal_weights;
metric_combo->ComputeBalancedWeights(x, *target_c, bal_weights);
metric_combo->SetWeights(bal_weights);
}
TMOP_QualityMetric *metric_to_use = barrier_type > 0 || worst_case_type > 0
? untangler_metric
: metric;
@@ -824,6 +827,7 @@ int main (int argc, char *argv[])
tmop_integ->ComputeUntangleMetricQuantiles(x, *pfespace);
}
// Finite differences for computations of derivatives.
if (fdscheme)
{
@@ -1252,7 +1256,7 @@ int main (int argc, char *argv[])
pmesh->PrintAsOne(mesh_ofs);
}
// Report the final energy of the functional.
// Compute the final energy of the functional.
const double fin_energy = a.GetParGridFunctionEnergy(x) /
(hradaptivity ? pmesh->GetGlobalNE() : 1);
double fin_metric_energy = fin_energy;
@@ -1280,7 +1284,7 @@ int main (int argc, char *argv[])
<< (init_energy - fin_energy) * 100.0 / init_energy << " %." << endl;
}
// Visualize the final mesh and metric values.
// 18. Visualize the final mesh and metric values.
if (visualization)
{
char title[] = "Final metric values";
@@ -1294,7 +1298,6 @@ int main (int argc, char *argv[])
600, 600, 300, 300);
}
// Visualize fitting surfaces and report fitting errors.
if (surface_fit_const > 0.0)
{
if (visualization)
@@ -1314,7 +1317,7 @@ int main (int argc, char *argv[])
}
}
// Visualize the mesh displacement.
// 19. Visualize the mesh displacement.
if (visualization)
{
x0 -= x;
@@ -1335,6 +1338,7 @@ int main (int argc, char *argv[])
}
}
// 20. Free the used memory.
delete S;
delete S_prec;
delete target_c2;
+8 -11
View File
@@ -77,6 +77,7 @@ constexpr Element::Type QUAD = Element::QUADRILATERAL;
constexpr double NL_DMAX = std::numeric_limits<double>::max();
// Static variables for GLVis
static socketstream glvis;
constexpr int GLVIZ_W = 1024;
constexpr int GLVIZ_H = 1024;
constexpr int visport = 19916;
@@ -117,7 +118,6 @@ protected:
Opt &opt;
ParMesh *mesh;
Array<int> bc;
socketstream glvis;
H1_FECollection *fec;
ParFiniteElementSpace *fes;
public:
@@ -157,7 +157,7 @@ public:
// Initialize GLVis server if 'visualization' is set
if (opt.vis) { opt.vis = glvis.open(vishost, visport) == 0; }
// Send to GLVis the first mesh
if (opt.vis) { Visualize(glvis, opt, mesh, GLVIZ_W, GLVIZ_H); }
if (opt.vis) { Visualize(opt, mesh, GLVIZ_W, GLVIZ_H); }
// Create and launch the surface solver
if (opt.by_vdim)
{
@@ -170,7 +170,7 @@ public:
if (opt.vis && opt.snapshot)
{
opt.keys = "Sq";
Visualize(glvis, opt, mesh, mesh->GetNodes());
Visualize(opt, mesh, mesh->GetNodes());
}
return 0;
}
@@ -243,8 +243,7 @@ public:
}
// Initialize visualization of some given mesh
static void Visualize(socketstream &glvis,
Opt &opt, const Mesh *mesh,
static void Visualize(Opt &opt, const Mesh *mesh,
const int w, const int h,
const GridFunction *sol = nullptr)
{
@@ -260,8 +259,7 @@ public:
}
// Visualize some solution on the given mesh
static void Visualize(socketstream &glvis,
const Opt &opt, const Mesh *mesh,
static void Visualize(const Opt &opt, const Mesh *mesh,
const GridFunction *sol = nullptr)
{
glvis << "parallel " << opt.sz << " " << opt.id << "\n";
@@ -330,7 +328,7 @@ public:
for (int i=0; i < opt.niters; ++i)
{
if (opt.amr) { Amr(); }
if (opt.vis) { Surface::Visualize(S.glvis, opt, S.mesh); }
if (opt.vis) { Surface::Visualize(opt, S.mesh); }
if (!opt.id) { mfem::out << "Iteration " << i << ": "; }
S.mesh->NodesUpdated();
a.Update();
@@ -1248,9 +1246,8 @@ static int Problem1(Opt &opt)
ParGridFunction uold(&fes), u(&fes), b(&fes);
FunctionCoefficient u0_fc(u0);
u.ProjectCoefficient(u0_fc);
socketstream glvis;
if (opt.vis) { opt.vis = glvis.open(vishost, visport) == 0; }
if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, GLVIZ_W, GLVIZ_H, &u); }
if (opt.vis) { Surface::Visualize(opt, &mesh, GLVIZ_W, GLVIZ_H, &u); }
Vector B, X;
OperatorPtr A;
CGSolver cg(MPI_COMM_WORLD);
@@ -1282,7 +1279,7 @@ static int Problem1(Opt &opt)
mfem::out << "Iteration " << i << ", norm: " << norm
<< ", area: " << area << std::endl;
}
if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, &u); }
if (opt.vis) { Surface::Visualize(opt, &mesh, &u); }
if (opt.print) { Surface::Print(opt, &mesh, &u); }
if (norm < NRM) { break; }
}
File diff suppressed because it is too large Load Diff
+51 -48
View File
@@ -12,8 +12,6 @@
#ifndef MFEM_LOR_MMS_HPP
#define MFEM_LOR_MMS_HPP
extern bool grad_div_problem;
namespace mfem
{
@@ -23,34 +21,36 @@ static constexpr double pi = M_PI, pi2 = M_PI*M_PI;
// defined below.
double u(const Vector &xvec)
{
int dim = xvec.Size();
double x = pi*xvec[0], y = pi*xvec[1];
const int dim = xvec.Size();
const double x = pi*xvec[0], y = pi*xvec[1];
if (dim == 2) { return sin(x)*sin(y); }
else { double z = pi*xvec[2]; return sin(x)*sin(y)*sin(z); }
else { const double z = pi*xvec[2]; return sin(x)*sin(y)*sin(z); }
}
double f(const Vector &xvec)
std::function<double(const Vector &)> f(double mass_coeff)
{
int dim = xvec.Size();
double x = pi*xvec[0], y = pi*xvec[1];
if (dim == 2)
return [mass_coeff](const Vector &xvec)
{
return sin(x)*sin(y) + 2*pi2*sin(x)*sin(y);
}
else // dim == 3
{
double z = pi*xvec[2];
return sin(x)*sin(y)*sin(z) + 3*pi2*sin(x)*sin(y)*sin(z);
}
const int dim = xvec.Size();
const double x = pi*xvec[0], y = pi*xvec[1];
if (dim == 2)
{
return mass_coeff*sin(x)*sin(y) + 2*pi2*sin(x)*sin(y);
}
else // dim == 3
{
const double z = pi*xvec[2];
return mass_coeff*sin(x)*sin(y)*sin(z) + 3*pi2*sin(x)*sin(y)*sin(z);
}
};
}
// Exact solution for definite Maxwell and grad-div problems with RHS
// corresponding to f_vec below.
void u_vec(const Vector &xvec, Vector &u)
{
int dim = xvec.Size();
double x = pi*xvec[0], y = pi*xvec[1];
const int dim = xvec.Size();
const double x = pi*xvec[0], y = pi*xvec[1];
if (dim == 2)
{
u[0] = cos(x)*sin(y);
@@ -58,47 +58,50 @@ void u_vec(const Vector &xvec, Vector &u)
}
else // dim == 3
{
double z = pi*xvec[2];
const double z = pi*xvec[2];
u[0] = cos(x)*sin(y)*sin(z);
u[1] = sin(x)*cos(y)*sin(z);
u[2] = sin(x)*sin(y)*cos(z);
}
}
void f_vec(const Vector &xvec, Vector &f)
std::function<void(const Vector &, Vector &)> f_vec(bool grad_div_problem)
{
int dim = xvec.Size();
double x = pi*xvec[0], y = pi*xvec[1];
if (grad_div_problem)
return [grad_div_problem](const Vector &xvec, Vector &f)
{
if (dim == 2)
const int dim = xvec.Size();
const double x = pi*xvec[0], y = pi*xvec[1];
if (grad_div_problem)
{
f[0] = (1 + 2*pi2)*cos(x)*sin(y);
f[1] = (1 + 2*pi2)*cos(y)*sin(x);
if (dim == 2)
{
f[0] = (1 + 2*pi2)*cos(x)*sin(y);
f[1] = (1 + 2*pi2)*cos(y)*sin(x);
}
else // dim == 3
{
const double z = pi*xvec[2];
f[0] = (1 + 3*pi2)*cos(x)*sin(y)*sin(z);
f[1] = (1 + 3*pi2)*cos(y)*sin(x)*sin(z);
f[2] = (1 + 3*pi2)*cos(z)*sin(x)*sin(y);
}
}
else // dim == 3
else
{
double z = pi*xvec[2];
f[0] = (1 + 3*pi2)*cos(x)*sin(y)*sin(z);
f[1] = (1 + 3*pi2)*cos(y)*sin(x)*sin(z);
f[2] = (1 + 3*pi2)*cos(z)*sin(x)*sin(y);
if (dim == 2)
{
f[0] = cos(x)*sin(y);
f[1] = sin(x)*cos(y);
}
else // dim == 3
{
const double z = pi*xvec[2];
f[0] = cos(x)*sin(y)*sin(z);
f[1] = sin(x)*cos(y)*sin(z);
f[2] = sin(x)*sin(y)*cos(z);
}
}
}
else
{
if (dim == 2)
{
f[0] = cos(x)*sin(y);
f[1] = sin(x)*cos(y);
}
else // dim == 3
{
double z = pi*xvec[2];
f[0] = cos(x)*sin(y)*sin(z);
f[1] = sin(x)*cos(y)*sin(z);
f[2] = sin(x)*sin(y)*cos(z);
}
}
};
}
} // namespace mfem
+2 -5
View File
@@ -74,8 +74,6 @@
using namespace std;
using namespace mfem;
bool grad_div_problem = false;
int main(int argc, char *argv[])
{
const char *mesh_file = "../../data/star.mesh";
@@ -109,7 +107,6 @@ int main(int argc, char *argv[])
else if (string(fe) == "l") { L2 = true; }
else { MFEM_ABORT("Bad FE type. Must be 'h', 'n', 'r', or 'l'."); }
if (RT) { grad_div_problem = true; }
double kappa = (order+1)*(order+1); // Penalty used for DG discretizations
Mesh mesh(mesh_file, 1, 1);
@@ -117,8 +114,8 @@ int main(int argc, char *argv[])
MFEM_VERIFY(dim == 2 || dim == 3, "Spatial dimension must be 2 or 3.");
for (int l = 0; l < ref_levels; l++) { mesh.UniformRefinement(); }
FunctionCoefficient f_coeff(f), u_coeff(u);
VectorFunctionCoefficient f_vec_coeff(dim, f_vec), u_vec_coeff(dim, u_vec);
FunctionCoefficient f_coeff(f(1.0)), u_coeff(u);
VectorFunctionCoefficient f_vec_coeff(dim, f_vec(RT)), u_vec_coeff(dim, u_vec);
int b1 = BasisType::GaussLobatto, b2 = BasisType::IntegratedGLL;
unique_ptr<FiniteElementCollection> fec;
+2 -5
View File
@@ -72,8 +72,6 @@
using namespace std;
using namespace mfem;
bool grad_div_problem = false;
int main(int argc, char *argv[])
{
Mpi::Init();
@@ -112,7 +110,6 @@ int main(int argc, char *argv[])
else if (string(fe) == "l") { L2 = true; }
else { MFEM_ABORT("Bad FE type. Must be 'h', 'n', 'r', or 'l'."); }
if (RT) { grad_div_problem = true; }
double kappa = (order+1)*(order+1); // Penalty used for DG discretizations
Mesh serial_mesh(mesh_file, 1, 1);
@@ -126,8 +123,8 @@ int main(int argc, char *argv[])
if (mesh.ncmesh && (RT || ND))
{ MFEM_ABORT("LOR AMS and ADS solvers are not supported with AMR meshes."); }
FunctionCoefficient f_coeff(f), u_coeff(u);
VectorFunctionCoefficient f_vec_coeff(dim, f_vec), u_vec_coeff(dim, u_vec);
FunctionCoefficient f_coeff(f(1.0)), u_coeff(u);
VectorFunctionCoefficient f_vec_coeff(dim, f_vec(RT)), u_vec_coeff(dim, u_vec);
int b1 = BasisType::GaussLobatto, b2 = BasisType::IntegratedGLL;
unique_ptr<FiniteElementCollection> fec;
-2
View File
@@ -221,8 +221,6 @@ int main(int argc, char *argv[])
if (k > 0)
{
double r = log2(err_old / err_k);
// Error is zero (2nd derivative is exact) -> put rate 2 (optimal).
if (err_k < 1e-14) { r = 2.0; }
rate_sum += r;
if (verbose)
{
+2 -2
View File
@@ -190,7 +190,7 @@ int main(int argc, char *argv[])
src_dc->SetPadDigitsRank(src_pad_digits_rank);
src_dc->Load(src_cycle);
if (src_dc->Error() != DataCollection::No_Error)
if (src_dc->Error() != DataCollection::NO_ERROR)
{
mfem::out << "Error loading data collection: "
<< src_coll_name
@@ -227,7 +227,7 @@ int main(int argc, char *argv[])
out_dc->Save();
if (out_dc->Error() != DataCollection::No_Error)
if (out_dc->Error() != DataCollection::NO_ERROR)
{
mfem::out << "Error saving data collection: "
<< out_coll_name

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