PolyFEM
Loading...
Searching...
No Matches
SolveData.cpp
Go to the documentation of this file.
1#include "SolveData.hpp"
2
29
30#include <h5pp/h5pp.h>
31
32namespace polyfem::solver
33{
34 using namespace polyfem::time_integrator;
35
36 std::vector<std::shared_ptr<Form>> SolveData::init_forms(
37 // General
38 const Units &units,
39 const int dim,
40 const double t,
41 const Eigen::VectorXi &in_node_to_node,
42
43 // Elastic form
44 const int n_bases,
45 std::vector<basis::ElementBases> &bases,
46 const std::vector<basis::ElementBases> &geom_bases,
47 const assembler::Assembler &assembler,
48 assembler::AssemblyValsCache &ass_vals_cache,
49 const assembler::AssemblyValsCache &mass_ass_vals_cache,
50 const double jacobian_threshold,
51 const ElementInversionCheck check_inversion,
52 const unsigned conservative_max_iter,
53
54 // Body form
55 const int n_pressure_bases,
56 const std::vector<int> &boundary_nodes,
57 const std::vector<mesh::LocalBoundary> &local_boundary,
58 const std::vector<mesh::LocalBoundary> &local_neumann_boundary,
59 const QuadratureOrders &n_boundary_samples,
60 const Eigen::MatrixXd &rhs,
61 const Eigen::MatrixXd &sol,
62 const assembler::Density &density,
63
64 // Pressure form
65 const std::vector<mesh::LocalBoundary> &local_pressure_boundary,
66 const std::unordered_map<int, std::vector<mesh::LocalBoundary>> &local_pressure_cavity,
67 const std::shared_ptr<assembler::PressureAssembler> pressure_assembler,
68
69 // Inertia form
70 const bool ignore_inertia,
71 const StiffnessMatrix &mass,
72 const std::shared_ptr<assembler::ViscousDamping> damping_assembler,
73
74 // Lagged regularization form
75 const double lagged_regularization_weight,
76 const int lagged_regularization_iterations,
77
78 // Augemented lagrangian form
79 const size_t obstacle_ndof,
80 const std::vector<std::string> &hard_constraint_files,
81 const std::vector<json> &soft_constraint_files,
82
83 // Contact form
84 const bool contact_enabled,
85 const ipc::CollisionMesh &collision_mesh,
86 const double dhat,
87 const double avg_mass,
88 const bool use_area_weighting,
89 const bool use_improved_max_operator,
90 const bool use_physical_barrier,
91 const json &barrier_stiffness,
92 const double initial_barrier_stiffness,
93 const ipc::BroadPhaseMethod broad_phase,
94 const double ccd_tolerance,
95 const long ccd_max_iterations,
96 const bool enable_shape_derivatives,
97
98 // Smooth Contact Form
99 const bool use_gcp_formulation,
100 const double alpha_t,
101 const double alpha_n,
102 const bool use_adaptive_dhat,
103 const double min_distance_ratio,
104
105 // Normal Adhesion Form
106 const bool adhesion_enabled,
107 const double dhat_p,
108 const double dhat_a,
109 const double Y,
110
111 // Tangential Adhesion Form
112 const double tangential_adhesion_coefficient,
113 const double epsa,
114 const int tangential_adhesion_iterations,
115
116 // Homogenization
117 const assembler::MacroStrainValue &macro_strain_constraint,
118
119 // Periodic contact
120 const bool periodic_contact,
121 const Eigen::VectorXi &tiled_to_single,
122 const std::shared_ptr<utils::PeriodicBoundary> &periodic_bc,
123
124 // Friction form
125 const double friction_coefficient,
126 const double epsv,
127 const int friction_iterations,
128
129 // Rayleigh damping form
130 const json &rayleigh_damping)
131 {
132 const bool is_time_dependent = time_integrator != nullptr;
133 assert(!is_time_dependent || time_integrator != nullptr);
134 const double dt = is_time_dependent ? time_integrator->dt() : 0.0;
135 const int ndof = n_bases * dim;
136 // if (is_formulation_mixed) // mixed not supported
137 // ndof_ += n_pressure_bases; // pressure is a scalar
138 const bool is_volume = dim == 3;
139
140 std::vector<std::shared_ptr<Form>> forms;
141 al_form.clear();
142
143 elastic_form = std::make_shared<ElasticForm>(
144 n_bases, bases, geom_bases, assembler, ass_vals_cache,
145 t, dt, is_volume, jacobian_threshold, check_inversion, conservative_max_iter);
146 forms.push_back(elastic_form);
147
148 if (rhs_assembler != nullptr)
149 {
150 body_form = std::make_shared<BodyForm>(
151 ndof, n_pressure_bases, boundary_nodes, local_boundary,
152 local_neumann_boundary, n_boundary_samples, rhs, *rhs_assembler,
153 density, /*is_formulation_mixed=*/false,
154 is_time_dependent);
155 body_form->update_quantities(t, sol);
156 forms.push_back(body_form);
157 }
158
159 if (pressure_assembler != nullptr)
160 {
161 pressure_form = std::make_shared<PressureForm>(
162 ndof,
163 local_pressure_boundary,
164 local_pressure_cavity,
165 boundary_nodes,
166 n_boundary_samples, *pressure_assembler,
167 is_time_dependent);
168 pressure_form->update_quantities(t, sol);
169 forms.push_back(pressure_form);
170 }
171
172 inertia_form = nullptr;
173 damping_form = nullptr;
174 if (is_time_dependent)
175 {
176 if (!ignore_inertia)
177 {
178 assert(time_integrator != nullptr);
179 inertia_form = std::make_shared<InertiaForm>(mass, *time_integrator);
180 forms.push_back(inertia_form);
181 }
182
183 if (damping_assembler != nullptr)
184 {
185 damping_form = std::make_shared<ElasticForm>(
186 n_bases, bases, geom_bases, *damping_assembler, ass_vals_cache, t, dt, is_volume,
187 0., ElementInversionCheck::Discrete, conservative_max_iter);
188 forms.push_back(damping_form);
189 }
190 }
191 else
192 {
193 if (lagged_regularization_weight > 0)
194 {
195 forms.push_back(std::make_shared<LaggedRegForm>(lagged_regularization_iterations));
196 forms.back()->set_weight(lagged_regularization_weight);
197 }
198 }
199
200 if (rhs_assembler != nullptr)
201 {
202 // assembler::Mass mass_mat_assembler;
203 // mass_mat_assembler.set_size(dim);
204 StiffnessMatrix mass_tmp = mass;
205 // mass_mat_assembler.assemble(dim == 3, n_bases, bases, geom_bases, mass_ass_vals_cache, mass_tmp, true);
206 // assert(mass_tmp.rows() == mass.rows() && mass_tmp.cols() == mass.cols());
207
208 if (!boundary_nodes.empty())
209 al_form.push_back(std::make_shared<BCLagrangianForm>(
210 ndof, boundary_nodes, local_boundary, local_neumann_boundary,
211 n_boundary_samples, mass_tmp, *rhs_assembler, obstacle_ndof, is_time_dependent, t));
212 // forms.push_back(al_form.back());
213 }
214
215 if (periodic_bc != nullptr)
216 {
217 al_form.push_back(std::make_shared<PeriodicLagrangianForm>(ndof, periodic_bc));
218 }
219
220 for (const auto &path : hard_constraint_files)
221 {
222 logger().debug("Setting up hard constraints for {}", path);
223 h5pp::File file(path, h5pp::FileAccess::READONLY);
224 std::vector<int> local2global;
225 if (!file.findDatasets("local2global").empty())
226 local2global = file.readDataset<std::vector<int>>("local2global");
227
228 if (local2global.empty())
229 {
230 local2global.resize(in_node_to_node.size());
231
232 for (int i = 0; i < local2global.size(); ++i)
233 local2global[i] = in_node_to_node[i];
234 }
235 else
236 {
237 for (auto &v : local2global)
238 v = in_node_to_node[v];
239 }
240
241 Eigen::MatrixXd bin = file.readDataset<Eigen::MatrixXd>("b");
242
243 StiffnessMatrix A, A_proj;
244 Eigen::MatrixXd b, b_proj;
245
246 if (!file.findDatasets("A").empty())
247 {
248 Eigen::MatrixXd Ain = file.readDataset<Eigen::MatrixXd>("A");
249 utils::scatter_matrix(ndof, dim, Ain, bin, local2global, A, b);
250
251 if (!file.findDatasets("A_proj").empty())
252 {
253 Eigen::MatrixXd A_proj_in = file.readDataset<Eigen::MatrixXd>("A_proj");
254 if (file.findDatasets("b_proj").empty())
255 log_and_throw_error("Missing b_proj in hard constraint file");
256
257 Eigen::MatrixXd b_proj_in = file.readDataset<Eigen::MatrixXd>("b_proj");
258 utils::scatter_matrix_col(ndof, dim, A_proj_in, b_proj_in, local2global, A_proj, b_proj);
259 }
260 }
261 else
262 {
263 std::vector<double> values = file.readDataset<std::vector<double>>("A_triplets/values");
264 std::vector<int> rows = file.readDataset<std::vector<int>>("A_triplets/rows");
265 std::vector<int> cols = file.readDataset<std::vector<int>>("A_triplets/cols");
266 std::vector<long> shape = file.readDataset<std::vector<long>>("A_triplets/shape");
267 utils::scatter_matrix(ndof, dim, shape, rows, cols, values, bin, local2global, A, b);
268
269 if (!file.findGroups("A_proj_triplets").empty())
270 {
271 if (file.findDatasets("b_proj").empty())
272 log_and_throw_error("Missing b_proj in hard constraint file");
273 if (file.findDatasets("rows", "/A_proj_triplets").empty())
274 log_and_throw_error("Missing A_proj_triplets/rows in hard constraint file");
275 if (file.findDatasets("cols", "/A_proj_triplets").empty())
276 log_and_throw_error("Missing A_proj_triplets/cols in hard constraint file");
277 if (file.findDatasets("values", "/A_proj_triplets").empty())
278 log_and_throw_error("Missing A_proj_triplets/values in hard constraint file");
279
280 std::vector<double> values_proj = file.readDataset<std::vector<double>>("A_proj_triplets/values");
281 std::vector<int> rows_proj = file.readDataset<std::vector<int>>("A_proj_triplets/rows");
282 std::vector<int> cols_proj = file.readDataset<std::vector<int>>("A_proj_triplets/cols");
283 Eigen::MatrixXd b_projin = file.readDataset<Eigen::MatrixXd>("b_proj");
284 std::vector<long> shape_proj = file.readDataset<std::vector<long>>("A_proj_triplets/shape");
285
286 utils::scatter_matrix_col(ndof, dim, shape_proj, rows_proj, cols_proj, values_proj, b_projin, local2global, A_proj, b_proj);
287 }
288 }
289
290 al_form.push_back(std::make_shared<MatrixLagrangianForm>(A, b, A_proj, b_proj));
291 // forms.push_back(al_form.back());
292 }
293
294 for (const auto &j : soft_constraint_files)
295 {
296 const std::string &path = j["data"];
297 double weight = j["weight"];
298
299 logger().debug("Setting up soft constraints for {}", path);
300 h5pp::File file(path, h5pp::FileAccess::READONLY);
301 std::vector<int> local2global;
302 if (!file.findDatasets("local2global").empty())
303 local2global = file.readDataset<std::vector<int>>("local2global");
304
305 if (local2global.empty())
306 {
307 local2global.resize(in_node_to_node.size());
308
309 for (int i = 0; i < local2global.size(); ++i)
310 local2global[i] = in_node_to_node[i];
311 }
312 else
313 {
314 for (auto &v : local2global)
315 v = in_node_to_node[v];
316 }
317
318 Eigen::MatrixXd bin = file.readDataset<Eigen::MatrixXd>("b");
319
321 Eigen::MatrixXd b;
322
323 if (!file.findDatasets("A").empty())
324 {
325 Eigen::MatrixXd Ain = file.readDataset<Eigen::MatrixXd>("A");
326 utils::scatter_matrix(ndof, dim, Ain, bin, local2global, A, b);
327 }
328 else
329 {
330 std::vector<double> values = file.readDataset<std::vector<double>>("A_triplets/values");
331 std::vector<int> rows = file.readDataset<std::vector<int>>("A_triplets/rows");
332 std::vector<int> cols = file.readDataset<std::vector<int>>("A_triplets/cols");
333 std::vector<long> shape = file.readDataset<std::vector<long>>("A_triplets/shape");
334
335 utils::scatter_matrix(ndof, dim, shape, rows, cols, values, bin, local2global, A, b);
336 }
337
338 forms.push_back(std::make_shared<QuadraticPenaltyForm>(A, b, weight));
339 }
340
341 if (macro_strain_constraint.is_active())
342 {
343 // don't push these two into forms because they take a different input x
344 strain_al_lagr_form = std::make_shared<MacroStrainLagrangianForm>(macro_strain_constraint);
345 }
346
347 contact_form = nullptr;
348 periodic_contact_form = nullptr;
349 friction_form = nullptr;
350 if (contact_enabled)
351 {
352 const bool use_adaptive_barrier_stiffness = !barrier_stiffness.is_number();
353
354 if (periodic_contact)
355 {
356 periodic_contact_form = std::make_shared<PeriodicContactForm>(
357 collision_mesh, tiled_to_single, dhat, avg_mass, use_area_weighting, use_improved_max_operator, use_physical_barrier,
358 use_adaptive_barrier_stiffness, is_time_dependent, enable_shape_derivatives, broad_phase, ccd_tolerance,
359 ccd_max_iterations);
360
361 if (use_adaptive_barrier_stiffness)
362 {
363 periodic_contact_form->set_barrier_stiffness(1);
364 // logger().debug("Using adaptive barrier stiffness");
365 }
366 else
367 {
368 assert(barrier_stiffness.is_number());
369 assert(barrier_stiffness.get<double>() > 0);
370 periodic_contact_form->set_barrier_stiffness(barrier_stiffness);
371 // logger().debug("Using fixed barrier stiffness of {}", contact_form->barrier_stiffness());
372 }
373
374 // periodic_contact_form is not pushed into forms since it takes different input vectors.
375 }
376 else
377 {
378 if (use_gcp_formulation)
379 {
380 contact_form = std::make_shared<SmoothContactForm>(
381 collision_mesh, dhat, avg_mass, alpha_t, alpha_n, use_adaptive_dhat, min_distance_ratio,
382 use_adaptive_barrier_stiffness, is_time_dependent, enable_shape_derivatives, broad_phase,
383 ccd_tolerance * units.characteristic_length(), ccd_max_iterations);
384 }
385 else
386 {
387 contact_form = std::make_shared<BarrierContactForm>(
388 collision_mesh, dhat, avg_mass, use_area_weighting, use_improved_max_operator, use_physical_barrier,
389 use_adaptive_barrier_stiffness, is_time_dependent, enable_shape_derivatives, broad_phase, ccd_tolerance * units.characteristic_length(),
390 ccd_max_iterations);
391 }
392
393 if (use_adaptive_barrier_stiffness)
394 {
395 contact_form->set_barrier_stiffness(initial_barrier_stiffness);
396 // logger().debug("Using adaptive barrier stiffness");
397 }
398 else
399 {
400 assert(barrier_stiffness.is_number());
401 assert(barrier_stiffness.get<double>() > 0);
402 contact_form->set_barrier_stiffness(barrier_stiffness);
403 // logger().debug("Using fixed barrier stiffness of {}", contact_form->barrier_stiffness());
404 }
405
406 forms.push_back(contact_form);
407 }
408
409 if (friction_coefficient != 0)
410 {
411 friction_form = std::make_shared<FrictionForm>(
412 collision_mesh, time_integrator, epsv, friction_coefficient,
413 broad_phase, *contact_form, friction_iterations);
414 friction_form->init_lagging(sol);
415 forms.push_back(friction_form);
416 }
417
418 if (adhesion_enabled)
419 {
420 normal_adhesion_form = std::make_shared<NormalAdhesionForm>(
421 collision_mesh, dhat_p, dhat_a, Y, is_time_dependent, enable_shape_derivatives,
422 broad_phase, ccd_tolerance * units.characteristic_length(), ccd_max_iterations);
423 forms.push_back(normal_adhesion_form);
424
425 if (tangential_adhesion_coefficient != 0)
426 {
427 tangential_adhesion_form = std::make_shared<TangentialAdhesionForm>(
428 collision_mesh, time_integrator, epsa, tangential_adhesion_coefficient,
429 broad_phase, *normal_adhesion_form, tangential_adhesion_iterations);
430 forms.push_back(tangential_adhesion_form);
431 }
432 }
433 }
434
435 const std::vector<json> rayleigh_damping_jsons = utils::json_as_array(rayleigh_damping);
436 if (is_time_dependent)
437 {
438 // Map from form name to form so RayleighDampingForm::create can get the correct form to damp
439 const std::unordered_map<std::string, std::shared_ptr<Form>> possible_forms_to_damp = {
440 {"elasticity", elastic_form},
441 {"contact", contact_form},
442 };
443
444 for (const json &params : rayleigh_damping_jsons)
445 {
446 forms.push_back(RayleighDampingForm::create(
447 params, possible_forms_to_damp,
449 }
450 }
451 else if (rayleigh_damping_jsons.size() > 0)
452 {
453 log_and_throw_adjoint_error("Rayleigh damping is only supported for time-dependent problems");
454 }
455
456 update_dt();
457
458 return forms;
459 }
460
461 void SolveData::update_barrier_stiffness(const Eigen::VectorXd &x)
462 {
463 if (contact_form == nullptr || !contact_form->use_adaptive_barrier_stiffness())
464 return;
465
466 Eigen::VectorXd grad_energy = Eigen::VectorXd::Zero(x.size());
467 const std::array<std::shared_ptr<Form>, 4> energy_forms{
469 for (const std::shared_ptr<Form> &form : energy_forms)
470 {
471 if (form == nullptr || !form->enabled())
472 continue;
473
474 Eigen::VectorXd grad_form;
475 form->first_derivative(x, grad_form);
476 grad_energy += grad_form;
477 }
478
479 contact_form->update_barrier_stiffness(x, grad_energy);
480 }
481
483 {
484 if (time_integrator == nullptr) // if is not time dependent
485 return;
486
487 const std::array<std::shared_ptr<Form>, 6> energy_forms{
489 for (const std::shared_ptr<Form> &form : energy_forms)
490 {
491 if (form == nullptr)
492 continue;
493 form->set_weight(time_integrator->acceleration_scaling());
494 }
495 }
496
497 std::vector<std::pair<std::string, std::shared_ptr<solver::Form>>> SolveData::named_forms() const
498 {
499 std::vector<std::pair<std::string, std::shared_ptr<solver::Form>>> res{
500 {"elastic", elastic_form},
501 {"inertia", inertia_form},
502 {"body", body_form},
503 {"contact", contact_form},
504 {"friction", friction_form},
505 {"damping", damping_form},
506 {"pressure", pressure_form},
507 {"strain_augmented_lagrangian_lagr", strain_al_lagr_form},
508 {"periodic_contact", periodic_contact_form},
509 };
510
511 for (const auto &form : al_form)
512 res.push_back({"augmented_lagrangian", form});
513
514 return res;
515 }
516} // namespace polyfem::solver
int x
double characteristic_length() const
Definition Units.hpp:22
Caches basis evaluation and geometric mapping at every element.
static std::shared_ptr< RayleighDampingForm > create(const json &params, const std::unordered_map< std::string, std::shared_ptr< Form > > &forms, const time_integrator::ImplicitTimeIntegrator &time_integrator)
std::shared_ptr< solver::FrictionForm > friction_form
std::shared_ptr< solver::InertiaForm > inertia_form
std::shared_ptr< solver::PeriodicContactForm > periodic_contact_form
void update_dt()
updates the dt inside the different forms
std::shared_ptr< solver::PressureForm > pressure_form
std::shared_ptr< solver::BodyForm > body_form
std::shared_ptr< solver::MacroStrainLagrangianForm > strain_al_lagr_form
std::shared_ptr< solver::NormalAdhesionForm > normal_adhesion_form
std::shared_ptr< solver::ContactForm > contact_form
std::vector< std::shared_ptr< Form > > init_forms(const Units &units, const int dim, const double t, const Eigen::VectorXi &in_node_to_node, const int n_bases, std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &geom_bases, const assembler::Assembler &assembler, assembler::AssemblyValsCache &ass_vals_cache, const assembler::AssemblyValsCache &mass_ass_vals_cache, const double jacobian_threshold, const solver::ElementInversionCheck check_inversion, const unsigned conservative_max_iter, const int n_pressure_bases, const std::vector< int > &boundary_nodes, const std::vector< mesh::LocalBoundary > &local_boundary, const std::vector< mesh::LocalBoundary > &local_neumann_boundary, const QuadratureOrders &n_boundary_samples, const Eigen::MatrixXd &rhs, const Eigen::MatrixXd &sol, const assembler::Density &density, const std::vector< mesh::LocalBoundary > &local_pressure_boundary, const std::unordered_map< int, std::vector< mesh::LocalBoundary > > &local_pressure_cavity, const std::shared_ptr< assembler::PressureAssembler > pressure_assembler, const bool ignore_inertia, const StiffnessMatrix &mass, const std::shared_ptr< assembler::ViscousDamping > damping_assembler, const double lagged_regularization_weight, const int lagged_regularization_iterations, const size_t obstacle_ndof, const std::vector< std::string > &hard_constraint_files, const std::vector< json > &soft_constraint_files, const bool contact_enabled, const ipc::CollisionMesh &collision_mesh, const double dhat, const double avg_mass, const bool use_area_weighting, const bool use_improved_max_operator, const bool use_physical_barrier, const json &barrier_stiffness, const double initial_barrier_stiffness, const ipc::BroadPhaseMethod broad_phase, const double ccd_tolerance, const long ccd_max_iterations, const bool enable_shape_derivatives, const bool use_gcp_formulation, const double alpha_t, const double alpha_n, const bool use_adaptive_dhat, const double min_distance_ratio, const bool adhesion_enabled, const double dhat_p, const double dhat_a, const double Y, const double tangential_adhesion_coefficient, const double epsa, const int tangential_adhesion_iterations, const assembler::MacroStrainValue &macro_strain_constraint, const bool periodic_contact, const Eigen::VectorXi &tiled_to_single, const std::shared_ptr< utils::PeriodicBoundary > &periodic_bc, const double friction_coefficient, const double epsv, const int friction_iterations, const json &rayleigh_damping)
Initialize the forms and return a vector of pointers to them.
Definition SolveData.cpp:36
std::vector< std::pair< std::string, std::shared_ptr< solver::Form > > > named_forms() const
std::shared_ptr< solver::ElasticForm > damping_form
std::shared_ptr< solver::ElasticForm > elastic_form
std::vector< std::shared_ptr< solver::AugmentedLagrangianForm > > al_form
std::shared_ptr< time_integrator::ImplicitTimeIntegrator > time_integrator
void update_barrier_stiffness(const Eigen::VectorXd &x)
update the barrier stiffness for the forms
std::shared_ptr< solver::TangentialAdhesionForm > tangential_adhesion_form
std::shared_ptr< assembler::PressureAssembler > pressure_assembler
std::shared_ptr< assembler::RhsAssembler > rhs_assembler
void scatter_matrix(const int n_dofs, const int dim, const Eigen::MatrixXd &A, const Eigen::MatrixXd &b, const std::vector< int > &local_to_global, StiffnessMatrix &Aout, Eigen::MatrixXd &bout)
std::vector< T > json_as_array(const json &j)
Return the value of a json object as an array.
Definition JSONUtils.hpp:38
void scatter_matrix_col(const int n_dofs, const int dim, const Eigen::MatrixXd &A, const Eigen::MatrixXd &b, const std::vector< int > &local_to_global, StiffnessMatrix &Aout, Eigen::MatrixXd &bout)
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
std::array< int, 2 > QuadratureOrders
Definition Types.hpp:19
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:79
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24