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