Skip to content
Snippets Groups Projects
localfriction.hh 5.78 KiB
Newer Older
#ifndef DUNE_TECTONIC_LOCALFRICTION_HH
#define DUNE_TECTONIC_LOCALFRICTION_HH
Elias Pipping's avatar
Elias Pipping committed
#include <cmath>
Elias Pipping's avatar
Elias Pipping committed
#include <limits>

#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>

Elias Pipping's avatar
Elias Pipping committed
#include <dune/fufem/arithmetic.hh>
#include <dune/solvers/common/interval.hh>
podlesny's avatar
podlesny committed
#include "frictionpotential.hh"
Elias Pipping's avatar
Elias Pipping committed

template <size_t dimension> class LocalFriction {
  virtual ~LocalFriction() {}

  using VectorType = Dune::FieldVector<double, dimension>;
  using MatrixType = Dune::FieldMatrix<double, dimension, dimension>;
podlesny's avatar
podlesny committed
  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;

private:
    VectorType removeNormal(const VectorType& x) {
        VectorType res = x;
        res[0] = 0.0;
        return res;
    }

public:
  template <typename... Args>
  WrappedScalarFriction(Args... args)
      : func_(args...) {}
podlesny's avatar
podlesny committed
  double operator()(VectorType const &x) const override {
    auto tangential_x = removeNormal(x);
    return func_.evaluate(tangential_x.two_norm());
  void updateAlpha(double alpha) override { func_.updateAlpha(alpha); }
Elias Pipping's avatar
Elias Pipping committed

  double regularity(VectorType const &x) const override {
    auto tangential_x = removeNormal(x);
    double const xnorm = tangential_x.two_norm();
    if (xnorm < 0.0)
Elias Pipping's avatar
Elias Pipping committed
      return std::numeric_limits<double>::infinity();

    return func_.regularity(xnorm);
  double coefficientOfFriction(VectorType const &x) const override {
    auto tangential_x = removeNormal(x);
    return func_.coefficientOfFriction(tangential_x.two_norm());
Elias Pipping's avatar
Elias Pipping committed
  // directional subdifferential: at u on the line u + t*v
Elias Pipping's avatar
Elias Pipping committed
  // u and v are assumed to be non-zero
  void directionalSubDiff(VectorType const &x, VectorType const &v,
                          Dune::Solvers::Interval<double> &D) const override {

    auto tangential_x = removeNormal(x);
    double const xnorm = tangential_x.two_norm();
      D[0] = D[1] = func_.differential(0.0) * v.two_norm();
      D[0] = D[1] = func_.differential(xnorm) * (tangential_x * v) / xnorm;
  /** Formula for the derivative:

Elias Pipping's avatar
Elias Pipping committed
      \f{align*}{
      \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}
Elias Pipping's avatar
Elias Pipping committed
     \right)\\
      &= \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
Elias Pipping's avatar
Elias Pipping committed
     \otimes z
      + \frac {H'(|z|)}{|z|} \operatorname{id}
Elias Pipping's avatar
Elias Pipping committed
      \f}
Elias Pipping's avatar
Elias Pipping committed
  */
  void addHessian(VectorType const &x, MatrixType &A) const override {
podlesny's avatar
.  
podlesny committed
    //std::cout << A << std::endl;
    //std::cout << x << std::endl;

podlesny's avatar
podlesny committed
 /*   double const xnorm2 = x.two_norm2();
Elias Pipping's avatar
Elias Pipping committed
    double const xnorm = std::sqrt(xnorm2);
podlesny's avatar
.  
podlesny committed
    //std::cout << xnorm << " " << xnorm2 << std::endl;

    double const H1 = func_.differential(xnorm);
    double const H2 = func_.second_deriv(xnorm);
podlesny's avatar
.  
podlesny committed
    //std::cout << H1 << " " << H2 << std::endl;

    double const tensorweight = (H2 - H1 / xnorm) / xnorm2;
    double const idweight = H1 / xnorm;
podlesny's avatar
.  
podlesny committed
    //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 * x[i] * x[j];
Elias Pipping's avatar
Elias Pipping committed
        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's avatar
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's avatar
podlesny committed
      return;

podlesny's avatar
podlesny committed
    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;
podlesny's avatar
.  
podlesny committed

    //std::cout << A << std::endl;
  void addGradient(VectorType const &x, VectorType &y) const override {
    auto tangential_x = removeNormal(x);
    double const xnorm = tangential_x.two_norm();
    if (std::isinf(func_.regularity(xnorm)))
      Arithmetic::addProduct(y, func_.differential(xnorm) / xnorm, tangential_x);
Elias Pipping's avatar
Elias Pipping committed
  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();
  }
Elias Pipping's avatar
Elias Pipping committed
private:
  ScalarFriction func_;