#ifdef HAVE_CONFIG_H #include "config.h" #endif #include <dune/common/exceptions.hh> #include <dune/matrix-vector/axpy.hh> #include <dune/solvers/norms/energynorm.hh> #include <dune/solvers/solvers/loopsolver.hh> #include <dune/contact/assemblers/nbodyassembler.hh> #include <dune/contact/common/dualbasisadapter.hh> #include <dune/localfunctions/lagrange/pqkfactory.hh> #include <dune/functions/gridfunctions/gridfunction.hh> #include <dune/geometry/quadraturerules.hh> #include <dune/geometry/type.hh> #include <dune/geometry/referenceelements.hh> #include <dune/fufem/functions/basisgridfunction.hh> #include "../data-structures/enums.hh" #include "../data-structures/enumparser.hh" #include "../utils/tobool.hh" #include "../utils/debugutils.hh" #include <dune/solvers/solvers/loopsolver.hh> #include <dune/solvers/iterationsteps/truncatedblockgsstep.hh> #include <dune/solvers/iterationsteps/multigridstep.hh> #include "../spatial-solving/preconditioners/nbodycontacttransfer.hh" #include "tnnmg/functional.hh" #include "tnnmg/zerononlinearity.hh" #include "fixedpointiterator.hh" void FixedPointIterationCounter::operator+=( FixedPointIterationCounter const &other) { iterations += other.iterations; multigridIterations += other.multigridIterations; } template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms> FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::FixedPointIterator( Dune::ParameterTree const &parset, const NBodyAssembler& nBodyAssembler, const IgnoreVector& ignoreNodes, GlobalFriction& globalFriction, const std::vector<const BitVector*>& bodywiseNonmortarBoundaries, const ErrorNorms& errorNorms) : parset_(parset), nBodyAssembler_(nBodyAssembler), ignoreNodes_(ignoreNodes), globalFriction_(globalFriction), bodywiseNonmortarBoundaries_(bodywiseNonmortarBoundaries), fixedPointMaxIterations_(parset.get<size_t>("v.fpi.maximumIterations")), fixedPointTolerance_(parset.get<double>("v.fpi.tolerance")), lambda_(parset.get<double>("v.fpi.lambda")), velocityMaxIterations_(parset.get<size_t>("v.solver.maximumIterations")), velocityTolerance_(parset.get<double>("v.solver.tolerance")), verbosity_(parset.get<Solver::VerbosityMode>("v.solver.verbosity")), errorNorms_(errorNorms) {} template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms> template <class LinearSolver> FixedPointIterationCounter FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::run( Updaters updaters, std::shared_ptr<LinearSolver>& linearSolver, const std::vector<Matrix>& velocityMatrices, const std::vector<Vector>& velocityRHSs, std::vector<Vector>& velocityIterates) { //std::cout << "FixedPointIterator::run()" << std::endl; // debugging /*const auto& contactCouplings = nBodyAssembler_.getContactCouplings(); for (size_t i=0; i<contactCouplings.size(); i++) { print(*contactCouplings[i]->nonmortarBoundary().getVertices(), "nonmortarBoundaries:"); }*/ const auto nBodies = nBodyAssembler_.nGrids(); std::vector<const Matrix*> matrices_ptr(nBodies); for (int i=0; i<nBodies; i++) { matrices_ptr[i] = &velocityMatrices[i]; } // assemble full global contact problem Matrix bilinearForm; nBodyAssembler_.assembleJacobian(matrices_ptr, bilinearForm); //print(bilinearForm, "bilinearForm:"); Vector totalRhs; nBodyAssembler_.assembleRightHandSide(velocityRHSs, totalRhs); //print(totalRhs, "totalRhs:"); // get lower and upper obstacles const auto& totalObstacles = nBodyAssembler_.totalObstacles_; Vector lower(totalObstacles.size()); Vector upper(totalObstacles.size()); for (size_t j=0; j<totalObstacles.size(); ++j) { const auto& totalObstaclesj = totalObstacles[j]; auto& lowerj = lower[j]; auto& upperj = upper[j]; for (size_t d=0; d<dims; ++d) { lowerj[d] = totalObstaclesj[d][0]; upperj[d] = totalObstaclesj[d][1]; } } //print(totalObstacles, "totalObstacles:"); //print(lower, "lower obstacles:"); //print(upper, "upper obstacles:"); // compute velocity obstacles /*Vector vLower, vUpper; std::vector<Vector> u0, v0; updaters.rate_->extractOldVelocity(v0); updaters.rate_->extractOldDisplacement(u0); Vector totalu0, totalv0; nBodyAssembler_.concatenateVectors(u0, totalu0); nBodyAssembler_.concatenateVectors(v0, totalv0); updaters.rate_->velocityObstacles(totalu0, lower, totalv0, vLower); updaters.rate_->velocityObstacles(totalu0, upper, totalv0, vUpper); */ //print(vLower, "vLower obstacles:"); //print(vUpper, "vUpper obstacles:"); //std::cout << "- Problem assembled: success" << std::endl; //print(ignoreNodes_, "ignoreNodes:"); // set up functional and TNMMG solver //using ZeroSolverFactory = SolverFactory<Functional, IgnoreVector>; //Functional J(bilinearForm, totalRhs, ZeroNonlinearity(), vLower, vUpper); //ZeroSolverFactory solverFactory(parset_.sub("solver.tnnmg"), J, mgSolver, ignoreNodes_); Functional J(bilinearForm, totalRhs, globalFriction_, lower, upper); Factory solverFactory(parset_.sub("solver.tnnmg"), J, ignoreNodes_); solverFactory.build(linearSolver); auto step = solverFactory.step(); //std::cout << "- Functional and TNNMG step setup: success" << std::endl; EnergyNorm<Matrix, Vector> energyNorm(bilinearForm); LoopSolver<Vector> velocityProblemSolver(*step.get(), velocityMaxIterations_, velocityTolerance_, energyNorm, verbosity_); size_t fixedPointIteration; size_t multigridIterations = 0; std::vector<ScalarVector> alpha(nBodies); updaters.state_->extractAlpha(alpha); Vector totalVelocityIterate; nBodyAssembler_.nodalToTransformed(velocityIterates, totalVelocityIterate); // project in onto admissible set const size_t blocksize = Vector::block_type::dimension; for (size_t i=0; i<totalVelocityIterate.size(); i++) { for (size_t j=0; j<blocksize; j++) { if (totalVelocityIterate[i][j] < lower[i][j]) { totalVelocityIterate[i][j] = lower[i][j]; } if (totalVelocityIterate[i][j] > upper[i][j]) { totalVelocityIterate[i][j] = upper[i][j]; } } } Vector old_v = totalVelocityIterate; for (fixedPointIteration = 0; fixedPointIteration < fixedPointMaxIterations_; ++fixedPointIteration) { //print(alpha, "alpha:"); // contribution from nonlinearity globalFriction_.updateAlpha(alpha); //print(velocityIterates, "velocityIterates:"); //print(totalVelocityIterate, "totalVelocityIterate:"); //std::cout << "- FixedPointIteration iterate" << std::endl; // solve a velocity problem solverFactory.setProblem(totalVelocityIterate); //std::cout << "- Velocity problem set" << std::endl; velocityProblemSolver.preprocess(); //std::cout << "-- Preprocessed" << std::endl; velocityProblemSolver.solve(); //std::cout << "-- Solved" << std::endl; const auto& tnnmgSol = step->getSol(); //std::cout << "FixPointIterator: Energy of TNNMG solution: " << J(tnnmgSol) << std::endl; nBodyAssembler_.postprocess(tnnmgSol, velocityIterates); //nBodyAssembler_.postprocess(totalVelocityIterate, velocityIterates); //print(totalVelocityIterate, "totalVelocityIterate:"); //print(velocityIterates, "velocityIterates:"); //DUNE_THROW(Dune::Exception, "Just need to stop here!"); multigridIterations += velocityProblemSolver.getResult().iterations; Vector v_m = old_v; v_m *= 1.0 - lambda_; Dune::MatrixVector::addProduct(v_m, lambda_, tnnmgSol); // extract relative velocities in mortar basis std::vector<Vector> v_rel; relativeVelocities(v_m, v_rel); //print(v_m, "v_m: "); //print(v_rel, "v_rel"); //std::cout << "- State problem set" << std::endl; // solve a state problem updaters.state_->solve(v_rel); //std::cout << "-- Solved" << std::endl; std::vector<ScalarVector> newAlpha(nBodies); updaters.state_->extractAlpha(newAlpha); //print(newAlpha, "new alpha:"); bool breakCriterion = true; for (int i=0; i<nBodies; i++) { if (alpha[i].size()==0 || newAlpha[i].size()==0) continue; //print(alpha[i], "alpha i:"); //print(newAlpha[i], "new alpha i:"); if (errorNorms_[i]->diff(alpha[i], newAlpha[i]) >= fixedPointTolerance_) { breakCriterion = false; //std::cout << "fixedPoint error: " << errorNorms_[i]->diff(alpha[i], newAlpha[i]) << std::endl; break; } } if (lambda_ < 1e-12 or breakCriterion) { //std::cout << "-FixedPointIteration finished! " << (lambda_ < 1e-12 ? "lambda" : "breakCriterion") << std::endl; fixedPointIteration++; break; } alpha = newAlpha; } //TODO: recently added, might be wrong or superfluous globalFriction_.updateAlpha(alpha); //print(alpha, "alpha: "); //std::cout << "-FixedPointIteration finished! " << std::endl; if (fixedPointIteration == fixedPointMaxIterations_) DUNE_THROW(Dune::Exception, "FPI failed to converge"); updaters.rate_->postProcess(velocityIterates); // Cannot use return { fixedPointIteration, multigridIterations }; // with gcc 4.9.2, see also http://stackoverflow.com/a/37777814/179927 FixedPointIterationCounter ret; ret.iterations = fixedPointIteration; ret.multigridIterations = multigridIterations; return ret; } /*std::ostream &operator<<(std::ostream &stream, FixedPointIterationCounter const &fpic) { return stream << "(" << fpic.iterations << "," << fpic.multigridIterations << ")"; }*/ template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms> void FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::relativeVelocities( const Vector& v, std::vector<Vector>& v_rel) const { const size_t nBodies = nBodyAssembler_.nGrids(); // const auto& contactCouplings = nBodyAssembler.getContactCouplings(); size_t globalIdx = 0; v_rel.resize(nBodies); for (size_t bodyIdx=0; bodyIdx<nBodies; bodyIdx++) { const auto& nonmortarBoundary = *bodywiseNonmortarBoundaries_[bodyIdx]; auto& v_rel_ = v_rel[bodyIdx]; v_rel_.resize(nonmortarBoundary.size()); for (size_t i=0; i<v_rel_.size(); i++) { if (toBool(nonmortarBoundary[i])) { v_rel_[i] = v[globalIdx]; } globalIdx++; } } /* boundaryNodes = const auto gridView = contactCouplings[couplingIndices[0]]->nonmortarBoundary().gridView(); Dune::MultipleCodimMultipleGeomTypeMapper< decltype(gridView), Dune::MCMGVertexLayout> const vertexMapper(gridView, Dune::mcmgVertexLayout()); for (auto it = gridView.template begin<block_size>(); it != gridView.template end<block_size>(); ++it) { const auto i = vertexMapper.index(*it); for (size_t j=0; j<couplingIndices.size(); j++) { const auto couplingIdx = couplingIndices[j]; if (not contactCouplings[couplingIdx]->nonmortarBoundary().containsVertex(i)) continue; localToGlobal_.emplace_back(i); restrictions_.emplace_back(weights[bodyIdx][i], weightedNormalStress[bodyIdx][i], couplings[i]->frictionData()(geoToPoint(it->geometry()))); break; } globalIdx++; } maxIndex_[bodyIdx] = globalIdx; }*/ } #include "fixedpointiterator_tmpl.cc"