ALL 0.9.4
A Loadbalacing Library
Loading...
Searching...
No Matches
ALL.hpp
Go to the documentation of this file.
1/*
2Copyright 2018-2026 Rene Halver, Forschungszentrum Juelich GmbH, Germany
3Copyright 2018-2026 Godehard Sutmann, Forschungszentrum Juelich GmbH, Germany
4Copyright 2026-2026 Jonas Kroschewski, Forschungszentrum Juelich GmbH, Germany
5
6Redistribution and use in source and binary forms, with or without modification,
7are permitted provided that the following conditions are met:
8
91. Redistributions of source code must retain the above copyright notice, this
10 list of conditions and the following disclaimer.
11
122. Redistributions in binary form must reproduce the above copyright notice,
13this list of conditions and the following disclaimer in the documentation and/or
14 other materials provided with the distribution.
15
163. Neither the name of the copyright holder nor the names of its contributors
17may be used to endorse or promote products derived from this software without
18 specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*/
31
32#ifndef ALL_MAIN_HEADER_INC
33#define ALL_MAIN_HEADER_INC
34
36#include "ALL_LB.hpp"
37#include "ALL_Point.hpp"
38#include "ALL_Tensor.hpp"
39#ifdef ALL_VORONOI_ACTIVE
40#include "ALL_Voronoi.hpp"
41#endif
42#include "ALL_ForceBased.hpp"
43#include "ALL_Histogram.hpp"
44#include "ALL_Staggered.hpp"
45#include <algorithm>
46#include <iomanip>
47#include <memory>
48#include <numeric>
49#include <sstream>
50#include <string>
51#include <vector>
52
53#include <cerrno>
54#include <sys/stat.h>
55
56#ifdef ALL_VTK_OUTPUT
57#include <limits>
58#include <vtkCellArray.h>
59#include <vtkCellData.h>
60#include <vtkFloatArray.h>
61#include <vtkInformation.h>
62#include <vtkIntArray.h>
63#include <vtkMPIController.h>
64#include <vtkPolyhedron.h>
65#include <vtkProgrammableFilter.h>
66#include <vtkSmartPointer.h>
67#include <vtkUnstructuredGrid.h>
68#include <vtkVoxel.h>
69#include <vtkXMLPUnstructuredGridWriter.h>
70#include <vtkXMLUnstructuredGridWriter.h>
71#include <vtkUnstructuredGridWriter.h> //For vtkXMLUnstructuredGridWriter debug
72
73#ifdef VTK_CELL_ARRAY_V2
74#include <vtkNew.h>
75#endif
76#endif
77
78namespace ALL {
79
80#define ALL_ESTIMATION_LIMIT_DEFAULT 0
81
83enum LB_t : int {
87 TENSOR = 1,
90#ifdef ALL_VORONOI_ACTIVE
93#endif
100};
101
104
105template <class T, class W> class ALL {
106public:
110 : loadbalancing_step(0)
111#ifdef ALL_VTK_OUTPUT
112 ,
113 vtk_init(false)
114#endif
115 {
116 // determine correct MPI data type for template T
117 if (std::is_same<T, double>::value)
118 MPIDataTypeT = MPI_DOUBLE;
119 else if (std::is_same<T, float>::value)
120 MPIDataTypeT = MPI_FLOAT;
121 else if (std::is_same<T, int>::value)
122 MPIDataTypeT = MPI_INT;
123 else if (std::is_same<T, long>::value)
124 MPIDataTypeT = MPI_LONG;
125
126 // determine correct MPI data type for template W
127 if (std::is_same<W, double>::value)
128 MPIDataTypeW = MPI_DOUBLE;
129 else if (std::is_same<W, float>::value)
130 MPIDataTypeW = MPI_FLOAT;
131 else if (std::is_same<W, int>::value)
132 MPIDataTypeW = MPI_INT;
133 else if (std::is_same<W, long>::value)
134 MPIDataTypeW = MPI_LONG;
135 }
136
145 ALL(const LB_t m, const int d, const T g) : ALL() {
146 method = m;
147 switch (method) {
148 case LB_t::TENSOR:
149 balancer.reset(new Tensor_LB<T, W>(d, (W)0, g));
150 break;
151 case LB_t::STAGGERED:
152 balancer.reset(new Staggered_LB<T, W>(d, (W)0, g));
153 break;
154 case LB_t::FORCEBASED:
155 balancer.reset(new ForceBased_LB<T, W>(d, (W)0, g));
156 break;
157#ifdef ALL_VORONOI_ACTIVE
158 case LB_t::VORONOI:
159 balancer.reset(new Voronoi_LB<T, W>(d, (W)0, g));
160 break;
161#endif
162 case LB_t::HISTOGRAM:
163 balancer.reset(new Histogram_LB<T, W>(d, std::vector<W>(10), g));
164 break;
165 case LB_t::TENSOR_MAX:
166 balancer.reset(new TensorMax_LB<T, W>(d, (W)0, g));
167 break;
168 default:
169 throw InvalidArgumentException(__FILE__, __func__, __LINE__,
170 "Unknown type of loadbalancing passed.");
171 }
172 balancer->setDimension(d);
173 balancer->setGamma(g);
174 estimation_limit = ALL_ESTIMATION_LIMIT_DEFAULT;
175 }
176
186 ALL(const LB_t m, const int d, const std::vector<Point<T>> &inp, const T g)
187 : ALL(m, d, g) {
188 balancer->setVertices(inp);
189 calculate_outline();
190 }
191
193 ~ALL() = default;
194
198 void setVertices(const std::vector<Point<T>> &inp) {
199 int dim = inp.at(0).getDimension();
200 if (dim != balancer->getDimension())
202 __FILE__, __func__, __LINE__,
203 "Dimension of ALL::Points in input vector do not match dimension of "
204 "ALL "
205 "object.");
206 balancer->setVertices(inp);
207 calculate_outline();
208 }
209
214 void setCommunicator(const MPI_Comm comm) {
215 int comm_type;
216 MPI_Topo_test(comm, &comm_type);
217 if (comm_type == MPI_CART) {
218 communicator = comm;
219 balancer->setCommunicator(communicator);
220 // set procGridLoc and procGridDim
221 const int dimension = balancer->getDimension();
222 int location[dimension];
223 int size[dimension];
224 int periodicity[dimension];
225 MPI_Cart_get(communicator, dimension, size, periodicity, location);
226 procGridLoc.assign(location, location + dimension);
227 procGridDim.assign(size, size + dimension);
228 procGridSet = true;
229 } else {
230 int rank;
231 MPI_Comm_rank(comm, &rank);
232 if (procGridSet) {
233 // compute 1D index from the location in the process grid (using z-y-x
234 // ordering, as MPI_Dims_create)
235 int idx;
236 switch (balancer->getDimension()) {
237 case 3:
238 idx = procGridLoc.at(2) + procGridLoc.at(1) * procGridDim.at(2) +
239 procGridLoc.at(0) * procGridDim.at(2) * procGridDim.at(1);
240 break;
241 case 2:
242 idx = procGridLoc.at(1) + procGridLoc.at(0) * procGridDim.at(1);
243 break;
244 case 1:
245 idx = procGridLoc.at(0);
246 break;
247 default:
249 __FILE__, __func__, __LINE__,
250 "ALL cannot deal with more then three dimensions (or less then "
251 "one).");
252 break;
253 }
254
255 // create new temporary communicator with correct ranks
256 MPI_Comm temp_comm;
257 MPI_Comm_split(comm, 0, idx, &temp_comm);
258
259 std::vector<int> periods(3, 1);
260
261 // transform temporary communicator to cartesian communicator
262 MPI_Cart_create(temp_comm, balancer->getDimension(), procGridDim.data(),
263 periods.data(), 0, &communicator);
264 balancer->setCommunicator(communicator);
265 } else {
267 __FILE__, __func__, __LINE__,
268 "When using a non-cartesian communicator process grid parameters "
269 "required (not set).");
270 }
271 }
272 }
273
276 T getGamma() { return balancer->getGamma(); };
277
280 void setGamma(const T g) { balancer->setGamma(g); };
281
282 // method to set the automatic calculation of the correction value
283 // @param[in] b the boolean to activate/deactivate automatic calculation
284 void setGammaAutoCalc(const bool b) { balancer->setGammaAutoCalc(b); }
285
288 bool getGammaAutoCalc() { return balancer->getGammaAutoCalc(); }
289
292 void setWork(const W work) {
293 // set new value for work (single value for whole domain)
294 balancer->setWork(work);
295 }
296
297 // method to set a multi-dimensional work for the local domain
299 void setWork(const std::vector<W> &work) { balancer->setWork(work); }
300
303 void setup() { balancer->setup(); }
304
310 std::vector<Point<T>> &balance() {
311 nVertices = balancer->getNVertices();
312 switch (method) {
313 case LB_t::TENSOR:
314 balancer->balance(loadbalancing_step);
315 calculate_outline();
316 break;
317 case LB_t::STAGGERED:
318
319 /* ToDo: Check if repetition is useful at all and
320 * change it to be included for all methods,
321 * not only STAGGERED */
322 /*
323 // estimation to improve speed of convergence
324 // changing vertices during estimation
325 std::vector<Point<T>> tmp_vertices = balancer->getVertices();
326 // saved original vertices
327 std::vector<Point<T>> old_vertices = balancer->getVertices();
328 // old temporary vertices
329 std::vector<Point<T>> old_tmp_vertices = balancer->getVertices();
330 // result temporary vertices
331 std::vector<Point<T>> result_vertices = balancer->getVertices();
332 // temporary work
333 W tmp_work = balancer->getWork().at(0);
334 // old temporary work
335 W old_tmp_work = balancer->getWork().at(0);
336
337 W max_work;
338 W sum_work;
339 double d_max;
340 int n_ranks;
341
342 // compute work density on local domain
343 double V = 1.0;
344 for (int i = 0; i < balancer->getDimension(); ++i)
345 V *= ( outline.at(1)[i] - outline.at(0)[i] );
346 double rho = workArray.at(0) / V;
347
348 // collect maximum work in system
349 MPI_Allreduce(workArray.data(), &max_work, 1, MPIDataTypeW, MPI_MAX,
350 communicator); MPI_Allreduce(workArray.data(), &sum_work, 1,
351 MPIDataTypeW, MPI_SUM, communicator);
352 MPI_Comm_size(communicator,&n_ranks);
353 d_max = (double)(max_work) * (double)n_ranks / (double)sum_work - 1.0;
354
355
356 // internal needs to be readded to argument list
357 const bool internal = false
358 for (int i = 0; i < estimation_limit && d_max > 0.1 && !internal; ++i)
359 {
360 balancer->setWork(tmp_work);
361 balancer->setup();
362 balancer->balance(true);
363 bool sane = true;
364 // check if the estimated boundaries are not too deformed
365 for (int j = 0; j < balancer->getDimension(); ++j)
366 sane = sane && (result_vertices.at(0)[j] <=
367 old_vertices.at(1)[j]);
368 MPI_Allreduce(MPI_IN_PLACE,&sane,1,MPI_CXX_BOOL,MPI_LAND,communicator);
369 if (sane)
370 {
371 old_tmp_vertices = tmp_vertices;
372 tmp_vertices = result_vertices;
373 V = 1.0;
374 for (int i = 0; i < balancer->getDimension(); ++i)
375 V *= ( tmp_vertices.at(1)[i] - tmp_vertices.at(0)[i] );
376 old_tmp_work = tmp_work;
377 tmp_work = rho * V;
378 }
379 else if (!sane || i == estimation_limit - 1)
380 {
381 balancer->getVertices() = old_tmp_vertices;
382 workArray->at(0) = old_tmp_work;
383 calculate_outline();
384 i = estimation_limit;
385 }
386 }
387
388 ((Staggered_LB<T,W>*)balancer.get())->setVertices(outline->data());
389 */
390 balancer->balance(loadbalancing_step);
391 calculate_outline();
392 break;
393 case LB_t::FORCEBASED:
394 balancer->balance(loadbalancing_step);
395 calculate_outline();
396 break;
397#ifdef ALL_VORONOI_ACTIVE
398 case LB_t::VORONOI:
399 balancer->balance(loadbalancing_step);
400 break;
401#endif
402 case LB_t::HISTOGRAM:
403 balancer->balance(loadbalancing_step);
404 calculate_outline();
405 break;
406 case LB_t::TENSOR_MAX:
407 balancer->balance(loadbalancing_step);
408 calculate_outline();
409 break;
410
411 default:
412 throw InvalidArgumentException(__FILE__, __func__, __LINE__,
413 "Unknown type of loadbalancing passed.");
414 }
415 loadbalancing_step++;
416 return balancer->getVertices();
417 }
418
419 /**********************/
420 /* getter functions */
421 /**********************/
422
426 std::vector<Point<T>> &getPrevVertices() {
427 return balancer->getPrevVertices();
428 };
429
434 std::vector<Point<T>> &getVertices() { return balancer->getVertices(); };
435
439 int getDimension() { return balancer->getDimension(); }
440
444 void getWork(std::vector<W> &result) { result = balancer->getWork(); }
445
448 W getWork() { return balancer->getWork().at(0); }
449
453 std::vector<int> &getNeighbors() { return balancer->getNeighbors(); }
454
459 std::vector<T> &getNeighborVertices() {
460 return balancer->getNeighborVertices();
461 }
462
466 return balancer->getEfficiency();
467 }
468
472 // currently only implemented for HISTOGRAM
473 return balancer->getEstimatedEfficiency();
474 }
475
476 /**********************/
477 /* setter functions */
478 /**********************/
479
485 void setSysSize(const std::vector<T> &sysSize) {
486 balancer.get()->setSysSize(sysSize);
487 }
488
497 void setMethodData(const void *data) {
498 balancer.get()->setAdditionalData(data);
499 }
500
505 void setProcGridParams(const std::vector<int> &loc,
506 const std::vector<int> &size) {
507 // todo(s.schulz): We should probably throw if the dimension does not match
508 procGridLoc.insert(procGridLoc.begin(), loc.begin(), loc.end());
509 procGridDim.insert(procGridDim.begin(), size.begin(), size.end());
510 procGridSet = true;
511 }
512
515 void setProcTag(int tag) { procTag = tag; }
516
521 void setMinDomainSize(const std::vector<T> &minSize) {
522 (balancer.get())->setMinDomainSize(minSize);
523 }
524
525#ifdef ALL_VTK_OUTPUT
530 void printVTKoutlines(const int step) {
531 // define grid points, i.e. vertices of local domain
532 auto points = vtkSmartPointer<vtkPoints>::New();
533 // allocate space for eight points (describing the cuboid around the domain)
534 points->Allocate(8 * balancer->getDimension());
535
536 int n_ranks;
537 int local_rank;
538
539 if (!vtk_init) {
540 controller = vtkMPIController::New();
541 controller->Initialize();
542 controller->SetGlobalController(controller);
543 vtk_init = true;
544 }
545
546 MPI_Comm_rank(communicator, &local_rank);
547 MPI_Comm_size(communicator, &n_ranks);
548
549 std::vector<Point<W>> tmp_outline(2);
550 std::vector<W> tmp_0(
551 {outline.at(0)[0], outline.at(0)[1], outline.at(0)[2]});
552 std::vector<W> tmp_1(
553 {outline.at(1)[0], outline.at(1)[1], outline.at(1)[2]});
554 tmp_outline.at(0) = Point<W>(tmp_0);
555 tmp_outline.at(1) = Point<W>(tmp_1);
556
557 for (auto z = 0; z <= 1; ++z)
558 for (auto y = 0; y <= 1; ++y)
559 for (auto x = 0; x <= 1; ++x) {
560 points->InsertPoint(x + 2 * y + 4 * z, tmp_outline.at(x)[0],
561 tmp_outline.at(y)[1], tmp_outline.at(z)[2]);
562 }
563
564 auto hexa = vtkSmartPointer<vtkVoxel>::New();
565 for (int i = 0; i < 8; ++i)
566 hexa->GetPointIds()->SetId(i, i);
567
568 auto cellArray = vtkSmartPointer<vtkCellArray>::New();
569 cellArray->InsertNextCell(hexa);
570
571 // define work array (length = 1)
572 auto work = vtkSmartPointer<vtkFloatArray>::New();
573 work->SetNumberOfComponents(1);
574 work->SetNumberOfTuples(1);
575 work->SetName("work");
576 W total_work = std::accumulate(balancer->getWork().begin(),
577 balancer->getWork().end(), (W)0);
578 work->SetValue(0, total_work);
579
580 // define rank array (length = 4, x,y,z, rank)
581 int rank = 0;
582 MPI_Comm_rank(communicator, &rank);
583 auto coords = vtkSmartPointer<vtkFloatArray>::New();
584 coords->SetNumberOfComponents(3);
585 coords->SetNumberOfTuples(1);
586 coords->SetName("coords");
587 coords->SetValue(0, procGridLoc.at(0));
588 coords->SetValue(1, procGridLoc.at(1));
589 coords->SetValue(2, procGridLoc.at(2));
590
591 auto rnk = vtkSmartPointer<vtkFloatArray>::New();
592 rnk->SetNumberOfComponents(1);
593 rnk->SetNumberOfTuples(1);
594 rnk->SetName("MPI rank");
595 rnk->SetValue(0, rank);
596
597 // define tag array (length = 1)
598 auto tag = vtkSmartPointer<vtkIntArray>::New();
599 tag->SetNumberOfComponents(1);
600 tag->SetNumberOfTuples(1);
601 tag->SetName("tag");
602 tag->SetValue(0, procTag);
603
604 // determine extent of system
605 W known_unused global_extent[6];
606 W local_min[3];
607 W local_max[3];
608 W global_min[3];
609 W global_max[3];
610 W width[3];
611 W volume = (W)1.0;
612
613 for (int i = 0; i < 3; ++i) {
614 local_min[i] = outline.at(0)[i];
615 local_max[i] = outline.at(1)[i];
616 width[i] = local_max[i] - local_min[i];
617 volume *= width[i];
618 }
619
620 W surface = (W)2.0 * width[0] * width[1] + (W)2.0 * width[1] * width[2] +
621 (W)2.0 * width[0] * width[2];
622
623 auto expanse = vtkSmartPointer<vtkFloatArray>::New();
624 expanse->SetNumberOfComponents(6);
625 expanse->SetNumberOfTuples(1);
626 expanse->SetName("expanse");
627 expanse->SetValue(0, width[0]);
628 expanse->SetValue(1, width[0]);
629 expanse->SetValue(2, width[0]);
630 expanse->SetValue(3, volume);
631 expanse->SetValue(4, surface);
632 expanse->SetValue(5, surface / volume);
633
634 MPI_Allreduce(&local_min, &global_min, 3, MPIDataTypeW, MPI_MIN,
635 communicator);
636 MPI_Allreduce(&local_max, &global_max, 3, MPIDataTypeW, MPI_MAX,
637 communicator);
638
639 for (int i = 0; i < 3; ++i) {
640 global_extent[2 * i] = global_min[i];
641 global_extent[2 * i + 1] = global_max[i];
642 }
643
644 // create a structured grid and assign data to it
645 auto unstructuredGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
646 unstructuredGrid->SetPoints(points);
647 unstructuredGrid->SetCells(VTK_VOXEL, cellArray);
648 unstructuredGrid->GetCellData()->AddArray(work);
649 unstructuredGrid->GetCellData()->AddArray(expanse);
650 unstructuredGrid->GetCellData()->AddArray(rnk);
651 unstructuredGrid->GetCellData()->AddArray(coords);
652 unstructuredGrid->GetCellData()->AddArray(tag);
653
654 //DEBUG
655 /*
656 createDirectory("vtk_outline_debug");
657 std::ostringstream ss_local_debug;
658 ss_local_debug << "vtk_outline_debug/ALL_vtk_outline_" << std::setw(7)
659 << std::setfill('0') << step << "_" << local_rank << ".vtk";
660
661 auto debug_writer = vtkSmartPointer<vtkUnstructuredGridWriter>::New();
662 debug_writer->SetFileName(ss_local_debug.str().c_str());
663 debug_writer->SetInputData(unstructuredGrid);
664 debug_writer->Write();
665 */
666 //ENDDEBUG
667
668 createDirectory("vtk_outline");
669 std::ostringstream ss_local;
670 ss_local << "vtk_outline/ALL_vtk_outline_" << std::setw(7)
671 << std::setfill('0') << step << "_" << local_rank << ".vtu";
672
673 //DEBUG
674 /*
675 createDirectory("vtk_outline_debug");
676 std::ostringstream ss_local_debug;
677 ss_local_debug << "vtk_outline_debug/ALL_vtk_outline_" << std::setw(7)
678 << std::setfill('0') << step << "_" << local_rank << ".vtk";
679
680 auto debug_writer = vtkSmartPointer<vtkUnstructuredGridWriter>::New();
681 debug_writer->SetFileName(ss_local_debug.str().c_str());
682 debug_writer->SetInputData(unstructuredGrid);
683 debug_writer->Write();
684 */
685 //ENDDEBUG
686
687 auto writer = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
688 writer->SetInputData(unstructuredGrid);
689 writer->SetFileName(ss_local.str().c_str());
690 //writer->SetDataModeToAscii(); //Causes Segmentation fault. Was used for debugging and is replaced by vtkUnstructuredGridWriter
691 writer->SetDataModeToBinary();
692 writer->Write();
693
694 // if (local_rank == 0)
695 //{
696 std::ostringstream ss_para;
697 ss_para << "vtk_outline/ALL_vtk_outline_" << std::setw(7)
698 << std::setfill('0') << step << ".pvtu";
699
700 // create the parallel writer
701 auto parallel_writer =
702 vtkSmartPointer<vtkXMLPUnstructuredGridWriter>::New();
703 parallel_writer->SetFileName(ss_para.str().c_str());
704 parallel_writer->SetNumberOfPieces(n_ranks);
705 parallel_writer->SetStartPiece(local_rank);
706 parallel_writer->SetEndPiece(local_rank);
707 parallel_writer->SetInputData(unstructuredGrid);
708 //parallel_writer->SetDataModeToAscii(); //Causes Segmentation fault. Was used for debugging and is replaced by vtkUnstructuredGridWriter
709 parallel_writer->SetDataModeToBinary();
710 parallel_writer->Write();
711 //}
712 }
713
718 void printVTKvertices(const int step) {
719 int n_ranks;
720 int local_rank;
721
722 MPI_Comm_rank(communicator, &local_rank);
723 MPI_Comm_size(communicator, &n_ranks);
724
725 // local vertices
726 // (vertices + work)
727 T local_vertices[nVertices * balancer->getDimension() + 1];
728
729 for (int v = 0; v < nVertices; ++v) {
730 for (int d = 0; d < balancer->getDimension(); ++d) {
731 local_vertices[v * balancer->getDimension() + d] =
732 balancer->getVertices().at(v)[d];
733 }
734 }
735 local_vertices[nVertices * balancer->getDimension()] =
736 (T)balancer->getWork().at(0);
737
738 /*
739 T *global_vertices;
740 if (local_rank == 0) {
741 global_vertices =
742 new T[n_ranks * (nVertices * balancer->getDimension() + 1)];
743 }
744 */
745 T global_vertices[n_ranks * (nVertices * balancer->getDimension() + 1)];
746
747 // collect all works and vertices on a single process
748 MPI_Gather(local_vertices, nVertices * balancer->getDimension() + 1,
749 MPIDataTypeT, global_vertices,
750 nVertices * balancer->getDimension() + 1, MPIDataTypeT, 0,
751 communicator);
752
753 if (local_rank == 0) {
754 auto vtkpoints = vtkSmartPointer<vtkPoints>::New();
755#ifdef VTK_CELL_ARRAY_V2
756 vtkNew<vtkUnstructuredGrid> unstructuredGrid;
757 unstructuredGrid->Allocate(n_ranks + 10);
758#else
759 auto unstructuredGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
760#endif
761
762 // enter vertices into unstructured grid
763 for (int i = 0; i < n_ranks; ++i) {
764 for (int v = 0; v < nVertices; ++v) {
765 vtkpoints->InsertNextPoint(
766 global_vertices[i * (nVertices * balancer->getDimension() + 1) +
767 v * balancer->getDimension() + 0],
768 global_vertices[i * (nVertices * balancer->getDimension() + 1) +
769 v * balancer->getDimension() + 1],
770 global_vertices[i * (nVertices * balancer->getDimension() + 1) +
771 v * balancer->getDimension() + 2]);
772 }
773 }
774 unstructuredGrid->SetPoints(vtkpoints);
775
776 // data arrays for work and cell id
777 auto work = vtkSmartPointer<vtkFloatArray>::New();
778 auto cell = vtkSmartPointer<vtkFloatArray>::New();
779 work->SetNumberOfComponents(1);
780 work->SetNumberOfTuples(n_ranks);
781 work->SetName("work");
782 cell->SetNumberOfComponents(1);
783 cell->SetNumberOfTuples(n_ranks);
784 cell->SetName("cell id");
785
786 for (int n = 0; n < n_ranks; ++n) {
787
788#ifdef VTK_CELL_ARRAY_V2
789 // define grid points, i.e. vertices of local domain
790 vtkIdType pointIds[8] = {8 * n + 0, 8 * n + 1, 8 * n + 2, 8 * n + 3,
791 8 * n + 4, 8 * n + 5, 8 * n + 6, 8 * n + 7};
792
793 vtkIdType faces[48] = {
794 3, 8 * n + 0, 8 * n + 2, 8 * n + 1,
795 3, 8 * n + 1, 8 * n + 2, 8 * n + 3,
796 3, 8 * n + 0, 8 * n + 4, 8 * n + 2,
797 3, 8 * n + 2, 8 * n + 4, 8 * n + 6,
798 3, 8 * n + 2, 8 * n + 6, 8 * n + 3,
799 3, 8 * n + 3, 8 * n + 6, 8 * n + 7,
800 3, 8 * n + 1, 8 * n + 5, 8 * n + 3,
801 3, 8 * n + 3, 8 * n + 5, 8 * n + 7,
802 3, 8 * n + 0, 8 * n + 4, 8 * n + 1,
803 3, 8 * n + 1, 8 * n + 4, 8 * n + 5,
804 3, 8 * n + 4, 8 * n + 6, 8 * n + 5,
805 3, 8 * n + 5, 8 * n + 6, 8 * n + 7};
806
807 unstructuredGrid->InsertNextCell(VTK_POLYHEDRON, 8, pointIds, 12,
808 faces);
809#else
810 // define grid points, i.e. vertices of local domain
811 vtkIdType pointIds[8] = {8 * n + 0, 8 * n + 1, 8 * n + 2, 8 * n + 3,
812 8 * n + 4, 8 * n + 5, 8 * n + 6, 8 * n + 7};
813
814 auto faces = vtkSmartPointer<vtkCellArray>::New();
815 // setup faces of polyhedron
816 vtkIdType f0[3] = {8 * n + 0, 8 * n + 2, 8 * n + 1};
817 vtkIdType f1[3] = {8 * n + 1, 8 * n + 2, 8 * n + 3};
818
819 vtkIdType f2[3] = {8 * n + 0, 8 * n + 4, 8 * n + 2};
820 vtkIdType f3[3] = {8 * n + 2, 8 * n + 4, 8 * n + 6};
821
822 vtkIdType f4[3] = {8 * n + 2, 8 * n + 6, 8 * n + 3};
823 vtkIdType f5[3] = {8 * n + 3, 8 * n + 6, 8 * n + 7};
824
825 vtkIdType f6[3] = {8 * n + 1, 8 * n + 5, 8 * n + 3};
826 vtkIdType f7[3] = {8 * n + 3, 8 * n + 5, 8 * n + 7};
827
828 vtkIdType f8[3] = {8 * n + 0, 8 * n + 4, 8 * n + 1};
829 vtkIdType f9[3] = {8 * n + 1, 8 * n + 4, 8 * n + 5};
830
831 vtkIdType fa[3] = {8 * n + 4, 8 * n + 6, 8 * n + 5};
832 vtkIdType fb[3] = {8 * n + 5, 8 * n + 6, 8 * n + 7};
833
834 faces->InsertNextCell(3, f0);
835 faces->InsertNextCell(3, f1);
836 faces->InsertNextCell(3, f2);
837 faces->InsertNextCell(3, f3);
838 faces->InsertNextCell(3, f4);
839 faces->InsertNextCell(3, f5);
840 faces->InsertNextCell(3, f6);
841 faces->InsertNextCell(3, f7);
842 faces->InsertNextCell(3, f8);
843 faces->InsertNextCell(3, f9);
844 faces->InsertNextCell(3, fa);
845 faces->InsertNextCell(3, fb);
846
847 unstructuredGrid->InsertNextCell(VTK_POLYHEDRON, 8, pointIds, 12,
848 faces->GetPointer());
849#endif
850 work->SetValue(
851 n, global_vertices[n * (nVertices * balancer->getDimension() + 1) +
852 8 * balancer->getDimension()]);
853 cell->SetValue(n, (T)n);
854 }
855 unstructuredGrid->GetCellData()->AddArray(work);
856 unstructuredGrid->GetCellData()->AddArray(cell);
857
858 createDirectory("vtk_vertices");
859 std::ostringstream filename;
860 filename << "vtk_vertices/ALL_vtk_vertices_" << std::setw(7)
861 << std::setfill('0') << step << ".vtu";
862 auto writer = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
863 writer->SetInputData(unstructuredGrid);
864 writer->SetFileName(filename.str().c_str());
865 writer->SetDataModeToAscii();
866 // writer->SetDataModeToBinary();
867 writer->Write();
868
869 // delete[] global_vertices;
870 }
871 }
872#endif
873
874private:
876 LB_t method;
877
881 std::vector<Point<T>> outline;
882
884 std::unique_ptr<LB<T, W>> balancer;
885
888 std::vector<W> workArray;
889
891 MPI_Comm communicator;
892
894 int nVertices;
895
897 int nNeighbors;
898
901 void calculate_outline() {
902 // calculation only possible if there are vertices defining the domain
903 if (balancer->getVertices().size() > 0) {
904 outline.resize(2);
905 // setup the outline with the first point
906 for (int i = 0; i < balancer->getDimension(); ++i) {
907 outline.at(0) = balancer->getVertices().at(0);
908 outline.at(1) = balancer->getVertices().at(0);
909 }
910 // compare value of each outline point with all vertices to find the
911 // maximum extend of the domain in each dimension
912 for (int i = 1; i < (int)balancer->getVertices().size(); ++i) {
913 Point<T> p = balancer->getVertices().at(i);
914 for (int j = 0; j < balancer->getDimension(); ++j) {
915 outline.at(0)[j] = std::min(outline.at(0)[j], p[j]);
916 outline.at(1)[j] = std::max(outline.at(1)[j], p[j]);
917 }
918 }
919 }
920 }
921
925 void createDirectory(const char *filename) {
926 errno = 0;
927 mode_t mode = S_IRWXU | S_IRWXG; // rwx for user and group
928 if (mkdir(filename, mode)) {
929 if (errno != EEXIST) {
930 throw FilesystemErrorException(__FILE__, __func__, __LINE__,
931 "Could not create output directory.");
932 }
933 }
934 // check permission in case directory already existed, but had wrong
935 // permissions
936 struct stat attr;
937 stat(filename, &attr);
938 if ((attr.st_mode & S_IRWXU) != S_IRWXU) {
940 __FILE__, __func__, __LINE__,
941 "Possibly already existing directory does not have correct "
942 "permissions (rwx) for user");
943 }
944 }
945
949 int estimation_limit;
950
952 std::vector<int> procGridLoc;
954 std::vector<int> procGridDim;
956 bool procGridSet;
958 int procTag;
959
961 MPI_Datatype MPIDataTypeT;
962
964 MPI_Datatype MPIDataTypeW;
965
967 int loadbalancing_step;
968
969#ifdef ALL_VTK_OUTPUT
971 bool vtk_init;
972
974 vtkMPIController *controller;
975
977 vtkMPIController *controller_vertices;
978#endif
979};
980
981} // namespace ALL
982
983#endif
984
985// VIM modeline for indentation
986// vim: sw=2 et
#define ALL_ESTIMATION_LIMIT_DEFAULT
Definition ALL.hpp:80
#define known_unused
Definition ALL_Defines.h:49
std::vector< T > & getNeighborVertices()
Definition ALL.hpp:459
T getGamma()
Definition ALL.hpp:276
void setSysSize(const std::vector< T > &sysSize)
Definition ALL.hpp:485
ALL(const LB_t m, const int d, const std::vector< Point< T > > &inp, const T g)
Definition ALL.hpp:186
void setProcGridParams(const std::vector< int > &loc, const std::vector< int > &size)
Definition ALL.hpp:505
std::vector< Point< T > > & getPrevVertices()
Definition ALL.hpp:426
void setMethodData(const void *data)
Definition ALL.hpp:497
void setCommunicator(const MPI_Comm comm)
Definition ALL.hpp:214
std::vector< int > & getNeighbors()
Definition ALL.hpp:453
void printVTKvertices(const int step)
Definition ALL.hpp:718
void getWork(std::vector< W > &result)
Definition ALL.hpp:444
ALL()
Definition ALL.hpp:109
std::vector< Point< T > > & getVertices()
Definition ALL.hpp:434
W getEstimatedEfficiency()
Definition ALL.hpp:471
W getEfficiency()
Definition ALL.hpp:465
void setGammaAutoCalc(const bool b)
Definition ALL.hpp:284
W getWork()
Definition ALL.hpp:448
void setMinDomainSize(const std::vector< T > &minSize)
Definition ALL.hpp:521
void setWork(const W work)
Definition ALL.hpp:292
void setup()
Definition ALL.hpp:303
bool getGammaAutoCalc()
Definition ALL.hpp:288
std::vector< Point< T > > & balance()
Definition ALL.hpp:310
void setVertices(const std::vector< Point< T > > &inp)
Definition ALL.hpp:198
void printVTKoutlines(const int step)
Definition ALL.hpp:530
int getDimension()
Definition ALL.hpp:439
ALL(const LB_t m, const int d, const T g)
Definition ALL.hpp:145
void setWork(const std::vector< W > &work)
Definition ALL.hpp:299
void setGamma(const T g)
Definition ALL.hpp:280
void setProcTag(int tag)
Definition ALL.hpp:515
~ALL()=default
destructor
Definition ALL.hpp:78
LB_t
enum type to describe the different balancing methods
Definition ALL.hpp:83
@ FORCEBASED
unstructured-mesh load balancing
Definition ALL.hpp:89
@ STAGGERED
staggered grid load balancing
Definition ALL.hpp:85
@ VORONOI
voronoi cell based load balancing
Definition ALL.hpp:92
@ UNIMPLEMENTED
Unimplemented load balancing NEVER SUPPORTED.
Definition ALL.hpp:99
@ HISTOGRAM
histogram based load balancing
Definition ALL.hpp:95
@ TENSOR_MAX
tensor based load balancing using maximum values
Definition ALL.hpp:97
@ TENSOR
tensor based load balancing
Definition ALL.hpp:87
Exception to be used for missmatches in dimension for ALL::Point class.