MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
functions.cpp File Reference

Go to the source code of this file.

Functions

void mTerm (const MInt errorCode, const MString &location, const MString &message)
 
MBool fileExists (const MString &fileName)
 Returns true if the file fileName exists, false otherwise. More...
 
MInt copyFile (const MString &fromName, const MString &toName)
 Copies file fromName to file toName. More...
 
void checkMultiSolverGridExtents (const MInt nDim, const MFloat *centerOfGravity, const MFloat lengthLevel0, const MInt minLevel, const MFloat *targetGridCenterOfGravity, const MFloat targetGridLengthLevel0, const MInt targetGridMinLevel)
 Checks if the given grid extents and cell sizes match when creating a multisolver grid and corresponding single solver grids to ensure that the same min-level cells and Hilbert order is used. More...
 
MInt loadPointCoordinatesFromFile (const MString inputFileName, const MInt nDim, std::vector< MFloat > &coordinates)
 Loads point coordinates from an input file. More...
 
void writeMemoryStatistics (const MPI_Comm comm, const MInt noDomains, const MInt domainId, const MString at, const MString comment)
 Write memory statistics. More...
 

Variables

EnvironmentmEnvironment
 

Function Documentation

◆ checkMultiSolverGridExtents()

void checkMultiSolverGridExtents ( const MInt  nDim,
const MFloat centerOfGravity,
const MFloat  lengthLevel0,
const MInt  minLevel,
const MFloat targetGridCenterOfGravity,
const MFloat  targetGridLengthLevel0,
const MInt  targetGridMinLevel 
)

Note: from createGridMap()

Definition at line 112 of file functions.cpp.

114 {
115 // Define epsilon for floating point comparisons (argh!)... the original
116 // definition is taken from the grid constructor but it must be clear to anyone
117 // that this is a less-than-optimal solution
118 const MFloat eps = 1.0 / FPOW2(30) * lengthLevel0;
119
120 m_log << std::setprecision(15) << "Check multisolver grid extends: length0=" << lengthLevel0
121 << "; minLevel=" << minLevel << "; targetLenght0=" << targetGridLengthLevel0
122 << "; targetMinLevel=" << targetGridMinLevel << "; eps=" << eps << std::endl;
123
124 // Check extents
125 const std::array<MString, 3> dirs = {{"x", "y", "z"}};
126 for(MInt dir = 0; dir < nDim; dir++) {
127 const std::array<MFloat, 2> gridExtent = {
128 {centerOfGravity[dir] - 0.5 * lengthLevel0, centerOfGravity[dir] + 0.5 * lengthLevel0}};
129 const std::array<MFloat, 2> globalExtent = {{targetGridCenterOfGravity[dir] - 0.5 * targetGridLengthLevel0,
130 targetGridCenterOfGravity[dir] + 0.5 * targetGridLengthLevel0}};
131
132 if(gridExtent[0] + eps < globalExtent[0]) {
133 TERMM(1,
134 "Grid extents exceed multisolver bouding box in negative " + dirs[dir]
135 + "-direction: grid=" + std::to_string(gridExtent[0]) + "; box=" + std::to_string(globalExtent[0]));
136 }
137 if(gridExtent[1] - eps > globalExtent[1]) {
138 TERMM(1,
139 "Grid extents exceed multisolver bouding box in positive " + dirs[dir]
140 + "-direction: grid=" + std::to_string(gridExtent[1]) + "; box=" + std::to_string(globalExtent[1]));
141 }
142 m_log << std::setprecision(15) << "Grid extents in the " << dirs[dir] << "-direction: [" << gridExtent[0] << ", "
143 << gridExtent[1] << "]; global: [" << globalExtent[0] << ", " << globalExtent[1] << "]" << std::endl;
144 }
145
146 // Check cell length at min level
147 const MFloat gridMinLevelLength = lengthLevel0 * FFPOW2(minLevel);
148 const MFloat globalMinLevelLength = targetGridLengthLevel0 * FFPOW2(targetGridMinLevel);
149 if(fabs(gridMinLevelLength - globalMinLevelLength) > eps) {
150 TERMM(1,
151 "Length of min level cells do not match between grid and given multisolver bounding "
152 "box: grid: "
153 + std::to_string(gridMinLevelLength) + "; box: " + std::to_string(globalMinLevelLength));
154 } else {
155 m_log << std::setprecision(15)
156 << "Length of min level cells match between grid and given multisolver bounding "
157 "box: grid: "
158 << gridMinLevelLength << "; box: " << globalMinLevelLength << std::endl;
159 }
160
161 // Check if grid centers are displaced by an integer multiple of the min
162 // level length
163 for(MInt dir = 0; dir < nDim; dir++) {
164 const MFloat displacement = fabs(centerOfGravity[dir] - targetGridCenterOfGravity[dir]);
165 const MFloat quotient = displacement / globalMinLevelLength;
166 if(!isApproxInt(quotient, eps)) {
167 TERMM(1, "The grid centers are displaced in the " + dirs[dir]
168 + "-direction by a non-integer multiple of the length of a "
169 "partition cell: "
170 + std::to_string(quotient));
171 } else {
172 m_log << std::setprecision(15) << "The grid centers are displaced in the " << dirs[dir]
173 << "-direction by a multiple of the length of a "
174 "partition cell: "
175 << quotient << " (displacement = " << displacement << ")" << std::endl;
176 }
177 }
178}
MBool isApproxInt(const T &, const T)
Definition: functions.h:284
InfoOutFile m_log
constexpr MFloat FPOW2(MInt x)
constexpr MFloat FFPOW2(MInt x)
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52

