Newer
Older
#ifndef DUNE_TECTONIC_LOCALFRICTION_HH
#define DUNE_TECTONIC_LOCALFRICTION_HH
#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>
#include <dune/solvers/common/interval.hh>
template <size_t dimension> class LocalFriction {
using VectorType = Dune::FieldVector<double, dimension>;
using MatrixType = Dune::FieldMatrix<double, dimension, dimension>;
double virtual operator()(VectorType const &x) const = 0;
void virtual updateAlpha(double alpha) = 0;
double virtual regularity(VectorType const &x) const = 0;
double virtual coefficientOfFriction(VectorType const &x) const = 0;
void virtual directionalSubDiff(VectorType const &x, VectorType const &v,
Dune::Solvers::Interval<double> &D) const = 0;
void virtual addHessian(VectorType const &x, MatrixType &A) const = 0;
void virtual addGradient(VectorType const &x, VectorType &y) const = 0;
void virtual directionalDomain(
VectorType const &, VectorType const &,
Dune::Solvers::Interval<double> &dom) const = 0;
};
template <size_t dimension, class ScalarFriction>
class WrappedScalarFriction : public LocalFriction<dimension> {
using VectorType = typename LocalFriction<dimension>::VectorType;
using MatrixType = typename LocalFriction<dimension>::MatrixType;
podlesny
committed
private:
VectorType removeNormal(const VectorType& x) {
VectorType res = x;
res[0] = 0.0;
return res;
}
public:
template <typename... Args>
WrappedScalarFriction(Args... args)
: func_(args...) {}
double operator()(VectorType const &x) const override {
podlesny
committed
auto tangential_x = removeNormal(x);
return func_.evaluate(tangential_x.two_norm());
void updateAlpha(double alpha) override { func_.updateAlpha(alpha); }
double regularity(VectorType const &x) const override {
podlesny
committed
auto tangential_x = removeNormal(x);
double const xnorm = tangential_x.two_norm();
double coefficientOfFriction(VectorType const &x) const override {
podlesny
committed
auto tangential_x = removeNormal(x);
return func_.coefficientOfFriction(tangential_x.two_norm());
// directional subdifferential: at u on the line u + t*v
void directionalSubDiff(VectorType const &x, VectorType const &v,
Dune::Solvers::Interval<double> &D) const override {
podlesny
committed
auto tangential_x = removeNormal(x);
double const xnorm = tangential_x.two_norm();
D[0] = D[1] = func_.differential(0.0) * v.two_norm();
podlesny
committed
D[0] = D[1] = func_.differential(xnorm) * (tangential_x * v) / xnorm;
/** Formula for the derivative:
\frac {d^2}{dz^2} H(|z|)
&= \frac d{dz} \left( H'(|z|) \otimes \frac z{|z|} \right)\\
&= H''(|z|) \frac z{|z|} \otimes \frac z{|z|}
+ H'(|z|) \left( \frac {|z| \operatorname{id} - z \otimes z/|z|}{|z|^2}
&= \frac {H''(|z|)}{|z|^2} z \otimes z
+ \frac {H'(|z|)}{|z|} \operatorname{id}
- \frac {H'(|z|)}{|z|^3} z \otimes z\\
&= \left( \frac {H''(|z|)}{|z|^2} - \frac {H'(|z|)}{|z|^3} \right) z
+ \frac {H'(|z|)}{|z|} \operatorname{id}
void addHessian(VectorType const &x, MatrixType &A) const override {
double const H1 = func_.differential(xnorm);
double const H2 = func_.second_deriv(xnorm);
double const tensorweight = (H2 - H1 / xnorm) / xnorm2;
double const idweight = H1 / xnorm;
for (size_t i = 0; i < dimension; ++i)
for (size_t j = 0; j < i; ++j) {
double const entry = tensorweight * x[i] * x[j];
A[i][j] += entry;
A[j][i] += entry;
}
for (size_t k = 0; k < dimension; ++k) {
double const entry = tensorweight * x[k] * x[k];
A[k][k] += entry + idweight;
podlesny
committed
auto tangential_x = removeNormal(x);
const double xnorm = tangential_x.two_norm();
if (std::isinf(func_.regularity(xnorm)) or xnorm<=0.0)
podlesny
committed
VectorType y = tangential_x;
y /= xnorm;
double const H1 = func_.differential(xnorm);
double const H2 = func_.second_deriv(xnorm);
double const tensorweight = (H2 - H1 / xnorm);
double const idweight = H1 / xnorm;
//std::cout << tensorweight << " " << idweight << std::endl;
for (size_t i = 0; i < dimension; ++i)
for (size_t j = 0; j < i; ++j) {
double const entry = tensorweight * y[i] * y[j];
A[i][j] += entry;
A[j][i] += entry;
}
for (size_t k = 0; k < dimension; ++k) {
double const entry = tensorweight * y[k] * y[k];
A[k][k] += entry + idweight;
void addGradient(VectorType const &x, VectorType &y) const override {
podlesny
committed
auto tangential_x = removeNormal(x);
double const xnorm = tangential_x.two_norm();
if (std::isinf(func_.regularity(xnorm)))
podlesny
committed
Arithmetic::addProduct(y, func_.differential(xnorm) / xnorm, tangential_x);
void directionalDomain(VectorType const &, VectorType const &,
Dune::Solvers::Interval<double> &dom) const override {
dom[0] = -std::numeric_limits<double>::max();
dom[1] = std::numeric_limits<double>::max();
}