13#ifndef CONTACTCONSTRAINTS
14#define CONTACTCONSTRAINTS
21#include <dune/common/fvector.hh>
22#include "dune/istl/bvector.hh"
68 template <
class Space,
class DisplacedFace,
class Displacement>
71 DisplacedFace
const& face,
75 using Grid =
typename Space::Grid;
76 using ctype =
typename Grid::ctype;
78 using EntryType = std::pair<size_t,RowEntry>;
79 using ReturnType = std::optional<std::pair<std::vector<EntryType>,ctype>>;
84 auto n = face.unitOuterNormal(xi);
87 if (overlap == std::numeric_limits<double>::lowest())
89 ctype diameter = std::pow(face.volume(),1.0/DisplacedFace::facedimension);
90 overlap = 0.05*diameter;
93 auto const x = face.global(xi);
94 auto intersection = boundaryLocator.
byRay(x-overlap*n,n);
99 auto [oface,oxi,calpha] = *intersection;
100 auto const y = oface.global(oxi);
103 auto dofs = space.linearCombination( face.gridFace().inside(), face.gridFace().geometryInInside().global(xi));
104 auto odofs = space.linearCombination(oface.gridFace().inside(),oface.gridFace().geometryInInside().global(oxi));
108 std::vector<EntryType> entries;
110 RowEntry nt; nt[0] = n;
112 ctype
const eps = std::numeric_limits<ctype>::epsilon();
113 for (
auto const& p: dofs)
114 if (p.second.two_norm2() > 1e3*eps)
115 entries.push_back(std::make_pair(p.first,p.second[0]*nt));
116 for (
auto const& p: odofs)
117 if (p.second.two_norm2() > 1e3*eps)
118 entries.push_back(std::make_pair(p.first,-p.second[0]*nt));
131 return ReturnType(std::make_pair(entries,(y-x)*n));
149 template <
class Space1,
class DisplacedFace1,
class Displacement1,
int dimw1=Space1::Gr
idView::Gr
id::dimension,
class Space2,
class Displacement2,
int dimw2=Space2::Gr
idView::Gr
id::dimension>
152 DisplacedFace1
const& face,
158 using ctype =
typename Space1::GridView::ctype;
160 using EntryType = std::pair<size_t,RowEntry>;
161 using ReturnType = std::optional<std::tuple<std::vector<EntryType>,std::vector<EntryType>,ctype>>;
163 constexpr int dim1 = Space1::GridView::Grid::dimension;
164 constexpr int dim2 = Space2::GridView::Grid::dimension;
167 auto n = face.unitOuterNormal(xi);
172 if constexpr(dim1==dimw1) volume = face.gridFace().inside().geometry().volume();
173 else volume = face.gridFace().geometry().volume();
174 ctype diameter = std::pow(volume,1.0/dim1);
175 if(overlap == std::numeric_limits<double>::lowest())
176 overlap = 0.05*diameter;
181 auto intersection = boundaryLocator2.
byRay(face.global(xi)-overlap*n,n);
183 RowEntry nt; nt[0] = n;
189 auto oface = std::get<0>(intersection.value());
190 auto oxi = std::get<1>(intersection.value());
192 std::vector<EntryType> entries1;
193 std::vector<EntryType> entries2;
194 ctype
const eps = std::numeric_limits<ctype>::epsilon();
197 if constexpr(dim1==dimw1)
199 auto dofs = space1.linearCombination(face.gridFace().inside(),face.gridFace().geometryInInside().global(xi));
200 for (
auto const& p: dofs)
201 if (p.second.two_norm2() > 1e3*eps)
202 entries1.push_back(std::make_pair(p.first,p.second[0]*nt));
206 auto dofs = space1.linearCombination(face,xi);
207 for (
auto const& p: dofs)
208 if (p.second.two_norm2() > 1e3*eps)
209 entries1.push_back(std::make_pair(p.first,p.second[0]*nt));
212 if constexpr(dim2==dimw2)
214 auto odofs = space2.linearCombination(oface.gridFace().inside(),oface.gridFace().geometryInInside().global(oxi));
215 for (
auto const& p: odofs)
216 if (p.second.two_norm2() > 1e3*eps)
217 entries2.push_back(std::make_pair(p.first,-p.second[0]*nt));
221 auto odofs = space2.linearCombination(oface,oxi);
222 for (
auto const& p: odofs)
223 if (p.second.two_norm2() > 1e3*eps)
224 entries2.push_back(std::make_pair(p.first,-p.second[0]*nt));
227 auto x = face.global(xi);
228 auto y = oface.global(oxi);
231 return ReturnType(std::make_tuple(entries1,entries2,(y-x)*n));
264 template <
class Scalar,
int dim>
275 using Row = std::vector<std::pair<size_t,Entry>>;
282 virtual int size(
int n)
const = 0;
304 std::vector<Row>& B, std::vector<Scalar>& b)
const = 0;
316 template <
class Scalar,
int dim>
325 virtual int size(
int n)
const {
return n; }
332 std::vector<Row>& B, std::vector<Scalar>& b)
const;
336 namespace ContactConstraintsDetail
338 template <
class Scalar,
int dim>
353 template <
class Scalar,
int dim>
376 std::vector<Row>& rows, std::vector<Scalar>& bounds)
const;
392 enum class Type { Dirac, Bezier };
428 std::vector<Dune::QuadraturePoint<double,dim>>
constraintPositions(Dune::GeometryType gt,
int nodesPerEdge)
430 assert(nodesPerEdge>0);
433 using QP = Dune::QuadraturePoint<double,dim>;
441 pos.push_back(QP(p,1.0));
445 for (
int i=0; i<nodesPerEdge; ++i)
448 double w = (i==0 || i+1==nodesPerEdge)? 0.5/(nodesPerEdge-1): 1.0/(nodesPerEdge-1);
449 pos.push_back(QP(p,w));
453 else if (gt.isTriangle())
458 pos.push_back(QP(p,1.0));
462 double w = 2.0/(nodesPerEdge*(nodesPerEdge+1));
463 for (
int ix=0; ix<nodesPerEdge; ++ix)
465 double x = ix/(nodesPerEdge-1.0);
466 for (
int iy=0; iy<nodesPerEdge-ix; ++iy)
468 double y = iy/(nodesPerEdge-1.0);
470 pos.push_back(QP(p,w));
477 std::cerr <<
"unsupported geometry type of face!\n";
503 template <
class Space,
class Displacement>
506 int pointsPerEdge,
double overlap = std::numeric_limits<double>::lowest(),
510 using Grid =
typename Space::Grid;
511 using ctype =
typename Grid::ctype;
512 constexpr int dim = Grid::dimension;
514 using Row = std::vector<std::pair<size_t,Entry>>;
516 std::vector<Row> rows;
517 std::vector<ctype> bounds;
526 auto const& face = faces[i];
527 auto const qr = constraintPositions<dim-1>(face.type(),pointsPerEdge);
528 auto volume = face.volume();
531 std::vector<Row> tmpRows;
532 std::vector<ctype> tmpBounds;
534 for (auto const& qp: qr)
536 auto const& xi = qp.position();
537 auto c = getContactConstraint(space,boundaryLocator,face,xi,overlap);
541 ctype w = qp.weight()*volume;
547 mortar.updateConstraints(qr.size(),xi,vic,g,tmpRows,tmpBounds);
552 std::lock_guard lock(mutex);
554 rows.reserve(size(rows)+size(tmpRows));
555 for (
auto& tr: tmpRows)
556 rows.push_back(std::move(tr));
558 bounds.reserve(size(bounds)+size(tmpBounds));
559 for (
auto& tb: tmpBounds)
560 bounds.push_back(std::move(tb));
565 ScopedTimingSection(
"convert to NumaBCRSMatrix");
567 NumaCRSPatternCreator<> creator(rows.size(),space.degreesOfFreedom());
568 for (
size_t i=0; i<rows.size(); ++i)
569 for (
auto const& p: rows[i])
570 creator.addElement(i,p.first);
573 NumaBCRSMatrix<Entry> B(creator);
574 for (
size_t i=0; i<rows.size(); ++i)
575 for (
auto const& p: rows[i])
576 B[i][p.first] += p.second;
580 std::copy(begin(bounds),end(bounds),begin(b));
583 return std::make_pair(B,b);
604 template <
class Space1,
class Displacement1,
class Space2,
class Displacement2,
bool flattened=false>
607 int order,
double overlap = std::numeric_limits<double>::lowest(),
bool symmetric=
true)
609 constexpr int dim1 = Space1::GridView::Grid::dimension;
610 constexpr int dim2 = Space2::GridView::Grid::dimension;
611 constexpr int dimw1= Space1::GridView::Grid::dimensionworld;
612 constexpr int dimw2= Space2::GridView::Grid::dimensionworld;
613 constexpr int dimensionworld =
std::max(dimw1,dimw2);
614 constexpr int dimension =
std::min(dim1, dim2);
616 using ctype =
typename Space1::GridView::ctype;
617 constexpr int blockSize = flattened ? 1 : dimensionworld;
618 constexpr int blocksPerNode = flattened ? dimensionworld : 1;
620 using Row = std::vector<std::pair<size_t,Dune::FieldMatrix<ctype,1,dimensionworld>>>;
623 std::vector<Row> rows1;
624 std::vector<Row> rows2;
625 std::vector<ctype> bounds;
628 std::vector<typename BoundaryLocator<typename Space1::GridView,Displacement1,dimw1>::DisplacedFace> reducedFaces;
631 for (
auto const& face: faces)
633 auto volume = face.volume();
636 for (
auto const& qp:
qr)
638 auto const& xi = qp.position();
639 auto w = qp.weight()*volume;
643 auto [vic1,vic2,g] = *c;
649 rows1.push_back(vic1);
650 rows2.push_back(vic2);
652 reducedFaces.push_back(face);
655 if constexpr(dimension!=dimensionworld)
659 auto cc =
getContactConstraint(space1,boundaryLocator1,space2,boundaryLocator2,face,xi,overlap,1);
662 auto [vic1,vic2,g] = *cc;
668 rows1.push_back(vic1);
669 rows2.push_back(vic2);
671 reducedFaces.push_back(face);
681 std::vector<typename BoundaryLocator<typename Space2::GridView,Displacement2,dimw2>::DisplacedFace> reducedFaces2;
684 for (
auto const& face: faces2)
686 auto volume = face.volume();
689 for (
auto const& qp:
qr)
691 auto const& xi = qp.position();
692 auto w = qp.weight()*volume;
696 auto [vic1,vic2,g] = *c;
702 rows2.push_back(vic1);
703 rows1.push_back(vic2);
705 reducedFaces2.push_back(face);
708 if constexpr(dimension!=dimensionworld)
712 auto cc =
getContactConstraint(space2,boundaryLocator2,space1,boundaryLocator1,face,xi,overlap,1);
715 auto [vic1,vic2,g] = *cc;
721 rows2.push_back(vic1);
722 rows1.push_back(vic2);
724 reducedFaces.push_back(face);
732 for (
size_t i=0; i<rows1.size(); ++i)
733 for (
auto const& p: rows1[i])
734 for (
int l=0; l<blocksPerNode; ++l)
735 creator1.
addElement(i,p.first*blocksPerNode+l);
738 for (
size_t i=0; i<rows1.size(); ++i)
739 for (
auto const& p: rows1[i]) {
740 if(!flattened) B1[i][p.first] = p.second;
742 for (
int l=0; l<blocksPerNode; ++l)
743 B1[i][p.first*blocksPerNode+l] = p.second[0][l];
747 for (
size_t i=0; i<rows2.size(); ++i)
748 for (
auto const& p: rows2[i])
749 for (
int l=0; l<blocksPerNode; ++l)
750 creator2.
addElement(i,p.first*blocksPerNode+l);
753 for (
size_t i=0; i<rows2.size(); ++i)
754 for (
auto const& p: rows2[i]) {
755 if(!flattened) B2[i][p.first] = p.second;
757 for (
int l=0; l<blocksPerNode; ++l)
758 B2[i][p.first*blocksPerNode+l] = p.second[0][l];
762 std::copy(begin(bounds),end(bounds),begin(b));
764 return std::make_tuple(B1,B2,b,reducedFaces);
785 template <
class Gr
idView,
class Displacement>
788 int order,
double overlap = std::numeric_limits<double>::lowest(),
789 double maxGap = 1e-4)
791 using ctype =
typename GridView::ctype;
799 for (
auto const& face: faces)
806 for (
auto const& qp:
qr)
808 auto const& xi = qp.position();
811 if (c && std::get<2>(*c) < maxGap)
813 auto dupi = boundaryLocator1.
displacement()->derivative(face.gridFace().inside(), face.gridFace().geometryInInside().global(xi));
814 dupi += unitMatrix<ctype, GridView::Grid::dimension>();
816 auto jt = face.gridFace().geometry().jacobianTransposed(xi).rightmultiplyany(dupi.transposed());
817 ctype intElem = std::sqrt(std::abs(jt.rightmultiplyany(jt.transposed()).determinant()));
818 area += intElem * qp.weight();
854 template <
class Displacement,
class BoundaryDisplacement>
857 Displacement
const& direction,
858 int pointsPerEdge,
double trialStepSize=0.2,
859 double overlap = std::numeric_limits<double>::lowest(),
860 double targetOverlap = 0,
862 ContactConstraintsDetail::defaultMortar<typename Displacement::ctype,Displacement::GridView::dimension>())
864 using GridView =
typename Displacement::GridView;
865 static_assert(GridView::dimensionworld==Displacement::components);
866 assert(pointsPerEdge>=0);
867 assert(targetOverlap<
std::max(0.0,overlap) || (targetOverlap==0 && overlap==std::numeric_limits<double>::lowest()));
878 auto getGap = [&](
double t)
882 uTrial.axpy(t,direction);
885 auto Bx(Bb.second); Bb.first.mv(direction.coefficients(),Bx);
886 auto const& b = Bb.second;
891 double dg, taumax = gmin;
892 for (
int i=0; i<b.N(); ++i)
905 taumax =
std::min(taumax,(b[i][0]+targetOverlap)/Bx[i][0]);
908 return std::make_tuple(gmin,dg,taumax);
913 double const h = trialStepSize;
914 std::cout <<
"starting linesearch in [" << tmin+h <<
"," << tmax <<
"]\n";
915 while (tmin < 0.999*tmax)
918 auto [g0,dg0,tau0] = getGap(t);
920 if (g0 < -targetOverlap)
926 if (tmin >= 0.999*tmax)
932 std::cout <<
"No feasible stepsize found in this interval.\n";
936 std::cout <<
"starting linesearch in [" << tmin <<
"," << tmax <<
"]\n";
937 while (tmax-tmin >
std::min(1e-2,tmax/10))
939 double t = (tmax+tmin)/2;
942 auto [g0,dg0,tau0] = getGap(t);
944 if (g0 < -targetOverlap)
950 std::cout <<
"Found stepsize t=" << tmin <<
".\n";
986 template <
class Displacement1,
class BoundaryDisplacement1,
class Displacement2,
class BoundaryDisplacement2>
988 Displacement1
const& direction1,
990 Displacement2
const& direction2,
991 int order,
double trialStepSize=0.2,
992 double overlap = std::numeric_limits<double>::lowest(),
993 double targetOverlap = 0)
996 assert(0<trialStepSize && trialStepSize<1);
997 assert(targetOverlap<overlap || (targetOverlap==0 && overlap==std::numeric_limits<double>::lowest()));
998 assert(Displacement1::GridView::Grid::dimensionworld==Displacement2::GridView::Grid::dimensionworld);
1005 size_t nCoeff1 = direction1.coefficients().N();
1006 size_t nCoeff2 = direction2.coefficients().N();
1010 auto getGap = [&](
double t)
1013 uTrial1.axpy(t,direction1);
1015 uTrial2.axpy(t,direction2);
1018 auto Bb =
getContactConstraints(u1.space(),boundaryLocator1,u2.space(),boundaryLocator2,order,overlap);
1020 auto const& B =
horzcat(std::get<0>(Bb),std::get<1>(Bb));
1021 auto const& g = std::get<2>(Bb);
1022 typename Displacement1::StorageType combinedDirection(nCoeff1+nCoeff2);
1023 for(
size_t i=0; i< nCoeff1; ++i)
1024 combinedDirection[i]=direction1.coefficients()[i];
1025 for(
size_t i=0; i< nCoeff2; ++i)
1026 combinedDirection[i+nCoeff1]=direction2.coefficients()[i];
1028 auto Bx(g); B.mv(combinedDirection,Bx); Bx *= -1;
1033 double dg, taumax = gmin;
1034 for (
int i=0; i<g.N(); ++i)
1043 taumax =
std::min(taumax,-(g[i][0]+targetOverlap)/Bx[i][0]);
1048 return std::make_tuple(gmin,dg,taumax);
1053 double const h = trialStepSize;
1054 while (tmin < 0.999*tmax)
1057 auto [g0,dg0,tau0] = getGap(t);
1058std::cout <<
"gap(t=" << t <<
") = " << g0 <<
" [dg = " << dg0 <<
", taumax = " << tau0 <<
"]\n";
1059 if (g0 < -targetOverlap)
1065 if (tmin >= 0.999*tmax)
1070std::cout <<
"starting linesearch in [" << tmin <<
"," << tmax <<
"]\n";
1071 while (tmax-tmin >
std::min(1e-4,tmax/10))
1073 double t = (tmax+tmin)/2;
1074 auto [g0,dg0,tau0] = getGap(t);
1076 if (g0 < -targetOverlap)
Defines a constraint formulation where samples are weighted by Bezier test functions.
BezierMortar(int m)
Creates a Bezier mortar formulation of order m.
virtual int size(int n) const
The number of resulting constraints if m samples are provided.
virtual void updateConstraints(int n, Dune::FieldVector< Scalar, dim-1 > const &xi, Row &vic, Scalar g, std::vector< Row > &rows, std::vector< Scalar > &bounds) const
The.
Function const * displacement() const
Returns the current displacement of the mesh.
std::vector< DisplacedFace > displacedFaces() const
Returns a sequence of all deformed faces.
std::optional< std::tuple< typename BoundaryLocator< GridView, Function, dimw >::DisplacedFace, typename BoundaryLocator< GridView, Function, dimw >::LocalPosition, typename GridView::ctype > > byRay(Position const &from, Position const &direction, ctype minAngle=-0.5) const
Finds the first boundary face that is intersected by the given ray from outside towards inside.
void updateDisplacement(Update const &update)
Creates or updates the displacement function.
Defines a constraint formulation where each sample is taken as a single constraint of its own.
virtual void updateConstraints(int n, Dune::FieldVector< Scalar, dim-1 > const &xi, Row &Gi, Scalar gi, std::vector< Row > &B, std::vector< Scalar > &b) const
The.
virtual int size(int n) const
The number of resulting constraints if n samples are provided.
Abstract base class for computation of constraints from constraint samples.
virtual int size(int n) const =0
The number of resulting constraints if n samples are provided.
virtual void updateConstraints(int n, Dune::FieldVector< Scalar, dim-1 > const &xi, Row &Gi, Scalar gi, std::vector< Row > &B, std::vector< Scalar > &b) const =0
Updates the given set of constraints (by and ) when a new constraint sample becomes available.
std::vector< std::pair< size_t, Entry > > Row
A NUMA-aware compressed row storage matrix adhering mostly to the Dune ISTL interface (to complete....
A NUMA-aware creator for matrix sparsity patterns.
void addElement(Index row, Index col)
Enters a single entry into the sparsity pattern.
A scope guard object that automatically closes a timing section on destruction.
Dune::FieldVector< T, n > max(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise maximum.
std::tuple< std::vector< typename EntryTraits< Entry >::field_type >, DynamicMatrix< typename EntryTraits< Entry >::field_type >, std::vector< int > > qr(DynamicMatrix< Entry > const &A)
Computes a rank-revealing QR decomposition of using column pivoting.
auto horzcat(DynamicMatrix< EntryA > const &A, DynamicMatrix< EntryB > const &B)
Concatenates two matrices horizontally.
Dune::FieldVector< T, n > min(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise minimum.
void parallelFor(Func const &f, int maxTasks=std::numeric_limits< int >::max())
A parallel for loop that executes the given functor in parallel on different CPUs.
Grid locking information based on grid type.
Defines the sample-based contact constraint formulation.
static constexpr MortarB dirac()
Type
Defines the type of constraint formulation.
static constexpr MortarB bezier(int order)
A cache that stores suitable quadrature rules for quick retrieval.