14#include <paraviewo/VTUWriter.hpp>
16#include <igl/boundary_facets.h>
22 const Eigen::MatrixXd &obstacle_displacements,
23 const Eigen::MatrixXd &obstacle_quantities,
24 const double current_time,
25 const double starting_energy)
27 args(state.args[
"space"][
"remesh"]),
28 m_obstacle_displacements(obstacle_displacements),
29 m_obstacle_quantities(obstacle_quantities),
30 current_time(current_time),
31 starting_energy(starting_energy)
36 const Eigen::MatrixXd &rest_positions,
37 const Eigen::MatrixXd &positions,
38 const Eigen::MatrixXi &elements,
39 const Eigen::MatrixXd &projection_quantities,
41 const std::vector<int> &body_ids,
52 std::unordered_map<int, std::vector<int>> body_elements;
53 for (
int i = 0; i <
elements.rows(); ++i)
56 if (body_elements.find(body_id) == body_elements.end())
57 body_elements[body_id] = std::vector<int>();
58 body_elements[body_id].push_back(i);
62 std::vector<bool> is_boundary_vertex(
positions.rows(),
false);
63 for (
const auto &[body_id, rows] : body_elements)
65 Eigen::MatrixXi boundary_facets;
66 igl::boundary_facets(
elements(rows, Eigen::all), boundary_facets);
68 for (
int i = 0; i < boundary_facets.rows(); ++i)
69 for (
int j = 0; j < boundary_facets.cols(); ++j)
70 is_boundary_vertex[boundary_facets(i, j)] =
true;
104 std::vector<ElementBases> from_bases;
105 std::vector<LocalBoundary> _;
106 Eigen::VectorXi from_vertex_to_basis;
113 from_vertex_to_basis, n_from_basis,
dim());
116 assert(
dim() * n_from_basis == from_projection_quantities.rows());
124 std::vector<ElementBases> to_bases;
125 Eigen::VectorXi to_vertex_to_basis;
137 assert(
dim() * n_to_basis == to_projection_quantities.rows());
142 Eigen::SparseMatrix<double> M, A;
150 n_to_basis, to_bases, to_bases,
152 assert(M.rows() == to_projection_quantities.rows());
159 n_from_basis, from_bases, from_bases,
160 n_to_basis, to_bases, to_bases,
162 assert(A.rows() == to_projection_quantities.rows());
163 assert(A.cols() == from_projection_quantities.rows());
168 ipc::CollisionMesh collision_mesh;
189 collision_mesh = ipc::CollisionMesh::build_from_full_mesh(
195 Eigen::MatrixXd projected_quantities(to_projection_quantities.rows(),
n_quantities());
196 const int n_constrained_quantaties =
n_quantities() / 3;
197 const int n_unconstrained_quantaties =
n_quantities() - n_constrained_quantaties;
200 for (
int i = 0; i < n_constrained_quantaties; ++i)
205 M, A, from_projection_quantities.col(i),
209 collision_mesh,
state.
args[
"contact"][
"dhat"],
213 state.
args[
"contact"][
"use_convergent_formulation"],
214 state.
args[
"solver"][
"contact"][
"CCD"][
"broad_phase"],
215 state.
args[
"solver"][
"contact"][
"CCD"][
"tolerance"],
216 state.
args[
"solver"][
"contact"][
"CCD"][
"max_iterations"],
220 to_projection_quantities.col(i));
232 const int row = M.rows() - i - 1;
233 M.coeffRef(row, row) = 1.0;
238 const int row = A.rows() - i - 1;
239 const int col = A.cols() - i - 1;
240 A.coeffRef(row, col) = 1.0;
245 M, A, from_projection_quantities.rightCols(n_unconstrained_quantaties));
249 assert(projected_quantities.rows() ==
dim() * n_to_basis);
251 projected_quantities, to_vertex_to_basis, to_vertex_to_basis.size(),
dim()));
256 const std::string &assembler_formulation,
257 std::vector<polyfem::basis::ElementBases> &bases,
258 std::vector<LocalBoundary> &local_boundary,
259 Eigen::VectorXi &vertex_to_basis)
264 std::map<int, basis::InterfaceData> poly_edge_to_data;
265 std::shared_ptr<mesh::MeshNodes> mesh_nodes;
269 dynamic_cast<const Mesh2D &
>(mesh),
270 assembler_formulation, 1,
273 false, bases, local_boundary,
274 poly_edge_to_data, mesh_nodes);
280 dynamic_cast<const Mesh3D &
>(mesh),
281 assembler_formulation, 1,
284 false, bases, local_boundary,
285 poly_edge_to_data, mesh_nodes);
289 vertex_to_basis.setConstant(mesh.
n_vertices(), -1);
292 for (
const Basis &basis : elm.bases)
294 assert(basis.global().size() == 1);
295 const int basis_id = basis.global()[0].index;
300 if ((mesh.
point(i).array() == v.array()).all())
302 if (vertex_to_basis[i] == -1)
303 vertex_to_basis[i] = basis_id;
304 assert(vertex_to_basis[i] == basis_id);
318 paraviewo::VTUWriter writer;
324 std::vector<Eigen::MatrixXd> unflattened_projection_quantities;
329 std::vector<std::vector<int>> all_elements(
elements.rows(), std::vector<int>(
elements.cols()));
330 for (
int i = 0; i <
elements.rows(); i++)
331 for (
int j = 0; j <
elements.cols(); j++)
332 all_elements[i][j] =
elements(i, j);
339 for (
int i = 0; i < unflattened_projection_quantities.size(); ++i)
341 unflattened_projection_quantities[i],
346 const Eigen::MatrixXi obstacle_edges =
obstacle().
e().array() + offset;
347 all_elements.resize(all_elements.size() + obstacle_edges.rows());
350 all_elements[i +
elements.rows()] = std::vector<int>(obstacle_edges.cols());
351 for (
int j = 0; j < obstacle_edges.cols(); j++)
352 all_elements[i +
elements.rows()][j] = obstacle_edges(i, j);
358 const Eigen::MatrixXi obstacle_faces =
obstacle().
f().array() + offset;
359 all_elements.resize(all_elements.size() + obstacle_faces.rows());
362 all_elements[i +
elements.rows()] = std::vector<int>(obstacle_faces.cols());
363 for (
int j = 0; j < obstacle_faces.cols(); j++)
364 all_elements[i +
elements.rows()][j] = obstacle_faces(i, j);
369 for (
int i = 0; i < unflattened_projection_quantities.size(); ++i)
370 writer.add_field(fmt::format(
"projection_quantity_{:d}", i), unflattened_projection_quantities[i]);
372 writer.write_mesh(path,
rest_positions, all_elements,
true,
false);
376 const std::shared_ptr<time_integrator::ImplicitTimeIntegrator> &time_integrator)
378 if (time_integrator ==
nullptr)
379 return Eigen::MatrixXd();
383 time_integrator->x_prev().size(), 3 * time_integrator->steps());
385 for (
const Eigen::VectorXd &
x : time_integrator->x_prevs())
387 for (
const Eigen::VectorXd &v : time_integrator->v_prevs())
389 for (
const Eigen::VectorXd &a : time_integrator->a_prevs())
397 const Eigen::MatrixXd &quantities,
399 Eigen::MatrixXd &x_prevs,
400 Eigen::MatrixXd &v_prevs,
401 Eigen::MatrixXd &a_prevs)
403 if (quantities.size() == 0)
406 assert(quantities.cols() % 3 == 0);
407 const int n_steps = quantities.cols() / 3;
409 x_prevs = quantities.leftCols(n_steps);
410 v_prevs = quantities.middleCols(n_steps, n_steps);
411 a_prevs = quantities.rightCols(n_steps);
416 if (!
logger().should_log(spdlog::level::debug) ||
timings.empty())
419 std::cout <<
"--------------------------------------------------------------------------------" << std::endl;
425 std::vector<std::pair<std::string, utils::Timing>> sorted_timings(
timings.begin(),
timings.end());
427 std::sort(sorted_timings.begin(), sorted_timings.end(), [](
const auto &a,
const auto &b) { return a.second > b.second; });
428 for (
const auto &[name, time] : sorted_timings)
430 logger().debug(
"{:62s}: {:10.3g}s {:5.1f}% ({:6d} calls)", name, time, time /
total_time * 100, time.count);
438 std::cout <<
"--------------------------------------------------------------------------------" << std::endl;
std::unique_ptr< MatrixCache > cache
#define POLYFEM_REMESHER_SCOPED_TIMER(name)
main class that contains the polyfem solver and all its state
std::string formulation() const
return the formulation (checks if the problem is scalar or not and deals with multiphysics)
std::shared_ptr< polysolve::nonlinear::Solver > make_nl_solver(bool for_al) const
factory to create the nl solver depending on input
json args
main input arguments containing all defaults
solver::SolveData solve_data
timedependent stuff cached
Caches basis evaluation and geometric mapping at every element.
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, 9, 1 > assemble(const LinearAssemblerData &data) const override
computes and returns local stiffness matrix (1x1) for bases i,j (where i,j is passed in through data)...
void assemble_cross(const bool is_volume, const int size, const int n_from_basis, const std::vector< basis::ElementBases > &from_bases, const std::vector< basis::ElementBases > &from_gbases, const int n_to_basis, const std::vector< basis::ElementBases > &to_bases, const std::vector< basis::ElementBases > &to_gbases, const AssemblyValsCache &cache, StiffnessMatrix &mass) const
Assembles the cross mass matrix between to function spaces.
Represents one basis function and its gradient.
Stores the basis functions for a given element in a mesh (facet in 2d, cell in 3d).
static int build_bases(const mesh::Mesh2D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, const int discr_order, const bool serendipity, const bool has_polys, const bool is_geom_bases, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_edge_to_data, std::shared_ptr< mesh::MeshNodes > &mesh_nodes)
Builds FE basis functions over the entire mesh (P1, P2 over triangles, Q1, Q2 over quads).
static int build_bases(const mesh::Mesh3D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, const int discr_order, const bool serendipity, const bool has_polys, const bool is_geom_bases, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_face_to_data, std::shared_ptr< mesh::MeshNodes > &mesh_nodes)
Builds FE basis functions over the entire mesh (P1, P2 over tets, Q1, Q2 over hes).
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
virtual int n_vertices() const =0
number of vertices
virtual RowVectorNd point(const int global_index) const =0
point coordinates
static std::unique_ptr< Mesh > create(const std::string &path, const bool non_conforming=false)
factory to build the proper mesh
int dimension() const
utily for dimension
const Eigen::MatrixXi & e() const
const Eigen::MatrixXi & f() const
const Eigen::MatrixXd & obstacle_displacements() const
Get a reference to the collision obstacles' displacements.
static int build_bases(const Mesh &mesh, const std::string &assembler_formulation, std::vector< polyfem::basis::ElementBases > &bases, std::vector< LocalBoundary > &local_boundary, Eigen::VectorXi &vertex_to_basis)
Build bases for a given mesh (V, F)
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)
virtual void set_body_ids(const std::vector< int > &body_ids)=0
Set the body IDs of all elements.
virtual void init_attributes_and_connectivity(const size_t num_vertices, const Eigen::MatrixXi &elements)=0
Create an internal mesh representation and associate attributes.
virtual void set_projection_quantities(const Eigen::MatrixXd &projection_quantities)=0
Set projected quantities of the stored mesh.
virtual std::vector< int > boundary_nodes(const Eigen::VectorXi &vertex_to_basis) const =0
Get the boundary nodes of the stored mesh.
Remesher(const State &state, const Eigen::MatrixXd &obstacle_displacements, const Eigen::MatrixXd &obstacle_quantities, const double current_time, const double starting_energy)
Construct a new Remesher object.
const Obstacle & obstacle() const
Get a reference to the collision obstacles.
virtual Eigen::MatrixXd positions() const =0
Exports displacements of the stored mesh.
virtual Eigen::MatrixXd rest_positions() const =0
Exports rest positions of the stored mesh.
std::variant< EdgeMap< T >, FaceMap< T > > BoundaryMap
virtual Eigen::MatrixXi boundary_edges() const =0
Exports boundary edges of the stored mesh.
GlobalProjectionCache global_projection_cache
virtual void set_fixed(const std::vector< bool > &fixed)=0
Set if a vertex is fixed.
void project_quantities()
Update the mesh positions and other projection quantities.
const Eigen::MatrixXd & obstacle_quantities() const
Get a reference to the collision obstacles' extra quantities.
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)
void write_mesh(const std::string &path) const
Writes a VTU mesh file.
virtual bool is_volume() const
Is the mesh a volumetric mesh.
virtual Eigen::MatrixXi boundary_faces() const =0
Exports boundary faces of the stored mesh.
void cache_before()
Cache quantities before applying an operation.
virtual std::vector< int > body_ids() const =0
Exports body ids of the stored mesh.
virtual Eigen::MatrixXd displacements() const =0
Exports positions of the stored mesh.
virtual Eigen::MatrixXi elements() const =0
Exports elements of the stored mesh.
const State & state
Reference to the simulation state.
static void log_timings()
virtual void set_positions(const Eigen::MatrixXd &positions)=0
Set deformed positions of the stored mesh.
virtual void set_boundary_ids(const BoundaryMap< int > &boundary_to_id)=0
Set the boundary IDs of all edges.
static size_t total_ndofs
virtual void set_rest_positions(const Eigen::MatrixXd &positions)=0
Set rest positions of the stored mesh.
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.
static std::unordered_map< std::string, utils::Timing > timings
Timings for the remeshing operations.
virtual int dim() const =0
Dimension of the mesh.
virtual Eigen::MatrixXd projection_quantities() const =0
Exports projected quantities of the stored mesh.
virtual void init(const Eigen::MatrixXd &rest_positions, const Eigen::MatrixXd &positions, const Eigen::MatrixXi &elements, const Eigen::MatrixXd &projection_quantities, const BoundaryMap< int > &boundary_to_id, const std::vector< int > &body_ids, const EdgeMap< double > &elastic_energy, const EdgeMap< double > &contact_energy)
Initialize the mesh.
virtual int n_quantities() const =0
Number of projection quantities (not including the position)
std::shared_ptr< solver::ContactForm > contact_form
Eigen::MatrixXd unconstrained_L2_projection(const Eigen::SparseMatrix< double > &M, const Eigen::SparseMatrix< double > &A, const Eigen::Ref< const Eigen::MatrixXd > &y)
Eigen::VectorXd constrained_L2_projection(std::shared_ptr< polysolve::nonlinear::Solver > nl_solver, const Eigen::SparseMatrix< double > &M, const Eigen::SparseMatrix< double > &A, const Eigen::VectorXd &y, const Eigen::MatrixXd &rest_positions, const Eigen::MatrixXi &elements, const int dim, const ipc::CollisionMesh &collision_mesh, const double dhat, const double barrier_stiffness, const bool use_convergent_formulation, const ipc::BroadPhaseMethod broad_phase_method, const double ccd_tolerance, const int ccd_max_iterations, const std::vector< int > &boundary_nodes, const size_t obstacle_ndof, const Eigen::VectorXd &target_x, const Eigen::VectorXd &x0)
bool endswith(const std::string &str, const std::string &suffix)
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 unreorder_matrix(const Eigen::MatrixXd &out, const Eigen::VectorXi &in_to_out, int in_blocks=-1, const int block_size=1)
Undo the reordering of 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.
void append_rows(DstMat &dst, const SrcMat &src)
Eigen::MatrixXi map_index_matrix(const Eigen::MatrixXi &in, const Eigen::VectorXi &index_mapping)
Map the entrys of an index matrix to new indices.
spdlog::logger & logger()
Retrieves the current logger.
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Eigen::MatrixXi elements
Elements before an operation.
Eigen::MatrixXd rest_positions
Rest positions of the mesh before an operation.
Eigen::MatrixXd projection_quantities
dim rows per vertex and 1 column per quantity