Newer
Older
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef HAVE_PYTHON
#error Python is required
#endif
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#ifdef HAVE_IPOPT
#undef HAVE_IPOPT
#endif
#ifndef srcdir
#error srcdir unset
#endif
#ifndef DIM
#error DIM unset
#endif
#if !HAVE_ALUGRID
#error ALUGRID is required
#endif
#include <cmath>
#include <exception>
#include <iostream>
#include <boost/format.hpp>
#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/localassemblers/boundarymassassembler.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/boundarypatch.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/iterationsteps/blockgsstep.hh>
#include <dune/solvers/norms/energynorm.hh>
#include <dune/solvers/norms/sumnorm.hh>
#include <dune/solvers/solvers/loopsolver.hh>
#include <dune/solvers/solvers/solver.hh> // Solver::FULL
#include <dune/tnnmg/problem-classes/convexproblem.hh>
#include <dune/tectonic/myblockproblem.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 &velocityDirichletFunction,
Dune::BitSetVector<dims> const &velocityDirichletNodes,
MatrixType const &massMatrix, MatrixType const &stiffnessMatrix,
VectorType const &u_initial, VectorType const &v_initial,
VectorType const &a_initial) {
switch (scheme) {
case Config::ImplicitEuler:
return Dune::make_shared<
ImplicitEuler<VectorType, MatrixType, FunctionType, dims>>(
stiffnessMatrix, u_initial, v_initial, velocityDirichletNodes,
velocityDirichletFunction);
case Config::Newmark:
return Dune::make_shared<
Newmark<VectorType, MatrixType, FunctionType, dims>>(
stiffnessMatrix, massMatrix, u_initial, v_initial, a_initial,
velocityDirichletNodes, velocityDirichletFunction);
case Config::EulerPair:
return Dune::make_shared<
EulerPair<VectorType, MatrixType, FunctionType, dims>>(
stiffnessMatrix, massMatrix, u_initial, v_initial,
velocityDirichletNodes, velocityDirichletFunction);
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,
FrictionData const &fd) {
switch (model) {
case Config::Dieterich:
return Dune::make_shared<
DieterichStateUpdater<SingletonVectorType, VectorType>>(
case Config::Ruina:
return Dune::make_shared<
RuinaStateUpdater<SingletonVectorType, VectorType>>(
Python::start();
Python::run("import sys");
Python::run("sys.path.append('" srcdir "')");
}
double computeCOF(FrictionData const &fd, double V, double log_state) {
double const mu = fd.mu0 + fd.a * std::log(V / fd.V0) +
fd.b * (log_state + std::log(fd.V0 / fd.L));
return (mu > 0) ? mu : 0;
}
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);
using SmallVector = Dune::FieldVector<double, dims>;
using SmallMatrix = Dune::FieldMatrix<double, dims, dims>;
using SmallSingletonMatrix = Dune::FieldMatrix<double, 1, 1>;
using MatrixType = Dune::BCRSMatrix<SmallMatrix>;
using SingletonMatrixType = Dune::BCRSMatrix<SmallSingletonMatrix>;
using VectorType = Dune::BlockVector<SmallVector>;
using SingletonVectorType = Dune::BlockVector<Dune::FieldVector<double, 1>>;
auto const E = parset.get<double>("body.E");
auto const nu = parset.get<double>("body.nu");
// {{{ Set up grid
using GridType =
Dune::ALUGrid<dims, dims, Dune::simplex, Dune::nonconforming>;
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::shared_ptr<GridType> grid;
{
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");
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);
GridView const leafView = grid->leafView();
// }}}
// Set up bases
using P0Basis = P0Basis<GridView, double>;
using P1Basis = P1NodalBasis<GridView, double>;
P0Basis const p0Basis(leafView);
P1Basis const p1Basis(leafView);
Assembler<P0Basis, P0Basis> const p0Assembler(p0Basis, p0Basis);
Assembler<P1Basis, P1Basis> const p1Assembler(p1Basis, p1Basis);
Dune::BitSetVector<dims> velocityDirichletNodes(finestSize, false);
Dune::BitSetVector<dims> noNodes(finestSize, false);
Dune::BitSetVector<1> neumannNodes(finestSize, false);
Dune::BitSetVector<1> frictionalNodes(finestSize, false);
{
Dune::MultipleCodimMultipleGeomTypeMapper<
GridView, Dune::MCMGVertexLayout> const myVertexMapper(leafView);
for (auto it = leafView.begin<dims>(); it != leafView.end<dims>(); ++it) {
assert(it->geometry().corners() == 1);
size_t const id = myVertexMapper.map(*it);
coordinates[id] = it->geometry().corner(0);
auto const &localCoordinates = coordinates[id];
if (localCoordinates[1] == lowerLeft[1]) {
velocityDirichletNodes[id][1] = true;
else if (localCoordinates[1] == upperRight[1])
velocityDirichletNodes[id] = true;
// right face (except for both corners)
else if (localCoordinates[0] == upperRight[0])
;
// left face (except for both corners)
else if (localCoordinates[0] == lowerLeft[0])
// Set up functions for time-dependent boundary conditions
using FunctionType = Dune::VirtualFunction<double, double>;
using FunctionMap = SharedPointerMap<std::string, FunctionType>;
FunctionMap functions;
{
initPython();
Python::import("one-body-sample")
.get("Functions")
.toC<typename FunctionMap::Base>(functions);
}
auto const &velocityDirichletFunction =
functions.get("velocityDirichletCondition");
auto const &neumannFunction = functions.get("neumannCondition");
// Set up normal stress, mass matrix, and gravity functional
double normalStress;
MatrixType massMatrix;
EnergyNorm<MatrixType, VectorType> const massMatrixNorm(massMatrix);
VectorType gravityFunctional;
{
double const gravity = 9.81;
double const density = parset.get<double>("body.density");
{
MassAssembler<GridType, P1Basis::LocalFiniteElement,
P1Basis::LocalFiniteElement,
Dune::ScaledIdentityMatrix<double, dims>> const localMass;
p1Assembler.assembleOperator(localMass, massMatrix);
{
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);
p1Assembler.assembleFunctional(gravityFunctionalAssembler,
gravityFunctional);
FrictionData const frictionData(parset.sub("boundary.friction"),
normalStress);
EnergyNorm<MatrixType, VectorType> const stiffnessMatrixNorm(
stiffnessMatrix);
{
StVenantKirchhoffAssembler<GridType, P1Basis::LocalFiniteElement,
P1Basis::LocalFiniteElement> const
localStiffness(E, nu);
p1Assembler.assembleOperator(localStiffness, stiffnessMatrix);
}
SingletonMatrixType frictionalBoundaryMassMatrix;
EnergyNorm<SingletonMatrixType, SingletonVectorType> const stateEnergyNorm(
frictionalBoundaryMassMatrix);
{
BoundaryPatch<GridView> const frictionalBoundary(leafView,
frictionalNodes);
BoundaryMassAssembler<
GridType, BoundaryPatch<GridView>, P1Basis::LocalFiniteElement,
P1Basis::LocalFiniteElement, SmallSingletonMatrix> const
frictionalBoundaryMassAssembler(frictionalBoundary);
p1Assembler.assembleOperator(frictionalBoundaryMassAssembler,
frictionalBoundaryMassMatrix);
SumNorm<VectorType> const velocityEnergyNorm(1.0, stiffnessMatrixNorm, 1.0,
massMatrixNorm);
auto const nodalIntegrals = assemble_frictional<GridView, SmallVector>(
leafView, p1Assembler, frictionalNodes);
auto myGlobalNonlinearity = assemble_nonlinearity<MatrixType, VectorType>(
frictionalNodes, *nodalIntegrals, frictionData);
// Problem formulation: right-hand side
auto const createRHS = [&](double _time, VectorType &_ell) {
assemble_neumann(leafView, p1Assembler, neumannNodes, _ell,
neumannFunction, _time);
_ell += gravityFunctional;
};
VectorType ell(finestSize);
// {{{ Initial conditions
SingletonVectorType alpha_initial(finestSize);
alpha_initial =
std::log(parset.get<double>("boundary.friction.initial_state"));
VectorType u_initial(finestSize);
u_initial = 0.0;
VectorType v_initial(finestSize);
{
// Prescribe a homogeneous velocity field in the x-direction
// This way, the initial condition for v and the Dirichlet
// condition match up at t=0
v_initial = 0.0;
double v_initial_const;
velocityDirichletFunction.evaluate(0.0, v_initial_const);
for (size_t i = 0; i < v_initial.size(); ++i)
v_initial[i][0] = v_initial_const;
}
VectorType a_initial(finestSize);
a_initial = 0.0;
{
// We solve Au + Ma + Psi(v) = ell, thus Ma = - (Au + Psi(v) - ell)
VectorType problem_rhs_initial(finestSize);
{
problem_rhs_initial = 0.0;
Arithmetic::addProduct(problem_rhs_initial, stiffnessMatrix, u_initial);
myGlobalNonlinearity->updateState(alpha_initial);
// NOTE: We assume differentiability of Psi at v0 here!
myGlobalNonlinearity->addGradient(v_initial, problem_rhs_initial);
createRHS(0.0, ell);
problem_rhs_initial -= ell;
problem_rhs_initial *= -1.0;
}
BlockGSStep<MatrixType, VectorType> accelerationSolverStep(
massMatrix, a_initial, problem_rhs_initial);
accelerationSolverStep.ignoreNodes_ = &noNodes;
LoopSolver<VectorType> accelerationSolver(
&accelerationSolverStep, 100000, // FIXME
1e-12, // FIXME
&massMatrixNorm, Solver::FULL, // FIXME
false); // absolute error
accelerationSolver.solve();
}
auto const solverTolerance = parset.get<double>("solver.tolerance");
MySolver<dims, MatrixType, VectorType, GridType> solverHost(
parset.sub("solver.tnnmg"), refinements, solverTolerance, *grid,
velocityDirichletNodes);
auto multigridStep = solverHost.getSolver();
Solver::VerbosityMode const verbosity =
parset.get<bool>("verbose") ? Solver::FULL : Solver::QUIET;
{
std::fstream coordinateWriter("coordinates", std::fstream::out);
for (size_t i = 0; i < frictionalNodes.size(); ++i)
if (frictionalNodes[i][0])
coordinateWriter << coordinates[i] << std::endl;
coordinateWriter.close();
}
std::fstream stateWriter("states", std::fstream::out);
std::fstream displacementWriter("displacements", std::fstream::out);
std::fstream velocityWriter("velocities", std::fstream::out);
std::fstream coefficientWriter("coefficients", std::fstream::out);
std::fstream iterationWriter("iterations", std::fstream::out);
std::fstream dampingWriter("damping", std::fstream::out);
auto timeSteppingScheme = initTimeStepper(
parset.get<Config::scheme>("timeSteppingScheme"),
velocityDirichletFunction, velocityDirichletNodes, massMatrix,
stiffnessMatrix, u_initial, v_initial, a_initial);
auto stateUpdater = initStateUpdater<SingletonVectorType, VectorType>(
parset.get<Config::state_model>("boundary.friction.state_model"),
auto const timesteps = parset.get<size_t>("timeSteps");
auto const tau = parset.get<double>("endOfTime") / timesteps;
auto const state_fpi_max =
parset.get<size_t>("solver.tnnmg.fixed_point_iterations");
auto const fixedPointTolerance =
parset.get<double>("solver.tnnmg.fixed_point_tolerance");
auto const damping = parset.get<double>("solver.damping");
auto const minimalCorrectionReduction =
parset.get<double>("solver.minimal_correction_reduction");
auto const printProgress = parset.get<bool>("printProgress");
for (size_t run = 1; run <= timesteps; ++run) {
VectorType u;
stateUpdater->nextTimeStep();
timeSteppingScheme->nextTimeStep();
double const time = tau * run;
createRHS(time, ell);
VectorType problem_rhs(finestSize);
VectorType problem_iterate(finestSize);
stateUpdater->setup(tau);
timeSteppingScheme->setup(ell, tau, time, problem_rhs, problem_iterate,
multigridStep, parset.get<size_t>("solver.tnnmg.maxiterations"),
solverTolerance, &velocityEnergyNorm, verbosity,
auto solveVelocityProblem = [&](VectorType &_problem_iterate,
SingletonVectorType const &_alpha) {
using ConvexProblemType = ConvexProblem<
Dune::GlobalNonlinearity<MatrixType, VectorType>, MatrixType>;
// FIXME: Do we really need to pass u here?
ConvexProblemType const myConvexProblem(1.0, problem_AB,
*myGlobalNonlinearity,
problem_rhs, _problem_iterate);
MyBlockProblem<ConvexProblemType> velocityProblem(parset,
myConvexProblem);
multigridStep->setProblem(_problem_iterate, velocityProblem);
velocityProblemSolver.preprocess();
velocityProblemSolver.solve();
iterationCounter = velocityProblemSolver.getResult().iterations;
};
// 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) {
SingletonVectorType computed_state;
stateUpdater->extractState(computed_state);
double const correction = stateEnergyNorm.diff(computed_state, alpha);
if (state_fpi <= 2 // Let the first two steps pass through unchanged
|| correction < minimalCorrectionReduction * lastCorrection) {
dampingWriter << "N ";
Arithmetic::addProduct(alpha, 1.0 - damping, computed_state);
dampingWriter << "Y ";
timeSteppingScheme->postProcess(problem_iterate);
timeSteppingScheme->extractDisplacement(u);
iterationWriter << iterationCounter << " ";
if (printProgress)
(std::cerr << '.').flush();
double const correctionNorm = velocityEnergyNorm.diff(u_saved, u);
if (correctionNorm < fixedPointTolerance) {
if (printProgress)
(std::cerr << '#').flush();
if (state_fpi == state_fpi_max)
DUNE_THROW(Dune::Exception, "FPI failed to converge");
for (size_t i = 0; i < frictionalNodes.size(); ++i)
if (frictionalNodes[i][0]) {
stateWriter << alpha[i][0] << " ";
displacementWriter << u[i][0] << " ";
velocityWriter << v[i][0] << " ";
coefficientWriter << computeCOF(frictionData, v[i].two_norm(),
stateWriter << std::endl;
displacementWriter << std::endl;
velocityWriter << std::endl;
coefficientWriter << std::endl;
iterationWriter << std::endl;
dampingWriter << std::endl;
if (parset.get<bool>("writeVTK")) {
SingletonVectorType vonMisesStress;
Dune::make_shared<BasisGridFunction<P1Basis, VectorType> const>(
p1Basis, u);
VonMisesStressAssembler<GridType> localStressAssembler(
E, nu, gridDisplacement);
p0Assembler.assembleFunctional(localStressAssembler, vonMisesStress);
writeVtk(p1Basis, u, alpha, p0Basis, vonMisesStress,
(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;
stateWriter.close();
displacementWriter.close();
velocityWriter.close();
coefficientWriter.close();
iterationWriter.close();
dampingWriter.close();