Alamo
Util.cpp
Go to the documentation of this file.
1#include "Util.H"
2#include "AMReX_Config.H"
3#include "AMReX_DistributionMapping.H"
4#include "AMReX_VisMF.H"
5#include "Color.H"
6
7#include <chrono>
8#include <cstdlib>
9#include <filesystem>
10#include <iostream>
11#include <stdexcept>
12#include <string>
13#include <vector>
14
15#include "AMReX_ParallelDescriptor.H"
16#include "AMReX_Utility.H"
17
18#include "IO/ParmParse.H"
19#include "IO/WriteMetaData.H"
20#include "IO/FileNameParse.H"
21#include "IO/OutputLog.H"
22#include "Color.H"
23#include "Numeric/Stencil.H"
24#include "Util/MPI.H"
25#include <mpi.h>
26
27namespace
28{
29void
30ParseArgsError(const std::string &message)
31{
32 std::cerr << "ERROR: " << message << std::endl;
33 std::exit(EXIT_FAILURE);
34}
35
36bool
37IsInputDefinition(const std::string &arg)
38{
39 return arg == "input" || arg.rfind("input=", 0) == 0;
40}
41
42void
43RejectParseArgsInputFiles(const std::vector<char*> &argv)
44{
45 for (std::size_t i = 1; i < argv.size(); ++i)
46 {
47 const std::string arg(argv[i]);
48
49 if (arg == "--") break;
50
51 if (IsInputDefinition(arg))
52 {
53 ParseArgsError("--parse-args does not accept input-file directives: " + arg);
54 }
55
56 if (arg == "=") continue;
57 if (!arg.empty() && arg[0] == '-') continue;
58 if (arg.find('=') != std::string::npos) continue;
59 if (i + 1 < argv.size() && std::string(argv[i + 1]) == "=") continue;
60 if (i > 1 && std::string(argv[i - 1]) == "=") continue;
61
62 ParseArgsError("--parse-args does not accept input files or positional arguments: " + arg);
63 }
64}
65
66void
67InjectParseArgsDefaults()
68{
69 {
70 amrex::ParmParse pp("amr");
71
72 int max_level = 0;
73 pp.queryAdd("max_level", max_level);
74
75 std::vector<int> n_cell(AMREX_SPACEDIM, 1);
76 pp.queryAdd("n_cell", n_cell);
77
78 int max_grid_size = 1;
79 pp.queryAdd("max_grid_size", max_grid_size);
80
81 int blocking_factor = 1;
82 pp.queryAdd("blocking_factor", blocking_factor);
83 }
84
85 {
86 amrex::ParmParse pp("geometry");
87
88 std::vector<double> prob_lo(AMREX_SPACEDIM, 0.0);
89 pp.queryAdd("prob_lo", prob_lo, AMREX_SPACEDIM);
90
91 if (!pp.contains("prob_hi") && !pp.contains("prob_extent"))
92 {
93 std::vector<double> prob_hi(AMREX_SPACEDIM, 1.0);
94 pp.addarr("prob_hi", prob_hi);
95 }
96
97 std::vector<int> is_periodic(AMREX_SPACEDIM, 0);
98 pp.queryAdd("is_periodic", is_periodic, AMREX_SPACEDIM);
99 }
100
101 {
102 amrex::ParmParse pp;
103
104 std::string stop_time = "1.0";
105 pp.queryAdd("stop_time", stop_time);
106
107 std::string timestep = "1.0";
108 pp.queryAdd("timestep", timestep);
109 }
110}
111}
112
113namespace Util
114{
115
116std::string filename = "";
117std::string globalprefix = "";
118std::pair<std::string,std::string> file_overwrite;
119bool initialized = false;
120bool finalized = false;
121
122std::string GetFileName()
123{
124 if (filename == "")
125 {
126 IO::ParmParse pp;
127
128 pp.forbid("amr.plot_file","Depricated");
129
130 // Output file path
131 pp.query_default("plot_file", filename, "output"); // Name of directory containing all output data
132
134 // else
135 // if (amrex::ParallelDescriptor::IOProcessor())
136 // Util::Abort("No plot file specified! (Specify plot_file = \"plot_file_name\" in input file");
137 }
138 return filename;
139}
140void CopyFileToOutputDir(std::string a_path, bool fullpath, std::string prefix)
141{
142 if (IO::ParmParse::InTraversalMode()) return;
143
144 try
145 {
146 if (filename == "")
147 Util::Exception(INFO,"Cannot back up files yet because the output directory has not been specified");
148
149 std::string basefilename = std::filesystem::path(a_path).filename();
150 std::string absolutepath = std::filesystem::absolute(std::filesystem::path(a_path)).string();
151 std::string abspathfilename = absolutepath;
152 std::replace(abspathfilename.begin(),abspathfilename.end(),'/','_');
153 if (prefix != "")
154 {
155 abspathfilename = prefix + "__" + abspathfilename;
156 basefilename = prefix + "__" + abspathfilename;
157 }
158
159 if (amrex::ParallelDescriptor::IOProcessor())
160 {
161 std::string destinationpath;
162 if (fullpath) destinationpath = filename+"/"+abspathfilename;
163 else destinationpath = filename+"/"+basefilename;
164
165 // Copy the file where the file name is the absolute path, with / replaced with _
166 if (std::filesystem::exists(destinationpath))
167 Util::Exception(INFO,"Trying to copy ",destinationpath," but it already exists.");
168 std::filesystem::copy_file(a_path,destinationpath);
169 }
170 }
171 catch (std::filesystem::filesystem_error const& ex)
172 {
174 "file system error: \n",
175 " what(): " , ex.what() , '\n',
176 " path1(): " , ex.path1() , '\n',
177 " path2(): " , ex.path2() , '\n',
178 " code().value(): " , ex.code().value() , '\n',
179 " code().message(): " , ex.code().message() , '\n',
180 " code().category(): " , ex.code().category().name());
181 }
182}
183
184std::pair<std::string,std::string> GetOverwrittenFile()
185{
186 return file_overwrite;
187}
188
189void SignalHandler(int s)
190{
192 amrex::ParallelDescriptor::IOProcessor())
193 {
194 std::string filename = GetFileName();
196 if (s == SIGSEGV) status = IO::Status::Segfault;
197 else if (s == SIGINT) status = IO::Status::Interrupt;
198 if (s == SIGABRT) status = IO::Status::Abort;
199 if (filename != "")
201 }
202
203#ifdef MEME
204 IO::ParmParse pp;
205 if (!pp.contains("nomeme"))
206 {
207 time_t timer; time(&timer);
208 std::stringstream cmd;
209 cmd << "xdg-open " << BUILD_DIR << "/src/Util/Meme/cat0" << (1+((int)timer)%6) << ".gif &";
210 std::system(cmd.str().c_str());
211 std::cout << Color::Bold << Color::FG::Red << "PROGRAM FAILED!" << Color::Reset << " (Compile without -DMEME, or set nomeme = 1 in the input file to disable this!)";
212 }
213#endif
214
215 amrex::BLBackTrace::handler(s);
216}
217
218
220{
221 int argc = 0;
222 char **argv = nullptr;
223 Initialize(argc,argv);
224 initialized = true;
225}
226void Initialize (int argc, char* argv[])
227{
229 srand (time(NULL));
230
231 bool parse_args = false;
232 std::string parse_args_output = "alamo-inputs.schema.json";
233 std::vector<char*> amrex_argv;
234 amrex_argv.reserve(argc > 0 ? argc : 0);
235 for (int i = 0; i < argc; i++)
236 {
237 if (std::string(argv[i]) == "--parse-args")
238 {
239 parse_args = true;
240 continue;
241 }
242 if (std::string(argv[i]) == "--parse-args-output")
243 {
244 if (i + 1 >= argc)
245 ParseArgsError("--parse-args-output requires a file path");
246 parse_args_output = argv[++i];
247 continue;
248 }
249 amrex_argv.push_back(argv[i]);
250 }
251
252 if (parse_args) RejectParseArgsInputFiles(amrex_argv);
253
254 int amrex_argc = static_cast<int>(amrex_argv.size());
255 amrex_argv.push_back(nullptr);
256 char **amrex_argv_ptr = amrex_argc == 0 ? nullptr : amrex_argv.data();
257
259 if (parse_args)
260 IO::ParmParse::SetTraversalOutputFile(parse_args_output);
261
262 amrex::Initialize(amrex_argc, amrex_argv_ptr);
263
264 if (parse_args) InjectParseArgsDefaults();
265
266 IO::ParmParse pp;
267 pp.add("amrex.throw_exception",1);
268 //amrex.throw_exception=1
269
270 signal(SIGSEGV, Util::SignalHandler);
271 signal(SIGINT, Util::SignalHandler);
272 signal(SIGABRT, Util::SignalHandler);
273
274 std::string filename = GetFileName();
275
277 {
278 if (amrex::ParallelDescriptor::IOProcessor())
279 {
281 IO::OutputLog::Open(filename + "/out.log");
283 }
284 else
285 {
287 }
288 }
289 else
290 {
292 }
293
294 std::string length, time, mass, temperature, current, amount, luminousintensity;
295 // Set the system length unit
296 pp.query_default("system.length",length,"m");
297 // Set the system time unit
298 pp.query_default("system.time",time,"s");
299 // Set the system mass unit
300 pp.query_default("system.mass",mass,"kg");
301 // Set the system temperature unit
302 pp.query_default("system.temperature",temperature,"K");
303 // Set the system current unit
304 pp.query_default("system.current",current,"A");
305 // Set the system amount unit
306 pp.query_default("system.amount",amount,"mol");
307 // Set the system luminous intensity unit
308 pp.query_default("system.luminousintensity",luminousintensity,"cd");
309 try
310 {
311 Unit::setLengthUnit(length);
312 Unit::setTimeUnit(time);
313 Unit::setMassUnit(mass);
314 Unit::setTemperatureUnit(temperature);
315 Unit::setCurrentUnit(current);
316 Unit::setAmountUnit(amount);
317 Unit::setLuminousIntensityUnit(luminousintensity);
318
319 // Update Constants to desired system units
321 }
322 catch (std::runtime_error &e)
323 {
324 Util::Exception(INFO, "Error in setting system units: ", e.what());
325 }
326
327 //
328 // This is some logic to unit-ize the geometry.prob_lo, geometry.prob_hi input variables/
329 // We also do some checking to make sure the geometry is valid.
330 //
331 // Note that here, unlike most places, we actually **replace and overwrite** the
332 // geom.prob_* variables, since they are read deep inside amrex infrastructure.
333 //
334 {
335 IO::ParmParse pp("geometry");
336
337 if (IO::ParmParse::InTraversalMode() || pp.contains("prob_lo"))
338 {
339 std::vector<Set::Scalar> prob_lo, prob_hi;
340 // Location of the lower+left+bottom corner
341 pp.queryarr_required("prob_lo", prob_lo, Unit::Length());
342 // Location of the upper_right_top corner
343 pp.queryarr_required("prob_hi", prob_hi, Unit::Length());
344 pp.remove("prob_lo");
345 pp.remove("prob_hi");
346
347 Util::Assert( INFO,TEST(prob_lo[0] < prob_hi[0]),
348 "Invalid domain specified: ", prob_lo[0], " < x < ", prob_hi[0], " is incorrect.");
349 Util::Assert( INFO,TEST(prob_lo[1] < prob_hi[1]),
350 "Invalid domain specified: ", prob_lo[0], " < y < ", prob_hi[0], " is incorrect.");
351#if AMREX_SPACEDIM>2
352 Util::Assert( INFO,TEST(prob_lo[2] < prob_hi[2]),
353 "Invalid domain specified: ", prob_lo[0], " < z < ", prob_hi[0], " is incorrect.");
354#endif
355
356 Util::DebugMessage(INFO,"Domain lower left corner: ", Set::Vector(prob_lo.data()).transpose());
357 Util::DebugMessage(INFO,"Domain upper right corenr: ", Set::Vector(prob_hi.data()).transpose());
358
359 pp.addarr("prob_lo",prob_lo);
360 pp.addarr("prob_hi",prob_hi);
361 }
362 }
363
364
365 // This allows the user to ignore certain arguments that
366 // would otherwise cause problems.
367 // Most generally this is used in the event of a "above inputs
368 // specified but not used" error.
369 // The primary purpose of this was to fix those errors that arise
370 // in regression tests.
371
372 {
373 IO::ParmParse pp;
374 std::vector<std::string> ignore;
375 if (pp.contains("ignore")) Util::Message(INFO, "Ignore directive detected");
376 pp.queryarr("ignore", ignore); // Space-separated list of entries to ignore
377 for (unsigned int i = 0; i < ignore.size(); i++)
378 {
379 Util::Message(INFO, "ignoring ", ignore[i]);
380 pp.remove(ignore[i].c_str());
381 }
382 }
383}
384
386{
388 {
390 }
391 else
392 {
393 std::string filename = GetFileName();
394 if (filename != "")
396 }
397 amrex::Finalize();
399 finalized = true;
400}
401
402
403
404AMREX_GPU_HOST_DEVICE
405void
406Abort (const char * msg)
407{
408 AMREX_IF_ON_HOST((Terminate(msg, SIGABRT, true);))
409 AMREX_IF_ON_DEVICE((amrex::Abort();))
410}
411
412void
413Terminate(const char * /* msg */, int signal, bool /*backtrace*/)
414{
415 SignalHandler(signal);
416}
417
418std::pair<std::string,std::string>
419CreateCleanDirectory (const std::string &path, bool callbarrier)
420{
421 std::pair<std::string,std::string> ret("","");
422
423 if(amrex::ParallelDescriptor::IOProcessor()) {
424 if(amrex::FileExists(path)) {
425 std::time_t t = std::time(0);
426 std::tm * now = std::localtime(&t);
427 int year = now->tm_year+1900;
428 int month = now->tm_mon+1;
429 int day = now->tm_mday;
430 int hour = now->tm_hour;
431 int minute = now->tm_min;
432 int second = now->tm_sec;
433
434 std::stringstream ss;
435 ss << year
436 << std::setfill('0') << std::setw(2) << month
437 << std::setfill('0') << std::setw(2) << day
438 << std::setfill('0') << std::setw(2) << hour
439 << std::setfill('0') << std::setw(2) << minute
440 << std::setfill('0') << std::setw(2) << second;
441
442 std::string newoldname(path + ".old." + ss.str());
443 if (amrex::system::verbose) {
444 amrex::Print() << "Util::CreateCleanDirectory(): " << path
445 << " exists. Renaming to: " << newoldname << std::endl;
446 }
447 std::rename(path.c_str(), newoldname.c_str());
448 ret.first = path;
449 ret.second = newoldname;
450 }
451 if( ! amrex::UtilCreateDirectory(path, 0755)) {
452 amrex::CreateDirectoryFailed(path);
453 }
454 }
455 if(callbarrier) {
456 // Force other processors to wait until directory is built.
457 amrex::ParallelDescriptor::Barrier("amrex::UtilCreateCleanDirectory");
458 }
459 return ret;
460}
461
462
463namespace Test
464{
465int Message(std::string testname)
466{
467 if (amrex::ParallelDescriptor::IOProcessor())
468 std::cout << std::left
469 << Color::FG::White << Color::Bold << testname << Color::Reset << std::endl;
470 return 0;
471}
472int Message(std::string testname, int failed)
473{
474 if (amrex::ParallelDescriptor::IOProcessor())
475 {
476 winsize w;
477 ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
478 std::stringstream ss;
479 if (!failed)
480 ss << "[" << Color::FG::Green << Color::Bold << "PASS" << Color::Reset << "]";
481 else
482 ss << "[" << Color::FG::Red << Color::Bold << "FAIL" << Color::Reset << "]";
483
484 int terminalwidth = 80; //std::min(w.ws_col,(short unsigned int) 100);
485
486 std::cout << std::left
487 << testname
488 << std::setw(terminalwidth - testname.size() + ss.str().size() - 6) << std::right << std::setfill('.') << ss.str() << std::endl;
489 }
490 return failed;
491}
492int SubMessage(std::string testname, int failed)
493{
494 if (amrex::ParallelDescriptor::IOProcessor())
495 {
496 winsize w;
497 ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
498 std::stringstream ss;
499 if (!failed)
500 ss << "[" << Color::FG::LightGreen << Color::Bold << "PASS" << Color::Reset << "]";
501 else
502 ss << "[" << Color::FG::Red << Color::Bold << "FAIL" << Color::Reset << "]";
503
504 int terminalwidth = 80;
505
506 std::cout << std::left
507 << " ├ "
508 << testname
509 << std::setw(terminalwidth - testname.size() + ss.str().size() - 12) << std::right << std::setfill('.') << ss.str() << std::endl;
510 }
511 return failed;
512}
513void SubWarning(std::string testname)
514{
515 if (amrex::ParallelDescriptor::IOProcessor())
516 {
517 winsize w;
518 ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
519 std::stringstream ss;
520 ss << "[" << Color::FG::LightYellow << Color::Bold << "WARN" << Color::Reset << "]";
521
522 int terminalwidth = 80;
523
524 std::cout << std::left
525 << " ├ "
526 << testname
527 << std::setw(terminalwidth - testname.size() + ss.str().size() - 12) << std::right << std::setfill('.') << ss.str() << std::endl;
528 }
529}
530int SubFinalMessage(int failed)
531{
532 if (amrex::ParallelDescriptor::IOProcessor())
533 {
534 winsize w;
535 ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
536 std::stringstream ss;
537 std::cout << std::left << " └ ";
538
539 if (!failed)
540 std::cout << Color::FG::Green << Color::Bold << failed << " tests failed" << Color::Reset << std::endl;
541 else
542 std::cout << Color::FG::Red << Color::Bold << failed << " tests failed" << Color::Reset << std::endl;
543 }
544 return failed;
545}
546
547}
548
549void AverageCellcenterToNode(amrex::MultiFab& node_mf, const int &dcomp, const amrex::MultiFab &cell_mf, const int &scomp, const int &ncomp/*, const int ngrow=0*/)
550{
551 Util::Assert(INFO,TEST(dcomp + ncomp <= node_mf.nComp()));
552 Util::Assert(INFO,TEST(scomp + ncomp <= cell_mf.nComp()));
553 //Util::Assert(INFO,TEST(cell_mf.boxArray() == node_mf.boxArray()));
554 Util::Assert(INFO,TEST(cell_mf.DistributionMap() == cell_mf.DistributionMap()));
555 Util::Assert(INFO,TEST(cell_mf.nGrow() > 0));
556 for (amrex::MFIter mfi(node_mf,amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
557 {
558 amrex::Box bx = mfi.nodaltilebox();
559 amrex::Array4<Set::Scalar> const& node = node_mf.array(mfi);
560 amrex::Array4<const Set::Scalar> const& cell = cell_mf.array(mfi);
561 for (int n = 0; n < ncomp; n++)
562 amrex::ParallelFor (bx,[=] AMREX_GPU_DEVICE(int i, int j, int k) {
563 node(i,j,k,dcomp+n) = Numeric::Interpolate::CellToNodeAverage(cell,i,j,k,scomp+n);
564 });
565 }
566}
567
568
569}
std::time_t t
#define TEST(x)
Definition Util.H:25
#define INFO
Definition Util.H:24
void forbid(std::string name, std::string explanation, const std::source_location &location=std::source_location::current())
Definition ParmParse.H:301
static void SetTraversalMode(bool enabled)
Definition ParmParse.cpp:8
int queryarr_required(std::string name, std::vector< T > &value, const std::source_location &location=std::source_location::current())
Definition ParmParse.H:1223
int queryarr(std::string name, std::vector< T > &value, const std::source_location &location=std::source_location::current())
Definition ParmParse.H:1024
static void SetTraversalOutputFile(std::string path)
Definition ParmParse.cpp:38
int query_default(std::string name, T &value, T defaultvalue, const std::source_location &location=std::source_location::current())
Definition ParmParse.H:492
static const std::string & TraversalOutputFile()
Definition ParmParse.cpp:44
static void WriteInputTreeJsonFile(const std::string &path)
Definition ParmParse.cpp:56
static bool InTraversalMode()
Definition ParmParse.cpp:14
bool contains(std::string name, const std::source_location &location=std::source_location::current())
Definition ParmParse.H:318
static std::string LightYellow
Definition Color.H:30
static std::string Green
Definition Color.H:21
static std::string LightGreen
Definition Color.H:29
static std::string Red
Definition Color.H:20
static std::string White
Definition Color.H:34
static std::string Bold
Definition Color.H:9
static std::string Reset
Definition Color.H:8
void Initialize()
Route stdout and stderr through the terminal/file tee.
void Finalize()
Flush the log and restore the original terminal stream buffers.
void DisableFile()
Stop retaining output on ranks that do not own the log file.
void Open(const std::string &path)
Open the rank-zero log after the output directory has been created.
void WriteMetaData(std::string plot_file, Status status, int per)
void FileNameParse(std::string &filename)
Internal function to do processing of the file name.
@ Segfault
@ Complete
@ Running
@ Interrupt
@ Abort
void SetGlobalConstants()
Definition Set.cpp:19
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, 1 > Vector
Definition Base.H:21
Definition GB.H:8
int Message(std::string testname)
Definition Util.cpp:465
int SubMessage(std::string testname, int failed)
Definition Util.cpp:492
int SubFinalMessage(int failed)
Definition Util.cpp:530
void SubWarning(std::string testname)
Definition Util.cpp:513
A collection of utility routines.
Definition Set.cpp:33
std::pair< std::string, std::string > CreateCleanDirectory(const std::string &path, bool callbarrier)
Definition Util.cpp:419
void DebugMessage(std::string, std::string, int, Args const &...)
Definition Util.H:187
std::string GetFileName()
Definition Util.cpp:122
bool finalized
Definition Util.cpp:120
std::string globalprefix
Definition Util.cpp:117
void Finalize()
Definition Util.cpp:385
std::string filename
Definition Util.cpp:116
void AverageCellcenterToNode(amrex::MultiFab &node_mf, const int &dcomp, const amrex::MultiFab &cell_mf, const int &scomp, const int &ncomp)
Definition Util.cpp:549
bool initialized
Definition Util.cpp:119
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE void Assert(const char *file, const char *func, int line, const char *smt, bool pass, Args const &... args)
Definition Util.H:60
std::pair< std::string, std::string > file_overwrite
Definition Util.cpp:118
void CopyFileToOutputDir(std::string a_path, bool fullpath, std::string prefix)
Definition Util.cpp:140
void Initialize()
Definition Util.cpp:219
std::pair< std::string, std::string > GetOverwrittenFile()
Definition Util.cpp:184
void Message(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:140
AMREX_GPU_HOST_DEVICE void Abort(const char *msg)
Definition Util.cpp:406
void Exception(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:237
void Terminate(const char *, int signal, bool)
Definition Util.cpp:413
void SignalHandler(int s)
Definition Util.cpp:189
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE T CellToNodeAverage(const amrex::Array4< const T > &f, const int &i, const int &j, const int &k, const int &m, std::array< StencilType, AMREX_SPACEDIM > stencil=DefaultType())
Definition Stencil.H:1445
static void setTimeUnit(std::string unit)
Definition Unit.H:377
static void setLuminousIntensityUnit(std::string unit)
Definition Unit.H:417
static void setLengthUnit(std::string unit)
Definition Unit.H:369
static void setMassUnit(std::string unit)
Definition Unit.H:385
static void setTemperatureUnit(std::string unit)
Definition Unit.H:393
static void setCurrentUnit(std::string unit)
Definition Unit.H:401
static void setAmountUnit(std::string unit)
Definition Unit.H:409
static Unit Length()
Definition Unit.H:198