diff --git a/dune/contact/assemblers/largedeformationcontactassembler.cc b/dune/contact/assemblers/largedeformationcontactassembler.cc index a1bb37d63d97e43dc036e270a9765ad6669f2911..4dd8829d55bd01989a614e7a423b5df9e78c7366 100644 --- a/dune/contact/assemblers/largedeformationcontactassembler.cc +++ b/dune/contact/assemblers/largedeformationcontactassembler.cc @@ -7,6 +7,8 @@ #include <dune/istl/umfpack.hh> #include <dune/matrix-vector/transpose.hh> #include <dune/matrix-vector/addtodiagonal.hh> +#include <dune/matrix-vector/blockmatrixview.hh> +#include <dune/matrix-vector/algorithm.hh> namespace Dune { namespace Contact { @@ -82,6 +84,8 @@ template <class GridType, class VectorType> void LargeDeformationContactAssembler<GridType, VectorType>::assembleExactJacobian(const std::vector<const MatrixType*>& submat, MatrixType& totalMatrix) const { + namespace MV = Dune::MatrixVector; + // TODO Clean this up // Create a block view of the grand matrix Dune::MatrixVector::BlockMatrixView<MatrixType> bV(submat); @@ -114,30 +118,23 @@ void LargeDeformationContactAssembler<GridType, VectorType>::assembleExactJacobi } // use fact that nonmortar and mortar matrix are dense - auto&& it = BT_[first].begin(); - auto&& end = BT_[first].end(); - - int offset0 = bV.col(idx0,0); - for (; it != end; it++) { - + auto offset0 = bV.col(idx0,0); + MV::sparseRangeFor(BT_[first], [&](auto&&, auto&& idx) { // collected all mortar indices and nonmortar indices that are not // part of the reduced boundary - if (((int)it.index()>=offset0+grids_[idx0]->size(dim)) or - ((int)it.index()<offset0) or (!nmPatch.containsVertex(it.index()-offset0))) - contactIdx[i][1].insert(it.index()); + if ((idx >= offset0 + this->grids_[idx0]->size(dim)) or + (idx < offset0) or (!nmPatch.containsVertex(idx-offset0))) + contactIdx[i][1].insert(idx); else // and all nonmortar indices - contactIdx[i][0].insert(it.index()); - } + contactIdx[i][0].insert(idx); + }); // now find all interior nonmortar nodes - for (const auto& k : contactIdx[i][0]) { - auto&& it = (*submat[idx0])[k].begin(); - auto&& end = (*submat[idx0])[k].end(); - - for (; it!=end; it++) - if (!nmPatch.containsVertex(it.index())) - interiorIdx[i].insert(bV.row(idx0,it.index())); - } + for (const auto& k : contactIdx[i][0]) + MV::sparseRangeFor((*submat[idx0])[k], [&](auto&&, auto&& idx) { + if (!nmPatch.containsVertex(idx)) + interiorIdx[i].insert(bV.row(idx0,idx)); + }); for (size_t j=0; j<2; j++) { @@ -167,8 +164,6 @@ void LargeDeformationContactAssembler<GridType, VectorType>::assembleExactJacobi // Multiply transformation matrix to the global stiffness matrix // //////////////////////////////////////////////////////////////////// - namespace MV = Dune::MatrixVector; - indicesBABT.exportIdx(totalMatrix); totalMatrix = 0; @@ -188,16 +183,10 @@ void LargeDeformationContactAssembler<GridType, VectorType>::assembleExactJacobi colAD[count] = 0; - auto&& it = (*submat[idx0])[cIdx-offset0].begin(); - auto&& end = (*submat[idx0])[cIdx-offset0].end(); - - for (; it != end; it++) { - - if (!nmPatch.containsVertex(it.index())) - continue; - - MV::addProduct(colAD[count], *it, BT_[bV.row(idx0, it.index())][nmCol]); - } + MV::sparseRangeFor((*submat[idx0])[cIdx-offset0], [&](auto&& col, auto&& idx) { + if (nmPatch.containsVertex(idx)) + MV::addProduct(colAD[count], col, this->BT_[bV.row(idx0, idx)][nmCol]); + }); count++; } @@ -240,16 +229,9 @@ void LargeDeformationContactAssembler<GridType, VectorType>::assembleExactJacobi colAD[count] = 0; - auto&& it = (*submat[idx0])[cIdx-offset0].begin(); - auto&& end = (*submat[idx0])[cIdx-offset0].end(); - - for (; it != end; it++) { - - if (!nmPatch.containsVertex(it.index())) - continue; - - MV::addProduct(colAD[count], *it, BT_[bV.row(idx0, it.index())][mCol]); - } + MV::sparseRangeFor((*submat[idx0])[cIdx-offset0], [&](auto&& col, auto&& idx) { + if (nmPatch.containsVertex(idx)) + MV::addProduct(colAD[count], col, this->BT_[bV.row(idx0, idx)][mCol]);}); count++; } @@ -289,16 +271,11 @@ void LargeDeformationContactAssembler<GridType, VectorType>::assembleExactJacobi for (size_t j=0; j<2; j++) for (const auto& col : contactIdx[i][j]) { - auto&& it = rowIN.begin(); - auto&& end = rowIN.end(); - MatrixBlock sum(0); - for (; it != end; it++) { - if (!nmPatch.containsVertex(it.index())) - continue; - - MV::addProduct(sum, *it, BT_[bV.col(idx0,it.index())][col]); - } + MV::sparseRangeFor(rowIN, [&](auto&& entry, auto&& idx) { + if (nmPatch.containsVertex(idx)) + MV::addProduct(sum, entry, this->BT_[bV.col(idx0, idx)][col]); + }); totalMatrix[intIdx][col] += sum; MatrixBlock sumT; @@ -327,18 +304,13 @@ void LargeDeformationContactAssembler<GridType, VectorType>::assembleExactJacobi for(size_t j=0; j<submat[i]->N(); j++) { // skip nonmortar rows - if (contains(j)) - continue; - - const auto& mat = (*submat[i]); - - auto&& end = mat[j].end(); - for (auto&& it = mat[j].begin(); it != end; it++) - if (!contains(it.index())) - totalMatrix[bV.row(i,j)][bV.col(i,it.index())] += *it; + if (not contains(j)) + MV::sparseRangeFor((*submat[i])[j], [&](auto&& col, auto&& idx) { + if (not contains(idx)) + totalMatrix[bV.row(i,j)][bV.col(i,idx)] += col; + }); } } - std::cout<<"Transformed matrix in "<<timer.stop()<<std::endl; } @@ -585,14 +557,11 @@ computeExactTransformationMatrix() // finally rotate the nonmortar blocks //TODO might not work for more than one coupling - for(size_t rowIdx=0; rowIdx<nmNormalMatrix.N(); rowIdx++) { + for(size_t rowIdx=0; rowIdx<nmNormalMatrix.N(); ++rowIdx) { int globalRowIdx = offsets[grid0Idx] + nonmortarToGlobal[i][rowIdx]; - auto& row = BT_[globalRowIdx]; - - auto&& cEndIt = row.end(); - for(auto&& cIt = row.begin(); cIt!=cEndIt; ++cIt) - cIt->leftmultiply(this->localCoordSystems_[globalRowIdx]); + for (auto& cIt : BT_[globalRowIdx]) + cIt.leftmultiply(this->localCoordSystems_[globalRowIdx]); } } } @@ -601,6 +570,7 @@ template <class GridType, class VectorType> void LargeDeformationContactAssembler<GridType, VectorType>:: computeLumppedTransformationMatrix() { + namespace MV = Dune::MatrixVector; /** * Compute the mortar transformation that decouples the non-penetration constraints * in the case of large deformations. @@ -669,20 +639,11 @@ computeLumppedTransformationMatrix() auto globalRowIdx = offsets[grid0Idx] + nonmortarToGlobal[i][j]; indicesBT.add(globalRowIdx,globalRowIdx); - { - const auto& row = nmMatrix[j]; - auto&& end = row.end(); - - for (auto&& it = row.begin(); it != end; ++it) - indicesBT.add(globalRowIdx, offsets[grid0Idx] + it.index()); - } + MV::sparseRangeFor(nmMatrix[j],[&](auto&&, auto&& idx) { + indicesBT.add(globalRowIdx, offsets[grid0Idx] + idx);}); - { - const auto& row = mMatrix[j]; - auto&& end = row.end(); - for (auto&& it = row.begin(); it != end; ++it) - indicesBT.add(globalRowIdx, offsets[grid1Idx] + it.index()); - } + MV::sparseRangeFor(mMatrix[j],[&](auto&&, auto&& idx) { + indicesBT.add(globalRowIdx, offsets[grid1Idx] + idx);}); } } @@ -712,27 +673,24 @@ computeLumppedTransformationMatrix() // setup non-mortar in normal coordinates auto normalMat = nmMat; - for (size_t j=0; j<normalMat.N(); j++) { - - auto&& cEnd = normalMat[j].end(); - for(auto&& col = normalMat[j].begin(); col != cEnd; col++) - if (nonmortarBoundary.containsVertex(col.index())) { + for (size_t j=0; j<normalMat.N(); j++) + MV::sparseRangeFor(normalMat[j], [&](auto&& col, auto&& idx) { + if (nonmortarBoundary.containsVertex(idx)) { - const auto& householder = this->localCoordSystems_[offsets[grid0Idx] + col.index()]; - auto entry = (*col)[0]; - householder.mtv(entry, (*col)[0]); + const auto& householder = this->localCoordSystems_[offsets[grid0Idx] + idx]; + auto entry = col[0]; + householder.mtv(entry, col[0]); } - } + }); for (size_t j=0; j<normalMat.N(); j++) { // invert normal component field_type lumpedEntry(0); - auto end = normalMat[j].end(); - for (auto it = normalMat[j].begin(); it != end; ++it) - if (nonmortarBoundary.containsVertex(it.index())) - lumpedEntry += (*it)[0][0]; + MV::sparseRangeFor(normalMat[j], [&](auto&& col, auto&& idx){ + if (nonmortarBoundary.containsVertex(idx)) + lumpedEntry += col[0][0];}); if (std::fabs(lumpedEntry)<1e-15) DUNE_THROW(Dune::Exception,"Warning: Normal entry of the diagonal is zero!"); @@ -744,23 +702,17 @@ computeLumppedTransformationMatrix() // non-mortar entries auto globalRowIdx = offsets[grid0Idx] + nonmortarToGlobal[i][j]; - { - auto end = normalMat[j].end(); - for (auto it = normalMat[j].begin(); it != end; ++it) { - BT_[globalRowIdx][offsets[grid0Idx] + it.index()][0].axpy(lumpedEntry,(*it)[0]); - if (nonmortarBoundary.containsVertex(it.index())) - BT_[globalRowIdx][offsets[grid0Idx] + it.index()][0][0] = 0; - } + MV::sparseRangeFor(normalMat[j], [&](auto&& col, auto&& idx) { + this->BT_[globalRowIdx][offsets[grid0Idx] + idx][0].axpy(lumpedEntry,col[0]); + if (nonmortarBoundary.containsVertex(idx)) + this->BT_[globalRowIdx][offsets[grid0Idx] + idx][0][0] = 0; + }); - BT_[globalRowIdx][globalRowIdx][0][0] = lumpedEntry; - } + BT_[globalRowIdx][globalRowIdx][0][0] = lumpedEntry; - { - const auto& row = mMat[j]; - auto&& end = row.end(); - for (auto&& it = row.begin(); it != end; ++it) - BT_[globalRowIdx][offsets[grid1Idx] + it.index()][0].axpy(lumpedEntry,(*it)[0]); - } + MV::sparseRangeFor(mMat[j], [&](auto&& col, auto&& idx) { + this->BT_[globalRowIdx][offsets[grid1Idx] + idx][0].axpy(lumpedEntry, col[0]); + }); } // finally rotate the nonmortar blocks @@ -780,6 +732,7 @@ template <class GridType, class VectorType> void LargeDeformationContactAssembler<GridType, VectorType>:: computeInverseTransformationMatrix() { + namespace MV = Dune::MatrixVector; /** * Compute the inverse of the mortar transformation that decouples the non-penetration constraints * in the case of large deformations. @@ -890,60 +843,46 @@ computeInverseTransformationMatrix() // non-mortar entries auto globalRowIdx = offsets[grid0Idx] + nonmortarToGlobal[i][j]; - { - const auto& row = nmMat[j]; - auto&& end = row.end(); - - // TODO: only add entries that are non-zero in normal coords - for (auto&& it = row.begin(); it != end; ++it) { - - MatrixBlock invTrans(0); - - // for non-mortar components, the entrie is twice multiplied by the Householder - // reflection, hence we don't have to compute normal coordinates - if (nonmortarBoundary.containsVertex(it.index()) and - nonmortarToGlobal[i][j]== it.index()) - invTrans = this->localCoordSystems_[offsets[grid0Idx] + it.index()]; + // TODO: only add entries that are non-zero in normal coords + MV::sparseRangeFor(nmMat[j], [&](auto&& col, auto&& idx) { + MatrixBlock invTrans(0); - invTrans[0] = (*it)[0]; - invTrans[0] *= -1; + // for non-mortar components, the entrie is twice multiplied by the Householder + // reflection, hence we don't have to compute normal coordinates + if (nonmortarBoundary.containsVertex(idx) and + nonmortarToGlobal[i][j]== idx) + invTrans = this->localCoordSystems_[offsets[grid0Idx] + idx]; - inverse_[globalRowIdx][offsets[grid0Idx]+it.index()] = invTrans; - } - } + invTrans[0] = col[0]; + invTrans[0] *= -1; - { - const auto& row = mMat[j]; - auto&& end = row.end(); - for (auto&& it = row.begin(); it != end; ++it) { + inverse_[globalRowIdx][offsets[grid0Idx] + idx] = invTrans; + }); - MatrixBlock invTrans(0); - invTrans[0] -= (*it)[0]; - inverse_[offsets[grid0Idx]+nonmortarToGlobal[i][j]][offsets[grid1Idx]+it.index()] = invTrans; - } - } + MV::sparseRangeFor(mMat[j], [&](auto&& col, auto&& idx) { + MatrixBlock invTrans(0); + invTrans[0] -= col[0]; + inverse_[globalRowIdx][offsets[grid1Idx] + idx] = invTrans; + }); } } // compute the norms of the columns, these determine the length of the // transformed basis vectors and are taken into account by the trust-region - const auto& inverse = inverse_; - colNorms_.resize(inverse.N()); + colNorms_.resize(inverse_.N()); colNorms_ = 0; - for (size_t i=0; i<inverse.N(); i++) { - auto cEnd = inverse[i].end(); - for (auto col = inverse[i].begin(); col != cEnd; col++) - for (int j=0; j<dim;j++) - for (int k=0; k<dim;k++) - colNorms_[col.index()][k] += std::pow((*col)[j][k],2); - } - - field_type min(std::numeric_limits<field_type>::max()),max(-1); - for (size_t i=0; i<inverse.N(); i++) - for (int j=0; j<dim;j++) { - field_type root = std::sqrt(colNorms_[i][j]); - colNorms_[i][j] = 1.0/root; + MV::sparseMatrixFor(inverse_, [&](auto&& entry, auto&&, auto&& colIdx) { + for (int j=0; j < dim; ++j) + for (int k=0; k < dim; ++k) + colNorms_[colIdx][k] += std::pow(entry[j][k], 2); + }); + + field_type min(std::numeric_limits<field_type>::max()), max(-1); + for (auto& colNorm : colNorms_) + for (int j=0; j < dim; ++j) { + field_type root = std::sqrt(colNorm[j]); + colNorm[j] = 1.0/root; min = std::fmin(min, root); max = std::fmax(max, root); @@ -951,13 +890,14 @@ computeInverseTransformationMatrix() std::cout<<" Transformed basis vector norms range from "<<min<<" to "<<max<<std::endl; } - template <class GridType, class VectorType> template <class VectorTypeContainer> void LargeDeformationContactAssembler<GridType, VectorType>:: assembleExactRightHandSide(const VectorTypeContainer& rhs, VectorType& totalRhs) const { + namespace MV = Dune::MatrixVector; + // first combine all regular parts this->concatenateVectors(rhs,totalRhs); @@ -991,14 +931,10 @@ assembleExactRightHandSide(const VectorTypeContainer& rhs, // indices of normal nm matrix Dune::MatrixIndexSet nmIsN(nmMatrix.N(),nmMatrix.N()); // for the normal projection the tangential matrix is not square - for (size_t j=0; j<nmMatrix.N(); j++) { - const auto& row = nmMatrix[j]; - auto&& end = row.end(); - - for (auto&& it = row.begin(); it != end; ++it) - if (nonmortarBoundary.containsVertex(it.index())) - nmIsN.add(globalToLocal[it.index()],j); - } + MV::sparseMatrixFor(nmMatrix, [&](auto&&, auto&& rowIdx, auto&& colIdx) { + if (nonmortarBoundary.containsVertex(colIdx)) + nmIsN.add(globalToLocal[colIdx], rowIdx); + }); using ScalarMatrix = BCRSMatrix<FieldMatrix<field_type,1 , 1> >; ScalarMatrix nmMatN; @@ -1028,22 +964,17 @@ assembleExactRightHandSide(const VectorTypeContainer& rhs, totalRhs[globalRowIdx][0] = 0; } - for (size_t j=0; j<nmMatT.N(); j++) { - auto& row = nmMatT[j]; - for(auto&& col = row.begin(); col != nmMatT[j].end(); col++) { + MV::sparseMatrixFor(nmMatT, [&](auto&& entry, auto&& rowIdx, auto&& colIdx){ + if (nonmortarBoundary.containsVertex(colIdx)) { + const auto& householder = this->localCoordSystems_[offsets[gridIdx[0]] + colIdx]; - if (!nonmortarBoundary.containsVertex(col.index())) - continue; - const auto& householder = this->localCoordSystems_[offsets[gridIdx[0]] + col.index()]; - - auto entry = (*col)[0]; - householder.mtv(entry, (*col)[0]); + auto val = entry[0]; + householder.mtv(val, entry[0]); - // if (std::fabs((*col)[0][0])>1e-15) - nmMatN[globalToLocal[col.index()]][j][0][0] = (*col)[0][0]; - (*col)[0][0] = 0; + nmMatN[globalToLocal[colIdx]][rowIdx][0][0] = entry[0][0]; + entry[0][0] = 0; } - } + }); // solve the small system nmMatN*transRhsNm = rhsNm; auto transRhsNm = rhsNm; @@ -1060,16 +991,12 @@ assembleExactRightHandSide(const VectorTypeContainer& rhs, std::vector<std::reference_wrapper<const JacobianType> > linMatrices; linMatrices = {{std::cref(nmMatT), std::cref(coupling->exactMortarMatrix())}}; - for (size_t j =0; j<2; j++) { - const auto& mat = linMatrices[j].get(); + for (size_t j =0; j < 2; ++j) + MV::sparseMatrixFor(linMatrices[j].get(), [&](auto&& entry, auto&& rowIdx, auto&& colIdx) { + totalRhs[offsets[gridIdx[j]] + colIdx].axpy(transRhsNm[rowIdx][0], entry[0]);}); - for (size_t p=0; p<linMatrices[j].get().N(); p++) - for (auto col = mat[p].begin(); col != mat[p].end();col++) - totalRhs[offsets[gridIdx[j]]+col.index()].axpy(transRhsNm[p][0],(*col)[0]); - } - - for (size_t p=0; p<transRhsNm.size(); p++) - totalRhs[offsets[gridIdx[0]]+nonmortarToGlobal[p]][0] += transRhsNm[p][0]; + for (size_t p=0; p < transRhsNm.size(); ++p) + totalRhs[offsets[gridIdx[0]] + nonmortarToGlobal[p]][0] += transRhsNm[p][0]; } } @@ -1078,6 +1005,8 @@ template <class VectorTypeContainer> void LargeDeformationContactAssembler<GridType, VectorType>:: postprocess(const VectorType& totalX, VectorTypeContainer& x) const { + namespace MV = Dune::MatrixVector; + auto untransformedX = totalX; // compute offsets for the involved grids @@ -1110,14 +1039,10 @@ postprocess(const VectorType& totalX, VectorTypeContainer& x) const // indices of normal nm matrix Dune::MatrixIndexSet nmIsN(nmMatrix.N(),nmMatrix.N()); // for the normal projection the tangential matrix is not square - for (size_t j=0; j<nmMatrix.N(); j++) { - const auto& row = nmMatrix[j]; - auto&& end = row.end(); - - for (auto&& it = row.begin(); it != end; ++it) - if (nonmortarBoundary.containsVertex(it.index())) - nmIsN.add(j, globalToLocal[it.index()]); - } + MV::sparseMatrixFor(nmMatrix, [&](auto&&, auto&& rowIdx, auto&& colIdx) { + if (nonmortarBoundary.containsVertex(colIdx)) + nmIsN.add(rowIdx, globalToLocal[colIdx]); + }); using ScalarMatrix = BCRSMatrix<FieldMatrix<field_type,1 , 1> >; ScalarMatrix nmMatN; @@ -1156,9 +1081,8 @@ postprocess(const VectorType& totalX, VectorTypeContainer& x) const // add mortar terms const auto& mMatrix = coupling->exactMortarMatrix(); - for (size_t j=0; j<mMatrix.N(); j++) - for(auto col = mMatrix[j].begin(); col != mMatrix[j].end(); col++) - rhsNm[j] += (*col)[0]*totalX[offsets[gridIdx[1]] + col.index()]; + MV::sparseMatrixFor(mMatrix, [&](auto&& entry, auto&& rowIdx, auto&& colIdx) { + rhsNm[rowIdx] += entry[0]*totalX[offsets[gridIdx[1]] + colIdx];}); // we actually need the negative term rhsNm *= -1;