◆ copyFile()

MInt copyFile ( const MString fromName,
const MString toName 
)
Returns
error code
Return values
0if copying succeeded
-1if copying failed

Definition at line 83 of file functions.cpp.

83 {
84 if(!fileExists(fromName)) {
85 std::cerr << "Could not copy file " << fromName << ".\n";
86 return -1;
87 }
88 if(fileExists(toName)) {
89 remove(toName.c_str());
90 }
91 std::ifstream src(fromName.c_str());
92 std::ofstream dst(toName.c_str());
93 if(src.good() && dst.good()) {
94 dst << src.rdbuf();
95 dst.close();
96 dst.clear();
97 src.close();
98 src.clear();
99 } else {
100 std::cerr << "Could not copy file " << fromName << " (2).\n";
101 return -1;
102 }
103 return 0;
104}
MBool fileExists(const MString &fileName)
Returns true if the file fileName exists, false otherwise.
Definition: functions.cpp:73

◆ fileExists()

MBool fileExists ( const MString fileName)

Definition at line 73 of file functions.cpp.

73 {
74 struct stat buffer;
75 return (stat(fileName.c_str(), &buffer) == 0);
76}

◆ loadPointCoordinatesFromFile()

MInt loadPointCoordinatesFromFile ( const MString  inputFileName,
const MInt  nDim,
std::vector< MFloat > &  coordinates 
)

Definition at line 182 of file functions.cpp.

182 {
183 TRACE();
184
185 MString line;
186 MFloat curFloat;
187 MInt noPoints = 0;
188 std::istringstream iss;
189 std::ifstream csvFile(inputFileName);
190 coordinates.clear();
191
192 // Read all lines and get coordinates
193 while(getline(csvFile, line)) {
194 iss.str(line);
195 iss.clear();
196
197 for(MInt i = 0; i < nDim; i++) {
198 iss >> curFloat;
199 if(iss.fail()) {
200 std::ostringstream err;
201 // start line count at one
202 err << "Error at line " << noPoints + 1 << ": " << line << "\n"
203 << "Either wrong dimension (nDim = " << nDim << ") or otherwise wrong format."
204 << "Format should be nDim floats seperated by spaces per line.";
205 TERMM(1, err.str());
206 }
207 coordinates.push_back(curFloat);
208 }
209 noPoints++;
210 }
211
212 return noPoints;
213}
std::basic_string< char > MString
Definition: maiatypes.h:55
std::istream & getline(std::istream &input, std::string &line)
Definition: cpptoml.h:1519

◆ mTerm()

void mTerm ( const MInt  errorCode,
const MString location,
const MString message 
)

Terminates MAIA properly

Author
Pascal Meysonnat

Definition at line 29 of file functions.cpp.

