diff --git a/src/mesh/MeshSmootherEscobar.cpp b/src/mesh/MeshSmootherEscobar.cpp index 736a0e03725e1910605779898e3107ff82575144..c1ff9e69feb146b15716498ec72c28c3c40e4752 100644 --- a/src/mesh/MeshSmootherEscobar.cpp +++ b/src/mesh/MeshSmootherEscobar.cpp @@ -99,7 +99,9 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar boundary_condition); } -#warning treat the axis line case in dimension 3 before this + if constexpr (Dimension == 3) { + throw NotImplementedError("treat sliding axis node kind"); + } synchronize(is_fixed); @@ -164,17 +166,163 @@ class MeshSmootherEscobarHandler::MeshSmootherEscobar if constexpr (std::is_same_v<BCType, SymmetryBoundaryCondition>) { const Rd& n = bc.outgoingNormal(); + const auto node_list = bc.nodeList(); + const Rdxd I = identity; const Rdxd nxn = tensorProduct(n, n); const Rdxd P = I - nxn; - const Array<const NodeId>& node_list = bc.nodeList(); - parallel_for( - node_list.size(), PUGS_LAMBDA(const size_t i_node) { - const NodeId node_id = node_list[i_node]; + const ConnectivityType& connectivity = m_given_mesh.connectivity(); - new_xr[node_id] = P * new_xr[node_id]; - }); + auto is_boundary_node = connectivity.isBoundaryNode(); + auto node_is_owned = connectivity.nodeIsOwned(); + + if constexpr (Dimension == 2) { + const TinyVector<Dimension> t{-n[1], n[0]}; + + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + auto node_number_in_their_cells = connectivity.nodeLocalNumbersInTheirCells(); + + NodeValue<double> quality{connectivity}; + + constexpr double eps = 1E-15; + quality.fill(2); + + auto smooth = [=](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 = std::acos(-1) / cell_list.size(); + const TinyMatrix<Dimension> W{1, std::cos(alpha), // + 0, std::sin(alpha)}; + + const TinyMatrix<Dimension> inv_W = inverse(W); + + TinyMatrix<Dimension, Dimension> dtheta_S = + TinyMatrix<Dimension>{t[0], t[0] * (1. / std::sin(alpha) - 1. / std::tan(alpha)), // + t[1], t[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]; + const 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]); + } + + 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; + + 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 < 3; ++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 = 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 f = 0; + double dtheta_f = 0; + double d2theta_f = 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]; + + 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; + + const double dtheta_sigma = trace(Sigma * dtheta_S); + + TinyMatrix<Dimension, Dimension> dtheta_Sigma = + TinyMatrix<Dimension>{t[1] * (1. / std::sin(alpha) - 1. / std::tan(alpha)), + -t[0] * (1. / std::sin(alpha) - 1. / std::tan(alpha)), // + -t[1], t[0]}; + + const double g = trace(transpose(S) * dtheta_S) / S_norm2 // + + trace(transpose(Sigma) * dtheta_Sigma) / Sigma_norm2 // + - dtheta_sigma / (h - sigma); + + const double dtheta_f_jr = f_jr * g; + const double dtheta2_f_jr = + (trace(transpose(dtheta_S) * dtheta_S) / S_norm2 // + - 2 * trace(transpose(S) * dtheta_S) * trace(transpose(S) * dtheta_S) / (S_norm2 * S_norm2) // + // + + trace(transpose(dtheta_Sigma) * dtheta_Sigma) / Sigma_norm2 // + 0 + - 2 * trace(transpose(Sigma) * dtheta_Sigma) * trace(transpose(Sigma) * dtheta_Sigma) / + (Sigma_norm2 * Sigma_norm2) // + // + - 2 * trace(dtheta_Sigma * dtheta_S) / (h - sigma) // + + 2 * sigma / (std::pow(h - sigma, 3)) * dtheta_sigma * dtheta_sigma // + + g * g) * + f_jr; + + f += f_jr; + dtheta_f += dtheta_f_jr; + d2theta_f += dtheta2_f_jr; + } + if (std::abs(dtheta_f) < 1E-6) { + break; + } + x += dtheta_f / d2theta_f * t; + + final_f = f; + } + return final_f; + }; + + parallel_for( + node_list.size(), PUGS_LAMBDA(const size_t i_node) { + const NodeId node_id = node_list[i_node]; + if (not m_is_fixed_node[node_id] and node_is_owned[node_id]) { + smooth(node_id, new_xr[node_id]); + } + }); + + } else { + throw NotImplementedError("Dimension != 2"); + } } else if constexpr (std::is_same_v<BCType, AxisBoundaryCondition>) { if constexpr (Dimension > 1) {