PolyFEM
Loading...
Searching...
No Matches
FluidVarForm.cpp
Go to the documentation of this file.
1#include "FluidVarForm.hpp"
2
22
23#include <polysolve/linear/FEMSolver.hpp>
24
25namespace polyfem::varform
26{
27 using namespace varform::internal;
28
30 {
32 space_.reset();
40 rhs_assembler_ = nullptr;
41 mass_.resize(0, 0);
42 pure_mass_.resize(0, 0);
43 avg_mass_ = 0;
44 rhs_.resize(0, 0);
45 primary_assembler_ = nullptr;
46 mass_assembler_ = nullptr;
47 pure_mass_assembler_ = nullptr;
48 mixed_assembler_ = nullptr;
49 pressure_assembler_ = nullptr;
50 use_avg_pressure = true;
51 t0 = 0;
52 time_steps = 0;
53 dt = 0;
54 time_integrator = nullptr;
55 }
56
57 void FluidVarForm::init(const std::string &formulation, const Units &units, const json &args, const std::string &out_path)
58 {
59 VarForm::init(formulation, units, args, out_path);
60 const bool is_time_dependent = args.contains("time") && !args["time"].is_null();
61
63 mass_assembler_ = std::make_shared<assembler::Mass>();
64 pure_mass_assembler_ = std::make_shared<assembler::HRZMass>();
67
68 if (!args.contains("preset_problem"))
69 {
70 problem = std::make_shared<assembler::GenericTensorProblem>("GenericTensor");
71 problem->clear();
72
73 json tmp;
74 tmp["is_time_dependent"] = is_time_dependent;
75 problem->set_parameters(tmp, root_path);
76
77 auto bc = args["boundary_conditions"];
78 bc["root_path"] = root_path;
79 problem->set_parameters(bc, root_path);
80 problem->set_parameters(args["initial_conditions"], root_path);
81 problem->set_parameters(args["output"], root_path);
82 }
83 else
84 {
85 if (args["preset_problem"]["type"] == "Kernel")
86 {
87 problem = std::make_shared<problem::KernelProblem>("Kernel", *primary_assembler_);
88 problem->clear();
89 }
90 else
91 {
92 problem = problem::ProblemFactory::factory().get_problem(args["preset_problem"]["type"]);
93 problem->clear();
94 }
95 problem->set_parameters(args["preset_problem"], root_path);
96 }
97
98 problem->set_units(*primary_assembler_, units);
99
100 t0 = is_time_dependent ? args["time"]["t0"].get<double>() : 0.0;
101 time_steps = is_time_dependent ? args["time"]["time_steps"].get<int>() : 0;
102 dt = is_time_dependent ? args["time"]["dt"].get<double>() : 0.0;
103
104 assert(primary_assembler_->is_fluid());
105 }
106
107 void FluidVarForm::save_json(const Eigen::MatrixXd &solution, std::ostream &out) const
108 {
109 if (!mesh_)
110 {
111 logger().error("Load the mesh first!");
112 return;
113 }
114 if (solution.size() <= 0)
115 {
116 logger().error("Solve the problem first!");
117 return;
118 }
119
120 logger().info("Saving json...");
121 const int primary_size = primary_ndof();
122 const Eigen::MatrixXd stats_solution =
123 solution.rows() >= primary_size
124 ? solution.topRows(primary_size).eval()
125 : solution;
126
127 nlohmann::json j;
130 stats_solution, *mesh_, space_.disc_orders, space_.disc_ordersq, *problem,
132 args["output"]["advanced"]["sol_at_node"], j);
133 out << j.dump(4) << std::endl;
134 }
135
137 {
138 Eigen::VectorXi output_orders = space_.disc_orders;
139 if (mesh_ && space_.disc_ordersq.size() == space_.disc_orders.size())
140 {
141 for (int e = 0; e < output_orders.size(); ++e)
142 {
143 if (mesh_->is_prism(e))
144 output_orders(e) = std::max(space_.disc_orders(e), space_.disc_ordersq(e));
145 }
146 }
147
148 return {
149 mesh_.get(),
151 output_orders,
152 &space_.polys,
155 nullptr,
156 nullptr,
159 }
160
161 io::OutStatsData FluidVarForm::compute_errors(const Eigen::MatrixXd &solution)
162 {
163 if (!args["output"]["advanced"]["compute_error"])
164 return stats;
165
166 double tend = 0;
167 if (!args["time"].is_null())
168 tend = args["time"]["tend"];
169
170 Eigen::MatrixXd velocity, pressure;
171 split_solution(solution, velocity, pressure);
173 return stats;
174 }
175
176 void FluidVarForm::export_data(const Eigen::MatrixXd &solution) const
177 {
178 const io::OutputSpace space = output_space();
179 if (!space.mesh)
180 {
181 logger().error("Load the mesh first!");
182 return;
183 }
184 if (solution.size() <= 0)
185 {
186 logger().error("Solve the problem first!");
187 return;
188 }
189
191
192 const std::string vis_mesh_path = resolve_output_path(args["output"]["paraview"]["file_name"]);
193 const bool has_time = args.contains("time") && !args["time"].is_null();
194 double tend = has_time ? args["time"]["tend"].get<double>() : 1.0;
195 double dt = 1;
196 if (has_time)
197 dt = args["time"]["dt"];
198
199 const auto opts = export_options(space);
201 space,
202 output_field_function(solution, opts),
203 has_time,
204 tend, dt,
205 opts,
206 vis_mesh_path);
207
208 Eigen::MatrixXd velocity, pressure;
209 split_solution(solution, velocity, pressure);
210
211 const std::string solution_path = resolve_output_path(args["output"]["data"]["solution"]);
212 if (!solution_path.empty())
213 {
214 const int primary_rows = std::min<int>(velocity.rows(), primary_ndof());
215 const Eigen::MatrixXd primary_solution = velocity.topRows(primary_rows);
216 if (opts.reorder_output && space_.space_in_node_to_node.size() > 0)
217 {
218 const Eigen::MatrixXd nodal_solution = utils::unflatten(primary_solution, mesh_->dimension());
219 Eigen::MatrixXd reordered = Eigen::MatrixXd::Zero(nodal_solution.rows(), nodal_solution.cols());
220 for (int input_node = 0; input_node < space_.space_in_node_to_node.size(); ++input_node)
221 {
222 const int node = space_.space_in_node_to_node(input_node);
223 if (node >= 0 && node < nodal_solution.rows() && input_node < reordered.rows())
224 reordered.row(input_node) = nodal_solution.row(node);
225 }
226 io::write_matrix(solution_path, reordered);
227 }
228 else
229 {
230 io::write_matrix(solution_path, primary_solution);
231 }
232 }
233
234 const std::string nodes_path = resolve_output_path(args["output"]["data"]["nodes"]);
235 if (!nodes_path.empty())
236 {
237 Eigen::MatrixXd nodes = Eigen::MatrixXd::Zero(space_.n_bases, mesh_->dimension());
238 for (const basis::ElementBases &element_bases : space_.basis_list())
239 for (const basis::Basis &basis : element_bases.bases)
240 for (const auto &global : basis.global())
241 nodes.row(global.index) = global.node;
242 io::write_matrix(nodes_path, nodes);
243 }
244
245 const std::string stress_path = resolve_output_path(args["output"]["data"]["stress_mat"]);
246 const std::string mises_path = resolve_output_path(args["output"]["data"]["mises"]);
247 if ((!stress_path.empty() || !mises_path.empty()) && primary_assembler_)
248 {
249 Eigen::MatrixXd stress;
250 Eigen::VectorXd mises;
254 stress, mises);
255 if (!stress_path.empty())
256 io::write_matrix(stress_path, stress);
257 if (!mises_path.empty())
258 io::write_matrix(mises_path, mises);
259 }
260 }
261
262 void FluidVarForm::load_mesh(const mesh::Mesh &mesh, const json &args)
263 {
266 pure_mass_assembler_->set_size(mass_assembler_->size());
267 problem->init(mesh);
268
270 mixed_assembler_->set_size(mesh.dimension());
273 }
274
276 {
277 return mesh_ ? space_.n_bases * mesh_->dimension() : 0;
278 }
279
281 {
283 }
284
286 {
288 }
289
291 {
292 json rhs_solver_params = args["solver"]["linear"];
293 if (!rhs_solver_params.contains("Pardiso"))
294 rhs_solver_params["Pardiso"] = {};
295 rhs_solver_params["Pardiso"]["mtype"] = -2;
296
297 rhs_assembler_ = std::make_shared<assembler::RhsAssembler>(
298 *primary_assembler_, *mesh_, nullptr, // no obstacle for the rhs assembler
302 args["space"]["advanced"]["bc_method"],
303 rhs_solver_params);
304 }
305
306 void FluidVarForm::build_basis(mesh::Mesh &mesh, const bool iso_parametric, const json &args)
307 {
308 assert(problem);
309 assert(primary_assembler_);
310 assert(mass_assembler_);
311 assert(pure_mass_assembler_);
312
313 Eigen::VectorXi space_disc_orders;
314 assign_discr_orders(args["space"]["discr_order"], mesh, space_disc_orders);
315
316 if (args["space"]["use_p_ref"])
317 {
319 mesh,
320 args["space"]["advanced"]["B"],
321 args["space"]["advanced"]["h1_formula"],
322 args["space"]["discr_order"],
323 args["space"]["advanced"]["discr_order_max"],
324 stats,
325 space_disc_orders);
326
327 logger().info("min p: {} max p: {}", space_disc_orders.minCoeff(), space_disc_orders.maxCoeff());
328 }
329
331 mesh,
332 iso_parametric,
333 space_disc_orders,
334 args["space"]["basis_type"],
335 args["space"]["poly_basis_type"],
337 mesh.dimension(),
338 args["space"]["advanced"]["quadrature_order"],
339 args["space"]["advanced"]["mass_quadrature_order"],
340 args["space"]["advanced"]["use_corner_quadrature"],
341 args["space"]["advanced"]["n_harmonic_samples"],
342 args["space"]["advanced"]["integral_constraints"],
343 space_,
344 boundary_);
345
346 problem->update_nodes(space_.space_in_node_to_node);
348
349 const auto &current_bases = space_.geometry_basis_list();
350 if (args["space"]["advanced"]["count_flipped_els"])
351 stats.count_flipped_elements(mesh, current_bases);
352
353 const int n_samples = 10;
354 stats.compute_mesh_size(mesh, current_bases, n_samples, args["output"]["advanced"]["curved_mesh_size"]);
355
356 logger().info("flipped elements {}", stats.n_flipped);
357 logger().info("h: {}", stats.mesh_size);
358
359 if (space_.disc_orders.maxCoeff() != space_.disc_orders.minCoeff())
360 log_and_throw_error("p refinement not supported in mixed formulation!");
361 if (!space_.poly_edge_to_data.empty())
362 log_and_throw_error("Polygonal bases are not supported in mixed formulations!");
363
364 if (space_.n_bases <= args["solver"]["advanced"]["cache_size"])
365 {
366 igl::Timer cache_timer;
367 cache_timer.start();
368 logger().info("Building cache...");
369 ass_vals_cache_.init(mesh.is_volume(), space_.basis_list(), current_bases);
370 mass_ass_vals_cache_.init(mesh.is_volume(), space_.basis_list(), current_bases, true);
371 pure_mass_ass_vals_cache_.init(mesh.is_volume(), space_.basis_list(), current_bases, true);
372 logger().info(" took {}s", cache_timer.getElapsedTime());
373 }
374 else
375 {
379 }
380
381 const auto &all_boundary = boundary_.total_local_boundary;
382 const int prev_bases = space_.n_bases;
383 const int prev_b_size = int(all_boundary.size());
384 const bool use_corner_quadrature = args["space"]["advanced"]["use_corner_quadrature"];
385 const int quadrature_order = args["space"]["advanced"]["quadrature_order"].get<int>();
386 const int mass_quadrature_order = args["space"]["advanced"]["mass_quadrature_order"].get<int>();
387 const int order = args["space"]["pressure_discr_order"];
388 Eigen::VectorXi pressure_disc_orders(mesh.n_elements());
389 pressure_disc_orders.setConstant(order);
390 // to avoid serendipity
391 const std::string pressure_basis_type = args["space"]["basis_type"].get<std::string>() == "Bernstein" ? "Bernstein" : "Lagrange";
393 mesh,
394 /*iso_parametric=*/true,
395 pressure_disc_orders,
396 pressure_basis_type,
397 args["space"]["poly_basis_type"],
399 /*value_dim=*/1,
400 quadrature_order,
401 mass_quadrature_order,
402 use_corner_quadrature,
403 args["space"]["advanced"]["n_harmonic_samples"],
404 args["space"]["advanced"]["integral_constraints"],
408
409 assert(space_.basis_list().size() == pressure_space_.basis_list().size());
410 for (int i = 0; i < int(pressure_space_.basis_list().size()); ++i)
411 {
413 space_.basis_list()[i].compute_quadrature(b_quad);
414 (*pressure_space_.bases)[i].set_quadrature([b_quad](quadrature::Quadrature &quad) { quad = b_quad; });
415 }
416
418 for (const auto &lb : all_boundary)
419 boundary_.local_boundary.emplace_back(lb);
421
422 problem->setup_bc(
423 mesh, space_.n_bases,
433
436
437 const bool has_neumann = !boundary_.local_neumann_boundary.empty() || int(boundary_.local_boundary.size()) < prev_b_size;
438 use_avg_pressure = !has_neumann;
439
440 for (int i = prev_bases; i < space_.n_bases; ++i)
441 for (int d = 0; d < mesh.dimension(); ++d)
442 boundary_.boundary_nodes.push_back(i * mesh.dimension() + d);
443
445
446 if (space_.n_bases <= args["solver"]["advanced"]["cache_size"])
448 else
450
452
453 logger().info("n pressure bases: {}", pressure_space_.n_bases);
454 }
455
457 {
459
460 igl::Timer timer;
461 json p_params = {};
462 p_params["formulation"] = primary_assembler_->name();
463 p_params["root_path"] = root_path;
464 {
465 RowVectorNd min, max, delta;
466 mesh.bounding_box(min, max);
467 delta = (max - min) / 2. + min;
468 if (mesh.is_volume())
469 p_params["bbox_center"] = {delta(0), delta(1), delta(2)};
470 else
471 p_params["bbox_center"] = {delta(0), delta(1)};
472 }
473 problem->set_parameters(p_params, root_path);
474
475 rhs_.resize(0, 0);
476
477 timer.start();
478 logger().info("Assigning rhs...");
479
480 assert(rhs_assembler_ != nullptr);
481 rhs_assembler_->assemble(mass_assembler_->density(), rhs_);
482 rhs_ *= -1;
483
484 timings.assigning_rhs_time = timer.getElapsedTime();
485 logger().info(" took {}s", timings.assigning_rhs_time);
486
487 const int prev_size = rhs_.rows();
488 rhs_.conservativeResize(prev_size + pressure_block_size(), rhs_.cols());
489 rhs_.bottomRows(pressure_block_size()).setZero();
490 }
491
492 void FluidVarForm::assemble_mass_mat(const mesh::Mesh &mesh, const json &args)
493 {
494 if (!problem->is_time_dependent())
495 {
496 avg_mass_ = 1;
498 if (!primary_assembler_->is_linear())
500 return;
501 }
502
503 mass_.resize(0, 0);
504 igl::Timer timer;
505 timer.start();
506 logger().info("Assembling mass mat...");
507
508 StiffnessMatrix velocity_mass;
510 if (!primary_assembler_->is_linear())
512
513 std::vector<Eigen::Triplet<double>> blocks;
514 blocks.reserve(velocity_mass.nonZeros());
515 for (int k = 0; k < velocity_mass.outerSize(); ++k)
516 for (StiffnessMatrix::InnerIterator it(velocity_mass, k); it; ++it)
517 blocks.emplace_back(it.row(), it.col(), it.value());
518
519 mass_.resize(primary_ndof(), primary_ndof());
520 mass_.setFromTriplets(blocks.begin(), blocks.end());
521 mass_.makeCompressed();
522
523 avg_mass_ = 0;
524 for (int k = 0; k < velocity_mass.outerSize(); ++k)
525 for (StiffnessMatrix::InnerIterator it(velocity_mass, k); it; ++it)
526 {
527 assert(it.col() == k);
528 avg_mass_ += it.value();
529 }
530 avg_mass_ /= std::max(1, int(velocity_mass.rows()));
531 logger().info("average mass {}", avg_mass_);
532
533 if (args["solver"]["advanced"]["lump_mass_matrix"])
535
536 timer.stop();
537 timings.assembling_mass_mat_time = timer.getElapsedTime();
538 logger().info(" took {}s", timings.assembling_mass_mat_time);
539
540 stats.nn_zero = mass_.nonZeros();
541 stats.num_dofs = mass_.rows();
542 stats.mat_size = (long long)mass_.rows() * (long long)mass_.cols();
543 logger().info("sparsity: {}/{}", stats.nn_zero, stats.mat_size);
544 }
545
546 void FluidVarForm::prepare_initial_solution(Eigen::MatrixXd &sol) const
547 {
548 if (sol.size() <= 0)
549 {
550 assert(rhs_assembler_ != nullptr);
551 const bool was_solution_loaded = read_initial_x_from_file(
552 resolve_input_path(args["input"]["data"]["state"]), "u",
553 args["input"]["data"]["reorder"], space_.space_in_node_to_node,
554 mesh_->dimension(), sol);
555
556 if (!was_solution_loaded)
557 {
558 if (problem->is_time_dependent())
559 rhs_assembler_->initial_solution(sol);
560 else
561 {
562 sol.resize(rhs_.size(), 1);
563 sol.setZero();
564 }
565 }
566 }
567 if (sol.cols() > 1)
568 sol.conservativeResize(Eigen::NoChange, 1);
569 sol.conservativeResize(stacked_ndof(), sol.cols());
570 sol.bottomRows(pressure_block_size()).setZero();
571 }
572
573 void FluidVarForm::split_solution(const Eigen::MatrixXd &stacked, Eigen::MatrixXd &primary, Eigen::MatrixXd &pressure) const
574 {
575 const int cols = std::max(1, int(stacked.cols()));
576 primary.setZero(primary_ndof(), cols);
577 pressure.setZero(pressure_space_.n_bases, cols);
578
579 const int primary_rows = std::min(primary_ndof(), int(stacked.rows()));
580 if (primary_rows > 0)
581 primary.topRows(primary_rows) = stacked.topRows(primary_rows);
582
583 if (stacked.rows() > primary_ndof())
584 {
585 const int pressure_rows = std::min(pressure_space_.n_bases, int(stacked.rows()) - primary_ndof());
586 if (pressure_rows > 0)
587 pressure.topRows(pressure_rows) = stacked.middleRows(primary_ndof(), pressure_rows);
588 }
589 }
590
592 {
593 igl::Timer timer;
594 timer.start();
595 logger().info("Assembling stiffness mat...");
596
597 StiffnessMatrix velocity_stiffness, mixed_stiffness, pressure_stiffness;
598 primary_assembler_->assemble(mesh_->is_volume(), space_.n_bases, space_.basis_list(), space_.geometry_basis_list(), ass_vals_cache_, 0, velocity_stiffness);
601
604 velocity_stiffness, mixed_stiffness, pressure_stiffness, stiffness);
605
606 timer.stop();
607 timings.assembling_stiffness_mat_time = timer.getElapsedTime();
608 logger().info(" took {}s", timings.assembling_stiffness_mat_time);
609
610 stats.nn_zero = stiffness.nonZeros();
611 stats.num_dofs = stiffness.rows();
612 stats.mat_size = (long long)stiffness.rows() * (long long)stiffness.cols();
613 logger().info("sparsity: {}/{}", stats.nn_zero, stats.mat_size);
614
615 write_matrix_market(args, stiffness);
616 }
617
619 const std::unique_ptr<polysolve::linear::Solver> &solver,
621 Eigen::VectorXd &b,
622 const bool compute_spectrum,
623 Eigen::MatrixXd &sol)
624 {
625 Eigen::VectorXd x;
626 stats.spectrum = dirichlet_solve(
627 *solver,
628 A,
629 b,
631 x,
632 primary_ndof(),
633 args["output"]["data"]["stiffness_mat"],
634 compute_spectrum,
635 /*is_fluid=*/true,
637
638 sol = x;
639 solver->get_info(stats.solver_info);
640
641 const double error = (A * x - b).norm();
642 if (error > 1e-4)
643 logger().error("Solver error: {}", error);
644 else
645 logger().debug("Solver error: {}", error);
646 }
647
648 std::vector<io::OutputField> FluidVarForm::output_fields(
649 const io::OutputSample &sample,
650 const Eigen::MatrixXd &solution,
651 const io::OutputFieldOptions &options) const
652 {
653 std::vector<io::OutputField> fields;
654 if (!mesh_ || !problem || solution.size() <= 0)
655 return fields;
656
657 Eigen::MatrixXd velocity, pressure;
658 split_solution(solution, velocity, pressure);
659
660 const int field_dim = mesh_->dimension();
661 const bool has_element_samples = sample.local_points.rows() > 0 && sample.local_points.rows() == sample.element_ids.size();
662 const int output_rows = sample.points.rows() > 0 ? sample.points.rows() : std::max<int>(sample.local_points.rows(), sample.node_ids.size());
663 const bool export_solution_gradient =
664 !options.fields.empty() && options.export_field("solution_gradient");
665 const bool export_pressure_gradient =
666 !options.fields.empty() && options.export_field("pressure_gradient");
667
668 const auto resize_to_output_rows = [&](Eigen::MatrixXd &values) {
669 if (output_rows <= values.rows())
670 return;
671
672 const int previous_rows = values.rows();
673 values.conservativeResize(output_rows, values.cols());
674 values.bottomRows(output_rows - previous_rows).setZero();
675 };
676
677 const auto sample_vector_field = [&](const Eigen::MatrixXd &dof_values, Eigen::MatrixXd &values, Eigen::MatrixXd *gradients = nullptr) -> bool {
678 if (dof_values.size() <= 0 || field_dim <= 0)
679 return false;
680
681 if (has_element_samples)
682 {
683 values.resize(sample.local_points.rows(), field_dim);
684 if (gradients)
685 gradients->resize(sample.local_points.rows(), field_dim * mesh_->dimension());
686 for (int i = 0; i < sample.local_points.rows(); ++i)
687 {
688 const int element_id = sample.element_ids(i);
689 if (element_id < 0)
690 {
691 values.row(i).setZero();
692 if (gradients)
693 gradients->row(i).setZero();
694 continue;
695 }
696
697 Eigen::MatrixXd local_sol, local_grad;
700 element_id, sample.local_points.row(i), dof_values, local_sol, local_grad);
701
702 for (int d = 0; d < field_dim; ++d)
703 values(i, d) = local_sol(d);
704 if (gradients)
705 gradients->row(i) = local_grad;
706 }
707
708 resize_to_output_rows(values);
709 if (gradients)
710 resize_to_output_rows(*gradients);
711 return true;
712 }
713
714 if (sample.node_ids.size() > 0)
715 {
716 values.resize(sample.node_ids.size(), field_dim);
717 for (int i = 0; i < sample.node_ids.size(); ++i)
718 {
719 const int node_id = sample.node_ids(i);
720 for (int d = 0; d < field_dim; ++d)
721 {
722 const int dof = node_id * field_dim + d;
723 if (dof < 0 || dof >= dof_values.rows())
724 return false;
725 values(i, d) = dof_values(dof);
726 }
727 }
728 return sample.points.rows() == 0 || sample.points.rows() == values.rows();
729 }
730
731 return false;
732 };
733
734 Eigen::MatrixXd velocity_values, velocity_gradients;
735 const bool sampled_velocity = sample_vector_field(
736 velocity, velocity_values,
737 export_solution_gradient ? &velocity_gradients : nullptr);
738 if (sampled_velocity && options.export_field("velocity"))
739 fields.push_back({"velocity", velocity_values, io::OutputField::Association::Point});
740 if (sampled_velocity && options.export_field("solution"))
741 fields.push_back({"solution", velocity_values, io::OutputField::Association::Point});
742 if (sampled_velocity && export_solution_gradient)
743 fields.push_back({"solution_gradient", velocity_gradients, io::OutputField::Association::Point});
744
745 if (mesh_ && (options.export_field("pressure") || export_pressure_gradient))
746 {
747 Eigen::MatrixXd values, gradients;
748 if (sample_scalar_field(
749 *mesh_, pressure_space_.basis_list(), space_.geometry_basis_list(), sample, pressure, values,
750 export_pressure_gradient ? &gradients : nullptr))
751 {
752 if (options.export_field("pressure"))
753 fields.push_back({"pressure", values, io::OutputField::Association::Point});
754 if (export_pressure_gradient)
755 fields.push_back({"pressure_gradient", gradients, io::OutputField::Association::Point});
756 }
757 }
758
759 const auto &paraview_options = args["output"]["paraview"]["options"];
760 if (paraview_options["material"] && has_element_samples)
761 {
762 const auto &params = primary_assembler_->parameters();
763 std::map<std::string, Eigen::MatrixXd> param_values;
764 for (const auto &[p, _] : params)
765 param_values[p].setZero(output_rows, 1);
766
767 Eigen::MatrixXd rhos = Eigen::MatrixXd::Zero(output_rows, 1);
768 const auto &density = mass_assembler_->density();
769 for (int i = 0; i < sample.local_points.rows(); ++i)
770 {
771 const int element_id = sample.element_ids(i);
772 if (element_id < 0)
773 continue;
774
775 for (const auto &[p, func] : params)
776 param_values.at(p)(i) = func(sample.local_points.row(i), sample.points.row(i), sample.time, element_id);
777 rhos(i) = density(sample.local_points.row(i), sample.points.row(i), sample.time, element_id);
778 }
779
780 for (const auto &[name, values] : param_values)
781 if (options.export_field(name))
782 fields.push_back({name, values, io::OutputField::Association::Point});
783 if (options.export_field("rho"))
784 fields.push_back({"rho", rhos, io::OutputField::Association::Point});
785 }
786
787 if (paraview_options["body_ids"] && options.export_field("body_ids") && has_element_samples)
788 {
789 Eigen::MatrixXd ids = Eigen::MatrixXd::Zero(output_rows, 1);
790 for (int i = 0; i < sample.element_ids.size(); ++i)
791 {
792 const int element_id = sample.element_ids(i);
793 if (element_id >= 0)
794 ids(i) = mesh_->get_body_id(element_id);
795 }
796 fields.push_back({"body_ids", ids, io::OutputField::Association::Point});
797 }
798
799 return fields;
800 }
801
802 void StokesVarForm::solve_static_linear(Eigen::MatrixXd &sol)
803 {
804 auto solver = polysolve::linear::Solver::create(args["solver"]["linear"], logger());
805 logger().info("{}...", solver->name());
806
807 const int gdiscr_order = mesh_->orders().size() <= 0 ? 1 : mesh_->orders().maxCoeff();
808 const QuadratureOrders boundary_samples = n_boundary_samples(space_.disc_orders.maxCoeff(), gdiscr_order);
809 rhs_assembler_->set_bc(
810 boundary_.local_boundary, boundary_.boundary_nodes, boundary_samples,
811 boundary_.local_neumann_boundary, rhs_);
812
814 build_stiffness_mat(A);
815 Eigen::VectorXd b = rhs_;
816 solve_linear_system(solver, A, b, args["output"]["advanced"]["spectrum"], sol);
817 }
818
819 void StokesVarForm::solve_transient_linear(Eigen::MatrixXd &sol)
820 {
821 auto solver = polysolve::linear::Solver::create(args["solver"]["linear"], logger());
822 logger().info("{}...", solver->name());
823
824 Eigen::MatrixXd velocity, pressure;
825 split_solution(sol, velocity, pressure);
826
827 auto bdf = make_bdf_time_integrator();
828 bdf->init(
829 velocity,
830 Eigen::MatrixXd::Zero(velocity.rows(), velocity.cols()),
831 Eigen::MatrixXd::Zero(velocity.rows(), velocity.cols()),
832 dt);
833 time_integrator = bdf;
834
835 save_timestep(t0, 0, t0, dt, sol);
836
837 Eigen::MatrixXd current_rhs = rhs_;
838 StiffnessMatrix stiffness, expanded_mass;
839 build_stiffness_mat(stiffness);
840 expand_primary_matrix(stacked_ndof(), mass_, expanded_mass);
841 const int gdiscr_order = mesh_->orders().size() <= 0 ? 1 : mesh_->orders().maxCoeff();
842 const QuadratureOrders boundary_samples = n_boundary_samples(space_.disc_orders.maxCoeff(), gdiscr_order);
843
844 for (int t = 1; t <= time_steps; ++t)
845 {
846 const double time = t0 + t * dt;
847 rhs_assembler_->compute_energy_grad(
848 boundary_.local_boundary, boundary_.boundary_nodes, mass_assembler_->density(), boundary_samples, boundary_.local_neumann_boundary, rhs_, time,
849 current_rhs);
850 rhs_assembler_->set_bc(
851 boundary_.local_boundary, boundary_.boundary_nodes, boundary_samples, boundary_.local_neumann_boundary, current_rhs, velocity, time);
852
853 if (current_rhs.rows() != stacked_ndof())
854 {
855 const int old_rows = current_rhs.rows();
856 current_rhs.conservativeResize(stacked_ndof(), current_rhs.cols());
857 if (stacked_ndof() > old_rows)
858 current_rhs.bottomRows(stacked_ndof() - old_rows).setZero();
859 }
860 current_rhs.bottomRows(pressure_block_size()).setZero();
861
862 StiffnessMatrix A = expanded_mass / bdf->beta_dt() + stiffness;
863 Eigen::VectorXd b = Eigen::VectorXd::Zero(stacked_ndof());
864 b.head(primary_ndof()) = (mass_ * bdf->weighted_sum_x_prevs()) / bdf->beta_dt();
865 for (int i : boundary_.boundary_nodes)
866 b[i] = 0;
867 b += current_rhs;
868
869 solve_linear_system(solver, A, b, args["output"]["advanced"]["spectrum"].get<bool>() && t == time_steps, sol);
870 split_solution(sol, velocity, pressure);
871 bdf->update_quantities(velocity.col(0));
872
873 save_timestep(time, t, t0, dt, sol);
874 save_step_state(t0, dt, t, time_integrator.get());
875 logger().info("{}/{} t={}", t, time_steps, time);
876 notify_time_step(t, time_steps, t0, dt);
877 }
878 }
879
880 void StokesVarForm::solve_problem(Eigen::MatrixXd &sol)
881 {
882 stats.spectrum.setZero();
883 igl::Timer timer;
884 timer.start();
885 logger().info("Solving {}", primary_assembler_->name());
886
887 prepare_initial_solution(sol);
888 if (problem->is_time_dependent())
889 solve_transient_linear(sol);
890 else
891 {
892 time_integrator = nullptr;
893 solve_static_linear(sol);
894 }
895
896 timer.stop();
897 timings.solving_time = timer.getElapsedTime();
898 logger().info(" took {}s", timings.solving_time);
899 }
900
901 void NavierStokesVarForm::solve_static(Eigen::MatrixXd &sol)
902 {
903 assert(rhs_assembler_ != nullptr);
904 const int gdiscr_order = mesh_->orders().size() <= 0 ? 1 : mesh_->orders().maxCoeff();
905 const QuadratureOrders boundary_samples = n_boundary_samples(space_.disc_orders.maxCoeff(), gdiscr_order);
906 rhs_assembler_->set_bc(
907 boundary_.local_boundary, boundary_.boundary_nodes, boundary_samples, boundary_.local_neumann_boundary, rhs_);
908
909 auto velocity_stokes_assembler = std::make_shared<assembler::StokesVelocity>();
910 set_materials(*velocity_stokes_assembler, mesh_->dimension());
911
912 Eigen::VectorXd x;
913 solver::NavierStokesSolver ns_solver(args["solver"]);
914 ns_solver.minimize(
915 space_.n_bases, pressure_space_.n_bases,
916 space_.basis_list(), pressure_space_.basis_list(),
917 space_.geometry_basis_list(),
918 *velocity_stokes_assembler,
919 *dynamic_cast<assembler::NavierStokesVelocity *>(primary_assembler_.get()),
920 *mixed_assembler_,
921 *pressure_assembler_,
922 ass_vals_cache_,
923 pressure_ass_vals_cache_,
924 boundary_.boundary_nodes,
925 use_avg_pressure,
926 mesh_->dimension(),
927 mesh_->is_volume(),
928 rhs_,
929 x);
930 sol = x;
931 ns_solver.get_info(stats.solver_info);
932 }
933
934 void NavierStokesVarForm::solve_transient(Eigen::MatrixXd &sol)
935 {
936
937 Eigen::MatrixXd velocity, pressure;
938 split_solution(sol, velocity, pressure);
939
940 auto bdf = make_bdf_time_integrator();
941 bdf->init(
942 velocity,
943 Eigen::MatrixXd::Zero(velocity.rows(), velocity.cols()),
944 Eigen::MatrixXd::Zero(velocity.rows(), velocity.cols()),
945 dt);
946 time_integrator = bdf;
947
948 save_timestep(t0, 0, t0, dt, sol);
949
950 Eigen::MatrixXd current_rhs = rhs_;
951 StiffnessMatrix velocity_mass;
952 mass_assembler_->assemble(mesh_->is_volume(), space_.n_bases, space_.basis_list(), space_.geometry_basis_list(), mass_ass_vals_cache_, 0, velocity_mass, true);
953
954 StiffnessMatrix velocity_stiffness, mixed_stiffness, pressure_stiffness;
955 auto velocity_stokes_assembler = std::make_shared<assembler::StokesVelocity>();
956 set_materials(*velocity_stokes_assembler, mesh_->dimension());
957
958 mixed_assembler_->assemble(mesh_->is_volume(), pressure_space_.n_bases, space_.n_bases, pressure_space_.basis_list(), space_.basis_list(), space_.geometry_basis_list(), pressure_ass_vals_cache_, ass_vals_cache_, 0, mixed_stiffness);
959 pressure_assembler_->assemble(mesh_->is_volume(), pressure_space_.n_bases, pressure_space_.basis_list(), space_.geometry_basis_list(), pressure_ass_vals_cache_, 0, pressure_stiffness);
960
961 solver::TransientNavierStokesSolver ns_solver(args["solver"]);
962 for (int t = 1; t <= time_steps; ++t)
963 {
964 const double time = t0 + t * dt;
965 velocity_stokes_assembler->assemble(mesh_->is_volume(), space_.n_bases, space_.basis_list(), space_.geometry_basis_list(), ass_vals_cache_, time, velocity_stiffness);
966
967 logger().info("{}/{} steps, dt={}s t={}s", t, time_steps, dt, time);
968
969 const Eigen::VectorXd prev_sol = bdf->weighted_sum_x_prevs();
970 const int gdiscr_order = mesh_->orders().size() <= 0 ? 1 : mesh_->orders().maxCoeff();
971 const QuadratureOrders boundary_samples = n_boundary_samples(space_.disc_orders.maxCoeff(), gdiscr_order);
972 rhs_assembler_->compute_energy_grad(
973 boundary_.local_boundary, boundary_.boundary_nodes, mass_assembler_->density(), boundary_samples, boundary_.local_neumann_boundary, rhs_, time, current_rhs);
974 rhs_assembler_->set_bc(
975 boundary_.local_boundary, boundary_.boundary_nodes, boundary_samples, boundary_.local_neumann_boundary, current_rhs, velocity, time);
976
977 if (current_rhs.rows() != stacked_ndof())
978 {
979 const int old_rows = current_rhs.rows();
980 current_rhs.conservativeResize(stacked_ndof(), current_rhs.cols());
981 if (stacked_ndof() > old_rows)
982 current_rhs.bottomRows(stacked_ndof() - old_rows).setZero();
983 }
984 current_rhs.bottomRows(pressure_block_size()).setZero();
985
986 Eigen::VectorXd tmp_sol;
987 ns_solver.minimize(
988 space_.n_bases, pressure_space_.n_bases,
989 time,
990 space_.basis_list(), space_.geometry_basis_list(),
991 *dynamic_cast<assembler::NavierStokesVelocity *>(primary_assembler_.get()),
992 ass_vals_cache_,
993 boundary_.boundary_nodes,
994 use_avg_pressure,
995 mesh_->dimension(),
996 mesh_->is_volume(),
997 std::sqrt(bdf->acceleration_scaling()), prev_sol, velocity_stiffness, mixed_stiffness,
998 pressure_stiffness, velocity_mass, current_rhs, tmp_sol);
999 sol = tmp_sol;
1000 split_solution(sol, velocity, pressure);
1001 bdf->update_quantities(velocity.col(0));
1002 save_timestep(time, t, t0, dt, sol);
1003 save_step_state(t0, dt, t, time_integrator.get());
1004 notify_time_step(t, time_steps, t0, dt);
1005 }
1006
1007 ns_solver.get_info(stats.solver_info);
1008 }
1009
1010 void NavierStokesVarForm::solve_problem(Eigen::MatrixXd &sol)
1011 {
1012 stats.spectrum.setZero();
1013 igl::Timer timer;
1014 timer.start();
1015 logger().info("Solving {}", primary_assembler_->name());
1016
1017 prepare_initial_solution(sol);
1018 if (problem->is_time_dependent())
1019 solve_transient(sol);
1020 else
1021 {
1022 time_integrator = nullptr;
1023 solve_static(sol);
1024 }
1025
1026 timer.stop();
1027 timings.solving_time = timer.getElapsedTime();
1028 logger().info(" took {}s", timings.solving_time);
1029 }
1030} // namespace polyfem::varform
int x
std::array< Matrix< int, 3, 3 >, 3 > space_
static std::shared_ptr< MixedAssembler > make_mixed_assembler(const std::string &formulation)
static std::string other_assembler_name(const std::string &formulation)
static void merge_mixed_matrices(const int n_bases, const int n_pressure_bases, const int problem_dim, const bool add_average, const StiffnessMatrix &velocity_stiffness, const StiffnessMatrix &mixed_stiffness, const StiffnessMatrix &pressure_stiffness, StiffnessMatrix &stiffness)
utility to merge 3 blocks of mixed matrices, A=velocity_stiffness, B=mixed_stiffness,...
static std::shared_ptr< Assembler > make_assembler(const std::string &formulation)
void init(const bool is_volume, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const bool is_mass=false)
computes the basis evaluation and geometric mapping for each of the given ElementBases in bases initi...
void init_empty(const bool is_mass=false)
initialize an empty cache.
Represents one basis function and its gradient.
Definition Basis.hpp:44
Stores the basis functions for a given element in a mesh (facet in 2d, cell in 3d).
static void interpolate_at_local_vals(const mesh::Mesh &mesh, const bool is_problem_scalar, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const int el_index, const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &fun, Eigen::MatrixXd &result, Eigen::MatrixXd &result_grad)
interpolate solution and gradient at element (calls interpolate_at_local_vals with sol)
static void compute_stress_at_quadrature_points(const mesh::Mesh &mesh, const bool is_problem_scalar, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXi &disc_orders, const Eigen::VectorXi &disc_ordersq, const assembler::Assembler &assembler, const Eigen::MatrixXd &fun, const double t, Eigen::MatrixXd &result, Eigen::VectorXd &von_mises)
compute von mises stress at quadrature points for the function fun, also compute the interpolated fun...
void export_data(const OutputSpace &space, const OutputFieldFunction &output_fields, const bool is_time_dependent, const double tend_in, const double dt, const ExportOptions &opts, const std::string &vis_mesh_path) const
exports everytihng, txt, vtu, etc
Definition OutData.cpp:1124
double assembling_stiffness_mat_time
time to assembly
double assigning_rhs_time
time to computing the rhs
double assembling_mass_mat_time
time to assembly mass
all stats from polyfem
int n_flipped
number of flipped elements, compute only when using count_flipped_els (false by default)
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)
void count_flipped_elements(const polyfem::mesh::Mesh &mesh, const std::vector< polyfem::basis::ElementBases > &gbases)
counts the number of flipped elements
Definition OutData.cpp:1811
void compute_errors(const int n_bases, const std::vector< polyfem::basis::ElementBases > &bases, const std::vector< polyfem::basis::ElementBases > &gbases, const polyfem::mesh::Mesh &mesh, const assembler::Problem &problem, const double tend, const Eigen::MatrixXd &sol)
compute errors
Definition OutData.cpp:1856
void compute_mesh_size(const polyfem::mesh::Mesh &mesh_in, const std::vector< polyfem::basis::ElementBases > &bases_in, const int n_samples, const bool use_curved_mesh_size)
computes the mesh size, it samples every edges n_samples times uses curved_mesh_size (false by defaul...
Definition OutData.cpp:1728
long long nn_zero
non zeros and sytem matrix size num dof is the total dof in the system
double mesh_size
max edge lenght
void save_json(const nlohmann::json &args, const int n_bases, const int n_pressure_bases, const Eigen::MatrixXd &sol, const mesh::Mesh &mesh, const Eigen::VectorXi &disc_orders, const Eigen::VectorXi &disc_ordersq, const assembler::Problem &problem, const OutRuntimeData &runtime, const std::string &formulation, const bool isoparametric, const int sol_at_node_id, nlohmann::json &j) const
saves the output statistic to a json object
Definition OutData.cpp:2099
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:41
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
Definition Mesh.hpp:163
virtual void bounding_box(RowVectorNd &min, RowVectorNd &max) const =0
computes the bbox of the mesh
virtual bool is_volume() const =0
checks if mesh is volume
void update_nodes(const Eigen::VectorXi &in_node_to_node)
Update the node ids to reorder them.
Definition Mesh.cpp:371
int dimension() const
utily for dimension
Definition Mesh.hpp:153
static const ProblemFactory & factory()
std::shared_ptr< assembler::Problem > get_problem(const std::string &problem) const
static void p_refine(const mesh::Mesh &mesh, const double B, const bool h1_formula, const int base_p, const int discr_order_max, io::OutStatsData &stats, Eigen::VectorXi &disc_orders)
compute a priori prefinement
Definition APriori.cpp:242
void minimize(const int n_bases, const int n_pressure_bases, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &pressure_bases, const std::vector< basis::ElementBases > &gbases, const assembler::Assembler &velocity_stokes_assembler, assembler::NavierStokesVelocity &velocity_assembler, const assembler::MixedAssembler &mixed_assembler, const assembler::Assembler &pressure_assembler, const assembler::AssemblyValsCache &ass_vals_cache, const assembler::AssemblyValsCache &pressure_ass_vals_cache, const std::vector< int > &boundary_nodes, const bool use_avg_pressure, const int problem_dim, const bool is_volume, const Eigen::MatrixXd &rhs, Eigen::VectorXd &x)
void minimize(const int n_bases, const int n_pressure_bases, const double t, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, assembler::NavierStokesVelocity &velocity_assembler, const assembler::AssemblyValsCache &ass_vals_cache, const std::vector< int > &boundary_nodes, const bool use_avg_pressure, const int problem_dim, const bool is_volume, const double beta_dt, const Eigen::VectorXd &prev_sol, const StiffnessMatrix &velocity_stiffness, const StiffnessMatrix &mixed_stiffness, const StiffnessMatrix &pressure_stiffness, const StiffnessMatrix &velocity_mass1, const Eigen::MatrixXd &rhs, Eigen::VectorXd &x)
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
std::shared_ptr< GeometryMapping > geometry
Geometric mapping used to integrate this FE space.
Definition FESpace.hpp:89
Eigen::VectorXi disc_orders
Primary polynomial degree for each mesh element.
Definition FESpace.hpp:71
Eigen::VectorXi disc_ordersq
Secondary polynomial degree for anisotropic bases, e.g. prisms.
Definition FESpace.hpp:74
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
std::map< int, std::pair< Eigen::MatrixXd, Eigen::MatrixXi > > polys_3d
Physical vertices and face connectivity for 3D polyhedral elements.
Definition FESpace.hpp:83
std::map< int, Eigen::MatrixXd > polys
Physical boundary samples for 2D polygonal elements.
Definition FESpace.hpp:80
std::map< int, basis::InterfaceData > poly_edge_to_data
Polygonal-basis construction data, indexed by element ID.
Definition FESpace.hpp:77
const std::vector< basis::ElementBases > & basis_list() const
Definition FESpace.hpp:109
bool is_iso_parametric() const
Definition FESpace.hpp:104
void assemble_rhs(const mesh::Mesh &mesh) override
assembler::AssemblyValsCache pressure_ass_vals_cache_
void assemble_mass_mat(const mesh::Mesh &mesh, const json &args) override
void build_basis(mesh::Mesh &mesh, const bool iso_parametric, const json &args) override
std::shared_ptr< assembler::HRZMass > pure_mass_assembler_
io::OutputSpace output_space() const override
Get the output space of the variational formulation, for output purposes.
VarFormBoundaryState pressure_boundary_
void init(const std::string &formulation, const Units &units, const json &args, const std::string &out_path) override
Initialize the variational formulation with the given parameters.
std::shared_ptr< time_integrator::ImplicitTimeIntegrator > time_integrator
assembler::AssemblyValsCache ass_vals_cache_
void split_solution(const Eigen::MatrixXd &stacked, Eigen::MatrixXd &primary, Eigen::MatrixXd &pressure) const
std::shared_ptr< assembler::Assembler > primary_assembler_
assembler::AssemblyValsCache pure_mass_ass_vals_cache_
std::shared_ptr< assembler::RhsAssembler > rhs_assembler_
void export_data(const Eigen::MatrixXd &solution) const override
void prepare_initial_solution(Eigen::MatrixXd &sol) const
VarFormBoundaryState boundary_
void save_json(const Eigen::MatrixXd &solution, std::ostream &out) const override
Save the solution to a JSON file, for output purposes.
io::OutStatsData compute_errors(const Eigen::MatrixXd &solution) override
Get the error statistics of the variational formulation, for output purposes.
std::shared_ptr< assembler::Mass > mass_assembler_
void solve_linear_system(const std::unique_ptr< polysolve::linear::Solver > &solver, StiffnessMatrix &A, Eigen::VectorXd &b, const bool compute_spectrum, Eigen::MatrixXd &sol)
void build_stiffness_mat(StiffnessMatrix &stiffness)
std::vector< io::OutputField > output_fields(const io::OutputSample &sample, const Eigen::MatrixXd &solution, const io::OutputFieldOptions &options) const override
Get the output fields of the variational formulation, for output purposes.
std::shared_ptr< assembler::Assembler > pressure_assembler_
assembler::AssemblyValsCache mass_ass_vals_cache_
std::shared_ptr< assembler::MixedAssembler > mixed_assembler_
void load_mesh(const mesh::Mesh &mesh, const json &args) override
std::string resolve_input_path(const std::string &path, const bool only_if_exists=false) const
Definition VarForm.cpp:1057
static void rebuild_node_positions(const std::vector< basis::ElementBases > &bases, const std::vector< int > &node_ids, std::vector< RowVectorNd > &positions)
Definition VarForm.cpp:1071
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
Definition VarForm.hpp:191
virtual std::string name() const =0
Get the name of the variational formulation.
std::unique_ptr< mesh::Mesh > mesh_
Definition VarForm.hpp:203
io::OutStatsData stats
Definition VarForm.hpp:195
static bool read_initial_x_from_file(const std::string &state_path, const std::string &x_name, const bool reorder, const Eigen::VectorXi &in_node_to_node, const int dim, Eigen::MatrixXd &x)
Definition VarForm.cpp:39
io::OutGeometryData::ExportOptions export_options(const io::OutputSpace &space) const
Definition VarForm.cpp:846
io::OutGeometryData output_geometry_
Definition VarForm.hpp:207
io::OutputFieldFunction output_field_function(const Eigen::MatrixXd &solution, const io::OutGeometryData::ExportOptions &opts) const
Definition VarForm.cpp:855
std::string resolve_output_path(const std::string &path) const
Definition VarForm.cpp:1062
void ensure_output_sampler() const
Definition VarForm.cpp:832
virtual void init(const std::string &formulation, const Units &units, const json &args, const std::string &out_path)
Initialize the variational formulation with the given parameters.
Definition VarForm.cpp:280
void build_fe_space(mesh::Mesh &mesh, const bool iso_parametric, const Eigen::VectorXi &disc_orders, const std::string &basis_type, const std::string &poly_basis_type, const assembler::Assembler &space_assembler, const int value_dim, const int quadrature_order, const int mass_quadrature_order, const bool use_corner_quadrature, const int n_harmonic_samples, const int integral_constraints, FESpace &space, VarFormBoundaryState &boundary, std::shared_ptr< GeometryMapping > geometry=nullptr)
Definition VarForm.cpp:323
io::OutRuntimeData timings
runtime statistics
Definition VarForm.hpp:198
void set_materials(assembler::Assembler &assembler, const int size) const
Definition VarForm.cpp:817
virtual void reset()=0
Definition VarForm.cpp:268
void assign_discr_orders(const json &discr_order, const mesh::Mesh &mesh, Eigen::VectorXi &disc_orders)
Definition VarForm.cpp:745
str func
Definition p_bases.py:417
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
Eigen::SparseMatrix< double > lump_matrix(const Eigen::SparseMatrix< double > &M)
Lump each row of a matrix into the diagonal.
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
bool write_matrix_market(const json &args, const StiffnessMatrix &stiffness)
void expand_primary_matrix(const int full_size, const StiffnessMatrix &primary, StiffnessMatrix &expanded)
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
bool export_field(const std::string &field) const
Definition OutData.cpp:51
std::vector< std::string > fields
Eigen::VectorXi node_ids
Eigen::VectorXi element_ids
Eigen::MatrixXd local_points
const mesh::Mesh * mesh
std::vector< RowVectorNd > neumann_nodes_position
Definition FESpace.hpp:163
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< RowVectorNd > dirichlet_nodes_position
Definition FESpace.hpp:161
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