29 {
30 if(errorCode != 0) {
31 std::stringstream s;
32 s << "\n";
33 s << "Rank " << globalDomainId() << " threw exit code " << errorCode << "\n";
34 s << "Error in " << location << ": " << message << "\n";
35 s << "\n"
36 << "Program is aborting!!\n";
37 std::cerr << s.str() << std::flush;
38
39 // Print backtrace (if enabled)
40 BACKTRACE();
41
42 // Close the log file to make sure that no MPI error occurs from the
43 // unclosed file, and that a proper XML footer is written
44#ifndef PVPLUGIN
45 m_log.close(true);
46 maia_res.close(true);
47#endif
48 MPI_Abort(MPI_COMM_WORLD, errorCode, AT_);
49 } else {
50 mDealloc();
51#ifndef PVPLUGIN
52 if(mEnvironment) {
53 delete mEnvironment;
54 mEnvironment = nullptr;
55 }
56
57 // Close the log file to make sure that no MPI error occurs from the
58 // unclosed file, and that a proper XML footer is written
59 m_log.close();
61#endif
62 // Call MPI_Finalize to ensure proper MPI shutdown
63 MPI_Finalize();
64
65 // Exit the program
66 exit(0);
67 }
68 exit(errorCode);
69}
void mDealloc()
Deallocates all memory allocated previously by mAlloc(...)
Definition: alloc.cpp:20
void close(MBool forceClose=false)
Pass the close call to the respective internal buffer.
Definition: infoout.cpp:1011
Environment * mEnvironment
Definition: maia.cpp:42
const MString const MString & message
Definition: functions.h:37
const MString & location
Definition: functions.h:37
MInt globalDomainId()
Return global domain id.
InfoOutFile maia_res
int MPI_Abort(MPI_Comm comm, int errorcode, const MString &name)
same as MPI_Abort

◆ writeMemoryStatistics()

void writeMemoryStatistics ( const MPI_Comm  comm,
const MInt  noDomains,
const MInt  domainId,
const MString  at,
const MString  comment 
)

Definition at line 218 of file functions.cpp.

