Line data Source code
1 : #include "Util.H"
2 : #include "Color.H"
3 :
4 : #include <chrono>
5 : #include <cstdlib>
6 : #include <filesystem>
7 : #include <stdexcept>
8 :
9 : #include "AMReX_ParallelDescriptor.H"
10 : #include "AMReX_Utility.H"
11 :
12 : #include "IO/ParmParse.H"
13 : #include "IO/WriteMetaData.H"
14 : #include "IO/FileNameParse.H"
15 : #include "Color.H"
16 : #include "Numeric/Stencil.H"
17 :
18 : namespace Util
19 : {
20 :
21 : std::string filename = "";
22 : std::string globalprefix = "";
23 : std::pair<std::string,std::string> file_overwrite;
24 : bool initialized = false;
25 : bool finalized = false;
26 :
27 121 : std::string GetFileName()
28 : {
29 121 : if (filename == "")
30 : {
31 41 : IO::ParmParse pp;
32 41 : IO::ParmParse pp_amr("amr");
33 :
34 123 : if (pp_amr.contains("plot_file") && pp.contains("plot_file"))
35 0 : Util::Abort("plot_file specified in too many locations");
36 82 : else if (pp_amr.contains("plot_file"))
37 : {
38 0 : if (amrex::ParallelDescriptor::IOProcessor())
39 : amrex::Warning("amr.plot_file will be depricated; use plot_file instead");
40 0 : pp_amr.query("plot_file", filename);
41 :
42 : }
43 82 : else if (pp.contains("plot_file"))
44 : {
45 41 : pp_query("plot_file", filename); // Name of directory containing all output data
46 : }
47 41 : IO::FileNameParse(filename);
48 : // else
49 : // if (amrex::ParallelDescriptor::IOProcessor())
50 : // Util::Abort("No plot file specified! (Specify plot_file = \"plot_file_name\" in input file");
51 41 : }
52 121 : return filename;
53 : }
54 1 : void CopyFileToOutputDir(std::string a_path, bool fullpath, std::string prefix)
55 : {
56 : try
57 : {
58 1 : if (filename == "")
59 0 : Util::Exception(INFO,"Cannot back up files yet because the output directory has not been specified");
60 :
61 1 : std::string basefilename = std::filesystem::path(a_path).filename();
62 1 : std::string absolutepath = std::filesystem::absolute(std::filesystem::path(a_path)).string();
63 1 : std::string abspathfilename = absolutepath;
64 1 : std::replace(abspathfilename.begin(),abspathfilename.end(),'/','_');
65 1 : if (prefix != "")
66 : {
67 1 : abspathfilename = prefix + "__" + abspathfilename;
68 1 : basefilename = prefix + "__" + abspathfilename;
69 : }
70 :
71 1 : if (amrex::ParallelDescriptor::IOProcessor())
72 : {
73 1 : std::string destinationpath;
74 1 : if (fullpath) destinationpath = filename+"/"+abspathfilename;
75 0 : else destinationpath = filename+"/"+basefilename;
76 :
77 : // Copy the file where the file name is the absolute path, with / replaced with _
78 1 : if (std::filesystem::exists(destinationpath))
79 0 : Util::Exception(INFO,"Trying to copy ",destinationpath," but it already exists.");
80 1 : std::filesystem::copy_file(a_path,destinationpath);
81 1 : }
82 1 : }
83 0 : catch (std::filesystem::filesystem_error const& ex)
84 : {
85 0 : Util::Exception(INFO,
86 : "file system error: \n",
87 0 : " what(): " , ex.what() , '\n',
88 0 : " path1(): " , ex.path1() , '\n',
89 0 : " path2(): " , ex.path2() , '\n',
90 0 : " code().value(): " , ex.code().value() , '\n',
91 0 : " code().message(): " , ex.code().message() , '\n',
92 0 : " code().category(): " , ex.code().category().name());
93 0 : }
94 1 : }
95 :
96 0 : std::pair<std::string,std::string> GetOverwrittenFile()
97 : {
98 0 : return file_overwrite;
99 : }
100 :
101 0 : void SignalHandler(int s)
102 : {
103 0 : if (amrex::ParallelDescriptor::IOProcessor())
104 : {
105 0 : std::string filename = GetFileName();
106 0 : IO::Status status = IO::Status::Running;
107 0 : if (s == SIGSEGV) status = IO::Status::Segfault;
108 0 : else if (s == SIGINT) status = IO::Status::Interrupt;
109 0 : if (s == SIGABRT) status = IO::Status::Abort;
110 0 : if (filename != "")
111 0 : IO::WriteMetaData(filename,status);
112 0 : }
113 :
114 : #ifdef MEME
115 : IO::ParmParse pp;
116 : if (!pp.contains("nomeme"))
117 : {
118 : time_t timer; time(&timer);
119 : std::stringstream cmd;
120 : cmd << "xdg-open " << BUILD_DIR << "/src/Util/Meme/cat0" << (1+((int)timer)%6) << ".gif &";
121 : std::system(cmd.str().c_str());
122 : 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!)";
123 : }
124 : #endif
125 :
126 0 : amrex::BLBackTrace::handler(s);
127 0 : }
128 :
129 :
130 0 : void Initialize ()
131 : {
132 0 : int argc = 0;
133 0 : char **argv = nullptr;
134 0 : Initialize(argc,argv);
135 0 : initialized = true;
136 0 : }
137 41 : void Initialize (int argc, char* argv[])
138 : {
139 41 : srand (time(NULL));
140 :
141 41 : amrex::Initialize(argc, argv);
142 :
143 41 : IO::ParmParse pp_amrex("amrex");
144 41 : pp_amrex.add("throw_exception",1);
145 : //amrex.throw_exception=1
146 :
147 41 : signal(SIGSEGV, Util::SignalHandler);
148 41 : signal(SIGINT, Util::SignalHandler);
149 41 : signal(SIGABRT, Util::SignalHandler);
150 :
151 41 : std::string filename = GetFileName();
152 :
153 41 : if (amrex::ParallelDescriptor::IOProcessor() && filename != "")
154 : {
155 41 : file_overwrite = Util::CreateCleanDirectory(filename, false);
156 41 : IO::WriteMetaData(filename);
157 : }
158 :
159 41 : IO::ParmParse pp;
160 41 : std::string length, time, mass, temperature, current, amount, luminousintensity;
161 : // Set the system length unit
162 82 : pp.query_default("system.length",length,"m");
163 : // Set the system time unit
164 82 : pp.query_default("system.time",time,"s");
165 : // Set the system mass unit
166 82 : pp.query_default("system.mass",mass,"kg");
167 : // Set the system temperature unit
168 82 : pp.query_default("system.temperature",temperature,"K");
169 : // Set the system current unit
170 82 : pp.query_default("system.current",current,"A");
171 : // Set the system amount unit
172 82 : pp.query_default("system.amount",amount,"mol");
173 : // Set the system luminous intensity unit
174 41 : pp.query_default("system.luminousintensity",luminousintensity,"cd");
175 : try
176 : {
177 41 : Unit::setLengthUnit(length);
178 41 : Unit::setTimeUnit(time);
179 41 : Unit::setMassUnit(mass);
180 41 : Unit::setTemperatureUnit(temperature);
181 41 : Unit::setCurrentUnit(current);
182 41 : Unit::setAmountUnit(amount);
183 41 : Unit::setLuminousIntensityUnit(luminousintensity);
184 :
185 : // Update Constants to desired system units
186 41 : Set::Constant::SetGlobalConstants();
187 : }
188 0 : catch (std::runtime_error &e)
189 : {
190 0 : Util::Exception(INFO, "Error in setting system units: ", e.what());
191 0 : }
192 :
193 : //
194 : // This is some logic to unit-ize the geometry.prob_lo, geometry.prob_hi input variables/
195 : // We also do some checking to make sure the geometry is valid.
196 : //
197 : // Note that here, unlike most places, we actually **replace and overwrite** the
198 : // geom.prob_* variables, since they are read deep inside amrex infrastructure.
199 : //
200 : {
201 82 : IO::ParmParse pp("geometry");
202 :
203 82 : if (pp.contains("prob_lo"))
204 : {
205 39 : std::vector<Set::Scalar> prob_lo, prob_hi;
206 : // Location of the lower+left+bottom corner
207 78 : pp.queryarr("prob_lo", prob_lo, Unit::Length());
208 : // Location of the upper_right_top corner
209 78 : pp.queryarr("prob_hi", prob_hi, Unit::Length());
210 39 : pp.remove("prob_lo");
211 39 : pp.remove("prob_hi");
212 :
213 273 : Util::Assert( INFO,TEST(prob_lo[0] < prob_hi[0]),
214 39 : "Invalid domain specified: ", prob_lo[0], " < x < ", prob_hi[0], " is incorrect.");
215 273 : Util::Assert( INFO,TEST(prob_lo[1] < prob_hi[1]),
216 39 : "Invalid domain specified: ", prob_lo[0], " < y < ", prob_hi[0], " is incorrect.");
217 : #if AMREX_SPACEDIM>2
218 21 : Util::Assert( INFO,TEST(prob_lo[2] < prob_hi[2]),
219 3 : "Invalid domain specified: ", prob_lo[0], " < z < ", prob_hi[0], " is incorrect.");
220 : #endif
221 :
222 156 : Util::DebugMessage(INFO,"Domain lower left corner: ", Set::Vector(prob_lo.data()).transpose());
223 156 : Util::DebugMessage(INFO,"Domain upper right corenr: ", Set::Vector(prob_hi.data()).transpose());
224 :
225 39 : pp.addarr("prob_lo",prob_lo);
226 39 : pp.addarr("prob_hi",prob_hi);
227 39 : }
228 41 : }
229 :
230 :
231 : // This allows the user to ignore certain arguments that
232 : // would otherwise cause problems.
233 : // Most generally this is used in the event of a "above inputs
234 : // specified but not used" error.
235 : // The primary purpose of this was to fix those errors that arise
236 : // in regression tests.
237 :
238 : {
239 41 : IO::ParmParse pp;
240 41 : std::vector<std::string> ignore;
241 90 : if (pp.contains("ignore")) Util::Message(INFO, "Ignore directive detected");
242 41 : pp.queryarr("ignore", ignore); // Space-separated list of entries to ignore
243 45 : for (unsigned int i = 0; i < ignore.size(); i++)
244 : {
245 16 : Util::Message(INFO, "ignoring ", ignore[i]);
246 4 : pp.remove(ignore[i].c_str());
247 : }
248 41 : }
249 41 : }
250 :
251 41 : void Finalize()
252 : {
253 41 : std::string filename = GetFileName();
254 41 : if (filename != "")
255 41 : IO::WriteMetaData(filename,IO::Status::Complete);
256 41 : amrex::Finalize();
257 41 : finalized = true;
258 41 : }
259 :
260 :
261 :
262 : void
263 0 : Abort (const char * msg) { Terminate(msg, SIGABRT, true); }
264 :
265 : void
266 0 : Terminate(const char * /* msg */, int signal, bool /*backtrace*/)
267 : {
268 0 : SignalHandler(signal);
269 0 : }
270 :
271 : std::pair<std::string,std::string>
272 41 : CreateCleanDirectory (const std::string &path, bool callbarrier)
273 : {
274 41 : std::pair<std::string,std::string> ret("","");
275 :
276 41 : if(amrex::ParallelDescriptor::IOProcessor()) {
277 41 : if(amrex::FileExists(path)) {
278 0 : std::time_t t = std::time(0);
279 0 : std::tm * now = std::localtime(&t);
280 0 : int year = now->tm_year+1900;
281 0 : int month = now->tm_mon+1;
282 0 : int day = now->tm_mday;
283 0 : int hour = now->tm_hour;
284 0 : int minute = now->tm_min;
285 0 : int second = now->tm_sec;
286 :
287 0 : std::stringstream ss;
288 : ss << year
289 0 : << std::setfill('0') << std::setw(2) << month
290 0 : << std::setfill('0') << std::setw(2) << day
291 0 : << std::setfill('0') << std::setw(2) << hour
292 0 : << std::setfill('0') << std::setw(2) << minute
293 0 : << std::setfill('0') << std::setw(2) << second;
294 :
295 0 : std::string newoldname(path + ".old." + ss.str());
296 0 : if (amrex::system::verbose) {
297 0 : amrex::Print() << "Util::CreateCleanDirectory(): " << path
298 0 : << " exists. Renaming to: " << newoldname << std::endl;
299 : }
300 0 : std::rename(path.c_str(), newoldname.c_str());
301 0 : ret.first = path;
302 0 : ret.second = newoldname;
303 0 : }
304 41 : if( ! amrex::UtilCreateDirectory(path, 0755)) {
305 0 : amrex::CreateDirectoryFailed(path);
306 : }
307 : }
308 41 : if(callbarrier) {
309 : // Force other processors to wait until directory is built.
310 0 : amrex::ParallelDescriptor::Barrier("amrex::UtilCreateCleanDirectory");
311 : }
312 41 : return ret;
313 0 : }
314 :
315 :
316 : namespace Test
317 : {
318 42 : int Message(std::string testname)
319 : {
320 42 : if (amrex::ParallelDescriptor::IOProcessor())
321 42 : std::cout << std::left
322 42 : << Color::FG::White << Color::Bold << testname << Color::Reset << std::endl;
323 42 : return 0;
324 : }
325 0 : int Message(std::string testname, int failed)
326 : {
327 0 : if (amrex::ParallelDescriptor::IOProcessor())
328 : {
329 : winsize w;
330 0 : ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
331 0 : std::stringstream ss;
332 0 : if (!failed)
333 0 : ss << "[" << Color::FG::Green << Color::Bold << "PASS" << Color::Reset << "]";
334 : else
335 0 : ss << "[" << Color::FG::Red << Color::Bold << "FAIL" << Color::Reset << "]";
336 :
337 0 : int terminalwidth = 80; //std::min(w.ws_col,(short unsigned int) 100);
338 :
339 0 : std::cout << std::left
340 : << testname
341 0 : << std::setw(terminalwidth - testname.size() + ss.str().size() - 6) << std::right << std::setfill('.') << ss.str() << std::endl;
342 0 : }
343 0 : return failed;
344 : }
345 168 : int SubMessage(std::string testname, int failed)
346 : {
347 168 : if (amrex::ParallelDescriptor::IOProcessor())
348 : {
349 : winsize w;
350 168 : ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
351 168 : std::stringstream ss;
352 168 : if (!failed)
353 168 : ss << "[" << Color::FG::LightGreen << Color::Bold << "PASS" << Color::Reset << "]";
354 : else
355 0 : ss << "[" << Color::FG::Red << Color::Bold << "FAIL" << Color::Reset << "]";
356 :
357 168 : int terminalwidth = 80;
358 :
359 168 : std::cout << std::left
360 : << " ├ "
361 : << testname
362 168 : << std::setw(terminalwidth - testname.size() + ss.str().size() - 12) << std::right << std::setfill('.') << ss.str() << std::endl;
363 168 : }
364 168 : return failed;
365 : }
366 20 : void SubWarning(std::string testname)
367 : {
368 20 : if (amrex::ParallelDescriptor::IOProcessor())
369 : {
370 : winsize w;
371 20 : ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
372 20 : std::stringstream ss;
373 20 : ss << "[" << Color::FG::LightYellow << Color::Bold << "WARN" << Color::Reset << "]";
374 :
375 20 : int terminalwidth = 80;
376 :
377 20 : std::cout << std::left
378 : << " ├ "
379 : << testname
380 20 : << std::setw(terminalwidth - testname.size() + ss.str().size() - 12) << std::right << std::setfill('.') << ss.str() << std::endl;
381 20 : }
382 20 : }
383 30 : int SubFinalMessage(int failed)
384 : {
385 30 : if (amrex::ParallelDescriptor::IOProcessor())
386 : {
387 : winsize w;
388 30 : ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
389 30 : std::stringstream ss;
390 30 : std::cout << std::left << " └ ";
391 :
392 30 : if (!failed)
393 30 : std::cout << Color::FG::Green << Color::Bold << failed << " tests failed" << Color::Reset << std::endl;
394 : else
395 0 : std::cout << Color::FG::Red << Color::Bold << failed << " tests failed" << Color::Reset << std::endl;
396 30 : }
397 30 : return failed;
398 : }
399 :
400 : }
401 :
402 62 : void AverageCellcenterToNode(amrex::MultiFab& node_mf, const int &dcomp, const amrex::MultiFab &cell_mf, const int &scomp, const int &ncomp/*, const int ngrow=0*/)
403 : {
404 434 : Util::Assert(INFO,TEST(dcomp + ncomp <= node_mf.nComp()));
405 434 : Util::Assert(INFO,TEST(scomp + ncomp <= cell_mf.nComp()));
406 : //Util::Assert(INFO,TEST(cell_mf.boxArray() == node_mf.boxArray()));
407 434 : Util::Assert(INFO,TEST(cell_mf.DistributionMap() == cell_mf.DistributionMap()));
408 434 : Util::Assert(INFO,TEST(cell_mf.nGrow() > 0));
409 269 : for (amrex::MFIter mfi(node_mf,amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
410 : {
411 207 : amrex::Box bx = mfi.nodaltilebox();
412 207 : amrex::Array4<Set::Scalar> const& node = node_mf.array(mfi);
413 207 : amrex::Array4<const Set::Scalar> const& cell = cell_mf.array(mfi);
414 414 : for (int n = 0; n < ncomp; n++)
415 207 : amrex::ParallelFor (bx,[=] AMREX_GPU_DEVICE(int i, int j, int k) {
416 212934 : node(i,j,k,dcomp+n) = Numeric::Interpolate::CellToNodeAverage(cell,i,j,k,scomp+n);
417 106467 : });
418 62 : }
419 62 : }
420 :
421 :
422 : }
|