Loading [MathJax]/extensions/tex2jax.js
MAIA bb96820c
Multiphysics at AIA
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
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.