From 5b9bcd3fdadd3d1694aae0ebf3cf498c32b89938 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Wed, 5 Jul 2023 19:19:18 +0200
Subject: [PATCH] [ci-skip] Add jacobian and hessian (still buggy?)

---
 src/mesh/MeshSmootherEscobar.cpp | 149 ++++++++++++++++++++++++++-----
 1 file changed, 127 insertions(+), 22 deletions(-)

diff --git a/src/mesh/MeshSmootherEscobar.cpp b/src/mesh/MeshSmootherEscobar.cpp
index 793153c0a..bca86deec 100644
--- a/src/mesh/MeshSmootherEscobar.cpp
+++ b/src/mesh/MeshSmootherEscobar.cpp
@@ -2,7 +2,6 @@
 
 #include <algebra/TinyMatrix.hpp>
 #include <algebra/TinyVector.hpp>
-#include <geometry/TriangleTransformation.hpp>
 #include <language/utils/InterpolateItemValue.hpp>
 #include <mesh/Connectivity.hpp>
 #include <mesh/ItemValueUtils.hpp>
@@ -220,53 +219,157 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar
       constexpr double eps = 1E-15;
       quality.fill(2);
 
-      auto f_inner = [=](const NodeId node_id, const TinyVector<Dimension>& x) -> double {
+      auto f_inner = [=](const NodeId node_id, TinyVector<Dimension>& x) -> double {
         auto cell_list           = node_to_cell_matrix[node_id];
         auto node_number_in_cell = node_number_in_their_cells[node_id];
 
         const double alpha = 2 * std::acos(-1) / cell_list.size();
-        const TinyMatrix<Dimension> W{1, std::cos(alpha), 0, std::sin(alpha)};
+        const TinyMatrix<Dimension> W{1, std::cos(alpha),   //
+                                      0, std::sin(alpha)};
 
         const TinyMatrix<Dimension> inv_W = inverse(W);
 
-        SmallArray<TinyMatrix<Dimension>> S(cell_list.size());
+        std::array<TinyMatrix<Dimension>, Dimension> S_gradient =
+          {TinyMatrix<Dimension>{-1, -1. / std::sin(alpha) + 1. / std::tan(alpha),   //
+                                 +0, +0},                                            //
+           TinyMatrix<Dimension>{+0, +0,                                             //
+                                 -1, -1. / std::sin(alpha) + 1. / std::tan(alpha)}};
+
+        SmallArray<TinyMatrix<Dimension>> S_list(cell_list.size());
         for (size_t i_cell = 0; i_cell < cell_list.size(); ++i_cell) {
           const size_t i_cell_node   = node_number_in_cell[i_cell];
           auto cell_node_list        = cell_to_node_matrix[cell_list[i_cell]];
           const size_t cell_nb_nodes = cell_node_list.size();
 
-          TriangleTransformation<Dimension> T(x,   //
-                                              xr[cell_node_list[(i_cell_node + 1) % cell_nb_nodes]],
-                                              xr[cell_node_list[(i_cell_node + cell_nb_nodes - 1) % cell_nb_nodes]]);
-          S[i_cell] = T.jacobian() * inv_W;
+          const TinyVector a = xr[cell_node_list[(i_cell_node + 1) % cell_nb_nodes]];
+          const TinyVector b = xr[cell_node_list[(i_cell_node + cell_nb_nodes - 1) % cell_nb_nodes]];
+
+          const TinyMatrix<Dimension> A{a[0] - x[0], b[0] - x[0],   //
+                                        a[1] - x[1], b[1] - x[1]};
+
+          S_list[i_cell] = A * inv_W;
         }
 
-        SmallArray<double> sigma(S.size());
-        for (size_t j = 0; j < S.size(); ++j) {
-          sigma[j] = det(S[j]);
+        SmallArray<double> sigma_list(S_list.size());
+        for (size_t i_cell = 0; i_cell < S_list.size(); ++i_cell) {
+          sigma_list[i_cell] = det(S_list[i_cell]);
         }
 
-        const double sigma_min = min(sigma);
+        const double sigma_min = min(sigma_list);
 
         const double delta =
           (sigma_min < eps) ? std::max(std::sqrt(eps * (eps - sigma_min)), std::sqrt(eps) * std::abs(sigma_min)) : 0;
 
-        double f = 0;
-        for (size_t j = 0; j < S.size(); ++j) {
-          const TinyMatrix<Dimension> Sigma = sigma[j] * inverse(S[j]);
+        auto frobenius = [](const TinyMatrix<Dimension>& M) { return std::sqrt(trace(transpose(M) * M)); };
+
+        // TinyVector<Dimension> f_gradient = zero;
+        // TinyMatrix<Dimension> f_hessian  = zero;
+
+        double final_f = 0;
+
+        for (size_t i_iter = 0; i_iter < 15; ++i_iter) {
+          SmallArray<TinyMatrix<Dimension>> S_list(cell_list.size());
+          for (size_t i_cell = 0; i_cell < cell_list.size(); ++i_cell) {
+            const size_t i_cell_node   = node_number_in_cell[i_cell];
+            auto cell_node_list        = cell_to_node_matrix[cell_list[i_cell]];
+            const size_t cell_nb_nodes = cell_node_list.size();
+
+            const TinyVector a = xr[cell_node_list[(i_cell_node + 1) % cell_nb_nodes]];
+            const TinyVector b = xr[cell_node_list[(i_cell_node + cell_nb_nodes - 1) % cell_nb_nodes]];
+
+            const TinyMatrix<Dimension> A{a[0] - x[0], b[0] - x[0],   //
+                                          a[1] - x[1], b[1] - x[1]};
+
+            S_list[i_cell] = A * inv_W;
+          }
+
+          SmallArray<double> sigma_list(S_list.size());
+          for (size_t i_cell = 0; i_cell < S_list.size(); ++i_cell) {
+            sigma_list[i_cell] = det(S_list[i_cell]);
+          }
+
+          double f                         = 0;
+          TinyVector<Dimension> f_gradient = zero;
+          TinyMatrix<Dimension> f_hessian  = zero;
+
+          for (size_t i_cell = 0; i_cell < S_list.size(); ++i_cell) {
+            const double sigma            = sigma_list[i_cell];
+            const TinyMatrix<Dimension> S = S_list[i_cell];
+
+            const TinyMatrix<Dimension> Sigma = sigma * inverse(S);
+
+            const double S_norm      = frobenius(S);
+            const double Sigma_norm  = frobenius(Sigma);
+            const double S_norm2     = S_norm * S_norm;
+            const double Sigma_norm2 = Sigma_norm * Sigma_norm;
+
+            const double h = sigma + std::sqrt(sigma * sigma + 4 * delta * delta);
+
+            const double f_jr = S_norm * Sigma_norm / h;
+
+            TinyVector<Dimension> sigma_gradient{trace(Sigma * S_gradient[0]),   //
+                                                 trace(Sigma * S_gradient[1])};
+
+            const std::array<TinyMatrix<Dimension>, Dimension>   //
+              Sigma_gradient{sigma_gradient[0] * inverse(S) - Sigma * S_gradient[0] * Sigma,
+                             sigma_gradient[1] * inverse(S) - Sigma * S_gradient[1] * Sigma};
+
+            // TinyVector<Dimension> h_gradient = h / (h - sigma_list[i_cell]) * sigma_gradient;
+
+            TinyVector<Dimension> g{trace(transpose(S) * S_gradient[0]) / S_norm2                   //
+                                      + trace(transpose(Sigma) * Sigma_gradient[0]) / Sigma_norm2   //
+                                      - trace(Sigma * S_gradient[0]) / (h - sigma),
+                                    //
+                                    trace(transpose(S) * S_gradient[1]) / S_norm2                   //
+                                      + trace(transpose(Sigma) * Sigma_gradient[1]) / Sigma_norm2   //
+                                      - trace(Sigma * S_gradient[1]) / (h - sigma)};
+
+            const TinyVector<Dimension> f_jr_gradient = f_jr * g;
+            TinyMatrix<Dimension> f_jr_hessian        = zero;
+            for (size_t i = 0; i < Dimension; ++i) {
+              for (size_t j = 0; j < Dimension; ++j) {
+                f_jr_hessian(i, j) =                                           //
+                  (trace(transpose(S_gradient[j]) * S_gradient[i]) / S_norm2   //
+                   - 2 * trace(transpose(S) * S_gradient[j]) * trace(transpose(S) * S_gradient[i]) /
+                       (S_norm2 * S_norm2)                                                   //
+                                                                                             //
+                   + trace(transpose(Sigma_gradient[j]) * Sigma_gradient[i]) / Sigma_norm2   // + 0
+                   - 2 * trace(transpose(Sigma) * Sigma_gradient[j]) * trace(transpose(Sigma) * Sigma_gradient[i]) /
+                       (Sigma_norm2 * Sigma_norm2)                                                             //
+                                                                                                               //
+                   - 2 * trace(Sigma_gradient[j] * S_gradient[i]) / (h - sigma)                                //
+                   + 2 * trace(Sigma * S_gradient[i]) * sigma / (std::pow(h - sigma, 3)) * sigma_gradient[j]   //
+                   + g[j] * g[i]) *
+                  f_jr;
+              }
+            }
+
+            f += f_jr;
+            f_gradient += f_jr_gradient;
+            f_hessian += f_jr_hessian;
+          }
+
+          std::cout << "f = " << f << '\n';
+          std::cout << "grad(f) = " << f_gradient << '\n';
+          std::cout << "hess(f) = " << f_hessian << " | hess(f)^T -hess(f) = " << transpose(f_hessian) - f_hessian
+                    << '\n';
+
+          std::cout << "inv(H)         = " << inverse(f_hessian) << '\n';
+          std::cout << "inv(H)*grad(f) = " << inverse(f_hessian) * f_gradient << '\n';
 
-          const double Sj_norm    = std::sqrt(trace(transpose(S[j]) * S[j]));
-          const double Sigma_norm = std::sqrt(trace(transpose(Sigma) * Sigma));
+          std::cout << "x = " << x << " -> " << x - inverse(f_hessian) * f_gradient << '\n';
 
-          f += Sj_norm * Sigma_norm / (sigma[j] + std::sqrt(sigma[j] * sigma[j] + 4 * delta * delta));
+          x -= inverse(f_hessian) * f_gradient;
+
+          final_f = f;
         }
-        return f;
+        return final_f;
       };
 
       parallel_for(
         connectivity.numberOfNodes(), PUGS_LAMBDA(NodeId node_id) {
-          auto cell_list           = node_to_cell_matrix[node_id];
-          auto node_number_in_cell = node_number_in_their_cells[node_id];
+          // auto cell_list           = node_to_cell_matrix[node_id];
+          // auto node_number_in_cell = node_number_in_their_cells[node_id];
 
           if (is_boundary_node[node_id]) {
             quality[node_id] = 1;
@@ -274,7 +377,9 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar
             TinyVector x     = xr[node_id];
             quality[node_id] = f_inner(node_id, x);
 
-            TinyMatrix<Dimension> B = identity;
+            std::exit(0);
+
+            // TinyMatrix<Dimension> B = identity;
           }
         });
 
-- 
GitLab