diff --git a/src/.gitignore b/src/.gitignore index c52dff94094dc5e1803403a968c0b9d144941306..aa8174205fc7e75281254e0edd1c8b65231201a9 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,4 @@ timestepping.cc timestepping.hh timestepping_tmpl.cc +one-body-sample.cc \ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am index 6c8d03b969ff6b75b5a4649f0809aa6103c102bd..1ea490f5c9a8c62c5edae19fc7467473a36e9575 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -111,3 +111,8 @@ $(srcdir)/timestepping.hh: $(srcdir)/timestepping.org emacs -Q --batch --eval \ "(let (vc-handled-backends) \ (org-babel-tangle-file \"$<\" nil 'c++))" + +$(srcdir)/one-body-sample.cc: $(srcdir)/one-body-sample.org + emacs -Q --batch --eval \ + "(let (vc-handled-backends) \ + (org-babel-tangle-file \"$<\" nil 'c++))" diff --git a/src/one-body-sample.cc b/src/one-body-sample.cc deleted file mode 100644 index aca2b01ff42281bd1ec60ffbcee5755489e47990..0000000000000000000000000000000000000000 --- a/src/one-body-sample.cc +++ /dev/null @@ -1,484 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_IPOPT -#undef HAVE_IPOPT -#endif - -#ifndef srcdir -#error srcdir unset -#endif - -#ifndef DIM -#error DIM unset -#endif - -#ifndef HAVE_PYTHON -#error Python is required -#endif - -#if !HAVE_ALUGRID -#error ALUGRID is required -#endif - -#include <cmath> -#include <exception> -#include <iostream> - -#include <boost/format.hpp> - -#include <Python.h> - -#include <dune/common/bitsetvector.hh> -#include <dune/common/exceptions.hh> -#include <dune/common/fmatrix.hh> -#include <dune/common/function.hh> -#include <dune/common/fvector.hh> -#include <dune/common/parametertree.hh> -#include <dune/common/parametertreeparser.hh> -#include <dune/common/shared_ptr.hh> -#include <dune/common/timer.hh> -#include <dune/grid/alugrid.hh> -#include <dune/grid/common/mcmgmapper.hh> -#include <dune/grid/utility/structuredgridfactory.hh> -#include <dune/istl/bcrsmatrix.hh> -#include <dune/istl/bvector.hh> - -#include <dune/fufem/assemblers/functionalassembler.hh> -#include <dune/fufem/assemblers/localassemblers/l2functionalassembler.hh> -#include <dune/fufem/assemblers/localassemblers/massassembler.hh> -#include <dune/fufem/assemblers/localassemblers/stvenantkirchhoffassembler.hh> -#include <dune/fufem/assemblers/localassemblers/vonmisesstressassembler.hh> -#include <dune/fufem/assemblers/operatorassembler.hh> -#include <dune/fufem/dunepython.hh> -#include <dune/fufem/functions/basisgridfunction.hh> -#include <dune/fufem/functions/constantfunction.hh> -#include <dune/fufem/functionspacebases/p0basis.hh> -#include <dune/fufem/functionspacebases/p1nodalbasis.hh> -#include <dune/fufem/sharedpointermap.hh> -#include <dune/solvers/norms/energynorm.hh> -#include <dune/solvers/solvers/loopsolver.hh> -#include <dune/solvers/solvers/solver.hh> // Solver::FULL - -#include <dune/tectonic/myblockproblem.hh> -#include <dune/tectonic/myconvexproblem.hh> - -#include "assemblers.hh" -#include "mysolver.hh" -#include "vtk.hh" - -#include "enums.hh" -#include "enum_parser.cc" -#include "enum_state_model.cc" -#include "enum_scheme.cc" - -#include "timestepping.hh" - -#include "ruinastateupdater.hh" -#include "dieterichstateupdater.hh" - -int const dim = DIM; - -template <class GridView, class GridCorner> -void setup_boundary(GridView const &gridView, - Dune::BitSetVector<dim> &ignoreNodes, - Dune::BitSetVector<1> &neumannNodes, - Dune::BitSetVector<1> &frictionalNodes, - GridCorner const &lowerLeft, GridCorner const &upperRight, - size_t &specialNode) { - typedef typename GridView::template Codim<dim>::Iterator VertexLeafIterator; - - Dune::MultipleCodimMultipleGeomTypeMapper< - GridView, Dune::MCMGVertexLayout> const myVertexMapper(gridView); - - for (auto it = gridView.template begin<dim>(); - it != gridView.template end<dim>(); ++it) { - assert(it->geometry().corners() == 1); - Dune::FieldVector<double, dim> const coordinates = it->geometry().corner(0); - size_t const id = myVertexMapper.map(*it); - - // Find the center of the lower face - switch (dim) { - case 3: - if (coordinates[2] != lowerLeft[2]) - break; - // fallthrough - case 2: - if (coordinates[1] == lowerLeft[1] && - std::abs(coordinates[0] - lowerLeft[0]) < 1e-8) - specialNode = id; - break; - default: - assert(false); - } - - // lower face - if (coordinates[1] == lowerLeft[1]) { - frictionalNodes[id] = true; - ignoreNodes[id][1] = true; - } - - // upper face - else if (coordinates[1] == upperRight[1]) - ignoreNodes[id] = true; - - // right face (except for both corners) - else if (coordinates[0] == upperRight[0]) - ; - - // left face (except for both corners) - else if (coordinates[0] == lowerLeft[0]) - ; - } -} - -template <class VectorType, class MatrixType, class FunctionType, int dim> -Dune::shared_ptr<TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim>> -initTimeStepper(Config::scheme scheme, FunctionType const &dirichletFunction, - Dune::BitSetVector<dim> const &ignoreNodes, - MatrixType const &massMatrix, MatrixType const &stiffnessMatrix, - VectorType const &u_initial, VectorType const &ud_initial, - VectorType const &udd_initial) { - switch (scheme) { - case Config::ImplicitTwoStep: - return Dune::make_shared< - ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>>( - stiffnessMatrix, u_initial, ud_initial, ignoreNodes, - dirichletFunction); - case Config::ImplicitEuler: - return Dune::make_shared< - ImplicitEuler<VectorType, MatrixType, FunctionType, dim>>( - stiffnessMatrix, u_initial, ud_initial, ignoreNodes, - dirichletFunction); - case Config::Newmark: - return Dune::make_shared< - Newmark<VectorType, MatrixType, FunctionType, dim>>( - stiffnessMatrix, massMatrix, u_initial, ud_initial, udd_initial, - ignoreNodes, dirichletFunction); - } -} - -template <class SingletonVectorType, class VectorType> -Dune::shared_ptr<StateUpdater<SingletonVectorType, VectorType>> -initStateUpdater(Config::state_model model, - SingletonVectorType const &alpha_initial, - Dune::BitSetVector<1> const &frictionalNodes, double L) { - switch (model) { - case Config::Dieterich: - return Dune::make_shared< - DieterichStateUpdater<SingletonVectorType, VectorType>>( - alpha_initial, frictionalNodes, L); - case Config::Ruina: - return Dune::make_shared< - RuinaStateUpdater<SingletonVectorType, VectorType>>( - alpha_initial, frictionalNodes, L); - } -} - -template <class FunctionMap> void initPython(FunctionMap &functions) { - Python::start(); - - Python::run("import sys"); - Python::run("sys.path.append('" srcdir "')"); - - Python::import("one-body-sample") - .get("Functions") - .toC<typename FunctionMap::Base>(functions); -} - -int main(int argc, char *argv[]) { - try { - typedef SharedPointerMap<std::string, Dune::VirtualFunction<double, double>> - FunctionMap; - FunctionMap functions; - initPython(functions); - - Dune::ParameterTree parset; - Dune::ParameterTreeParser::readINITree(srcdir "/one-body-sample.parset", - parset); - Dune::ParameterTreeParser::readOptions(argc, argv, parset); - - Dune::Timer timer; - - typedef Dune::FieldVector<double, dim> SmallVector; - typedef Dune::FieldMatrix<double, dim, dim> SmallMatrix; - typedef Dune::BCRSMatrix<SmallMatrix> MatrixType; - typedef Dune::BlockVector<SmallVector> VectorType; - typedef Dune::BlockVector<Dune::FieldVector<double, 1>> SingletonVectorType; - - auto const E = parset.get<double>("body.E"); - auto const nu = parset.get<double>("body.nu"); - auto const solver_tolerance = parset.get<double>("solver.tolerance"); - - auto const refinements = parset.get<size_t>("grid.refinements"); - - auto const verbose = parset.get<bool>("verbose"); - Solver::VerbosityMode const verbosity = - verbose ? Solver::FULL : Solver::QUIET; - - // {{{ Set up grid - typedef Dune::ALUGrid<dim, dim, Dune::simplex, Dune::nonconforming> - GridType; - - Dune::FieldVector<typename GridType::ctype, dim> lowerLeft(0); - Dune::FieldVector<typename GridType::ctype, dim> upperRight(1); - upperRight[0] = parset.get<size_t>("body.width"); - upperRight[1] = parset.get<size_t>("body.height"); - - Dune::array<unsigned int, dim> elements; - std::fill(elements.begin(), elements.end(), 1); - elements[0] = parset.get<size_t>("body.width"); - elements[1] = parset.get<size_t>("body.height"); - - auto grid = Dune::StructuredGridFactory<GridType>::createSimplexGrid( - lowerLeft, upperRight, elements); - - grid->globalRefine(refinements); - size_t const finestSize = grid->size(grid->maxLevel(), dim); - - typedef GridType::LeafGridView GridView; - GridView const leafView = grid->leafView(); - // }}} - - // Set up bases - typedef P0Basis<GridView, double> P0Basis; - typedef P1NodalBasis<GridView, double> P1Basis; - P0Basis const p0Basis(leafView); - P1Basis const p1Basis(leafView); - - double normalStress; - MatrixType massMatrix; - VectorType gravityFunctional; - { - double const gravity = 9.81; - double const density = parset.get<double>("body.density"); - - { // Assemble mass matrix - MassAssembler<GridType, P1Basis::LocalFiniteElement, - P1Basis::LocalFiniteElement> const localMass; - OperatorAssembler<P1Basis, P1Basis>(p1Basis, p1Basis) - .assemble(localMass, massMatrix); - massMatrix *= density; - } - - { // Compute normal stress - double volume = 1.0; - for (int i = 0; i < dim; ++i) - volume *= (upperRight[i] - lowerLeft[i]); - - double area = 1.0; - for (int i = 0; i < dim; ++i) - if (i != 1) - area *= (upperRight[i] - lowerLeft[i]); - - // volume * gravity * density / area = normal stress - // V * g * rho / A = sigma_n - // m^d * N/kg * kg/m^d / m^(d-1) = N/m^(d-1) - normalStress = volume * gravity * density / area; - } - - { // Compute gravitational body force - SmallVector weightedGravitationalDirection(0); - weightedGravitationalDirection[1] = -density * gravity; - ConstantFunction<SmallVector, SmallVector> const gravityFunction( - weightedGravitationalDirection); - L2FunctionalAssembler<GridType, SmallVector> gravityFunctionalAssembler( - gravityFunction); - FunctionalAssembler<P1Basis>(p1Basis) - .assemble(gravityFunctionalAssembler, gravityFunctional, true); - } - } - - // Assemble elastic force on the body - MatrixType stiffnessMatrix; - { - StVenantKirchhoffAssembler<GridType, P1Basis::LocalFiniteElement, - P1Basis::LocalFiniteElement> const - localStiffness(E, nu); - OperatorAssembler<P1Basis, P1Basis>(p1Basis, p1Basis) - .assemble(localStiffness, stiffnessMatrix); - } - EnergyNorm<MatrixType, VectorType> energyNorm(stiffnessMatrix); - - // Set up the boundary - size_t specialNode = finestSize; - Dune::BitSetVector<dim> ignoreNodes(finestSize, false); - Dune::BitSetVector<1> neumannNodes(finestSize, false); - Dune::BitSetVector<1> frictionalNodes(finestSize, false); - setup_boundary(leafView, ignoreNodes, neumannNodes, frictionalNodes, - lowerLeft, upperRight, specialNode); - assert(specialNode != finestSize); - assert(frictionalNodes[specialNode][0]); - - auto const nodalIntegrals = - assemble_frictional<GridType, GridView, SmallVector, P1Basis>( - leafView, p1Basis, frictionalNodes); - - // {{{ Initialise vectors - VectorType u(finestSize); - u = 0.0; - VectorType ud(finestSize); - ud = 0.0; - - VectorType u_initial(finestSize); - u_initial = 0.0; - VectorType ud_initial(finestSize); - ud_initial = 0.0; - VectorType udd_initial(finestSize); - udd_initial = 0.0; - - SingletonVectorType alpha_initial(finestSize); - alpha_initial = parset.get<double>("boundary.friction.state.initial"); - SingletonVectorType alpha(alpha_initial); - - SingletonVectorType vonMisesStress; - - SingletonVectorType surfaceNormalStress(finestSize); - surfaceNormalStress = 0.0; - for (size_t i = 0; i < frictionalNodes.size(); ++i) - if (frictionalNodes[i][0]) - surfaceNormalStress[i] = normalStress; - // }}} - - typedef MyConvexProblem<MatrixType, VectorType> MyConvexProblemType; - typedef MyBlockProblem<MyConvexProblemType> MyBlockProblemType; - - // Set up TNNMG solver - MySolver<dim, MatrixType, VectorType, GridType, MyBlockProblemType> - mySolver(parset.sub("solver.tnnmg"), refinements, solver_tolerance, *grid, - ignoreNodes); - - std::fstream state_writer("state", std::fstream::out); - std::fstream displacement_writer("displacement", std::fstream::out); - std::fstream velocity_writer("velocity", std::fstream::out); - std::fstream coefficient_writer("coefficient", std::fstream::out); - - auto const L = parset.get<double>("boundary.friction.ruina.L"); - auto const a = parset.get<double>("boundary.friction.ruina.a"); - auto const b = parset.get<double>("boundary.friction.ruina.b"); - auto const V0 = parset.get<double>("boundary.friction.V0"); - auto const mu = parset.get<double>("boundary.friction.mu"); - auto const timesteps = parset.get<size_t>("timeSteps"); - auto const tau = parset.get<double>("endOfTime") / timesteps; - - auto const &dirichletFunction = functions.get("dirichletCondition"); - auto const &neumannFunction = functions.get("neumannCondition"); - - auto timeSteppingScheme = - initTimeStepper(parset.get<Config::scheme>("timeSteppingScheme"), - dirichletFunction, ignoreNodes, massMatrix, - stiffnessMatrix, u_initial, ud_initial, udd_initial); - auto stateUpdater = initStateUpdater<SingletonVectorType, VectorType>( - parset.get<Config::state_model>("boundary.friction.state.model"), - alpha_initial, frictionalNodes, L); - - auto const state_fpi_max = - parset.get<size_t>("solver.tnnmg.fixed_point_iterations"); - for (size_t run = 1; run <= timesteps; ++run) { - double const time = tau * run; - { - stateUpdater->nextTimeStep(); - - VectorType ell(finestSize); - assemble_neumann<GridType, GridView, SmallVector, P1Basis>( - leafView, p1Basis, neumannNodes, ell, neumannFunction, time); - ell += gravityFunctional; - - // Copy everything for now - MatrixType problem_A; - VectorType problem_rhs(finestSize); - VectorType problem_iterate(finestSize); - - stateUpdater->setup(tau); - timeSteppingScheme->setup(ell, tau, time, problem_rhs, problem_iterate, - problem_A); - - VectorType u_saved; - for (size_t state_fpi = 1; state_fpi <= state_fpi_max; ++state_fpi) { - auto myGlobalNonlinearity = - assemble_nonlinearity<MatrixType, VectorType>( - parset.sub("boundary.friction"), *nodalIntegrals, alpha, - surfaceNormalStress); - - MyConvexProblemType const myConvexProblem( - problem_A, *myGlobalNonlinearity, problem_rhs); - MyBlockProblemType myBlockProblem(parset, myConvexProblem); - auto multigridStep = mySolver.getSolver(); - multigridStep->setProblem(problem_iterate, myBlockProblem); - - LoopSolver<VectorType> overallSolver( - multigridStep, parset.get<size_t>("solver.tnnmg.maxiterations"), - solver_tolerance, &energyNorm, verbosity, - false); // absolute error - overallSolver.solve(); - - timeSteppingScheme->postProcess(problem_iterate); - timeSteppingScheme->extractDisplacement(u); - timeSteppingScheme->extractVelocity(ud); - - stateUpdater->solve(ud); - stateUpdater->extractState(alpha); - - if (parset.get<bool>("printProgress")) { - std::cerr << '.'; - std::cerr.flush(); - } - if (state_fpi > 1 && - energyNorm.diff(u_saved, u) < - parset.get<double>("solver.tnnmg.fixed_point_tolerance")) - break; - else - u_saved = u; - - if (state_fpi == state_fpi_max) - std::cerr << "[ref = " << refinements - << "]: FPI did not converge after " << state_fpi_max - << " iterations" << std::endl; - } - if (parset.get<bool>("printProgress")) - std::cerr << std::endl; - } - - { // Write all kinds of data - state_writer << alpha[specialNode][0] << " " << std::endl; - displacement_writer << u[specialNode][0] << " " << std::endl; - velocity_writer << ud[specialNode][0] << " " << std::endl; - coefficient_writer << mu + - a *std::log(ud[specialNode].two_norm() / V0) + - b * (alpha[specialNode] + std::log(V0 / L)) - << " " << std::endl; - } - - // Compute von Mises stress and write everything to a file - if (parset.get<bool>("writeVTK")) { - VonMisesStressAssembler<GridType> localStressAssembler( - E, nu, - Dune::make_shared<BasisGridFunction<P1Basis, VectorType> const>( - p1Basis, u)); - FunctionalAssembler<P0Basis>(p0Basis) - .assemble(localStressAssembler, vonMisesStress, true); - - writeVtk<P1Basis, P0Basis, VectorType, SingletonVectorType, GridView>( - p1Basis, u, alpha, p0Basis, vonMisesStress, leafView, - (boost::format("obs%d") % run).str()); - } - } - if (parset.get<bool>("enableTimer")) - std::cerr << std::endl << "Making " << timesteps << " time steps took " - << timer.elapsed() << "s" << std::endl; - - state_writer.close(); - displacement_writer.close(); - velocity_writer.close(); - coefficient_writer.close(); - - Python::stop(); - } - catch (Dune::Exception &e) { - Dune::derr << "Dune reported error: " << e << std::endl; - } - catch (std::exception &e) { - std::cerr << "Standard exception: " << e.what() << std::endl; - } -} diff --git a/src/one-body-sample.org b/src/one-body-sample.org new file mode 100644 index 0000000000000000000000000000000000000000..325a2829ccdc9b06db56b069f533a99b8f4c0001 --- /dev/null +++ b/src/one-body-sample.org @@ -0,0 +1,514 @@ +#+name: assembleMassMatrix +#+begin_src c++ + { + MassAssembler + <GridType, P1Basis::LocalFiniteElement, + P1Basis::LocalFiniteElement> const localMass; + OperatorAssembler<P1Basis,P1Basis>(p1Basis, p1Basis) + .assemble(localMass, massMatrix); + massMatrix *= density; + } +#+end_src + +#+name: computeNormalStress +#+begin_src c++ + { + double volume = 1.0; + for (int i=0; i<dim; ++i) + volume *= (upperRight[i] - lowerLeft[i]); + + double area = 1.0; + for (int i=0; i<dim; ++i) + if (i != 1) + area *= (upperRight[i] - lowerLeft[i]); + + // volume * gravity * density / area = normal stress + // V * g * rho / A = sigma_n + // m^d * N/kg * kg/m^d / m^(d-1) = N/m^(d-1) + normalStress = volume * gravity * density / area; + } +#+end_src + +#+name: computeGravitationalBodyForce +#+begin_src c++ + { + SmallVector weightedGravitationalDirection(0); + weightedGravitationalDirection[1] = - density * gravity; + ConstantFunction<SmallVector,SmallVector> const gravityFunction + (weightedGravitationalDirection); + L2FunctionalAssembler<GridType, SmallVector> gravityFunctionalAssembler + (gravityFunction); + FunctionalAssembler<P1Basis>(p1Basis) + .assemble(gravityFunctionalAssembler, gravityFunctional, true); + } +#+end_src + +#+name: assembleStiffnessMatrix +#+begin_src c++ + { + StVenantKirchhoffAssembler + <GridType, P1Basis::LocalFiniteElement, + P1Basis::LocalFiniteElement> const localStiffness(E, nu); + OperatorAssembler<P1Basis,P1Basis>(p1Basis, p1Basis) + .assemble(localStiffness, stiffnessMatrix); + } +#+end_src c++ + +#+begin_src c++ :tangle one-body-sample.cc :noweb yes + #ifdef HAVE_CONFIG_H + #include "config.h" + #endif + + #ifdef HAVE_IPOPT + #undef HAVE_IPOPT + #endif + + #ifndef srcdir + #error srcdir unset + #endif + + #ifndef DIM + #error DIM unset + #endif + + #ifndef HAVE_PYTHON + #error Python is required + #endif + + #if ! HAVE_ALUGRID + #error ALUGRID is required + #endif + + #include <cmath> + #include <exception> + #include <iostream> + + #include <boost/format.hpp> + + #include <Python.h> + + #include <dune/common/bitsetvector.hh> + #include <dune/common/exceptions.hh> + #include <dune/common/fmatrix.hh> + #include <dune/common/function.hh> + #include <dune/common/fvector.hh> + #include <dune/common/parametertree.hh> + #include <dune/common/parametertreeparser.hh> + #include <dune/common/shared_ptr.hh> + #include <dune/common/timer.hh> + #include <dune/grid/alugrid.hh> + #include <dune/grid/common/mcmgmapper.hh> + #include <dune/grid/utility/structuredgridfactory.hh> + #include <dune/istl/bcrsmatrix.hh> + #include <dune/istl/bvector.hh> + + #include <dune/fufem/assemblers/functionalassembler.hh> + #include <dune/fufem/assemblers/localassemblers/l2functionalassembler.hh> + #include <dune/fufem/assemblers/localassemblers/massassembler.hh> + #include <dune/fufem/assemblers/localassemblers/stvenantkirchhoffassembler.hh> + #include <dune/fufem/assemblers/localassemblers/vonmisesstressassembler.hh> + #include <dune/fufem/assemblers/operatorassembler.hh> + #include <dune/fufem/dunepython.hh> + #include <dune/fufem/functions/basisgridfunction.hh> + #include <dune/fufem/functions/constantfunction.hh> + #include <dune/fufem/functionspacebases/p0basis.hh> + #include <dune/fufem/functionspacebases/p1nodalbasis.hh> + #include <dune/fufem/sharedpointermap.hh> + #include <dune/solvers/norms/energynorm.hh> + #include <dune/solvers/solvers/loopsolver.hh> + #include <dune/solvers/solvers/solver.hh> // Solver::FULL + + #include <dune/tectonic/myblockproblem.hh> + #include <dune/tectonic/myconvexproblem.hh> + + #include "assemblers.hh" + #include "mysolver.hh" + #include "vtk.hh" + + #include "enums.hh" + #include "enum_parser.cc" + #include "enum_state_model.cc" + #include "enum_scheme.cc" + + #include "timestepping.hh" + + #include "ruinastateupdater.hh" + #include "dieterichstateupdater.hh" + + int const dim = DIM; + + template <class GridView, class GridCorner> + void + setup_boundary(GridView const &gridView, + Dune::BitSetVector<dim> &ignoreNodes, + Dune::BitSetVector<1> &neumannNodes, + Dune::BitSetVector<1> &frictionalNodes, + GridCorner const &lowerLeft, + GridCorner const &upperRight, + size_t &specialNode) + { + typedef typename GridView::template Codim<dim>::Iterator VertexLeafIterator; + + Dune::MultipleCodimMultipleGeomTypeMapper + <GridView, Dune::MCMGVertexLayout> const myVertexMapper(gridView); + + for (auto it = gridView.template begin<dim>(); + it != gridView.template end<dim>(); + ++it) { + assert(it->geometry().corners() == 1); + Dune::FieldVector<double, dim> const coordinates = it->geometry().corner(0); + size_t const id = myVertexMapper.map(*it); + + // Find the center of the lower face + switch (dim) { + case 3: + if (coordinates[2] != lowerLeft[2]) + break; + // fallthrough + case 2: + if (coordinates[1] == lowerLeft[1] + && std::abs(coordinates[0] - lowerLeft[0]) < 1e-8) + specialNode = id; + break; + default: + assert(false); + } + + // lower face + if (coordinates[1] == lowerLeft[1]) { + frictionalNodes[id] = true; + ignoreNodes[id][1] = true; + } + + // upper face + else if (coordinates[1] == upperRight[1]) + ignoreNodes[id] = true; + + // right face (except for both corners) + else if (coordinates[0] == upperRight[0]) + ; + + // left face (except for both corners) + else if (coordinates[0] == lowerLeft[0]) + ; + } + } + + template<class VectorType, class MatrixType, class FunctionType, int dim> + Dune::shared_ptr + <TimeSteppingScheme + <VectorType,MatrixType,FunctionType,dim> > + initTimeStepper(Config::scheme scheme, + FunctionType const &dirichletFunction, + Dune::BitSetVector<dim> const &ignoreNodes, + MatrixType const &massMatrix, MatrixType const &stiffnessMatrix, + VectorType const &u_initial, + VectorType const &ud_initial, + VectorType const &udd_initial) + { + switch (scheme) { + case Config::ImplicitTwoStep: + return Dune::make_shared<ImplicitTwoStep<VectorType,MatrixType, + FunctionType,dim> > + (stiffnessMatrix, u_initial, ud_initial, ignoreNodes, dirichletFunction); + case Config::ImplicitEuler: + return Dune::make_shared<ImplicitEuler<VectorType,MatrixType, + FunctionType,dim> > + (stiffnessMatrix, u_initial, ud_initial, ignoreNodes, dirichletFunction); + case Config::Newmark: + return Dune::make_shared <Newmark <VectorType,MatrixType,FunctionType,dim> > + (stiffnessMatrix, massMatrix, u_initial, ud_initial, udd_initial, + ignoreNodes, dirichletFunction); + } + } + + template<class SingletonVectorType, class VectorType> + Dune::shared_ptr<StateUpdater<SingletonVectorType, VectorType> > + initStateUpdater(Config::state_model model, + SingletonVectorType const &alpha_initial, + Dune::BitSetVector<1> const &frictionalNodes, + double L) + { + switch (model) { + case Config::Dieterich: + return Dune::make_shared + <DieterichStateUpdater<SingletonVectorType, VectorType> > + (alpha_initial, frictionalNodes, L); + case Config::Ruina: + return Dune::make_shared + <RuinaStateUpdater<SingletonVectorType, VectorType> > + (alpha_initial, frictionalNodes, L); + } + } + + template <class FunctionMap> + void + initPython(FunctionMap &functions) + { + Python::start(); + + Python::run("import sys"); + Python::run("sys.path.append('" srcdir "')"); + + Python::import("one-body-sample") + .get("Functions") + .toC<typename FunctionMap::Base>(functions); + } + + int + main(int argc, char *argv[]) + { + try { + typedef SharedPointerMap + <std::string, Dune::VirtualFunction<double, double> > FunctionMap; + FunctionMap functions; + initPython(functions); + + Dune::ParameterTree parset; + Dune::ParameterTreeParser::readINITree + (srcdir "/one-body-sample.parset", parset); + Dune::ParameterTreeParser::readOptions(argc, argv, parset); + + Dune::Timer timer; + + typedef Dune::FieldVector<double, dim> SmallVector; + typedef Dune::FieldMatrix<double, dim, dim> SmallMatrix; + typedef Dune::BCRSMatrix<SmallMatrix> MatrixType; + typedef Dune::BlockVector<SmallVector> VectorType; + typedef Dune::BlockVector<Dune::FieldVector<double,1> > SingletonVectorType; + + auto const E = parset.get<double>("body.E"); + auto const nu = parset.get<double>("body.nu"); + auto const solver_tolerance = parset.get<double>("solver.tolerance"); + + auto const refinements = parset.get<size_t>("grid.refinements"); + + auto const verbose = parset.get<bool>("verbose"); + Solver::VerbosityMode const verbosity + = verbose ? Solver::FULL : Solver::QUIET; + + // {{{ Set up grid + typedef Dune::ALUGrid<dim, dim, Dune::simplex, Dune::nonconforming> + GridType; + + Dune::FieldVector<typename GridType::ctype, dim> lowerLeft(0); + Dune::FieldVector<typename GridType::ctype, dim> upperRight(1); + upperRight[0] = parset.get<size_t>("body.width"); + upperRight[1] = parset.get<size_t>("body.height"); + + Dune::array<unsigned int, dim> elements; + std::fill(elements.begin(), elements.end(), 1); + elements[0] = parset.get<size_t>("body.width"); + elements[1] = parset.get<size_t>("body.height"); + + auto grid = Dune::StructuredGridFactory<GridType>::createSimplexGrid + (lowerLeft, upperRight, elements); + + grid->globalRefine(refinements); + size_t const finestSize = grid->size(grid->maxLevel(), dim); + + typedef GridType::LeafGridView GridView; + GridView const leafView = grid->leafView(); + // }}} + + // Set up bases + typedef P0Basis<GridView, double> P0Basis; + typedef P1NodalBasis<GridView, double> P1Basis; + P0Basis const p0Basis(leafView); + P1Basis const p1Basis(leafView); + + double normalStress; + MatrixType massMatrix; + VectorType gravityFunctional; + { + double const gravity = 9.81; + double const density = parset.get<double>("body.density"); + + <<assembleMassMatrix>>; + <<computeNormalStress>>; + <<computeGravitationalBodyForce>>; + } + + // Assemble elastic force on the body + MatrixType stiffnessMatrix; + <<assembleStiffnessMatrix>>; + EnergyNorm<MatrixType, VectorType> energyNorm(stiffnessMatrix); + + // Set up the boundary + size_t specialNode = finestSize; + Dune::BitSetVector<dim> ignoreNodes(finestSize, false); + Dune::BitSetVector<1> neumannNodes(finestSize, false); + Dune::BitSetVector<1> frictionalNodes(finestSize, false); + setup_boundary(leafView, ignoreNodes, neumannNodes, frictionalNodes, + lowerLeft, upperRight, specialNode); + assert(specialNode != finestSize); + assert(frictionalNodes[specialNode][0]); + + auto const nodalIntegrals + = assemble_frictional<GridType, GridView, SmallVector, P1Basis> + (leafView, p1Basis, frictionalNodes); + + // {{{ Initialise vectors + VectorType u(finestSize); u = 0.0; + VectorType ud(finestSize); ud = 0.0; + + VectorType u_initial(finestSize); u_initial = 0.0; + VectorType ud_initial(finestSize); ud_initial = 0.0; + VectorType udd_initial(finestSize); udd_initial = 0.0; + + SingletonVectorType alpha_initial(finestSize); + alpha_initial = parset.get<double>("boundary.friction.state.initial"); + SingletonVectorType alpha(alpha_initial); + + SingletonVectorType vonMisesStress; + + SingletonVectorType surfaceNormalStress(finestSize); + surfaceNormalStress = 0.0; + for (size_t i = 0; i < frictionalNodes.size(); ++i) + if (frictionalNodes[i][0]) + surfaceNormalStress[i] = normalStress; + // }}} + + typedef MyConvexProblem<MatrixType, VectorType> MyConvexProblemType; + typedef MyBlockProblem<MyConvexProblemType> MyBlockProblemType; + + // Set up TNNMG solver + MySolver<dim, MatrixType, VectorType, GridType, MyBlockProblemType> + mySolver(parset.sub("solver.tnnmg"), refinements, solver_tolerance, + *grid, ignoreNodes); + + std::fstream state_writer("state", std::fstream::out); + std::fstream displacement_writer("displacement", std::fstream::out); + std::fstream velocity_writer("velocity", std::fstream::out); + std::fstream coefficient_writer("coefficient", std::fstream::out); + + auto const L = parset.get<double>("boundary.friction.ruina.L"); + auto const a = parset.get<double>("boundary.friction.ruina.a"); + auto const b = parset.get<double>("boundary.friction.ruina.b"); + auto const V0 = parset.get<double>("boundary.friction.V0"); + auto const mu = parset.get<double>("boundary.friction.mu"); + auto const timesteps = parset.get<size_t>("timeSteps"); + auto const tau = parset.get<double>("endOfTime") / timesteps; + + auto const &dirichletFunction = functions.get("dirichletCondition"); + auto const &neumannFunction = functions.get("neumannCondition"); + + auto timeSteppingScheme = initTimeStepper + (parset.get<Config::scheme>("timeSteppingScheme"), dirichletFunction, + ignoreNodes, massMatrix, stiffnessMatrix, u_initial, ud_initial, + udd_initial); + auto stateUpdater = initStateUpdater<SingletonVectorType, VectorType> + (parset.get<Config::state_model>("boundary.friction.state.model"), + alpha_initial, frictionalNodes, L); + + auto const state_fpi_max + = parset.get<size_t>("solver.tnnmg.fixed_point_iterations"); + for (size_t run = 1; run <= timesteps; ++run) { + double const time = tau * run; + { + stateUpdater->nextTimeStep(); + + VectorType ell(finestSize); + assemble_neumann<GridType, GridView, SmallVector, P1Basis> + (leafView, p1Basis, neumannNodes, ell, neumannFunction, time); + ell += gravityFunctional; + + // Copy everything for now + MatrixType problem_A; + VectorType problem_rhs(finestSize); + VectorType problem_iterate(finestSize); + + stateUpdater->setup(tau); + timeSteppingScheme->setup(ell, tau, time, + problem_rhs, problem_iterate, problem_A); + + VectorType u_saved; + for (size_t state_fpi = 1; state_fpi <= state_fpi_max; ++state_fpi) { + auto myGlobalNonlinearity + = assemble_nonlinearity<MatrixType, VectorType> + (parset.sub("boundary.friction"), *nodalIntegrals, alpha, + surfaceNormalStress); + + MyConvexProblemType const myConvexProblem + (problem_A, *myGlobalNonlinearity, problem_rhs); + MyBlockProblemType myBlockProblem(parset, myConvexProblem); + auto multigridStep = mySolver.getSolver(); + multigridStep->setProblem(problem_iterate, myBlockProblem); + + LoopSolver<VectorType> overallSolver + (multigridStep, parset.get<size_t>("solver.tnnmg.maxiterations"), + solver_tolerance, &energyNorm, verbosity, false); // absolute error + overallSolver.solve(); + + timeSteppingScheme->postProcess(problem_iterate); + timeSteppingScheme->extractDisplacement(u); + timeSteppingScheme->extractVelocity(ud); + + stateUpdater->solve(ud); + stateUpdater->extractState(alpha); + + if (parset.get<bool>("printProgress")) { + std::cerr << '.'; + std::cerr.flush(); + } + if (state_fpi > 1 && energyNorm.diff(u_saved, u) + < parset.get<double>("solver.tnnmg.fixed_point_tolerance")) + break; + else + u_saved = u; + + if (state_fpi == state_fpi_max) + std::cerr << "[ref = " << refinements + << "]: FPI did not converge after " + << state_fpi_max << " iterations" << std::endl; + } + if (parset.get<bool>("printProgress")) + std::cerr << std::endl; + } + + { // Write all kinds of data + state_writer << alpha[specialNode][0] << " " << std::endl; + displacement_writer << u[specialNode][0] << " " << std::endl; + velocity_writer << ud[specialNode][0] << " " << std::endl; + coefficient_writer << mu + + a * std::log(ud[specialNode].two_norm() / V0) + + b * (alpha[specialNode] + std::log(V0 / L)) + << " " << std::endl; + } + + // Compute von Mises stress and write everything to a file + if (parset.get<bool>("writeVTK")) { + VonMisesStressAssembler<GridType> localStressAssembler + (E, nu, + Dune::make_shared<BasisGridFunction<P1Basis, VectorType> const> + (p1Basis, u)); + FunctionalAssembler<P0Basis>(p0Basis) + .assemble(localStressAssembler, vonMisesStress, true); + + writeVtk<P1Basis, P0Basis, VectorType, SingletonVectorType, GridView> + (p1Basis, u, alpha, p0Basis, vonMisesStress, leafView, + (boost::format("obs%d") % run).str()); + } + } + if (parset.get<bool>("enableTimer")) + std::cerr << std::endl + << "Making " << timesteps + << " time steps took " << timer.elapsed() + << "s" << std::endl; + + state_writer.close(); + displacement_writer.close(); + velocity_writer.close(); + coefficient_writer.close(); + + Python::stop(); + } + catch (Dune::Exception &e) { + Dune::derr << "Dune reported error: " << e << std::endl; + } + catch (std::exception &e) { + std::cerr << "Standard exception: " << e.what() << std::endl; + } + } + +#+end_src