PolyFEM
Loading...
Searching...
No Matches
LocalRelaxationData.cpp
Go to the documentation of this file.
2
12
13namespace polyfem::mesh
14{
15 template <typename M>
17 const State &state,
18 LocalMesh<M> &local_mesh,
19 const double current_time,
20 const bool contact_enabled)
21 : local_mesh(local_mesh)
22 {
23 problem = std::make_shared<assembler::GenericTensorProblem>("GenericTensor");
24
25 init_mesh(state);
26 init_bases(state);
28 init_assembler(state);
29 init_mass_matrix(state);
30 init_solve_data(state, current_time, contact_enabled);
31 }
32
33 template <typename M>
35 {
36 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_mesh");
37
38 mesh = Mesh::create(local_mesh.rest_positions(), local_mesh.elements());
39 assert(mesh->n_vertices() == local_mesh.num_vertices());
40
41 std::vector<int> boundary_ids(mesh->n_boundary_elements(), -1);
42 if constexpr (std::is_same_v<M, WildTriRemesher>)
43 {
44 const auto local_boundary_ids = std::get<Remesher::EdgeMap<int>>(local_mesh.boundary_ids());
45 for (int i = 0; i < mesh->n_edges(); i++)
46 {
47 const size_t e0 = mesh->edge_vertex(i, 0);
48 const size_t e1 = mesh->edge_vertex(i, 1);
49 boundary_ids[i] = local_boundary_ids.at({{e0, e1}});
50 }
51 }
52 else
53 {
54 const auto local_boundary_ids = std::get<Remesher::FaceMap<int>>(local_mesh.boundary_ids());
55 for (int i = 0; i < mesh->n_faces(); i++)
56 {
57 std::array<size_t, 3> f = {{
58 (size_t)mesh->face_vertex(i, 0),
59 (size_t)mesh->face_vertex(i, 1),
60 (size_t)mesh->face_vertex(i, 2),
61 }};
62 boundary_ids[i] = local_boundary_ids.at(f);
63 }
64 }
65
66 mesh->set_boundary_ids(boundary_ids);
67 mesh->set_body_ids(local_mesh.body_ids());
68 }
69
70 template <typename M>
72 {
73 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_bases");
74
75 Eigen::VectorXi vertex_to_basis;
76 m_n_bases = Remesher::build_bases(
77 *mesh, state.formulation(), bases, local_boundary, vertex_to_basis);
78
79 assert(m_n_bases == local_mesh.num_local_vertices());
80 m_n_bases = local_mesh.num_vertices(); // the real n_bases includes the global boundary nodes
81 assert(vertex_to_basis.size() == m_n_bases);
82
83 const int start_i = local_mesh.num_local_vertices();
84 if (start_i < m_n_bases)
85 {
86 // set tail to range [start_i, n_bases)
87 std::iota(vertex_to_basis.begin() + start_i, vertex_to_basis.end(), start_i);
88 }
89
90 assert(std::all_of(vertex_to_basis.begin(), vertex_to_basis.end(), [](const int basis_id) {
91 return basis_id >= 0;
92 }));
93
94 // State::build_node_mapping();
95 local_mesh.reorder_vertices(vertex_to_basis);
96 problem->update_nodes(vertex_to_basis);
97 mesh->update_nodes(vertex_to_basis);
98 }
99
100 template <typename M>
102 {
103 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_boundary_conditions");
104
105 assert(mesh != nullptr);
106 state.problem->init(*mesh);
107
108 std::vector<int> pressure_boundary_nodes;
109 state.problem->setup_bc(
110 *mesh, n_bases() - state.obstacle.n_vertices(), bases, /*geom_bases=*/bases,
111 /*pressure_bases=*/std::vector<basis::ElementBases>(), local_boundary,
112 boundary_nodes, local_neumann_boundary, local_pressure_boundary,
113 local_pressure_cavity, pressure_boundary_nodes, dirichlet_nodes, neumann_nodes);
114
115 auto find_node_position = [&](const int n_id) {
116 for (const auto &bs : bases)
117 for (const auto &b : bs.bases)
118 for (const auto &lg : b.global())
119 if (lg.index == n_id)
120 return lg.node;
121 log_and_throw_error("Node not found");
122 };
123
124 // setup nodal values
125 dirichlet_nodes_position.resize(dirichlet_nodes.size());
126 for (int n = 0; n < dirichlet_nodes.size(); ++n)
127 dirichlet_nodes_position[n] = find_node_position(dirichlet_nodes[n]);
128
129 neumann_nodes_position.resize(neumann_nodes.size());
130 for (int n = 0; n < neumann_nodes.size(); ++n)
131 neumann_nodes_position[n] = find_node_position(neumann_nodes[n]);
132
133 // Add fixed boundary DOF
134 for (const int vi : local_mesh.fixed_vertices())
135 {
136 for (int d = 0; d < dim(); ++d)
137 {
138 boundary_nodes.push_back(vi * dim() + d);
139 }
140 }
141
142 std::sort(boundary_nodes.begin(), boundary_nodes.end());
143 auto it = std::unique(boundary_nodes.begin(), boundary_nodes.end());
144 boundary_nodes.erase(it, boundary_nodes.end());
145 }
146
147 template <typename M>
149 {
150 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_assembler");
151 assert(utils::is_param_valid(state.args, "materials"));
152
154 assert(assembler->name() == state.formulation());
155 assembler->set_size(dim());
156 assembler->set_materials(local_mesh.body_ids(), state.args["materials"], state.units);
157
158 mass_matrix_assembler = std::make_shared<assembler::Mass>();
159 mass_matrix_assembler->set_size(dim());
160 mass_matrix_assembler->set_materials(local_mesh.body_ids(), state.args["materials"], state.units);
161
162 pressure_assembler = nullptr; // TODO: implement this
163 }
164
165 template <typename M>
167 {
168 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_mass_matrix");
169
170 // Assemble the mass matrix.
171 mass_assembly_vals_cache.init(
172 is_volume(), bases, /*gbases=*/bases, /*is_mass=*/true);
173 assert(mass_matrix_assembler != nullptr);
174 mass_matrix_assembler->assemble(
175 is_volume(), n_bases(), bases, /*gbases=*/bases,
176 mass_assembly_vals_cache,
177 /*t=*/0, // TODO: time-dependent mass matrix
178 mass, /*is_mass=*/true);
179
180 // Set the mass of the codimensional fixed vertices to the average mass.
181 const int local_ndof = dim() * local_mesh.num_local_vertices();
182 for (int i = local_ndof; i < ndof(); ++i)
183 mass.coeffRef(i, i) = state.avg_mass;
184 }
185
186 template <typename M>
188 const State &state,
189 const double current_time,
190 const bool contact_enabled)
191 {
192 // Current solution.
193 const Eigen::MatrixXd target_x = this->sol();
194
195 // Assemble the stiffness matrix.
196 assembly_vals_cache.init(is_volume(), bases, /*gbases=*/bases, /*is_mass=*/false);
197
198 // Create collision mesh.
199 if (contact_enabled)
200 {
201 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_solve_data -> create collision mesh");
202
203 collision_mesh = ipc::CollisionMesh::build_from_full_mesh(
204 local_mesh.rest_positions(), local_mesh.boundary_edges(),
205 local_mesh.boundary_faces());
206
207 // Ignore all collisions between fixed elements.
208 std::vector<bool> is_vertex_fixed(local_mesh.num_vertices(), false);
209 for (const int vi : local_mesh.fixed_vertices())
210 is_vertex_fixed[vi] = true;
211 collision_mesh.can_collide = [is_vertex_fixed, this](size_t vi, size_t vj) {
212 return !is_vertex_fixed[this->collision_mesh.to_full_vertex_id(vi)]
213 || !is_vertex_fixed[this->collision_mesh.to_full_vertex_id(vj)];
214 };
215 }
216
217 // Initialize time integrator
218 if (state.problem->is_time_dependent())
219 {
220 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_solve_data -> create time integrator");
221 solve_data.time_integrator =
223 state.args["time"]["integrator"]);
224 Eigen::MatrixXd x_prevs, v_prevs, a_prevs;
226 local_mesh.projection_quantities(), dim(), x_prevs, v_prevs, a_prevs);
227 solve_data.time_integrator->init(
228 x_prevs, v_prevs, a_prevs, state.args["time"]["dt"]);
229 }
230
231 // Initialize solve_data.rhs_assembler
232 {
233 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_solve_data -> create RHS assembler");
234
235 json rhs_solver_params = state.args["solver"]["linear"];
236 if (!rhs_solver_params.contains("Pardiso"))
237 rhs_solver_params["Pardiso"] = {};
238 rhs_solver_params["Pardiso"]["mtype"] = -2; // matrix type for Pardiso (2 = SPD)
239
240 const int size = state.problem->is_scalar() ? 1 : dim();
241 solve_data.rhs_assembler = std::make_shared<assembler::RhsAssembler>(
242 *assembler, *mesh, Obstacle(), dirichlet_nodes, neumann_nodes,
243 dirichlet_nodes_position, neumann_nodes_position, n_bases(),
244 dim(), bases, /*geom_bases=*/bases, mass_assembly_vals_cache,
245 *state.problem, state.args["space"]["advanced"]["bc_method"],
246 rhs_solver_params);
247
248 solve_data.rhs_assembler->assemble(mass_matrix_assembler->density(), rhs);
249 rhs *= -1;
250 }
251
252 std::vector<std::shared_ptr<solver::Form>> forms;
253 {
254 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_solve_data -> init forms");
255 forms = solve_data.init_forms(
256 // General
257 state.units, dim(), current_time,
258 // Elastic form
259 n_bases(), bases, /*geom_bases=*/bases, *assembler,
260 assembly_vals_cache, assembly_vals_cache,
261 // Body form
262 /*n_pressure_bases=*/0, boundary_nodes, local_boundary,
263 local_neumann_boundary, state.n_boundary_samples(), rhs,
264 target_x, mass_matrix_assembler->density(),
265 // Pressure form
266 local_pressure_boundary, local_pressure_cavity, pressure_assembler,
267 // Inertia form
268 state.args.value("/time/quasistatic"_json_pointer, true), mass,
269 /*damping_assembler=*/nullptr,
270 // Lagged regularization form
271 state.args["solver"]["advanced"]["lagged_regularization_weight"],
272 state.args["solver"]["advanced"]["lagged_regularization_iterations"],
273 // Augmented lagrangian form
274 /*obstacle_ndof=*/0,
275 // Contact form
276 contact_enabled, collision_mesh, state.args["contact"]["dhat"],
277 state.avg_mass, state.args["contact"]["use_convergent_formulation"],
278 contact_enabled ? state.solve_data.contact_form->barrier_stiffness() : 0,
279 state.args["solver"]["contact"]["CCD"]["broad_phase"],
280 state.args["solver"]["contact"]["CCD"]["tolerance"],
281 state.args["solver"]["contact"]["CCD"]["max_iterations"],
282 /*enable_shape_derivatives=*/false,
283 // Homogenization
285 // Periodic contact
286 /*periodic_contact=*/false, /*tiled_to_single=*/Eigen::VectorXi(),
287 // Friction form
288 state.args["contact"]["friction_coefficient"],
289 state.args["contact"]["epsv"],
290 state.args["solver"]["contact"]["friction_iterations"],
291 // Rayleigh damping form
292 state.args["solver"]["rayleigh_damping"]);
293
294 // Remove AL forms because we do not need them in the remeshing process.
295 forms.erase(std::remove(forms.begin(), forms.end(), solve_data.al_lagr_form), forms.end());
296 forms.erase(std::remove(forms.begin(), forms.end(), solve_data.al_pen_form), forms.end());
297 solve_data.al_lagr_form = nullptr;
298 solve_data.al_pen_form = nullptr;
299 }
300
301 solve_data.nl_problem = std::make_shared<polyfem::solver::StaticBoundaryNLProblem>(
302 ndof(), boundary_nodes, target_x, forms);
303
304 assert(solve_data.time_integrator != nullptr);
305 solve_data.nl_problem->update_quantities(current_time, solve_data.time_integrator->x_prev());
306 solve_data.nl_problem->init(target_x);
307 solve_data.nl_problem->init_lagging(solve_data.time_integrator->x_prev());
308 solve_data.nl_problem->update_lagging(target_x, /*iter_num=*/0);
309 }
310
311 // -------------------------------------------------------------------------
312 // Template instantiations
315} // namespace polyfem::mesh
#define POLYFEM_REMESHER_SCOPED_TIMER(name)
Definition Remesher.hpp:15
main class that contains the polyfem solver and all its state
Definition State.hpp:79
std::string formulation() const
return the formulation (checks if the problem is scalar or not and deals with multiphysics)
Definition State.cpp:328
int n_boundary_samples() const
quadrature used for projecting boundary conditions
Definition State.hpp:263
mesh::Obstacle obstacle
Obstacles used in collisions.
Definition State.hpp:468
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
Definition State.hpp:168
json args
main input arguments containing all defaults
Definition State.hpp:101
double avg_mass
average system mass, used for contact with IPC
Definition State.hpp:204
solver::SolveData solve_data
timedependent stuff cached
Definition State.hpp:324
static std::shared_ptr< Assembler > make_assembler(const std::string &formulation)
void init_solve_data(const State &state, const double current_time, const bool contact_enabled)
LocalRelaxationData(const State &state, LocalMesh< M > &local_mesh, const double current_time, const bool contact_enabled)
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
void init_boundary_conditions(const State &state)
static std::unique_ptr< Mesh > create(const std::string &path, const bool non_conforming=false)
factory to build the proper mesh
Definition Mesh.cpp:173
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)
Definition Remesher.cpp:254
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.
Definition Remesher.cpp:396
std::shared_ptr< solver::ContactForm > contact_form
static std::shared_ptr< ImplicitTimeIntegrator > construct_time_integrator(const json &params)
Factory method for constructing implicit time integrators from the name of the integrator.
bool is_param_valid(const json &params, const std::string &key)
Determine if a key exists and is non-null in a json object.
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:71