diff --git a/src/.gitignore b/src/.gitignore index aa8174205fc7e75281254e0edd1c8b65231201a9..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,4 +0,0 @@ -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 a05d4c69a6dfabfb921df57e38e4cadda6103d5d..48b85a8f3c1b653fdf626690cbf28fc379f1c93e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -102,19 +102,3 @@ DISTCHECK_CONFIGURE_FLAGS = \ CXX="$(CXX)" CC="$(CC)" include $(top_srcdir)/am/global-rules - -BUILT_SOURCES = timestepping.hh timestepping.cc -# Make sure the two are not built in parallel -$(srcdir)/timestepping.cc: $(srcdir)/timestepping.hh - -EMACS ?= emacs - -$(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 new file mode 100644 index 0000000000000000000000000000000000000000..624e94fc32dc3638000dc8b7ae68e190528f9d7a --- /dev/null +++ b/src/one-body-sample.cc @@ -0,0 +1,471 @@ +#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 "state/stateupdater.hh" +#include "state/ruinastateupdater.hh" +#include "state/dieterichstateupdater.hh" + +int const dims = DIM; + +template <class VectorType, class MatrixType, class FunctionType, int dims> +Dune::shared_ptr<TimeSteppingScheme<VectorType, MatrixType, FunctionType, dims>> +initTimeStepper(Config::scheme scheme, FunctionType const &dirichletFunction, + Dune::BitSetVector<dims> 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, dims>>( + stiffnessMatrix, u_initial, ud_initial, ignoreNodes, + dirichletFunction); + case Config::ImplicitEuler: + return Dune::make_shared< + ImplicitEuler<VectorType, MatrixType, FunctionType, dims>>( + stiffnessMatrix, u_initial, ud_initial, ignoreNodes, + dirichletFunction); + case Config::Newmark: + return Dune::make_shared< + Newmark<VectorType, MatrixType, FunctionType, dims>>( + 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 { + Dune::Timer timer; + + Dune::ParameterTree parset; + Dune::ParameterTreeParser::readINITree(srcdir "/one-body-sample.parset", + parset); + Dune::ParameterTreeParser::readOptions(argc, argv, parset); + + typedef Dune::FieldVector<double, dims> SmallVector; + typedef Dune::FieldMatrix<double, dims, dims> 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 mu = parset.get<double>("boundary.friction.mu"); + auto const a = parset.get<double>("boundary.friction.a"); + auto const b = parset.get<double>("boundary.friction.b"); + auto const V0 = parset.get<double>("boundary.friction.V0"); + auto const L = parset.get<double>("boundary.friction.L"); + + // {{{ Set up grid + typedef Dune::ALUGrid<dims, dims, Dune::simplex, Dune::nonconforming> + GridType; + + Dune::FieldVector<typename GridType::ctype, dims> lowerLeft(0); + Dune::FieldVector<typename GridType::ctype, dims> upperRight(1); + upperRight[0] = parset.get<size_t>("body.width"); + upperRight[1] = parset.get<size_t>("body.height"); + + Dune::array<unsigned int, dims> 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); + + auto const refinements = parset.get<size_t>("grid.refinements"); + grid->globalRefine(refinements); + size_t const finestSize = grid->size(grid->maxLevel(), dims); + + 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); + + // Set up the boundary + size_t specialNode = finestSize; + Dune::BitSetVector<dims> ignoreNodes(finestSize, false); + Dune::BitSetVector<1> neumannNodes(finestSize, false); + Dune::BitSetVector<1> frictionalNodes(finestSize, false); + { + typedef typename GridView::Codim<dims>::Iterator VertexLeafIterator; + + Dune::MultipleCodimMultipleGeomTypeMapper< + GridView, Dune::MCMGVertexLayout> const myVertexMapper(leafView); + + for (auto it = leafView.begin<dims>(); it != leafView.end<dims>(); ++it) { + assert(it->geometry().corners() == 1); + Dune::FieldVector<double, dims> const coordinates = + it->geometry().corner(0); + size_t const id = myVertexMapper.map(*it); + + // Find the center of the lower face + switch (dims) { + 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]) + ; + } + // Make sure that specialNode was set and points to a frictional node + assert(specialNode != finestSize); + assert(frictionalNodes[specialNode][0]); + }; + + // Set up functions for time-dependent boundary conditions + typedef Dune::VirtualFunction<double, double> FunctionType; + SharedPointerMap<std::string, FunctionType> functions; + initPython(functions); + auto const &dirichletFunction = functions.get("dirichletCondition"); + auto const &neumannFunction = functions.get("neumannCondition"); + + // Set up normal stress, mass matrix, and gravity functional + double normalStress; + MatrixType massMatrix; + VectorType gravityFunctional; + { + double const gravity = 9.81; + double const density = parset.get<double>("body.density"); + + { + MassAssembler<GridType, P1Basis::LocalFiniteElement, + P1Basis::LocalFiniteElement> const localMass; + OperatorAssembler<P1Basis, P1Basis>(p1Basis, p1Basis) + .assemble(localMass, massMatrix); + massMatrix *= density; + }; + { + double volume = 1.0; + for (int i = 0; i < dims; ++i) + volume *= (upperRight[i] - lowerLeft[i]); + + double area = 1.0; + for (int i = 0; i < dims; ++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; + }; + { + 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); + }; + } + SingletonVectorType surfaceNormalStress(finestSize); + surfaceNormalStress = normalStress; + + 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); + + auto const nodalIntegrals = + assemble_frictional<GridType, GridView, SmallVector, P1Basis>( + leafView, p1Basis, frictionalNodes); + + // {{{ Initial conditions + 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.initial_log_state"); + // }}} + + // Set up TNNMG solver + auto const solver_tolerance = parset.get<double>("solver.tolerance"); + typedef MyConvexProblem<MatrixType, VectorType> MyConvexProblemType; + typedef MyBlockProblem<MyConvexProblemType> MyBlockProblemType; + MySolver<dims, MatrixType, VectorType, GridType, MyBlockProblemType> + mySolver(parset.sub("solver.tnnmg"), refinements, solver_tolerance, *grid, + ignoreNodes); + + Solver::VerbosityMode const verbosity = + parset.get<bool>("verbose") ? Solver::FULL : Solver::QUIET; + + 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 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 timesteps = parset.get<size_t>("timeSteps"); + auto const tau = parset.get<double>("endOfTime") / timesteps; + + auto createRHS = [&](double _time, VectorType &_ell) { + assemble_neumann<GridType, GridView, SmallVector, P1Basis>( + leafView, p1Basis, neumannNodes, _ell, neumannFunction, _time); + _ell += gravityFunctional; + }; + + auto const state_fpi_max = + parset.get<size_t>("solver.tnnmg.fixed_point_iterations"); + for (size_t run = 1; run <= timesteps; ++run) { + VectorType u; + VectorType ud; + SingletonVectorType alpha; + stateUpdater->extractState(alpha); + + stateUpdater->nextTimeStep(); + timeSteppingScheme->nextTimeStep(); + + double const time = tau * run; + + VectorType ell(finestSize); + createRHS(time, ell); + + 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); + + auto solveDisplacementProblem = [&](VectorType &_problem_iterate, + SingletonVectorType const &_alpha) { + 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"), + parset.get<double>("solver.tolerance"), &energyNorm, verbosity, + false); // absolute error + overallSolver.preprocess(); + overallSolver.solve(); + }; + + // Since the velocity explodes in the quasistatic case, use the + // displacement as a convergence criterion + VectorType u_saved; + for (size_t state_fpi = 1; state_fpi <= state_fpi_max; ++state_fpi) { + solveDisplacementProblem(problem_iterate, alpha); + + 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) + DUNE_THROW(Dune::Exception, "FPI failed to converge"); + } + if (parset.get<bool>("printProgress")) + std::cerr << std::endl; + ; + + 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; + ; + if (parset.get<bool>("writeVTK")) { + SingletonVectorType vonMisesStress; + 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 deleted file mode 100644 index 9372163b20c9c3c60e139c0eec7360a41b9ce4b4..0000000000000000000000000000000000000000 --- a/src/one-body-sample.org +++ /dev/null @@ -1,548 +0,0 @@ -* Setup -#+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<dims; ++i) - volume *= (upperRight[i] - lowerLeft[i]); - - double area = 1.0; - for (int i=0; i<dims; ++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++ -#+name: setupBoundary -#+begin_src c++ - { - typedef typename GridView::Codim<dims>::Iterator VertexLeafIterator; - - Dune::MultipleCodimMultipleGeomTypeMapper - <GridView, Dune::MCMGVertexLayout> const myVertexMapper(leafView); - - for (auto it = leafView.begin<dims>(); - it != leafView.end<dims>(); - ++it) { - assert(it->geometry().corners() == 1); - Dune::FieldVector<double, dims> const coordinates = it->geometry().corner(0); - size_t const id = myVertexMapper.map(*it); - - // Find the center of the lower face - switch (dims) { - 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]) - ; - } - // Make sure that specialNode was set and points to a frictional node - assert(specialNode != finestSize); - assert(frictionalNodes[specialNode][0]); - } -#+end_src -* Writers -#+name: createWriters -#+begin_src c++ - 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); -#+end_src -#+name: writeData -#+begin_src c++ - 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; -#+end_src -#+name: closeWriters -#+begin_src c++ - state_writer.close(); - displacement_writer.close(); - velocity_writer.close(); - coefficient_writer.close(); -#+end_src -#+name: assembleAndWriteStress -#+begin_src c++ - if (parset.get<bool>("writeVTK")) { - SingletonVectorType vonMisesStress; - 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()); - } -#+end_src -* Misc. helpers -#+name: printBenchmarkData -#+begin_src c++ - if (parset.get<bool>("enableTimer")) - std::cerr << std::endl - << "Making " << timesteps - << " time steps took " << timer.elapsed() - << "s" << std::endl; -#+end_src -#+name: printInnerProgress -#+begin_src c++ - if (parset.get<bool>("printProgress")) { - std::cerr << '.'; - std::cerr.flush(); - } -#+end_src -#+name: printOuterProgress -#+begin_src c++ - if (parset.get<bool>("printProgress")) - std::cerr << std::endl; -#+end_src -* Functions -#+name: defineInitTimeStepper -#+begin_src c++ - template<class VectorType, class MatrixType, class FunctionType, int dims> - Dune::shared_ptr - <TimeSteppingScheme - <VectorType,MatrixType,FunctionType,dims> > - initTimeStepper(Config::scheme scheme, - FunctionType const &dirichletFunction, - Dune::BitSetVector<dims> 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,dims> > - (stiffnessMatrix, u_initial, ud_initial, ignoreNodes, dirichletFunction); - case Config::ImplicitEuler: - return Dune::make_shared<ImplicitEuler<VectorType,MatrixType, - FunctionType,dims> > - (stiffnessMatrix, u_initial, ud_initial, ignoreNodes, dirichletFunction); - case Config::Newmark: - return Dune::make_shared <Newmark <VectorType,MatrixType,FunctionType,dims> > - (stiffnessMatrix, massMatrix, u_initial, ud_initial, udd_initial, - ignoreNodes, dirichletFunction); - } - } -#+end_src -#+name: defineInitStateUpdater -#+begin_src c++ - 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); - } - } -#+end_src -#+name: defineInitPython -#+begin_src c++ - 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); - } -#+end_src -#+name: mainBody -#+begin_src c++ - try { - Dune::Timer timer; - - Dune::ParameterTree parset; - Dune::ParameterTreeParser::readINITree - (srcdir "/one-body-sample.parset", parset); - Dune::ParameterTreeParser::readOptions(argc, argv, parset); - - typedef Dune::FieldVector<double, dims> SmallVector; - typedef Dune::FieldMatrix<double, dims, dims> 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 mu = parset.get<double>("boundary.friction.mu"); - auto const a = parset.get<double>("boundary.friction.a"); - auto const b = parset.get<double>("boundary.friction.b"); - auto const V0 = parset.get<double>("boundary.friction.V0"); - auto const L = parset.get<double>("boundary.friction.L"); - - // {{{ Set up grid - typedef Dune::ALUGrid<dims, dims, Dune::simplex, Dune::nonconforming> - GridType; - - Dune::FieldVector<typename GridType::ctype, dims> lowerLeft(0); - Dune::FieldVector<typename GridType::ctype, dims> upperRight(1); - upperRight[0] = parset.get<size_t>("body.width"); - upperRight[1] = parset.get<size_t>("body.height"); - - Dune::array<unsigned int, dims> 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); - - auto const refinements = parset.get<size_t>("grid.refinements"); - grid->globalRefine(refinements); - size_t const finestSize = grid->size(grid->maxLevel(), dims); - - 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); - - // Set up the boundary - size_t specialNode = finestSize; - Dune::BitSetVector<dims> ignoreNodes(finestSize, false); - Dune::BitSetVector<1> neumannNodes(finestSize, false); - Dune::BitSetVector<1> frictionalNodes(finestSize, false); - <<setupBoundary>>; - - // Set up functions for time-dependent boundary conditions - typedef Dune::VirtualFunction<double, double> FunctionType; - SharedPointerMap <std::string, FunctionType> functions; - initPython(functions); - auto const &dirichletFunction = functions.get("dirichletCondition"); - auto const &neumannFunction = functions.get("neumannCondition"); - - // Set up normal stress, mass matrix, and gravity functional - double normalStress; - MatrixType massMatrix; - VectorType gravityFunctional; - { - double const gravity = 9.81; - double const density = parset.get<double>("body.density"); - - <<assembleMassMatrix>>; - <<computeNormalStress>>; - <<computeGravitationalBodyForce>>; - } - SingletonVectorType surfaceNormalStress(finestSize); - surfaceNormalStress = normalStress; - - MatrixType stiffnessMatrix; - <<assembleStiffnessMatrix>>; - EnergyNorm<MatrixType, VectorType> energyNorm(stiffnessMatrix); - - auto const nodalIntegrals - = assemble_frictional<GridType, GridView, SmallVector, P1Basis> - (leafView, p1Basis, frictionalNodes); - - // {{{ Initial conditions - 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.initial_log_state"); - // }}} - - // Set up TNNMG solver - auto const solver_tolerance = parset.get<double>("solver.tolerance"); - typedef MyConvexProblem<MatrixType, VectorType> MyConvexProblemType; - typedef MyBlockProblem<MyConvexProblemType> MyBlockProblemType; - MySolver<dims, MatrixType, VectorType, GridType, MyBlockProblemType> - mySolver(parset.sub("solver.tnnmg"), refinements, solver_tolerance, - ,*grid, ignoreNodes); - - Solver::VerbosityMode const verbosity - = parset.get<bool>("verbose") ? Solver::FULL : Solver::QUIET; - - <<createWriters>>; - - 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 timesteps = parset.get<size_t>("timeSteps"); - auto const tau = parset.get<double>("endOfTime") / timesteps; - - auto createRHS = [&](double _time, VectorType &_ell) { - assemble_neumann<GridType, GridView, SmallVector, P1Basis> - (leafView, p1Basis, neumannNodes, _ell, neumannFunction, _time); - _ell += gravityFunctional; - }; - - auto const state_fpi_max - = parset.get<size_t>("solver.tnnmg.fixed_point_iterations"); - for (size_t run = 1; run <= timesteps; ++run) { - VectorType u; - VectorType ud; - SingletonVectorType alpha; - stateUpdater->extractState(alpha); - - stateUpdater->nextTimeStep(); - timeSteppingScheme->nextTimeStep(); - - double const time = tau * run; - - VectorType ell(finestSize); - createRHS(time, ell); - - 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); - - auto solveDisplacementProblem = [&](VectorType &_problem_iterate, - SingletonVectorType const &_alpha) { - 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"), - parset.get<double>("solver.tolerance"), &energyNorm, verbosity, - false); // absolute error - overallSolver.preprocess(); - overallSolver.solve(); - }; - - // Since the velocity explodes in the quasistatic case, use the - // displacement as a convergence criterion - VectorType u_saved; - for (size_t state_fpi = 1; state_fpi <= state_fpi_max; ++state_fpi) { - solveDisplacementProblem(problem_iterate, alpha); - - timeSteppingScheme->postProcess(problem_iterate); - timeSteppingScheme->extractDisplacement(u); - timeSteppingScheme->extractVelocity(ud); - - stateUpdater->solve(ud); - stateUpdater->extractState(alpha); - - <<printInnerProgress>>; - 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) - DUNE_THROW(Dune::Exception, "FPI failed to converge"); - } - <<printOuterProgress>>; - - <<writeData>>; - <<assembleAndWriteStress>>; - } - <<printBenchmarkData>>; - <<closeWriters>>; - - 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 -* Skeleton -#+begin_src c++ :tangle one-body-sample.cc :noweb yes - // GENERATED -- DO NOT MODIFY - - #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 "state/stateupdater.hh" - #include "state/ruinastateupdater.hh" - #include "state/dieterichstateupdater.hh" - - int const dims = DIM; - - <<defineInitTimeStepper>> - <<defineInitStateUpdater>> - <<defineInitPython>> - - int - main(int argc, char *argv[]) - { - <<mainBody>> - } -#+end_src diff --git a/src/timestepping.cc b/src/timestepping.cc new file mode 100644 index 0000000000000000000000000000000000000000..9b46235d3cfd41778a90748c306c5e8cdd8c5b32 --- /dev/null +++ b/src/timestepping.cc @@ -0,0 +1,336 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <dune/fufem/arithmetic.hh> +#include "timestepping.hh" + +template <class VectorType, class MatrixType, class FunctionType, int dim> +ImplicitEuler<VectorType, MatrixType, FunctionType, dim>::ImplicitEuler( + MatrixType const &_A, VectorType const &_u_initial, + VectorType const &_ud_initial, + Dune::BitSetVector<dim> const &_dirichletNodes, + FunctionType const &_dirichletFunction) + : A(_A), + u(_u_initial), + ud(_ud_initial), + dirichletNodes(_dirichletNodes), + dirichletFunction(_dirichletFunction) {} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void ImplicitEuler<VectorType, MatrixType, FunctionType, dim>::nextTimeStep() { + ud_old = ud; + u_old = u; +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void ImplicitEuler<VectorType, MatrixType, FunctionType, dim>::setup( + VectorType const &ell, double _tau, double time, VectorType &problem_rhs, + VectorType &problem_iterate, MatrixType &problem_A) { + postProcessCalled = false; + + tau = _tau; + + problem_rhs = ell; + A.mmv(u_old, problem_rhs); + + // For fixed tau, we'd only really have to do this once + problem_A = A; + problem_A *= tau; + + // ud_old makes a good initial iterate; we could use anything, though + problem_iterate = ud_old; + + for (size_t i = 0; i < dirichletNodes.size(); ++i) + switch (dirichletNodes[i].count()) { + case 0: + continue; + case dim: + problem_iterate[i] = 0; + dirichletFunction.evaluate(time, problem_iterate[i][0]); + break; + case 1: + if (dirichletNodes[i][0]) { + dirichletFunction.evaluate(time, problem_iterate[i][0]); + break; + } + if (dirichletNodes[i][1]) { + problem_iterate[i][1] = 0; + break; + } + assert(false); + default: + assert(false); + } +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void ImplicitEuler<VectorType, MatrixType, FunctionType, dim>::postProcess( + VectorType const &problem_iterate) { + postProcessCalled = true; + + ud = problem_iterate; + + u = u_old; + Arithmetic::addProduct(u, tau, ud); +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void ImplicitEuler<VectorType, MatrixType, FunctionType, + dim>::extractDisplacement(VectorType &displacement) const { + if (!postProcessCalled) + DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); + + displacement = u; +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void ImplicitEuler<VectorType, MatrixType, FunctionType, dim>::extractVelocity( + VectorType &velocity) const { + if (!postProcessCalled) + DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); + + velocity = ud; +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * +ImplicitEuler<VectorType, MatrixType, FunctionType, dim>::clone() { + return new ImplicitEuler<VectorType, MatrixType, FunctionType, dim>(*this); +} +template <class VectorType, class MatrixType, class FunctionType, int dim> +ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>::ImplicitTwoStep( + MatrixType const &_A, VectorType const &_u_initial, + VectorType const &_ud_initial, + Dune::BitSetVector<dim> const &_dirichletNodes, + FunctionType const &_dirichletFunction) + : A(_A), + u(_u_initial), + ud(_ud_initial), + dirichletNodes(_dirichletNodes), + dirichletFunction(_dirichletFunction) {} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void +ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>::nextTimeStep() { + u_old_old = u_old; + ud_old = ud; + u_old = u; +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>::setup( + VectorType const &ell, double _tau, double time, VectorType &problem_rhs, + VectorType &problem_iterate, MatrixType &problem_A) { + postProcessCalled = false; + + tau = _tau; + + switch (state) { + // Perform an implicit Euler step since we lack information + case NO_SETUP: + state = FIRST_SETUP; + + problem_rhs = ell; + A.mmv(u_old, problem_rhs); + + problem_A = A; + problem_A *= tau; + break; + case FIRST_SETUP: + state = SECOND_SETUP; + // FALLTHROUGH + case SECOND_SETUP: + problem_rhs = ell; + A.usmv(-4.0 / 3.0, u_old, problem_rhs); + A.usmv(+1.0 / 3.0, u_old_old, problem_rhs); + + // For fixed tau, we'd only really have to do this once + problem_A = A; + problem_A *= 2.0 / 3.0 * tau; + break; + default: + assert(false); + } + + // ud_old makes a good initial iterate; we could use anything, though + problem_iterate = ud_old; + + for (size_t i = 0; i < dirichletNodes.size(); ++i) + switch (dirichletNodes[i].count()) { + case 0: + continue; + case dim: + problem_iterate[i] = 0; + dirichletFunction.evaluate(time, problem_iterate[i][0]); + break; + case 1: + if (dirichletNodes[i][0]) { + dirichletFunction.evaluate(time, problem_iterate[i][0]); + break; + } + if (dirichletNodes[i][1]) { + problem_iterate[i][1] = 0; + break; + } + assert(false); + default: + assert(false); + } +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>::postProcess( + VectorType const &problem_iterate) { + postProcessCalled = true; + + ud = problem_iterate; + + switch (state) { + case FIRST_SETUP: + u = u_old; + Arithmetic::addProduct(u, tau, ud); + break; + case SECOND_SETUP: + u = 0.0; + Arithmetic::addProduct(u, tau, ud); + Arithmetic::addProduct(u, 2.0, u_old); + Arithmetic::addProduct(u, -.5, u_old_old); + u *= 2.0 / 3.0; + break; + default: + assert(false); + } +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void ImplicitTwoStep<VectorType, MatrixType, FunctionType, + dim>::extractDisplacement(VectorType &displacement) const { + if (!postProcessCalled) + DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); + + displacement = u; +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void ImplicitTwoStep<VectorType, MatrixType, FunctionType, + dim>::extractVelocity(VectorType &velocity) const { + if (!postProcessCalled) + DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); + + velocity = ud; +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * +ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>::clone() { + return new ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>(*this); +} +template <class VectorType, class MatrixType, class FunctionType, int dim> +Newmark<VectorType, MatrixType, FunctionType, dim>::Newmark( + MatrixType const &_A, MatrixType const &_B, VectorType const &_u_initial, + VectorType const &_ud_initial, VectorType const &_udd_initial, + Dune::BitSetVector<dim> const &_dirichletNodes, + FunctionType const &_dirichletFunction) + : A(_A), + B(_B), + u(_u_initial), + ud(_ud_initial), + udd(_udd_initial), + dirichletNodes(_dirichletNodes), + dirichletFunction(_dirichletFunction) {} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void Newmark<VectorType, MatrixType, FunctionType, dim>::nextTimeStep() { + udd_old = udd; + ud_old = ud; + u_old = u; +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void Newmark<VectorType, MatrixType, FunctionType, dim>::setup( + VectorType const &ell, double _tau, double time, VectorType &problem_rhs, + VectorType &problem_iterate, MatrixType &problem_A) { + postProcessCalled = false; + + tau = _tau; + + problem_rhs = ell; + B.usmv(2.0 / tau, ud_old, problem_rhs); + B.usmv(1.0, udd_old, problem_rhs); + A.usmv(-1.0, u_old, problem_rhs); + A.usmv(-tau / 2.0, ud_old, problem_rhs); + + // For fixed tau, we'd only really have to do this once + problem_A = A; + problem_A *= tau / 2.0; + Arithmetic::addProduct(problem_A, 2.0 / tau, B); + + // ud_old makes a good initial iterate; we could use anything, though + problem_iterate = ud_old; + + for (size_t i = 0; i < dirichletNodes.size(); ++i) + switch (dirichletNodes[i].count()) { + case 0: + continue; + case dim: + problem_iterate[i] = 0; + dirichletFunction.evaluate(time, problem_iterate[i][0]); + break; + case 1: + if (dirichletNodes[i][0]) { + dirichletFunction.evaluate(time, problem_iterate[i][0]); + break; + } + if (dirichletNodes[i][1]) { + problem_iterate[i][1] = 0; + break; + } + assert(false); + default: + assert(false); + } +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void Newmark<VectorType, MatrixType, FunctionType, dim>::postProcess( + VectorType const &problem_iterate) { + postProcessCalled = true; + + ud = problem_iterate; + + u = u_old; + Arithmetic::addProduct(u, tau / 2.0, ud); + Arithmetic::addProduct(u, tau / 2.0, ud_old); + + udd = 0; + Arithmetic::addProduct(udd, 2.0 / tau, ud); + Arithmetic::addProduct(udd, -2.0 / tau, ud_old); + Arithmetic::addProduct(udd, -1.0, udd_old); +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void Newmark<VectorType, MatrixType, FunctionType, dim>::extractDisplacement( + VectorType &displacement) const { + if (!postProcessCalled) + DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); + + displacement = u; +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +void Newmark<VectorType, MatrixType, FunctionType, dim>::extractVelocity( + VectorType &velocity) const { + if (!postProcessCalled) + DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); + + velocity = ud; +} + +template <class VectorType, class MatrixType, class FunctionType, int dim> +TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * +Newmark<VectorType, MatrixType, FunctionType, dim>::clone() { + return new Newmark<VectorType, MatrixType, FunctionType, dim>(*this); +} + +#include "timestepping_tmpl.cc" diff --git a/src/timestepping.hh b/src/timestepping.hh new file mode 100644 index 0000000000000000000000000000000000000000..84da56b74f7775a079b6c3bd3dd968e992817a8f --- /dev/null +++ b/src/timestepping.hh @@ -0,0 +1,132 @@ +#ifndef DUNE_TECTONIC_TIMESTEPPING_HH +#define DUNE_TECTONIC_TIMESTEPPING_HH +#include <dune/common/bitsetvector.hh> + +template <class VectorType, class MatrixType, class FunctionType, int dim> +class TimeSteppingScheme { +public: + void virtual nextTimeStep() = 0; + void virtual setup(VectorType const &ell, double _tau, double time, + VectorType &problem_rhs, VectorType &problem_iterate, + MatrixType &problem_A) = 0; + + void virtual postProcess(VectorType const &problem_iterate) = 0; + void virtual extractDisplacement(VectorType &displacement) const = 0; + void virtual extractVelocity(VectorType &velocity) const = 0; + + virtual TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * + clone() = 0; +}; +template <class VectorType, class MatrixType, class FunctionType, int dim> +class ImplicitEuler + : public TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> { +public: + ImplicitEuler(MatrixType const &_A, VectorType const &_u_initial, + VectorType const &_ud_initial, + Dune::BitSetVector<dim> const &_dirichletNodes, + FunctionType const &_dirichletFunction); + + void virtual nextTimeStep(); + void virtual setup(VectorType const &, double, double, VectorType &, + VectorType &, MatrixType &); + void virtual postProcess(VectorType const &); + void virtual extractDisplacement(VectorType &) const; + void virtual extractVelocity(VectorType &) const; + + virtual TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * + clone(); + +private: + MatrixType const &A; + VectorType u; + VectorType ud; + Dune::BitSetVector<dim> const &dirichletNodes; + FunctionType const &dirichletFunction; + + VectorType u_old; + VectorType ud_old; + + double tau; + + bool postProcessCalled = false; +}; +template <class VectorType, class MatrixType, class FunctionType, int dim> +class ImplicitTwoStep + : public TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> { +public: + ImplicitTwoStep(MatrixType const &_A, VectorType const &_u_initial, + VectorType const &_ud_initial, + Dune::BitSetVector<dim> const &_dirichletNodes, + FunctionType const &_dirichletFunction); + + void virtual nextTimeStep(); + void virtual setup(VectorType const &, double, double, VectorType &, + VectorType &, MatrixType &); + void virtual postProcess(VectorType const &); + void virtual extractDisplacement(VectorType &) const; + void virtual extractVelocity(VectorType &) const; + + virtual TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * + clone(); + +private: + MatrixType const &A; + VectorType u; + VectorType ud; + Dune::BitSetVector<dim> const &dirichletNodes; + FunctionType const &dirichletFunction; + + VectorType u_old; + VectorType u_old_old; + VectorType ud_old; + + double tau; + + bool postProcessCalled = false; + + // Handle a lack of information + enum state_type { + NO_SETUP, + FIRST_SETUP, + SECOND_SETUP + }; + state_type state = NO_SETUP; +}; +template <class VectorType, class MatrixType, class FunctionType, int dim> +class Newmark + : public TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> { +public: + Newmark(MatrixType const &_A, MatrixType const &_B, + VectorType const &_u_initial, VectorType const &_ud_initial, + VectorType const &_udd_initial, + Dune::BitSetVector<dim> const &_dirichletNodes, + FunctionType const &_dirichletFunction); + + void virtual nextTimeStep(); + void virtual setup(VectorType const &, double, double, VectorType &, + VectorType &, MatrixType &); + void virtual postProcess(VectorType const &); + void virtual extractDisplacement(VectorType &) const; + void virtual extractVelocity(VectorType &) const; + + virtual TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * + clone(); + +private: + MatrixType const &A; + MatrixType const &B; + VectorType u; + VectorType ud; + VectorType udd; + Dune::BitSetVector<dim> const &dirichletNodes; + FunctionType const &dirichletFunction; + + VectorType u_old; + VectorType ud_old; + VectorType udd_old; + + double tau; + + bool postProcessCalled = false; +}; +#endif diff --git a/src/timestepping.org b/src/timestepping.org deleted file mode 100644 index a234d86ebfd83e909525e6d39aa31b075228550d..0000000000000000000000000000000000000000 --- a/src/timestepping.org +++ /dev/null @@ -1,602 +0,0 @@ -* Preamble -#+name: includes.hh -#+begin_src c++ - #include <dune/common/bitsetvector.hh> -#+end_src -#+name: preamble.cc -#+begin_src c++ - #ifdef HAVE_CONFIG_H - #include "config.h" - #endif - - #include <dune/fufem/arithmetic.hh> - #include "timestepping.hh" -#+end_src -#+name: preamble.tex -#+begin_src latex - \documentclass{scrartcl} - \usepackage{amsmath} - \begin{document} -#+end_src -#+name: virtual_function_declaration -#+begin_src c++ - void virtual nextTimeStep(); - void virtual setup(VectorType const &, double, double, VectorType &, - VectorType &, MatrixType &); - void virtual postProcess(VectorType const &); - void virtual extractDisplacement(VectorType &) const; - void virtual extractVelocity(VectorType &) const; - - virtual TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * - clone(); -#+end_src -#+name: dirichletCondition -#+begin_src c++ - for (size_t i=0; i < dirichletNodes.size(); ++i) - switch (dirichletNodes[i].count()) { - case 0: - continue; - case dim: - problem_iterate[i] = 0; - dirichletFunction.evaluate(time, problem_iterate[i][0]); - break; - case 1: - if (dirichletNodes[i][0]) { - dirichletFunction.evaluate(time, problem_iterate[i][0]); - break; - } - if (dirichletNodes[i][1]) { - problem_iterate[i][1] = 0; - break; - } - assert(false); - default: - assert(false); - } -#+end_src -* Abstract TimeSteppingScheme -#+name: TimeSteppingScheme.hh -#+begin_src c++ - template <class VectorType, class MatrixType, class FunctionType, int dim> - class TimeSteppingScheme - { - public: - void virtual nextTimeStep() = 0; - void virtual - setup(VectorType const &ell, - double _tau, - double time, - VectorType &problem_rhs, - VectorType &problem_iterate, - MatrixType &problem_A) = 0; - - void virtual postProcess(VectorType const &problem_iterate) = 0; - void virtual extractDisplacement(VectorType &displacement) const = 0; - void virtual extractVelocity(VectorType &velocity) const = 0; - - virtual TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * - clone() = 0; - }; -#+end_src -* TimeSteppingScheme: Implicit Euler -#+name: ImplicitEuler.hh -#+begin_src c++ noweb: yes - template <class VectorType, class MatrixType, class FunctionType, int dim> - class ImplicitEuler : public TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> - { - public: - ImplicitEuler(MatrixType const &_A, - VectorType const &_u_initial, - VectorType const &_ud_initial, - Dune::BitSetVector<dim> const &_dirichletNodes, - FunctionType const &_dirichletFunction); - - <<virtual_function_declaration>> - - private: - MatrixType const &A; - VectorType u; - VectorType ud; - Dune::BitSetVector<dim> const &dirichletNodes; - FunctionType const &dirichletFunction; - - VectorType u_old; - VectorType ud_old; - - double tau; - - bool postProcessCalled = false; - }; -#+end_src -#+name: ImplicitEuler.cc -#+begin_src c++ - template <class VectorType, class MatrixType, class FunctionType, int dim> - ImplicitEuler<VectorType, MatrixType, FunctionType, dim>:: - ImplicitEuler(MatrixType const &_A, - VectorType const &_u_initial, - VectorType const &_ud_initial, - Dune::BitSetVector<dim> const &_dirichletNodes, - FunctionType const &_dirichletFunction) - : A(_A), - u(_u_initial), - ud(_ud_initial), - dirichletNodes(_dirichletNodes), - dirichletFunction(_dirichletFunction) - {} - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void ImplicitEuler<VectorType, MatrixType, FunctionType, dim>:: - nextTimeStep() - { - ud_old = ud; - u_old = u; - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void ImplicitEuler<VectorType, MatrixType, FunctionType, dim>:: - setup(VectorType const &ell, - double _tau, - double time, - VectorType &problem_rhs, - VectorType &problem_iterate, - MatrixType &problem_A) - { - postProcessCalled = false; - - tau = _tau; - - problem_rhs = ell; - A.mmv(u_old, problem_rhs); - - // For fixed tau, we'd only really have to do this once - problem_A = A; - problem_A *= tau; - - // ud_old makes a good initial iterate; we could use anything, though - problem_iterate = ud_old; - - <<dirichletCondition>> - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void ImplicitEuler<VectorType, MatrixType, FunctionType, dim>:: - postProcess(VectorType const &problem_iterate) - { - postProcessCalled = true; - - ud = problem_iterate; - - u = u_old; - Arithmetic::addProduct(u, tau, ud); - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void ImplicitEuler<VectorType, MatrixType, FunctionType, dim>:: - extractDisplacement(VectorType &displacement) const - { - if (!postProcessCalled) - DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); - - displacement = u; - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void ImplicitEuler<VectorType, MatrixType, FunctionType, dim>:: - extractVelocity(VectorType &velocity) const - { - if (!postProcessCalled) - DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); - - velocity = ud; - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * - ImplicitEuler<VectorType, MatrixType, FunctionType, dim>:: - clone() { - return new ImplicitEuler<VectorType, MatrixType, FunctionType, dim>(*this); - } -#+end_src -* TimeSteppingScheme: Implicit Two-Step -#+begin_src latex :tangle twostep.tex :noweb yes - \documentclass{scrartcl} - \usepackage{amsmath} - \begin{document} - We start out with - \begin{align} - a(u_1, v - \dot u_1) + j(v) - j(\dot u_1) \ge \ell(v-\dot u_1) - \end{align} - With the two-step implicit scheme - \begin{equation*} - \tau \dot u_1 = \frac 32 u_1 - 2 u_0 + \frac 12 u_{-1} - \end{equation*} - or equivalently - \begin{equation*} - \frac 23 \left( \tau \dot u_1 + 2 u_0 - \frac 12 u_{-1} \right) = u_1 - \end{equation*} - we obtain - \begin{equation*} - \frac 23 \tau a(\dot u_1, v - \dot u_1) + j(v) - j(\dot u_1) \ge \ell(v-\dot u_1) - a\left(\frac 43 u_0 - \frac 13 u_{-1}, v - \dot u_1\right) - \end{equation*} - \end{document} -#+end_src -#+name: ImplicitTwoStep.hh -#+begin_src c++ noweb: yes - template <class VectorType, class MatrixType, class FunctionType, int dim> - class ImplicitTwoStep : public TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> - { - public: - ImplicitTwoStep(MatrixType const &_A, - VectorType const &_u_initial, - VectorType const &_ud_initial, - Dune::BitSetVector<dim> const &_dirichletNodes, - FunctionType const &_dirichletFunction); - - <<virtual_function_declaration>> - - private: - MatrixType const &A; - VectorType u; - VectorType ud; - Dune::BitSetVector<dim> const &dirichletNodes; - FunctionType const &dirichletFunction; - - VectorType u_old; - VectorType u_old_old; - VectorType ud_old; - - double tau; - - bool postProcessCalled = false; - - // Handle a lack of information - enum state_type { NO_SETUP, FIRST_SETUP, SECOND_SETUP }; - state_type state = NO_SETUP; - }; -#+end_src -#+name: ImplicitTwoStep.cc -#+begin_src c++ - template <class VectorType, class MatrixType, class FunctionType, int dim> - ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>:: - ImplicitTwoStep(MatrixType const &_A, - VectorType const &_u_initial, - VectorType const &_ud_initial, - Dune::BitSetVector<dim> const &_dirichletNodes, - FunctionType const &_dirichletFunction) - : A(_A), - u(_u_initial), - ud(_ud_initial), - dirichletNodes(_dirichletNodes), - dirichletFunction(_dirichletFunction) - {} - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>:: - nextTimeStep() - { - u_old_old = u_old; - ud_old = ud; - u_old = u; - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>:: - setup(VectorType const &ell, - double _tau, - double time, - VectorType &problem_rhs, - VectorType &problem_iterate, - MatrixType &problem_A) - { - postProcessCalled = false; - - tau = _tau; - - switch (state) { - // Perform an implicit Euler step since we lack information - case NO_SETUP: - state = FIRST_SETUP; - - problem_rhs = ell; - A.mmv(u_old, problem_rhs); - - problem_A = A; - problem_A *= tau; - break; - case FIRST_SETUP: - state = SECOND_SETUP; - // FALLTHROUGH - case SECOND_SETUP: - problem_rhs = ell; - A.usmv(-4.0/3.0, u_old, problem_rhs); - A.usmv(+1.0/3.0, u_old_old, problem_rhs); - - // For fixed tau, we'd only really have to do this once - problem_A = A; - problem_A *= 2.0/3.0 * tau; - break; - default: - assert(false); - } - - // ud_old makes a good initial iterate; we could use anything, though - problem_iterate = ud_old; - - <<dirichletCondition>> - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>:: - postProcess(VectorType const &problem_iterate) - { - postProcessCalled = true; - - ud = problem_iterate; - - switch (state) { - case FIRST_SETUP: - u = u_old; - Arithmetic::addProduct(u, tau, ud); - break; - case SECOND_SETUP: - u = 0.0; - Arithmetic::addProduct(u, tau, ud); - Arithmetic::addProduct(u, 2.0, u_old); - Arithmetic::addProduct(u, -.5, u_old_old); - u *= 2.0/3.0; - break; - default: - assert(false); - } - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>:: - extractDisplacement(VectorType &displacement) const - { - if (!postProcessCalled) - DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); - - displacement = u; - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>:: - extractVelocity(VectorType &velocity) const - { - if (!postProcessCalled) - DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); - - velocity = ud; - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * - ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>:: - clone() { - return new ImplicitTwoStep<VectorType, MatrixType, FunctionType, dim>(*this); - } -#+end_src -* TimeSteppingScheme: Newmark -#+begin_src latex :tangle newmark.tex :noweb yes - <<preamble.tex>> - \noindent The Newmark scheme in its classical form with $\gamma = 1/2$ - and $\beta = 1/4$ reads - \begin{align} - \label{eq:1} \dot u_1 - &= \dot u_0 + \frac \tau 2 (\ddot u_0 + \ddot u_1 )\\ - \label{eq:2} u_1 - &= u_0 + \tau \dot u_0 + \frac {\tau^2}4 ( \ddot u_0 + \ddot u_1 )\text. - \intertext{We can also write \eqref{eq:1} as} - \label{eq:3} \ddot u_1 - &= \frac 2\tau (\dot u_1 - \dot u_0) - \ddot u_0 - \intertext{so that it yields} - \label{eq:4} u_1 - &= u_0 + \tau \dot u_0 + \frac {\tau^2}4 \ddot u_0 + \frac {\tau^2}4 \left( - \frac 2\tau (\dot u_1 - \dot u_0) - \ddot u_0\right)\\ - &= u_0 + \tau \dot u_0 + \frac \tau 2 (\dot u_1 - \dot u_0)\nonumber\\ - &= u_0 + \frac \tau 2 (\dot u_1 + \dot u_0)\nonumber - \end{align} - in conjunction with \eqref{eq:2}. If we now consider the EVI - \begin{align*} - b(\ddot u_1, v - \dot u_1) + a(u_1, v - \dot u_1) + j(v) - j(\dot u_1) - &\ge \ell (v - \dot u_1) - \intertext{with unknowns $u_1$, $\dot u_1$, and $\ddot u_1$, we first derive} - \frac 2\tau b(\dot u_1, v - \dot u_1) - + a(u_1, v - \dot u_1) + j(v) - j(\dot u_1) - &\ge \ell (v - \dot u_1) + b\left( - \frac 2\tau \dot u_0 + \ddot u_0, v - \dot u_1\right) - \intertext{from \eqref{eq:3} and then} - \frac 2\tau b(\dot u_1, v - \dot u_1) + \frac \tau 2 a(\dot u_1, v - \dot u_1) - + j(v) - j(\dot u_1) - &\ge \ell (v - \dot u_1) + b\left( - \frac 2\tau \dot u_0 + \ddot u_0, v - \dot u_1\right)\\ - &\quad - a\left(u_0 + \frac \tau 2 \dot u_0, v - \dot u_1\right) - \end{align*} - from \eqref{eq:4}. The only unknown is now $\dot u_1$. - \end{document} -#+end_src -#+name: Newmark.hh -#+begin_src c++ noweb: yes - template <class VectorType, class MatrixType, class FunctionType, int dim> - class Newmark : public TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> - { - public: - Newmark(MatrixType const &_A, - MatrixType const &_B, - VectorType const &_u_initial, - VectorType const &_ud_initial, - VectorType const &_udd_initial, - Dune::BitSetVector<dim> const &_dirichletNodes, - FunctionType const &_dirichletFunction); - - <<virtual_function_declaration>> - - private: - MatrixType const &A; - MatrixType const &B; - VectorType u; - VectorType ud; - VectorType udd; - Dune::BitSetVector<dim> const &dirichletNodes; - FunctionType const &dirichletFunction; - - VectorType u_old; - VectorType ud_old; - VectorType udd_old; - - double tau; - - bool postProcessCalled = false; - }; -#+end_src -#+name: Newmark.cc -#+begin_src c++ - template <class VectorType, class MatrixType, class FunctionType, int dim> - Newmark<VectorType, MatrixType, FunctionType, dim>:: - Newmark(MatrixType const &_A, - MatrixType const &_B, - VectorType const &_u_initial, - VectorType const &_ud_initial, - VectorType const &_udd_initial, - Dune::BitSetVector<dim> const &_dirichletNodes, - FunctionType const &_dirichletFunction) - : A(_A), - B(_B), - u(_u_initial), - ud(_ud_initial), - udd(_udd_initial), - dirichletNodes(_dirichletNodes), - dirichletFunction(_dirichletFunction) - {} - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void Newmark<VectorType, MatrixType, FunctionType, dim>:: - nextTimeStep() - { - udd_old = udd; - ud_old = ud; - u_old = u; - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void Newmark<VectorType, MatrixType, FunctionType, dim>:: - setup(VectorType const &ell, - double _tau, - double time, - VectorType &problem_rhs, - VectorType &problem_iterate, - MatrixType &problem_A) - { - postProcessCalled = false; - - tau = _tau; - - problem_rhs = ell; - B.usmv( 2.0/tau, ud_old, problem_rhs); - B.usmv( 1.0, udd_old, problem_rhs); - A.usmv( -1.0, u_old, problem_rhs); - A.usmv(-tau/2.0, ud_old, problem_rhs); - - // For fixed tau, we'd only really have to do this once - problem_A = A; - problem_A *= tau/2.0; - Arithmetic::addProduct(problem_A, 2.0/tau, B); - - // ud_old makes a good initial iterate; we could use anything, though - problem_iterate = ud_old; - - <<dirichletCondition>> - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void Newmark<VectorType, MatrixType, FunctionType, dim>:: - postProcess(VectorType const &problem_iterate) - { - postProcessCalled = true; - - ud = problem_iterate; - - u = u_old; - Arithmetic::addProduct(u, tau/2.0, ud); - Arithmetic::addProduct(u, tau/2.0, ud_old); - - udd = 0; - Arithmetic::addProduct(udd, 2.0/tau, ud); - Arithmetic::addProduct(udd, -2.0/tau, ud_old); - Arithmetic::addProduct(udd, -1.0, udd_old); - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void Newmark<VectorType, MatrixType, FunctionType, dim>:: - extractDisplacement(VectorType &displacement) const - { - if (!postProcessCalled) - DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); - - displacement = u; - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - void Newmark<VectorType, MatrixType, FunctionType, dim>:: - extractVelocity(VectorType &velocity) const - { - if (!postProcessCalled) - DUNE_THROW(Dune::Exception, "It seems you forgot to call postProcess!"); - - velocity = ud; - } - - template <class VectorType, class MatrixType, class FunctionType, int dim> - TimeSteppingScheme<VectorType, MatrixType, FunctionType, dim> * - Newmark<VectorType, MatrixType, FunctionType, dim>:: - clone() { - return new Newmark<VectorType, MatrixType, FunctionType, dim>(*this); - } -#+end_src -* C++ code generation -#+begin_src c++ :tangle timestepping.hh :noweb yes - // GENERATED -- DO NOT MODIFY - #ifndef DUNE_TECTONIC_TIMESTEPPING_HH - #define DUNE_TECTONIC_TIMESTEPPING_HH - <<includes.hh>> - - <<TimeSteppingScheme.hh>> - <<ImplicitEuler.hh>> - <<ImplicitTwoStep.hh>> - <<Newmark.hh>> - #endif -#+end_src -#+begin_src c++ :tangle timestepping.cc :noweb yes - // GENERATED -- DO NOT MODIFY - <<preamble.cc>> - - <<ImplicitEuler.cc>> - <<ImplicitTwoStep.cc>> - <<Newmark.cc>> - - #include "timestepping_tmpl.cc" -#+end_src - -#+begin_src c++ :tangle timestepping_tmpl.cc :noweb yes - // GENERATED -- DO NOT MODIFY - #ifndef DIM - #error DIM unset - #endif - - #include <dune/common/fmatrix.hh> - #include <dune/common/function.hh> - #include <dune/common/fvector.hh> - #include <dune/istl/bcrsmatrix.hh> - #include <dune/istl/bvector.hh> - - 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::VirtualFunction<double, double> FunctionType; - - template class ImplicitEuler<VectorType, MatrixType, FunctionType, DIM>; - template class ImplicitTwoStep<VectorType, MatrixType, FunctionType, DIM>; - template class Newmark<VectorType, MatrixType, FunctionType, DIM>; -#+end_src diff --git a/src/timestepping_tmpl.cc b/src/timestepping_tmpl.cc new file mode 100644 index 0000000000000000000000000000000000000000..3db2ba607cf744dcfedcef563ff836d4b0a2352e --- /dev/null +++ b/src/timestepping_tmpl.cc @@ -0,0 +1,19 @@ +#ifndef DIM +#error DIM unset +#endif + +#include <dune/common/fmatrix.hh> +#include <dune/common/function.hh> +#include <dune/common/fvector.hh> +#include <dune/istl/bcrsmatrix.hh> +#include <dune/istl/bvector.hh> + +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::VirtualFunction<double, double> FunctionType; + +template class ImplicitEuler<VectorType, MatrixType, FunctionType, DIM>; +template class ImplicitTwoStep<VectorType, MatrixType, FunctionType, DIM>; +template class Newmark<VectorType, MatrixType, FunctionType, DIM>;