ALL 0.9.4
A Loadbalacing Library
Loading...
Searching...
No Matches
ALL_Staggered.cpp
Go to the documentation of this file.
1/*
2 Copyright 2020-2020 Stephan Schulz, Forschungszentrum Juelich GmbH, Germany
3 Copyright 2018-2024 Rene Halver, Forschungszentrum Juelich GmbH, Germany
4 Copyright 2018-2020 Godehard Sutmann, Forschungszentrum Juelich GmbH, Germany
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 3. Neither the name of the copyright holder nor the names of its contributors
17 may be used to endorse or promote products derived from this software without
18 specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <stdlib.h>
34#include <stdio.h>
35// #include <time.h>
36#include <mpi.h>
37#include <string>
38#include <fstream>
39#include <iostream>
40
41// #define ALL_VTK_OUTPUT
42
43#ifdef USE_AMALGAMATED
44#include "ALL_Amalgamated.hpp"
45#else
46#include <ALL.hpp>
47#endif
48
49// Run fun in order of ranks
50// Todo(s.schulz): This seems to only work roughly with the result width an 32 ranks, with up to 16 it seems to work correctly.
51// Adding sleep(1) also orders everything correctly. So this is probably a flushing problem.
52// It also exists for the cout stream with endl.
53#define MPI_RUN_ORDER(comm, rank, max_ranks, fun) \
54 { \
55 int MPI_RO_IT; \
56 for (MPI_RO_IT = 0; MPI_RO_IT < max_ranks; MPI_RO_IT++) \
57 { \
58 if (MPI_RO_IT == rank) \
59 { \
60 fun; \
61 MPI_Barrier(comm); \
62 } \
63 else \
64 { \
65 MPI_Barrier(comm); \
66 } \
67 } \
68 }
69
70// Quick and dirty helper function. Assumes comm, rank and max_ranks
71// CAVEAT: the function call must be wrapped in () if it contains a comma
72#define MPI_RUN_ORDER_DEF(fun) MPI_RUN_ORDER(MPI_COMM_WORLD, MyRank, MaximumRank, fun)
73
74// void millisleep(unsigned long ms)
75//{
76// struct timespec SleepTime;
77// SleepTime.tv_sec = ms/1000;
78// SleepTime.tv_nsec = (ms%1000)*1000000L;
79// struct timespec RemainingTime;
80// while(nanosleep(&SleepTime, &RemainingTime))
81// {
82// SleepTime.tv_sec = RemainingTime.tv_sec;
83// SleepTime.tv_nsec = RemainingTime.tv_nsec;
84// }
85// }
86
87void print_width(int rank, double width, double bottom, double top)
88{
89 printf("[%03d] Result Width: %10.6f (%10.6f -- %10.6f)\n", rank, width, bottom, top);
90 fflush(stdout);
91}
92
93void print_testing_output(int rank, std::vector<ALL::Point<double>> &vertices, int timestep)
94{
95 // printf("[%4d,%03d] Result Width: %10.6f %10.6f %10.6f\n",
96 // timestep,
97 // rank,
98 // vertices.at(1)[0]-vertices.at(0)[0],
99 // vertices.at(1)[1]-vertices.at(0)[1],
100 // vertices.at(1)[2]-vertices.at(0)[2]);
101 // fflush(stdout);
102 printf("[%4d,%03d,%02d] Result Vertex: %10.6f %10.6f %10.6f\n",
103 timestep,
104 rank,
105 0,
106 vertices.at(0)[0],
107 vertices.at(0)[1],
108 vertices.at(0)[2]);
109 fflush(stdout);
110 printf("[%4d,%03d,%02d] Result Vertex: %10.6f %10.6f %10.6f\n",
111 timestep,
112 rank,
113 1,
114 vertices.at(1)[0],
115 vertices.at(1)[1],
116 vertices.at(1)[2]);
117 fflush(stdout);
118}
119
120void print_loc(int rank, int *loc, int *size)
121{
122 printf("[%03d] Location: (%3d,%3d,%3d)/(%3d,%3d,%3d)\n", rank, loc[0], loc[1], loc[2], size[0], size[1], size[2]);
123 fflush(stdout);
124}
125
126void print_domain(int rank, double *verts)
127{
128 printf("[%03d] Lower: %g\t%g\t%g\n", rank, verts[0], verts[1], verts[2]);
129 printf("[%03d] Upper: %g\t%g\t%g\n", rank, verts[3], verts[4], verts[5]);
130 fflush(stdout);
131}
132
133void print_work(int rank, double work)
134{
135 printf("[%03d] Work: %g\n", rank, work);
136 fflush(stdout);
137}
138
139void print_binary(int step, int rank, double work, std::vector<ALL::Point<double>> &vertices, int *loc, int *size, MPI_File fh)
140{
141 int nranks = size[0] * size[1] * size[2];
142
143 MPI_Offset offset = (step * size[0] * size[1] * size[2] * 11 + rank * 11) * sizeof(double);
144
145 double buf[11];
146
147 buf[0] = (double)rank;
148 buf[1] = work;
149 buf[2] = vertices.at(0)[0];
150 buf[3] = vertices.at(0)[1];
151 buf[4] = vertices.at(0)[2];
152 buf[5] = vertices.at(1)[0];
153 buf[6] = vertices.at(1)[1];
154 buf[7] = vertices.at(1)[2];
155 buf[8] = (double)(loc[0]);
156 buf[9] = (double)(loc[1]);
157 buf[10] = (double)(loc[2]);
158
159 MPI_Status state;
160 MPI_File_write_at(fh, offset, buf, 11, MPI_DOUBLE, &state);
161}
162
163void convert_verts(std::vector<ALL::Point<double>> *vv, double *verts)
164{
165 verts[0] = vv->at(0)[0];
166 verts[1] = vv->at(0)[1];
167 verts[2] = vv->at(0)[2];
168 verts[3] = vv->at(1)[0];
169 verts[4] = vv->at(1)[1];
170 verts[5] = vv->at(1)[2];
171}
172
173int main(int argc, char **argv)
174{
175 MPI_Init(&argc, &argv);
176 int CurrentStep = 0;
177 const int NumberOfSteps = 50;
178
179 // set the output directory for the binary file
180 std::string outputDir;
181 if (argc > 1)
182 {
183 outputDir.assign(argv[1]);
184 }
185 else
186 outputDir.assign(".");
187
188 const int Dimensions = 3;
189 const int LoadbalancerGamma = 0; // ignored for staggered method
190 // Todo(s.schulz): is gamma also ignored for tensor method?
191 // Todo(s.schulz): maybe change to automatic destruction on scope end
192 // The ALL::TENSOR method can be used just like the staggered method.
193 // Just exchange ALL::STAGGERED with ALL::TENSOR in the constructor.
194 ALL::ALL<double, double> *jall = new ALL::ALL<double, double>(ALL::STAGGERED, Dimensions, LoadbalancerGamma);
195 int MyLocation[3] = {0};
196 // All domains are placed along a line in z direction, even though they are three dimensional
197 MPI_Comm_rank(MPI_COMM_WORLD, &MyLocation[2]);
198 int MyRank = MyLocation[2];
199
200 int NumberOfProcesses[3] = {1, 1, 1};
201 MPI_Comm_size(MPI_COMM_WORLD, &NumberOfProcesses[2]);
202 int MaximumRank = NumberOfProcesses[2];
203
204 std::stringstream ss;
205 ss << outputDir << "/" << "ALL_Staggered_" << NumberOfProcesses[2] << ".bin";
206 std::string file = ss.str();
207 MPI_File fh;
208 MPI_File_delete(file.c_str(), MPI_INFO_NULL);
209 MPI_File_open(MPI_COMM_WORLD, file.c_str(), MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);
210 MPI_File_set_size(fh, NumberOfSteps * NumberOfProcesses[2] * 11 * sizeof(MPI_DOUBLE));
211 MPI_File_preallocate(fh, NumberOfSteps * NumberOfProcesses[2] * 11 * sizeof(MPI_DOUBLE));
212
213 if (MyRank == 0)
214 {
215 printf("Ranks: %d\nNumber of Steps: %d\n", MaximumRank, NumberOfSteps);
216 fflush(stdout);
217 }
218 MPI_Barrier(MPI_COMM_WORLD);
219 MPI_RUN_ORDER_DEF((print_loc(MyRank, MyLocation, NumberOfProcesses)));
220
221 // For a cartesian communicator this is not required, but we are using
222 // MPI_COMM_WORLD here.
223 std::vector<int> MyLocationVector(MyLocation, MyLocation + 3);
224 std::vector<int> NumberOfProcessesVector(NumberOfProcesses, NumberOfProcesses + 3);
225 jall->setProcGridParams(MyLocationVector, NumberOfProcessesVector);
226
227 // If we want to set a minimum domain size:
228 std::vector<double> MinimumDomainSize{0.1, 0.1, 0.1};
229 jall->setMinDomainSize(MinimumDomainSize);
230
231 jall->setCommunicator(MPI_COMM_WORLD);
232
233 // We also set the optional process tag for the output.
234 // This can be useful if we want to know which of 'our'
235 // ranks is which in the output produces by the library.
236 // The ranks used inside the library do not necessarily
237 // match our own numbering.
238 jall->setProcTag(MyRank);
239
240 jall->setup();
241 // Todo(s.schulz): document: what exactly must be set before setup()?
242
243 // A first domain distribution must be given to the balancer.
244 // We use the provided ALL::Point class to define the vertices,
245 // but a simple double array can also be used. We need 2 vertices
246 // which correspond to the two opposing corners.
247 std::vector<ALL::Point<double>> DomainVertices(2, ALL::Point<double>(3));
248 const double DomainSize = 1.0; // Domain size
249 // We create a cubic domain initially
250 for (int VertexIndex = 0; VertexIndex < 2; VertexIndex++)
251 {
252 for (int DimensionIndex = 0; DimensionIndex < Dimensions; DimensionIndex++)
253 {
254 DomainVertices.at(VertexIndex)[DimensionIndex] = (MyLocation[DimensionIndex] + VertexIndex) * DomainSize;
255 }
256 }
257 double VertexArray[6];
258 convert_verts(&DomainVertices, VertexArray);
259 MPI_RUN_ORDER_DEF((print_domain(MyRank, VertexArray)));
260 jall->setVertices(DomainVertices);
261
262 // Calculate the work of our domain. Here we just use
263 double MyWork = (double)MyRank + 1.;
264 jall->setWork(MyWork);
265 MPI_RUN_ORDER_DEF((print_work(MyRank, MyWork)));
266 for (CurrentStep = 0; CurrentStep < NumberOfSteps; CurrentStep++)
267 {
268 // In a real code we need to set the updated work in each
269 // iteration before calling balance()
270 if (MyRank == 0)
271 {
272 printf("Starting step: %d/%d\n", CurrentStep + 1, NumberOfSteps);
273 fflush(stdout);
274 }
275#ifdef ALL_VTK_OUTPUT_EXAMPLE
276 try
277 {
278 jall->printVTKoutlines(CurrentStep);
279 }
281 {
282 std::cout << e.what() << std::endl;
283 std::exit(2);
284 // Maybe also treat this error in some way, e.g. whether the simulation
285 // should abort if no output could be written or not.
286 }
287#endif
288 jall->balance();
289
290 std::vector<ALL::Point<double>> NewVertices = jall->getVertices();
291 // MPI_RUN_ORDER(MPI_COMM_WORLD, MyRank, MaximumRank, (print_width(MyRank, NewVertices.at(1)[2]-NewVertices.at(0)[2], NewVertices.at(0)[2], NewVertices.at(1)[2])));
292 // MPI_RUN_ORDER_DEF((print_testing_output(MyRank, NewVertices, CurrentStep + 1)));
293 print_binary(CurrentStep, MyRank, MyWork, NewVertices, MyLocation, NumberOfProcesses, fh);
294
295 // Maybe print our new domain? Or not..
296 // convert_verts(&NewVertices, VertexArray);
297 // MPI_RUN_ORDER_DEF((print_domain(MyRank, VertexArray)));
298 // jall->getWork(MyWork);
299 // MPI_RUN_ORDER_DEF((print_work(MyRank,MyWork)));
300 // MPI_Barrier(MPI_COMM_WORLD);
301 }
302#ifdef ALL_VTK_OUTPUT_EXAMPLE
303 try
304 {
305 jall->printVTKoutlines(CurrentStep);
306 }
308 {
309 std::cout << e.what() << std::endl;
310 }
311#endif
312
313 delete jall;
314 MPI_File_close(&fh);
315
316 /* Check correctness of binary file (if in doubt)*/
317 /*
318 if (MyRank == 0)
319 {
320 std::string filename = ss.str();
321 std::ifstream infile(filename, std::ios::binary);
322
323 double d;
324 for (int nSteps = 0; nSteps < NumberOfSteps; ++nSteps)
325 for (int n = 0; n < NumberOfProcesses[2]; ++n)
326 {
327 for (int i = 0; i < 11; ++i)
328 {
329 infile.read(reinterpret_cast<char *>(&d), sizeof d);
330 std::cerr << d << " ";
331 }
332 std::cerr << '\n';
333 }
334 infile.close();
335 }
336 */
337
338 MPI_Finalize();
339 return EXIT_SUCCESS;
340}
void print_loc(int rank, int *loc, int *size)
int main(int argc, char **argv)
void print_binary(int step, int rank, double work, std::vector< ALL::Point< double > > &vertices, int *loc, int *size, MPI_File fh)
void convert_verts(std::vector< ALL::Point< double > > *vv, double *verts)
#define MPI_RUN_ORDER_DEF(fun)
void print_testing_output(int rank, std::vector< ALL::Point< double > > &vertices, int timestep)
void print_width(int rank, double width, double bottom, double top)
void print_domain(int rank, double *verts)
void print_work(int rank, double work)
void setProcGridParams(const std::vector< int > &loc, const std::vector< int > &size)
Definition ALL.hpp:505
void setCommunicator(const MPI_Comm comm)
Definition ALL.hpp:214
std::vector< Point< T > > & getVertices()
Definition ALL.hpp:434
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
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
void setProcTag(int tag)
Definition ALL.hpp:515
@ STAGGERED
staggered grid load balancing
Definition ALL.hpp:85
virtual const char * what() const