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