OGS
NodeWiseMeshPartitioner.cpp
Go to the documentation of this file.
1 
16 
17 #include <limits>
18 #include <numeric>
19 #include <unordered_map>
20 
21 #include "BaseLib/Error.h"
22 #include "BaseLib/FileTools.h"
23 #include "BaseLib/Logging.h"
24 #include "BaseLib/Stream.h"
26 
27 namespace ApplicationUtils
28 {
29 struct NodeStruct
30 {
32  double const x_,
33  double const y_,
34  double const z_)
35  : id(id_), x(x_), y(y_), z(z_)
36  {
37  }
38 
40  double x;
41  double y;
42  double z;
43 };
44 
46  MeshLib::MeshItemType const item_type) const
47 {
48  if (item_type == MeshLib::MeshItemType::Node)
49  {
50  return nodes.size();
51  }
52 
53  if (item_type == MeshLib::MeshItemType::Cell)
54  {
55  return regular_elements.size() + ghost_elements.size();
56  }
57  OGS_FATAL("Mesh items other than nodes and cells are not supported.");
58 }
59 
60 std::ostream& Partition::writeNodes(
61  std::ostream& os, std::vector<std::size_t> const& global_node_ids) const
62 {
63  std::vector<NodeStruct> nodes_buffer;
64  nodes_buffer.reserve(nodes.size());
65 
66  for (const auto* node : nodes)
67  {
68  double const* coords = node->getCoords();
69  nodes_buffer.emplace_back(global_node_ids[node->getID()], coords[0],
70  coords[1], coords[2]);
71  }
72  return os.write(reinterpret_cast<const char*>(nodes_buffer.data()),
73  sizeof(NodeStruct) * nodes_buffer.size());
74 }
75 
81  std::vector<const MeshLib::Element*> const& elements)
82 {
83  return 3 * elements.size() +
84  std::accumulate(begin(elements), end(elements), 0,
85  [](auto const nnodes, auto const* e)
86  { return nnodes + e->getNumberOfNodes(); });
87 }
88 
89 std::ostream& Partition::writeConfig(std::ostream& os) const
90 {
91  long const data[] = {
92  static_cast<long>(nodes.size()),
93  static_cast<long>(number_of_base_nodes),
94  static_cast<long>(regular_elements.size()),
95  static_cast<long>(ghost_elements.size()),
96  static_cast<long>(number_of_regular_base_nodes),
97  static_cast<long>(number_of_regular_nodes),
98  static_cast<long>(number_of_mesh_base_nodes),
99  static_cast<long>(number_of_mesh_all_nodes),
100  static_cast<long>(
102  static_cast<long>(
104  };
105 
106  return os.write(reinterpret_cast<const char*>(data), sizeof(data));
107 }
108 
109 std::size_t nodeIdBulkMesh(
110  MeshLib::Node const& node,
111  std::vector<std::size_t> const* node_id_mapping = nullptr)
112 {
113  return node_id_mapping ? (*node_id_mapping)[node.getID()] : node.getID();
114 }
115 
116 std::size_t partitionLookup(
117  MeshLib::Node const& node,
118  std::vector<std::size_t> const& partition_ids,
119  std::vector<std::size_t> const* node_id_mapping = nullptr)
120 {
121  auto node_id = [&node_id_mapping](MeshLib::Node const& n)
122  { return nodeIdBulkMesh(n, node_id_mapping); };
123 
124  return partition_ids[node_id(node)];
125 }
126 
134 std::pair<std::vector<MeshLib::Node*>, std::vector<MeshLib::Node*>>
136  std::size_t const part_id,
137  const bool is_mixed_high_order_linear_elems,
138  std::vector<MeshLib::Node*> const& nodes,
139  std::vector<std::size_t> const& partition_ids,
140  MeshLib::Mesh const& mesh,
141  std::vector<std::size_t> const* node_id_mapping = nullptr)
142 {
143  // Find nodes belonging to a given partition id.
144  std::vector<MeshLib::Node*> partition_nodes;
145  copy_if(begin(nodes), end(nodes), std::back_inserter(partition_nodes),
146  [&](auto const& n) {
147  return partitionLookup(*n, partition_ids, node_id_mapping) ==
148  part_id;
149  });
150 
151  // Space for resulting vectors.
152  std::vector<MeshLib::Node*> base_nodes;
153  base_nodes.reserve(partition_nodes.size() /
154  2); // if linear mesh, then one reallocation, no realloc
155  // for higher order elements meshes.
156  std::vector<MeshLib::Node*> higher_order_nodes;
157  higher_order_nodes.reserve(
158  partition_nodes.size() /
159  2); // if linear mesh, then wasted space, good estimate for quadratic
160  // order mesh, and realloc needed for higher order element meshes.
161 
162  // Split the nodes into base nodes and extra nodes.
163  std::partition_copy(
164  begin(partition_nodes), end(partition_nodes),
165  std::back_inserter(base_nodes), std::back_inserter(higher_order_nodes),
166  [&](MeshLib::Node* const n)
167  {
168  return !is_mixed_high_order_linear_elems ||
170  });
171 
172  return {base_nodes, higher_order_nodes};
173 }
174 
175 std::ptrdiff_t numberOfRegularNodes(
176  MeshLib::Element const& e, std::size_t const part_id,
177  std::vector<std::size_t> const& partition_ids,
178  std::vector<std::size_t> const* node_id_mapping = nullptr)
179 {
180  return std::count_if(e.getNodes(), e.getNodes() + e.getNumberOfNodes(),
181  [&](MeshLib::Node* const n) {
182  return partitionLookup(*n, partition_ids,
183  node_id_mapping) == part_id;
184  });
185 }
186 
191 std::tuple<std::vector<MeshLib::Element const*>,
192  std::vector<MeshLib::Element const*>>
194  std::size_t const part_id,
195  std::vector<MeshLib::Element*> const& elements,
196  std::vector<std::size_t> const& partition_ids,
197  std::vector<std::size_t> const* node_id_mapping = nullptr)
198 {
199  std::vector<MeshLib::Element const*> regular_elements;
200  std::vector<MeshLib::Element const*> ghost_elements;
201 
202  for (auto elem : elements)
203  {
204  auto const regular_nodes = numberOfRegularNodes(
205  *elem, part_id, partition_ids, node_id_mapping);
206 
207  if (regular_nodes == 0)
208  {
209  continue;
210  }
211 
212  if (regular_nodes ==
213  static_cast<std::ptrdiff_t>(elem->getNumberOfNodes()))
214  {
215  regular_elements.push_back(elem);
216  }
217  else
218  {
219  ghost_elements.push_back(elem);
220  }
221  }
222  return std::tuple<std::vector<MeshLib::Element const*>,
223  std::vector<MeshLib::Element const*>>{regular_elements,
224  ghost_elements};
225 }
226 
231 std::tuple<std::vector<MeshLib::Node*>, std::vector<MeshLib::Node*>>
233  std::size_t const part_id,
234  const bool is_mixed_high_order_linear_elems,
235  std::vector<MeshLib::Node*> const& nodes,
236  std::vector<MeshLib::Element const*> const& ghost_elements,
237  std::vector<std::size_t> const& partition_ids,
238  MeshLib::Mesh const& mesh,
239  std::vector<std::size_t> const* node_id_mapping = nullptr)
240 {
241  std::vector<MeshLib::Node*> base_nodes;
242  std::vector<MeshLib::Node*> ghost_nodes;
243 
244  std::vector<bool> is_ghost_node(nodes.size(), false);
245  for (const auto* ghost_elem : ghost_elements)
246  {
247  for (unsigned i = 0; i < ghost_elem->getNumberOfNodes(); i++)
248  {
249  auto const& n = ghost_elem->getNode(i);
250  if (is_ghost_node[n->getID()])
251  {
252  continue;
253  }
254 
255  if (partitionLookup(*n, partition_ids, node_id_mapping) != part_id)
256  {
257  if (!is_mixed_high_order_linear_elems ||
259  {
260  base_nodes.push_back(nodes[n->getID()]);
261  }
262  else
263  {
264  ghost_nodes.push_back(nodes[n->getID()]);
265  }
266  is_ghost_node[n->getID()] = true;
267  }
268  }
269  }
270  return std::tuple<std::vector<MeshLib::Node*>, std::vector<MeshLib::Node*>>{
271  base_nodes, ghost_nodes};
272 }
273 
275  std::size_t const part_id, const bool is_mixed_high_order_linear_elems)
276 {
277  auto& partition = _partitions[part_id];
278  std::vector<MeshLib::Node*> higher_order_regular_nodes;
279  std::tie(partition.nodes, higher_order_regular_nodes) =
280  findRegularNodesInPartition(part_id, is_mixed_high_order_linear_elems,
281  _mesh->getNodes(), _nodes_partition_ids,
282  *_mesh);
283 
284  partition.number_of_regular_base_nodes = partition.nodes.size();
285  partition.number_of_regular_nodes = partition.number_of_regular_base_nodes +
286  higher_order_regular_nodes.size();
287 
288  std::tie(partition.regular_elements, partition.ghost_elements) =
289  findElementsInPartition(part_id, _mesh->getElements(),
291  std::vector<MeshLib::Node*> base_ghost_nodes;
292  std::vector<MeshLib::Node*> higher_order_ghost_nodes;
293  std::tie(base_ghost_nodes, higher_order_ghost_nodes) =
294  findGhostNodesInPartition(part_id, is_mixed_high_order_linear_elems,
295  _mesh->getNodes(), partition.ghost_elements,
297 
298  std::copy(begin(base_ghost_nodes), end(base_ghost_nodes),
299  std::back_inserter(partition.nodes));
300 
301  partition.number_of_base_nodes = partition.nodes.size();
302 
303  if (is_mixed_high_order_linear_elems)
304  {
305  std::copy(begin(higher_order_regular_nodes),
306  end(higher_order_regular_nodes),
307  std::back_inserter(partition.nodes));
308  std::copy(begin(higher_order_ghost_nodes),
309  end(higher_order_ghost_nodes),
310  std::back_inserter(partition.nodes));
311  }
312 
313  // Set the node numbers of base and all mesh nodes.
314  partition.number_of_mesh_base_nodes = _mesh->getNumberOfBaseNodes();
315  partition.number_of_mesh_all_nodes = _mesh->getNumberOfNodes();
316 }
317 
320 template <typename T>
322  Partition const& p,
323  std::size_t const offset,
324  MeshLib::PropertyVector<T> const& pv,
325  MeshLib::PropertyVector<T>& partitioned_pv)
326 {
327  auto const& nodes = p.nodes;
328  auto const nnodes = nodes.size();
329  auto const n_components = pv.getNumberOfGlobalComponents();
330  for (std::size_t i = 0; i < nnodes; ++i)
331  {
332  const auto global_id = nodes[i]->getID();
333  std::copy_n(&pv[n_components * global_id], n_components,
334  &partitioned_pv[offset + n_components * i]);
335  }
336  return n_components * nnodes;
337 }
338 
342 template <typename T>
344  Partition const& p,
345  std::size_t const offset,
346  MeshLib::PropertyVector<T> const& pv,
347  MeshLib::PropertyVector<T>& partitioned_pv)
348 {
349  std::size_t const n_regular(p.regular_elements.size());
350  auto const n_components = pv.getNumberOfGlobalComponents();
351  for (std::size_t i = 0; i < n_regular; ++i)
352  {
353  const auto id = p.regular_elements[i]->getID();
354  std::copy_n(&pv[n_components * id], n_components,
355  &partitioned_pv[offset + n_components * i]);
356  }
357 
358  std::size_t const n_ghost(p.ghost_elements.size());
359  for (std::size_t i = 0; i < n_ghost; ++i)
360  {
361  const auto id = p.ghost_elements[i]->getID();
362  std::copy_n(&pv[n_components * id], n_components,
363  &partitioned_pv[offset + n_components * (n_regular + i)]);
364  }
365  return n_components * (n_regular + n_ghost);
366 }
367 
368 template <typename T>
370  MeshLib::Properties& partitioned_properties,
371  std::vector<Partition> const& partitions,
372  MeshLib::PropertyVector<T> const* const pv,
373  std::map<MeshLib::MeshItemType, std::size_t> const& total_number_of_tuples)
374 {
375  if (pv == nullptr)
376  {
377  return false;
378  }
379  auto const item_type = pv->getMeshItemType();
380 
382  {
383  return true; // Skip integration point data. Requires parsing of json
384  // for the integration point data. Return true, because
385  // the property was "successfully" parsed.
386  }
387 
388  auto partitioned_pv = partitioned_properties.createNewPropertyVector<T>(
389  pv->getPropertyName(), pv->getMeshItemType(),
391  partitioned_pv->resize(total_number_of_tuples.at(item_type) *
393 
394  auto copy_property_vector_values =
395  [&](Partition const& p, std::size_t offset)
396  {
397  if (item_type == MeshLib::MeshItemType::Node)
398  {
399  return copyNodePropertyVectorValues(p, offset, *pv,
400  *partitioned_pv);
401  }
402  if (item_type == MeshLib::MeshItemType::Cell)
403  {
404  return copyCellPropertyVectorValues(p, offset, *pv,
405  *partitioned_pv);
406  }
407  OGS_FATAL(
408  "Copying of property vector values for mesh item type {:s} is not "
409  "implemented.",
410  item_type);
411  };
412 
413  std::size_t position_offset(0);
414  for (auto p : partitions)
415  {
416  position_offset += copy_property_vector_values(p, position_offset);
417  }
418  return true;
419 }
420 
426 template <typename Function>
428 {
429  for (auto [name, property] : properties)
430  {
431  // Open question, why is the 'unsigned long' case not compiling giving
432  // an error "expected '(' for function-style cast or type construction"
433  // with clang-7, and "error C4576: a parenthesized type followed by an
434  // initializer list is a non-standard explicit type conversion syntax"
435  // with MSVC-15.
436  bool success = f(double{}, property) || f(float{}, property) ||
437  f(int{}, property) || f(long{}, property) ||
438  f(unsigned{}, property) || f(long{}, property) ||
439  f(static_cast<unsigned long>(0), property) ||
440  f(std::size_t{}, property) || f(char{}, property) ||
441  f(static_cast<unsigned char>(0), property);
442  if (!success)
443  {
444  OGS_FATAL("Could not apply function to PropertyVector '{:s}'.",
445  property->getPropertyName());
446  }
447  }
448 }
449 
450 void addVtkGhostTypeProperty(MeshLib::Properties& partitioned_properties,
451  std::vector<Partition> const& partitions,
452  std::size_t const total_number_of_cells)
453 {
454  auto* vtk_ghost_type =
455  partitioned_properties.createNewPropertyVector<unsigned char>(
456  "vtkGhostType", MeshLib::MeshItemType::Cell);
457  if (vtk_ghost_type == nullptr)
458  {
459  OGS_FATAL("Could not create vtkGhostType cell data array.");
460  }
461 
462  vtk_ghost_type->resize(total_number_of_cells);
463  std::size_t offset = 0;
464  for (auto const& partition : partitions)
465  {
466  offset += partition.regular_elements.size();
467  for (std::size_t i = 0; i < partition.ghost_elements.size(); ++i)
468  {
469  if (partition.duplicate_ghost_cell[i])
470  {
471  (*vtk_ghost_type)[offset + i] |=
472  vtkDataSetAttributes::DUPLICATECELL;
473  }
474  }
475  offset += partition.ghost_elements.size();
476  }
477 }
478 
481  MeshLib::Properties const& properties,
482  std::vector<Partition> const& partitions)
483 {
484  using namespace MeshLib;
485 
486  Properties partitioned_properties;
487 
488  auto count_tuples = [&](MeshItemType const mesh_item_type)
489  {
490  return std::accumulate(
491  begin(partitions), end(partitions), 0,
492  [&](std::size_t const sum, Partition const& p)
493  { return sum + p.numberOfMeshItems(mesh_item_type); });
494  };
495  std::map<MeshItemType, std::size_t> const total_number_of_tuples = {
496  {MeshItemType::Cell, count_tuples(MeshItemType::Cell)},
497  {MeshItemType::Node, count_tuples(MeshItemType::Node)}};
498 
499  DBUG(
500  "total number of tuples after partitioning defined for cells is {:d} "
501  "and for nodes {:d}.",
502  total_number_of_tuples.at(MeshItemType::Cell),
503  total_number_of_tuples.at(MeshItemType::Node));
504 
505  // 1 create new PV
506  // 2 resize the PV with total_number_of_tuples
507  // 3 copy the values according to the partition info
509  properties,
510  [&](auto type, auto const property)
511  {
512  return copyPropertyVector<decltype(type)>(
513  partitioned_properties, partitions,
514  dynamic_cast<PropertyVector<decltype(type)> const*>(property),
515  total_number_of_tuples);
516  });
517 
518  addVtkGhostTypeProperty(partitioned_properties,
519  partitions,
520  total_number_of_tuples.at(MeshItemType::Cell));
521 
522  return partitioned_properties;
523 }
524 
526  std::vector<Partition>& partitions)
527 {
528  std::vector<bool> cell_visited(mesh.getElements().size(), false);
529 
530  for (auto& partition : partitions)
531  {
532  partition.duplicate_ghost_cell.resize(partition.ghost_elements.size(),
533  true);
534 
535  for (std::size_t i = 0; i < partition.ghost_elements.size(); i++)
536  {
537  const auto& ghost_element = *partition.ghost_elements[i];
538  if (!cell_visited[ghost_element.getID()])
539  {
540  cell_visited[ghost_element.getID()] = true;
541  partition.duplicate_ghost_cell[i] = false;
542  }
543  }
544  }
545 }
546 
548  const bool is_mixed_high_order_linear_elems)
549 {
550  for (std::size_t part_id = 0; part_id < _partitions.size(); part_id++)
551  {
552  INFO("Processing partition: {:d}", part_id);
553  processPartition(part_id, is_mixed_high_order_linear_elems);
554  }
555 
557 
558  renumberNodeIndices(is_mixed_high_order_linear_elems);
559 
561  partitionProperties(_mesh->getProperties(), _partitions);
562 }
563 
565  MeshLib::PropertyVector<std::size_t>* const bulk_node_ids_pv,
566  std::vector<Partition> const& local_partitions) const
567 {
568  if (bulk_node_ids_pv == nullptr)
569  {
570  return;
571  }
572 
573  auto& bulk_node_ids = *bulk_node_ids_pv;
574 
575  std::size_t offset = 0; // offset in property vector for current partition
576 
577  assert(_partitions.size() == local_partitions.size());
578  int const n_partitions = static_cast<int>(_partitions.size());
579  for (int partition_id = 0; partition_id < n_partitions; ++partition_id)
580  {
581  auto const& bulk_partition = _partitions[partition_id];
582  auto const& local_partition = local_partitions[partition_id];
583 
584  // Create global-to-local node id mapping for the bulk partition.
585  auto const& bulk_nodes = bulk_partition.nodes;
586  auto const n_bulk_nodes = bulk_nodes.size();
587  std::map<std::size_t, std::size_t> global_to_local;
588  for (std::size_t local_node_id = 0; local_node_id < n_bulk_nodes;
589  ++local_node_id)
590  {
591  global_to_local[bulk_nodes[local_node_id]->getID()] = local_node_id;
592  }
593 
594  auto const& local_nodes = local_partition.nodes;
595  auto const n_local_nodes = local_nodes.size();
596  for (std::size_t local_node_id = 0; local_node_id < n_local_nodes;
597  ++local_node_id)
598  {
599  bulk_node_ids[offset + local_node_id] =
600  global_to_local[bulk_node_ids[offset + local_node_id]];
601  }
602  offset += n_local_nodes;
603  }
604 }
605 
607  MeshLib::PropertyVector<std::size_t>* const bulk_element_ids_pv,
608  std::vector<Partition> const& local_partitions) const
609 {
610  if (bulk_element_ids_pv == nullptr)
611  {
612  return;
613  }
614 
615  auto& bulk_element_ids = *bulk_element_ids_pv;
616 
617  std::size_t offset = 0; // offset in property vector for current partition
618 
619  assert(_partitions.size() == local_partitions.size());
620  int const n_partitions = static_cast<int>(_partitions.size());
621  for (int partition_id = 0; partition_id < n_partitions; ++partition_id)
622  {
623  auto const& bulk_partition = _partitions[partition_id];
624  auto const& local_partition = local_partitions[partition_id];
625 
626  // Create global-to-local element id mapping for the bulk partition.
627  std::map<std::size_t, std::size_t> global_to_local;
628  auto map_elements =
629  [&global_to_local](
630  std::vector<MeshLib::Element const*> const& elements,
631  std::size_t const offset)
632  {
633  auto const n_elements = elements.size();
634  for (std::size_t e = 0; e < n_elements; ++e)
635  {
636  global_to_local[elements[e]->getID()] = offset + e;
637  }
638  };
639 
640  map_elements(bulk_partition.regular_elements, 0);
641  map_elements(bulk_partition.ghost_elements,
642  bulk_partition.regular_elements.size());
643 
644  // Renumber the local bulk_element_ids map.
645  auto renumber_elements =
646  [&bulk_element_ids, &global_to_local](
647  std::vector<MeshLib::Element const*> const& elements,
648  std::size_t const offset)
649  {
650  auto const n_elements = elements.size();
651  for (std::size_t e = 0; e < n_elements; ++e)
652  {
653  bulk_element_ids[offset + e] =
654  global_to_local[bulk_element_ids[offset + e]];
655  }
656  return n_elements;
657  };
658 
659  offset += renumber_elements(local_partition.regular_elements, offset);
660  offset += renumber_elements(local_partition.ghost_elements, offset);
661  }
662 }
663 
665  MeshLib::Mesh const& mesh,
666  bool const is_mixed_high_order_linear_elems) const
667 {
668  auto const& bulk_node_ids =
669  mesh.getProperties().getPropertyVector<std::size_t>(
670  "bulk_node_ids", MeshLib::MeshItemType::Node, 1);
671 
672  std::vector<Partition> partitions(_partitions.size());
673  for (std::size_t part_id = 0; part_id < _partitions.size(); part_id++)
674  {
675  auto& partition = partitions[part_id];
676  INFO("Processing partition: {:d}", part_id);
677  // Set the node numbers of base and all mesh nodes.
678  partition.number_of_mesh_base_nodes = mesh.getNumberOfBaseNodes();
679  partition.number_of_mesh_all_nodes = mesh.getNumberOfNodes();
680 
681  std::vector<MeshLib::Node*> higher_order_regular_nodes;
682  std::tie(partition.nodes, higher_order_regular_nodes) =
684  part_id, is_mixed_high_order_linear_elems, mesh.getNodes(),
685  _nodes_partition_ids, mesh, bulk_node_ids);
686 
687  partition.number_of_regular_base_nodes = partition.nodes.size();
688  partition.number_of_regular_nodes =
689  partition.number_of_regular_base_nodes +
690  higher_order_regular_nodes.size();
691 
692  std::tie(partition.regular_elements, partition.ghost_elements) =
694  _nodes_partition_ids, bulk_node_ids);
695 
696  std::vector<MeshLib::Node*> base_ghost_nodes;
697  std::vector<MeshLib::Node*> higher_order_ghost_nodes;
698  std::tie(base_ghost_nodes, higher_order_ghost_nodes) =
699  findGhostNodesInPartition(part_id, is_mixed_high_order_linear_elems,
700  mesh.getNodes(), partition.ghost_elements,
702  bulk_node_ids);
703 
704  std::copy(begin(base_ghost_nodes), end(base_ghost_nodes),
705  std::back_inserter(partition.nodes));
706 
707  partition.number_of_base_nodes = partition.nodes.size();
708 
709  if (is_mixed_high_order_linear_elems)
710  {
711  std::copy(begin(higher_order_regular_nodes),
712  end(higher_order_regular_nodes),
713  std::back_inserter(partition.nodes));
714  std::copy(begin(higher_order_ghost_nodes),
715  end(higher_order_ghost_nodes),
716  std::back_inserter(partition.nodes));
717  }
718  }
719 
720  markDuplicateGhostCells(mesh, partitions);
721  return partitions;
722 }
723 
725  const bool is_mixed_high_order_linear_elems)
726 {
727  std::size_t node_global_id_offset = 0;
728  // Renumber the global indices.
729  // -- Base nodes
730  for (auto& partition : _partitions)
731  {
732  for (std::size_t i = 0; i < partition.number_of_regular_base_nodes; i++)
733  {
734  _nodes_global_ids[partition.nodes[i]->getID()] =
735  node_global_id_offset;
736  node_global_id_offset++;
737  }
738  }
739 
740  if (!is_mixed_high_order_linear_elems)
741  {
742  return;
743  }
744 
745  // -- Nodes for high order elements.
746  for (auto& partition : _partitions)
747  {
748  const std::size_t end_id = partition.number_of_base_nodes +
749  partition.number_of_regular_nodes -
750  partition.number_of_regular_base_nodes;
751  for (std::size_t i = partition.number_of_base_nodes; i < end_id; i++)
752  {
753  _nodes_global_ids[partition.nodes[i]->getID()] =
754  node_global_id_offset;
755  node_global_id_offset++;
756  }
757  }
758 }
759 
760 template <typename T>
761 void writePropertyVectorValues(std::ostream& os,
762  MeshLib::PropertyVector<T> const& pv)
763 {
764  os.write(reinterpret_cast<const char*>(pv.data()), pv.size() * sizeof(T));
765 }
766 
767 template <typename T>
769  MeshLib::MeshItemType const mesh_item_type,
770  std::ostream& out_val, std::ostream& out_meta)
771 {
772  if (pv == nullptr)
773  {
774  return false;
775  }
776  // skip property of different mesh item type. Return true, because this
777  // operation was successful.
778  if (pv->getMeshItemType() != mesh_item_type)
779  {
780  return true;
781  }
782 
784  pvmd.property_name = pv->getPropertyName();
787  pvmd.number_of_tuples = pv->getNumberOfTuples();
788  writePropertyVectorValues(out_val, *pv);
790  return true;
791 }
792 
793 void writeProperties(const std::string& file_name_base,
794  MeshLib::Properties const& partitioned_properties,
795  std::vector<Partition> const& partitions,
796  MeshLib::MeshItemType const mesh_item_type)
797 {
798  auto const number_of_properties =
799  partitioned_properties.size(mesh_item_type);
800  if (number_of_properties == 0)
801  {
802  return;
803  }
804 
805  auto const file_name_infix = toString(mesh_item_type);
806 
807  auto const file_name_cfg = file_name_base + "_partitioned_" +
808  file_name_infix + "_properties_cfg" +
809  std::to_string(partitions.size()) + ".bin";
810  std::ofstream out(file_name_cfg, std::ios::binary);
811  if (!out)
812  {
813  OGS_FATAL("Could not open file '{:s}' for output.", file_name_cfg);
814  }
815 
816  auto const file_name_val = file_name_base + "_partitioned_" +
817  file_name_infix + "_properties_val" +
818  std::to_string(partitions.size()) + ".bin";
819  std::ofstream out_val(file_name_val, std::ios::binary);
820  if (!out_val)
821  {
822  OGS_FATAL("Could not open file '{:s}' for output.", file_name_val);
823  }
824 
826 
828  partitioned_properties,
829  [&](auto type, auto const& property)
830  {
831  return writePropertyVector<decltype(type)>(
832  dynamic_cast<MeshLib::PropertyVector<decltype(type)> const*>(
833  property),
834  mesh_item_type, out_val, out);
835  });
836 
837  unsigned long offset = 0;
838  for (const auto& partition : partitions)
839  {
841  offset, static_cast<unsigned long>(
842  partition.numberOfMeshItems(mesh_item_type))};
843  DBUG(
844  "Write meta data for node-based PropertyVector: global offset "
845  "{:d}, number of tuples {:d}",
846  pvpmd.offset, pvpmd.number_of_tuples);
848  offset += pvpmd.number_of_tuples;
849  }
850 }
851 
853 {
857 
858  std::ostream& writeConfig(std::ostream& os) const;
859 };
860 
861 std::ostream& ConfigOffsets::writeConfig(std::ostream& os) const
862 {
863  os.write(reinterpret_cast<const char*>(this), sizeof(ConfigOffsets));
864 
865  static long reserved = 0; // Value reserved in the binary format, not used
866  // in the partitioning process.
867  return os.write(reinterpret_cast<const char*>(&reserved), sizeof(long));
868 }
869 
871 {
872  long node;
875 };
876 
878 {
879  return {static_cast<long>(partition.nodes.size()),
880  static_cast<long>(partition.regular_elements.size() +
882  partition.regular_elements)),
883  static_cast<long>(partition.ghost_elements.size() +
885  partition.ghost_elements))};
886 }
887 
889  PartitionOffsets const& offsets)
890 {
891  return {
892  static_cast<long>(oldConfig.node_rank_offset +
893  offsets.node * sizeof(NodeStruct)),
894  // Offset the ending entry of the element integer variables of
895  // the non-ghost elements of this partition in the vector of elem_info.
896  static_cast<long>(oldConfig.element_rank_offset +
897  offsets.regular_elements * sizeof(long)),
898 
899  // Offset the ending entry of the element integer variables of
900  // the ghost elements of this partition in the vector of elem_info.
901  static_cast<long>(oldConfig.ghost_element_rank_offset +
902  offsets.ghost_elements * sizeof(long))};
903 }
904 
910 std::tuple<std::vector<long>, std::vector<long>> writeConfigData(
911  const std::string& file_name_base, std::vector<Partition> const& partitions)
912 {
913  auto const file_name_cfg = file_name_base + "_partitioned_msh_cfg" +
914  std::to_string(partitions.size()) + ".bin";
915  std::ofstream of_bin_cfg(file_name_cfg, std::ios::binary);
916  if (!of_bin_cfg)
917  {
918  OGS_FATAL("Could not open file '{:s}' for output.", file_name_cfg);
919  }
920 
921  std::vector<long> partitions_element_offsets;
922  partitions_element_offsets.reserve(partitions.size());
923  std::vector<long> partitions_ghost_element_offsets;
924  partitions_ghost_element_offsets.reserve(partitions.size());
925 
926  ConfigOffsets config_offsets = {0, 0, 0}; // 0 for first partition.
927  for (const auto& partition : partitions)
928  {
929  partition.writeConfig(of_bin_cfg);
930 
931  config_offsets.writeConfig(of_bin_cfg);
932  auto const& partition_offsets = computePartitionOffsets(partition);
933  config_offsets =
934  incrementConfigOffsets(config_offsets, partition_offsets);
935 
936  partitions_element_offsets.push_back(
937  partition_offsets.regular_elements);
938  partitions_ghost_element_offsets.push_back(
939  partition_offsets.ghost_elements);
940  }
941 
942  return std::make_tuple(partitions_element_offsets,
943  partitions_ghost_element_offsets);
944 }
945 
954  const MeshLib::Element& elem,
955  const std::unordered_map<std::size_t, long>& local_node_ids,
956  std::vector<long>& elem_info,
957  long& counter)
958 {
959  constexpr unsigned mat_id =
960  0; // TODO: Material ID to be set from the mesh data
961  const long nn = elem.getNumberOfNodes();
962  elem_info[counter++] = mat_id;
963  elem_info[counter++] = static_cast<long>(elem.getCellType());
964  elem_info[counter++] = nn;
965 
966  for (long i = 0; i < nn; i++)
967  {
968  auto const& n = *elem.getNode(i);
969  elem_info[counter++] = local_node_ids.at(n.getID());
970  }
971 }
972 
974 std::unordered_map<std::size_t, long> enumerateLocalNodeIds(
975  std::vector<MeshLib::Node*> const& nodes)
976 {
977  std::unordered_map<std::size_t, long> local_ids;
978  local_ids.reserve(nodes.size());
979 
980  long local_node_id = 0;
981  for (const auto* node : nodes)
982  {
983  local_ids[node->getID()] = local_node_id++;
984  }
985  return local_ids;
986 }
987 
994 void writeElements(std::string const& file_name_base,
995  std::vector<Partition> const& partitions,
996  std::vector<long> const& regular_element_offsets,
997  std::vector<long> const& ghost_element_offsets)
998 {
999  const std::string npartitions_str = std::to_string(partitions.size());
1000 
1001  auto const file_name_ele =
1002  file_name_base + "_partitioned_msh_ele" + npartitions_str + ".bin";
1003  std::ofstream element_info_os(file_name_ele, std::ios::binary);
1004  if (!element_info_os)
1005  {
1006  OGS_FATAL("Could not open file '{:s}' for output.", file_name_ele);
1007  }
1008 
1009  auto const file_name_ele_g =
1010  file_name_base + "_partitioned_msh_ele_g" + npartitions_str + ".bin";
1011  std::ofstream ghost_element_info_os(file_name_ele_g, std::ios::binary);
1012  if (!ghost_element_info_os)
1013  {
1014  OGS_FATAL("Could not open file '{:s}' for output.", file_name_ele_g);
1015  }
1016 
1017  for (std::size_t i = 0; i < partitions.size(); i++)
1018  {
1019  const auto& partition = partitions[i];
1020  auto const local_node_ids = enumerateLocalNodeIds(partition.nodes);
1021 
1022  // Vector containing the offsets of the regular elements of this
1023  // partition
1024  std::vector<long> ele_info(regular_element_offsets[i]);
1025 
1026  auto writeElementData =
1027  [&local_node_ids](
1028  std::vector<MeshLib::Element const*> const& elements,
1029  long const element_offsets,
1030  std::ofstream& output_stream)
1031  {
1032  long counter = elements.size();
1033  std::vector<long> ele_info(element_offsets);
1034 
1035  for (std::size_t j = 0; j < elements.size(); j++)
1036  {
1037  const auto* elem = elements[j];
1038  ele_info[j] = counter;
1039  getElementIntegerVariables(*elem, local_node_ids, ele_info,
1040  counter);
1041  }
1042  // Write vector data of regular elements
1043  output_stream.write(reinterpret_cast<const char*>(ele_info.data()),
1044  ele_info.size() * sizeof(long));
1045  };
1046 
1047  // regular elements.
1048  writeElementData(partition.regular_elements, regular_element_offsets[i],
1049  element_info_os);
1050  // Ghost elements
1051  writeElementData(partition.ghost_elements, ghost_element_offsets[i],
1052  ghost_element_info_os);
1053  }
1054 }
1055 
1060 void writeNodes(const std::string& file_name_base,
1061  std::vector<Partition> const& partitions,
1062  std::vector<std::size_t> const& global_node_ids)
1063 {
1064  auto const file_name = file_name_base + "_partitioned_msh_nod" +
1065  std::to_string(partitions.size()) + ".bin";
1066  std::ofstream os(file_name, std::ios::binary);
1067  if (!os)
1068  {
1069  OGS_FATAL("Could not open file '{:s}' for output.", file_name);
1070  }
1071 
1072  for (const auto& partition : partitions)
1073  {
1074  partition.writeNodes(os, global_node_ids);
1075  }
1076 }
1077 
1078 void NodeWiseMeshPartitioner::write(const std::string& file_name_base)
1079 {
1084 
1085  const auto elements_offsets = writeConfigData(file_name_base, _partitions);
1086 
1087  const std::vector<IntegerType>& regular_element_offsets =
1088  std::get<0>(elements_offsets);
1089  const std::vector<IntegerType>& ghost_element_offsets =
1090  std::get<1>(elements_offsets);
1091  writeElements(file_name_base, _partitions, regular_element_offsets,
1092  ghost_element_offsets);
1093 
1094  writeNodes(file_name_base, _partitions, _nodes_global_ids);
1095 }
1096 
1098  std::string const& output_filename_base,
1099  std::vector<Partition> const& partitions,
1100  MeshLib::Properties const& partitioned_properties) const
1101 {
1102  writeNodes(output_filename_base, partitions, _nodes_global_ids);
1103 
1104  const auto elem_integers =
1105  writeConfigData(output_filename_base, partitions);
1106 
1107  const std::vector<IntegerType>& num_elem_integers =
1108  std::get<0>(elem_integers);
1109  const std::vector<IntegerType>& num_g_elem_integers =
1110  std::get<1>(elem_integers);
1111  writeElements(output_filename_base, partitions, num_elem_integers,
1112  num_g_elem_integers);
1113 
1114  writeProperties(output_filename_base, partitioned_properties, partitions,
1116  writeProperties(output_filename_base, partitioned_properties, partitions,
1118 }
1119 } // namespace ApplicationUtils
#define OGS_FATAL(...)
Definition: Error.h:26
Filename manipulation routines.
void INFO(char const *fmt, Args const &... args)
Definition: Logging.h:32
void DBUG(char const *fmt, Args const &... args)
Definition: Logging.h:27
Declare a class to perform node wise mesh partitioning.
Helper tools for debugging.
Implementation of the VtuInterface class.
void processPartition(std::size_t const part_id, const bool is_mixed_high_order_linear_elems)
void renumberBulkElementIdsProperty(MeshLib::PropertyVector< std::size_t > *const bulk_element_ids_pv, std::vector< Partition > const &local_partitions) const
void partitionByMETIS(const bool is_mixed_high_order_linear_elems)
void write(const std::string &file_name_base)
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< Partition > partitionOtherMesh(MeshLib::Mesh const &mesh, bool const is_mixed_high_order_linear_elems) const
std::vector< std::size_t > _nodes_global_ids
Global IDs of all nodes after partitioning.
void renumberNodeIndices(const bool is_mixed_high_order_linear_elems)
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
std::size_t getID() const
Definition: Point3dWithID.h:62
virtual Node *const * getNodes() const =0
Get array of element nodes.
virtual CellType getCellType() const =0
virtual const Node * getNode(unsigned idx) const =0
virtual unsigned getNumberOfNodes() const =0
std::size_t getNumberOfBaseNodes() const
Get the number of base nodes.
Definition: Mesh.cpp:214
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition: Mesh.h:95
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition: Mesh.h:98
Properties & getProperties()
Definition: Mesh.h:123
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition: Mesh.h:89
std::vector< Element const * > const & getElementsConnectedToNode(std::size_t node_id) const
Definition: Mesh.cpp:232
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
Definition: Properties.h:36
std::map< std::string, PropertyVectorBase * >::size_type size() const
Definition: Properties.cpp:165
PropertyVector< T > const * getPropertyVector(std::string const &name) const
PropertyVector< T > * createNewPropertyVector(std::string const &name, MeshItemType mesh_item_type, std::size_t n_components=1)
std::string const & getPropertyName() const
MeshItemType getMeshItemType() const
int getNumberOfGlobalComponents() const
std::size_t getNumberOfTuples() const
std::size_t size() const
std::function< bool(const double t, MappedConstVector< N > const &y, MappedVector< N > &ydot)> Function
std::size_t copyCellPropertyVectorValues(Partition const &p, std::size_t const offset, MeshLib::PropertyVector< T > const &pv, MeshLib::PropertyVector< T > &partitioned_pv)
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)
std::ptrdiff_t numberOfRegularNodes(MeshLib::Element const &e, std::size_t const part_id, std::vector< std::size_t > const &partition_ids, std::vector< std::size_t > const *node_id_mapping=nullptr)
std::tuple< std::vector< MeshLib::Node * >, std::vector< MeshLib::Node * > > findGhostNodesInPartition(std::size_t const part_id, const bool is_mixed_high_order_linear_elems, 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=nullptr)
MeshLib::Properties partitionProperties(MeshLib::Properties const &properties, std::vector< Partition > const &partitions)
Partition existing properties and add vtkGhostType cell data array property.
void writeNodes(const std::string &file_name_base, std::vector< Partition > const &partitions, std::vector< std::size_t > const &global_node_ids)
std::size_t nodeIdBulkMesh(MeshLib::Node const &node, std::vector< std::size_t > const *node_id_mapping=nullptr)
ConfigOffsets incrementConfigOffsets(ConfigOffsets const &oldConfig, PartitionOffsets const &offsets)
std::tuple< std::vector< MeshLib::Element const * >, std::vector< MeshLib::Element const * > > findElementsInPartition(std::size_t const part_id, std::vector< MeshLib::Element * > const &elements, std::vector< std::size_t > const &partition_ids, std::vector< std::size_t > const *node_id_mapping=nullptr)
bool copyPropertyVector(MeshLib::Properties &partitioned_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 applyToPropertyVectors(MeshLib::Properties const &properties, Function f)
PartitionOffsets computePartitionOffsets(Partition const &partition)
NodeWiseMeshPartitioner::IntegerType getNumberOfIntegerVariablesOfElements(std::vector< const MeshLib::Element * > const &elements)
std::size_t partitionLookup(MeshLib::Node const &node, std::vector< std::size_t > const &partition_ids, std::vector< std::size_t > const *node_id_mapping=nullptr)
std::tuple< std::vector< long >, std::vector< long > > writeConfigData(const std::string &file_name_base, std::vector< Partition > const &partitions)
std::pair< std::vector< MeshLib::Node * >, std::vector< MeshLib::Node * > > findRegularNodesInPartition(std::size_t const part_id, const bool is_mixed_high_order_linear_elems, std::vector< MeshLib::Node * > const &nodes, std::vector< std::size_t > const &partition_ids, MeshLib::Mesh const &mesh, std::vector< std::size_t > const *node_id_mapping=nullptr)
void writePropertyVectorValues(std::ostream &os, MeshLib::PropertyVector< T > const &pv)
std::unordered_map< std::size_t, long > enumerateLocalNodeIds(std::vector< MeshLib::Node * > const &nodes)
Generates a mapping of given node ids to a new local (renumbered) node ids.
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)
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)
void writeValueBinary(std::ostream &out, T const &val)
write value as binary into the given output stream
Definition: FileTools.h:63
const char * toString(mgis::behaviour::Behaviour::Kinematic kin)
Converts MGIS kinematic to a string representation.
Definition: MFront.cpp:103
void copy(PETScVector const &x, PETScVector &y)
Definition: LinAlg.cpp:37
void writePropertyVectorPartitionMetaData(std::ostream &os, PropertyVectorPartitionMetaData const &pvpmd)
void writePropertyVectorMetaData(std::ostream &os, PropertyVectorMetaData const &pvmd)
MeshItemType
Definition: Location.h:21
bool isBaseNode(Node const &node, std::vector< Element const * > const &elements_connected_to_node)
Definition: Mesh.cpp:370
std::ostream & writeConfig(std::ostream &os) const
NodeWiseMeshPartitioner::IntegerType id
NodeStruct(NodeWiseMeshPartitioner::IntegerType const id_, double const x_, double const y_, double const z_)
std::ostream & writeConfig(std::ostream &os) const
std::vector< MeshLib::Node * > nodes
nodes.
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