PolyFEM
Loading...
Searching...
No Matches
DifferentiableNonlinearElasticVarForm.cpp
Go to the documentation of this file.
2
15
16#include <igl/Timer.h>
17
18#include <polysolve/linear/Solver.hpp>
19#include <polysolve/nonlinear/Solver.hpp>
20
21namespace polyfem::varform
22{
24 Eigen::MatrixXd &solution,
25 const InitialConditionOverride *initial_condition_override,
26 const ForwardStepCallback &post_step,
27 const bool differentiable)
28 {
29 differentiable_mode_ = differentiable;
30 NonlinearElasticVarForm::solve(solution, initial_condition_override, post_step);
31 }
32
37
39 const std::string &path,
40 const Eigen::MatrixXd &solution,
41 const double time,
42 const double dt) const
43 {
46 const auto opts = NonlinearElasticVarForm::export_options(space);
48 path, space, NonlinearElasticVarForm::output_field_function(solution, opts), time, dt, opts);
49 }
50
53
55 {
56 assert(mesh_ && "The mesh must be loaded before it is accessed");
57 return *mesh_;
58 }
59
61 {
62 assert(problem && "The problem must be initialized before it is accessed");
63 return *problem;
64 }
65
67 {
68 assert(problem && "The problem must be initialized before it is accessed");
69 return *problem;
70 }
71
73
74 std::string DifferentiableNonlinearElasticVarForm::input_path(const std::string &path, const bool only_if_exists) const
75 {
76 return NonlinearElasticVarForm::resolve_input_path(path, only_if_exists);
77 }
78
79 std::string DifferentiableNonlinearElasticVarForm::output_file_path(const std::string &path) const
80 {
82 }
83
86
89
91 {
92 assert(primary_assembler_ && "The primary assembler must be initialized before it is accessed");
93 return *primary_assembler_;
94 }
95
97 {
98 assert(mass_assembler_ && "The mass assembler must be initialized before it is accessed");
99 return *mass_assembler_;
100 }
101
107 const ipc::CollisionMesh &DifferentiableNonlinearElasticVarForm::collision_mesh() const { return collision_mesh_; }
109
114
119
121 Eigen::MatrixXd &solution,
122 const InitialConditionOverride *override) const
123 {
125 }
126
128 Eigen::MatrixXd &velocity,
129 const InitialConditionOverride *override) const
130 {
132 }
133
135 Eigen::MatrixXd &acceleration,
136 const InitialConditionOverride *override) const
137 {
138 NonlinearElasticVarForm::initial_acceleration(acceleration, override);
139 }
140
147
149 {
150 assert(mesh_ && "Vertex positions can only be updated after loading a mesh");
151 return *mesh_;
152 }
153
167
180
182 const int discr_order,
183 const int discr_orderq,
184 const int geometry_discr_order) const
185 {
186 return NonlinearElasticVarForm::n_boundary_samples(discr_order, discr_orderq, geometry_discr_order);
187 }
188
189 // The differentiable path matches NonlinearElasticVarForm::init_forms except
190 // that it enables IPC shape derivatives when constructing the contact forms.
192 const json &args,
193 const int dim,
194 Eigen::MatrixXd &solution,
195 const double time)
196 {
198 {
199 NonlinearElasticVarForm::init_forms(args, dim, solution, time);
200 return;
201 }
202
203 damping_assembler_ = std::make_shared<assembler::ViscousDamping>();
204 set_materials(*damping_assembler_, mesh_->dimension());
205
207
208 damping_prev_assembler_ = std::make_shared<assembler::ViscousDampingPrev>();
210
211 const solver::ElementInversionCheck check_inversion = args["solver"]["advanced"]["check_inversion"];
212
214 units,
215 dim, time, space_.space_in_node_to_node,
216 space_.n_bases, *space_.bases, space_.geometry_basis_list(), *primary_assembler_, ass_vals_cache_, mass_ass_vals_cache_, args["solver"]["advanced"]["jacobian_threshold"], check_inversion,
217 args["solver"]["advanced"]["conservative_max_iter"],
220 elastic_boundary_samples(), rhs_, solution, mass_assembler_->density(),
222 args.value("/time/quasistatic"_json_pointer, true), mass_,
223 damping_assembler_->is_valid() ? damping_assembler_ : nullptr,
224 args["solver"]["advanced"]["lagged_regularization_weight"],
225 args["solver"]["advanced"]["lagged_regularization_iterations"],
226 obstacle.ndof(), args["constraints"]["hard"], args["constraints"]["soft"], args["constraints"]["zero_mean"],
227 args["contact"]["enabled"],
228 args["contact"]["periodic"] ? periodic_collision_mesh_ : collision_mesh_,
229 args["contact"]["dhat"],
230 avg_mass_, args["contact"]["use_convergent_formulation"] ? bool(args["contact"]["use_area_weighting"]) : false,
231 args["contact"]["use_convergent_formulation"] ? bool(args["contact"]["use_improved_max_operator"]) : false,
232 args["contact"]["use_convergent_formulation"] ? bool(args["contact"]["use_physical_barrier"]) : false,
233 args["solver"]["contact"]["barrier_stiffness"],
234 args["solver"]["contact"]["initial_barrier_stiffness"],
235 args["solver"]["contact"]["CCD"]["broad_phase"],
236 args["solver"]["contact"]["CCD"]["tolerance"],
237 args["solver"]["contact"]["CCD"]["max_iterations"],
238 true,
239 args["contact"]["use_gcp_formulation"],
240 args["contact"]["alpha_t"],
241 args["contact"]["alpha_n"],
242 args["contact"]["use_adaptive_dhat"],
243 args["contact"]["min_distance_ratio"],
244 args["contact"]["adhesion"]["adhesion_enabled"],
245 args["contact"]["adhesion"]["dhat_p"],
246 args["contact"]["adhesion"]["dhat_a"],
247 args["contact"]["adhesion"]["adhesion_strength"],
248 args["contact"]["adhesion"]["tangential_adhesion_coefficient"],
249 args["contact"]["adhesion"]["epsa"],
250 args["solver"]["contact"]["tangential_adhesion_iterations"],
252 args["contact"]["periodic"], periodic_collision_mesh_to_basis_,
253 args["contact"]["friction_coefficient"],
254 args["contact"]["epsv"],
255 args["solver"]["contact"]["friction_iterations"],
256 args["solver"]["rayleigh_damping"],
257 args["solver"]["augmented_lagrangian"]["lumping"],
259 args["boundary_conditions"]["periodic"], /*fe_space_id=*/-1);
260
261 for (const auto &form : forms)
262 form->set_output_dir(output_path);
263
264 if (solve_data_.contact_form != nullptr)
265 solve_data_.contact_form->save_ccd_debug_meshes = args["output"]["advanced"]["save_ccd_debug_meshes"];
266 }
267
268 // The differentiable path performs the initial nonlinear solve but skips the
269 // subsequent lagging iterations. The adjoint uses the forms frozen at that
270 // solution instead of differentiating through the lagging update loop.
272 const int step,
273 Eigen::MatrixXd &solution,
274 const bool init_lagging)
275 {
277 {
278 NonlinearElasticVarForm::solve_tensor_nonlinear(step, solution, init_lagging);
279 return;
280 }
281
282 assert(solve_data_.nl_problem != nullptr && "Nonlinear forms must initialize the nonlinear problem before solving");
284 assert(solution.size() == rhs_.size());
285
286 if (nl_problem.uses_lagging())
287 {
288 if (init_lagging)
289 {
290 POLYFEM_SCOPED_TIMER("Initializing lagging");
291 nl_problem.init_lagging(solution);
292 }
293 logger().info("Lagging iteration 1:");
294 }
295
296 save_subsolve(0, step, solution);
297
298 std::shared_ptr<polysolve::nonlinear::Solver> nl_solver =
299 polysolve::nonlinear::Solver::create(
300 args["solver"]["augmented_lagrangian"]["nonlinear"],
301 args["solver"]["linear"], units.characteristic_length(), logger());
302
303 solver::ALSolver al_solver(
305 args["solver"]["augmented_lagrangian"]["initial_weight"],
306 args["solver"]["augmented_lagrangian"]["scaling"],
307 args["solver"]["augmented_lagrangian"]["max_weight"],
308 args["solver"]["augmented_lagrangian"]["eta"],
309 [&](const Eigen::VectorXd &) {
310 solve_data_.update_barrier_stiffness(solution);
311 });
312
313 al_solver.post_subsolve = [&](const double al_weight) {
314 stats.solver_info.push_back(
315 {{"type", al_weight > 0 ? "al" : "rc"},
316 {"t", step},
317 {"info", nl_solver->info()}});
318 if (al_weight > 0)
319 stats.solver_info.back()["weight"] = al_weight;
320 save_subsolve(stats.solver_info.size(), step, solution);
321 };
322
323 al_solver.solve_al(
324 nl_problem, solution,
325 args["solver"]["augmented_lagrangian"]["nonlinear"],
326 args["solver"]["linear"], units.characteristic_length());
327
328 al_solver.solve_reduced(
329 nl_problem, solution,
330 args["solver"]["nonlinear"],
331 args["solver"]["linear"], units.characteristic_length());
332
333 if (args["space"]["advanced"]["count_flipped_els_continuous"])
334 {
335 const auto invalid = utils::count_invalid(
336 mesh_->dimension(), space_.basis_list(), space_.geometry_basis_list(), solution);
337 logger().debug("Flipped elements (cnt {}) : {}", invalid.size(), invalid);
338 }
339 }
340
342 Eigen::MatrixXd &solution,
343 const double time,
344 const InitialConditionOverride *initial_condition_override)
345 {
346 assert(is_homogenization());
349 mesh_->dimension(), args["constraints"]["macro_displacement_gradient"], root_path);
350 init_solve_data(solution, time, "", initial_condition_override);
351
352 for (const auto &[name, form] : solve_data_.named_forms())
353 {
354 if (name == "augmented_lagrangian")
355 {
356 form->set_weight(0);
357 form->disable();
358 }
359 }
360
361 bool solve_symmetric_macro_strain = false;
362 const Eigen::VectorXi &fixed_entries = macro_strain_constraint_.get_fixed_entry();
363 const int dim = mesh_->dimension();
364 for (int i = 0; i < dim && !solve_symmetric_macro_strain; ++i)
365 {
366 for (int j = 0; j < i; ++j)
367 {
368 const bool ij_fixed = std::find(
369 fixed_entries.data(), fixed_entries.data() + fixed_entries.size(), i + j * dim)
370 != fixed_entries.data() + fixed_entries.size();
371 const bool ji_fixed = std::find(
372 fixed_entries.data(), fixed_entries.data() + fixed_entries.size(), j + i * dim)
373 != fixed_entries.data() + fixed_entries.size();
374 if (!ij_fixed && !ji_fixed)
375 solve_symmetric_macro_strain = true;
376 }
377 }
378
379 double characteristic_length = args["solver"]["advanced"]["characteristic_length"];
380 if (characteristic_length <= 0)
381 {
382 RowVectorNd min, max;
383 mesh_->bounding_box(min, max);
384 characteristic_length = (max - min).norm();
385 }
386 double characteristic_force_density = args["solver"]["advanced"]["characteristic_force_density"];
387 if (characteristic_force_density <= 0)
388 characteristic_force_density = 10000;
389
390 const int ndof = space_.n_bases * dim;
391 auto homo_problem = std::make_shared<solver::NLHomoProblem>(
393 time, forms, solve_data_.al_form, solve_symmetric_macro_strain,
394 polysolve::linear::Solver::create(args["solver"]["linear"], logger()),
395 characteristic_length, characteristic_force_density, pure_mass_, dim);
397 homo_problem->add_form(solve_data_.periodic_contact_form);
399 homo_problem->add_form(solve_data_.strain_al_lagr_form);
400
401 solve_data_.nl_problem = homo_problem;
402 const Eigen::VectorXd initial_reduced = Eigen::VectorXd::Zero(
403 homo_problem->reduced_size() + homo_problem->macro_reduced_size());
404 homo_problem->init(initial_reduced);
405 homo_problem->update_quantities(time, initial_reduced);
406 stats.solver_info = json::array();
407 }
408
410 Eigen::MatrixXd &solution,
411 const ForwardStepCallback &post_step)
412 {
413 auto homo_problem = std::dynamic_pointer_cast<solver::NLHomoProblem>(solve_data_.nl_problem);
414 assert(homo_problem && solve_data_.strain_al_lagr_form);
415
416 const int dim = mesh_->dimension();
417 Eigen::VectorXd extended_solution = Eigen::VectorXd::Zero(homo_problem->full_size() + dim * dim);
418 const Eigen::VectorXi &fixed_entries = macro_strain_constraint_.get_fixed_entry();
419 homo_problem->set_fixed_entry({});
420
421 auto lagrangian_form = solve_data_.strain_al_lagr_form;
422 lagrangian_form->enable();
423 Eigen::VectorXd reduced_solution = homo_problem->extended_to_reduced(extended_solution);
424 const Eigen::VectorXd initial_solution = reduced_solution;
425 const Eigen::VectorXi fixed_indices = fixed_entries.array() + homo_problem->full_size();
426 const Eigen::VectorXd fixed_values =
427 utils::flatten(macro_strain_constraint_.eval(/*time=*/0))(fixed_entries);
428 const double initial_error = lagrangian_form->compute_error(extended_solution);
429 extended_solution(fixed_indices) = fixed_values;
430 Eigen::VectorXd constrained_solution = homo_problem->extended_to_reduced(extended_solution);
431 homo_problem->line_search_begin(reduced_solution, constrained_solution);
432
433 double al_weight = args["solver"]["augmented_lagrangian"]["initial_weight"];
434 const double max_weight = args["solver"]["augmented_lagrangian"]["max_weight"];
435 const double eta_tolerance = args["solver"]["augmented_lagrangian"]["eta"];
436 const double scaling = args["solver"]["augmented_lagrangian"]["scaling"];
437 lagrangian_form->set_initial_weight(al_weight);
438 bool force_al_solve = true;
439
440 while (force_al_solve
441 || !std::isfinite(homo_problem->value(constrained_solution))
442 || !homo_problem->is_step_valid(reduced_solution, constrained_solution)
443 || !homo_problem->is_step_collision_free(reduced_solution, constrained_solution))
444 {
445 force_al_solve = false;
446 homo_problem->line_search_end();
447 homo_problem->init(reduced_solution);
448 auto nonlinear_solver = polysolve::nonlinear::Solver::create(
449 args["solver"]["augmented_lagrangian"]["nonlinear"],
450 args["solver"]["linear"], units.characteristic_length(), logger());
451 homo_problem->normalize_forms();
452 nonlinear_solver->minimize(*homo_problem, reduced_solution);
453
454 extended_solution = homo_problem->reduced_to_extended(reduced_solution);
455 const double current_error = lagrangian_form->compute_error(extended_solution);
456 const double eta = initial_error > 0 ? 1 - std::sqrt(current_error / initial_error) : 1;
457 if (eta < eta_tolerance && al_weight < max_weight)
458 al_weight *= scaling;
459 else
460 lagrangian_form->update_lagrangian(extended_solution, al_weight);
461 if (eta <= 0)
462 reduced_solution = initial_solution;
463
464 extended_solution(fixed_indices) = fixed_values;
465 constrained_solution = homo_problem->extended_to_reduced(extended_solution);
466 homo_problem->line_search_begin(reduced_solution, constrained_solution);
467 }
468 homo_problem->line_search_end();
469 lagrangian_form->disable();
470
471 homo_problem->set_fixed_entry(fixed_entries);
472 reduced_solution = homo_problem->extended_to_reduced(extended_solution);
473 homo_problem->init(reduced_solution);
474 auto nonlinear_solver = polysolve::nonlinear::Solver::create(
475 args["solver"]["nonlinear"], args["solver"]["linear"],
477 homo_problem->normalize_forms();
478 nonlinear_solver->minimize(*homo_problem, reduced_solution);
479
480 displacement_gradient_ = homo_problem->reduced_to_disp_grad(reduced_solution);
481 solution = homo_problem->reduced_to_full(reduced_solution);
482 if (post_step)
483 post_step(0, solution);
484 }
485
486 // Same as NonlinearElasticStaticVarForm
488 Eigen::MatrixXd &solution,
489 const InitialConditionOverride *initial_condition_override,
490 const ForwardStepCallback &post_step)
491 {
492 assert(
493 (!initial_condition_override
494 || (initial_condition_override->velocity.size() == 0
495 && initial_condition_override->acceleration.size() == 0))
496 && "Static elasticity does not accept initial velocity or acceleration overrides");
497
498 stats.spectrum.setZero();
499
500 igl::Timer timer;
501 timer.start();
502 logger().info("Solving {}", primary_assembler_->name());
503
504 {
505 POLYFEM_SCOPED_TIMER("Setup RHS");
506
507 if (initial_condition_override && initial_condition_override->solution.size() != 0)
508 initial_solution(solution, initial_condition_override);
509 else if (solution.size() <= 0)
510 initial_solution(solution, initial_condition_override);
511
512 if (initial_condition_override && initial_condition_override->solution.size() != 0)
513 assert(solution.cols() == 1 && "Static initial solution override must have exactly one column");
514 else if (solution.cols() != 1)
515 log_and_throw_error("Static elasticity requires exactly one initial solution column.");
516 }
517
518 if (is_homogenization())
519 {
520 init_homogenization_solve(solution, /*time=*/0, initial_condition_override);
521 solve_homogenization_step(solution, post_step);
522 timer.stop();
523 timings.solving_time = timer.getElapsedTime();
524 logger().info(" took {}s", timings.solving_time);
525 return;
526 }
527
528 init_solve(solution, 1.0, initial_condition_override);
529 solve_tensor_nonlinear(0, solution, true);
530 if (post_step)
531 post_step(0, solution);
532
533 const std::string state_path = resolve_output_path(args["output"]["data"]["state"]);
534 if (!state_path.empty())
535 io::write_matrix(state_path, "u", solution);
536
537 timer.stop();
538 timings.solving_time = timer.getElapsedTime();
539 logger().info(" took {}s", timings.solving_time);
540 }
541
542 // Same as NonlinearElasticTransientVarForm.
544 Eigen::MatrixXd &solution,
545 const InitialConditionOverride *initial_condition_override,
546 const ForwardStepCallback &post_step)
547 {
548 const bool save_stats = args["output"]["stats"];
549 stats.spectrum.setZero();
550
551 igl::Timer timer;
552 timer.start();
553 logger().info("Solving {}", primary_assembler_->name());
554
555 {
556 POLYFEM_SCOPED_TIMER("Setup RHS");
557
558 if (initial_condition_override && initial_condition_override->solution.size() != 0)
559 initial_solution(solution, initial_condition_override);
560 else if (solution.size() <= 0)
561 initial_solution(solution, initial_condition_override);
562
563 if (solution.cols() > 1)
564 solution.conservativeResize(Eigen::NoChange, 1);
565 }
566
567 init_solve(solution, t0 + dt, initial_condition_override);
568 if (post_step)
569 post_step(0, solution);
570
571 int save_i = 0;
572 std::unique_ptr<io::EnergyCSVWriter> energy_csv;
573 std::unique_ptr<io::RuntimeStatsCSVWriter> stats_csv;
574
575 if (save_stats)
576 {
577 logger().debug(
578 "Saving nl stats to {} and {}",
579 resolve_output_path("energy.csv"), resolve_output_path("stats.csv"));
580 energy_csv = std::make_unique<io::EnergyCSVWriter>(resolve_output_path("energy.csv"), solve_data_);
581 const io::OutputSpace space = output_space();
582 stats_csv = std::make_unique<io::RuntimeStatsCSVWriter>(
583 resolve_output_path("stats.csv"),
585 space.mesh ? space.mesh->n_elements() : 0,
586 t0, dt);
587 }
588
589 if (energy_csv)
590 energy_csv->write(save_i, solution);
591 save_timestep(t0, 0, t0, dt, solution);
592 ++save_i;
593
594 for (int t = 1; t <= time_steps; ++t)
595 {
596 double forward_solve_time = 0;
597 const double remeshing_time = 0;
598 const double global_relaxation_time = 0;
599
600 {
601 POLYFEM_SCOPED_TIMER(forward_solve_time);
602 solve_tensor_nonlinear(t, solution, true);
603 }
604 if (post_step)
605 post_step(t, solution);
606
607 if (energy_csv)
608 energy_csv->write(save_i, solution);
609 save_timestep(t0 + dt * t, t, t0, dt, solution);
610 ++save_i;
611
612 {
613 POLYFEM_SCOPED_TIMER("Update quantities");
615 solve_data_.time_integrator->update_quantities(solution);
616 solve_data_.nl_problem->update_quantities(t0 + (t + 1) * dt, solution);
619 }
620
621 logger().info("{}/{} t={}", t, time_steps, t0 + dt * t);
624 if (stats_csv)
625 stats_csv->write(t, forward_solve_time, remeshing_time, global_relaxation_time);
626 }
627
628 timer.stop();
629 timings.solving_time = timer.getElapsedTime();
630 logger().info(" took {}s", timings.solving_time);
631 }
632} // namespace polyfem::varform
#define POLYFEM_SCOPED_TIMER(...)
Definition Timer.hpp:10
double characteristic_length() const
Definition Units.hpp:22
Caches basis evaluation and geometric mapping at every element.
void init(const int dim, const json &param, const std::string &root_path)
Eigen::MatrixXd eval(const double t) const
const Eigen::VectorXi & get_fixed_entry() const
void save_vtu(const std::string &path, const OutputSpace &space, const OutputFieldFunction &output_fields, const double t, const double dt, const ExportOptions &opts) const
saves the vtu file for time t
Definition OutData.cpp:2162
double solving_time
time to solve
json solver_info
information of the solver, eg num iteration, time, errors, etc the informations varies depending on t...
Eigen::Vector4d spectrum
spectrum of the stiffness matrix, enable only if POLYSOLVE_WITH_SPECTRA is ON (off by default)
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:49
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
Definition Mesh.hpp:174
void solve_reduced(NLProblem &nl_problem, Eigen::MatrixXd &sol, std::shared_ptr< polysolve::nonlinear::Solver > nl_solver)
Definition ALSolver.hpp:41
std::function< void(const double)> post_subsolve
Definition ALSolver.hpp:53
void solve_al(NLProblem &nl_problem, Eigen::MatrixXd &sol, std::shared_ptr< polysolve::nonlinear::Solver > nl_solver)
Definition ALSolver.hpp:29
void init_lagging(const TVector &x) override
class to store time stepping data
Definition SolveData.hpp:55
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 json &zero_mean, 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 double friction_coefficient, const double epsv, const int friction_iterations, const json &rayleigh_damping, const BCLumpingMode al_lumping=BCLumpingMode::ROW_SUM, const mesh::Mesh *periodic_mesh=nullptr, const std::vector< mesh::LocalBoundary > *periodic_local_boundary=nullptr, const json &periodic_conditions=json::array(), const int fe_space_id=-1)
Initialize the forms and return a vector of pointers to them.
Definition SolveData.cpp:35
std::shared_ptr< solver::PeriodicContactForm > periodic_contact_form
void update_dt()
updates the dt inside the different forms
std::shared_ptr< solver::NLProblem > nl_problem
std::shared_ptr< solver::MacroStrainLagrangianForm > strain_al_lagr_form
std::shared_ptr< solver::ContactForm > contact_form
std::vector< std::pair< std::string, std::shared_ptr< solver::Form > > > named_forms() const
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
void solve_problem(Eigen::MatrixXd &solution, const InitialConditionOverride *initial_condition_override, const ForwardStepCallback &post_step) override
void solve_problem(Eigen::MatrixXd &solution, const InitialConditionOverride *initial_condition_override, const ForwardStepCallback &post_step) override
void init_homogenization_solve(Eigen::MatrixXd &solution, double time, const InitialConditionOverride *initial_condition_override)
void init_forms(const json &args, int dim, Eigen::MatrixXd &solution, double time) override
const assembler::ViscousDampingPrev * damping_prev_assembler() const override
QuadratureOrders boundary_samples(int discr_order, int discr_orderq, int geometry_discr_order) const override
void initial_solution(Eigen::MatrixXd &solution, const InitialConditionOverride *override=nullptr) const override
void initial_velocity(Eigen::MatrixXd &velocity, const InitialConditionOverride *override=nullptr) const override
void solve_tensor_nonlinear(int step, Eigen::MatrixXd &solution, bool init_lagging=true) override
void solve(Eigen::MatrixXd &solution, const InitialConditionOverride *initial_condition_override, const ForwardStepCallback &post_step, bool differentiable) override
const assembler::AssemblyValsCache & assembly_cache() const override
std::string input_path(const std::string &path, bool only_if_exists=false) const override
void solve_homogenization_step(Eigen::MatrixXd &solution, const ForwardStepCallback &post_step)
void initial_acceleration(Eigen::MatrixXd &acceleration, const InitialConditionOverride *override=nullptr) const override
bool is_contact_enabled() const override
Check if contact is enabled for the variational formulation, for output purposes.
const assembler::AssemblyValsCache & mass_assembly_cache() const override
void save_vtu(const std::string &path, const Eigen::MatrixXd &solution, double time, double dt) const override
std::string output_file_path(const std::string &path) const override
virtual Eigen::MatrixXd displacement_gradient() const
virtual std::string name() const =0
std::shared_ptr< assembler::Assembler > primary_assembler_
void save_elastic_step_state(const double t0, const double dt, const int t, const time_integrator::ImplicitTimeIntegrator *time_integrator) const
QuadratureOrders elastic_boundary_samples() const
assembler::AssemblyValsCache ass_vals_cache_
std::shared_ptr< assembler::Mass > mass_assembler_
std::shared_ptr< assembler::RhsAssembler > rhs_assembler_
assembler::AssemblyValsCache mass_ass_vals_cache_
void initial_velocity(Eigen::MatrixXd &velocity, const InitialConditionOverride *override=nullptr, const std::string &state_prefix="") const
void initial_acceleration(Eigen::MatrixXd &acceleration, const InitialConditionOverride *override=nullptr, const std::string &state_prefix="") const
void initial_solution(Eigen::MatrixXd &solution, const InitialConditionOverride *override=nullptr, const std::string &state_prefix="") const
A finite-element space for one scalar- or vector-valued field.
Definition FESpace.hpp:59
const std::vector< basis::ElementBases > & geometry_basis_list() const
Definition FESpace.hpp:115
std::shared_ptr< std::vector< basis::ElementBases > > bases
Per-element basis data.
Definition FESpace.hpp:68
int n_bases
Number of globally indexed scalar basis functions in the space.
Definition FESpace.hpp:65
Eigen::VectorXi space_in_node_to_node
Definition FESpace.hpp:91
const std::vector< basis::ElementBases > & basis_list() const
Definition FESpace.hpp:109
std::shared_ptr< mesh::MeshNodes > mesh_nodes
Optional primitive-to-node mapping for this FE space.
Definition FESpace.hpp:86
virtual void init_forms(const json &args, int dim, Eigen::MatrixXd &sol, double t)
std::shared_ptr< assembler::PressureAssembler > elasticity_pressure_assembler
std::shared_ptr< assembler::ViscousDampingPrev > damping_prev_assembler_
virtual void solve_tensor_nonlinear(int step, Eigen::MatrixXd &sol, bool init_lagging=true)
void init_solve(Eigen::MatrixXd &sol, double t, const InitialConditionOverride *initial_condition_override)
std::shared_ptr< assembler::ViscousDamping > damping_assembler_
io::OutputSpace output_space() const override
Get the output space of the variational formulation, for output purposes.
void init_solve_data(Eigen::MatrixXd &sol, double t, const std::string &state_prefix, const InitialConditionOverride *initial_condition_override=nullptr)
bool is_contact_enabled() const override
Check if contact is enabled for the variational formulation, for output purposes.
std::vector< std::shared_ptr< solver::Form > > forms
std::shared_ptr< assembler::PressureAssembler > build_pressure_assembler() const
std::string resolve_input_path(const std::string &path, const bool only_if_exists=false) const
Definition VarForm.cpp:1105
void prepare()
Prepare all discretization and assembly data without running a solve.
Definition VarForm.cpp:304
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
Definition VarForm.hpp:214
void solve(Eigen::MatrixXd &sol, const InitialConditionOverride *initial_condition_override=nullptr, const ForwardStepCallback &post_step={})
Solve the variational formulation and store the solution in the given matrix.
Definition VarForm.cpp:639
std::unique_ptr< mesh::Mesh > mesh_
Definition VarForm.hpp:226
io::OutStatsData stats
Definition VarForm.hpp:218
void notify_time_step(const int t, const int time_steps, const double t0, const double dt) const
Definition VarForm.cpp:999
io::OutGeometryData::ExportOptions export_options(const io::OutputSpace &space) const
Definition VarForm.cpp:898
io::OutGeometryData output_geometry_
Definition VarForm.hpp:230
void save_subsolve(const int i, const int t, const Eigen::MatrixXd &solution) const
Definition VarForm.cpp:980
io::OutputFieldFunction output_field_function(const Eigen::MatrixXd &solution, const io::OutGeometryData::ExportOptions &opts) const
Definition VarForm.cpp:907
QuadratureOrders n_boundary_samples(const int discr_order, const int discr_orderq, const int gdiscr_order) const
Definition VarForm.cpp:255
std::string resolve_output_path(const std::string &path) const
Definition VarForm.cpp:1110
void ensure_output_sampler() const
Definition VarForm.cpp:884
void save_timestep(const double time, const int t, const double t0, const double dt, const Eigen::MatrixXd &solution) const
Definition VarForm.cpp:941
io::OutRuntimeData timings
runtime statistics
Definition VarForm.hpp:221
void set_materials(assembler::Assembler &assembler, const int size) const
Definition VarForm.cpp:869
bool write_matrix(const std::string &path, const Mat &mat)
Writes a matrix to a file. Determines the file format based on the path's extension.
Definition MatrixIO.cpp:42
std::vector< int > count_invalid(const int dim, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXd &u, const unsigned max_iter)
Definition Jacobian.cpp:122
Eigen::VectorXd flatten(const Eigen::MatrixXd &X)
Flatten rowwises.
std::function< void(int step, const Eigen::MatrixXd &solution)> ForwardStepCallback
Definition VarForm.hpp:49
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
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24
const mesh::Mesh * mesh
Temporary compatibility wrapper for boundary data belonging to one FE space.
Definition FESpace.hpp:152
std::vector< mesh::LocalBoundary > local_boundary
Definition FESpace.hpp:155
std::vector< mesh::LocalBoundary > local_neumann_boundary
Definition FESpace.hpp:156
std::vector< mesh::LocalBoundary > total_local_boundary
Definition FESpace.hpp:154
std::vector< mesh::LocalBoundary > local_pressure_boundary
Definition FESpace.hpp:157
std::unordered_map< int, std::vector< mesh::LocalBoundary > > local_pressure_cavity
Definition FESpace.hpp:158