From cd11ade9ed089f64caa7cf76b9f7a66f1cf53150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com> Date: Fri, 28 Jul 2023 19:24:07 +0200 Subject: [PATCH] Begin EMC algorithms [ci-skip] Debugging still in progress --- src/mesh/MeshSmootherEscobar.cpp | 395 ++++++++++++++++++++++++++----- 1 file changed, 333 insertions(+), 62 deletions(-) diff --git a/src/mesh/MeshSmootherEscobar.cpp b/src/mesh/MeshSmootherEscobar.cpp index 412f459b1..eb54ae8fd 100644 --- a/src/mesh/MeshSmootherEscobar.cpp +++ b/src/mesh/MeshSmootherEscobar.cpp @@ -460,6 +460,8 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar void _getNewPositions(const NodeValue<const Rd>& old_xr, NodeValue<Rd>& new_xr) const { + constexpr bool multi_connection = true; + const ConnectivityType& connectivity = m_given_mesh.connectivity(); auto is_boundary_node = connectivity.isBoundaryNode(); @@ -478,6 +480,8 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar quality.fill(2); auto smooth = [=](const NodeId node_id, TinyVector<Dimension>& x) -> double { + const bool print = (node_id == 4); + auto cell_list = node_to_cell_matrix[node_id]; auto node_number_in_cell = node_number_in_their_cells[node_id]; @@ -492,42 +496,30 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar const TinyMatrix<Dimension> inv_W = inverse(W); - std::array<TinyMatrix<Dimension>, Dimension> S_gradient = - {TinyMatrix<Dimension>{-1, -inv_sin_alpha + inv_tan_alpha, // - +0, +0}, // - TinyMatrix<Dimension>{+0, +0, // - -1, -inv_sin_alpha + inv_tan_alpha}}; + std::array<TinyMatrix<Dimension>, Dimension> // + S_gradient = {TinyMatrix<Dimension>{-1, -1, // + +0, +0}, + TinyMatrix<Dimension>{+inv_tan_alpha, +inv_tan_alpha, // + -inv_sin_alpha, -inv_sin_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(); - - const TinyVector a = old_xr[cell_node_list[(i_cell_node + 1) % cell_nb_nodes]]; - const TinyVector b = old_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 sigma_min = min(sigma_list); - double delta = - (sigma_min < eps) ? std::max(std::sqrt(eps * (eps - sigma_min)), std::sqrt(eps) * std::abs(sigma_min)) : 0; + double sigma_min = std::numeric_limits<double>::max(); + double delta = 0; auto frobenius = [](const TinyMatrix<Dimension>& M) { return std::sqrt(trace(transpose(M) * M)); }; double final_f = 0; - for (size_t i_iter = 0; i_iter < 200; ++i_iter) { + std::cout.precision(15); + + for (size_t i_iter = 0; i_iter < 1; ++i_iter) { + if (print) { + std::cout << "------------------------------\n"; + std::cout << "iter = " << i_iter << '\n'; + std::cout << "x = " << x << '\n'; + } + double f = 0; TinyVector<Dimension> f_gradient = zero; TinyMatrix<Dimension> f_hessian = zero; @@ -545,6 +537,15 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar a[1] - x[1], b[1] - x[1]}; S_list[i_cell] = A * inv_W; + + if (print) { + std::cout << "--- S --- cell = " << i_cell << " (" << node_to_cell_matrix[node_id][i_cell] << ")\n"; + std::cout << "a = " << a << '\n'; + std::cout << "b = " << b << '\n'; + std::cout << "x = " << x << '\n'; + std::cout << "A = " << A << '\n'; + std::cout << "S = " << S_list[i_cell] << '\n'; + } } SmallArray<double> sigma_list(S_list.size()); @@ -554,18 +555,102 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar { double current_sigma_min = min(sigma_list); + + if constexpr (multi_connection) { + size_t nb_medium_range_simplices = 0; + for (size_t i_cell = 0; i_cell < cell_list.size(); ++i_cell) { + const CellId cell_id = cell_list[i_cell]; + nb_medium_range_simplices += 2 * (cell_to_node_matrix[cell_id].size() - 3); + } + + if (nb_medium_range_simplices > 0) { + SmallArray<double> medium_range_sigma_list(nb_medium_range_simplices); + + for (size_t i_cell = 0; i_cell < cell_list.size(); ++i_cell) { + const CellId cell_id = cell_list[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 double mr_alpha = 2 * std::acos(-1) / ((cell_nb_nodes - 2) * (cell_list.size())); + const double mr_sin_alpha = std::sin(mr_alpha); + const double mr_cos_alpha = std::cos(mr_alpha); + + const TinyMatrix<Dimension> mr_W{1, mr_cos_alpha, // + 0, mr_sin_alpha}; + + const TinyMatrix mr_inv_W = inverse(mr_W); + + if (print) { + std::cout << "MC === i_cell = " << i_cell << '\n'; + } + + { // first simplex + const TinyVector a = old_xr[cell_node_list[(i_cell_node + 1) % cell_nb_nodes]]; + const TinyVector b = old_xr[cell_node_list[(i_cell_node + 2) % cell_nb_nodes]]; + + const TinyMatrix<Dimension> mr_A{a[0] - x[0], b[0] - x[0], // + a[1] - x[1], b[1] - x[1]}; + + const TinyMatrix mr_S = mr_A * mr_inv_W; + const double mr_sigma = det(mr_S); + if (mr_sigma < current_sigma_min) { + current_sigma_min = mr_sigma; + } + + if (print) { + std::cout << "MC triangle 1 ===\n"; + std::cout << "MC a = " << a << '\n'; + std::cout << "MC b = " << b << '\n'; + std::cout << "MC x = " << x << '\n'; + } + } + + { // second simplex + const TinyVector a = old_xr[cell_node_list[(i_cell_node + cell_nb_nodes - 2) % cell_nb_nodes]]; + const TinyVector b = old_xr[cell_node_list[(i_cell_node + cell_nb_nodes - 1) % cell_nb_nodes]]; + + const TinyMatrix<Dimension> mr_A{a[0] - x[0], b[0] - x[0], // + a[1] - x[1], b[1] - x[1]}; + + const TinyMatrix mr_S = mr_A * mr_inv_W; + const double mr_sigma = det(mr_S); + if (mr_sigma < current_sigma_min) { + current_sigma_min = mr_sigma; + } + + if (print) { + std::cout << "MC triangle 2 ===\n"; + std::cout << "MC a = " << a << '\n'; + std::cout << "MC b = " << b << '\n'; + std::cout << "MC x = " << x << '\n'; + } + } + } + } + } + if (current_sigma_min < sigma_min) { sigma_min = current_sigma_min; delta = (sigma_min < eps) ? std::max(std::sqrt(eps * (eps - sigma_min)), std::sqrt(eps) * std::abs(sigma_min)) : 0; } - } - 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]; + if (print) { + std::cout << " ==== \n"; + std::cout << "delta = " << delta << '\n'; + } + } + auto escobarSSigma = [&frobenius, delta, // + // + &print, &node_to_cell_matrix, + &node_id](const double sigma, const TinyMatrix<Dimension>& S, + const TinyVector<Dimension>& sigma_gradient, + const std::array<TinyMatrix<Dimension>, Dimension>& S_gradient, + const std::array<TinyMatrix<Dimension>, Dimension>& Sigma_gradient, double& f, + TinyVector<Dimension>& f_gradient, TinyMatrix<Dimension>& f_hessian) { const TinyMatrix<Dimension> Sigma = [&S] { TinyMatrix<Dimension> transposed_comS; for (size_t i = 0; i < Dimension; ++i) { @@ -585,15 +670,6 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar 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{TinyMatrix<Dimension>{0, inv_sin_alpha - inv_tan_alpha, // - 0, -1}, - TinyMatrix<Dimension>{-inv_sin_alpha + inv_tan_alpha, 0, // - 1, 0}}; - 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), @@ -603,7 +679,8 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar - trace(Sigma * S_gradient[1]) / (h - sigma)}; const TinyVector<Dimension> f_jr_gradient = f_jr * g; - TinyMatrix<Dimension> f_jr_hessian = zero; + + 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) = // @@ -615,20 +692,189 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar - 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] // + - trace(Sigma_gradient[j] * S_gradient[i]) / (h - sigma) // + + sigma / (std::pow(h - sigma, 3)) * sigma_gradient[i] * sigma_gradient[j] // + g[j] * g[i]) * f_jr; } } + if (print) { + std::cout << "S = " << S << '\n'; + std::cout << "Sigma = " << Sigma << '\n'; + + std::cout << "normS = " << S_norm << '\n'; + std::cout << "normSigma = " << Sigma_norm << '\n'; + + std::cout << "sigma = " << sigma << '\n'; + std::cout << "f_jr = " << f_jr << '\n'; + std::cout << "g = " << g << '\n'; + std::cout << "grad_f_jr = " << f_jr_gradient << '\n'; + std::cout << "hess_f_jr = " << f_jr_hessian << '\n'; + } + f += f_jr; f_gradient += f_jr_gradient; f_hessian += f_jr_hessian; + }; + + auto escobar = escobarSSigma; + + for (size_t i_cell = 0; i_cell < S_list.size(); ++i_cell) { + if (print) { + std::cout << "------ cell = " << i_cell << '\n'; + } + + const double sigma = sigma_list[i_cell]; + const TinyMatrix<Dimension> S = S_list[i_cell]; + + const TinyMatrix<Dimension> Sigma = [&S] { + TinyMatrix<Dimension> transposed_comS; + for (size_t i = 0; i < Dimension; ++i) { + for (size_t j = 0; j < Dimension; ++j) { + transposed_comS(i, j) = cofactor(S, j, i); + } + } + return transposed_comS; + }(); + + TinyVector<Dimension> sigma_gradient{trace(Sigma * S_gradient[0]), // + trace(Sigma * S_gradient[1])}; + + const std::array<TinyMatrix<Dimension>, Dimension> // + Sigma_gradient{TinyMatrix<Dimension>{+0, +1, // + +0, -1}, + TinyMatrix<Dimension>{-inv_sin_alpha, -inv_tan_alpha, // + +inv_sin_alpha, +inv_tan_alpha}}; + + escobar(sigma, S, sigma_gradient, S_gradient, Sigma_gradient, f, f_gradient, f_hessian); } - if (l2Norm(f_gradient) < 1E-12) { - break; + if constexpr (multi_connection) { + for (size_t i_cell = 0; i_cell < cell_list.size(); ++i_cell) { + const CellId cell_id = cell_list[i_cell]; + auto cell_node_list = cell_to_node_matrix[cell_list[i_cell]]; + const size_t cell_nb_nodes = cell_node_list.size(); + + if (print) { + std::cout << "=== MC cell " << i_cell << " ===\n"; + } + + if (cell_nb_nodes <= 3) { + continue; + } + + const size_t i_cell_node = node_number_in_cell[i_cell]; + + const double mr_alpha = 2 * std::acos(-1) / ((cell_nb_nodes - 2) * (cell_list.size())); + if (print) { + std::cout << "=== MC mr_alpha " << mr_alpha << " ===\n"; + } + const double mr_sin_alpha = std::sin(mr_alpha); + const double mr_cos_alpha = std::cos(mr_alpha); + const double mr_inv_sin_alpha = 1. / mr_sin_alpha; + const double mr_inv_tan_alpha = 1. / std::tan(mr_alpha); + + const TinyMatrix<Dimension> mr_W{1, mr_cos_alpha, // + 0, mr_sin_alpha}; + + const TinyMatrix mr_inv_W = inverse(mr_W); + + std::array<TinyMatrix<Dimension>, Dimension> // + mr_S_gradient = {TinyMatrix<Dimension>{-1, (mr_cos_alpha - 1) / mr_sin_alpha, // + +0, +0}, + TinyMatrix<Dimension>{+0, +0, // + -1, (mr_cos_alpha - 1) / mr_sin_alpha}}; + + { // first simplex + const TinyVector a = old_xr[cell_node_list[(i_cell_node + 1) % cell_nb_nodes]]; + const TinyVector b = old_xr[cell_node_list[(i_cell_node + 2) % cell_nb_nodes]]; + + const TinyMatrix<Dimension> mr_A{a[0] - x[0], b[0] - x[0], // + a[1] - x[1], b[1] - x[1]}; + + const TinyMatrix mr_S = mr_A * mr_inv_W; + const double mr_sigma = det(mr_S); + + const TinyMatrix<Dimension> mr_Sigma = [&mr_S] { + TinyMatrix<Dimension> transposed_comS; + for (size_t i = 0; i < Dimension; ++i) { + for (size_t j = 0; j < Dimension; ++j) { + transposed_comS(i, j) = cofactor(mr_S, j, i); + } + } + return transposed_comS; + }(); + + TinyVector<Dimension> mr_sigma_gradient{trace(mr_Sigma * mr_S_gradient[0]), // + trace(mr_Sigma * mr_S_gradient[1])}; + + const std::array<TinyMatrix<Dimension>, Dimension> // + mr_Sigma_gradient{TinyMatrix<Dimension>{+0, (1 - mr_cos_alpha) / mr_sin_alpha, // + +0, -1}, + TinyMatrix<Dimension>{(mr_cos_alpha - 1) / mr_sin_alpha, +0, // + +1, +0}}; + + if (print) { + std::cout << "=== MC triangle 1 ===\n"; + std::cout << " A = " << mr_A << '\n'; + std::cout << " W = " << mr_W << '\n'; + std::cout << " inv(W) = " << mr_inv_W << '\n'; + + std::cout << " A * inv(W) = " << mr_A * mr_inv_W << '\n'; + + std::cout << " mr_S = " << mr_S << '\n'; + std::cout << " mr_Sigma = " << mr_Sigma << '\n'; + + std::cout << " mr_S_gradient = " << mr_S_gradient[0] << " || " << mr_S_gradient[1] << '\n'; + std::cout << " mr_Sigma_gradient = " << mr_Sigma_gradient[0] << " || " << mr_Sigma_gradient[1] + << '\n'; + } + + escobar(mr_sigma, mr_S, mr_sigma_gradient, mr_S_gradient, mr_Sigma_gradient, f, f_gradient, f_hessian); + } + + { // second simplex + const TinyVector a = old_xr[cell_node_list[(i_cell_node + cell_nb_nodes - 2) % cell_nb_nodes]]; + const TinyVector b = old_xr[cell_node_list[(i_cell_node + cell_nb_nodes - 1) % cell_nb_nodes]]; + + const TinyMatrix<Dimension> mr_A{a[0] - x[0], b[0] - x[0], // + a[1] - x[1], b[1] - x[1]}; + + const TinyMatrix mr_S = mr_A * mr_inv_W; + const double mr_sigma = det(mr_S); + + const TinyMatrix<Dimension> mr_Sigma = [&mr_S] { + TinyMatrix<Dimension> transposed_comS; + for (size_t i = 0; i < Dimension; ++i) { + for (size_t j = 0; j < Dimension; ++j) { + transposed_comS(i, j) = cofactor(mr_S, j, i); + } + } + return transposed_comS; + }(); + + TinyVector<Dimension> mr_sigma_gradient{trace(mr_Sigma * mr_S_gradient[0]), // + trace(mr_Sigma * mr_S_gradient[1])}; + + const std::array<TinyMatrix<Dimension>, Dimension> // + mr_Sigma_gradient{TinyMatrix<Dimension>{0, +1, // + 0, -1}, + TinyMatrix<Dimension>{-mr_inv_sin_alpha, -mr_inv_tan_alpha, // + +mr_inv_sin_alpha, +mr_inv_tan_alpha}}; + + if (print) { + std::cout << "=== MC triangle 2 ===\n"; + std::cout << " A = " << mr_A << '\n'; + std::cout << " W = " << mr_W << '\n'; + std::cout << " inv(W) = " << mr_inv_W << '\n'; + std::cout << " mr_S = " << mr_S << '\n'; + std::cout << " mr_Sigma = " << mr_Sigma << '\n'; + } + + escobar(mr_sigma, mr_S, mr_sigma_gradient, mr_S_gradient, mr_Sigma_gradient, f, f_gradient, f_hessian); + } + } } const double max_edge_lenght = [=] { @@ -651,13 +897,25 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar const double delta_x_norm = l2Norm(delta_x_candidate); + double factor = 1; if (delta_x_norm > 0.3 * max_edge_lenght) { - x += (0.3 * max_edge_lenght / delta_x_norm) * delta_x_candidate; - } else { - x += delta_x_candidate; + factor = (0.3 * max_edge_lenght / delta_x_norm); + } + x += factor * delta_x_candidate; + + if (print) { + std::cout << "==============\n"; + std::cout << "f_gradient = " << f_gradient << '\n'; + std::cout << "f_hessian = " << f_hessian << '\n'; + std::cout << "inv(f_hes) = " << inverse(f_hessian) << '\n'; + std::cout << "factor = " << factor << '\n'; + std::cout << "delta_x= " << delta_x_candidate << '\n'; + } + if (l2Norm(f_gradient) < 1E-12) { + break; } - if (delta_x_norm < 1E-2 * max_edge_lenght) { + if (delta_x_norm < 1E-8 * max_edge_lenght) { break; } @@ -667,12 +925,21 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar return final_f; }; - parallel_for( - connectivity.numberOfNodes(), PUGS_LAMBDA(NodeId node_id) { - if (node_is_owned[node_id] and m_is_smoothed_node[node_id] and not is_boundary_node[node_id]) { - quality[node_id] = smooth(node_id, new_xr[node_id]); - } - }); + // parallel_for( + // connectivity.numberOfNodes(), PUGS_LAMBDA(NodeId node_id) { + // if (node_is_owned[node_id] and m_is_smoothed_node[node_id] and not is_boundary_node[node_id]) { + // quality[node_id] = smooth(node_id, new_xr[node_id]); + // } + // }); + + size_t count = 0; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + if (node_is_owned[node_id] and m_is_smoothed_node[node_id] and not is_boundary_node[node_id]) { + quality[node_id] = smooth(node_id, new_xr[node_id]); + count++; + } + } + std::cout << "nb smoothed = " << count << '\n'; } else { throw NotImplementedError("Dimension != 2"); } @@ -690,10 +957,14 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar std::cout << "- convexfication step " << i_convexify++ << '\n'; NodeValue<Rd> new_xr = copy(xr); this->_getNewPositions(xr, new_xr); - xr = new_xr; - nb_non_convex_cells = sum(this->_getNonConvexCellTag(xr)); + xr = new_xr; + auto non_convex_cell_tag = this->_getNonConvexCellTag(xr); + nb_non_convex_cells = sum(non_convex_cell_tag); std::cout << " remaining non convex cells: " << nb_non_convex_cells << '\n'; - } while ((nb_non_convex_cells > 0) and (i_convexify < 120)); + if (nb_non_convex_cells > 0) { + m_is_smoothed_node = _getSmoothedNode(non_convex_cell_tag, m_is_fixed_node); + } + } while ((nb_non_convex_cells > 0) and (i_convexify < 10)); return std::make_shared<MeshType>(m_given_mesh.shared_connectivity(), xr); } @@ -784,9 +1055,6 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar auto node_to_cell_matrix = m_given_mesh.connectivity().nodeToCellMatrix(); - NodeValue<bool> is_displaced{m_given_mesh.connectivity()}; - is_displaced.fill(false); - CellValue<bool> is_zone_cell{m_given_mesh.connectivity()}; is_zone_cell.fill(false); @@ -809,6 +1077,9 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar return m_p_given_mesh; } + NodeValue<bool> is_displaced{m_given_mesh.connectivity()}; + is_displaced.fill(false); + for (size_t i_zone = 0; i_zone < discrete_function_variant_list.size(); ++i_zone) { auto characteristic_function = discrete_function_variant_list[i_zone]->get<DiscreteFunctionP0<Dimension, const double>>(); -- GitLab