219 {
220 // Static members to compute difference to last memory evaluation
221 static MLong virtMemLast = 0;
222 static MLong physMemLast = 0;
223 // OBTAIN MEMORY USAGE
224 MLong virtMem = 0;
225 MLong physMem = 0;
226 MLong stackMem = 0;
227 MLong physMemFree = 0;
228 MLong memAvailable = 0;
229
230 {
231 // Create error flags
232 MInt fileNotFound = 0;
233 MInt memoryNotFound = 0;
234
235 // Open status file of the process
236 std::ifstream fin;
237 fin.open("/proc/self/status");
238 // Modify flag if file is not found
239 if(!fin) {
240 fileNotFound = 1;
241 }
242
243 MString line;
244 MString name;
245 MLong buffer;
246 std::istringstream iss;
247 std::array<MInt, 5> foundInfo;
248 foundInfo.fill(false);
249
250 // Read all lines and get memory usage/allocation size for this process
251 while(getline(fin, line)) {
252 buffer = 0;
253 iss.str(line);
254 iss.clear();
255 getline(iss, name, ':');
256 if(name == "VmRSS") { // Physical memory currently used by current process
257 iss >> buffer;
258 physMem = buffer;
259 foundInfo[0] = true;
260 } else if(name == "VmData") { // Allocated memory size on heap
261 iss >> buffer;
262 virtMem += buffer;
263 foundInfo[1] = true;
264 } else if(name == "VmStk") { // Allocated memory size on stack
265 iss >> buffer;
266 virtMem += buffer;
267 stackMem = buffer;
268 foundInfo[2] = true;
269 }
270 }
271 fin.close();
272
273 // Open meminfo file on current node to determine total free/available memory per node
274 fin.open("/proc/meminfo");
275 if(!fin) {
276 fileNotFound = 1;
277 }
278
279 while(getline(fin, line)) {
280 buffer = 0;
281 iss.str(line);
282 iss.clear();
283 getline(iss, name, ':');
284 if(name == "MemFree") {
285 iss >> buffer;
286 physMemFree = buffer;
287 foundInfo[3] = true;
288 } else if(name == "MemAvailable") {
289 iss >> buffer;
290 memAvailable = buffer;
291 foundInfo[4] = true;
292 }
293 }
294 fin.close();
295
296 // Set flag if any memory usage couldn't be gathered from file
297 memoryNotFound = std::any_of(foundInfo.begin(), foundInfo.end(), [](MBool i) { return !i; });
298
299 // Allreduce flags, only proceed if there was no error
300 MPI_Allreduce(MPI_IN_PLACE, &fileNotFound, 1, MPI_INT, MPI_MAX, comm, AT_, "MPI_IN_PLACE", "&fileNotFound");
301 MPI_Allreduce(MPI_IN_PLACE, &memoryNotFound, 1, MPI_INT, MPI_MAX, comm, AT_, "MPI_IN_PLACE", "&memoryNotFound");
302 MPI_Allreduce(MPI_IN_PLACE, &foundInfo[0], 5, MPI_INT, MPI_MAX, comm, AT_, "MPI_IN_PLACE", "&foundInfo");
303
304 if(fileNotFound || memoryNotFound) {
305 // Throw error and return from function if file or memory couldn't be accessed
306 if(domainId == 0) {
307 std::stringstream ss;
308 ss << "Error in writeMemoryStatistics: Could not determine memory statistics! " << fileNotFound << " "
309 << memoryNotFound << " (";
310 for(MInt i = 0; i < 5; i++) {
311 ss << " " << foundInfo[i];
312 }
313 ss << ")" << std::endl;
314 std::cerr << ss.str();
315 m_log << ss.str();
316 }
317 return;
318 }
319 }
320
321 MLongScratchSpace physMemPerProcess(noDomains, AT_, "physMemPerProcess");
322 MLongScratchSpace virtMemPerProcess(noDomains, AT_, "virtMemPerProcess");
323
324 // Gather memory from each process
325 MPI_Gather(&physMem, 1, MPI_LONG, physMemPerProcess.getPointer(), 1, MPI_LONG, 0, comm, AT_, "physMem",
326 "physMemPerProcess.getPointer()");
327 MPI_Gather(&virtMem, 1, MPI_LONG, virtMemPerProcess.getPointer(), 1, MPI_LONG, 0, comm, AT_, "virtMem",
328 "virtMemPerProcess.getPointer()");
329
330 MLongScratchSpace physMemDiffPerProcess(noDomains, AT_, "physMemDiffPerProcess");
331 MLongScratchSpace virtMemDiffPerProcess(noDomains, AT_, "virtMemDiffPerProcess");
332
333 MLong physMemDiff = physMem - physMemLast;
334 MLong virtMemDiff = virtMem - virtMemLast;
335 // Gather difference in allocated memory from each process
336 MPI_Gather(&physMemDiff, 1, MPI_LONG, physMemDiffPerProcess.getPointer(), 1, MPI_LONG, 0, comm, AT_, "physMem",
337 "physMemDiffPerProcess.getPointer()");
338 MPI_Gather(&virtMemDiff, 1, MPI_LONG, virtMemDiffPerProcess.getPointer(), 1, MPI_LONG, 0, comm, AT_, "virtMem",
339 "virtMemDiffPerProcess.getPointer()");
340
341 // Store current values for next evaluation
342 physMemLast = physMem;
343 virtMemLast = virtMem;
344
345 // Gather stack memory usage
346 MLongScratchSpace stackMemPerProcess(noDomains, AT_, "stackMemPerProcess");
347 MPI_Gather(&stackMem, 1, MPI_LONG, stackMemPerProcess.getPointer(), 1, MPI_LONG, 0, comm, AT_, "stackMem",
348 "stackMemPerProcess.getPointer()");
349
350 // Compute minimum free/available memory
351 MLong minPhysMemFree = physMemFree;
352 MPI_Allreduce(MPI_IN_PLACE, &minPhysMemFree, 1, MPI_LONG, MPI_MIN, comm, AT_, "MPI_IN_PLACE", "&minPhysMemFree");
353 MLong minMemAvailable = memAvailable;
354 MPI_Allreduce(MPI_IN_PLACE, &minMemAvailable, 1, MPI_LONG, MPI_MIN, comm, AT_, "MPI_IN_PLACE", "&minMemAvailable");
355
356 // Determine global memory statistics
357 if(domainId == 0) {
358 MLong totalPhysMem = 0;
359 MLong totalVirtMem = 0;
360 MLong totalPhysMemDiffSum = 0;
361 MLong totalVirtMemDiffSum = 0;
362 MLong totalPhysMemDiffMax = 0;
363 MLong totalVirtMemDiffMax = 0;
364 MLong maxStackMem = 0;
365
366 for(MInt i = 0; i < noDomains; i++) {
367 // Total allocation size
368 totalPhysMem += physMemPerProcess[i];
369 totalVirtMem += virtMemPerProcess[i];
370 // Total difference in allocation size compared to the last evaluation
371 totalPhysMemDiffSum += physMemDiffPerProcess[i];
372 totalVirtMemDiffSum += virtMemDiffPerProcess[i];
373 // Maximum difference in allocation size over all processes
374 totalPhysMemDiffMax = std::max(physMemDiffPerProcess[i], totalPhysMemDiffMax);
375 totalVirtMemDiffMax = std::max(virtMemDiffPerProcess[i], totalVirtMemDiffMax);
376 // Maximum stack memory usage
377 maxStackMem = std::max(stackMemPerProcess[i], maxStackMem);
378 }
379
380 // Get maximum size of the process stack (this assumes it is the same on all ranks)
381 rlimit rlim;
382 getrlimit(RLIMIT_STACK, &rlim);
383 // Define rlimit as an unsigned long (same as it's defined in the kernel)
384 const MUlong rlim_stack = rlim.rlim_cur;
385 // Note: issue warning if stack usage is quite high (compared to stack size limit)
386 if(maxStackMem > 0.5 * rlim_stack) {
387 std::stringstream warning;
388 warning << std::endl
389 << "WARNING: maximum stack memory usage >50% of its limit, use 'ulimit -s unlimited' to remove this "
390 "memory restriction and avoid segmentation faults if the stack memory usage exceeds its limit."
391 << std::endl;
392 warning << "WARNING: stack memory usage " << (MFloat)maxStackMem << " KB; stack limit "
393 << (MFloat)rlim_stack / 1024 << " KB" << std::endl
394 << std::endl;
395 m_log << warning.str();
396 std::cerr << warning.str();
397 }
398
399 // Write memory statistics
400#ifndef NDEBUG
401 // Memory per process
402 for(MInt i = 0; i < noDomains; i++) {
403 m_log << " Process " << i << " - Current memory usage: physical = " << (MFloat)physMemPerProcess[i] / 1024
404 << " MB; allocation = " << (MFloat)virtMemPerProcess[i] / 1024 << " MB" << std::endl;
405 }
406#endif
407
408 std::stringstream ss;
409 ss << std::endl;
410 ss << "******************************* MEMORY STATISTICS *******************************" << std::endl;
411 ss << "***** Comment: " << comment << " - #ranks: " << noDomains << std::endl;
412 ss << "***** Location: " << at << std::endl;
413 ss << "***** " << std::endl;
414 // Average memory
415 ss << "***** Average memory usage: physical = " << (MFloat)totalPhysMem / (noDomains * 1024)
416 << " MB; allocation = " << (MFloat)totalVirtMem / (noDomains * 1024) << " MB\n";
417
418 // Min/Max memory
419 ss << "***** Minimun memory usage: physical = "
420 << (MFloat)*std::min_element(physMemPerProcess.begin(), physMemPerProcess.end()) / 1024
421 << " MB; allocation = " << (MFloat)*std::min_element(virtMemPerProcess.begin(), virtMemPerProcess.end()) / 1024
422 << " MB\n";
423 ss << "***** Maximum memory usage: physical = "
424 << (MFloat)*std::max_element(physMemPerProcess.begin(), physMemPerProcess.end()) / 1024
425 << " MB; allocation = " << (MFloat)*std::max_element(virtMemPerProcess.begin(), virtMemPerProcess.end()) / 1024
426 << " MB\n";
427 ss << "***** Maximum diff in memory usage: physical = " << (MFloat)totalPhysMemDiffMax / 1024
428 << " MB; allocation = " << (MFloat)totalVirtMemDiffMax / 1024 << " MB\n";
429
430 // Total memory
431 ss << "***** Total physical memory usage (RAM): " << (MFloat)totalPhysMem / (1024 * 1024) << " GB\n";
432 ss << "***** Diff total physical memory usage (RAM): " << (MFloat)totalPhysMemDiffSum / (1024 * 1024) << " GB\n";
433 ss << "***** Total allocation size (Virtual Memory): " << (MFloat)totalVirtMem / (1024 * 1024) << " GB"
434 << std::endl;
435 ss << "***** Diff total allocation size (Virtual Memory): " << (MFloat)totalVirtMemDiffSum / (1024 * 1024) << " GB"
436 << std::endl;
437 ss << "***** " << std::endl;
438 ss << "***** Maximum stack memory: " << (MFloat)maxStackMem << " KB; stack limit " << (MFloat)rlim_stack / 1024
439 << " KB" << std::endl;
440 ss << "***** " << std::endl;
441 ss << "***** Minimum available memory per node (meminfo): " << (MFloat)minMemAvailable / (1024 * 1024) << " GB"
442 << std::endl;
443 ss << "***** Minimum free memory per node (RAM): " << (MFloat)minPhysMemFree / (1024 * 1024) << " GB" << std::endl;
444 ss << "******************************* MEMORY STATISTICS *******************************" << std::endl << std::endl;
445
446 std::cout << ss.str() << std::endl;
447 m_log << ss.str() << std::endl;
448 }
449}
This class is a ScratchSpace.
Definition: scratch.h:758
int64_t MLong
Definition: maiatypes.h:64
bool MBool
Definition: maiatypes.h:58
uint64_t MUlong
Definition: maiatypes.h:65
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce
int MPI_Gather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Gather

Variable Documentation

◆ mEnvironment

Environment* mEnvironment
extern

Definition at line 42 of file maia.cpp.