23 Remesher::BoundaryMap<int> build_boundary_to_id(
24 const std::unique_ptr<mesh::Mesh> &mesh,
25 const Eigen::VectorXi &in_node_to_node)
27 if (mesh->dimension() == 2)
29 Remesher::EdgeMap<int> edge_to_boundary_id;
30 for (
int i = 0; i < mesh->n_edges(); i++)
32 const size_t e0 = in_node_to_node[mesh->edge_vertex(i, 0)];
33 const size_t e1 = in_node_to_node[mesh->edge_vertex(i, 1)];
34 edge_to_boundary_id[{{e0, e1}}] = mesh->get_boundary_id(i);
36 return edge_to_boundary_id;
40 assert(mesh->dimension() == 3);
41 Remesher::FaceMap<int> face_to_boundary_id;
42 for (
int i = 0; i < mesh->n_faces(); i++)
44 std::array<size_t, 3>
f =
45 {{(size_t)in_node_to_node[mesh->face_vertex(i, 0)],
46 (size_t)in_node_to_node[mesh->face_vertex(i, 1)],
47 (size_t)in_node_to_node[mesh->face_vertex(i, 2)]}};
48 face_to_boundary_id[
f] = mesh->get_boundary_id(i);
51 if (mesh->is_boundary_face(i))
52 assert(face_to_boundary_id[f] >= 0);
54 assert(face_to_boundary_id[f] == -1);
57 return face_to_boundary_id;
68 void build_edge_energy_maps(
70 const Eigen::MatrixXd &vertices,
71 const Eigen::MatrixXi &elements,
72 const Eigen::MatrixXd &sol,
73 Remesher::EdgeMap<double> &elastic_energy,
74 Remesher::EdgeMap<double> &contact_energy)
76 Eigen::MatrixXi edges;
77 igl::edges(elements, edges);
78 Remesher::EdgeMap<std::vector<double>> elastic_multienergy;
79 for (
const auto &edge : edges.rowwise())
81 elastic_multienergy[{{(size_t)edge(0), (size_t)edge(1)}}] = std::vector<double>();
84 assert(state.solve_data.elastic_form !=
nullptr);
85 const Eigen::VectorXd elastic_energy_per_element = state.solve_data.elastic_form->value_per_element(sol);
86 for (
int i = 0; i < elements.rows(); ++i)
88 assert(elements.cols() == 3 || elements.cols() == 4);
89 const auto &element = elements.row(i);
90 const double energy = elastic_energy_per_element[i];
92 elastic_multienergy[{{(size_t)element(0), (size_t)element(1)}}].push_back(energy);
93 elastic_multienergy[{{(size_t)element(0), (size_t)element(2)}}].push_back(energy);
94 elastic_multienergy[{{(size_t)element(1), (size_t)element(2)}}].push_back(energy);
95 if (elements.cols() == 4)
97 elastic_multienergy[{{(size_t)element(0), (size_t)element(3)}}].push_back(energy);
98 elastic_multienergy[{{(size_t)element(1), (size_t)element(3)}}].push_back(energy);
99 elastic_multienergy[{{(size_t)element(2), (size_t)element(3)}}].push_back(energy);
104 for (
const auto &[edge, energies] : elastic_multienergy)
106 elastic_energy[edge] =
107 std::reduce(energies.begin(), energies.end()) / energies.size();
110 if (state.solve_data.contact_form !=
nullptr)
112 const Eigen::VectorXd contact_energy_per_vertex = state.solve_data.contact_form->value_per_element(sol);
113 for (
int i = 0; i < edges.rows(); ++i)
115 contact_energy[{{(size_t)edges(i, 0), (size_t)edges(i, 1)}}] =
116 (contact_energy_per_vertex[edges(i, 0)] + contact_energy_per_vertex[edges(i, 1)]) / 2.0;
121 std::shared_ptr<Remesher> create_wild_remeshing(
123 const Eigen::VectorXd &obstacle_sol,
124 const Eigen::MatrixXd &obstacle_projection_quantities,
126 const double current_energy)
128 const int dim = state.mesh->dimension();
130 const std::string type = state.args[
"space"][
"remesh"][
"type"];
131 std::shared_ptr<Remesher> remeshing =
nullptr;
132 if (type ==
"physics")
135 remeshing = std::make_shared<PhysicsTriRemesher>(
137 time, current_energy);
139 remeshing = std::make_shared<PhysicsTetRemesher>(
141 time, current_energy);
143 else if (type ==
"sizing_field")
146 remeshing = std::make_shared<SizingFieldTriRemesher>(
148 time, current_energy);
150 remeshing = std::make_shared<SizingFieldTetRemesher>(
152 time, current_energy);
154 assert(remeshing !=
nullptr);
159 bool State::remesh(
const double time,
const double dt, Eigen::MatrixXd &sol)
161 const int dim =
mesh->dimension();
162 int ndof = sol.size();
163 assert(sol.cols() == 1);
164 int ndof_mesh =
mesh->n_vertices() * dim;
166 assert(
ndof == ndof_mesh + ndof_obstacle);
168 Eigen::MatrixXd rest_positions;
169 Eigen::MatrixXi elements;
171 assert(rest_positions.size() == ndof_mesh);
176 build_edge_energy_maps(
177 *
this, rest_positions, elements, sol, elastic_energy, contact_energy);
183 const std::vector<int> body_ids =
mesh->has_body_ids() ?
mesh->get_body_ids() : std::vector<int>(elements.rows(), 0);
184 assert(body_ids.size() == elements.rows());
188 const Eigen::MatrixXd mesh_sol = sol.topRows(ndof_mesh);
189 const Eigen::MatrixXd obstacle_sol = sol.bottomRows(ndof_obstacle);
190 const Eigen::MatrixXd positions = rest_positions +
utils::unflatten(mesh_sol, dim);
195 assert(projection_quantities.rows() ==
ndof);
197 const Eigen::MatrixXd obstacle_projection_quantities = projection_quantities.bottomRows(ndof_obstacle);
198 projection_quantities.conservativeResize(ndof_mesh, Eigen::NoChange);
203 std::shared_ptr<Remesher> remeshing = create_wild_remeshing(
206 rest_positions, positions, elements, projection_quantities, boundary_to_id, body_ids,
207 elastic_energy, contact_energy);
209 const bool made_change = remeshing->execute();
220 mesh->set_body_ids(remeshing->body_ids());
223 std::vector<int> boundary_ids;
226 const auto remesh_boundary_ids = std::get<Remesher::EdgeMap<int>>(remeshing->boundary_ids());
227 boundary_ids = std::vector<int>(
mesh->n_edges(), -1);
228 for (
int i = 0; i <
mesh->n_edges(); i++)
230 const size_t e0 =
mesh->edge_vertex(i, 0);
231 const size_t e1 =
mesh->edge_vertex(i, 1);
232 boundary_ids[i] = remesh_boundary_ids.at({{e0, e1}});
237 const auto remesh_boundary_ids = std::get<Remesher::FaceMap<int>>(remeshing->boundary_ids());
238 boundary_ids = std::vector<int>(
mesh->n_faces(), -1);
239 for (
int i = 0; i <
mesh->n_faces(); i++)
241 const std::array<size_t, 3> f = {{(size_t)
mesh->face_vertex(i, 0),
242 (size_t)
mesh->face_vertex(i, 1),
243 (size_t)
mesh->face_vertex(i, 2)}};
244 boundary_ids[i] = remesh_boundary_ids.at(f);
247 mesh->set_boundary_ids(boundary_ids);
260 const int old_ndof =
ndof;
261 const int old_ndof_mesh = ndof_mesh;
262 const int old_ndof_obstacle = ndof_obstacle;
264 ndof_mesh =
mesh->n_vertices() * dim;
266 assert(ndof_obstacle == old_ndof_obstacle);
268 assert(
ndof == ndof_mesh + ndof_obstacle);
272 if (ndof_obstacle > 0)
273 sol.bottomRows(ndof_obstacle) = obstacle_sol;
276 if (
problem->is_time_dependent())
280 Eigen::MatrixXd projected_quantities = remeshing->projection_quantities();
281 assert(projected_quantities.rows() == ndof_mesh);
282 assert(projected_quantities.cols() == projection_quantities.cols());
285 projected_quantities.conservativeResize(
ndof, Eigen::NoChange);
286 projected_quantities.bottomRows(ndof_obstacle) = obstacle_projection_quantities;
288 Eigen::MatrixXd x_prevs, v_prevs, a_prevs;
290 projected_quantities, dim, x_prevs, v_prevs, a_prevs);
int n_bases
number of bases
void assemble_mass_mat()
assemble mass, step 4 of solve build mass matrix based on defined basis modifies mass (and maybe more...
Eigen::VectorXi in_node_to_node
Inpute nodes (including high-order) to polyfem nodes, only for isoparametric.
mesh::Obstacle obstacle
Obstacles used in collisions.
void load_mesh(bool non_conforming=false, const std::vector< std::string > &names=std::vector< std::string >(), const std::vector< Eigen::MatrixXi > &cells=std::vector< Eigen::MatrixXi >(), const std::vector< Eigen::MatrixXd > &vertices=std::vector< Eigen::MatrixXd >())
loads the mesh from the json arguments
bool remesh(const double time, const double dt, Eigen::MatrixXd &sol)
Remesh the FE space and update solution(s).
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
void build_basis()
builds the bases step 2 of solve modifies bases, pressure_bases, geom_bases_, boundary_nodes,...
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
void assemble_rhs()
compute rhs, step 3 of solve build rhs vector based on defined basis and given rhs of the problem mod...
std::shared_ptr< assembler::RhsAssembler > build_rhs_assembler() const
build a RhsAssembler for the problem
solver::SolveData solve_data
timedependent stuff cached
void init_nonlinear_tensor_solve(Eigen::MatrixXd &sol, const double t=1.0, const bool init_time_integrator=true)
initialize the nonlinear solver
void build_mesh_matrices(Eigen::MatrixXd &V, Eigen::MatrixXi &F)
Build the mesh matrices (vertices and elements) from the mesh using the bases node ordering.
static std::unique_ptr< Mesh > create(const std::string &path, const bool non_conforming=false)
factory to build the proper mesh
std::unordered_map< std::array< size_t, 2 >, T, polyfem::utils::HashUnorderedArray< size_t, 2 >, polyfem::utils::EqualUnorderedArray< size_t, 2 > > EdgeMap
Map from a (sorted) edge to an integer (ID)
std::variant< EdgeMap< T >, FaceMap< T > > BoundaryMap
static Eigen::MatrixXd combine_time_integrator_quantities(const std::shared_ptr< time_integrator::ImplicitTimeIntegrator > &time_integrator)
Combine the quantities of a time integrator into a single matrix (one column per quantity)
static void split_time_integrator_quantities(const Eigen::MatrixXd &quantities, const int dim, Eigen::MatrixXd &x_prevs, Eigen::MatrixXd &v_prevs, Eigen::MatrixXd &a_prevs)
Split the quantities of a time integrator into separate vectors.
std::shared_ptr< solver::NLProblem > nl_problem
std::shared_ptr< time_integrator::ImplicitTimeIntegrator > time_integrator
std::shared_ptr< assembler::RhsAssembler > rhs_assembler
Eigen::MatrixXd reorder_matrix(const Eigen::MatrixXd &in, const Eigen::VectorXi &in_to_out, int out_blocks=-1, const int block_size=1)
Reorder row blocks in a matrix.
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
Eigen::VectorXd flatten(const Eigen::MatrixXd &X)
Flatten rowwises.