33#include <spdlog/fmt/fmt.h>
34#include <paraviewo/VTMWriter.hpp>
39 const std::string &state_path,
40 const std::string &x_name,
42 const Eigen::VectorXi &in_node_to_node,
46 if (state_path.empty())
51 logger().debug(
"Unable to read initial {} from file ({})", x_name, state_path);
57 const int ndof = in_node_to_node.size() * dim;
67 bool should_use_iso_parametric(
const mesh::Mesh &mesh,
const json &args)
72 if (args[
"space"][
"basis_type"] ==
"Bernstein")
75 if (args[
"space"][
"basis_type"] ==
"Spline")
81 if (args[
"space"][
"use_p_ref"])
84 if (mesh.
orders().size() <= 0)
86 if (args[
"space"][
"discr_order"] == 1)
88 return args[
"space"][
"advanced"][
"isoparametric"];
91 if (mesh.
orders().minCoeff() != mesh.
orders().maxCoeff())
94 if (args[
"space"][
"discr_order"] == mesh.
orders().minCoeff())
97 return args[
"space"][
"advanced"][
"isoparametric"];
101 void build_in_node_to_in_primitive(
const mesh::Mesh &mesh,
const mesh::MeshNodes &mesh_nodes,
102 Eigen::VectorXi &in_node_to_in_primitive,
103 Eigen::VectorXi &in_node_offset)
105 const int num_vertex_nodes = mesh_nodes.num_vertex_nodes();
106 const int num_edge_nodes = mesh_nodes.num_edge_nodes();
107 const int num_face_nodes = mesh_nodes.num_face_nodes();
108 const int num_cell_nodes = mesh_nodes.num_cell_nodes();
110 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
112 const long n_vertices = num_vertex_nodes;
113 const int num_in_primitives = n_vertices + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
114 const int num_primitives = mesh.n_vertices() + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
116 in_node_to_in_primitive.resize(num_nodes);
117 in_node_offset.resize(num_nodes);
120 in_node_to_in_primitive.head(num_vertex_nodes).setLinSpaced(num_vertex_nodes, 0, num_vertex_nodes - 1);
121 in_node_offset.head(num_vertex_nodes).setZero();
123 int prim_offset = n_vertices;
124 int node_offset = num_vertex_nodes;
125 auto foo = [&](
const int num_prims,
const int num_prim_nodes) {
126 if (num_prims <= 0 || num_prim_nodes <= 0)
128 const Eigen::VectorXi range = Eigen::VectorXi::LinSpaced(num_prim_nodes, 0, num_prim_nodes - 1);
130 const int node_per_prim = num_prim_nodes / num_prims;
132 in_node_to_in_primitive.segment(node_offset, num_prim_nodes) =
133 range.array() / node_per_prim + prim_offset;
135 in_node_offset.segment(node_offset, num_prim_nodes) =
136 range.unaryExpr([&](
const int x) {
return x % node_per_prim; });
138 prim_offset += num_prims;
139 node_offset += num_prim_nodes;
142 foo(mesh.n_edges(), num_edge_nodes);
143 foo(mesh.n_faces(), num_face_nodes);
144 foo(mesh.n_cells(), num_cell_nodes);
147 bool build_in_primitive_to_primitive(
148 const mesh::Mesh &mesh,
const mesh::MeshNodes &mesh_nodes,
149 const Eigen::VectorXi &in_ordered_vertices,
150 const Eigen::MatrixXi &in_ordered_edges,
151 const Eigen::MatrixXi &in_ordered_faces,
152 Eigen::VectorXi &in_primitive_to_primitive)
155 const int num_vertex_nodes = mesh_nodes.num_vertex_nodes();
156 const int num_edge_nodes = mesh_nodes.num_edge_nodes();
157 const int num_face_nodes = mesh_nodes.num_face_nodes();
158 const int num_cell_nodes = mesh_nodes.num_cell_nodes();
159 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
161 const long n_vertices = num_vertex_nodes;
162 const int num_in_primitives = n_vertices + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
163 const int num_primitives = mesh.n_vertices() + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
165 in_primitive_to_primitive.setLinSpaced(num_in_primitives, 0, num_in_primitives - 1);
173 if (in_ordered_vertices.rows() != n_vertices)
175 logger().warn(
"Node ordering disabled, in_ordered_vertices != n_vertices, {} != {}", in_ordered_vertices.rows(), n_vertices);
179 in_primitive_to_primitive.head(n_vertices) = in_ordered_vertices;
181 int in_offset = n_vertices;
182 int offset = mesh.n_vertices();
188 logger().trace(
"Building Mesh edges to IDs...");
190 const auto edges_to_ids = mesh.edges_to_ids();
191 if (in_ordered_edges.rows() != edges_to_ids.size())
193 logger().warn(
"Node ordering disabled, in_ordered_edges != edges_to_ids, {} != {}", in_ordered_edges.rows(), edges_to_ids.size());
197 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
199 logger().trace(
"Building in-edge to edge mapping...");
201 for (
int in_ei = 0; in_ei < in_ordered_edges.rows(); in_ei++)
203 const std::pair<int, int> in_edge(
204 in_ordered_edges.row(in_ei).minCoeff(),
205 in_ordered_edges.row(in_ei).maxCoeff());
206 in_primitive_to_primitive[in_offset + in_ei] =
207 offset + edges_to_ids.at(in_edge);
210 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
212 in_offset += mesh.n_edges();
213 offset += mesh.n_edges();
219 if (mesh.is_volume())
221 logger().trace(
"Building Mesh faces to IDs...");
223 const auto faces_to_ids = mesh.faces_to_ids();
224 if (in_ordered_faces.rows() != faces_to_ids.size())
226 logger().warn(
"Node ordering disabled, in_ordered_faces != faces_to_ids, {} != {}", in_ordered_faces.rows(), faces_to_ids.size());
230 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
232 logger().trace(
"Building in-face to face mapping...");
234 for (
int in_fi = 0; in_fi < in_ordered_faces.rows(); in_fi++)
236 std::vector<int> in_face(in_ordered_faces.cols());
237 for (
int i = 0; i < in_face.size(); i++)
238 in_face[i] = in_ordered_faces(in_fi, i);
239 std::sort(in_face.begin(), in_face.end());
241 in_primitive_to_primitive[in_offset + in_fi] =
242 offset + faces_to_ids.at(in_face);
245 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
247 in_offset += mesh.n_faces();
248 offset += mesh.n_faces();
258 const int n_b_samples_j =
args[
"space"][
"advanced"][
"n_boundary_samples"];
259 const int boundary_order = std::max({discr_order, discr_orderq, gdiscr_order});
261 return {{n_b_samples, n_b_samples}};
294 mesh_ = std::move(mesh);
311 mesh_->prepare_mesh();
321 const bool iso_parametric,
322 const Eigen::VectorXi &disc_orders,
323 const Eigen::VectorXi &disc_ordersq,
324 const std::string &basis_type,
325 const std::string &poly_basis_type,
328 const int quadrature_order,
329 const int mass_quadrature_order,
330 const bool use_corner_quadrature,
331 const int n_harmonic_samples,
332 const int integral_constraints,
335 std::shared_ptr<GeometryMapping> geometry)
337 using namespace mesh;
339 const std::string space_assembler_name = space_assembler.
name();
340 const bool build_geom_mapping = geometry ==
nullptr;
347 space.
bases = std::make_shared<std::vector<basis::ElementBases>>();
348 space.
geometry = build_geom_mapping ? std::make_shared<GeometryMapping>() : std::move(geometry);
354 Eigen::MatrixXi geom_disc_orders;
355 if (build_geom_mapping && !iso_parametric)
357 if (mesh.
orders().size() <= 0)
360 geom_disc_orders.setConstant(1);
363 geom_disc_orders = mesh.
orders();
365 space.
geometry->bases = std::make_shared<std::vector<basis::ElementBases>>();
366 space.
geometry->disc_orders = geom_disc_orders;
369 Eigen::MatrixXi geom_disc_ordersq = geom_disc_orders;
371 logger().info(
"Building {} basis...", (build_geom_mapping ? (iso_parametric ?
"isoparametric" :
"not isoparametric") :
"finite-element"));
376 const bool has_polys = mesh.
has_poly();
377 std::map<int, basis::InterfaceData> poly_edge_to_data_geom;
379 const bool use_continuous_gbasis =
true;
383 const Mesh3D &tmp_mesh =
dynamic_cast<const Mesh3D &
>(mesh);
385 if (basis_type ==
"Spline")
388 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
393 if (build_geom_mapping && !iso_parametric)
395 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
396 geom_disc_orders, geom_disc_ordersq,
false,
false, has_polys,
397 !use_continuous_gbasis, use_corner_quadrature,
402 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
404 basis_type ==
"Bernstein",
405 basis_type ==
"Serendipity",
406 has_polys,
false, use_corner_quadrature,
412 const Mesh2D &tmp_mesh =
dynamic_cast<const Mesh2D &
>(mesh);
414 if (basis_type ==
"Spline")
417 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
422 if (build_geom_mapping && !iso_parametric)
424 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
425 geom_disc_orders,
false,
false, has_polys,
426 !use_continuous_gbasis, use_corner_quadrature,
431 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
433 basis_type ==
"Bernstein",
434 basis_type ==
"Serendipity",
435 has_polys,
false, use_corner_quadrature,
440 const bool use_fe_space_as_geometry = build_geom_mapping ? iso_parametric : space.
is_iso_parametric();
442 use_fe_space_as_geometry,
444 mass_quadrature_order,
446 integral_constraints,
450 if (build_geom_mapping)
453 space.
geometry->init_from_fe_space(space);
457 assert(space.
geometry->n_bases > 0);
465 if (build_geom_mapping)
468 logger().debug(
"Building node mapping...");
472 logger().debug(
"Done (took {}s)", timer2.getElapsedTime());
485 const std::string &poly_basis_type,
488 const int quadrature_order,
489 const int mass_quadrature_order,
490 const int n_harmonic_samples,
491 const int integral_constraints,
501 const std::string space_assembler_name = space_assembler.
name();
505 logger().info(
"Computing polygonal basis...");
513 if (poly_basis_type ==
"MeanValue" || poly_basis_type ==
"Wachspress")
517 assert(linear_assembler);
524 mass_quadrature_order,
525 integral_constraints,
534 if (poly_basis_type ==
"MeanValue")
537 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
539 mass_quadrature_order,
542 else if (poly_basis_type ==
"Wachspress")
545 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
547 mass_quadrature_order,
553 assert(linear_assembler);
560 mass_quadrature_order,
561 integral_constraints,
575 if (poly_basis_type ==
"MeanValue" || poly_basis_type ==
"Wachspress")
579 assert(linear_assembler);
586 mass_quadrature_order,
587 integral_constraints,
596 if (poly_basis_type ==
"MeanValue")
599 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
601 mass_quadrature_order,
604 else if (poly_basis_type ==
"Wachspress")
607 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
609 mass_quadrature_order,
615 assert(linear_assembler);
622 mass_quadrature_order,
623 integral_constraints,
640 Eigen::MatrixXd &sol,
650 const std::string &basis_type,
652 Eigen::VectorXi &space_in_node_to_node,
653 Eigen::VectorXi &space_in_primitive_to_primitive)
const
655 space_in_node_to_node.resize(0);
656 space_in_primitive_to_primitive.resize(0);
658 if (basis_type ==
"Spline")
660 logger().warn(
"Node ordering disabled, it dosent work for splines!");
666 logger().warn(
"Node ordering disabled, it works only for p < 4 and uniform order!");
672 logger().warn(
"Node ordering disabled, not supported for non-conforming meshes!");
678 logger().warn(
"Node ordering disabled, not supported for polygonal meshes!");
684 logger().warn(
"Node ordering disabled, input vertices/edges/faces not computed!");
690 logger().warn(
"Node ordering disabled, FE space does not expose mesh nodes!");
694 const int num_vertex_nodes = space.
mesh_nodes->num_vertex_nodes();
695 const int num_edge_nodes = space.
mesh_nodes->num_edge_nodes();
696 const int num_face_nodes = space.
mesh_nodes->num_face_nodes();
697 const int num_cell_nodes = space.
mesh_nodes->num_cell_nodes();
699 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
700 const long n_vertices = num_vertex_nodes;
706 logger().trace(
"Building in-node to in-primitive mapping...");
708 Eigen::VectorXi in_node_to_in_primitive;
709 Eigen::VectorXi in_node_offset;
710 build_in_node_to_in_primitive(mesh, *space.
mesh_nodes, in_node_to_in_primitive, in_node_offset);
712 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
714 logger().trace(
"Building in-primitive to primitive mapping...");
716 bool ok = build_in_primitive_to_primitive(
721 space_in_primitive_to_primitive);
723 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
727 space_in_node_to_node.resize(0);
728 space_in_primitive_to_primitive.resize(0);
732 const auto &tmp = space.
mesh_nodes->in_ordered_vertices();
735 max_tmp = std::max(max_tmp, v);
737 space_in_node_to_node.resize(max_tmp + 1);
738 for (
int i = 0; i < tmp.size(); ++i)
741 space_in_node_to_node[tmp[i]] = i;
746 const json &space_args,
748 Eigen::VectorXi &disc_orders,
749 Eigen::VectorXi &disc_ordersq)
755 const json &space_args,
756 const int fe_space_id,
758 Eigen::VectorXi &disc_orders,
759 Eigen::VectorXi &disc_ordersq)
761 const auto assign_order = [&](
const json &order_json, Eigen::VectorXi &orders) {
764 if (order_json.is_number_integer())
766 orders.setConstant(order_json);
768 else if (order_json.is_string())
773 assert(tmp.size() == orders.size());
774 assert(tmp.cols() == 1);
777 else if (order_json.is_array())
780 std::map<int, int> body_orders;
781 bool has_matching_order =
false;
782 for (
const json &entry : order_json)
784 if (entry.contains(
"fe_space"))
786 const int entry_space_id = entry[
"fe_space"].get<
int>();
787 if (entry_space_id >= 0 && fe_space_id < 0)
789 if (entry_space_id >= 0 && entry_space_id != fe_space_id)
793 has_matching_order =
true;
794 const int order = entry[
"order"];
795 if (!entry.contains(
"id") || (entry[
"id"].is_number_integer() && entry[
"id"].get<
int>() < 0))
797 orders.setConstant(order);
801 for (
const int id : utils::json_as_array<int>(entry[
"id"]))
803 body_orders[id] = order;
804 logger().trace(
"bid {}, discr {}",
id, order);
808 if (!has_matching_order)
813 const auto order = body_orders.find(mesh.
get_body_id(e));
814 if (order != body_orders.end())
815 orders[e] = order->second;
824 assign_order(space_args[
"discr_order"], disc_orders);
826 const json &discr_orderq = space_args[
"discr_orderq"];
827 if (discr_orderq.is_number_integer() && discr_orderq.get<
int>() < 0)
828 disc_ordersq = disc_orders;
830 assign_order(discr_orderq, disc_ordersq);
832 int max_prism_order = 0;
836 max_prism_order = std::max({max_prism_order, disc_orders[e], disc_ordersq[e]});
839 if (max_prism_order > 0)
844 disc_orders[e] = max_prism_order;
849 "discretization orders: p=[{}, {}], q=[{}, {}]",
850 disc_orders.minCoeff(), disc_orders.maxCoeff(),
851 disc_ordersq.minCoeff(), disc_ordersq.maxCoeff());
857 if (out_path.empty())
860 std::ofstream file(out_path);
863 logger().error(
"Unable to save simulation JSON to {}", out_path);
871 assert(
mesh_ !=
nullptr);
877 std::vector<int> body_ids(
mesh_->n_elements());
878 for (
int i = 0; i <
mesh_->n_elements(); ++i)
879 body_ids[i] =
mesh_->get_body_id(i);
913 sample.requested_fields.empty() ? fields : sample.requested_fields});
931 const bool rest_mesh_written)
const
935 if (!state_path.empty() && time_integrator)
941 void VarForm::save_timestep(
const double time,
const int t,
const double t0,
const double dt,
const Eigen::MatrixXd &solution)
const
943 paraviewo::VTMWriter vtm(time);
948 const std::string step_name =
args[
"output"][
"advanced"][
"timestep_prefix"];
953 [step_name](
int i) {
return fmt::format(step_name +
"{:d}.vtm", i); },
954 global_t, t0, dt,
args[
"output"][
"paraview"][
"skip_frame"].get<
int>());
958 const double time,
const int t,
const double dt,
959 const Eigen::MatrixXd &solution, paraviewo::VTMWriter &vtm,
960 const std::string &block_prefix)
const
963 if (!space.
mesh || !
args[
"output"][
"advanced"][
"save_time_sequence"])
966 if (global_t %
args[
"output"][
"paraview"][
"skip_frame"].get<int>())
970 logger().trace(
"Saving VTU...");
971 const std::string step_name =
args[
"output"][
"advanced"][
"timestep_prefix"];
976 opts, vtm, block_prefix);
983 if (!space.
mesh || !
args[
"output"][
"advanced"][
"save_solve_sequence_debug"].get<
bool>())
986 const bool has_time =
args.contains(
"time") && !
args[
"time"].is_null();
989 dt =
args[
"time"][
"dt"];
1002 time_callback(t, time_steps, t0 + dt * t, t0 + dt * time_steps);
1007 const std::string restart_json_path =
args[
"output"][
"restart_json"];
1008 if (restart_json_path.empty())
1016 restart_json[
"time"] = {{
"t0", t0 + dt * t}};
1017 restart_json[
"output"] = {{
"data", {{
"file_index_offset", global_t}}}};
1019 restart_json[
"space"] = R
"({
1022 "abs_max_edge_length": -1,
1023 "rel_max_edge_length": -1
1029 restart_json[
"space"][
"remesh"][
"collapse"][
"abs_max_edge_length"] = std::min(
1030 args[
"space"][
"remesh"][
"collapse"][
"abs_max_edge_length"].get<double>(),
1031 starting_min_edge_length *
args[
"space"][
"remesh"][
"collapse"][
"rel_max_edge_length"].get<double>());
1032 restart_json[
"space"][
"remesh"][
"collapse"][
"rel_max_edge_length"] = std::numeric_limits<float>::max();
1034 std::string rest_mesh_path =
args[
"output"][
"data"][
"rest_mesh"].get<std::string>();
1035 if (!rest_mesh_path.empty())
1037 if (!rest_mesh_written)
1038 logger().warn(
"Restart JSON for {} references a rest mesh that this formulation does not write.",
name());
1042 std::vector<json> patch;
1043 if (
args[
"geometry"].is_array())
1045 const std::vector<json> in_geometry =
args[
"geometry"];
1046 for (
int i = 0; i < in_geometry.size(); ++i)
1048 if (!in_geometry[i][
"is_obstacle"].get<bool>())
1052 {
"path", fmt::format(
"/geometry/{}", i)},
1057 const int remaining_geometry = in_geometry.size() - patch.size();
1058 assert(remaining_geometry >= 0);
1062 {
"path", fmt::format(
"/geometry/{}", remaining_geometry > 0 ?
"0" :
"-")},
1065 {
"mesh", rest_mesh_path},
1071 assert(
args[
"geometry"].is_object());
1074 {
"path",
"/geometry"},
1078 {
"path",
"/geometry"},
1081 {
"mesh", rest_mesh_path},
1086 restart_json[
"patch"] = patch;
1089 restart_json[
"input"] = {{
1097 file << restart_json;
1102 return t +
args[
"output"][
"data"][
"file_index_offset"].get<
int>();
1112 if (
output_path.empty() || path.empty() || std::filesystem::path(path).is_absolute())
1116 return std::filesystem::weakly_canonical(std::filesystem::path(
output_path) / path).string();
1120 const std::vector<basis::ElementBases> &bases,
1121 const std::vector<int> &node_ids,
1122 std::vector<RowVectorNd> &positions)
1124 positions.resize(node_ids.size());
1125 for (
int n = 0; n < int(node_ids.size()); ++n)
1127 const int node_id = node_ids[n];
1129 for (
const auto &bs : bases)
1131 for (
const auto &b : bs.bases)
1133 for (
const auto &lg : b.global())
1135 if (lg.index == node_id)
1137 positions[n] = lg.node;
virtual bool is_tensor() const
virtual std::string name() const =0
virtual void set_size(const int size)
void set_materials(const std::vector< int > &body_ids, const json &body_params, const Units &units, const std::string &root_path)
static int quadrature_order(const std::string &assembler, const int basis_degree, const BasisType &b_type, const int dim)
utility for retrieving the needed quadrature order to precisely integrate the given form on the given...
assemble matrix based on the local assembler local assembler is eg Laplace, LinearElasticity etc
static int build_bases(const mesh::Mesh2D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, const int discr_order, const bool bernstein, const bool serendipity, const bool has_polys, const bool is_geom_bases, const bool use_corner_quadrature, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_edge_to_data, std::shared_ptr< mesh::MeshNodes > &mesh_nodes)
Builds FE basis functions over the entire mesh (P1, P2 over triangles, Q1, Q2 over quads).
static int build_bases(const mesh::Mesh3D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, const int discr_orderp, const int discr_orderq, const bool bernstein, const bool serendipity, const bool has_polys, const bool is_geom_bases, const bool use_corner_quadrature, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_face_to_data, std::shared_ptr< mesh::MeshNodes > &mesh_nodes)
Builds FE basis functions over the entire mesh (P1, P2 over tets, Q1, Q2 over hes).
static int build_bases(const std::string &assembler_name, const int dim, const mesh::Mesh2D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, Eigen::MatrixXd > &mapped_boundary)
static int build_bases(const assembler::LinearAssembler &assembler, const int n_samples_per_edge, const mesh::Mesh2D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, const int integral_constraints, std::vector< ElementBases > &bases, const std::vector< ElementBases > &gbases, const std::map< int, InterfaceData > &poly_edge_to_data, std::map< int, Eigen::MatrixXd > &mapped_boundary)
Build bases over the remaining polygons of a mesh.
static int build_bases(const assembler::LinearAssembler &assembler, const int n_samples_per_edge, const mesh::Mesh3D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, const int integral_constraints, std::vector< ElementBases > &bases, const std::vector< ElementBases > &gbases, const std::map< int, InterfaceData > &poly_face_to_data, std::map< int, std::pair< Eigen::MatrixXd, Eigen::MatrixXi > > &mapped_boundary)
Build bases over the remaining polygons of a mesh.
static int build_bases(const mesh::Mesh2D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_edge_to_data)
static int build_bases(const mesh::Mesh3D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_face_to_data)
static int build_bases(const std::string &assembler_name, const int dim, const mesh::Mesh2D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, Eigen::MatrixXd > &mapped_boundary)
void build_grid(const polyfem::mesh::Mesh &mesh, const double spacing)
builds the grid to export the solution
void save_pvd(const std::string &name, const std::function< std::string(int)> &vtu_names, int time_steps, double t0, double dt, int skip_frame=1) const
save a PVD of a time dependent simulation
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
void init_sampler(const polyfem::mesh::Mesh &mesh, const double vismesh_rel_area)
unitalize the ref element sampler
double loading_mesh_time
time to load the mesh
double building_basis_time
time to construct the basis
double computing_poly_basis_time
time to build the polygonal/polyhedral bases
void reset()
clears all stats
void compute_mesh_stats(const polyfem::mesh::Mesh &mesh)
compute stats (counts els type, mesh lenght, etc), step 1 of solve
double min_edge_length
min edge lenght
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
virtual int n_vertices() const =0
number of vertices
virtual int get_body_id(const int primitive) const
Get the volume selection of an element (cell in 3d, face in 2d)
const Eigen::MatrixXi & in_ordered_edges() const
Order of the input edges.
bool is_rational() const
check if curved mesh has rational polynomials elements
virtual bool is_conforming() const =0
if the mesh is conforming
const Eigen::MatrixXi & orders() const
order of each element
bool is_simplex(const int el_id) const
checks if element is simplex
bool has_prism() const
checks if the mesh has prisms
bool is_prism(const int el_id) const
checks if element is a prism
bool is_linear() const
check if the mesh is linear
virtual bool is_volume() const =0
checks if mesh is volume
bool has_poly() const
checks if the mesh has polytopes
const Eigen::VectorXi & in_ordered_vertices() const
Order of the input vertices.
int dimension() const
utily for dimension
virtual int n_cells() const =0
number of cells
virtual int n_faces() const =0
number of faces
bool is_pyramid(const int el_id) const
checks if element is a pyramid
const Eigen::MatrixXi & in_ordered_faces() const
Order of the input edges.
virtual int n_edges() const =0
number of edges
Implicit time integrator of a second order ODE (equivently a system of coupled first order ODEs).
virtual void save_state(const std::string &state_path) const
Save the values of , , and .
bool read_matrix(const std::string &path, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Reads a matrix from a file. Determines the file format based on the path's extension.
std::function< std::vector< OutputField >(const OutputSample &)> OutputFieldFunction
Eigen::MatrixXd reorder_matrix(const Eigen::MatrixXd &in, const Eigen::VectorXi &in_to_out, int out_blocks=-1, const int block_size=1)
Reorder row blocks in a matrix.
std::string resolve_path(const std::string &path, const std::string &input_file_path, const bool only_if_exists=false)
bool is_param_valid(const json ¶ms, const std::string &key)
Determine if a key exists and is non-null in a json object.
spdlog::logger & logger()
Retrieves the current logger.
std::array< int, 2 > QuadratureOrders
void log_and_throw_error(const std::string &msg)
std::vector< std::string > fields