OGS
NodeWiseMeshPartitioner.cpp
Go to the documentation of this file.
1
16
17#include <limits>
18#include <numeric>
19#include <range/v3/algorithm/transform.hpp>
20#include <range/v3/range/conversion.hpp>
21#include <unordered_map>
22
23#include "BaseLib/Error.h"
24#include "BaseLib/FileTools.h"
25#include "BaseLib/Logging.h"
26#include "BaseLib/RunTime.h"
28#include "MeshLib/IO/NodeData.h"
30#include "MeshLib/MeshEnums.h"
33
34namespace ApplicationUtils
35{
37 MeshLib::MeshItemType const item_type) const
38{
39 if (item_type == MeshLib::MeshItemType::Node)
40 {
41 return nodes.size();
42 }
43
44 if (item_type == MeshLib::MeshItemType::Cell)
45 {
46 return regular_elements.size() + ghost_elements.size();
47 }
48
50 {
52 }
53 OGS_FATAL("Mesh items other than nodes and cells are not supported.");
54}
55
57 std::ostream& os, std::vector<std::size_t> const& global_node_ids) const
58{
59 std::vector<MeshLib::IO::NodeData> nodes_buffer;
60 nodes_buffer.reserve(nodes.size());
61
62 for (const auto* node : nodes)
63 {
64 double const* coords = node->data();
65 nodes_buffer.emplace_back(global_node_ids[node->getID()], coords[0],
66 coords[1], coords[2]);
67 }
68 return os.write(reinterpret_cast<const char*>(nodes_buffer.data()),
69 sizeof(MeshLib::IO::NodeData) * nodes_buffer.size());
70}
71
77 std::vector<const MeshLib::Element*> const& elements)
78{
79 return 3 * elements.size() +
80 std::accumulate(begin(elements), end(elements), 0,
81 [](auto const nnodes, auto const* e)
82 { return nnodes + e->getNumberOfNodes(); });
83}
84
85std::ostream& Partition::writeConfig(std::ostream& os) const
86{
87 long const data[] = {
88 static_cast<long>(nodes.size()),
89 static_cast<long>(number_of_base_nodes),
90 static_cast<long>(regular_elements.size()),
91 static_cast<long>(ghost_elements.size()),
92 static_cast<long>(number_of_regular_base_nodes),
93 static_cast<long>(number_of_regular_nodes),
94 static_cast<long>(number_of_mesh_base_nodes),
95 static_cast<long>(number_of_mesh_all_nodes),
96 static_cast<long>(
98 static_cast<long>(
100 };
101
102 return os.write(reinterpret_cast<const char*>(data), sizeof(data));
103}
104
105std::size_t partitionLookup(std::size_t const& node_id,
106 std::vector<std::size_t> const& partition_ids,
107 std::vector<std::size_t> const& node_id_mapping)
108{
109 return partition_ids[node_id_mapping[node_id]];
110}
111
112std::pair<std::vector<MeshLib::Node const*>, std::vector<MeshLib::Node const*>>
113splitIntoBaseAndHigherOrderNodes(std::vector<MeshLib::Node const*> const& nodes,
114 MeshLib::Mesh const& mesh)
115{
116 // Space for resulting vectors.
117 std::vector<MeshLib::Node const*> base_nodes;
118 // if linear mesh, then one reallocation, no realloc for higher order
119 // elements meshes.
120 base_nodes.reserve(nodes.size() / 2);
121 std::vector<MeshLib::Node const*> higher_order_nodes;
122 // if linear mesh, then wasted space, good estimate for quadratic
123 // order mesh, and realloc needed for higher order element meshes.
124 higher_order_nodes.reserve(nodes.size() / 2);
125
126 // Split the nodes into base nodes and extra nodes.
127 std::partition_copy(
128 begin(nodes), end(nodes), std::back_inserter(base_nodes),
129 std::back_inserter(higher_order_nodes),
130 [&](MeshLib::Node const* const n)
131 { return isBaseNode(*n, mesh.getElementsConnectedToNode(*n)); });
132
133 return {base_nodes, higher_order_nodes};
134}
135
139std::tuple<std::vector<MeshLib::Node*>, std::vector<MeshLib::Node*>>
141 std::size_t const part_id,
142 std::vector<MeshLib::Node*> const& nodes,
143 std::vector<MeshLib::Element const*> const& ghost_elements,
144 std::vector<std::size_t> const& partition_ids,
145 MeshLib::Mesh const& mesh,
146 std::vector<std::size_t> const& node_id_mapping)
147{
148 std::vector<MeshLib::Node*> base_ghost_nodes;
149 std::vector<MeshLib::Node*> higher_order_ghost_nodes;
150
151 std::vector<bool> is_ghost_node(nodes.size(), false);
152 for (const auto* ghost_elem : ghost_elements)
153 {
154 for (unsigned i = 0; i < ghost_elem->getNumberOfNodes(); i++)
155 {
156 auto const& n = ghost_elem->getNode(i);
157 auto const node_id = n->getID();
158 if (is_ghost_node[node_id])
159 {
160 continue;
161 }
162
163 if (partitionLookup(node_id, partition_ids, node_id_mapping) !=
164 part_id)
165 {
166 if (isBaseNode(*n, mesh.getElementsConnectedToNode(*n)))
167 {
168 base_ghost_nodes.push_back(nodes[node_id]);
169 }
170 else
171 {
172 higher_order_ghost_nodes.push_back(nodes[node_id]);
173 }
174 is_ghost_node[node_id] = true;
175 }
176 }
177 }
178 return std::tuple<std::vector<MeshLib::Node*>, std::vector<MeshLib::Node*>>{
179 base_ghost_nodes, higher_order_ghost_nodes};
180}
181
184template <typename T>
186 Partition const& p,
187 std::size_t const offset,
189 MeshLib::PropertyVector<T>& partitioned_pv)
190{
191 auto const& nodes = p.nodes;
192 auto const nnodes = nodes.size();
193 auto const n_components = pv.getNumberOfGlobalComponents();
194 for (std::size_t i = 0; i < nnodes; ++i)
195 {
196 const auto global_id = nodes[i]->getID();
197 std::copy_n(&pv[n_components * global_id], n_components,
198 &partitioned_pv[offset + n_components * i]);
199 }
200 return n_components * nnodes;
201}
202
206template <typename T>
208 Partition const& p,
209 std::size_t const offset,
211 MeshLib::PropertyVector<T>& partitioned_pv)
212{
213 std::size_t const n_regular(p.regular_elements.size());
214 auto const n_components = pv.getNumberOfGlobalComponents();
215 for (std::size_t i = 0; i < n_regular; ++i)
216 {
217 const auto id = p.regular_elements[i]->getID();
218 std::copy_n(&pv[n_components * id], n_components,
219 &partitioned_pv[offset + n_components * i]);
220 }
221
222 std::size_t const n_ghost(p.ghost_elements.size());
223 for (std::size_t i = 0; i < n_ghost; ++i)
224 {
225 const auto id = p.ghost_elements[i]->getID();
226 std::copy_n(&pv[n_components * id], n_components,
227 &partitioned_pv[offset + n_components * (n_regular + i)]);
228 }
229 return n_components * (n_regular + n_ghost);
230}
231
236template <typename T>
238 MeshLib::Properties const& properties,
239 Partition const& p,
240 std::size_t const id_offset_partition,
241 std::vector<std::size_t> const& element_ip_data_offsets,
243 MeshLib::PropertyVector<T>& partitioned_pv)
244{
245 // Special field data such as OGS_VERSION, IntegrationPointMetaData,
246 // etc., which are not "real" integration points, are copied "as is"
247 // (i.e. fully) for every partition.
248 if (pv.getPropertyName().find("_ip") == std::string::npos)
249 {
250 std::copy_n(&pv[0], pv.size(), &partitioned_pv[id_offset_partition]);
251 return pv.size();
252 }
253
254 auto const n_components = pv.getNumberOfGlobalComponents();
255
256 std::size_t id_offset = 0;
257
258 auto copyFieldData =
259 [&](std::vector<const MeshLib::Element*> const& elements)
260 {
261 auto const ip_meta_data = MeshLib::getIntegrationPointMetaData(
262 properties, pv.getPropertyName());
263
264 for (auto const element : elements)
265 {
266 int const number_of_element_field_data =
268 *element) *
269 n_components;
270 // The original element ID is not changed.
271 auto const element_id = element->getID();
272 int const begin_pos = element_ip_data_offsets[element_id];
273 int const end_pos = element_ip_data_offsets[element_id + 1];
274
275 std::copy(pv.begin() + begin_pos, pv.begin() + end_pos,
276 &partitioned_pv[id_offset + id_offset_partition]);
277 id_offset += number_of_element_field_data;
278 }
279 };
280
281 copyFieldData(p.regular_elements);
282 copyFieldData(p.ghost_elements);
283
284 return id_offset;
285}
286
288 std::vector<Partition>& partitions)
289{
290 for (auto const& [name, property] : properties)
291 {
292 auto const item_type = property->getMeshItemType();
293
295 {
296 continue;
297 }
298
299 // For special field data such as OGS_VERSION, IntegrationPointMetaData,
300 // etc., which are not "real" integration points:
301 if (property->getPropertyName().find("_ip") == std::string::npos)
302 {
303 continue;
304 }
305
306 std::string const property_name = property->getPropertyName();
307 auto countIntegrationPoints =
308 [&](std::vector<const MeshLib::Element*> const& elements)
309 {
310 auto const ip_meta_data =
311 MeshLib::getIntegrationPointMetaData(properties, property_name);
312 std::size_t counter = 0;
313 for (auto const element : elements)
314 {
315 int const number_of_integration_points =
317 ip_meta_data, *element);
318 counter += number_of_integration_points;
319 }
320 return counter;
321 };
322
323 for (auto& p : partitions)
324 {
325 p.number_of_integration_points =
326 countIntegrationPoints(p.regular_elements) +
327 countIntegrationPoints(p.ghost_elements);
328 }
329 return;
330 }
331}
332
333template <typename T>
335 std::vector<MeshLib::Element*> const& global_mesh_elements,
336 MeshLib::Properties& partitioned_properties,
337 MeshLib::Properties const& properties,
338 std::vector<Partition> const& partitions,
339 MeshLib::PropertyVector<T> const* const pv,
340 std::map<MeshLib::MeshItemType, std::size_t> const& total_number_of_tuples)
341{
342 if (pv == nullptr)
343 {
344 return false;
345 }
346 auto const item_type = pv->getMeshItemType();
347
348 std::size_t partitioned_pv_size = total_number_of_tuples.at(item_type) *
350
351 std::vector<std::size_t> element_ip_data_offsets;
353 {
354 // Special field data such as OGS_VERSION, IntegrationPointMetaData,
355 // etc., which are not "real" integration points, are copied "as is"
356 // (i.e. fully) for every partition.
357 if (pv->getPropertyName().find("_ip") == std::string::npos)
358 {
359 partitioned_pv_size = pv->size() * partitions.size();
360 }
361
362 element_ip_data_offsets =
364 global_mesh_elements, *pv, properties);
365 }
366
367 auto partitioned_pv = partitioned_properties.createNewPropertyVector<T>(
368 pv->getPropertyName(), pv->getMeshItemType(),
370 partitioned_pv->resize(partitioned_pv_size);
371
372 auto copy_property_vector_values =
373 [&](Partition const& p, std::size_t offset)
374 {
376 {
377 return copyFieldPropertyDataToPartitions(properties, p, offset,
378 element_ip_data_offsets,
379 *pv, *partitioned_pv);
380 }
381
382 if (item_type == MeshLib::MeshItemType::Node)
383 {
384 return copyNodePropertyVectorValues(p, offset, *pv,
385 *partitioned_pv);
386 }
387 if (item_type == MeshLib::MeshItemType::Cell)
388 {
389 return copyCellPropertyVectorValues(p, offset, *pv,
390 *partitioned_pv);
391 }
392
393 OGS_FATAL(
394 "Copying of property vector values for mesh item type {:s} is not "
395 "implemented.",
396 toString(item_type));
397 };
398
399 std::size_t position_offset(0);
400 for (auto p : partitions)
401 {
402 position_offset += copy_property_vector_values(p, position_offset);
403 }
404 return true;
405}
406
407void addVtkGhostTypeProperty(MeshLib::Properties& partitioned_properties,
408 std::vector<Partition> const& partitions,
409 std::size_t const total_number_of_cells)
410{
411 auto* vtk_ghost_type =
412 partitioned_properties.createNewPropertyVector<unsigned char>(
413 "vtkGhostType", MeshLib::MeshItemType::Cell);
414 if (vtk_ghost_type == nullptr)
415 {
416 OGS_FATAL("Could not create vtkGhostType cell data array.");
417 }
418
419 vtk_ghost_type->resize(total_number_of_cells);
420 std::size_t offset = 0;
421 for (auto const& partition : partitions)
422 {
423 offset += partition.regular_elements.size();
424 for (std::size_t i = 0; i < partition.ghost_elements.size(); ++i)
425 {
426 if (partition.duplicate_ghost_cell[i])
427 {
428 (*vtk_ghost_type)[offset + i] |=
429 vtkDataSetAttributes::DUPLICATECELL;
430 }
431 }
432 offset += partition.ghost_elements.size();
433 }
434}
435
438 std::unique_ptr<MeshLib::Mesh> const& mesh,
439 std::vector<Partition>& partitions)
440{
441 using namespace MeshLib;
442
443 MeshLib::Properties const& properties = mesh->getProperties();
444
445 // Count the number of integration point data of all partitions:
446 setIntegrationPointNumberOfPartition(properties, partitions);
447
448 Properties partitioned_properties;
449 auto count_tuples = [&](MeshItemType const mesh_item_type)
450 {
451 return std::accumulate(
452 begin(partitions), end(partitions), 0,
453 [&](std::size_t const sum, Partition const& p)
454 { return sum + p.numberOfMeshItems(mesh_item_type); });
455 };
456
457 std::map<MeshItemType, std::size_t> const total_number_of_tuples = {
458 {MeshItemType::Cell, count_tuples(MeshItemType::Cell)},
459 {MeshItemType::Node, count_tuples(MeshItemType::Node)},
460 {MeshItemType::IntegrationPoint,
461 count_tuples(MeshItemType::IntegrationPoint)}};
462
463 DBUG(
464 "total number of tuples after partitioning defined for cells is {:d} "
465 "and for nodes {:d} and for integration points {:d}.",
466 total_number_of_tuples.at(MeshItemType::Cell),
467 total_number_of_tuples.at(MeshItemType::Node),
468 total_number_of_tuples.at(MeshItemType::IntegrationPoint));
469
470 // 1 create new PV
471 // 2 resize the PV with total_number_of_tuples
472 // 3 copy the values according to the partition info
474 properties,
475 [&](auto type, auto const property)
476 {
478 mesh->getElements(), partitioned_properties, properties,
479 partitions,
480 dynamic_cast<PropertyVector<decltype(type)> const*>(property),
481 total_number_of_tuples);
482 });
483
484 addVtkGhostTypeProperty(partitioned_properties,
485 partitions,
486 total_number_of_tuples.at(MeshItemType::Cell));
487
488 return partitioned_properties;
489}
490
492 std::vector<Partition>& partitions)
493{
494 std::vector<bool> cell_visited(mesh.getElements().size(), false);
495
496 for (auto& partition : partitions)
497 {
498 partition.duplicate_ghost_cell.resize(partition.ghost_elements.size(),
499 true);
500
501 for (std::size_t i = 0; i < partition.ghost_elements.size(); i++)
502 {
503 const auto& ghost_element = *partition.ghost_elements[i];
504 if (!cell_visited[ghost_element.getID()])
505 {
506 cell_visited[ghost_element.getID()] = true;
507 partition.duplicate_ghost_cell[i] = false;
508 }
509 }
510 }
511}
512
514 std::vector<MeshLib::Element*> const& global_mesh_elements,
515 MeshLib::Properties const& properties)
516{
517 for (auto const& [name, property] : properties)
518 {
519 auto const item_type = property->getMeshItemType();
520
522 {
523 continue;
524 }
525
526 // For special field data such as OGS_VERSION, IntegrationPointMetaData,
527 // etc., which are not "real" integration points:
528 if (property->getPropertyName().find("_ip") == std::string::npos)
529 {
530 continue;
531 }
532
533 std::size_t number_of_total_integration_points = 0;
534 auto const ip_meta_data = MeshLib::getIntegrationPointMetaData(
535 properties, property->getPropertyName());
536 for (auto const element : global_mesh_elements)
537 {
538 int const number_of_integration_points =
540 *element);
541 number_of_total_integration_points += number_of_integration_points;
542 }
543
544 const auto pv =
545 dynamic_cast<MeshLib::PropertyVector<double> const*>(property);
546 std::size_t const component_number = pv->getNumberOfGlobalComponents();
547 if (pv->size() != number_of_total_integration_points * component_number)
548 {
549 OGS_FATAL(
550 "The property vector's size {:d} for integration point data "
551 "{:s} does not match its actual size {:d}. The field data in "
552 "the vtu file are wrong.",
553 pv->size(), name,
554 number_of_total_integration_points * component_number);
555 }
556 }
557}
558
559std::vector<std::vector<std::size_t>> computePartitionIDPerElement(
560 std::vector<std::size_t> const& node_partition_map,
561 std::vector<MeshLib::Element*> const& elements,
562 std::vector<std::size_t> const& bulk_node_ids)
563{
564 auto node_partition_ids = ranges::views::transform(
565 [&](MeshLib::Element const* const element)
566 {
567 auto node_lookup = ranges::views::transform(
568 [&](std::size_t const i)
569 { return node_partition_map[bulk_node_ids[i]]; });
570
571 return element->nodes() | MeshLib::views::ids | node_lookup |
572 ranges::to<std::vector>;
573 });
574
575 return elements | node_partition_ids | ranges::to<std::vector>;
576}
577
579 std::vector<Partition>& partitions,
580 std::vector<std::size_t> const& nodes_partition_ids,
581 std::vector<MeshLib::Node*> const& nodes,
582 std::vector<std::size_t> const& bulk_node_ids)
583{
584 for (auto const* const node : nodes)
585 {
586 partitions[nodes_partition_ids[bulk_node_ids[node->getID()]]]
587 .nodes.push_back(node);
588 }
589}
590
592 MeshLib::Mesh const& mesh)
593{
594 std::vector<MeshLib::Node const*> higher_order_nodes;
595 // after splitIntoBaseAndHigherOrderNodes() partition.nodes contains only
596 // base nodes
597 std::tie(partition.nodes, higher_order_nodes) =
599 partition.number_of_regular_base_nodes = partition.nodes.size();
600 std::copy(begin(higher_order_nodes), end(higher_order_nodes),
601 std::back_inserter(partition.nodes));
602 partition.number_of_regular_nodes = partition.nodes.size();
603}
604
606 std::vector<Partition>& partitions, MeshLib::Mesh const& mesh)
607{
608 for (auto& partition : partitions)
609 {
611 }
612}
613
614void setNumberOfNodesInPartitions(std::vector<Partition>& partitions,
615 MeshLib::Mesh const& mesh)
616{
617 auto const number_of_mesh_base_nodes = mesh.computeNumberOfBaseNodes();
618 auto const number_of_mesh_all_nodes = mesh.getNumberOfNodes();
619 for (auto& partition : partitions)
620 {
621 partition.number_of_regular_nodes = partition.nodes.size();
622 partition.number_of_mesh_base_nodes = number_of_mesh_base_nodes;
623 partition.number_of_mesh_all_nodes = number_of_mesh_all_nodes;
624 }
625}
626
628 std::vector<Partition>& partitions,
629 MeshLib::Mesh const& mesh,
630 std::vector<std::vector<std::size_t>> const& partition_ids_per_element)
631{
632 for (auto const& element : mesh.getElements())
633 {
634 auto const element_id = element->getID();
635 auto node_partition_ids = partition_ids_per_element[element_id];
636 // make partition ids unique
637 std::sort(node_partition_ids.begin(), node_partition_ids.end());
638 auto last =
639 std::unique(node_partition_ids.begin(), node_partition_ids.end());
640 node_partition_ids.erase(last, node_partition_ids.end());
641
642 // all element nodes belong to the same partition => regular element
643 if (node_partition_ids.size() == 1)
644 {
645 partitions[node_partition_ids[0]].regular_elements.push_back(
646 element);
647 }
648 else
649 {
650 for (auto const partition_id : node_partition_ids)
651 {
652 partitions[partition_id].ghost_elements.push_back(element);
653 }
654 }
655 }
656}
657
658// determine and append ghost nodes to partition.nodes in the following order
659// [base nodes, higher order nodes, base ghost nodes, higher order ghost
660// nodes]
662 std::vector<Partition>& partitions, MeshLib::Mesh const& mesh,
663 std::vector<std::size_t> const& nodes_partition_ids,
664 std::vector<std::size_t> const& node_id_mapping)
665{
666 for (std::size_t part_id = 0; part_id < partitions.size(); part_id++)
667 {
668 auto& partition = partitions[part_id];
669 std::vector<MeshLib::Node*> base_ghost_nodes;
670 std::vector<MeshLib::Node*> higher_order_ghost_nodes;
671 std::tie(base_ghost_nodes, higher_order_ghost_nodes) =
673 part_id, mesh.getNodes(), partition.ghost_elements,
674 nodes_partition_ids, mesh, node_id_mapping);
675
676 std::copy(begin(base_ghost_nodes), end(base_ghost_nodes),
677 std::back_inserter(partition.nodes));
678
679 partition.number_of_base_nodes =
680 partition.number_of_regular_base_nodes + base_ghost_nodes.size();
681
682 std::copy(begin(higher_order_ghost_nodes),
683 end(higher_order_ghost_nodes),
684 std::back_inserter(partition.nodes));
685 }
686}
687
688void partitionMesh(std::vector<Partition>& partitions,
689 MeshLib::Mesh const& mesh,
690 std::vector<std::size_t> const& nodes_partition_ids,
691 std::vector<std::size_t> const& bulk_node_ids)
692{
693 BaseLib::RunTime run_timer;
694 run_timer.start();
695 auto const partition_ids_per_element = computePartitionIDPerElement(
696 nodes_partition_ids, mesh.getElements(), bulk_node_ids);
697 INFO("partitionMesh(): Partition IDs per element computed in {:g} s",
698 run_timer.elapsed());
699
700 run_timer.start();
701 distributeNodesToPartitions(partitions, nodes_partition_ids,
702 mesh.getNodes(), bulk_node_ids);
703 INFO("partitionMesh(): distribute nodes to partitions took {:g} s",
704 run_timer.elapsed());
705
706 run_timer.start();
708 INFO(
709 "partitionMesh(): sorting [base nodes | higher order nodes] took {:g} "
710 "s",
711 run_timer.elapsed());
712
713 run_timer.start();
714 setNumberOfNodesInPartitions(partitions, mesh);
715 INFO(
716 "partitionMesh(): setting number of nodes and of all mesh base nodes "
717 "took {:g} s",
718 run_timer.elapsed());
719
720 run_timer.start();
721 distributeElementsIntoPartitions(partitions, mesh,
722 partition_ids_per_element);
723 INFO("partitionMesh(): distribute elements into partitions took {:g} s",
724 run_timer.elapsed());
725
726 run_timer.start();
728 partitions, mesh, nodes_partition_ids, bulk_node_ids);
729 INFO("partitionMesh(): determine / append ghost nodes took {:g} s",
730 run_timer.elapsed());
731
732 run_timer.start();
733 markDuplicateGhostCells(mesh, partitions);
734 INFO("partitionMesh(): markDuplicateGhostCells took {:g} s",
735 run_timer.elapsed());
736}
737
739{
740 std::vector<std::size_t> bulk_node_ids(_mesh->getNumberOfNodes());
741 std::iota(bulk_node_ids.begin(), bulk_node_ids.end(), 0);
742
744
746
747 // In case the field data in the vtu file are manually added, e.g. by using
748 // some tools, the size of the field property vector has to be checked.
749 checkFieldPropertyVectorSize(_mesh->getElements(), _mesh->getProperties());
750
752
754}
755
757 std::vector<Partition> const& partitions,
758 MeshLib::Properties& partitioned_properties)
759{
760 auto const bulk_node_ids_string =
762 if (partitioned_properties.hasPropertyVector(bulk_node_ids_string))
763 {
765 partitioned_properties.getPropertyVector<std::size_t>(
766 bulk_node_ids_string, MeshLib::MeshItemType::Node, 1),
767 partitions);
768 }
769 auto const bulk_element_ids_string =
771 if (partitioned_properties.hasPropertyVector<std::size_t>(
772 static_cast<std::string>(bulk_element_ids_string),
774 {
776 partitioned_properties.getPropertyVector<std::size_t>(
777 bulk_element_ids_string, MeshLib::MeshItemType::Cell, 1),
778 partitions);
779 }
780}
781
783 MeshLib::PropertyVector<std::size_t>* const bulk_node_ids_pv,
784 std::vector<Partition> const& local_partitions) const
785{
786 if (bulk_node_ids_pv == nullptr)
787 {
788 return;
789 }
790
791 auto& bulk_node_ids = *bulk_node_ids_pv;
792
793 std::size_t offset = 0; // offset in property vector for current partition
794
795 assert(_partitions.size() == local_partitions.size());
796 int const n_partitions = static_cast<int>(_partitions.size());
797 for (int partition_id = 0; partition_id < n_partitions; ++partition_id)
798 {
799 auto const& bulk_partition = _partitions[partition_id];
800 auto const& local_partition = local_partitions[partition_id];
801
802 // Create global-to-local node id mapping for the bulk partition.
803 auto const& bulk_nodes = bulk_partition.nodes;
804 auto const n_bulk_nodes = bulk_nodes.size();
805 std::map<std::size_t, std::size_t> global_to_local;
806 for (std::size_t local_node_id = 0; local_node_id < n_bulk_nodes;
807 ++local_node_id)
808 {
809 global_to_local[bulk_nodes[local_node_id]->getID()] = local_node_id;
810 }
811
812 auto const& local_nodes = local_partition.nodes;
813 auto const n_local_nodes = local_nodes.size();
814 for (std::size_t local_node_id = 0; local_node_id < n_local_nodes;
815 ++local_node_id)
816 {
817 bulk_node_ids[offset + local_node_id] =
818 global_to_local[bulk_node_ids[offset + local_node_id]];
819 }
820 offset += n_local_nodes;
821 }
822}
823
825 MeshLib::PropertyVector<std::size_t>* const bulk_element_ids_pv,
826 std::vector<Partition> const& local_partitions) const
827{
828 if (bulk_element_ids_pv == nullptr)
829 {
830 return;
831 }
832
833 auto& bulk_element_ids = *bulk_element_ids_pv;
834
835 std::size_t offset = 0; // offset in property vector for current partition
836
837 assert(_partitions.size() == local_partitions.size());
838 int const n_partitions = static_cast<int>(_partitions.size());
839 for (int partition_id = 0; partition_id < n_partitions; ++partition_id)
840 {
841 auto const& bulk_partition = _partitions[partition_id];
842 auto const& local_partition = local_partitions[partition_id];
843
844 // Create global-to-local element id mapping for the bulk partition.
845 std::map<std::size_t, std::size_t> global_to_local;
846 auto map_elements =
847 [&global_to_local](
848 std::vector<MeshLib::Element const*> const& elements,
849 std::size_t const offset)
850 {
851 auto const n_elements = elements.size();
852 for (std::size_t e = 0; e < n_elements; ++e)
853 {
854 global_to_local[elements[e]->getID()] = offset + e;
855 }
856 };
857
858 map_elements(bulk_partition.regular_elements, 0);
859 map_elements(bulk_partition.ghost_elements,
860 bulk_partition.regular_elements.size());
861
862 // Renumber the local bulk_element_ids map.
863 auto renumber_elements =
864 [&bulk_element_ids, &global_to_local](
865 std::vector<MeshLib::Element const*> const& elements,
866 std::size_t const offset)
867 {
868 auto const n_elements = elements.size();
869 for (std::size_t e = 0; e < n_elements; ++e)
870 {
871 bulk_element_ids[offset + e] =
872 global_to_local[bulk_element_ids[offset + e]];
873 }
874 return n_elements;
875 };
876
877 offset += renumber_elements(local_partition.regular_elements, offset);
878 offset += renumber_elements(local_partition.ghost_elements, offset);
879 }
880}
881
883 MeshLib::Mesh const& mesh) const
884{
885 auto const bulk_node_ids_string =
887 auto const& bulk_node_ids =
888 mesh.getProperties().getPropertyVector<std::size_t>(
889 bulk_node_ids_string, MeshLib::MeshItemType::Node, 1);
890
891 std::vector<Partition> partitions(_partitions.size());
892
893 partitionMesh(partitions, mesh, _nodes_partition_ids, *bulk_node_ids);
894
895 return partitions;
896}
897
899{
900 std::size_t node_global_id_offset = 0;
901 // Renumber the global indices.
902 for (auto& partition : _partitions)
903 {
904 for (std::size_t i = 0; i < partition.number_of_regular_nodes; i++)
905 {
906 _nodes_global_ids[partition.nodes[i]->getID()] =
907 node_global_id_offset++;
908 }
909 }
910}
911
912template <typename T>
913void writePropertyVectorValues(std::ostream& os,
915{
916 os.write(reinterpret_cast<const char*>(pv.data()), pv.size() * sizeof(T));
917}
918
919template <typename T>
921 MeshLib::MeshItemType const mesh_item_type,
922 std::ostream& out_val, std::ostream& out_meta)
923{
924 if (pv == nullptr)
925 {
926 return false;
927 }
928 // skip property of different mesh item type. Return true, because this
929 // operation was successful.
930 if (pv->getMeshItemType() != mesh_item_type)
931 {
932 return true;
933 }
934
936 pvmd.property_name = pv->getPropertyName();
940 writePropertyVectorValues(out_val, *pv);
942 return true;
943}
944
945void writeProperties(const std::string& file_name_base,
946 MeshLib::Properties const& partitioned_properties,
947 std::vector<Partition> const& partitions,
948 MeshLib::MeshItemType const mesh_item_type)
949{
950 auto const number_of_properties =
951 partitioned_properties.size(mesh_item_type);
952 if (number_of_properties == 0)
953 {
954 return;
955 }
956
957 auto const file_name_infix = toString(mesh_item_type);
958
959 auto const file_name_cfg = file_name_base + "_partitioned_" +
960 file_name_infix + "_properties_cfg" +
961 std::to_string(partitions.size()) + ".bin";
962 std::ofstream out(file_name_cfg, std::ios::binary);
963 if (!out)
964 {
965 OGS_FATAL("Could not open file '{:s}' for output.", file_name_cfg);
966 }
967
968 auto const file_name_val = file_name_base + "_partitioned_" +
969 file_name_infix + "_properties_val" +
970 std::to_string(partitions.size()) + ".bin";
971 std::ofstream out_val(file_name_val, std::ios::binary);
972 if (!out_val)
973 {
974 OGS_FATAL("Could not open file '{:s}' for output.", file_name_val);
975 }
976
977 BaseLib::writeValueBinary(out, number_of_properties);
978
980 partitioned_properties,
981 [&](auto type, auto const& property)
982 {
984 dynamic_cast<MeshLib::PropertyVector<decltype(type)> const*>(
985 property),
986 mesh_item_type, out_val, out);
987 });
988
989 unsigned long offset = 0;
990 for (const auto& partition : partitions)
991 {
993 offset, static_cast<unsigned long>(
994 partition.numberOfMeshItems(mesh_item_type))};
995 DBUG(
996 "Write meta data for node-based PropertyVector: global offset "
997 "{:d}, number of tuples {:d}",
998 pvpmd.offset, pvpmd.number_of_tuples);
1000 offset += pvpmd.number_of_tuples;
1001 }
1002}
1003
1005{
1009
1010 std::ostream& writeConfig(std::ostream& os) const;
1011};
1012
1013std::ostream& ConfigOffsets::writeConfig(std::ostream& os) const
1014{
1015 os.write(reinterpret_cast<const char*>(this), sizeof(ConfigOffsets));
1016
1017 static long reserved = 0; // Value reserved in the binary format, not used
1018 // in the partitioning process.
1019 return os.write(reinterpret_cast<const char*>(&reserved), sizeof(long));
1020}
1021
1028
1030{
1031 return {static_cast<long>(partition.nodes.size()),
1032 static_cast<long>(partition.regular_elements.size() +
1034 partition.regular_elements)),
1035 static_cast<long>(partition.ghost_elements.size() +
1037 partition.ghost_elements))};
1038}
1039
1041 PartitionOffsets const& offsets)
1042{
1043 return {
1044 static_cast<long>(oldConfig.node_rank_offset +
1045 offsets.node * sizeof(MeshLib::IO::NodeData)),
1046 // Offset the ending entry of the element integer variables of
1047 // the non-ghost elements of this partition in the vector of elem_info.
1048 static_cast<long>(oldConfig.element_rank_offset +
1049 offsets.regular_elements * sizeof(long)),
1050
1051 // Offset the ending entry of the element integer variables of
1052 // the ghost elements of this partition in the vector of elem_info.
1053 static_cast<long>(oldConfig.ghost_element_rank_offset +
1054 offsets.ghost_elements * sizeof(long))};
1055}
1056
1062std::tuple<std::vector<long>, std::vector<long>> writeConfigData(
1063 const std::string& file_name_base, std::vector<Partition> const& partitions)
1064{
1065 auto const file_name_cfg = file_name_base + "_partitioned_msh_cfg" +
1066 std::to_string(partitions.size()) + ".bin";
1067 std::ofstream of_bin_cfg(file_name_cfg, std::ios::binary);
1068 if (!of_bin_cfg)
1069 {
1070 OGS_FATAL("Could not open file '{:s}' for output.", file_name_cfg);
1071 }
1072
1073 std::vector<long> partitions_element_offsets;
1074 partitions_element_offsets.reserve(partitions.size());
1075 std::vector<long> partitions_ghost_element_offsets;
1076 partitions_ghost_element_offsets.reserve(partitions.size());
1077
1078 ConfigOffsets config_offsets = {0, 0, 0}; // 0 for first partition.
1079 for (const auto& partition : partitions)
1080 {
1081 partition.writeConfig(of_bin_cfg);
1082
1083 config_offsets.writeConfig(of_bin_cfg);
1084 auto const& partition_offsets = computePartitionOffsets(partition);
1085 config_offsets =
1086 incrementConfigOffsets(config_offsets, partition_offsets);
1087
1088 partitions_element_offsets.push_back(
1089 partition_offsets.regular_elements);
1090 partitions_ghost_element_offsets.push_back(
1091 partition_offsets.ghost_elements);
1092 }
1093
1094 return std::make_tuple(partitions_element_offsets,
1095 partitions_ghost_element_offsets);
1096}
1097
1106 const MeshLib::Element& elem,
1107 const std::unordered_map<std::size_t, long>& local_node_ids,
1108 std::vector<long>& elem_info,
1109 long& counter)
1110{
1111 constexpr unsigned mat_id =
1112 0; // TODO: Material ID to be set from the mesh data
1113 const long nn = elem.getNumberOfNodes();
1114 elem_info[counter++] = mat_id;
1115 elem_info[counter++] = static_cast<long>(elem.getCellType());
1116 elem_info[counter++] = nn;
1117
1118 for (long i = 0; i < nn; i++)
1119 {
1120 auto const& n = *elem.getNode(i);
1121 elem_info[counter++] = local_node_ids.at(n.getID());
1122 }
1123}
1124
1126std::unordered_map<std::size_t, long> enumerateLocalNodeIds(
1127 std::vector<MeshLib::Node const*> const& nodes)
1128{
1129 std::unordered_map<std::size_t, long> local_ids;
1130 local_ids.reserve(nodes.size());
1131
1132 long local_node_id = 0;
1133 for (const auto* node : nodes)
1134 {
1135 local_ids[node->getID()] = local_node_id++;
1136 }
1137 return local_ids;
1138}
1139
1146void writeElements(std::string const& file_name_base,
1147 std::vector<Partition> const& partitions,
1148 std::vector<long> const& regular_element_offsets,
1149 std::vector<long> const& ghost_element_offsets)
1150{
1151 const std::string npartitions_str = std::to_string(partitions.size());
1152
1153 auto const file_name_ele =
1154 file_name_base + "_partitioned_msh_ele" + npartitions_str + ".bin";
1155 std::ofstream element_info_os(file_name_ele, std::ios::binary);
1156 if (!element_info_os)
1157 {
1158 OGS_FATAL("Could not open file '{:s}' for output.", file_name_ele);
1159 }
1160
1161 auto const file_name_ele_g =
1162 file_name_base + "_partitioned_msh_ele_g" + npartitions_str + ".bin";
1163 std::ofstream ghost_element_info_os(file_name_ele_g, std::ios::binary);
1164 if (!ghost_element_info_os)
1165 {
1166 OGS_FATAL("Could not open file '{:s}' for output.", file_name_ele_g);
1167 }
1168
1169 for (std::size_t i = 0; i < partitions.size(); i++)
1170 {
1171 const auto& partition = partitions[i];
1172 auto const local_node_ids = enumerateLocalNodeIds(partition.nodes);
1173
1174 // Vector containing the offsets of the regular elements of this
1175 // partition
1176 std::vector<long> ele_info(regular_element_offsets[i]);
1177
1178 auto writeElementData =
1179 [&local_node_ids](
1180 std::vector<MeshLib::Element const*> const& elements,
1181 long const element_offsets,
1182 std::ofstream& output_stream)
1183 {
1184 long counter = elements.size();
1185 std::vector<long> ele_info(element_offsets);
1186
1187 for (std::size_t j = 0; j < elements.size(); j++)
1188 {
1189 const auto* elem = elements[j];
1190 ele_info[j] = counter;
1191 getElementIntegerVariables(*elem, local_node_ids, ele_info,
1192 counter);
1193 }
1194 // Write vector data of regular elements
1195 output_stream.write(reinterpret_cast<const char*>(ele_info.data()),
1196 ele_info.size() * sizeof(long));
1197 };
1198
1199 // regular elements.
1200 writeElementData(partition.regular_elements, regular_element_offsets[i],
1201 element_info_os);
1202 // Ghost elements
1203 writeElementData(partition.ghost_elements, ghost_element_offsets[i],
1204 ghost_element_info_os);
1205 }
1206}
1207
1212void writeNodes(const std::string& file_name_base,
1213 std::vector<Partition> const& partitions,
1214 std::vector<std::size_t> const& global_node_ids)
1215{
1216 auto const file_name = file_name_base + "_partitioned_msh_nod" +
1217 std::to_string(partitions.size()) + ".bin";
1218 std::ofstream os(file_name, std::ios::binary);
1219 if (!os)
1220 {
1221 OGS_FATAL("Could not open file '{:s}' for output.", file_name);
1222 }
1223
1224 for (const auto& partition : partitions)
1225 {
1226 partition.writeNodes(os, global_node_ids);
1227 }
1228}
1229
1230void NodeWiseMeshPartitioner::write(const std::string& file_name_base)
1231{
1238
1239 const auto elements_offsets = writeConfigData(file_name_base, _partitions);
1240
1241 const std::vector<IntegerType>& regular_element_offsets =
1242 std::get<0>(elements_offsets);
1243 const std::vector<IntegerType>& ghost_element_offsets =
1244 std::get<1>(elements_offsets);
1245 writeElements(file_name_base, _partitions, regular_element_offsets,
1246 ghost_element_offsets);
1247
1248 writeNodes(file_name_base, _partitions, _nodes_global_ids);
1249}
1250
1252 std::string const& output_filename_base,
1253 std::vector<Partition> const& partitions,
1254 MeshLib::Properties const& partitioned_properties) const
1255{
1256 writeNodes(output_filename_base, partitions, _nodes_global_ids);
1257
1258 const auto elem_integers =
1259 writeConfigData(output_filename_base, partitions);
1260
1261 const std::vector<IntegerType>& num_elem_integers =
1262 std::get<0>(elem_integers);
1263 const std::vector<IntegerType>& num_g_elem_integers =
1264 std::get<1>(elem_integers);
1265 writeElements(output_filename_base, partitions, num_elem_integers,
1266 num_g_elem_integers);
1267
1268 writeProperties(output_filename_base, partitioned_properties, partitions,
1270 writeProperties(output_filename_base, partitioned_properties, partitions,
1272}
1273} // namespace ApplicationUtils
#define OGS_FATAL(...)
Definition Error.h:26
Filename manipulation routines.
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:35
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:30
Definition of mesh-related Enumerations.
Declare a class to perform node wise mesh partitioning.
void applyToPropertyVectors(Properties const &properties, Function f)
Definition of the RunTime class.
Implementation of the VtuInterface class.
void renumberBulkElementIdsProperty(MeshLib::PropertyVector< std::size_t > *const bulk_element_ids_pv, std::vector< Partition > const &local_partitions) const
std::vector< Partition > partitionOtherMesh(MeshLib::Mesh const &mesh) const
void write(const std::string &file_name_base)
void renumberBulkIdsProperty(std::vector< Partition > const &partitions, MeshLib::Properties &partitioned_properties)
void renumberBulkNodeIdsProperty(MeshLib::PropertyVector< std::size_t > *const bulk_node_ids, std::vector< Partition > const &local_partitions) const
std::unique_ptr< MeshLib::Mesh > _mesh
Pointer to a mesh object.
MeshLib::Properties _partitioned_properties
Properties where values at ghost nodes and extra nodes are inserted.
std::vector< std::size_t > _nodes_global_ids
Global IDs of all nodes after partitioning.
std::vector< Partition > _partitions
Data for all partitions.
std::vector< std::size_t > _nodes_partition_ids
Partition IDs of each nodes.
void writeOtherMesh(std::string const &output_filename_base, std::vector< Partition > const &partitions, MeshLib::Properties const &partitioned_properties) const
Count the running time.
Definition RunTime.h:29
double elapsed() const
Get the elapsed time in seconds.
Definition RunTime.h:42
void start()
Start the timer.
Definition RunTime.h:32
virtual CellType getCellType() const =0
virtual unsigned getNumberOfNodes() const =0
virtual const Node * getNode(unsigned idx) const =0
constexpr std::span< Node *const > nodes() const
Span of element's nodes, their pointers actually.
Definition Element.h:72
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition Mesh.h:106
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:109
std::size_t computeNumberOfBaseNodes() const
Get the number of base nodes.
Definition Mesh.cpp:238
Properties & getProperties()
Definition Mesh.h:134
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition Mesh.h:100
std::vector< Element const * > const & getElementsConnectedToNode(std::size_t node_id) const
Definition Mesh.cpp:256
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
Definition Properties.h:36
bool hasPropertyVector(std::string_view name) const
std::map< std::string, PropertyVectorBase * >::size_type size() const
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)
PropertyVector< T > const * getPropertyVector(std::string_view name) const
MeshItemType getMeshItemType() const
int getNumberOfGlobalComponents() const
std::string const & getPropertyName() const
std::size_t getNumberOfTuples() const
std::size_t size() const
std::tuple< std::vector< MeshLib::Node * >, std::vector< MeshLib::Node * > > findGhostNodesInPartition(std::size_t const part_id, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element const * > const &ghost_elements, std::vector< std::size_t > const &partition_ids, MeshLib::Mesh const &mesh, std::vector< std::size_t > const &node_id_mapping)
std::size_t copyCellPropertyVectorValues(Partition const &p, std::size_t const offset, MeshLib::PropertyVector< T > const &pv, MeshLib::PropertyVector< T > &partitioned_pv)
std::unordered_map< std::size_t, long > enumerateLocalNodeIds(std::vector< MeshLib::Node const * > const &nodes)
Generates a mapping of given node ids to a new local (renumbered) node ids.
void addVtkGhostTypeProperty(MeshLib::Properties &partitioned_properties, std::vector< Partition > const &partitions, std::size_t const total_number_of_cells)
bool writePropertyVector(MeshLib::PropertyVector< T > const *const pv, MeshLib::MeshItemType const mesh_item_type, std::ostream &out_val, std::ostream &out_meta)
void checkFieldPropertyVectorSize(std::vector< MeshLib::Element * > const &global_mesh_elements, MeshLib::Properties const &properties)
void writeNodes(const std::string &file_name_base, std::vector< Partition > const &partitions, std::vector< std::size_t > const &global_node_ids)
ConfigOffsets incrementConfigOffsets(ConfigOffsets const &oldConfig, PartitionOffsets const &offsets)
void setIntegrationPointNumberOfPartition(MeshLib::Properties const &properties, std::vector< Partition > &partitions)
void distributeNodesToPartitions(std::vector< Partition > &partitions, std::vector< std::size_t > const &nodes_partition_ids, std::vector< MeshLib::Node * > const &nodes, std::vector< std::size_t > const &bulk_node_ids)
void reorderNodesIntoBaseAndHigherOrderNodes(Partition &partition, MeshLib::Mesh const &mesh)
void reorderNodesIntoBaseAndHigherOrderNodesPerPartition(std::vector< Partition > &partitions, MeshLib::Mesh const &mesh)
MeshLib::Properties partitionProperties(std::unique_ptr< MeshLib::Mesh > const &mesh, std::vector< Partition > &partitions)
Partition existing properties and add vtkGhostType cell data array property.
void setNumberOfNodesInPartitions(std::vector< Partition > &partitions, MeshLib::Mesh const &mesh)
std::pair< std::vector< MeshLib::Node const * >, std::vector< MeshLib::Node const * > > splitIntoBaseAndHigherOrderNodes(std::vector< MeshLib::Node const * > const &nodes, MeshLib::Mesh const &mesh)
PartitionOffsets computePartitionOffsets(Partition const &partition)
NodeWiseMeshPartitioner::IntegerType getNumberOfIntegerVariablesOfElements(std::vector< const MeshLib::Element * > const &elements)
void determineAndAppendGhostNodesToPartitions(std::vector< Partition > &partitions, MeshLib::Mesh const &mesh, std::vector< std::size_t > const &nodes_partition_ids, std::vector< std::size_t > const &node_id_mapping)
void partitionMesh(std::vector< Partition > &partitions, MeshLib::Mesh const &mesh, std::vector< std::size_t > const &nodes_partition_ids, std::vector< std::size_t > const &bulk_node_ids)
std::tuple< std::vector< long >, std::vector< long > > writeConfigData(const std::string &file_name_base, std::vector< Partition > const &partitions)
std::size_t copyFieldPropertyDataToPartitions(MeshLib::Properties const &properties, Partition const &p, std::size_t const id_offset_partition, std::vector< std::size_t > const &element_ip_data_offsets, MeshLib::PropertyVector< T > const &pv, MeshLib::PropertyVector< T > &partitioned_pv)
void writePropertyVectorValues(std::ostream &os, MeshLib::PropertyVector< T > const &pv)
void getElementIntegerVariables(const MeshLib::Element &elem, const std::unordered_map< std::size_t, long > &local_node_ids, std::vector< long > &elem_info, long &counter)
void markDuplicateGhostCells(MeshLib::Mesh const &mesh, std::vector< Partition > &partitions)
void distributeElementsIntoPartitions(std::vector< Partition > &partitions, MeshLib::Mesh const &mesh, std::vector< std::vector< std::size_t > > const &partition_ids_per_element)
std::size_t copyNodePropertyVectorValues(Partition const &p, std::size_t const offset, MeshLib::PropertyVector< T > const &pv, MeshLib::PropertyVector< T > &partitioned_pv)
std::size_t partitionLookup(std::size_t const &node_id, std::vector< std::size_t > const &partition_ids, std::vector< std::size_t > const &node_id_mapping)
std::vector< std::vector< std::size_t > > computePartitionIDPerElement(std::vector< std::size_t > const &node_partition_map, std::vector< MeshLib::Element * > const &elements, std::vector< std::size_t > const &bulk_node_ids)
void writeProperties(const std::string &file_name_base, MeshLib::Properties const &partitioned_properties, std::vector< Partition > const &partitions, MeshLib::MeshItemType const mesh_item_type)
void writeElements(std::string const &file_name_base, std::vector< Partition > const &partitions, std::vector< long > const &regular_element_offsets, std::vector< long > const &ghost_element_offsets)
bool copyPropertyVector(std::vector< MeshLib::Element * > const &global_mesh_elements, MeshLib::Properties &partitioned_properties, MeshLib::Properties const &properties, std::vector< Partition > const &partitions, MeshLib::PropertyVector< T > const *const pv, std::map< MeshLib::MeshItemType, std::size_t > const &total_number_of_tuples)
void writeValueBinary(std::ostream &out, T const &val)
write value as binary into the given output stream
void writePropertyVectorPartitionMetaData(std::ostream &os, PropertyVectorPartitionMetaData const &pvpmd)
void writePropertyVectorMetaData(std::ostream &os, PropertyVectorMetaData const &pvmd)
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
Definition Mesh.h:225
IntegrationPointMetaData getIntegrationPointMetaData(MeshLib::Properties const &properties, std::string const &name)
constexpr std::string_view getBulkIDString(MeshItemType mesh_item_type)
Definition Properties.h:188
MeshItemType
Definition Location.h:21
std::vector< std::size_t > getIntegrationPointDataOffsetsOfMeshElements(std::vector< MeshLib::Element * > const &mesh_elements, MeshLib::PropertyVectorBase const &pv, MeshLib::Properties const &properties)
int getNumberOfElementIntegrationPoints(MeshLib::IntegrationPointMetaData const &ip_meta_data, MeshLib::Element const &e)
std::ostream & writeConfig(std::ostream &os) const
std::ostream & writeConfig(std::ostream &os) const
std::size_t numberOfMeshItems(MeshLib::MeshItemType const item_type) const
std::vector< const MeshLib::Element * > regular_elements
Non ghost elements.
std::vector< const MeshLib::Element * > ghost_elements
std::ostream & writeNodes(std::ostream &os, std::vector< std::size_t > const &global_node_ids) const
std::vector< MeshLib::Node const * > nodes
nodes.
struct NodeData used for parallel reading and also partitioning
Definition NodeData.h:18