Compare commits

..
99 changed files with 844 additions and 8369 deletions
+1 -1
View File
@@ -141,7 +141,7 @@ jobs:
- name: get MPI (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
uses: mpi4py/setup-mpi@v1.1.4
uses: mpi4py/setup-mpi@v1.1.2
# Get Hypre through cache, or build it.
# Install will only run on cache miss.
-11
View File
@@ -131,12 +131,6 @@ examples/hiop/ex9-mesh.*
examples/hiop/ex9-init.*
examples/hiop/ex9-final.*
examples/ipopt/exContactBlockTL
examples/ipopt/exContactBlockTL.mesh
examples/ipopt/exContactBlockTL-mesh.*
examples/ipopt/exContactBlockTL-init.*
examples/ipopt/exContactBlockTL-final.*
examples/petsc/ex[1-69]p
examples/petsc/ex1[0-1]p
examples/petsc/mesh.*
@@ -209,7 +203,6 @@ miniapps/meshing/mesh-explorer
miniapps/meshing/shaper
miniapps/meshing/extruder
miniapps/meshing/trimmer
miniapps/meshing/reflector
miniapps/meshing/mesh-optimizer
miniapps/meshing/pmesh-optimizer
miniapps/meshing/minimal-surface
@@ -221,12 +214,9 @@ miniapps/meshing/toroid-*.mesh
miniapps/meshing/twist-*.mesh
miniapps/meshing/mesh-explorer.mesh
miniapps/meshing/partitioning.txt
miniapps/meshing/mesh-explorer-visit*
miniapps/meshing/mesh-explorer-paraview/
miniapps/meshing/shaper.mesh
miniapps/meshing/extruder.mesh
miniapps/meshing/trimmer.mesh
miniapps/meshing/reflected.mesh
miniapps/meshing/optimized*
miniapps/meshing/perturbed*
miniapps/meshing/polar-nc.mesh
@@ -286,7 +276,6 @@ miniapps/tools/convert-dc
miniapps/tools/lor-transfer
miniapps/tools/get-values
miniapps/tools/check-tmop-metric
miniapps/tools/tmop-metric-magnitude
miniapps/toys/automata
miniapps/toys/life
+1 -1
View File
@@ -93,7 +93,7 @@ report_baseline:
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
-41
View File
@@ -1,41 +0,0 @@
#!/bin/bash
# Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Try to push to the remote 5 times. If the push fails, and the local and remote
# have diverged, then pull from the remote to merge changes, and try pushing
# again. If some other failure happens
for i in {1..5}; do
git push origin master && exit 0
# Wait for 20 seconds in case someone else is pushing to the remote
# concurrently
sleep 20
# Fetch any updates from the remote
git remote update
# Get the latest commit on the local branch
LOCAL=$(git rev-parse @)
# Get the latest commit on the remote
REMOTE=$(git rev-parse @{u})
# Get the common ancestor
BASE=$(git merge-base @ @{u})
# Have the local and remote diverged?
if [[ $LOCAL != $REMOTE && $LOCAL != $BASE && $REMOTE != $BASE ]]; then
git pull
if [[ $? == 0 ]]; then
continue
else
exit 1 # Something else went wrong trying to pull
fi
fi
done
exit 1 # Did not succeed in 5 attempts
@@ -32,7 +32,7 @@ if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
@@ -29,7 +29,7 @@ if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
+1 -20
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,12 +27,7 @@ Linear and nonlinear solvers
New and updated examples and miniapps
-------------------------------------
- Added a new meshing miniapp, reflector, which reflects a high-order or NURBS
hexahedral mesh about a plane.
- The mesh-explorer miniapp can now save mesh files in the VisIt or ParaView
formats using the corresponding DataCollection objects. See option 'D' in the
main menu.
- TBD
Integrations, testing and documentation
---------------------------------------
@@ -116,9 +100,6 @@ Discretization improvements
- Added a class CoefficientVector for efficient access of variable coefficient
values at quadrature points (in particular for GPU/device kernels).
- Added support for GridFunction::GetGradients() and
GriFunction::GetVectorGradient() on face-neighbor elements.
- Added WhiteGaussianNoiseDomainLFIntegrator: a LinearFormIntegrator class for
spatial Gaussian white noise.
+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
-68
View File
@@ -1,68 +0,0 @@
# Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/ipopt/,)
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_EXAMPLES = exContactBlockTL
EXAMPLES = $(SEQ_EXAMPLES)
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all clean clean-build clean-exec
# Remove built-in rule
%: %.cpp
# Replace the default implicit rule for *.cpp files
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
all: $(EXAMPLES)
ifeq ($(MFEM_USE_IPOPT),NO)
$(EXAMPLES):
$(error MFEM is not configured with IPOPT)
endif
MFEM_TESTS = EXAMPLES
include $(MFEM_TEST_MK)
# Testing: Parallel vs. serial runs
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
%-test-par: %
@$(call mfem-test,$<, $(RUN_MPI), Parallel example)
%-test-seq: %
@$(call mfem-test,$<,, Serial example)
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
# Generate an error message if the MFEM library is not built and exit
$(MFEM_LIB_FILE):
$(error The MFEM library is not built)
clean: clean-build clean-exec
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -f exContactBlockTL.mesh exContactBlockTL-mesh.* exContactBlockTL-init.* exContactBlockTL-final.* ExampleContactBlockTL*
-888
View File
@@ -1,888 +0,0 @@
using namespace std;
using namespace mfem;
void BasisEval(const Vector xi, Vector &N, DenseMatrix &dNdxi) // dNdxi is 2*4
{
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi(0,0) = 0.25*(-1+xi[1]);
dNdxi(0,1) = 0.25*(1-xi[1]);
dNdxi(0,2) = 0.25*(1+xi[1]);
dNdxi(0,3) = 0.25*(-1-xi[1]);
dNdxi(1,0) = 0.25*(-1+xi[0]);
dNdxi(1,1) = 0.25*(-1-xi[0]);
dNdxi(1,2) = 0.25*(1+xi[0]);
dNdxi(1,3) = 0.25*(1-xi[0]);
}
void BasisEvalDerivs(const Vector xi, Vector& N, DenseMatrix& dNdxi,
DenseMatrix& dN2dxi)
{
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi.SetSize(2,4); dNdxi = 0.0;
dN2dxi.SetSize(3,4);
dN2dxi = 0.0; // first row dxi2, second detadxi, third deta2
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,1) = 0.25*(1-xi[1]);
dNdxi(0,2) = 0.25*(1+xi[1]); dNdxi(0,3) = 0.25*(-1-xi[1]);
dNdxi(1,0) = 0.25*(-1+xi[0]); dNdxi(1,1) = 0.25*(-1-xi[0]);
dNdxi(1,2) = 0.25*(1+xi[0]); dNdxi(1,3) = 0.25*(1-xi[0]);
dN2dxi(1,0) = 0.25; dN2dxi(1,1) = -0.25; dN2dxi(1,2) = 0.25;
dN2dxi(1,3) = -0.25;
}
// returns the vector and matrix form of the shape functions and its derivative
void BasisVectorDerivs(const Vector xi, DenseMatrix& N, DenseMatrix& dNdxi,
DenseMatrix& ddNdxi)
{
N.SetSize(3,12); N = 0.0;
N(0,0) = 0.25*(1-xi[0])*(1-xi[1]); N(0,3) = 0.25*(1+xi[0])*(1-xi[1]);
N(0,6) = 0.25*(1+xi[0])*(1+xi[1]); N(0,9) = 0.25*(1-xi[0])*(1+xi[1]);
N(1,1) = 0.25*(1-xi[0])*(1-xi[1]); N(1,4) = 0.25*(1+xi[0])*(1-xi[1]);
N(1,7) = 0.25*(1+xi[0])*(1+xi[1]); N(1,10) = 0.25*(1-xi[0])*(1+xi[1]);
N(2,2) = 0.25*(1-xi[0])*(1-xi[1]); N(2,5) = 0.25*(1+xi[0])*(1-xi[1]);
N(2,8) = 0.25*(1+xi[0])*(1+xi[1]); N(2,11) = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi.SetSize(3*2, 3*4); dNdxi = 0.0;
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,3) = 0.25*(1-xi[1]);
dNdxi(0,6) = 0.25*(1+xi[1]); dNdxi(0,9) = 0.25*(-1-xi[1]);
dNdxi(1,1) = 0.25*(-1+xi[1]); dNdxi(1,4) = 0.25*(1-xi[1]);
dNdxi(1,7) = 0.25*(1+xi[1]); dNdxi(1,10) = 0.25*(-1-xi[1]);
dNdxi(2,2) = 0.25*(-1+xi[1]); dNdxi(2,5) = 0.25*(1-xi[1]);
dNdxi(2,8) = 0.25*(1+xi[1]); dNdxi(2,11) = 0.25*(-1-xi[1]);
dNdxi(3,0) = 0.25*(-1+xi[0]); dNdxi(3,3) = 0.25*(-1-xi[0]);
dNdxi(3,6) = 0.25*(1+xi[0]); dNdxi(3,9) = 0.25*(1-xi[0]);
dNdxi(4,1) = 0.25*(-1+xi[0]); dNdxi(4,4) = 0.25*(-1-xi[0]);
dNdxi(4,7) = 0.25*(1+xi[0]); dNdxi(4,10) = 0.25*(1-xi[0]);
dNdxi(5,2) = 0.25*(-1+xi[0]); dNdxi(5,5) = 0.25*(-1-xi[0]);
dNdxi(5,8) = 0.25*(1+xi[0]); dNdxi(5,11) = 0.25*(1-xi[0]);
ddNdxi.SetSize(3*4, 3*4); ddNdxi = 0.0;
ddNdxi(3,0) = 0.25; ddNdxi(3,3) = -0.25;
ddNdxi(3,6) = 0.25; ddNdxi(3,9) = -0.25;
ddNdxi(4,1) = 0.25; ddNdxi(4,4) = -0.25;
ddNdxi(4,7) = 0.25; ddNdxi(4,10) = -0.25;
ddNdxi(5,2) = 0.25; ddNdxi(5,5) = -0.25;
ddNdxi(5,8) = 0.25; ddNdxi(5,11) = -0.25;
ddNdxi(6,0) = 0.25; ddNdxi(6,3) = -0.25;
ddNdxi(6,6) = 0.25; ddNdxi(6,9) = -0.25;
ddNdxi(7,1) = 0.25; ddNdxi(7,4) = -0.25;
ddNdxi(7,7) = 0.25; ddNdxi(7,10) = -0.25;
ddNdxi(8,2) = 0.25; ddNdxi(8,5) = -0.25;
ddNdxi(8,8) = 0.25; ddNdxi(8,11) = -0.25;
}
void cross(const Vector a, const Vector b, Vector& c)
{
assert(a.Size()==3);
c.SetSize(3);
c[0] = a[1]*b[2] - a[2]*b[1];
c[1] = -a[0]*b[2] + b[0]*a[2];
c[2] = a[0]*b[1] - a[1]*b[0];
}
// a outer b
void outer(const Vector a, const Vector b, DenseMatrix& c)
{
int m = a.Size();
int n = b.Size();
assert(c.Height()==m);
assert(c.Width() ==n);
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
{
c(i,j) = a[i]*b[j];
}
}
}
// dphidxi 2*4
// coords 4*3
void ComputeNormal(const DenseMatrix& dphidxi, const DenseMatrix& coords,
Vector& normal, double& nnorm)
{
DenseMatrix dxdxi(2,3);
Mult(dphidxi, coords, dxdxi);
Vector dxdxi1(3);
Vector dxdxi2(3);
dxdxi.GetRow(0,dxdxi1);
dxdxi.GetRow(1,dxdxi2);
cross(dxdxi1, dxdxi2, normal); // is there a cross product? no
// VectorCrossProductCoefficient::Eval has hard-coded cross product
nnorm = normal.Norml2( );
normal /= nnorm;
}
void SlaveToMaster(const DenseMatrix& m_coords, const Vector& s_x, Vector& xi)
{
bool converged = false;
bool pt_on_elem = false;
int dim = 3;
xi.SetSize(dim-1);
xi = 0.0;
double r = 1e10;
int max_iter = 15;
double off_el_xi = 1e-2;
double proj_newton_tol = 1e-13;
double proj_max_gap = 0.5;
Vector gap_v(dim);
// warm start from linear solution
for (int it=0; it<max_iter; it++)
{
//cout<<it<<endl;
Vector m_N(4);
m_N = 0.;
DenseMatrix m_dN(2,4);
m_dN = 0.;
DenseMatrix m_dN2(3,4);
m_dN2 = 0.;
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
Vector x_c(dim);
m_coords.MultTranspose(m_N, x_c);
gap_v = s_x;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
m_dx = 0.;
Mult(m_dN, m_coords, m_dx);
Vector r(dim-1);
r = 0.0;
m_dx.Mult(gap_v, r);
if (r.Normlinf() < proj_newton_tol)
{
converged = true;
break;
}
DenseMatrix drdxi(dim-1,dim-1);
drdxi = 0.;
MultABt(m_dx, m_dx, drdxi); // m_dx * m_dx.T
drdxi *= -1.0;
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
Mult(m_dN2,m_coords, m_dx2);
//m_d2x = m_dN(:,:,2) * m_elem_coords(1:4,:); //m_dN(:,:,2) is 3*4
for (int d=0; d<3; d++)
{
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
drdxi.Add(gap_v[d], Mtemp);
}
//cond_num = rcond(drdxi); condition number?
//drdxi.TestInversion();
DenseMatrixInverse drdxi_inv(drdxi);
Vector xi_tmp(dim-1);
drdxi_inv.Mult(r,xi_tmp);
xi -= xi_tmp;
}
if (!converged)
{
xi = 0.0;
}
off_el_xi += 1 ; // tolerance of offset of xi outside [-1,1]
//cout<<gap_v.Norml2()<<" " <<xi.Normlinf()<<endl;
if (gap_v.Norml2() < proj_max_gap && xi.Normlinf() <= off_el_xi)
{
pt_on_elem = true;
}
MFEM_VERIFY(pt_on_elem == true, "xi went out of bounds");
MFEM_VERIFY(converged == true, "projection didn't converge");
}
// m_coords is expected to be 4 * 3
void ComputeGapJacobian(const Vector x_s, const Vector xi,
const DenseMatrix m_coords,
double& gap, Vector& normal, Vector& dgdxm, Vector& dgdxs)
{
Vector m_N(4);
DenseMatrix m_dN(2,4);
DenseMatrix m_dN2(3,4);
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
Vector x_c(3);
m_coords.MultTranspose(m_N, x_c);
Vector gap_v(3); gap_v = 0.0;
gap_v = x_s;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
Mult(m_dN, m_coords, m_dx);
double nnorm = 0;
ComputeNormal(m_dN, m_coords, normal, nnorm);
gap = gap_v * normal; // gap function value, dot product between vectors
//dr_dx = zeros(2,4,3); % nsegment, nodes in quad, ndim
DenseMatrix dr_dx_res1(4,3); dr_dx_res1 = 0.;
DenseMatrix dr_dx_res2(4,3); dr_dx_res2 = 0.;
Vector m_dxrow1(3);
m_dx.GetRow(0, m_dxrow1);
outer(m_N, m_dxrow1, dr_dx_res1);// 4*1 times 1*3
dr_dx_res1 *= -1.0;
Vector m_dxrow2(3);
m_dx.GetRow(1, m_dxrow2);
outer(m_N, m_dxrow2, dr_dx_res2);// 4*1 times 1*3
dr_dx_res2 *= -1.0;
Vector m_dNrow1(4); m_dN.GetRow(0, m_dNrow1);
Vector m_dNrow2(4); m_dN.GetRow(1, m_dNrow2);
DenseMatrix dr_dx_res1_tmp(4,3); dr_dx_res1_tmp = 0.;
DenseMatrix dr_dx_res2_tmp(4,3); dr_dx_res2_tmp = 0.;
outer(m_dNrow1, gap_v, dr_dx_res1_tmp);// 4*1 times 1*3
outer(m_dNrow2, gap_v, dr_dx_res2_tmp);// 4*1 times 1*3
dr_dx_res1 += dr_dx_res1_tmp; // outer product in vector?
dr_dx_res2 += dr_dx_res2_tmp;
DenseMatrix K_dxidx1(2,2); // 2*2
K_dxidx1 = 0.;
MultABt(m_dx, m_dx, K_dxidx1); // m_dx * m_dx.T
Vector v_dxidx2(4);
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
// how to get 2nd order? multidimensional matrix?
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
DenseMatrix K_dxidx(2,2);
K_dxidx -= K_dxidx1;
K_dxidx += K_dxidx2;
// resize the vectors and matrices
Vector dxidx(24); dxidx = 0.0;
Vector drdx_r(24); drdx_r = 0.0;
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
drdx_r[4*j+i] = dr_dx_res1(i,j);
drdx_r[4*j+i+12] = dr_dx_res2(i,j);
}
}
//drdx_r(1:4*3,1) = reshape(dr_dx_res(:,:,1),4*3,1);
//drdx_r(4*3+1:2*4*3,1) = reshape(dr_dx_res(:,:,2),4*3,1);
DenseMatrix drdx_K(24,24); drdx_K = 0.;
for (int i =0; i<12; i++)
{
drdx_K(i,i) = K_dxidx(0,0);
drdx_K(i,12+i) = K_dxidx(0,1);
drdx_K(12+i,i) = K_dxidx(1,0);
drdx_K(12+i,12+i) = K_dxidx(1,1);
}
DenseMatrixInverse drdxK_inv(drdx_K);
drdxK_inv.Mult(drdx_r,dxidx);
// LinearSolve (drdx_K,drdx_r, dxidx) ; //???
dxidx *= -1.0;
Vector drdxs_r(6);
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
for (int i=0; i<3; i++)
{
drdxs_K(i,i) = K_dxidx(0,0);
drdxs_K(i,3+i) = K_dxidx(0,1);
drdxs_K(i+3,i) = K_dxidx(1,0);
drdxs_K(i+3,i+3) = K_dxidx(1,1);
}
Vector dxidxs(6); dxidxs = 0.0;
DenseMatrixInverse drdxsK_inv(drdxs_K);
drdxsK_inv.Mult(drdxs_r,dxidxs);
dxidxs *= -1.0;
//dxidxs = -drdxs_K\drdxs_r;
//dxidx = reshape(dxidx, 4,3,2); dxidxs = reshape(dxidxs, 1,3,2);
dgdxm.SetSize(12); dgdxm = 0.;
DenseMatrix dgdxm_tmp(4,3);
outer(m_N, normal,dgdxm_tmp);
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
dgdxm[3*i+j] = -dgdxm_tmp(i,j);
}
}
//dxidx_M = -m_dN(1:2,:,1) * (m_coords(1:4,:)*normal'); % this turns out to be 0
dgdxs.SetSize(3);
dgdxs += normal;
//dgdxs = dgdxs + dxidx_M(1) * dxidxs(:,:,1) + dxidx_M(2) * dxidxs(:,:,2);
};
void ComputeGapHessian(const Vector x_s, const Vector xi,
const DenseMatrix m_coords,
DenseMatrix& dg2dx)
{
Vector m_N(4);
DenseMatrix m_dN(2,4);
DenseMatrix m_dN2(3,4);
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
int dim = 3;
int num_dofs1 = dim;
int num_dofs2 = 4*dim;
int num_dofs = num_dofs1 + num_dofs2;
dg2dx.SetSize(num_dofs,num_dofs); dg2dx = 0.0;
Vector x_c(3);
m_coords.MultTranspose(m_N,x_c);
Vector gap_v(3); gap_v = 0.0;
gap_v = x_s;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
Mult(m_dN, m_coords, m_dx);
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
Mult(m_dN2,m_coords, m_dx2);
double nnorm = 0.0;
Vector normal(3); normal = 0.0;
ComputeNormal(m_dN, m_coords, normal, nnorm);
double gap = gap_v * normal; // gap function value, dot product between vectors
DenseMatrix M(2,2); M = 0.0;
MultABt(m_dx, m_dx, M);
DenseMatrix f(2, num_dofs2); f = 0.0;
for (int d=0; d<3; d++)
{
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
M.Add(-gap_v[d], Mtemp);
Vector m_dxcol(2); m_dx.GetColumn(d, m_dxcol);
DenseMatrix ftmp(2,4);
outer(m_dxcol, m_N, ftmp);
ftmp *= -1;
ftmp.Add( gap_v[d], m_dN); // 2*4
for (int j=0; j<4; j++)
{
assert(d+3*j<num_dofs2);
f(0,d+j*3) = ftmp(0,j);
f(1,d+j*3) = ftmp(1,j);
}
}
//fprintf('hess dxidxm\n');
DenseMatrixInverse Minv(M);
DenseMatrix dxidxm(2,num_dofs2); dxidxm = 0.0;
Minv.Mult(f, dxidxm);
//LinearSolve??
//dxidxm = M\f;
DenseMatrix nde2(2,2); nde2 = 0.0;
DenseMatrix Nndx2(2,num_dofs2); Nndx2 = 0.0;
for (int d=0; d<3; d++)
{
DenseMatrix ndetmp(2,2); ndetmp = 0.0;
ndetmp(0,0) = normal(d)*m_dx2(0,d); ndetmp(0,1) = normal(d)*m_dx2(1,d);
ndetmp(1,0) = normal(d)*m_dx2(1,d); ndetmp(1,1) = normal(d)*m_dx2(2,d);
nde2 += ndetmp;
for (int j=0; j<4; j++)
{
assert(d+3*j<num_dofs2);
Nndx2(0,d+j*3) = normal[d]*m_dN(0,j);
Nndx2(1,d+j*3) = normal[d]*m_dN(1,j);
}
}
DenseMatrix Ndn(2,num_dofs2); Ndn = 0.0;
Ndn += Nndx2;
AddMult(nde2, dxidxm, Ndn);
DenseMatrix M2(2,2); M2 = 0.0;
MultABt(m_dx, m_dx, M2);
DenseMatrixInverse M2inv(M2);
DenseMatrix diag2(2,2); diag2(0,0) = 1.0; diag2(1,1) = 1.0;
DenseMatrix m_con(2,2); m_con = 0.0;
M2inv.Mult(diag2, m_con);
DenseMatrix dg2dxm(num_dofs2, num_dofs2); dg2dxm = 0.0;
DenseMatrix dg2dxm_tmp(num_dofs2,2); dg2dxm_tmp = 0.0;
MultAtB(Ndn, m_con, dg2dxm_tmp);
Mult(dg2dxm_tmp, Ndn, dg2dxm);
dg2dxm *= gap;
DenseMatrix dg2dxm_tmp2(num_dofs2,num_dofs2); dg2dxm_tmp2 = 0.0;
MultAtB(Nndx2, dxidxm, dg2dxm_tmp2);
dg2dxm.Add(-1.0, dg2dxm_tmp2);
dg2dxm_tmp = 0.0;
MultAtB(dxidxm, nde2, dg2dxm_tmp);
AddMult_a(-1.0, dg2dxm_tmp, dxidxm, dg2dxm);
dg2dxm_tmp2 = 0.0;
MultAtB(dxidxm, Nndx2, dg2dxm_tmp2);
dg2dxm.Add(-1.0, dg2dxm_tmp2);
Vector v_dxidx2(4);
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
DenseMatrix K_dxidx(2,2);
K_dxidx -= M2;
K_dxidx += K_dxidx2;
Vector drdxs_r(6);
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
for (int i=0; i<3; i++)
{
drdxs_K(i,i) = K_dxidx(0,0);
drdxs_K(i,3+i) = K_dxidx(0,1);
drdxs_K(i+3,i) = K_dxidx(1,0);
drdxs_K(i+3,i+3) = K_dxidx(1,1);
}
Vector dxidxs(6);
DenseMatrixInverse drdxsK_inv(drdxs_K);
drdxsK_inv.Mult(drdxs_r,dxidxs);
dxidxs *= -1.0;
//dxidxs = -drdxs_K\drdxs_r;
DenseMatrix dxidxs_m(2,3); dxidxs_m = 0.0;
dxidxs_m(0,0) = dxidxs[0]; dxidxs_m(0,1) = dxidxs[1]; dxidxs_m(0,2) = dxidxs[2];
dxidxs_m(1,0) = dxidxs[3]; dxidxs_m(1,1) = dxidxs[4]; dxidxs_m(1,2) = dxidxs[5];
DenseMatrix dtao1dxs(3,3); dtao1dxs = 0.0;
DenseMatrix dtao2dxs(3,3); dtao2dxs = 0.0;
Vector dxidxs_row1(3); dxidxs_row1 = 0.0; Vector dxidxs_row2(3);
dxidxs_row2 = 0.0;
Vector mdx2_row1(3); mdx2_row1 = 0.0; Vector mdx2_row2(3); mdx2_row2 = 0.0;
Vector mdx2_row3(3); mdx2_row3 = 0.0;
dxidxs_m.GetRow(0,dxidxs_row1);
dxidxs_m.GetRow(1,dxidxs_row2);
m_dx2.GetRow(0,mdx2_row1);
m_dx2.GetRow(1,mdx2_row2);
m_dx2.GetRow(2,mdx2_row3);
DenseMatrix dtaotmp(3,3); dtaotmp = 0.0;
outer(mdx2_row1, dxidxs_row1,dtaotmp);
dtao1dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row2, dxidxs_row1,dtaotmp);
dtao1dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row2, dxidxs_row2, dtaotmp);
dtao2dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row3, dxidxs_row2, dtaotmp);
dtao2dxs += dtaotmp; dtaotmp = 0.0;
DenseMatrix dtaodxs(3,3); dtaodxs = 0.0; //tao = tao1 cross tao2
for (int d=0; d<3; d++)
{
Vector dtao1dxs_tmp(3); dtao1dxs_tmp = 0.0;
dtao1dxs.GetColumn(d,dtao1dxs_tmp);
Vector m_dxrow(3); m_dx.GetRow(1, m_dxrow);
Vector dtaodxs_tmp(3); dtaodxs_tmp = 0.0;
cross(dtao1dxs_tmp, m_dxrow, dtaodxs_tmp);
Vector dtaodxs_tmp2(3); dtaodxs_tmp2 = 0.0;
m_dx.GetRow(0, m_dxrow);
dtao1dxs_tmp = 0.0; // reuse the same vector for dtao2
dtao2dxs.GetColumn(d,dtao1dxs_tmp);
cross(m_dxrow, dtao1dxs_tmp, dtaodxs_tmp2);
dtaodxs_tmp2 += dtaodxs_tmp;
dtaodxs.SetCol(d, dtaodxs_tmp2);
}
DenseMatrix dndxs(3,3); dndxs = 0.0; dndxs += dtaodxs; dndxs *= 1.0/nnorm;
DenseMatrix dndxs_tmp(3,3); dndxs_tmp = 0.0;
outer(normal, normal, dndxs_tmp);
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxs, dndxs);
DenseMatrix dgvdxs(3,3); dgvdxs = 0.0;
MultAtB(m_dx, dxidxs_m, dgvdxs);
dgvdxs *= -1;
for (int d=0; d<3; d++)
{
dgvdxs(d,d) += 1.0;
}
//dxidxs: 2*3
DenseMatrix dg2dxs(3,3); dg2dxs = 0.0;
DenseMatrix dg2dxs_tmp(3,2); dg2dxs_tmp = 0.0;
MultAtB(dxidxs_m, nde2, dg2dxs_tmp);
AddMult_a(-1.0, dg2dxs_tmp, dxidxs_m, dg2dxs);
DenseMatrix dg2dxs_tmp2(3,3); dg2dxs_tmp2 = 0.0;
MultAtB(dgvdxs, dndxs, dg2dxs_tmp2);
dg2dxs += dg2dxs_tmp2;
dg2dxs_tmp2 = 0.0;
MultAtB(dndxs, dndxs_tmp, dg2dxs_tmp2);
AddMult(dg2dxs_tmp2, dgvdxs, dg2dxs);
DenseMatrix Ne(3,12), Be(6,12), dBe(12,12);
BasisVectorDerivs(xi, Ne, Be, dBe);
DenseMatrix dtao1dxm(3,12); dtao1dxm.CopyRows(Be, 0, 2);
DenseMatrix dtao2dxm(3,12); dtao2dxm.CopyRows(Be, 3, 5);
Vector m_coords_v(12);
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
m_coords_v[i*3+j] = m_coords(i,j);
}
}
for (int i=0; i<2; i++)
{
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
dxidxm.GetRow(i,dxidxm_tmp);
DenseMatrix dBe_tmp(3,12);
dBe_tmp.CopyRows(dBe,i*3,(i+1)*3-1);
DenseMatrix dtaodxm_tmp(12,12); dtaodxm_tmp = 0.0;
outer(m_coords_v, dxidxm_tmp, dtaodxm_tmp);
AddMult(dBe_tmp, dtaodxm_tmp, dtao1dxm);
//dtao1dxm += dBe(:,:,i)*reshape(m_coords(1:4,:)',12,1)*reshape(dxidxm(i,:),1,12); % 3*12
dBe_tmp = 0.0;
dBe_tmp.CopyRows(dBe,(i+2)*3,(i+3)*3-1);
AddMult(dBe_tmp, dtaodxm_tmp, dtao2dxm);
}
DenseMatrix dtaodxm(3,12); dtaodxm = 0.0;//tao = tao1 cross tao2
for (int d=0; d<12; d++)
{
Vector dtaodxm_tmp(3); dtaodxm_tmp = 0.0;
Vector dtaodxm_tmp2(3); dtaodxm_tmp2 = 0.0;
Vector tmp1(3); tmp1 = 0.0; dtao1dxm.GetColumn(d,tmp1);
Vector m_dxrow2(3); m_dx.GetRow(1, m_dxrow2);
Vector m_dxrow1(3); m_dx.GetRow(0, m_dxrow1);
Vector tmp2(3); tmp2 = 0.0; dtao2dxm.GetColumn(d,tmp2);
cross(tmp1, m_dxrow2, dtaodxm_tmp);
cross(m_dxrow1,tmp2, dtaodxm_tmp2);
dtaodxm_tmp += dtaodxm_tmp2;
dtaodxm.SetCol(d, dtaodxm_tmp);
}
DenseMatrix dndxm(3,12); dndxm = 0.0;
dndxm += dtaodxm;
dndxm *= 1.0/nnorm;
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxm, dndxm); //dndxs_tmp = normal'*normal
DenseMatrix dgvdxm(3,12); dgvdxm = 0.0;
dgvdxm -= Ne;
for (int i=0; i<2; i++)
{
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
dxidxm.GetRow(i,dxidxm_tmp);
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
DenseMatrix dgvdxm_tmp(12,12); dgvdxm_tmp = 0.0;
outer(m_coords_v, dxidxm_tmp, dgvdxm_tmp);
AddMult_a(-1.0, Be_tmp, dgvdxm_tmp, dgvdxm);
}
DenseMatrix dg2dxsxm(3,12); dg2dxsxm = 0.0;
DenseMatrix dg2dxsxm_tmp(3,3); dg2dxsxm_tmp = 0.0;
MultAtB(dgvdxs, dndxm, dg2dxsxm);
MultAtB(dndxs, dndxs_tmp, dg2dxsxm_tmp);
AddMult(dg2dxsxm_tmp, dgvdxm, dg2dxsxm); // += dndxs'*normal'*normal*dgvdxm;
DenseMatrix dgvdxsxmn(3,12); dgvdxsxmn = 0.0;
DenseMatrix dgvdxsxmn_tmp(3,2); dgvdxsxmn_tmp = 0.0;
MultAtB(dxidxs_m, nde2, dgvdxsxmn_tmp); //dxidxs_m: 2*3
AddMult_a(-1.0, dgvdxsxmn_tmp, dxidxm, dgvdxsxmn);
for (int i =0; i<2; i++)
{
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
DenseMatrix dgvdxsxmn_tmp2(3,3); dgvdxsxmn_tmp2 = 0.0;
outer(dxidxs_row, normal, dgvdxsxmn_tmp2);
AddMult_a(-1.0, dgvdxsxmn_tmp2, Be_tmp, dgvdxsxmn);
}
dg2dxsxm += dgvdxsxmn;
DenseMatrix dg2dxmxs(12,3); dg2dxmxs = 0.0;
DenseMatrix dg2dxmxs_tmp(12,3); dg2dxmxs_tmp = 0.0;
MultAtB(dgvdxm, dndxs, dg2dxmxs);
MultAtB(dndxm, dndxs_tmp, dg2dxmxs_tmp);
AddMult(dg2dxmxs_tmp, dgvdxs, dg2dxmxs);
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
DenseMatrix dgvdxmxsn_tmp(12,2); dgvdxmxsn_tmp = 0.0;
MultAtB(dxidxm, nde2, dgvdxmxsn_tmp);
dgvdxmxsn_tmp *= -1.0;
AddMult(dgvdxmxsn_tmp, dxidxs_m, dgvdxmxsn);
for (int i =0; i<2; i++)
{
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
Be_tmp.Transpose(); // Be is now 12*3
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
DenseMatrix dgvdxmxsn_tmp2(3,3); dgvdxmxsn_tmp2 = 0.0;
outer(normal, dxidxs_row, dgvdxmxsn_tmp2);
AddMult_a(-1.0, Be_tmp, dgvdxmxsn_tmp2, dgvdxmxsn);
}
dg2dxmxs += dgvdxmxsn;
dg2dx.CopyMN(dg2dxs, 0, 0);
dg2dx.CopyMN(dg2dxm, 3, 3);
dg2dx.CopyMN(dg2dxsxm, 0, 3);
dg2dx.CopyMN(dg2dxmxs, 3, 0);
};
void NodeSegConPairs(const Vector x1, const Vector xi2,
const DenseMatrix coords2,
double& node_g, Vector& node_dg, DenseMatrix& node_dg2)
{
double gap = 0.0;
Vector normal(3); normal = 0.0;
Vector dgdxm(12); dgdxm = 0.0;
Vector dgdxs(3); dgdxs = 0.0;
ComputeGapJacobian(x1, xi2, coords2, gap, normal, dgdxm, dgdxs);
node_g = gap;
node_dg.SetSize(12+3);
for (int i=0; i<3; i++) { node_dg[i] = dgdxs[i]; }
for (int i=0; i<12; i++) { node_dg[i+3] = dgdxm[i]; }
DenseMatrix dg2dx(15,15); dg2dx = 0.0;
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
ComputeGapHessian(x1, xi2, coords2, dg2dx);
node_dg2.SetSize(15,15);
node_dg2 = dg2dx;
/*
if(obj.space1.conns{e1}(i)==150) % for debugging purpose
v1 = 1:3;
v2 = 1:12;
%v1 = ones(1,3)
%v2 = ones(1,12)
v2 = reshape(v2,4,3);
x1n1 = x1 + 0.01*v1;
coords2n1 = coords2 + 0.001*v2;
[xi2n1, gapv1, ~, ~] = SlaveToMaster(obj, coords2n1, x1n1);
[gapn1, n1,dgdxmn1, dgdxsn1] = ComputeGapJacobian(obj, x1n1, xi2n1, coords2n1);
x1n2 = x1 - 0.01*v1;
coords2n2 = coords2 - 0.001*v2;
[xi2n2, gapv2, ~, ~] = SlaveToMaster(obj, coords2n2, x1n2);
[gapn2, n2,dgdxmn2, dgdxsn2] = ComputeGapJacobian(obj, x1n2, xi2n2, coords2n2);
fprintf('fd\n');
%gapv1-gapv2
[dgdxsn1(:)',dgdxmn1(:)'] - [dgdxsn2(:)',dgdxmn2(:)']
%dgdxsn1-dgdxsn2
fprintf('code\n');
v2n = v2';
%dg2dx(1:3,1:3)*0.04*ones(3,1)
temp = zeros(12,3);
for i = 1:4
temp1 = dg2dx(3+(i-1)*3+1:3+i*3,1:3);
temp((i-1)*3+1:i*3,:) = temp1';
end
temp2 = zeros(3,12);
for i = 1:4
temp3 = dg2dx(1:3,3+(i-1)*3+1:3+i*3);
temp2(:,(i-1)*3+1:i*3) = temp3';
end
%dg2dx
%dg2dx(4:end,1:3) = temp;
%dg2dx(1:3,4:end) = temp2;
%dgvdxm * 0.002*v2n(:)
(dg2dx*[0.02*v1(:)',0.002*v2n(:)']')'
%dg2dx(4:end,1:3)
end*/
};
// coordsm : (npoints*4, 3) use what class?
// m_conn: (npoints*4)
void Assemble_Contact(const int m, const int npoints, const int ndofs,
const Vector x_s,
const Vector xi, const DenseMatrix coordsm, const Array<int> s_conn,
const Array<int> m_conn, Vector& g, SparseMatrix& M,
std::vector<SparseMatrix>& dM)
{
int n = ndofs;
int ndim = 3;
g.SetSize(m);
g = 0.0;
//SparseMatrix M(m, n); // M needs to be the correct size
//dM.resize(m); // needs to clear?
double g_tmp = 0.;
Vector dg(4*ndim+ndim);
dg = 0.;
DenseMatrix dg2(4*ndim+ndim,4*ndim+ndim);
dg2 = 0.;
for (int i=0; i<npoints; i++)
{
Vector x1(ndim);
x1[0] = x_s[i*ndim];
x1[1] = x_s[i*ndim+1];
x1[2] = x_s[i*ndim+2];
Vector xi2(ndim-1);
xi2[0] = xi[i*(ndim-1)];
xi2[1] = xi[i*(ndim-1)+1];
DenseMatrix coords2(4,3);
coords2.CopyRows(coordsm, i*4,(i+1)*4-1);
//how to get coords2?
dg = 0.0;
dg2 = 0.;
NodeSegConPairs(x1, xi2, coords2, g_tmp, dg, dg2);
//x1.Print();
//xi2.Print();
//coords2.Print();
g[s_conn[i]] = g_tmp; // should be unique
Array<int> m_conn_i(4);
m_conn.GetSubArray(4*i, 4, m_conn_i);
Array<int> node_conn(5);
node_conn[0] = s_conn[i];
for (int j=0; j<4; j++)
{
node_conn[j+1] = m_conn_i[j];
}
Array<int> M_i_tmp(1);
M_i_tmp[0] = s_conn[i];
//j_idx = (node_conn-1)*obj.disp_field.num_components +repmat((1:obj.disp_field.num_components)', 1, length(node_conn{i}));
Array<int> j_idx(5*ndim); j_idx = 0;
for (int j=0; j< 5; j++)
{
for (int k=0; k<ndim; k++)
{
j_idx[j*ndim+k] = node_conn[j]*ndim+k;
}
}
DenseMatrix M_v_tmp(1, ndim*(4+1)); // SetData now?
M_v_tmp.SetRow(0, dg);
M.AddSubMatrix(M_i_tmp, j_idx, M_v_tmp);
Array<int> dM_i(ndim*(4+1));
Array<int> dM_j(ndim*(4+1));
for (int j=0; j< ndim*(4+1); j++)
{
dM_i[j] = j_idx[j];
dM_j[j] = j_idx[j];
}
//dg2.Print();
//dM[s_conn[i]].Print();
dM[s_conn[i]].AddSubMatrix(dM_i,dM_j, dg2);
}
};
-3
View File
@@ -46,9 +46,6 @@ endif
ifeq ($(MFEM_USE_HIOP),YES)
SUBDIRS += hiop
endif
ifeq ($(MFEM_USE_IPOPT),YES)
SUBDIRS += ipopt
endif
ifeq ($(MFEM_USE_PETSC),YES)
SUBDIRS += petsc
endif
-888
View File
@@ -1,888 +0,0 @@
using namespace std;
using namespace mfem;
void BasisEval(const Vector xi, Vector &N, DenseMatrix &dNdxi) // dNdxi is 2*4
{
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi(0,0) = 0.25*(-1+xi[1]);
dNdxi(0,1) = 0.25*(1-xi[1]);
dNdxi(0,2) = 0.25*(1+xi[1]);
dNdxi(0,3) = 0.25*(-1-xi[1]);
dNdxi(1,0) = 0.25*(-1+xi[0]);
dNdxi(1,1) = 0.25*(-1-xi[0]);
dNdxi(1,2) = 0.25*(1+xi[0]);
dNdxi(1,3) = 0.25*(1-xi[0]);
}
void BasisEvalDerivs(const Vector xi, Vector& N, DenseMatrix& dNdxi,
DenseMatrix& dN2dxi)
{
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi.SetSize(2,4); dNdxi = 0.0;
dN2dxi.SetSize(3,4);
dN2dxi = 0.0; // first row dxi2, second detadxi, third deta2
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,1) = 0.25*(1-xi[1]);
dNdxi(0,2) = 0.25*(1+xi[1]); dNdxi(0,3) = 0.25*(-1-xi[1]);
dNdxi(1,0) = 0.25*(-1+xi[0]); dNdxi(1,1) = 0.25*(-1-xi[0]);
dNdxi(1,2) = 0.25*(1+xi[0]); dNdxi(1,3) = 0.25*(1-xi[0]);
dN2dxi(1,0) = 0.25; dN2dxi(1,1) = -0.25; dN2dxi(1,2) = 0.25;
dN2dxi(1,3) = -0.25;
}
// returns the vector and matrix form of the shape functions and its derivative
void BasisVectorDerivs(const Vector xi, DenseMatrix& N, DenseMatrix& dNdxi,
DenseMatrix& ddNdxi)
{
N.SetSize(3,12); N = 0.0;
N(0,0) = 0.25*(1-xi[0])*(1-xi[1]); N(0,3) = 0.25*(1+xi[0])*(1-xi[1]);
N(0,6) = 0.25*(1+xi[0])*(1+xi[1]); N(0,9) = 0.25*(1-xi[0])*(1+xi[1]);
N(1,1) = 0.25*(1-xi[0])*(1-xi[1]); N(1,4) = 0.25*(1+xi[0])*(1-xi[1]);
N(1,7) = 0.25*(1+xi[0])*(1+xi[1]); N(1,10) = 0.25*(1-xi[0])*(1+xi[1]);
N(2,2) = 0.25*(1-xi[0])*(1-xi[1]); N(2,5) = 0.25*(1+xi[0])*(1-xi[1]);
N(2,8) = 0.25*(1+xi[0])*(1+xi[1]); N(2,11) = 0.25*(1-xi[0])*(1+xi[1]);
dNdxi.SetSize(3*2, 3*4); dNdxi = 0.0;
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,3) = 0.25*(1-xi[1]);
dNdxi(0,6) = 0.25*(1+xi[1]); dNdxi(0,9) = 0.25*(-1-xi[1]);
dNdxi(1,1) = 0.25*(-1+xi[1]); dNdxi(1,4) = 0.25*(1-xi[1]);
dNdxi(1,7) = 0.25*(1+xi[1]); dNdxi(1,10) = 0.25*(-1-xi[1]);
dNdxi(2,2) = 0.25*(-1+xi[1]); dNdxi(2,5) = 0.25*(1-xi[1]);
dNdxi(2,8) = 0.25*(1+xi[1]); dNdxi(2,11) = 0.25*(-1-xi[1]);
dNdxi(3,0) = 0.25*(-1+xi[0]); dNdxi(3,3) = 0.25*(-1-xi[0]);
dNdxi(3,6) = 0.25*(1+xi[0]); dNdxi(3,9) = 0.25*(1-xi[0]);
dNdxi(4,1) = 0.25*(-1+xi[0]); dNdxi(4,4) = 0.25*(-1-xi[0]);
dNdxi(4,7) = 0.25*(1+xi[0]); dNdxi(4,10) = 0.25*(1-xi[0]);
dNdxi(5,2) = 0.25*(-1+xi[0]); dNdxi(5,5) = 0.25*(-1-xi[0]);
dNdxi(5,8) = 0.25*(1+xi[0]); dNdxi(5,11) = 0.25*(1-xi[0]);
ddNdxi.SetSize(3*4, 3*4); ddNdxi = 0.0;
ddNdxi(3,0) = 0.25; ddNdxi(3,3) = -0.25;
ddNdxi(3,6) = 0.25; ddNdxi(3,9) = -0.25;
ddNdxi(4,1) = 0.25; ddNdxi(4,4) = -0.25;
ddNdxi(4,7) = 0.25; ddNdxi(4,10) = -0.25;
ddNdxi(5,2) = 0.25; ddNdxi(5,5) = -0.25;
ddNdxi(5,8) = 0.25; ddNdxi(5,11) = -0.25;
ddNdxi(6,0) = 0.25; ddNdxi(6,3) = -0.25;
ddNdxi(6,6) = 0.25; ddNdxi(6,9) = -0.25;
ddNdxi(7,1) = 0.25; ddNdxi(7,4) = -0.25;
ddNdxi(7,7) = 0.25; ddNdxi(7,10) = -0.25;
ddNdxi(8,2) = 0.25; ddNdxi(8,5) = -0.25;
ddNdxi(8,8) = 0.25; ddNdxi(8,11) = -0.25;
}
void cross(const Vector a, const Vector b, Vector& c)
{
assert(a.Size()==3);
c.SetSize(3);
c[0] = a[1]*b[2] - a[2]*b[1];
c[1] = -a[0]*b[2] + b[0]*a[2];
c[2] = a[0]*b[1] - a[1]*b[0];
}
// a outer b
void outer(const Vector a, const Vector b, DenseMatrix& c)
{
int m = a.Size();
int n = b.Size();
assert(c.Height()==m);
assert(c.Width() ==n);
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
{
c(i,j) = a[i]*b[j];
}
}
}
// dphidxi 2*4
// coords 4*3
void ComputeNormal(const DenseMatrix& dphidxi, const DenseMatrix& coords,
Vector& normal, double& nnorm)
{
DenseMatrix dxdxi(2,3);
Mult(dphidxi, coords, dxdxi);
Vector dxdxi1(3);
Vector dxdxi2(3);
dxdxi.GetRow(0,dxdxi1);
dxdxi.GetRow(1,dxdxi2);
cross(dxdxi1, dxdxi2, normal); // is there a cross product? no
// VectorCrossProductCoefficient::Eval has hard-coded cross product
nnorm = normal.Norml2( );
normal /= nnorm;
}
void SlaveToMaster(const DenseMatrix& m_coords, const Vector& s_x, Vector& xi)
{
bool converged = false;
bool pt_on_elem = false;
int dim = 3;
xi.SetSize(dim-1);
xi = 0.0;
double r = 1e10;
int max_iter = 15;
double off_el_xi = 1e-2;
double proj_newton_tol = 1e-13;
double proj_max_gap = 0.5;
Vector gap_v(dim);
// warm start from linear solution
for (int it=0; it<max_iter; it++)
{
//cout<<it<<endl;
Vector m_N(4);
m_N = 0.;
DenseMatrix m_dN(2,4);
m_dN = 0.;
DenseMatrix m_dN2(3,4);
m_dN2 = 0.;
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
Vector x_c(dim);
m_coords.MultTranspose(m_N, x_c);
gap_v = s_x;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
m_dx = 0.;
Mult(m_dN, m_coords, m_dx);
Vector r(dim-1);
r = 0.0;
m_dx.Mult(gap_v, r);
if (r.Normlinf() < proj_newton_tol)
{
converged = true;
break;
}
DenseMatrix drdxi(dim-1,dim-1);
drdxi = 0.;
MultABt(m_dx, m_dx, drdxi); // m_dx * m_dx.T
drdxi *= -1.0;
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
Mult(m_dN2,m_coords, m_dx2);
//m_d2x = m_dN(:,:,2) * m_elem_coords(1:4,:); //m_dN(:,:,2) is 3*4
for (int d=0; d<3; d++)
{
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
drdxi.Add(gap_v[d], Mtemp);
}
//cond_num = rcond(drdxi); condition number?
//drdxi.TestInversion();
DenseMatrixInverse drdxi_inv(drdxi);
Vector xi_tmp(dim-1);
drdxi_inv.Mult(r,xi_tmp);
xi -= xi_tmp;
}
if (!converged)
{
xi = 0.0;
}
off_el_xi += 1 ; // tolerance of offset of xi outside [-1,1]
//cout<<gap_v.Norml2()<<" " <<xi.Normlinf()<<endl;
if (gap_v.Norml2() < proj_max_gap && xi.Normlinf() <= off_el_xi)
{
pt_on_elem = true;
}
MFEM_VERIFY(pt_on_elem == true, "xi went out of bounds");
MFEM_VERIFY(converged == true, "projection didn't converge");
}
// m_coords is expected to be 4 * 3
void ComputeGapJacobian(const Vector x_s, const Vector xi,
const DenseMatrix m_coords,
double& gap, Vector& normal, Vector& dgdxm, Vector& dgdxs)
{
Vector m_N(4);
DenseMatrix m_dN(2,4);
DenseMatrix m_dN2(3,4);
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
Vector x_c(3);
m_coords.MultTranspose(m_N, x_c);
Vector gap_v(3); gap_v = 0.0;
gap_v = x_s;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
Mult(m_dN, m_coords, m_dx);
double nnorm = 0;
ComputeNormal(m_dN, m_coords, normal, nnorm);
gap = gap_v * normal; // gap function value, dot product between vectors
//dr_dx = zeros(2,4,3); % nsegment, nodes in quad, ndim
DenseMatrix dr_dx_res1(4,3); dr_dx_res1 = 0.;
DenseMatrix dr_dx_res2(4,3); dr_dx_res2 = 0.;
Vector m_dxrow1(3);
m_dx.GetRow(0, m_dxrow1);
outer(m_N, m_dxrow1, dr_dx_res1);// 4*1 times 1*3
dr_dx_res1 *= -1.0;
Vector m_dxrow2(3);
m_dx.GetRow(1, m_dxrow2);
outer(m_N, m_dxrow2, dr_dx_res2);// 4*1 times 1*3
dr_dx_res2 *= -1.0;
Vector m_dNrow1(4); m_dN.GetRow(0, m_dNrow1);
Vector m_dNrow2(4); m_dN.GetRow(1, m_dNrow2);
DenseMatrix dr_dx_res1_tmp(4,3); dr_dx_res1_tmp = 0.;
DenseMatrix dr_dx_res2_tmp(4,3); dr_dx_res2_tmp = 0.;
outer(m_dNrow1, gap_v, dr_dx_res1_tmp);// 4*1 times 1*3
outer(m_dNrow2, gap_v, dr_dx_res2_tmp);// 4*1 times 1*3
dr_dx_res1 += dr_dx_res1_tmp; // outer product in vector?
dr_dx_res2 += dr_dx_res2_tmp;
DenseMatrix K_dxidx1(2,2); // 2*2
K_dxidx1 = 0.;
MultABt(m_dx, m_dx, K_dxidx1); // m_dx * m_dx.T
Vector v_dxidx2(4);
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
// how to get 2nd order? multidimensional matrix?
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
DenseMatrix K_dxidx(2,2);
K_dxidx -= K_dxidx1;
K_dxidx += K_dxidx2;
// resize the vectors and matrices
Vector dxidx(24); dxidx = 0.0;
Vector drdx_r(24); drdx_r = 0.0;
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
drdx_r[4*j+i] = dr_dx_res1(i,j);
drdx_r[4*j+i+12] = dr_dx_res2(i,j);
}
}
//drdx_r(1:4*3,1) = reshape(dr_dx_res(:,:,1),4*3,1);
//drdx_r(4*3+1:2*4*3,1) = reshape(dr_dx_res(:,:,2),4*3,1);
DenseMatrix drdx_K(24,24); drdx_K = 0.;
for (int i =0; i<12; i++)
{
drdx_K(i,i) = K_dxidx(0,0);
drdx_K(i,12+i) = K_dxidx(0,1);
drdx_K(12+i,i) = K_dxidx(1,0);
drdx_K(12+i,12+i) = K_dxidx(1,1);
}
DenseMatrixInverse drdxK_inv(drdx_K);
drdxK_inv.Mult(drdx_r,dxidx);
// LinearSolve (drdx_K,drdx_r, dxidx) ; //???
dxidx *= -1.0;
Vector drdxs_r(6);
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
for (int i=0; i<3; i++)
{
drdxs_K(i,i) = K_dxidx(0,0);
drdxs_K(i,3+i) = K_dxidx(0,1);
drdxs_K(i+3,i) = K_dxidx(1,0);
drdxs_K(i+3,i+3) = K_dxidx(1,1);
}
Vector dxidxs(6); dxidxs = 0.0;
DenseMatrixInverse drdxsK_inv(drdxs_K);
drdxsK_inv.Mult(drdxs_r,dxidxs);
dxidxs *= -1.0;
//dxidxs = -drdxs_K\drdxs_r;
//dxidx = reshape(dxidx, 4,3,2); dxidxs = reshape(dxidxs, 1,3,2);
dgdxm.SetSize(12); dgdxm = 0.;
DenseMatrix dgdxm_tmp(4,3);
outer(m_N, normal,dgdxm_tmp);
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
dgdxm[3*i+j] = -dgdxm_tmp(i,j);
}
}
//dxidx_M = -m_dN(1:2,:,1) * (m_coords(1:4,:)*normal'); % this turns out to be 0
dgdxs.SetSize(3);
dgdxs += normal;
//dgdxs = dgdxs + dxidx_M(1) * dxidxs(:,:,1) + dxidx_M(2) * dxidxs(:,:,2);
};
void ComputeGapHessian(const Vector x_s, const Vector xi,
const DenseMatrix m_coords,
DenseMatrix& dg2dx)
{
Vector m_N(4);
DenseMatrix m_dN(2,4);
DenseMatrix m_dN2(3,4);
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
int dim = 3;
int num_dofs1 = dim;
int num_dofs2 = 4*dim;
int num_dofs = num_dofs1 + num_dofs2;
dg2dx.SetSize(num_dofs,num_dofs); dg2dx = 0.0;
Vector x_c(3);
m_coords.MultTranspose(m_N,x_c);
Vector gap_v(3); gap_v = 0.0;
gap_v = x_s;
gap_v -= x_c;
DenseMatrix m_dx(2,3);
Mult(m_dN, m_coords, m_dx);
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
Mult(m_dN2,m_coords, m_dx2);
double nnorm = 0.0;
Vector normal(3); normal = 0.0;
ComputeNormal(m_dN, m_coords, normal, nnorm);
double gap = gap_v * normal; // gap function value, dot product between vectors
DenseMatrix M(2,2); M = 0.0;
MultABt(m_dx, m_dx, M);
DenseMatrix f(2, num_dofs2); f = 0.0;
for (int d=0; d<3; d++)
{
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
M.Add(-gap_v[d], Mtemp);
Vector m_dxcol(2); m_dx.GetColumn(d, m_dxcol);
DenseMatrix ftmp(2,4);
outer(m_dxcol, m_N, ftmp);
ftmp *= -1;
ftmp.Add( gap_v[d], m_dN); // 2*4
for (int j=0; j<4; j++)
{
assert(d+3*j<num_dofs2);
f(0,d+j*3) = ftmp(0,j);
f(1,d+j*3) = ftmp(1,j);
}
}
//fprintf('hess dxidxm\n');
DenseMatrixInverse Minv(M);
DenseMatrix dxidxm(2,num_dofs2); dxidxm = 0.0;
Minv.Mult(f, dxidxm);
//LinearSolve??
//dxidxm = M\f;
DenseMatrix nde2(2,2); nde2 = 0.0;
DenseMatrix Nndx2(2,num_dofs2); Nndx2 = 0.0;
for (int d=0; d<3; d++)
{
DenseMatrix ndetmp(2,2); ndetmp = 0.0;
ndetmp(0,0) = normal(d)*m_dx2(0,d); ndetmp(0,1) = normal(d)*m_dx2(1,d);
ndetmp(1,0) = normal(d)*m_dx2(1,d); ndetmp(1,1) = normal(d)*m_dx2(2,d);
nde2 += ndetmp;
for (int j=0; j<4; j++)
{
assert(d+3*j<num_dofs2);
Nndx2(0,d+j*3) = normal[d]*m_dN(0,j);
Nndx2(1,d+j*3) = normal[d]*m_dN(1,j);
}
}
DenseMatrix Ndn(2,num_dofs2); Ndn = 0.0;
Ndn += Nndx2;
AddMult(nde2, dxidxm, Ndn);
DenseMatrix M2(2,2); M2 = 0.0;
MultABt(m_dx, m_dx, M2);
DenseMatrixInverse M2inv(M2);
DenseMatrix diag2(2,2); diag2(0,0) = 1.0; diag2(1,1) = 1.0;
DenseMatrix m_con(2,2); m_con = 0.0;
M2inv.Mult(diag2, m_con);
DenseMatrix dg2dxm(num_dofs2, num_dofs2); dg2dxm = 0.0;
DenseMatrix dg2dxm_tmp(num_dofs2,2); dg2dxm_tmp = 0.0;
MultAtB(Ndn, m_con, dg2dxm_tmp);
Mult(dg2dxm_tmp, Ndn, dg2dxm);
dg2dxm *= gap;
DenseMatrix dg2dxm_tmp2(num_dofs2,num_dofs2); dg2dxm_tmp2 = 0.0;
MultAtB(Nndx2, dxidxm, dg2dxm_tmp2);
dg2dxm.Add(-1.0, dg2dxm_tmp2);
dg2dxm_tmp = 0.0;
MultAtB(dxidxm, nde2, dg2dxm_tmp);
AddMult_a(-1.0, dg2dxm_tmp, dxidxm, dg2dxm);
dg2dxm_tmp2 = 0.0;
MultAtB(dxidxm, Nndx2, dg2dxm_tmp2);
dg2dxm.Add(-1.0, dg2dxm_tmp2);
Vector v_dxidx2(4);
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
DenseMatrix K_dxidx(2,2);
K_dxidx -= M2;
K_dxidx += K_dxidx2;
Vector drdxs_r(6);
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
for (int i=0; i<3; i++)
{
drdxs_K(i,i) = K_dxidx(0,0);
drdxs_K(i,3+i) = K_dxidx(0,1);
drdxs_K(i+3,i) = K_dxidx(1,0);
drdxs_K(i+3,i+3) = K_dxidx(1,1);
}
Vector dxidxs(6);
DenseMatrixInverse drdxsK_inv(drdxs_K);
drdxsK_inv.Mult(drdxs_r,dxidxs);
dxidxs *= -1.0;
//dxidxs = -drdxs_K\drdxs_r;
DenseMatrix dxidxs_m(2,3); dxidxs_m = 0.0;
dxidxs_m(0,0) = dxidxs[0]; dxidxs_m(0,1) = dxidxs[1]; dxidxs_m(0,2) = dxidxs[2];
dxidxs_m(1,0) = dxidxs[3]; dxidxs_m(1,1) = dxidxs[4]; dxidxs_m(1,2) = dxidxs[5];
DenseMatrix dtao1dxs(3,3); dtao1dxs = 0.0;
DenseMatrix dtao2dxs(3,3); dtao2dxs = 0.0;
Vector dxidxs_row1(3); dxidxs_row1 = 0.0; Vector dxidxs_row2(3);
dxidxs_row2 = 0.0;
Vector mdx2_row1(3); mdx2_row1 = 0.0; Vector mdx2_row2(3); mdx2_row2 = 0.0;
Vector mdx2_row3(3); mdx2_row3 = 0.0;
dxidxs_m.GetRow(0,dxidxs_row1);
dxidxs_m.GetRow(1,dxidxs_row2);
m_dx2.GetRow(0,mdx2_row1);
m_dx2.GetRow(1,mdx2_row2);
m_dx2.GetRow(2,mdx2_row3);
DenseMatrix dtaotmp(3,3); dtaotmp = 0.0;
outer(mdx2_row1, dxidxs_row1,dtaotmp);
dtao1dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row2, dxidxs_row1,dtaotmp);
dtao1dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row2, dxidxs_row2, dtaotmp);
dtao2dxs += dtaotmp; dtaotmp = 0.0;
outer(mdx2_row3, dxidxs_row2, dtaotmp);
dtao2dxs += dtaotmp; dtaotmp = 0.0;
DenseMatrix dtaodxs(3,3); dtaodxs = 0.0; //tao = tao1 cross tao2
for (int d=0; d<3; d++)
{
Vector dtao1dxs_tmp(3); dtao1dxs_tmp = 0.0;
dtao1dxs.GetColumn(d,dtao1dxs_tmp);
Vector m_dxrow(3); m_dx.GetRow(1, m_dxrow);
Vector dtaodxs_tmp(3); dtaodxs_tmp = 0.0;
cross(dtao1dxs_tmp, m_dxrow, dtaodxs_tmp);
Vector dtaodxs_tmp2(3); dtaodxs_tmp2 = 0.0;
m_dx.GetRow(0, m_dxrow);
dtao1dxs_tmp = 0.0; // reuse the same vector for dtao2
dtao2dxs.GetColumn(d,dtao1dxs_tmp);
cross(m_dxrow, dtao1dxs_tmp, dtaodxs_tmp2);
dtaodxs_tmp2 += dtaodxs_tmp;
dtaodxs.SetCol(d, dtaodxs_tmp2);
}
DenseMatrix dndxs(3,3); dndxs = 0.0; dndxs += dtaodxs; dndxs *= 1.0/nnorm;
DenseMatrix dndxs_tmp(3,3); dndxs_tmp = 0.0;
outer(normal, normal, dndxs_tmp);
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxs, dndxs);
DenseMatrix dgvdxs(3,3); dgvdxs = 0.0;
MultAtB(m_dx, dxidxs_m, dgvdxs);
dgvdxs *= -1;
for (int d=0; d<3; d++)
{
dgvdxs(d,d) += 1.0;
}
//dxidxs: 2*3
DenseMatrix dg2dxs(3,3); dg2dxs = 0.0;
DenseMatrix dg2dxs_tmp(3,2); dg2dxs_tmp = 0.0;
MultAtB(dxidxs_m, nde2, dg2dxs_tmp);
AddMult_a(-1.0, dg2dxs_tmp, dxidxs_m, dg2dxs);
DenseMatrix dg2dxs_tmp2(3,3); dg2dxs_tmp2 = 0.0;
MultAtB(dgvdxs, dndxs, dg2dxs_tmp2);
dg2dxs += dg2dxs_tmp2;
dg2dxs_tmp2 = 0.0;
MultAtB(dndxs, dndxs_tmp, dg2dxs_tmp2);
AddMult(dg2dxs_tmp2, dgvdxs, dg2dxs);
DenseMatrix Ne(3,12), Be(6,12), dBe(12,12);
BasisVectorDerivs(xi, Ne, Be, dBe);
DenseMatrix dtao1dxm(3,12); dtao1dxm.CopyRows(Be, 0, 2);
DenseMatrix dtao2dxm(3,12); dtao2dxm.CopyRows(Be, 3, 5);
Vector m_coords_v(12);
for (int i=0; i<4; i++)
{
for (int j=0; j<3; j++)
{
m_coords_v[i*3+j] = m_coords(i,j);
}
}
for (int i=0; i<2; i++)
{
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
dxidxm.GetRow(i,dxidxm_tmp);
DenseMatrix dBe_tmp(3,12);
dBe_tmp.CopyRows(dBe,i*3,(i+1)*3-1);
DenseMatrix dtaodxm_tmp(12,12); dtaodxm_tmp = 0.0;
outer(m_coords_v, dxidxm_tmp, dtaodxm_tmp);
AddMult(dBe_tmp, dtaodxm_tmp, dtao1dxm);
//dtao1dxm += dBe(:,:,i)*reshape(m_coords(1:4,:)',12,1)*reshape(dxidxm(i,:),1,12); % 3*12
dBe_tmp = 0.0;
dBe_tmp.CopyRows(dBe,(i+2)*3,(i+3)*3-1);
AddMult(dBe_tmp, dtaodxm_tmp, dtao2dxm);
}
DenseMatrix dtaodxm(3,12); dtaodxm = 0.0;//tao = tao1 cross tao2
for (int d=0; d<12; d++)
{
Vector dtaodxm_tmp(3); dtaodxm_tmp = 0.0;
Vector dtaodxm_tmp2(3); dtaodxm_tmp2 = 0.0;
Vector tmp1(3); tmp1 = 0.0; dtao1dxm.GetColumn(d,tmp1);
Vector m_dxrow2(3); m_dx.GetRow(1, m_dxrow2);
Vector m_dxrow1(3); m_dx.GetRow(0, m_dxrow1);
Vector tmp2(3); tmp2 = 0.0; dtao2dxm.GetColumn(d,tmp2);
cross(tmp1, m_dxrow2, dtaodxm_tmp);
cross(m_dxrow1,tmp2, dtaodxm_tmp2);
dtaodxm_tmp += dtaodxm_tmp2;
dtaodxm.SetCol(d, dtaodxm_tmp);
}
DenseMatrix dndxm(3,12); dndxm = 0.0;
dndxm += dtaodxm;
dndxm *= 1.0/nnorm;
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxm, dndxm); //dndxs_tmp = normal'*normal
DenseMatrix dgvdxm(3,12); dgvdxm = 0.0;
dgvdxm -= Ne;
for (int i=0; i<2; i++)
{
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
dxidxm.GetRow(i,dxidxm_tmp);
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
DenseMatrix dgvdxm_tmp(12,12); dgvdxm_tmp = 0.0;
outer(m_coords_v, dxidxm_tmp, dgvdxm_tmp);
AddMult_a(-1.0, Be_tmp, dgvdxm_tmp, dgvdxm);
}
DenseMatrix dg2dxsxm(3,12); dg2dxsxm = 0.0;
DenseMatrix dg2dxsxm_tmp(3,3); dg2dxsxm_tmp = 0.0;
MultAtB(dgvdxs, dndxm, dg2dxsxm);
MultAtB(dndxs, dndxs_tmp, dg2dxsxm_tmp);
AddMult(dg2dxsxm_tmp, dgvdxm, dg2dxsxm); // += dndxs'*normal'*normal*dgvdxm;
DenseMatrix dgvdxsxmn(3,12); dgvdxsxmn = 0.0;
DenseMatrix dgvdxsxmn_tmp(3,2); dgvdxsxmn_tmp = 0.0;
MultAtB(dxidxs_m, nde2, dgvdxsxmn_tmp); //dxidxs_m: 2*3
AddMult_a(-1.0, dgvdxsxmn_tmp, dxidxm, dgvdxsxmn);
for (int i =0; i<2; i++)
{
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
DenseMatrix dgvdxsxmn_tmp2(3,3); dgvdxsxmn_tmp2 = 0.0;
outer(dxidxs_row, normal, dgvdxsxmn_tmp2);
AddMult_a(-1.0, dgvdxsxmn_tmp2, Be_tmp, dgvdxsxmn);
}
dg2dxsxm += dgvdxsxmn;
DenseMatrix dg2dxmxs(12,3); dg2dxmxs = 0.0;
DenseMatrix dg2dxmxs_tmp(12,3); dg2dxmxs_tmp = 0.0;
MultAtB(dgvdxm, dndxs, dg2dxmxs);
MultAtB(dndxm, dndxs_tmp, dg2dxmxs_tmp);
AddMult(dg2dxmxs_tmp, dgvdxs, dg2dxmxs);
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
DenseMatrix dgvdxmxsn_tmp(12,2); dgvdxmxsn_tmp = 0.0;
MultAtB(dxidxm, nde2, dgvdxmxsn_tmp);
dgvdxmxsn_tmp *= -1.0;
AddMult(dgvdxmxsn_tmp, dxidxs_m, dgvdxmxsn);
for (int i =0; i<2; i++)
{
DenseMatrix Be_tmp(3,12);
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
Be_tmp.Transpose(); // Be is now 12*3
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
DenseMatrix dgvdxmxsn_tmp2(3,3); dgvdxmxsn_tmp2 = 0.0;
outer(normal, dxidxs_row, dgvdxmxsn_tmp2);
AddMult_a(-1.0, Be_tmp, dgvdxmxsn_tmp2, dgvdxmxsn);
}
dg2dxmxs += dgvdxmxsn;
dg2dx.CopyMN(dg2dxs, 0, 0);
dg2dx.CopyMN(dg2dxm, 3, 3);
dg2dx.CopyMN(dg2dxsxm, 0, 3);
dg2dx.CopyMN(dg2dxmxs, 3, 0);
};
void NodeSegConPairs(const Vector x1, const Vector xi2,
const DenseMatrix coords2,
double& node_g, Vector& node_dg, DenseMatrix& node_dg2)
{
double gap = 0.0;
Vector normal(3); normal = 0.0;
Vector dgdxm(12); dgdxm = 0.0;
Vector dgdxs(3); dgdxs = 0.0;
ComputeGapJacobian(x1, xi2, coords2, gap, normal, dgdxm, dgdxs);
node_g = gap;
node_dg.SetSize(12+3);
for (int i=0; i<3; i++) { node_dg[i] = dgdxs[i]; }
for (int i=0; i<12; i++) { node_dg[i+3] = dgdxm[i]; }
DenseMatrix dg2dx(15,15); dg2dx = 0.0;
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
ComputeGapHessian(x1, xi2, coords2, dg2dx);
node_dg2.SetSize(15,15);
node_dg2 = dg2dx;
/*
if(obj.space1.conns{e1}(i)==150) % for debugging purpose
v1 = 1:3;
v2 = 1:12;
%v1 = ones(1,3)
%v2 = ones(1,12)
v2 = reshape(v2,4,3);
x1n1 = x1 + 0.01*v1;
coords2n1 = coords2 + 0.001*v2;
[xi2n1, gapv1, ~, ~] = SlaveToMaster(obj, coords2n1, x1n1);
[gapn1, n1,dgdxmn1, dgdxsn1] = ComputeGapJacobian(obj, x1n1, xi2n1, coords2n1);
x1n2 = x1 - 0.01*v1;
coords2n2 = coords2 - 0.001*v2;
[xi2n2, gapv2, ~, ~] = SlaveToMaster(obj, coords2n2, x1n2);
[gapn2, n2,dgdxmn2, dgdxsn2] = ComputeGapJacobian(obj, x1n2, xi2n2, coords2n2);
fprintf('fd\n');
%gapv1-gapv2
[dgdxsn1(:)',dgdxmn1(:)'] - [dgdxsn2(:)',dgdxmn2(:)']
%dgdxsn1-dgdxsn2
fprintf('code\n');
v2n = v2';
%dg2dx(1:3,1:3)*0.04*ones(3,1)
temp = zeros(12,3);
for i = 1:4
temp1 = dg2dx(3+(i-1)*3+1:3+i*3,1:3);
temp((i-1)*3+1:i*3,:) = temp1';
end
temp2 = zeros(3,12);
for i = 1:4
temp3 = dg2dx(1:3,3+(i-1)*3+1:3+i*3);
temp2(:,(i-1)*3+1:i*3) = temp3';
end
%dg2dx
%dg2dx(4:end,1:3) = temp;
%dg2dx(1:3,4:end) = temp2;
%dgvdxm * 0.002*v2n(:)
(dg2dx*[0.02*v1(:)',0.002*v2n(:)']')'
%dg2dx(4:end,1:3)
end*/
};
// coordsm : (npoints*4, 3) use what class?
// m_conn: (npoints*4)
void Assemble_Contact(const int m, const int npoints, const int ndofs,
const Vector x_s,
const Vector xi, const DenseMatrix coordsm, const Array<int> s_conn,
const Array<int> m_conn, Vector& g, SparseMatrix& M,
std::vector<SparseMatrix>& dM)
{
int n = ndofs;
int ndim = 3;
g.SetSize(m);
g = 0.0;
//SparseMatrix M(m, n); // M needs to be the correct size
//dM.resize(m); // needs to clear?
double g_tmp = 0.;
Vector dg(4*ndim+ndim);
dg = 0.;
DenseMatrix dg2(4*ndim+ndim,4*ndim+ndim);
dg2 = 0.;
for (int i=0; i<npoints; i++)
{
Vector x1(ndim);
x1[0] = x_s[i*ndim];
x1[1] = x_s[i*ndim+1];
x1[2] = x_s[i*ndim+2];
Vector xi2(ndim-1);
xi2[0] = xi[i*(ndim-1)];
xi2[1] = xi[i*(ndim-1)+1];
DenseMatrix coords2(4,3);
coords2.CopyRows(coordsm, i*4,(i+1)*4-1);
//how to get coords2?
dg = 0.0;
dg2 = 0.;
NodeSegConPairs(x1, xi2, coords2, g_tmp, dg, dg2);
//x1.Print();
//xi2.Print();
//coords2.Print();
g[s_conn[i]] = g_tmp; // should be unique
Array<int> m_conn_i(4);
m_conn.GetSubArray(4*i, 4, m_conn_i);
Array<int> node_conn(5);
node_conn[0] = s_conn[i];
for (int j=0; j<4; j++)
{
node_conn[j+1] = m_conn_i[j];
}
Array<int> M_i_tmp(1);
M_i_tmp[0] = s_conn[i];
//j_idx = (node_conn-1)*obj.disp_field.num_components +repmat((1:obj.disp_field.num_components)', 1, length(node_conn{i}));
Array<int> j_idx(5*ndim); j_idx = 0;
for (int j=0; j< 5; j++)
{
for (int k=0; k<ndim; k++)
{
j_idx[j*ndim+k] = node_conn[j]*ndim+k;
}
}
DenseMatrix M_v_tmp(1, ndim*(4+1)); // SetData now?
M_v_tmp.SetRow(0, dg);
M.AddSubMatrix(M_i_tmp, j_idx, M_v_tmp);
Array<int> dM_i(ndim*(4+1));
Array<int> dM_j(ndim*(4+1));
for (int j=0; j< ndim*(4+1); j++)
{
dM_i[j] = j_idx[j];
dM_j[j] = j_idx[j];
}
//dg2.Print();
//dM[s_conn[i]].Print();
dM[s_conn[i]].AddSubMatrix(dM_i,dM_j, dg2);
}
};
+63
View File
@@ -278,6 +278,13 @@ void BilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator *bfi,
boundary_face_integs_marker.Append(&bdr_marker);
}
void BilinearForm::AddInteriorBoundaryFaceIntegrator(BilinearFormIntegrator* bfi,
Array<int>& int_bdr_marker)
{
interior_boundary_face_integs.Append(bfi);
interior_boundary_face_integs_marker.Append(&int_bdr_marker);
}
void BilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat)
{
if (element_matrices)
@@ -628,6 +635,62 @@ void BilinearForm::Assemble(int skip_zeros)
}
}
}
if (interior_boundary_face_integs.Size())
{
FaceElementTransformations* tr;
Array<int> vdofs2;
const FiniteElement* fe1, * fe2;
// Which interior boundary attributes need to be processed?
Array<int> int_bdr_attr_marker(mesh->bdr_attributes.Size() ?
mesh->bdr_attributes.Max() : 0);
int_bdr_attr_marker = 0;
for (int k = 0; k < interior_boundary_face_integs.Size(); k++)
{
if (interior_boundary_face_integs_marker[k] == NULL)
{
int_bdr_attr_marker = 1;
break;
}
Array<int>& int_bdr_marker = *interior_boundary_face_integs_marker[k];
MFEM_ASSERT(int_bdr_marker.Size() == int_bdr_attr_marker.Size(),
"invalid boundary marker for boundary face integrator #"
<< k << ", counting from zero");
for (int i = 0; i < int_bdr_attr_marker.Size(); i++)
{
int_bdr_attr_marker[i] |= int_bdr_marker[i];
}
}
for (int i = 0; i < fes->GetNBE(); i++)
{
const int mesh_bdr_attr = mesh->GetBdrAttribute(i);
if (int_bdr_attr_marker[mesh_bdr_attr - 1] == 0) { continue; }
tr = mesh->GetInteriorFaceTransformations(mesh->GetBdrFace(i));
if (tr != NULL)
{
fes->GetElementVDofs(tr->Elem1No, vdofs);
fes->GetElementVDofs(tr->Elem2No, vdofs2);
vdofs.Append(vdofs2);
fe1 = fes->GetFE(tr->Elem1No);
fe2 = fes->GetFE(tr->Elem2No);
for (int k = 0; k < interior_boundary_face_integs.Size(); k++)
{
if (interior_boundary_face_integs_marker[k] &&
(*interior_boundary_face_integs_marker[k])[mesh_bdr_attr - 1] == 0)
{
continue;
}
interior_boundary_face_integs[k]->AssembleFaceMatrix(*fe1, *fe2, *tr,
elemmat);
mat->AddSubMatrix(vdofs, vdofs, elemmat, skip_zeros);
}
}
}
}
}
#ifdef MFEM_USE_LEGACY_OPENMP
+14
View File
@@ -113,6 +113,10 @@ protected:
Array<BilinearFormIntegrator*> boundary_face_integs;
Array<Array<int>*> boundary_face_integs_marker; ///< Entries are not owned.
/// Set of interior boundary face Integrators to be applied.
Array<BilinearFormIntegrator*> interior_boundary_face_integs;
Array<Array<int>*> interior_boundary_face_integs_marker; ///< Entries are not owned.
DenseMatrix elemmat;
Array<int> vdofs;
@@ -272,6 +276,11 @@ public:
Array<Array<int>*> *GetBFBFI_Marker()
{ return &boundary_face_integs_marker; }
/// Access all the integrators added with AddInteriorBoundaryFaceIntegrator().
Array<BilinearFormIntegrator*>* GetIBFI() { return &interior_boundary_face_integs; }
/** @brief Access all boundary markers added with AddInteriorBoundaryFaceIntegrator().*/
Array<Array<int>*>* GetIBFI_Marker() { return &interior_boundary_face_integs_marker; }
/// Returns a reference to: \f$ M_{ij} \f$
const double &operator()(int i, int j) { return (*mat)(i,j); }
@@ -416,6 +425,11 @@ public:
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi,
Array<int> &bdr_marker);
/// Adds new Interior Boundary Integrator restricted to certain faces specified by
/// the @a int_bdr_marker.
void AddInteriorBoundaryFaceIntegrator(BilinearFormIntegrator* bfi,
Array<int>& int_bdr_marker);
/// Sets all sparse values of \f$ M \f$ and \f$ M_e \f$ to 'a'.
void operator=(const double a)
{
+21 -5
View File
@@ -56,7 +56,8 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
dim = mesh->Dimension();
ne = fes.GetMesh()->GetNE();
nq = ir->GetNPoints();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::DETERMINANTS, mt);
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::COORDINATES |
GeometricFactors::JACOBIANS, mt);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
@@ -73,7 +74,7 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
const auto J = Reshape(geom->detJ.Read(), Q1D,Q1D,NE);
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,2,2,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D, NE);
@@ -83,7 +84,11 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double detJ = J(qx,qy,e);
const double J11 = J(qx,qy,0,0,e);
const double J12 = J(qx,qy,1,0,e);
const double J21 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double detJ = (J11*J22)-(J21*J12);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
v(qx,qy,e) = W(qx,qy) * coeff * (by_val ? detJ : 1.0/detJ);
}
@@ -97,7 +102,7 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(geom->detJ.Read(), Q1D,Q1D,Q1D,NE);
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,Q1D,3,3,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D,Q1D,NE);
@@ -109,7 +114,18 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double detJ = J(qx,qy,qz,e);
const double J11 = J(qx,qy,qz,0,0,e);
const double J21 = J(qx,qy,qz,1,0,e);
const double J31 = J(qx,qy,qz,2,0,e);
const double J12 = J(qx,qy,qz,0,1,e);
const double J22 = J(qx,qy,qz,1,1,e);
const double J32 = J(qx,qy,qz,2,1,e);
const double J13 = J(qx,qy,qz,0,2,e);
const double J23 = J(qx,qy,qz,1,2,e);
const double J33 = J(qx,qy,qz,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double coeff = const_c ? C(0,0,0,0) : C(qx,qy,qz,e);
v(qx,qy,qz,e) = W(qx,qy,qz) * coeff * (by_val ? detJ : 1.0/detJ);
}
+17 -20
View File
@@ -110,8 +110,8 @@ DataCollection::DataCollection(const std::string& collection_name, Mesh *mesh_)
precision = precision_default;
pad_digits_cycle = pad_digits_rank = pad_digits_default;
format = SERIAL_FORMAT; // use serial mesh format
compression = 0;
error = No_Error;
compression = false;
error = NO_ERROR;
}
void DataCollection::SetMesh(Mesh *new_mesh)
@@ -494,7 +494,7 @@ void VisItDataCollection::Load(int cycle_)
{
DeleteAll();
time_step = 0.0;
error = No_Error;
error = NO_ERROR;
cycle = cycle_;
std::string root_name = prefix_path + name + "_" +
to_padded_string(cycle, pad_digits_cycle) +
@@ -767,13 +767,10 @@ ParaViewDataCollection::ParaViewDataCollection(const std::string&
high_order_output(false),
restart_mode(false)
{
cycle = 0; // always include a valid cycle index in file names
compression_level = -1; // default zlib compression level, equivalent to 6
#ifdef MFEM_USE_ZLIB
compression = true; // if we have zlib, enable compression
compression = -1; // default zlib compression level, equivalent to 6
#else
compression = false; // otherwise, disable compression
compression = 0;
#endif
}
@@ -922,7 +919,7 @@ void ParaViewDataCollection::Save()
{
const std::string &field_name = qfield.first;
std::ofstream os(vtu_prefix + GenerateVTUFileName(field_name, myid));
qfield.second->SaveVTU(os, pv_data_format, GetCompressionLevel());
qfield.second->SaveVTU(os, pv_data_format, compression);
}
// MPI rank 0 also creates a "PVTU" file that points to all of the separately
@@ -1036,13 +1033,13 @@ void ParaViewDataCollection::WritePVTUFooter(std::ostream &os,
void ParaViewDataCollection::SaveDataVTU(std::ostream &os, int ref)
{
os << "<VTKFile type=\"UnstructuredGrid\"";
if (GetCompressionLevel() != 0)
if (compression != 0)
{
os << " compressor=\"vtkZLibDataCompressor\"";
}
os << " version=\"0.1\" byte_order=\"" << VTKByteOrder() << "\">\n";
os << "<UnstructuredGrid>\n";
mesh->PrintVTU(os,ref,pv_data_format,high_order_output,GetCompressionLevel());
mesh->PrintVTU(os,ref,pv_data_format,high_order_output,compression);
// dump out the grid functions as point data
os << "<PointData >\n";
@@ -1106,7 +1103,7 @@ void ParaViewDataCollection::SaveGFieldVTU(std::ostream &os, int ref_,
if (IsBinaryFormat())
{
WriteVTKEncodedCompressed(os,buf.data(),buf.size(),GetCompressionLevel());
WriteVTKEncodedCompressed(os,buf.data(),buf.size(),compression);
os << '\n';
}
os << "</DataArray>" << std::endl;
@@ -1131,13 +1128,18 @@ void ParaViewDataCollection::SetCompressionLevel(int compression_level_)
{
MFEM_ASSERT(compression_level_ >= -1 && compression_level_ <= 9,
"Compression level must be between -1 and 9 (inclusive).");
compression_level = compression_level_;
compression = compression_level_ != 0;
compression = compression_level_;
}
void ParaViewDataCollection::SetCompression(bool compression_)
{
compression = compression_;
// If we are enabling compression, and it was disabled previously, use the
// default compression level. Otherwise, leave the compression level
// unchanged.
if (compression_ && compression == 0)
{
SetCompressionLevel(-1);
}
}
void ParaViewDataCollection::UseRestartMode(bool restart_mode_)
@@ -1169,9 +1171,4 @@ const char *ParaViewDataCollection::GetDataTypeString() const
}
}
int ParaViewDataCollection::GetCompressionLevel() const
{
return compression ? compression_level : 0;
}
} // end namespace MFEM
+9 -36
View File
@@ -378,24 +378,12 @@ public:
virtual ~DataCollection();
/// Errors returned by Error()
enum
{
// Workaround for use with headers that define NO_ERROR as a macro,
// e.g. winerror.h (which is included by Windows.h):
#ifndef NO_ERROR
NO_ERROR = 0,
#endif
// Use the following identifier if NO_ERROR is defined as a macro,
// e.g. winerror.h (which is included by Windows.h):
No_Error = 0,
READ_ERROR = 1,
WRITE_ERROR = 2
};
enum { NO_ERROR = 0, READ_ERROR = 1, WRITE_ERROR = 2 };
/// Get the current error state
int Error() const { return error; }
/// Reset the error state
void ResetError(int err_state = No_Error) { error = err_state; }
void ResetError(int err_state = NO_ERROR) { error = err_state; }
#ifdef MFEM_USE_MPI
friend class ParMesh;
@@ -507,7 +495,6 @@ class ParaViewDataCollection : public DataCollection
{
private:
int levels_of_detail;
int compression_level;
std::fstream pvd_stream;
VTKFormat pv_data_format;
bool high_order_output;
@@ -520,9 +507,6 @@ protected:
void SaveGFieldVTU(std::ostream& out, int ref_, const FieldMapIterator& it);
const char *GetDataFormatString() const;
const char *GetDataTypeString() const;
/// @brief If compression is enabled, return the compression level, otherwise
/// return 0.
int GetCompressionLevel() const;
std::string GenerateCollectionPath();
std::string GenerateVTUFileName(const std::string &prefix, int rank);
@@ -541,7 +525,7 @@ public:
mfem::Mesh *mesh_ = NULL);
/// Set refinement levels - every element is uniformly split based on
/// levels_of_detail_. The initial value is 1.
/// levels_of_detail_
void SetLevelsOfDetail(int levels_of_detail_);
/// Save the collection - the directory name is constructed based on the
@@ -552,27 +536,18 @@ public:
/// VTKFormat::ASCII, VTKFormat::BINARY, and VTKFormat::BINARY32.
/// The ASCII and BINARY options output double precision data, whereas the
/// BINARY32 option outputs single precision data.
///
/// The initial format is VTKFormat::BINARY.
void SetDataFormat(VTKFormat fmt);
/// @brief Set the zlib compression level.
///
/// 0 indicates no compression, -1 indicates the default compression level.
/// Otherwise, specify a number between 1 and 9, 1 being the fastest, and 9
/// being the best compression. Compression only takes effect if the output
/// format is BINARY or BINARY32. MFEM must be compiled with MFEM_USE_ZLIB =
/// YES.
///
/// The initial compression level is 0 if MFEM is compiled with MFEM_USE_ZLIB
/// turned off, and -1 otherwise.
///
/// Any nonzero compression level will enable compression.
/// Set the zlib compression level. 0 indicates no compression, -1 indicates
/// the default compression level. Otherwise, specify a number between 1 and
/// 9, 1 being the fastest, and 9 being the best compression. Compression
/// only takes effect if the output format is BINARY or BINARY32. MFEM must
/// be compiled with MFEM_USE_ZLIB = YES.
void SetCompressionLevel(int compression_level_);
/// Enable or disable zlib compression. If the input is true, use the default
/// zlib compression level (unless the compression level has previously been
/// set by calling SetCompressionLevel()).
/// set by calling SetCompressionLevel).
void SetCompression(bool compression_) override;
/// Returns true if the output format is BINARY or BINARY32, false if ASCII.
@@ -585,8 +560,6 @@ public:
/// Enable or disable restart mode. If restart is enabled, new writes will
/// preserve timestep metadata for any solutions prior to the currently
/// defined time.
///
/// Initially, restart mode is disabled.
void UseRestartMode(bool restart_mode_);
/// Load the collection - not implemented in the ParaView writer
+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());
+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
-2
View File
@@ -35,8 +35,6 @@
#ifndef __ZSTR_HPP
#define __ZSTR_HPP
#include "../config/config.hpp"
#include <cassert>
#include <fstream>
#include <sstream>
-3
View File
@@ -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))
+3 -39
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);
@@ -10516,7 +10480,7 @@ void Mesh::PrintVTU(std::string fname,
bool bdr)
{
int ref = (high_order_output && Nodes)
? Nodes->FESpace()->GetMaxElementOrder() : 1;
? Nodes->FESpace()->GetElementOrder(0) : 1;
fname = fname + ".vtu";
std::fstream os(fname.c_str(),std::ios::out);
+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);
-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 -6
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,13 @@ 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}*
+3 -47
View File
@@ -384,7 +384,6 @@ int main (int argc, char *argv[])
"o) Reorder elements\n"
"S) Save in MFEM format\n"
"V) Save in VTK format (only linear and quadratic meshes)\n"
"D) Save as a DataCollection\n"
"q) Quit\n"
#ifdef MFEM_USE_ZLIB
"Z) Save in MFEM format with compression\n"
@@ -959,9 +958,7 @@ int main (int argc, char *argv[])
cin >> nxyz[2]; np *= nxyz[2];
}
}
int *part = mesh->CartesianPartitioning(nxyz);
partitioning = Array<int>(part, mesh->GetNE());
delete [] part;
partitioning = Array<int>(mesh->CartesianPartitioning(nxyz), mesh->GetNE());
recover_bdr_partitioning(mesh, partitioning, bdr_partitioning);
}
else if (pk == 's')
@@ -985,9 +982,8 @@ int main (int argc, char *argv[])
}
cout << "Enter number of processors: " << flush;
cin >> np;
int *part = mesh->GeneratePartitioning(np, part_method);
partitioning = Array<int>(part, mesh->GetNE());
delete [] part;
partitioning = Array<int>(mesh->GeneratePartitioning(np, part_method),
mesh->GetNE());
recover_bdr_partitioning(mesh, partitioning, bdr_partitioning);
}
if (partitioning)
@@ -1194,46 +1190,6 @@ int main (int argc, char *argv[])
cout << "New VTK mesh file: " << omesh_file << endl;
}
if (mk == 'D')
{
cout << "What type of DataCollection?\n"
"p) ParaView Data Collection\n"
"v) VisIt Data Collection\n"
"--> " << flush;
char dk;
cin >> dk;
if (dk == 'p' || dk == 'P')
{
const char omesh_file[] = "mesh-explorer-paraview";
ParaViewDataCollection dc(omesh_file, mesh);
if (mesh->GetNodes())
{
int order = mesh->GetNodes()->FESpace()->GetMaxElementOrder();
if (order > 1)
{
dc.SetHighOrderOutput(true);
dc.SetLevelsOfDetail(order);
}
}
dc.Save();
cout << "New ParaView mesh file: " << omesh_file << endl;
}
else if (dk == 'v' || dk == 'V')
{
const char omesh_file[] = "mesh-explorer-visit";
VisItDataCollection dc(omesh_file, mesh);
dc.SetPrecision(14);
dc.Save();
cout << "New VisIt mesh file: " << omesh_file << "_000000.mfem_root"
<< endl;
}
else
{
cout << "Unrecognized DataCollection type: \"" << dk << "\""
<< endl;
}
}
#ifdef MFEM_USE_ZLIB
if (mk == 'Z')
{
+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
-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
+1 -1
View File
@@ -117,7 +117,7 @@ int main(int argc, char *argv[])
dc.SetPadDigitsRank(pad_digits_rank);
dc.Load(cycle);
if (dc.Error() != DataCollection::No_Error)
if (dc.Error() != DataCollection::NO_ERROR)
{
mfem::out << "Error loading VisIt data collection: " << coll_name << endl;
return 1;
+1 -1
View File
@@ -73,7 +73,7 @@ int main(int argc, char *argv[])
dc.SetPadDigitsRank(pad_digits_rank);
dc.Load(cycle);
if (dc.Error() != DataCollection::No_Error)
if (dc.Error() != DataCollection::NO_ERROR)
{
mfem::out << "Error loading VisIt data collection: " << coll_name << endl;
return 1;
+25 -33
View File
@@ -170,6 +170,7 @@ int main(int argc, char *argv[])
gt = new L2ProjectionGridTransfer(fespace, fespace_lor);
}
const Operator &R = gt->ForwardOperator();
const Operator &P = gt->BackwardOperator();
// HO->LOR restriction
direction = "HO -> LOR @ LOR";
@@ -177,29 +178,24 @@ int main(int argc, char *argv[])
compute_mass(&fespace_lor, ho_mass, LOR_dc, "R(HO) ");
if (vis) { visualize(LOR_dc, "R(HO)", Wx, Wy); Wx += offx; }
if (gt->SupportsBackwardsOperator())
{
const Operator &P = gt->BackwardOperator();
// LOR->HO prolongation
direction = "HO -> LOR @ HO";
GridFunction rho_prev = rho;
P.Mult(rho_lor, rho);
compute_mass(&fespace, ho_mass, HO_dc, "P(R(HO)) ");
if (vis) { visualize(HO_dc, "P(R(HO))", Wx, Wy); Wx = 0; Wy += offy; }
// LOR->HO prolongation
direction = "HO -> LOR @ HO";
GridFunction rho_prev = rho;
P.Mult(rho_lor, rho);
compute_mass(&fespace, ho_mass, HO_dc, "P(R(HO)) ");
if (vis) { visualize(HO_dc, "P(R(HO))", Wx, Wy); Wx = 0; Wy += offy; }
rho_prev -= rho;
cout.precision(12);
cout << "|HO - P(R(HO))|_∞ = " << rho_prev.Normlinf() << endl;
}
rho_prev -= rho;
cout.precision(12);
cout << "|HO - P(R(HO))|_∞ = " << rho_prev.Normlinf() << endl;
// HO* to LOR* dual fields
GridFunction ones(&fespace), ones_lor(&fespace_lor);
ones = 1.0;
ones_lor = 1.0;
LinearForm M_rho(&fespace), M_rho_lor(&fespace_lor);
if (!use_pointwise_transfer && gt->SupportsBackwardsOperator())
if (!use_pointwise_transfer)
{
const Operator &P = gt->BackwardOperator();
M_ho.Mult(rho, M_rho);
P.MultTranspose(M_rho, M_rho_lor);
cout << "HO -> LOR dual field: " << fabs(M_rho(ones)-M_rho_lor(ones_lor))
@@ -213,26 +209,22 @@ int main(int argc, char *argv[])
double lor_mass = compute_mass(&fespace_lor, -1.0, LOR_dc, "LOR ");
if (vis) { visualize(LOR_dc, "LOR", Wx, Wy); Wx += offx; }
if (gt->SupportsBackwardsOperator())
{
const Operator &P = gt->BackwardOperator();
// Prolongate to HO space
direction = "LOR -> HO @ HO";
P.Mult(rho_lor, rho);
compute_mass(&fespace, lor_mass, HO_dc, "P(LOR) ");
if (vis) { visualize(HO_dc, "P(LOR)", Wx, Wy); Wx += offx; }
// Prolongate to HO space
direction = "LOR -> HO @ HO";
P.Mult(rho_lor, rho);
compute_mass(&fespace, lor_mass, HO_dc, "P(LOR) ");
if (vis) { visualize(HO_dc, "P(LOR)", Wx, Wy); Wx += offx; }
// Restrict back to LOR space. This won't give the original function because
// the rho_lor doesn't necessarily live in the range of R.
direction = "LOR -> HO @ LOR";
R.Mult(rho, rho_lor);
compute_mass(&fespace_lor, lor_mass, LOR_dc, "R(P(LOR))");
if (vis) { visualize(LOR_dc, "R(P(LOR))", Wx, Wy); }
// Restrict back to LOR space. This won't give the original function because
// the rho_lor doesn't necessarily live in the range of R.
direction = "LOR -> HO @ LOR";
R.Mult(rho, rho_lor);
compute_mass(&fespace_lor, lor_mass, LOR_dc, "R(P(LOR))");
if (vis) { visualize(LOR_dc, "R(P(LOR))", Wx, Wy); }
rho_lor_prev -= rho_lor;
cout.precision(12);
cout << "|LOR - R(P(LOR))|_∞ = " << rho_lor_prev.Normlinf() << endl;
}
rho_lor_prev -= rho_lor;
cout.precision(12);
cout << "|LOR - R(P(LOR))|_∞ = " << rho_lor_prev.Normlinf() << endl;
// LOR* to HO* dual fields
if (!use_pointwise_transfer)
+2 -9
View File
@@ -25,9 +25,7 @@ include $(DEFAULTS_MK)
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_MINIAPPS = display-basis load-dc convert-dc get-values lor-transfer \
check-tmop-metric tmop-metric-magnitude
SEQ_MINIAPPS = display-basis load-dc convert-dc get-values lor-transfer
PAR_MINIAPPS =
ifeq ($(MFEM_USE_MPI),NO)
MINIAPPS = $(SEQ_MINIAPPS)
@@ -62,10 +60,6 @@ display-basis: %: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK) | lib-common
$(MFEM_CXX) $(MFEM_FLAGS) -c $(<)
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $@.o $(COMMON_LIB) $(MFEM_LIBS)
tmop-metric-magnitude: %: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK) | lib-common
$(MFEM_CXX) $(MFEM_FLAGS) -c $(<)
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $@.o $(COMMON_LIB) $(MFEM_LIBS)
# Rule for building lib-common
lib-common:
$(MAKE) -C $(MFEM_BUILD_DIR)/miniapps/common
@@ -82,8 +76,7 @@ RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
# Testing: Specific execution options
# Do not test: display-basis, load-dc, convert-dc, get-values, lor-transfer
NO_TEST_APPS = display-basis load-dc convert-dc get-values lor-transfer \
check-tmop-metric tmop-metric-magnitude
NO_TEST_APPS = display-basis load-dc convert-dc get-values lor-transfer
$(foreach app,$(NO_TEST_APPS),$(app)-test-seq $(app)-test-par):
@true
-204
View File
@@ -1,204 +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.
//
// Checks evaluation / 1st derivative / 2nd derivative for TMOP metrics. Serial.
// ./tmop-metric-magnitude -mid 2 -p 2.0
//
#include "mfem.hpp"
#include "../common/mfem-common.hpp"
#include <iostream>
using namespace mfem;
using namespace std;
void Form2DJac(double perturb_v, double perturb_ar, double perturb_s,
DenseMatrix &J);
void Form3DJac(double perturb_v, double perturb_ar, double perturb_s,
DenseMatrix &J);
int main(int argc, char *argv[])
{
int metric_id = 2;
double perturb_v = 1.0;
double perturb_ar = 1.0;
double perturb_s = 1.0;
OptionsParser args(argc, argv);
args.AddOption(&metric_id, "-mid", "--metric-id", "Metric id");
args.AddOption(&perturb_v, "-pv", "--perturb-factor-volume",
"Volume perturbation factor w.r.t. the ideal element.");
args.AddOption(&perturb_ar, "-par", "--perturb-factor-aspect-ratio",
"Aspect ratio perturbation factor w.r.t. the ideal element.");
args.AddOption(&perturb_s, "-ps", "--perturb-factor-skew",
"Skew perturbation factor w.r.t. the ideal element.");
args.Parse();
if (!args.Good()) { args.PrintUsage(cout); return 1; }
args.PrintOptions(cout);
// Setup metric.
TMOP_QualityMetric *metric = NULL;
switch (metric_id)
{
// T-metrics
case 1: metric = new TMOP_Metric_001; break;
case 2: metric = new TMOP_Metric_002; break;
case 7: metric = new TMOP_Metric_007; break;
case 9: metric = new TMOP_Metric_009; break;
case 14: metric = new TMOP_Metric_014; break;
case 50: metric = new TMOP_Metric_050; break;
case 55: metric = new TMOP_Metric_055; break;
case 56: metric = new TMOP_Metric_056; break;
case 58: metric = new TMOP_Metric_058; break;
case 77: metric = new TMOP_Metric_077; break;
case 85: metric = new TMOP_Metric_085; break;
case 98: metric = new TMOP_Metric_098; break;
// case 211: metric = new TMOP_Metric_211; break;
// case 252: metric = new TMOP_Metric_252(tauval); break;
case 301: metric = new TMOP_Metric_301; break;
case 302: metric = new TMOP_Metric_302; break;
case 303: metric = new TMOP_Metric_303; break;
case 304: metric = new TMOP_Metric_304; break;
// case 311: metric = new TMOP_Metric_311; break;
case 315: metric = new TMOP_Metric_315; break;
case 316: metric = new TMOP_Metric_316; break;
case 321: metric = new TMOP_Metric_321; break;
case 322: metric = new TMOP_Metric_322; break;
case 323: metric = new TMOP_Metric_323; break;
// case 352: metric = new TMOP_Metric_352(tauval); break;
case 360: metric = new TMOP_Metric_360; break;
// A-metrics
case 11: metric = new TMOP_AMetric_011; break;
case 36: metric = new TMOP_AMetric_036; break;
case 107: metric = new TMOP_AMetric_107a; break;
default: cout << "Unknown metric_id: " << metric_id << endl; return 3;
}
const int dim = (metric_id < 300) ? 2 : 3;
Mesh *mesh;
if (dim == 2)
{
mesh = new Mesh(Mesh::MakeCartesian2D(1, 1, Element::QUADRILATERAL));
}
else
{
mesh = new Mesh(Mesh::MakeCartesian3D(1, 1, 1, Element::HEXAHEDRON));
}
H1_FECollection fec(1, dim);
FiniteElementSpace fespace(mesh, &fec, dim);
mesh->SetNodalFESpace(&fespace);
GridFunction x(&fespace);
mesh->SetNodalGridFunction(&x);
socketstream sock1;
common::VisualizeMesh(sock1, "localhost", 19916, *mesh, "ideal", 0, 0);
DenseMatrix J;
(dim == 2) ? Form2DJac(perturb_v, perturb_ar, perturb_s, J)
/* */ : Form3DJac(perturb_v, perturb_ar, perturb_s, J);
const int nodes_cnt = x.Size() / dim;
for (int i = 0; i < nodes_cnt; i++)
{
Vector X(dim);
for (int d = 0; d < dim; d++) { X(d) = x(i + d * nodes_cnt); }
Vector Jx(dim);
J.Mult(X, Jx);
for (int d = 0; d < dim; d++) { x(i + d * nodes_cnt) = Jx(d); }
}
socketstream sock2;
common::VisualizeMesh(sock2, "localhost", 19916, *mesh, "perturbed", 400, 0);
// Target is always identity -> Jpt = Jpr.
cout << "Magnitude of metric " << metric_id << ": " << metric->EvalW(J)
<< "\n volume perturbation factor: " << perturb_v
<< "\n aspect ratio pert factor: " << perturb_ar
<< "\n skew perturbation factor: " << perturb_s << endl;
delete metric;
delete mesh;
return 0;
}
void Form2DJac(double perturb_v, double perturb_ar, double perturb_s,
DenseMatrix &J)
{
// Volume.
const double volume = 1.0 * perturb_v;
// Aspect Ratio.
const double a_r = 1.0 * perturb_ar;
DenseMatrix M_ar(2); M_ar = 0.0;
M_ar(0, 0) = 1.0 / sqrt(a_r);
M_ar(1, 1) = sqrt(a_r);
// Skew.
const double skew_angle = M_PI / 2.0 / perturb_s;
DenseMatrix M_skew(2);
M_skew(0, 0) = 1.0; M_skew(0, 1) = cos(skew_angle);
M_skew(1, 0) = 0.0; M_skew(1, 1) = sin(skew_angle);
// Rotation.
const double rot_angle = 0.0; // not sure how to choose
DenseMatrix M_rot(2);
M_rot(0, 0) = cos(rot_angle); M_rot(0, 1) = -sin(rot_angle);
M_rot(1, 0) = sin(rot_angle); M_rot(1, 1) = cos(rot_angle);
// Form J.
J.SetSize(2);
DenseMatrix TMP(2);
Mult(M_rot, M_skew, TMP);
Mult(TMP, M_ar, J);
J *= sqrt(volume / sin(skew_angle));
}
void Form3DJac(double perturb_v, double perturb_ar, double perturb_s,
DenseMatrix &J)
{
MFEM_ABORT("The 3D case is still not complete.");
// Volume.
const double volume = 1.0 * perturb_v;
// Aspect Ratio - only in one direction, the others are uniform.
const double ar_1 = 1.0 * perturb_ar,
ar_2 = 1.0 * perturb_ar;
// Skew - only in one direction, the others are pi/2.
const double skew_angle_12 = M_PI / 2.0 / perturb_s,
skew_angle_13 = M_PI / 2.0 / perturb_s,
skew_angle_23 = M_PI / 2.0 / perturb_s;
const double sin3 = sin(skew_angle_12)*sin(skew_angle_13)*sin(skew_angle_23);
// Rotation - not done yet.
J.SetSize(3);
//
J(0, 0) = ar_1;
J(0, 1) = ar_2 * cos(skew_angle_12);
J(0, 2) = cos(skew_angle_13) / (ar_1 * ar_2) *
sqrt(sin3 / volume);
//
J(1, 0) = 0.0;
J(1, 1) = ar_2 * sin(skew_angle_12);
J(1, 2) = sin(skew_angle_13) * cos(skew_angle_23) / (ar_1 * ar_2) *
sqrt(sin3 / volume);
//
J(2, 0) = 0.0;
J(2, 1) = 0.0;
J(2, 2) = sin(skew_angle_13) * sin(skew_angle_23) / (ar_1 * ar_2) *
sqrt(sin3/ volume);
//
J *= sqrt(volume / sin3);
}
+9 -25
View File
@@ -14,8 +14,6 @@ project(mfem-unit-tests NONE)
# Include the source directory for the unit tests - catch.hpp is there.
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
# The following list can be updated using (in bash):
# for d in general linalg mesh fem enzyme; do ls -1 $d/*.cpp; done
set(UNIT_TESTS_SRCS
general/test_array.cpp
general/test_mem.cpp
@@ -24,8 +22,8 @@ set(UNIT_TESTS_SRCS
general/test_zlib.cpp
linalg/test_cg_indefinite.cpp
linalg/test_chebyshev.cpp
linalg/test_complex_dense_matrix.cpp
linalg/test_complex_operator.cpp
linalg/test_complex_dense_matrix.cpp
linalg/test_constrainedsolver.cpp
linalg/test_direct_solvers.cpp
linalg/test_hypre_ilu.cpp
@@ -44,71 +42,57 @@ set(UNIT_TESTS_SRCS
mesh/test_fms.cpp
mesh/test_mesh.cpp
mesh/test_ncmesh.cpp
mesh/test_periodic_mesh.cpp
mesh/test_pmesh.cpp
mesh/test_psubmesh.cpp
mesh/test_submesh.cpp
mesh/test_psubmesh.cpp
mesh/test_periodic_mesh.cpp
mesh/test_vtu.cpp
fem/test_1d_bilininteg.cpp
fem/test_2d_bilininteg.cpp
fem/test_3d_bilininteg.cpp
fem/test_r1d_bilininteg.cpp
fem/test_r2d_bilininteg.cpp
fem/test_assemblediagonalpa.cpp
fem/test_assembly_levels.cpp
fem/test_bilinearform.cpp
fem/test_blocknonlinearform.cpp
fem/test_build_dof_to_arrays.cpp
fem/test_calccurlshape.cpp
fem/test_calcdivshape.cpp
fem/test_calcdshape.cpp
fem/test_calcshape.cpp
fem/test_calcvshape.cpp
fem/test_calcdshape.cpp
fem/test_calccurlshape.cpp
fem/test_calcdivshape.cpp
fem/test_coefficient.cpp
fem/test_datacollection.cpp
fem/test_derefine.cpp
fem/test_dgmassinv.cpp
fem/test_doftrans.cpp
fem/test_domain_int.cpp
fem/test_eigs.cpp
fem/test_estimator.cpp
fem/test_fa_determinism.cpp
fem/test_face_elem_trans.cpp
fem/test_face_permutation.cpp
fem/test_fe.cpp
fem/test_get_value.cpp
fem/test_getderivative.cpp
fem/test_getgradient.cpp
fem/test_intrules.cpp
fem/test_intruletypes.cpp
fem/test_inversetransform.cpp
fem/test_lexicographic_ordering.cpp
fem/test_lin_interp.cpp
fem/test_linear_fes.cpp
fem/test_linearform_ext.cpp
fem/test_lor.cpp
fem/test_lor_batched.cpp
fem/test_operatorjacobismoother.cpp
fem/test_oscillation.cpp
fem/test_pa_coeff.cpp
fem/test_pa_grad.cpp
fem/test_pa_idinterp.cpp
fem/test_pa_kernels.cpp
fem/test_project_bdr.cpp
fem/test_quadf_coef.cpp
fem/test_quadinterpolator.cpp
fem/test_quadraturefunc.cpp
fem/test_r1d_bilininteg.cpp
fem/test_r2d_bilininteg.cpp
fem/test_sparse_matrix.cpp
fem/test_sum_bilin.cpp
fem/test_surf_blf.cpp
fem/test_tet_reorder.cpp
fem/test_transfer.cpp
fem/test_var_order.cpp
fem/test_white_noise.cpp
enzyme/compatibility.cpp
# The following are tested separately (keep the comment as a reminder).
# This list can be updated using (in bash):
# for d in miniapps ceed; do ls -1 $d/*.cpp; done
# The following are tested separately (keep the comment as a reminder):
# miniapps/test_debug_device.cpp
# miniapps/test_sedov.cpp
# miniapps/test_tmop_pa.cpp
-370
View File
@@ -112,377 +112,7 @@ TEST_CASE("Derefine")
}
}
double integrate(GridFunction* gf)
{
ConstantCoefficient one(1.0);
LinearForm lf(gf->FESpace());
LinearFormIntegrator* lfi = new DomainLFIntegrator(one);
lf.AddDomainIntegrator(lfi);
lf.Assemble();
double integral = lf(*gf);
return integral;
}
struct PolyCoeff
{
static int order_;
static double poly_coeff(const Vector& x)
{
int& o{order_};
double f = 0.0;
for (int d = 0; d < dimension; d++)
{
f += pow(x[d],o);
}
return f;
}
};
int PolyCoeff::order_ = -1;
void test_derefine_L2_element(int order, Element::Type el_type, int basis_type)
{
Mesh mesh;
if (dimension == 1)
{
mesh = Mesh::MakeCartesian1D(1, 1.0);
}
if (dimension == 2)
{
mesh = Mesh::MakeCartesian2D(1, 1, el_type, true, 1.0, 1.0);
}
if (dimension == 3)
{
mesh = Mesh::MakeCartesian3D(1, 1, 1, el_type, true, 1.0, 1.0, 1.0);
}
mesh.EnsureNCMesh(true);
L2_FECollection fec(order, dimension, basis_type);
FiniteElementSpace fespace(&mesh, &fec);
GridFunction x(&fespace);
PolyCoeff pcoeff;
pcoeff.order_ = order+1; // raise order so it isn't exact
FunctionCoefficient c(PolyCoeff::poly_coeff);
Array<Refinement> refinements;
refinements.Append(Refinement(0));
mesh.GeneralRefinement(refinements);
fespace.Update();
x.Update();
// project to get function that isn't exactly representable in the
// fine space.
x.ProjectCoefficient(c);
// deep copy the fine solution
Vector xf = x;
GridFunction x_fine(x.FESpace());
x_fine.SetData(xf.GetData());
double mass_fine = integrate(&x_fine);
Vector local_err(mesh.GetNE());
local_err = 0.;
double threshold = 1.0;
mesh.DerefineByError(local_err, threshold);
fespace.Update();
x.Update();
Vector coarse_soln_v{x};
double mass_coarse = integrate(&x);
// conservation check
REQUIRE( fabs(mass_fine-mass_coarse) < 1.e-12 );
// re-refine to get everything on the same grid
mesh.GeneralRefinement(refinements);
fespace.Update();
x.Update();
// Compute error of coarse L2 projection against fine solution
GridFunctionCoefficient gfc(&x);
double err0 = x_fine.ComputeL2Error(gfc);
// test for local L2 optimality by shifting dofs by +/-epsilon and
// recomputing error wrt fine solution. maybe there is a more
// clever way to do this.
double eps = 1.e-3;
// limit to max 20 dofs for efficiency in 3D
int test_ndofs = std::min(coarse_soln_v.Size(), 20);
for (int i = 0; i < test_ndofs; i++)
{
for (int f = -1; f <= 1; f += 2)
{
mesh.DerefineByError(local_err, threshold);
fespace.Update();
x.Update();
x = coarse_soln_v;
x(i) += f*eps;
mesh.GeneralRefinement(refinements);
fespace.Update();
x.Update();
double err = x_fine.ComputeL2Error(gfc);
REQUIRE(err > err0);
}
}
}
TEST_CASE("AMR Coarsen L2 Element","[AMR][Coarsen]")
{
std::vector<int> orders_1d{0,1,2,3};
std::vector<int> orders_2d{0,1,2,3};
std::vector<int> orders_3d{0,1,2};
std::vector<int> basis_types
{
BasisType::Positive,
BasisType::GaussLegendre,
BasisType::GaussLobatto};
std::vector<Element::Type> el_types_1d;
el_types_1d.push_back(Element::SEGMENT);
std::vector<Element::Type> el_types_2d;
el_types_2d.push_back(Element::QUADRILATERAL);
el_types_2d.push_back(Element::TRIANGLE); // (nonconforming only)
std::vector<Element::Type> el_types_3d;
el_types_3d.push_back(Element::HEXAHEDRON);
el_types_3d.push_back(Element::TETRAHEDRON); // (nonconforming only)
// el_types_3d.push_back(Element::WEDGE); // derefinement not supported
dimension = 1;
for (auto el_type: el_types_1d)
{
for (auto order: orders_1d)
{
for (auto basis_type: basis_types)
{
test_derefine_L2_element(order, el_type, basis_type);
}
}
}
dimension = 2;
for (auto el_type: el_types_2d)
{
for (auto order: orders_2d)
{
for (auto basis_type: basis_types)
{
test_derefine_L2_element(order, el_type, basis_type);
}
}
}
dimension = 3;
for (auto el_type: el_types_3d)
{
for (auto order: orders_3d)
{
for (auto basis_type: basis_types)
{
test_derefine_L2_element(order, el_type, basis_type);
}
}
}
}
#ifdef MFEM_USE_MPI
void RefineRandomly(ParMesh& pmesh,
ParFiniteElementSpace& fespace, ParGridFunction& u)
{
double freq = 0.3;
Array<Refinement> refinements;
for (int k = 0; k < pmesh.GetNE(); k++)
{
double a = rand()/double(RAND_MAX);
if (a < freq)
{
refinements.Append(Refinement(k));
}
}
pmesh.GeneralRefinement(refinements);
fespace.Update();
u.Update();
}
void CoarsenRandomly(ParMesh& pmesh,
ParFiniteElementSpace& fespace, ParGridFunction& u)
{
double freq = 0.2;
Vector local_err(pmesh.GetNE());
local_err = 1.1;
double threshold = 1.0;
for (int k = 0; k < pmesh.GetNE(); k++)
{
double a = rand()/double(RAND_MAX);
if (a < freq)
{
local_err(k) = 0.0;
}
}
int op = 0; // take min
int nc_limit = 0;
pmesh.DerefineByError(local_err, threshold, nc_limit, op);
fespace.Update();
u.Update();
}
// stress test parallel correctness by:
// initializing with an exact polynomial
// loop:
// refine randomly
// rebalance
// coarsen randomly
// rebalance
// representation should remain exact throughout
void stress_parallel_coarsen(int order, Element::Type el_type, int basis_type)
{
// This is deactivated until we have a way to exactly project onto
// positive finite elements.
#if 0
int myid = Mpi::WorldRank();
Mesh mesh;
if (dimension == 1)
{
mesh = Mesh::MakeCartesian1D(4, 1.0);
}
if (dimension == 2)
{
mesh = Mesh::MakeCartesian2D(2, 2, el_type, true, 1.0, 1.0);
}
if (dimension == 3)
{
mesh = Mesh::MakeCartesian3D(2, 2, 2, el_type, true, 1.0, 1.0, 1.0);
}
mesh.EnsureNCMesh(true);
ParMesh *pmeshp = new ParMesh(MPI_COMM_WORLD, mesh);
ParMesh& pmesh{*pmeshp};
L2_FECollection fec(order, dimension, basis_type);
ParFiniteElementSpace fespace(&pmesh, &fec);
ParGridFunction x(&fespace);
PolyCoeff pcoeff;
pcoeff.order_ = order; // exact
FunctionCoefficient c(PolyCoeff::poly_coeff);
x.ProjectCoefficient(c);
srand( (unsigned)time( NULL )+myid );
int total_it = 10;
for (int it = 0; it < total_it; it++)
{
RefineRandomly(pmesh, fespace, x);
double err = x.ComputeL2Error(c);
REQUIRE( err < 1.e-12 );
pmesh.Rebalance();
fespace.Update();
x.Update();
err = x.ComputeL2Error(c);
REQUIRE( err < 1.e-12 );
CoarsenRandomly(pmesh, fespace, x);
err = x.ComputeL2Error(c);
REQUIRE( err < 1.e-12 );
pmesh.Rebalance();
fespace.Update();
x.Update();
err = x.ComputeL2Error(c);
REQUIRE( err < 1.e-12 );
}
#endif
}
TEST_CASE("Parallel AMR Coarsen Stress Test", "[AMR][Coarsen][Parallel]")
{
std::vector<int> orders_1d{0,1,2,3};
std::vector<int> orders_2d{0,1,2,3};
std::vector<int> orders_3d{0,1,2};
std::vector<int> basis_types
{
BasisType::Positive,
BasisType::GaussLegendre,
BasisType::GaussLobatto};
std::vector<Element::Type> el_types_1d;
el_types_1d.push_back(Element::SEGMENT);
std::vector<Element::Type> el_types_2d;
el_types_2d.push_back(Element::QUADRILATERAL);
// el_types_2d.push_back(Element::TRIANGLE); // derefinement not supported
std::vector<Element::Type> el_types_3d;
el_types_3d.push_back(Element::HEXAHEDRON);
// el_types_3d.push_back(Element::TETRAHEDRON); // derefinement not supported
// el_types_3d.push_back(Element::WEDGE); // derefinement not supported
dimension = 1;
for (auto el_type: el_types_1d)
{
for (auto order: orders_1d)
{
for (auto basis_type: basis_types)
{
stress_parallel_coarsen(order, el_type, basis_type);
}
}
}
dimension = 2;
for (auto el_type: el_types_2d)
{
for (auto order: orders_2d)
{
for (auto basis_type: basis_types)
{
stress_parallel_coarsen(order, el_type, basis_type);
}
}
}
dimension = 3;
for (auto el_type: el_types_3d)
{
for (auto order: orders_3d)
{
for (auto basis_type: basis_types)
{
stress_parallel_coarsen(order, el_type, basis_type);
}
}
}
}
TEST_CASE("ParDerefine", "[Parallel]")
{
for (dimension = 2; dimension <= 3; ++dimension)
-5
View File
@@ -14,9 +14,6 @@
using namespace mfem;
namespace test_GetDerivative_parallel
{
double func(const Vector &coord)
{
if (coord.Size() == 1) { return std::sin(coord(0)); }
@@ -77,5 +74,3 @@ TEST_CASE("GetDerivative", "[Parallel]")
}
#endif
}
-153
View File
@@ -1,153 +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.
#include "unit_tests.hpp"
#include "mfem.hpp"
using namespace mfem;
namespace test_GetGradient_shared_faces
{
int dim;
double func(const Vector &coord)
{
double x = coord(0),
y = (dim > 1) ? coord(1) : 0.0,
z = (dim > 2) ? coord(2) : 0.0;
return x * x + y * y + z * z;
}
void func_grad(const Vector &coord, Vector &grad)
{
grad.SetSize(coord.Size());
grad(0) = 2.0 * coord(0);
if (dim > 1) { grad(1) = 2.0 * coord(1); }
if (dim > 2) { grad(2) = 2.0 * coord(2); }
}
void vec_func(const Vector &coord, Vector &res)
{
double x = coord(0),
y = (dim > 1) ? coord(1) : 0.0,
z = (dim > 2) ? coord(2) : 0.0;
res(0) = (x + 1.0) * (y + 1.0) * (z + 1.0);
res(1) = x * x + y * y + z * z;
}
void vec_func_grad(const Vector &coord, DenseMatrix &grad)
{
grad.SetSize(2, dim);
double x = coord(0),
y = (dim > 1) ? coord(1) : 0.0,
z = (dim> 2) ? coord(2) : 0.0;
grad(0, 0) = (y + 1.0) * (z + 1.0);
grad(1, 0) = 2.0 * x;
if (dim > 1)
{
grad(0, 1) = (x + 1.0) * (z + 1.0);
grad(1, 1) = 2.0 * y;
}
if (dim > 2)
{
grad(0, 2) = (x + 1.0) * (y + 1.0);
grad(1, 2) = 2.0 * z;
}
}
#ifdef MFEM_USE_MPI
TEST_CASE("GetGradient Shared Faces", "[ParGridFunction][Parallel]")
{
const int fe_order = 3;
for (dim = 1; dim <= 3; dim++)
{
int num_procs;
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
int myid;
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
Mesh mesh;
if (dim == 1)
{
mesh = Mesh::MakeCartesian1D(100, 1.0);
}
else if (dim == 2)
{
mesh = Mesh::LoadFromFile("../../data/star-mixed.mesh");
}
else
{
mesh = Mesh::LoadFromFile("../../data/fichera-mixed.mesh");
}
for (int i = 0; i < 2; i++) { mesh.UniformRefinement(); }
ParMesh pmesh(MPI_COMM_WORLD, mesh);
FunctionCoefficient func_coeff(func);
VectorFunctionCoefficient vec_func_coeff(2, vec_func);
H1_FECollection fec(fe_order, dim);
ParFiniteElementSpace pfes(&pmesh, &fec), pfes_vec(&pmesh, &fec, 2);
ParGridFunction pgf(&pfes), pgf_vec(&pfes_vec);
pgf.ProjectCoefficient(func_coeff);
pgf_vec.ProjectCoefficient(vec_func_coeff);
pgf.ExchangeFaceNbrData();
pgf_vec.ExchangeFaceNbrData();
double max_error_grad = 0.0, max_error_grads = 0.0,
max_error_vec_grad = 0.0;
for (int f = 0; f < pmesh.GetNSharedFaces(); f++)
{
auto tr_f = pmesh.GetSharedFaceTransformations(f);
ElementTransformation &tr_e2 = tr_f->GetElement2Transformation();
const IntegrationRule &ir_f = IntRules.Get(tr_f->GetGeometryType(),
2*fe_order + 2);
IntegrationRule ir_e2(ir_f.GetNPoints());
tr_f->Loc2.Transform(ir_f, ir_e2);
Vector grad_e2, grad_exact, coord(dim);
DenseMatrix grads_e2, vec_grad_e2, vec_grad_exact;
pgf.GetGradients(tr_e2, ir_e2, grads_e2);
for (int q = 0; q < ir_f.GetNPoints(); q++)
{
const IntegrationPoint &ip_f = ir_f.IntPoint(q);
tr_f->SetIntPoint(&ip_f);
tr_f->Transform(ip_f, coord);
func_grad(coord, grad_exact);
pgf.GetGradient(tr_e2, grad_e2);
grad_e2 -= grad_exact;
max_error_grad = fmax(max_error_grad, grad_e2.Norml2());
grads_e2.GetColumn(q, grad_e2);
grad_e2 -= grad_exact;
max_error_grads = fmax(max_error_grads, grad_e2.Norml2());
pgf_vec.GetVectorGradient(tr_e2, vec_grad_e2);
vec_func_grad(coord, vec_grad_exact);
vec_grad_e2 -= vec_grad_exact;
max_error_vec_grad = fmax(max_error_vec_grad, vec_grad_e2.FNorm2());
}
}
REQUIRE(max_error_grad == MFEM_Approx(0.0));
REQUIRE(max_error_grads == MFEM_Approx(0.0));
REQUIRE(max_error_vec_grad == MFEM_Approx(0.0));
}
}
#endif
}
+2 -2
View File
@@ -44,8 +44,8 @@ TEST_CASE("MemoryManager/Scopes",
REQUIRE(h_x == x.GetData());
REQUIRE(mem->capacity == x.Size());
REQUIRE(mem->h_mt == Device::GetHostMemoryType());
constexpr unsigned Registered = 1 << 0;
const bool registered = mem->flags & Registered;
constexpr unsigned REGISTERED = 1 << 0;
const bool registered = mem->flags & REGISTERED;
const bool registered_is_known = registered == mm.IsKnown(h_x);
REQUIRE(registered_is_known);
}