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