Newer
Older
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef HAVE_PYTHON
#error Python is required
#endif
#ifdef HAVE_IPOPT
#undef HAVE_IPOPT
#endif
#endif
#ifndef DIM
#error DIM unset
#endif
#if !HAVE_ALUGRID
#error ALUGRID is required
#endif
#include <cmath>
#include <exception>
#include <iostream>
#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>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wignored-qualifiers"
#include <dune/grid/common/mcmgmapper.hh>
#include <dune/grid/utility/structuredgridfactory.hh>
#include <dune/istl/bcrsmatrix.hh>
#include <dune/istl/bvector.hh>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include <dune/fufem/boundarypatch.hh>
#include <dune/fufem/dunepython.hh>
#include <dune/fufem/functions/basisgridfunction.hh>
#include <dune/fufem/functionspacebases/p1nodalbasis.hh>
#include <dune/fufem/sharedpointermap.hh>
#include <dune/solvers/norms/energynorm.hh>
#include <dune/solvers/norms/sumnorm.hh>
#include <dune/solvers/solvers/loopsolver.hh>
#include <dune/tnnmg/nonlinearities/zerononlinearity.hh>
#include <dune/tnnmg/problem-classes/blocknonlineartnnmgproblem.hh>
#include <dune/tnnmg/problem-classes/convexproblem.hh>
#include <dune/tectonic/myblockproblem.hh>
#include <dune/tectonic/globalnonlinearity.hh>
#include "assemblers.hh"
#include "enum_parser.cc"
#include "enum_scheme.cc"
#include "enum_verbosity.cc"
#include "sliding-block-data/mybody.hh"
#include "sliding-block-data/mygeometry.hh"
#include "sliding-block-data/myglobalfrictiondata.hh"
#include "sliding-block-data/mygrid.hh"
Python::start();
Python::run("import sys");
}
int main(int argc, char *argv[]) {
try {
Dune::ParameterTree parset;
Dune::ParameterTreeParser::readINITree(datadir "/parset.cfg", parset);
Dune::ParameterTreeParser::readOptions(argc, argv, parset);
using Grid = Dune::ALUGrid<dims, dims, Dune::simplex, Dune::nonconforming>;
auto grid = constructGrid<Grid>(myGeometry); // FIXME
auto const refinements = parset.get<size_t>("grid.refinements");
grid->globalRefine(refinements);
size_t const fineVertexCount = grid->size(grid->maxLevel(), dims);
using GridView = Grid::LeafGridView;
GridView const leafView = grid->leafView();
// }}}
// Set up myFaces
MyFaces<GridView, MyGeometry> myFaces(leafView, myGeometry);
// Neumann boundary
BoundaryPatch<GridView> const neumannBoundary(leafView);
// Frictional Boundary
BoundaryPatch<GridView> const &frictionalBoundary = myFaces.lower;
Dune::BitSetVector<1> frictionalNodes(fineVertexCount);
frictionalBoundary.getVertices(frictionalNodes);
// Dirichlet Boundary
Dune::BitSetVector<dims> noNodes(fineVertexCount);
Dune::BitSetVector<dims> dirichletNodes(fineVertexCount);
for (size_t i = 0; i < fineVertexCount; ++i) {
dirichletNodes[i][1] = true;
// Set up functions for time-dependent boundary conditions
using Function = Dune::VirtualFunction<double, double>;
using FunctionMap = SharedPointerMap<std::string, Function>;
FunctionMap functions;
{
initPython();
.get("Functions")
.toC<typename FunctionMap::Base>(functions);
}
auto const &velocityDirichletFunction =
functions.get("velocityDirichletCondition"),
&neumannFunction = functions.get("neumannCondition");
using MyAssembler = MyAssembler<GridView, dims>;
using Matrix = MyAssembler::Matrix;
using LocalMatrix = Matrix::block_type;
using Vector = MyAssembler::Vector;
using LocalVector = Vector::block_type;
using ScalarMatrix = MyAssembler::ScalarMatrix;
using ScalarVector = MyAssembler::ScalarVector;
MyAssembler myAssembler(leafView);
MyBody<dims> const body(parset, myGeometry);
Matrix A, C, M;
myAssembler.assembleElasticity(body.getYoungModulus(),
body.getPoissonRatio(), A);
myAssembler.assembleViscosity(body.getShearViscosityField(),
body.getBulkViscosityField(), C);
myAssembler.assembleMass(body.getDensityField(), M);
EnergyNorm<Matrix, Vector> const ANorm(A), MNorm(M);
SumNorm<Vector> const AMNorm(1.0, ANorm, 1.0, MNorm);
ScalarMatrix frictionalBoundaryMass;
myAssembler.assembleFrictionalBoundaryMass(frictionalBoundary,
frictionalBoundaryMass);
EnergyNorm<ScalarMatrix, ScalarVector> const stateEnergyNorm(
frictionalBoundaryMass);
// Assemble forces
Vector gravityFunctional;
myAssembler.assembleBodyForce(body.getGravityField(), gravityFunctional);
// Problem formulation: right-hand side
auto const computeExternalForces = [&](double _relativeTime, Vector &_ell) {
myAssembler.assembleNeumann(neumannBoundary, _ell, neumannFunction,
_relativeTime);
_ell += gravityFunctional;
};
computeExternalForces(0.0, ell);
using LinearFactory = SolverFactory<
dims, BlockNonlinearTNNMGProblem<ConvexProblem<
ZeroNonlinearity<LocalVector, LocalMatrix>, Matrix>>,
ZeroNonlinearity<LocalVector, LocalMatrix> zeroNonlinearity;
// TODO: clean up once generic lambdas arrive
auto const solveLinearProblem = [&](
Dune::BitSetVector<dims> const &_dirichletNodes, Matrix const &_matrix,
Vector const &_rhs, Vector &_x, EnergyNorm<Matrix, Vector> const &_norm,
Dune::ParameterTree const &_localParset) {
LinearFactory factory(parset.sub("solver.tnnmg"), // FIXME
refinements, *grid, _dirichletNodes);
typename LinearFactory::ConvexProblem convexProblem(
1.0, _matrix, zeroNonlinearity, _rhs, _x);
typename LinearFactory::BlockProblem problem(parset, convexProblem);
auto multigridStep = factory.getSolver();
multigridStep->setProblem(_x, problem);
LoopSolver<Vector> solver(
multigridStep, _localParset.get<size_t>("maximumIterations"),
_localParset.get<double>("tolerance"), &_norm,
_localParset.get<Solver::VerbosityMode>("verbosity"),
solver.preprocess();
solver.solve();
};
// Solve the stationary problem
Vector u_initial(fineVertexCount);
u_initial = 0.0;
solveLinearProblem(dirichletNodes, A, ell, u_initial, ANorm,
parset.sub("u0.solver"));
ScalarVector alpha_initial(fineVertexCount);
alpha_initial =
std::log(parset.get<double>("boundary.friction.initialState"));
ScalarVector normalStress(fineVertexCount);
myAssembler.assembleNormalStress(frictionalBoundary, normalStress,
body.getYoungModulus(),
body.getPoissonRatio(), u_initial);
MyGlobalFrictionData<dims> frictionInfo(parset.sub("boundary.friction"),
myGeometry);
auto myGlobalNonlinearity = myAssembler.assembleFrictionNonlinearity(
frictionalBoundary, frictionInfo, normalStress);
myGlobalNonlinearity->updateLogState(alpha_initial);
Vector v_initial(fineVertexCount);
{
// 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
double v_initial_const;
velocityDirichletFunction.evaluate(0.0, v_initial_const);
for (auto &x : v_initial)
x[0] = v_initial_const;
Vector a_initial(fineVertexCount);
Vector accelerationRHS(fineVertexCount);
accelerationRHS = 0.0;
Arithmetic::addProduct(accelerationRHS, A, u_initial);
Arithmetic::addProduct(accelerationRHS, C, v_initial);
// NOTE: We assume differentiability of Psi at v0 here!
myGlobalNonlinearity->addGradient(v_initial, accelerationRHS);
solveLinearProblem(noNodes, M, accelerationRHS, a_initial, MNorm,
parset.sub("a0.solver"));
Vector vertexCoordinates(fineVertexCount);
{
Dune::MultipleCodimMultipleGeomTypeMapper<
GridView, Dune::MCMGVertexLayout> const vertexMapper(leafView);
for (auto it = leafView.begin<dims>(); it != leafView.end<dims>(); ++it) {
auto const geometry = it->geometry();
assert(geometry.corners() == 1);
vertexCoordinates[vertexMapper.map(*it)] = geometry.corner(0);
}
}
FrictionWriter<ScalarVector, Vector> frictionWriter(
vertexCoordinates, frictionalNodes,
[](LocalVector const &x) { return x[0]; });
auto const reportFriction = [&](Vector const &_u, Vector const &_v,
ScalarVector const &_alpha) {
myGlobalNonlinearity->coefficientOfFriction(_v, c);
frictionWriter.writeKinetics(_u, _v);
frictionWriter.writeOther(c, _alpha);
};
reportFriction(u_initial, v_initial, alpha_initial);
MyVTKWriter<typename MyAssembler::VertexBasis,
typename MyAssembler::CellBasis> const
vtkWriter(myAssembler.cellBasis, myAssembler.vertexBasis, "obs");
if (parset.get<bool>("io.writeVTK")) {
ScalarVector stress;
myAssembler.assembleVonMisesStress(
body.getYoungModulus(), body.getPoissonRatio(), u_initial, stress);
vtkWriter.write(0, u_initial, v_initial, alpha_initial, stress);
}
using NonlinearFactory =
SolverFactory<dims, MyBlockProblem<ConvexProblem<
GlobalNonlinearity<Matrix, Vector>, Matrix>>,
Grid>;
NonlinearFactory factory(parset.sub("solver.tnnmg"), refinements, *grid,
auto multigridStep = factory.getSolver();
std::fstream iterationWriter("iterations", std::fstream::out),
relaxationWriter("relaxation", std::fstream::out);
auto timeSteppingScheme =
initTimeStepper(parset.get<Config::scheme>("timeSteps.scheme"),
velocityDirichletFunction, dirichletNodes, M, A, C,
u_initial, v_initial, a_initial);
auto stateUpdater = initStateUpdater<ScalarVector, Vector>(
parset.get<Config::stateModel>("boundary.friction.stateModel"),
alpha_initial, frictionalNodes,
parset.get<double>("boundary.friction.L"));
Vector v_m(fineVertexCount);
ScalarVector alpha(fineVertexCount);
auto const timeSteps = parset.get<size_t>("timeSteps.number"),
maximumStateFPI = parset.get<size_t>("v.fpi.maximumIterations"),
maximumIterations =
parset.get<size_t>("v.solver.maximumIterations");
auto const tau = parset.get<double>("problem.finalTime") / timeSteps,
tolerance = parset.get<double>("v.solver.tolerance"),
fixedPointTolerance = parset.get<double>("v.fpi.tolerance"),
relaxation = parset.get<double>("v.fpi.relaxation"),
requiredReduction =
parset.get<double>("v.fpi.requiredReduction");
auto const printProgress = parset.get<bool>("io.printProgress");
auto const verbosity =
parset.get<Solver::VerbosityMode>("v.solver.verbosity");
for (size_t timeStep = 1; timeStep <= timeSteps; ++timeStep) {
std::cout << std::setw(7) << timeStep << " " << std::flush;
stateUpdater->nextTimeStep();
timeSteppingScheme->nextTimeStep();
auto const relativeTime = double(timeStep) / double(timeSteps);
computeExternalForces(relativeTime, ell);
Matrix velocityMatrix;
Vector velocityRHS(fineVertexCount);
Vector velocityIterate(fineVertexCount);
timeSteppingScheme->setup(ell, tau, relativeTime, velocityRHS,
velocityIterate, velocityMatrix);
LoopSolver<Vector> velocityProblemSolver(multigridStep, maximumIterations,
tolerance, &AMNorm, verbosity,
false); // absolute error
auto solveVelocityProblem = [&](Vector &_velocityIterate,
myGlobalNonlinearity->updateLogState(_alpha);
// NIT: Do we really need to pass u here?
typename NonlinearFactory::ConvexProblem convexProblem(
1.0, velocityMatrix, *myGlobalNonlinearity, velocityRHS,
_velocityIterate);
typename NonlinearFactory::BlockProblem velocityProblem(parset,
convexProblem);
multigridStep->setProblem(_velocityIterate, velocityProblem);
velocityProblemSolver.preprocess();
velocityProblemSolver.solve();
iterationCounter = velocityProblemSolver.getResult().iterations;
for (size_t stateFPI = 1; stateFPI <= maximumStateFPI; ++stateFPI) {
timeSteppingScheme->extractOldVelocity(v_m);
v_m *= 0.5;
Arithmetic::addProduct(v_m, 0.5, v);
stateUpdater->solve(v_m);
stateUpdater->extractLogState(alpha);
relaxationWriter << "N ";
else {
double const stateCorrection =
stateEnergyNorm.diff(alpha, alpha_saved);
if (stateFPI <= 2 // lastStateCorrection is only set for stateFPI > 2
or stateCorrection < requiredReduction * lastStateCorrection)
else {
alpha *= (1.0 - relaxation);
Arithmetic::addProduct(alpha, relaxation, alpha_saved);
solveVelocityProblem(velocityIterate, alpha);
timeSteppingScheme->postProcess(velocityIterate);
timeSteppingScheme->extractDisplacement(u);
iterationWriter << iterationCounter << " ";
double const velocityCorrection = AMNorm.diff(v_saved, v);
if (velocityCorrection < fixedPointTolerance)
DUNE_THROW(Dune::Exception, "FPI failed to converge");
reportFriction(u, v, alpha);
iterationWriter << std::endl;
myAssembler.assembleVonMisesStress(body.getYoungModulus(),
body.getPoissonRatio(), u, stress);
vtkWriter.write(timeStep, u, v, alpha, stress);
iterationWriter.close();