#ifndef SRC_PROGRAM_STATE_HH #define SRC_PROGRAM_STATE_HH #include <dune/common/parametertree.hh> #include <dune/matrix-vector/axpy.hh> #include <dune/fufem/boundarypatch.hh> #include <dune/tnnmg/nonlinearities/zerononlinearity.hh> #include <dune/tnnmg/problem-classes/blocknonlineartnnmgproblem.hh> #include <dune/contact/assemblers/nbodyassembler.hh> #include <dune/tectonic/body.hh> #include "assemblers.hh" #include "matrices.hh" #include "spatial-solving/solverfactory.hh" template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class BodyState { public: using Vector = VectorTEMPLATE; using ScalarVector = ScalarVectorTEMPLATE; BodyState(Vector * _u, Vector * _v, Vector * _a, ScalarVector * _alpha, ScalarVector * _weightedNormalStress) : u(_u), v(_v), a(_a), alpha(_alpha), weightedNormalStress(_weightedNormalStress) {} public: Vector * const u; Vector * const v; Vector * const a; ScalarVector * const alpha; ScalarVector * const weightedNormalStress; }; template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState { public: using Vector = VectorTEMPLATE; using ScalarVector = ScalarVectorTEMPLATE; using BodyState = BodyState<Vector, ScalarVector>; ProgramState(const std::vector<size_t>& leafVertexCounts) : bodyCount_(leafVertexCounts.size()), bodies(bodyCount_), u(bodyCount_), v(bodyCount_), a(bodyCount_), alpha(bodyCount_), weightedNormalStress(bodyCount_) { for (size_t i=0; i<bodyCount_; i++) { size_t leafVertexCount = leafVertexCounts[i]; u[i].resize(leafVertexCount), v[i].resize(leafVertexCount), a[i].resize(leafVertexCount), alpha[i].resize(leafVertexCount), weightedNormalStress[i].resize(leafVertexCount), bodies[i] = new BodyState(&u[i], &v[i], &a[i], &alpha[i], &weightedNormalStress[i]); } } ~ProgramState() { for (size_t i=0; i<bodyCount_; i++) { delete bodies[i]; } } size_t size() const { return bodyCount_; } // Set up initial conditions template <class Matrix, class GridView> void setupInitialConditions( const Dune::ParameterTree& parset, const Dune::Contact::NBodyAssembler<typename GridView::Grid, Vector>& nBodyAssembler, std::vector<std::function<void(double, Vector &)>> externalForces, const Matrices<Matrix>& matrices, const std::vector<std::shared_ptr<MyAssembler<GridView, Vector::block_type::dimension>>>& assemblers, const std::vector<Dune::BitSetVector<Vector::block_type::dimension>>& dirichletNodes, const std::vector<Dune::BitSetVector<Vector::block_type::dimension>>& noNodes, const std::vector<BoundaryPatch<GridView>>& frictionalBoundaries, const Body<Vector::block_type::dimension>& body) { using LocalVector = typename Vector::block_type; //using LocalMatrix = typename Matrix::block_type; auto constexpr dims = LocalVector::dimension; // Solving a linear problem with a multigrid solver auto const solveLinearProblem = [&]( const std::vector<Dune::BitSetVector<dims>>& _dirichletNodes, const std::vector<std::shared_ptr<Matrix>>& _matrices, const std::vector<Vector>& _rhs, std::vector<Vector>& _x, Dune::ParameterTree const &_localParset) { std::vector<const Matrix*> matrices_ptr(_matrices.size()); for (size_t i=0; i<matrices_ptr.size(); i++) { matrices_ptr[i] = _matrices[i].get(); } /*std::vector<Matrix> matrices(velocityMatrices.size()); std::vector<Vector> rhs(velocityRHSs.size()); for (size_t i=0; i<globalFriction_.size(); i++) { matrices[i] = velocityMatrices[i]; rhs[i] = velocityRHSs[i]; globalFriction_[i]->addHessian(v_rel[i], matrices[i]); globalFriction_[i]->addGradient(v_rel[i], rhs[i]); matrices_ptr[i] = &matrices[i]; }*/ // assemble full global contact problem Matrix bilinearForm; nBodyAssembler.assembleJacobian(matrices_ptr, bilinearForm); Vector totalRhs; nBodyAssembler.assembleRightHandSide(_rhs, totalRhs); Vector totalX; nBodyAssembler.nodalToTransformed(_x, totalX); using LinearFactory = SolverFactory<typename GridView::Grid, GlobalFriction<Matrix, Vector>, Matrix, Vector>; LinearFactory factory(parset.sub("solver.tnnmg"), nBodyAssembler, _dirichletNodes); auto multigridStep = factory.getStep(); multigridStep->setProblem(bilinearForm, totalX, totalRhs); const EnergyNorm<Matrix, Vector> norm(bilinearForm); LoopSolver<Vector> solver( multigridStep.get(), _localParset.get<size_t>("maximumIterations"), _localParset.get<double>("tolerance"), &norm, _localParset.get<Solver::VerbosityMode>("verbosity"), false); // absolute error solver.preprocess(); solver.solve(); nBodyAssembler.postprocess(multigridStep->getSol(), _x); }; timeStep = 0; relativeTime = 0.0; relativeTau = 1e-6; std::vector<Vector> ell0(bodyCount_); for (size_t i=0; i<bodyCount_; i++) { // Initial velocity v[i] = 0.0; ell0[i].resize(u[i].size()); ell0[i] = 0.0; // TODO //externalForces[i](relativeTime, ell0[i]); } // Initial displacement: Start from a situation of minimal stress, // which is automatically attained in the case [v = 0 = a]. // Assuming dPhi(v = 0) = 0, we thus only have to solve Au = ell0 solveLinearProblem(dirichletNodes, matrices.elasticity, ell0, u, parset.sub("u0.solver")); // Initial acceleration: Computed in agreement with Ma = ell0 - Au // (without Dirichlet constraints), again assuming dPhi(v = 0) = 0 std::vector<Vector> accelerationRHS = ell0; for (size_t i=0; i<bodyCount_; i++) { // Initial state alpha[i] = parset.get<double>("boundary.friction.initialAlpha"); // Initial normal stress assemblers[i]->assembleWeightedNormalStress( frictionalBoundaries[i], weightedNormalStress[i], body.getYoungModulus(), body.getPoissonRatio(), u[i]); Dune::MatrixVector::subtractProduct(accelerationRHS[i], *matrices.elasticity[i], u[i]); } solveLinearProblem(noNodes, matrices.mass, accelerationRHS, a, parset.sub("a0.solver")); } private: const size_t bodyCount_; public: std::vector<BodyState* > bodies; std::vector<Vector> u; std::vector<Vector> v; std::vector<Vector> a; std::vector<ScalarVector> alpha; std::vector<ScalarVector> weightedNormalStress; double relativeTime; double relativeTau; size_t timeStep; }; #endif