Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 :
4 : // This library is free software; you can redistribute it and/or
5 : // modify it under the terms of the GNU Lesser General Public
6 : // License as published by the Free Software Foundation; either
7 : // version 2.1 of the License, or (at your option) any later version.
8 :
9 : // This library is distributed in the hope that it will be useful,
10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : // Lesser General Public License for more details.
13 :
14 : // You should have received a copy of the GNU Lesser General Public
15 : // License along with this library; if not, write to the Free Software
16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 :
18 :
19 : // Local includes
20 : #include "libmesh/libmesh.h"
21 :
22 : // libMesh includes
23 : #include "libmesh/getpot.h"
24 : #include "libmesh/reference_counter.h"
25 : #include "libmesh/libmesh_singleton.h"
26 : #include "libmesh/remote_elem.h"
27 : #include "libmesh/threads.h"
28 : #include "libmesh/parallel_only.h"
29 : #include "libmesh/print_trace.h"
30 : #include "libmesh/enum_solver_package.h"
31 : #include "libmesh/perf_log.h"
32 :
33 : // TIMPI includes
34 : #include "timpi/communicator.h"
35 : #include "timpi/timpi_init.h"
36 :
37 : // C/C++ includes
38 : #include <cstdlib>
39 : #include <iostream>
40 : #include <fstream>
41 :
42 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
43 : #include <exception>
44 : #endif
45 :
46 : #ifdef LIBMESH_HAVE_OPENMP
47 : #include <omp.h>
48 : #endif
49 :
50 : #include "stdlib.h" // C, not C++ - we need setenv() from POSIX
51 : #include "signal.h"
52 :
53 :
54 : // floating-point exceptions
55 : #ifdef LIBMESH_HAVE_FENV_H
56 : # include <fenv.h>
57 : #endif
58 : #ifdef LIBMESH_HAVE_XMMINTRIN_H
59 : # include <xmmintrin.h>
60 : #endif
61 :
62 :
63 : #if defined(LIBMESH_HAVE_MPI)
64 : # include "libmesh/ignore_warnings.h"
65 : # include <mpi.h>
66 : # include "libmesh/restore_warnings.h"
67 : #endif // #if defined(LIBMESH_HAVE_MPI)
68 :
69 : #if defined(LIBMESH_HAVE_PETSC)
70 : # include "libmesh/petsc_solver_exception.h"
71 : # include <petsc.h>
72 : # include <petscerror.h>
73 : # include "libmesh/petscdmlibmesh.h"
74 : # if defined(LIBMESH_HAVE_SLEPC)
75 : // Ignore unused variable warnings from SLEPc
76 : # include "libmesh/ignore_warnings.h"
77 : # include "libmesh/slepc_macro.h"
78 : # include <slepc.h>
79 : # include "libmesh/restore_warnings.h"
80 : # endif // #if defined(LIBMESH_HAVE_SLEPC)
81 : #endif // #if defined(LIBMESH_HAVE_PETSC)
82 :
83 : #ifdef LIBMESH_HAVE_NETGEN
84 : // We need the nglib namespace, because it's used everywhere in nglib
85 : // and we don't get binary compatibility without it.
86 : //
87 : // We need the nglib namespace *here*, because somehow nobody ever
88 : // figured out to just put it in nglib.h?
89 : namespace nglib {
90 : #include "netgen/nglib/nglib.h"
91 : }
92 : #endif
93 :
94 : // If we're using MPI and VTK has been detected, we need to do some
95 : // MPI initialize/finalize stuff for VTK.
96 : #if defined(LIBMESH_HAVE_MPI) && defined(LIBMESH_HAVE_VTK)
97 : #include "libmesh/ignore_warnings.h"
98 : # include "vtkMPIController.h"
99 : #include "libmesh/restore_warnings.h"
100 : #endif
101 :
102 : #include <mutex>
103 :
104 : // --------------------------------------------------------
105 : // Local anonymous namespace to hold miscellaneous bits
106 : namespace {
107 :
108 : std::unique_ptr<GetPot> command_line;
109 :
110 : std::set<std::string> command_line_name_set;
111 :
112 : std::unique_ptr<std::ofstream> _ofstream;
113 : // If std::cout and std::cerr are redirected, we need to
114 : // be a little careful and save the original streambuf objects,
115 : // replacing them in the destructor before program termination.
116 : std::streambuf * out_buf (nullptr);
117 : std::streambuf * err_buf (nullptr);
118 :
119 : std::unique_ptr<libMesh::Threads::task_scheduler_init> task_scheduler;
120 : #if defined(LIBMESH_HAVE_PETSC)
121 : bool libmesh_initialized_petsc = false;
122 : #endif
123 : #if defined(LIBMESH_HAVE_SLEPC)
124 : bool libmesh_initialized_slepc = false;
125 : #endif
126 :
127 :
128 :
129 : /**
130 : * Floating point exception handler -- courtesy of Cody Permann & MOOSE team
131 : */
132 : #if LIBMESH_HAVE_DECL_SIGACTION
133 0 : void libmesh_handleFPE(int /*signo*/, siginfo_t * info, void * /*context*/)
134 : {
135 0 : libMesh::err << std::endl;
136 0 : libMesh::err << "Floating point exception signaled (";
137 0 : switch (info->si_code)
138 : {
139 0 : case FPE_INTDIV: libMesh::err << "integer divide by zero"; break;
140 0 : case FPE_INTOVF: libMesh::err << "integer overflow"; break;
141 0 : case FPE_FLTDIV: libMesh::err << "floating point divide by zero"; break;
142 0 : case FPE_FLTOVF: libMesh::err << "floating point overflow"; break;
143 0 : case FPE_FLTUND: libMesh::err << "floating point underflow"; break;
144 0 : case FPE_FLTRES: libMesh::err << "floating point inexact result"; break;
145 0 : case FPE_FLTINV: libMesh::err << "invalid floating point operation"; break;
146 0 : case FPE_FLTSUB: libMesh::err << "subscript out of range"; break;
147 0 : default: libMesh::err << "unrecognized"; break;
148 : }
149 0 : libMesh::err << ")!" << std::endl;
150 :
151 0 : libmesh_error_msg("\nTo track this down, compile in debug mode, then in gdb do:\n" \
152 : << " break libmesh_handleFPE\n" \
153 : << " run ...\n" \
154 : << " bt");
155 : }
156 :
157 :
158 0 : void libmesh_handleSEGV(int /*signo*/, siginfo_t * info, void * /*context*/)
159 : {
160 0 : libMesh::err << std::endl;
161 0 : libMesh::err << "Segmentation fault exception signaled (";
162 0 : switch (info->si_code)
163 : {
164 0 : case SEGV_MAPERR: libMesh::err << "Address not mapped"; break;
165 0 : case SEGV_ACCERR: libMesh::err << "Invalid permissions"; break;
166 0 : default: libMesh::err << "unrecognized"; break;
167 : }
168 0 : libMesh::err << ")!" << std::endl;
169 :
170 0 : libmesh_error_msg("\nTo track this down, compile in debug mode, then in gdb do:\n" \
171 : << " break libmesh_handleSEGV\n" \
172 : << " run ...\n" \
173 : << " bt");
174 : }
175 : #endif
176 : }
177 :
178 :
179 :
180 : #ifdef LIBMESH_HAVE_MPI
181 0 : void libMesh_MPI_Handler (MPI_Comm *, int *, ...)
182 : {
183 0 : libmesh_not_implemented();
184 : }
185 : #endif
186 :
187 :
188 : namespace libMesh
189 : {
190 :
191 : /**
192 : * Namespaces don't provide private data,
193 : * so let's take the data we would like
194 : * private and put it in an obnoxious
195 : * namespace. At least that way it is a
196 : * pain to use, thus discouraging errors.
197 : */
198 : namespace libMeshPrivateData {
199 :
200 : /**
201 : * Flag that tells if \p init() has been called.
202 : */
203 : extern bool _is_initialized;
204 :
205 : /**
206 : * The default solver package to use.
207 : */
208 : extern SolverPackage _solver_package;
209 : }
210 :
211 :
212 : // ------------------------------------------------------------
213 : // libMesh data initialization
214 : #ifdef LIBMESH_HAVE_MPI
215 : MPI_Comm GLOBAL_COMM_WORLD = MPI_COMM_NULL;
216 : #else
217 : int GLOBAL_COMM_WORLD = 0;
218 : #endif
219 :
220 : OStreamProxy out(std::cout);
221 : OStreamProxy err(std::cerr);
222 :
223 : bool warned_about_auto_ptr(false);
224 :
225 : PerfLog perflog ("libMesh",
226 : #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING
227 : true
228 : #else
229 : false
230 : #endif
231 : );
232 :
233 :
234 : #ifdef LIBMESH_USE_COMPLEX_NUMBERS
235 : const Number imaginary (0., 1.);
236 : // const Number zero (0., 0.);
237 : #else
238 : // const Number zero = 0.;
239 : #endif
240 :
241 : // This is now a static constant in the header; no reason not to let
242 : // the compiler inline it.
243 :
244 : // const unsigned int invalid_uint = static_cast<unsigned int>(-1);
245 :
246 :
247 :
248 : // ------------------------------------------------------------
249 : // libMesh::libMeshPrivateData data initialization
250 : #ifdef LIBMESH_HAVE_MPI
251 : MPI_Errhandler libmesh_errhandler;
252 :
253 : processor_id_type libMesh::libMeshPrivateData::_n_processors = 1;
254 : processor_id_type libMesh::libMeshPrivateData::_processor_id = 0;
255 : #endif
256 : int libMesh::libMeshPrivateData::_n_threads = 1; /* Threads::task_scheduler_init::automatic; */
257 : bool libMesh::libMeshPrivateData::_is_initialized = false;
258 : SolverPackage libMesh::libMeshPrivateData::_solver_package =
259 : #if defined(LIBMESH_HAVE_PETSC) // PETSc is the default
260 : PETSC_SOLVERS;
261 : #elif defined(LIBMESH_TRILINOS_HAVE_AZTECOO) // Use Trilinos if PETSc isn't there
262 : TRILINOS_SOLVERS;
263 : #elif defined(LIBMESH_HAVE_EIGEN) // Use Eigen if neither are there
264 : EIGEN_SOLVERS;
265 : #elif defined(LIBMESH_HAVE_LASPACK) // Use LASPACK as a last resort
266 : LASPACK_SOLVERS;
267 : #else // No valid linear solver package at compile time
268 : INVALID_SOLVER_PACKAGE;
269 : #endif
270 :
271 :
272 :
273 : // ------------------------------------------------------------
274 : // libMesh functions
275 :
276 76122 : bool initialized()
277 : {
278 76122 : return libMeshPrivateData::_is_initialized;
279 : }
280 :
281 :
282 :
283 26802 : bool closed()
284 : {
285 26802 : return !libMeshPrivateData::_is_initialized;
286 : }
287 :
288 :
289 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
290 : std::terminate_handler old_terminate_handler;
291 : #endif
292 :
293 0 : void libmesh_terminate_handler()
294 : {
295 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
296 : // If we have an active exception, it may have an error message that
297 : // we should print.
298 0 : libMesh::err << "libMesh terminating";
299 0 : std::exception_ptr ex = std::current_exception();
300 0 : if (ex)
301 : {
302 : try
303 : {
304 0 : std::rethrow_exception(ex);
305 : }
306 0 : catch (const std::exception & std_ex)
307 : {
308 0 : libMesh::err << ":\n" << std_ex.what();
309 0 : }
310 : }
311 0 : libMesh::err << std::endl;
312 : #endif
313 :
314 : // If this got called then we're probably crashing; let's print a
315 : // stack trace. The trace files that are ultimately written depend on:
316 : // 1.) Who throws the exception.
317 : // 2.) Whether the C++ runtime unwinds the stack before the
318 : // terminate_handler is called (this is implementation defined).
319 : //
320 : // The various cases are summarized in the table below:
321 : //
322 : // | libmesh exception | other exception
323 : // -------------------------------------
324 : // stack unwinds | A | B
325 : // stack does not unwind | C | D
326 : //
327 : // Case A: There will be two stack traces in the file: one "useful"
328 : // one, and one nearly empty one due to stack unwinding.
329 : // Case B: You will get one nearly empty stack trace (not great, Bob!)
330 : // Case C: You will get two nearly identical stack traces, ignore one of them.
331 : // Case D: You will get one useful stack trace.
332 : //
333 : // Cases A and B (where the stack unwinds when an exception leaves
334 : // main) appear to be non-existent in practice. I don't have a
335 : // definitive list, but the stack does not unwind for GCC on either
336 : // Mac or Linux. I think there's good reasons for this behavior too:
337 : // it's much easier to get a stack trace when the stack doesn't
338 : // unwind, for example.
339 0 : libMesh::write_traceout();
340 :
341 : // We may care about performance data pre-crash; it would be sad to
342 : // throw that away.
343 0 : libMesh::perflog.print_log();
344 0 : libMesh::perflog.clear();
345 :
346 : // If we have MPI and it has been initialized, we need to be sure
347 : // and call MPI_Abort instead of std::abort, so that the parallel
348 : // job can die nicely.
349 : #if defined(LIBMESH_HAVE_MPI)
350 : int mpi_initialized;
351 0 : MPI_Initialized (&mpi_initialized);
352 :
353 0 : if (mpi_initialized)
354 0 : MPI_Abort(libMesh::GLOBAL_COMM_WORLD, 1);
355 : #endif
356 :
357 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
358 : // The system terminate_handler may do useful things, or the user
359 : // may have set their own terminate handler that we want to call.
360 0 : old_terminate_handler();
361 : #endif
362 :
363 : // The last attempt to die if nothing else has killed us
364 0 : std::abort();
365 : }
366 :
367 :
368 :
369 16381 : LibMeshInit::LibMeshInit (int argc, const char * const * argv,
370 16381 : TIMPI::communicator COMM_WORLD_IN, int n_threads)
371 : {
372 : // should _not_ be initialized already.
373 462 : libmesh_assert (!libMesh::initialized());
374 :
375 : // Build a command-line parser.
376 31838 : command_line = std::make_unique<GetPot>(argc, argv);
377 :
378 : // Disable performance logging upon request
379 : {
380 32300 : if (libMesh::on_command_line ("--disable-perflog"))
381 0 : libMesh::perflog.disable_logging();
382 : }
383 :
384 46831 : auto check_empty_command_line_value = [](auto & cl, const std::string & option) {
385 46831 : libmesh_error_msg_if(cl.search(option),
386 : "Detected option " << option << " with no value. Did you forget '='?");
387 46831 : };
388 :
389 : // Build a task scheduler
390 : {
391 : // Get the requested number of threads, defaults to 1 to avoid MPI and
392 : // multithreading competition. If you would like to use MPI and multithreading
393 : // at the same time then (n_mpi_processes_per_node)x(n_threads) should be the
394 : // number of processing cores per node.
395 16843 : std::vector<std::string> n_threads_opt(2);
396 924 : n_threads_opt[0] = "--n_threads";
397 924 : n_threads_opt[1] = "--n-threads";
398 16381 : libMesh::libMeshPrivateData::_n_threads =
399 16381 : libMesh::command_line_value(n_threads_opt, n_threads);
400 :
401 16381 : if (libMesh::libMeshPrivateData::_n_threads == -1)
402 : {
403 45675 : for (auto & option : n_threads_opt)
404 30450 : check_empty_command_line_value(*command_line, option);
405 :
406 15225 : libMesh::libMeshPrivateData::_n_threads = 1;
407 : }
408 :
409 : // If there's no threading model active, force _n_threads==1
410 : #if !LIBMESH_USING_THREADS
411 : if (libMesh::libMeshPrivateData::_n_threads != 1)
412 : {
413 : libMesh::libMeshPrivateData::_n_threads = 1;
414 : libmesh_warning("Warning: You requested --n-threads>1 but no threading model is active!\n"
415 : << "Forcing --n-threads==1 instead!");
416 : }
417 : #endif
418 :
419 : // Set the number of OpenMP threads to the same as the number of threads libMesh is going to use
420 : #ifdef LIBMESH_HAVE_OPENMP
421 16381 : omp_set_num_threads(libMesh::libMeshPrivateData::_n_threads);
422 : #endif
423 :
424 15919 : task_scheduler = std::make_unique<Threads::task_scheduler_init>(libMesh::n_threads());
425 15457 : }
426 :
427 : // Construct singletons who may be at risk of the
428 : // "static initialization order fiasco"
429 16381 : Singleton::setup();
430 :
431 : // Make sure the construction worked
432 462 : libmesh_assert(remote_elem);
433 :
434 16381 : const bool using_threads = libMesh::n_threads() > 1;
435 462 : const bool handle_mpi_errors = false; // libMesh does this
436 :
437 : #if defined(LIBMESH_HAVE_MPI)
438 :
439 : // Allow the user to bypass MPI initialization
440 32300 : if (!libMesh::on_command_line ("--disable-mpi"))
441 : {
442 16381 : int mpi_thread_request = using_threads;
443 33224 : const auto mpi_thread_type = libMesh::command_line_value("--mpi-thread-type", std::string(""));
444 16381 : if (mpi_thread_type.empty())
445 : {
446 32300 : check_empty_command_line_value(*command_line, "--mpi-thread-type");
447 : #if defined(PETSC_HAVE_STRUMPACK) && defined(PETSC_HAVE_SLATE)
448 : // For GPU computations, the solver strumpack uses slate which always requests
449 : // MPI_THREAD_MULTIPLE. The solution here is not perfect because the run may never be
450 : // using strumpack, but we believe it's better to force the MPI library to use locks
451 : // whenever it accesses the message queue, that is, when processing any sends and receive,
452 : // than it is to require users to pre-announce/signal what solvers they are using through
453 : // --mpi-thread-type
454 : mpi_thread_request = 3;
455 : #endif
456 : }
457 : else
458 : {
459 0 : if (mpi_thread_type == "single")
460 : {
461 0 : if (using_threads)
462 0 : libmesh_error_msg("We are using threads, so we require more mpi thread support "
463 : "than '--mpi-thread-type=single'");
464 0 : mpi_thread_request = 0;
465 : }
466 0 : else if (mpi_thread_type == "funneled")
467 0 : mpi_thread_request = 1;
468 0 : else if (mpi_thread_type == "serialized")
469 0 : mpi_thread_request = 2;
470 0 : else if (mpi_thread_type == "multiple")
471 0 : mpi_thread_request = 3;
472 : else
473 0 : libmesh_error_msg(
474 : "Unsupported mpi thread type '"
475 : << mpi_thread_type
476 : << "'. Allowed options are 'single', 'funneled', 'serialized', and 'multiple'");
477 : }
478 :
479 16381 : this->_timpi_init =
480 : new TIMPI::TIMPIInit(argc, argv, mpi_thread_request,
481 16381 : handle_mpi_errors, COMM_WORLD_IN);
482 16381 : _comm = new Parallel::Communicator(this->_timpi_init->comm().get());
483 :
484 : const std::string timpi_sync =
485 33224 : libMesh::command_line_value("--timpi-sync", std::string("nbx"));
486 16381 : _comm->sync_type(timpi_sync);
487 :
488 16381 : libMesh::GLOBAL_COMM_WORLD = COMM_WORLD_IN;
489 :
490 : //MPI_Comm_set_name not supported in at least SGI MPT's MPI implementation
491 : //MPI_Comm_set_name (libMesh::COMM_WORLD, "libMesh::COMM_WORLD");
492 :
493 16381 : libMeshPrivateData::_processor_id =
494 924 : cast_int<processor_id_type>(this->comm().rank());
495 16381 : libMeshPrivateData::_n_processors =
496 924 : cast_int<processor_id_type>(this->comm().size());
497 :
498 : // Set up an MPI error handler if requested. This helps us get
499 : // into a debugger with a proper stack when an MPI error occurs.
500 32300 : if (libMesh::on_command_line ("--handle-mpi-errors"))
501 : {
502 0 : timpi_call_mpi
503 : (MPI_Comm_create_errhandler(libMesh_MPI_Handler, &libmesh_errhandler));
504 0 : timpi_call_mpi
505 : (MPI_Comm_set_errhandler(libMesh::GLOBAL_COMM_WORLD, libmesh_errhandler));
506 0 : timpi_call_mpi
507 : (MPI_Comm_set_errhandler(MPI_COMM_WORLD, libmesh_errhandler));
508 : }
509 : }
510 :
511 : // Could we have gotten bad values from the above calls?
512 462 : libmesh_assert_greater (libMeshPrivateData::_n_processors, 0);
513 :
514 : // The cast_int already tested _processor_id>=0
515 : // libmesh_assert_greater_equal (libMeshPrivateData::_processor_id, 0);
516 :
517 : // Let's be sure we properly initialize on every processor at once:
518 462 : libmesh_parallel_only(this->comm());
519 :
520 : #else
521 : libmesh_ignore(COMM_WORLD_IN);
522 : this->_timpi_init =
523 : new TIMPI::TIMPIInit(argc, argv, using_threads,
524 : handle_mpi_errors);
525 : _comm = new Parallel::Communicator(this->_timpi_init->comm().get());
526 : #endif
527 :
528 : #if defined(LIBMESH_HAVE_PETSC)
529 :
530 : // Allow the user to bypass PETSc initialization
531 32340 : if (!libMesh::on_command_line ("--disable-petsc")
532 :
533 : #if defined(LIBMESH_HAVE_MPI)
534 : // If the user bypassed MPI, we'd better be safe and assume that
535 : // PETSc was built to require it; otherwise PETSc initialization
536 : // dies.
537 32340 : && !libMesh::on_command_line ("--disable-mpi")
538 : #endif
539 : )
540 : {
541 : #ifdef LIBMESH_HAVE_MPI
542 16170 : PETSC_COMM_WORLD = libMesh::GLOBAL_COMM_WORLD;
543 : #else
544 : // PETSc --with-mpi=0 doesn't like our default "communicator" 0
545 : this->_comm->get() = PETSC_COMM_SELF;
546 : #endif
547 :
548 : // Check whether the calling program has already initialized
549 : // PETSc, and avoid duplicate Initialize/Finalize
550 : PetscBool petsc_already_initialized;
551 16170 : LibmeshPetscCallA(libMesh::GLOBAL_COMM_WORLD, PetscInitialized(&petsc_already_initialized));
552 16170 : if (petsc_already_initialized != PETSC_TRUE)
553 16170 : libmesh_initialized_petsc = true;
554 : # if defined(LIBMESH_HAVE_SLEPC)
555 :
556 : // If SLEPc allows us to check whether the calling program
557 : // has already initialized it, we do that, and avoid
558 : // duplicate Initialize/Finalize.
559 : // We assume that SLEPc will handle PETSc appropriately,
560 : // which it does in the versions we've checked.
561 16170 : if (!SlepcInitializeCalled)
562 : {
563 16170 : LibmeshPetscCallA(libMesh::GLOBAL_COMM_WORLD, SlepcInitialize (&argc, const_cast<char ***>(&argv), nullptr, nullptr));
564 16170 : libmesh_initialized_slepc = true;
565 : }
566 : # else
567 : if (libmesh_initialized_petsc)
568 : LibmeshPetscCallA(libMesh::GLOBAL_COMM_WORLD, PetscInitialize (&argc, const_cast<char ***>(&argv), nullptr, nullptr));
569 : # endif
570 : // Register the reference implementation of DMlibMesh
571 16170 : LibmeshPetscCallA(libMesh::GLOBAL_COMM_WORLD, DMRegister(DMLIBMESH, DMCreate_libMesh));
572 : }
573 : #endif
574 :
575 : #ifdef LIBMESH_HAVE_NETGEN
576 16381 : nglib::Ng_Init();
577 : #endif
578 :
579 : #if defined(LIBMESH_HAVE_MPI) && defined(LIBMESH_HAVE_VTK)
580 : // Do MPI initialization for VTK.
581 : _vtk_mpi_controller = vtkMPIController::New();
582 : _vtk_mpi_controller->Initialize(&argc, const_cast<char ***>(&argv), /*initialized_externally=*/1);
583 : _vtk_mpi_controller->SetGlobalController(_vtk_mpi_controller);
584 : #endif
585 :
586 : // Re-parse the command-line arguments. Note that PETSc and MPI
587 : // initialization above may have removed command line arguments
588 : // that are not relevant to this application in the above calls.
589 : // We don't want a false-positive by detecting those arguments.
590 : //
591 : // Note: this seems overly paranoid/like it should be unnecessary,
592 : // plus we were doing it wrong for many years and not clearing the
593 : // existing GetPot object before re-parsing the command line, so all
594 : // the command line arguments appeared twice in the GetPot object...
595 31838 : command_line = std::make_unique<GetPot>(argc, argv);
596 :
597 : // The following line is an optimization when simultaneous
598 : // C and C++ style access to output streams is not required.
599 : // The amount of benefit which occurs is probably implementation
600 : // defined, and may be nothing. On the other hand, I have seen
601 : // some IO tests where IO performance improves by a factor of two.
602 32300 : if (!libMesh::on_command_line ("--sync-with-stdio"))
603 16381 : std::ios::sync_with_stdio(false);
604 :
605 : // Honor the --separate-libmeshout command-line option.
606 : // When this is specified, the library uses an independent ostream
607 : // for libMesh::out/libMesh::err messages, and
608 : // std::cout and std::cerr are untouched by any other options
609 32300 : if (libMesh::on_command_line ("--separate-libmeshout"))
610 : {
611 : // Redirect. We'll share streambufs with cout/cerr for now, but
612 : // presumably anyone using this option will want to replace the
613 : // bufs later.
614 0 : std::ostream * newout = new std::ostream(std::cout.rdbuf());
615 0 : libMesh::out = *newout;
616 0 : std::ostream * newerr = new std::ostream(std::cerr.rdbuf());
617 0 : libMesh::err = *newerr;
618 : }
619 :
620 : // Process command line arguments for redirecting stdout/stderr.
621 : bool
622 16381 : cmdline_has_redirect_stdout = libMesh::on_command_line ("--redirect-stdout"),
623 16381 : cmdline_has_redirect_output = libMesh::on_command_line ("--redirect-output");
624 :
625 : // The --redirect-stdout command-line option has been deprecated in
626 : // favor of "--redirect-output basename".
627 : if (cmdline_has_redirect_stdout)
628 : libmesh_warning("The --redirect-stdout command line option has been deprecated. "
629 : "Use '--redirect-output basename' instead.");
630 :
631 : // Honor the "--redirect-stdout" and "--redirect-output basename"
632 : // command-line options. When one of these is specified, each
633 : // processor sends libMesh::out/libMesh::err messages to
634 : // stdout.processor.#### (default) or basename.processor.####.
635 16381 : if (cmdline_has_redirect_stdout || cmdline_has_redirect_output)
636 : {
637 0 : std::string basename = "stdout";
638 :
639 : // Look for following argument if using new API
640 0 : if (cmdline_has_redirect_output)
641 : {
642 : // Set the cursor to the correct location in the list of command line arguments.
643 0 : command_line->search(1, "--redirect-output");
644 :
645 : // Get the next option on the command line as a string.
646 0 : std::string next_string = "";
647 0 : next_string = command_line->next(next_string);
648 :
649 : // If the next string starts with a dash, we assume it's
650 : // another flag and not a file basename requested by the
651 : // user.
652 0 : if (next_string.size() > 0 && next_string.find_first_of("-") != 0)
653 0 : basename = next_string;
654 : }
655 :
656 0 : std::ostringstream filename;
657 0 : filename << basename << ".processor." << libMesh::global_processor_id();
658 0 : _ofstream = std::make_unique<std::ofstream>(filename.str().c_str());
659 :
660 : // Redirect, saving the original streambufs!
661 0 : out_buf = libMesh::out.rdbuf (_ofstream->rdbuf());
662 0 : err_buf = libMesh::err.rdbuf (_ofstream->rdbuf());
663 0 : }
664 :
665 : // redirect libMesh::out to nothing on all
666 : // other processors unless explicitly told
667 : // not to via the --keep-cout command-line argument.
668 32300 : if (!libMesh::on_command_line ("--keep-cout"))
669 16381 : if (libMesh::global_processor_id() != 0)
670 13629 : libMesh::out.rdbuf (nullptr);
671 :
672 : // Similarly, the user can request to drop cerr on all non-0 ranks.
673 : // By default, errors are printed on all ranks, but this can lead to
674 : // interleaved/unpredictable outputs when doing parallel regression
675 : // testing, which this option is designed to support.
676 32300 : if (libMesh::on_command_line ("--drop-cerr"))
677 0 : if (libMesh::global_processor_id() != 0)
678 0 : libMesh::err.rdbuf (nullptr);
679 :
680 : // Check command line to override printing
681 : // of reference count information.
682 32300 : if (libMesh::on_command_line("--disable-refcount-printing"))
683 0 : ReferenceCounter::disable_print_counter_info();
684 :
685 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
686 : // Set our terminate handler to write stack traces in the event of a
687 : // crash
688 16381 : old_terminate_handler = std::set_terminate(libmesh_terminate_handler);
689 : #endif
690 :
691 :
692 32300 : if (libMesh::on_command_line("--enable-fpe"))
693 0 : libMesh::enableFPE(true);
694 :
695 32300 : if (libMesh::on_command_line("--enable-segv"))
696 0 : libMesh::enableSEGV(true);
697 :
698 : #if defined(LIBMESH_HAVE_HDF5) && !defined(_MSC_VER)
699 : // We may be running with ExodusII configured not to use HDF5 (in
700 : // which case user code which wants to lock files has to do flock()
701 : // itself) or with ExodusII configured to use HDF5 (which will
702 : // helpfully try to get an exclusive flock() itself, and then scream
703 : // and die if user code has already locked the file. To get
704 : // consistent behavior, we need to disable file locking. The only
705 : // reliable way I can see to do this is via an HDF5 environment
706 : // variable.
707 : //
708 : // If the user set this environment variable then we'll trust that
709 : // they know what they're doing. If not then we'll set FALSE,
710 : // because that's a better default for us than the unset default.
711 462 : setenv("HDF5_USE_FILE_LOCKING", "FALSE", /*overwrite=false*/0);
712 : #endif // LIBMESH_HAVE_HDF5
713 :
714 : // The library is now ready for use
715 16381 : libMeshPrivateData::_is_initialized = true;
716 :
717 :
718 : // Make sure these work. Library methods
719 : // depend on these being implemented properly,
720 : // so this is a good time to test them!
721 462 : libmesh_assert (libMesh::initialized());
722 462 : libmesh_assert (!libMesh::closed());
723 16381 : }
724 :
725 :
726 :
727 17305 : LibMeshInit::~LibMeshInit()
728 : {
729 : // Every processor had better be ready to exit at the same time.
730 : // This would be a libmesh_parallel_only() function, except that
731 : // libmesh_parallel_only() uses libmesh_assert() which throws an
732 : // exception() which causes compilers to scream about exceptions
733 : // inside destructors.
734 :
735 : // Even if we're not doing parallel_only debugging, we don't want
736 : // one processor to try to exit until all others are done working.
737 16381 : this->comm().barrier();
738 :
739 : // We can't delete, finalize, etc. more than once without
740 : // reinitializing in between
741 462 : libmesh_exceptionless_assert(!libMesh::closed());
742 :
743 : // Delete reference counted singleton(s)
744 16381 : Singleton::cleanup();
745 :
746 : // Clear the thread task manager we started
747 462 : task_scheduler.reset();
748 :
749 : // Force the \p ReferenceCounter to print
750 : // its reference count information. This allows
751 : // us to find memory leaks. By default the
752 : // \p ReferenceCounter only prints its information
753 : // when the last created object has been destroyed.
754 : // That does no good if we are leaking memory!
755 16381 : ReferenceCounter::print_info ();
756 :
757 :
758 : // Print an informative message if we detect a memory leak
759 16381 : if (ReferenceCounter::n_objects() != 0)
760 : {
761 0 : libMesh::err << "Memory leak detected!"
762 0 : << std::endl;
763 :
764 : #if !defined(LIBMESH_ENABLE_REFERENCE_COUNTING) || defined(NDEBUG)
765 :
766 : libMesh::err << "Compile in DEBUG mode with --enable-reference-counting"
767 : << std::endl
768 : << "for more information"
769 : << std::endl;
770 : #endif
771 :
772 : }
773 :
774 : // print the perflog to individual processor's file.
775 16381 : libMesh::perflog.print_log();
776 :
777 : // Now clear the logging object, we don't want it to print
778 : // a second time during the PerfLog destructor.
779 16381 : libMesh::perflog.clear();
780 :
781 : // Reconnect the output streams
782 : // (don't do this, or we will get messages from objects
783 : // that go out of scope after the following return)
784 : //std::cout.rdbuf(std::cerr.rdbuf());
785 :
786 :
787 : // Set the initialized() flag to false
788 16381 : libMeshPrivateData::_is_initialized = false;
789 :
790 33686 : if (libMesh::on_command_line ("--redirect-stdout") ||
791 33224 : libMesh::on_command_line ("--redirect-output"))
792 : {
793 : // If stdout/stderr were redirected to files, reset them now.
794 0 : libMesh::out.rdbuf (out_buf);
795 0 : libMesh::err.rdbuf (err_buf);
796 : }
797 :
798 : // If we built our own output streams, we want to clean them up.
799 32300 : if (libMesh::on_command_line ("--separate-libmeshout"))
800 : {
801 0 : delete libMesh::out.get();
802 0 : delete libMesh::err.get();
803 :
804 0 : libMesh::out.reset(std::cout);
805 0 : libMesh::err.reset(std::cerr);
806 : }
807 :
808 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
809 : // Reset the old terminate handler; maybe the user code wants to
810 : // keep doing C++ stuff after closing libMesh stuff.
811 16381 : std::set_terminate(old_terminate_handler);
812 : #endif
813 :
814 : #ifdef LIBMESH_HAVE_NETGEN
815 16381 : nglib::Ng_Exit();
816 : #endif
817 :
818 32300 : if (libMesh::on_command_line("--enable-fpe"))
819 0 : libMesh::enableFPE(false);
820 :
821 : #if defined(LIBMESH_HAVE_PETSC)
822 : // Let PETSc know about all the command line objects that we
823 : // consumed without asking them, so we don't get unused option
824 : // warnings about those.
825 17094 : std::vector<std::string> cli_names = command_line_names();
826 505204 : for (const auto & name : cli_names)
827 489034 : if (!name.empty() && name[0] == '-')
828 : {
829 : // Newer PETSc can give me a double-free I'm having trouble
830 : // replicating; let's protect against trying to clear
831 : // already-used values
832 476434 : PetscBool used = PETSC_FALSE;
833 476434 : auto ierr = PetscOptionsUsed(NULL, name.c_str(), &used);
834 476434 : CHKERRABORT(libMesh::GLOBAL_COMM_WORLD, ierr);
835 476434 : if (used == PETSC_FALSE)
836 : {
837 476434 : ierr = PetscOptionsClearValue(NULL, name.c_str());
838 476434 : CHKERRABORT(libMesh::GLOBAL_COMM_WORLD, ierr);
839 : }
840 : }
841 :
842 : // Allow the user to bypass PETSc finalization
843 32340 : if (!libMesh::on_command_line ("--disable-petsc")
844 : #if defined(LIBMESH_HAVE_MPI)
845 32340 : && !libMesh::on_command_line ("--disable-mpi")
846 : #endif
847 : )
848 : {
849 462 : PetscErrorCode ierr = LIBMESH_PETSC_SUCCESS;
850 : # if defined(LIBMESH_HAVE_SLEPC)
851 16170 : if (libmesh_initialized_slepc)
852 16170 : ierr = SlepcFinalize();
853 : # else
854 : if (libmesh_initialized_petsc)
855 : ierr = PetscFinalize();
856 : # endif
857 16170 : CHKERRABORT(libMesh::GLOBAL_COMM_WORLD, ierr);
858 : }
859 : #endif
860 :
861 : #if defined(LIBMESH_HAVE_MPI) && defined(LIBMESH_HAVE_VTK)
862 : _vtk_mpi_controller->Finalize(/*finalized_externally=*/1);
863 : _vtk_mpi_controller->Delete();
864 : #endif
865 :
866 32300 : delete this->_comm;
867 :
868 : #if defined(LIBMESH_HAVE_MPI)
869 : // Allow the user to bypass MPI finalization
870 32300 : if (!libMesh::on_command_line ("--disable-mpi"))
871 : {
872 16381 : delete this->_timpi_init;
873 : }
874 : #else
875 : delete this->_timpi_init;
876 : #endif
877 16381 : }
878 :
879 :
880 :
881 : /**
882 : * Toggle floating point exceptions -- courtesy of Cody Permann & MOOSE team
883 : */
884 0 : void enableFPE(bool on)
885 : {
886 : #if !defined(LIBMESH_HAVE_FEENABLEEXCEPT) && defined(LIBMESH_HAVE_XMMINTRIN_H)
887 : static int flags = 0;
888 : #endif
889 :
890 0 : if (on)
891 : {
892 : #ifdef LIBMESH_HAVE_FEENABLEEXCEPT
893 0 : feenableexcept(FE_DIVBYZERO | FE_INVALID);
894 : #elif LIBMESH_HAVE_XMMINTRIN_H
895 : flags = _MM_GET_EXCEPTION_MASK(); // store the flags
896 : _MM_SET_EXCEPTION_MASK(flags & ~_MM_MASK_INVALID);
897 : #endif
898 :
899 : #if LIBMESH_HAVE_DECL_SIGACTION
900 : struct sigaction new_action, old_action;
901 :
902 : // Set up the structure to specify the new action.
903 0 : new_action.sa_sigaction = libmesh_handleFPE;
904 0 : sigemptyset (&new_action.sa_mask);
905 0 : new_action.sa_flags = SA_SIGINFO;
906 :
907 0 : sigaction (SIGFPE, nullptr, &old_action);
908 0 : if (old_action.sa_handler != SIG_IGN)
909 0 : sigaction (SIGFPE, &new_action, nullptr);
910 : #endif
911 : }
912 : else
913 : {
914 : #ifdef LIBMESH_HAVE_FEDISABLEEXCEPT
915 0 : fedisableexcept(FE_DIVBYZERO | FE_INVALID);
916 : #elif LIBMESH_HAVE_XMMINTRIN_H
917 : _MM_SET_EXCEPTION_MASK(flags);
918 : #endif
919 0 : signal(SIGFPE, SIG_DFL);
920 : }
921 0 : }
922 :
923 :
924 : // Enable handling of SIGSEGV by libMesh
925 : // (potentially instead of PETSc)
926 0 : void enableSEGV(bool on)
927 : {
928 : #if LIBMESH_HAVE_DECL_SIGACTION
929 : static struct sigaction old_action;
930 : static bool was_on = false;
931 :
932 0 : if (on)
933 : {
934 : struct sigaction new_action;
935 0 : was_on = true;
936 :
937 : // Set up the structure to specify the new action.
938 0 : new_action.sa_sigaction = libmesh_handleSEGV;
939 0 : sigemptyset (&new_action.sa_mask);
940 0 : new_action.sa_flags = SA_SIGINFO;
941 :
942 0 : sigaction (SIGSEGV, &new_action, &old_action);
943 : }
944 0 : else if (was_on)
945 : {
946 0 : was_on = false;
947 0 : sigaction (SIGSEGV, &old_action, nullptr);
948 : }
949 : #else
950 : libmesh_error_msg("System call sigaction not supported.");
951 : #endif
952 0 : }
953 :
954 :
955 :
956 4350476 : void add_command_line_name(const std::string & name)
957 : {
958 : // Users had better not be asking about an empty string
959 115082 : libmesh_assert(!name.empty());
960 :
961 : static std::mutex command_line_names_mutex;
962 230164 : std::scoped_lock lock(command_line_names_mutex);
963 :
964 4235402 : command_line_name_set.insert(name);
965 4350476 : }
966 :
967 :
968 :
969 71 : void add_command_line_names(const GetPot & getpot)
970 : {
971 213 : for (auto & getter : {&GetPot::get_requested_arguments,
972 : &GetPot::get_requested_variables,
973 284 : &GetPot::get_requested_sections})
974 10591 : for (const std::string & name : (getpot.*getter)())
975 10372 : add_command_line_name(name);
976 71 : }
977 :
978 :
979 16170 : std::vector<std::string> command_line_names()
980 : {
981 : return std::vector<std::string>(command_line_name_set.begin(),
982 16170 : command_line_name_set.end());
983 : }
984 :
985 :
986 :
987 4289269 : bool on_command_line (std::string arg)
988 : {
989 : // Make sure the command line parser is ready for use. If it's not,
990 : // then we'll have to treat the command line as empty, for maximum
991 : // compatibility with programs that don't use LibMeshInit but
992 : // indirectly (e.g. via error handling code) query the command line.
993 4289269 : if (!command_line.get())
994 0 : return false;
995 :
996 : // Keep track of runtime queries, for later
997 4289269 : add_command_line_name(arg);
998 :
999 113152 : bool found_it = command_line->search(arg);
1000 :
1001 4289269 : if (!found_it)
1002 : {
1003 : // Try with all dashes instead of underscores
1004 112720 : std::replace(arg.begin(), arg.end(), '_', '-');
1005 112720 : found_it = command_line->search(arg);
1006 : }
1007 :
1008 4278809 : if (!found_it)
1009 : {
1010 : // OK, try with all underscores instead of dashes
1011 112718 : auto name_begin = arg.begin();
1012 12826010 : while (*name_begin == '-')
1013 225124 : ++name_begin;
1014 112718 : std::replace(name_begin, arg.end(), '-', '_');
1015 112718 : found_it = command_line->search(arg);
1016 : }
1017 :
1018 113152 : return found_it;
1019 : }
1020 :
1021 :
1022 :
1023 : template <typename T>
1024 339739 : T command_line_value (const std::string & name, T value)
1025 : {
1026 : // Make sure the command line parser is ready for use
1027 9880 : libmesh_assert(command_line.get());
1028 :
1029 : // only if the variable exists in the file
1030 9880 : if (command_line->have_variable(name))
1031 : {
1032 2652 : value = (*command_line)(name, value);
1033 :
1034 : // Keep track of runtime queries, for later. GetPot splits
1035 : // foo=bar into a separate name=value, so we can query for the
1036 : // name, but as far as PETSc is concerned that's one CLI
1037 : // argument. We'll store it that way.
1038 124 : const std::string stringvalue =
1039 2111 : (*command_line)(name, std::string());
1040 4284 : add_command_line_name(name+"="+stringvalue);
1041 : }
1042 :
1043 339739 : return value;
1044 : }
1045 :
1046 : template <typename T>
1047 16381 : T command_line_value (const std::vector<std::string> & names, T value)
1048 : {
1049 : // Make sure the command line parser is ready for use
1050 462 : libmesh_assert(command_line.get());
1051 :
1052 : // Keep track of runtime queries, for later
1053 49143 : for (const auto & entry : names)
1054 : {
1055 : // Keep track of runtime queries, for later. GetPot splits
1056 : // foo=bar into a separate name=value, so we can query for the
1057 : // name, but as far as PETSc is concerned that's one CLI
1058 : // argument. We'll store it that way.
1059 1848 : const std::string stringvalue =
1060 31838 : (*command_line)(entry, std::string());
1061 64600 : add_command_line_name(entry+"="+stringvalue);
1062 : }
1063 :
1064 : // Check for multiple options (return the first that matches)
1065 46831 : for (const auto & entry : names)
1066 582 : if (command_line->have_variable(entry))
1067 : {
1068 1156 : value = (*command_line)(entry, value);
1069 1156 : break;
1070 : }
1071 :
1072 16381 : return value;
1073 : }
1074 :
1075 :
1076 :
1077 : template <typename T>
1078 15620 : T command_line_next (std::string name, T value)
1079 : {
1080 : // Make sure the command line parser is ready for use
1081 642 : libmesh_assert(command_line.get());
1082 :
1083 : // Keep track of runtime queries, for later
1084 15620 : add_command_line_name(name);
1085 :
1086 : // on_command_line also puts the command_line cursor in the spot we
1087 : // need
1088 30598 : if (on_command_line(name))
1089 8790 : return command_line->next(value);
1090 :
1091 6720 : return value;
1092 : }
1093 :
1094 :
1095 :
1096 : template <typename T>
1097 280 : void command_line_vector (const std::string & name, std::vector<T> & vec)
1098 : {
1099 : // Make sure the command line parser is ready for use
1100 8 : libmesh_assert(command_line.get());
1101 :
1102 : // Keep track of runtime queries, for later
1103 280 : add_command_line_name(name);
1104 :
1105 : // only if the variable exists on the command line
1106 8 : if (command_line->have_variable(name))
1107 : {
1108 8 : unsigned size = command_line->vector_variable_size(name);
1109 280 : vec.resize(size);
1110 :
1111 560 : for (unsigned i=0; i<size; ++i)
1112 280 : vec[i] = (*command_line)(name, vec[i], i);
1113 : }
1114 280 : }
1115 :
1116 :
1117 1934237 : SolverPackage default_solver_package ()
1118 : {
1119 56824 : libmesh_assert (libMesh::initialized());
1120 :
1121 : static bool called = false;
1122 :
1123 : // Check the command line. Since the command line is
1124 : // unchanging it is sufficient to do this only once.
1125 1934237 : if (!called)
1126 : {
1127 14902 : called = true;
1128 :
1129 : #ifdef LIBMESH_HAVE_PETSC
1130 28988 : if (libMesh::on_command_line ("--use-petsc"))
1131 0 : libMeshPrivateData::_solver_package = PETSC_SOLVERS;
1132 : #endif
1133 :
1134 : #ifdef LIBMESH_TRILINOS_HAVE_AZTECOO
1135 : if (libMesh::on_command_line ("--use-trilinos") ||
1136 : libMesh::on_command_line ("--disable-petsc"))
1137 : libMeshPrivateData::_solver_package = TRILINOS_SOLVERS;
1138 : #endif
1139 :
1140 : #ifdef LIBMESH_HAVE_EIGEN
1141 44284 : if (libMesh::on_command_line ("--use-eigen" ) ||
1142 : #if defined(LIBMESH_HAVE_MPI)
1143 : // If the user bypassed MPI, we disable PETSc and Trilinos
1144 : // too
1145 31070 : libMesh::on_command_line ("--disable-mpi") ||
1146 : #endif
1147 30226 : libMesh::on_command_line ("--disable-petsc"))
1148 0 : libMeshPrivateData::_solver_package = EIGEN_SOLVERS;
1149 : #endif
1150 :
1151 : #ifdef LIBMESH_HAVE_LASPACK
1152 2110 : if (libMesh::on_command_line ("--use-laspack" ) ||
1153 : #if defined(LIBMESH_HAVE_MPI)
1154 : // If the user bypassed MPI, we disable PETSc and Trilinos
1155 : // too
1156 2954 : libMesh::on_command_line ("--disable-mpi") ||
1157 : #endif
1158 2110 : libMesh::on_command_line ("--disable-petsc"))
1159 0 : libMeshPrivateData::_solver_package = LASPACK_SOLVERS;
1160 : #endif
1161 :
1162 29804 : if (libMesh::on_command_line ("--disable-laspack") &&
1163 14902 : libMesh::on_command_line ("--disable-trilinos") &&
1164 30226 : libMesh::on_command_line ("--disable-eigen") &&
1165 : (
1166 : #if defined(LIBMESH_HAVE_MPI)
1167 : // If the user bypassed MPI, we disable PETSc too
1168 14902 : libMesh::on_command_line ("--disable-mpi") ||
1169 : #endif
1170 14902 : libMesh::on_command_line ("--disable-petsc")))
1171 0 : libMeshPrivateData::_solver_package = INVALID_SOLVER_PACKAGE;
1172 : }
1173 :
1174 :
1175 1934237 : return libMeshPrivateData::_solver_package;
1176 : }
1177 :
1178 :
1179 :
1180 : //-------------------------------------------------------------------------------
1181 : template LIBMESH_EXPORT unsigned char command_line_value<unsigned char> (const std::string &, unsigned char);
1182 : template LIBMESH_EXPORT unsigned short command_line_value<unsigned short> (const std::string &, unsigned short);
1183 : template LIBMESH_EXPORT unsigned int command_line_value<unsigned int> (const std::string &, unsigned int);
1184 : template LIBMESH_EXPORT char command_line_value<char> (const std::string &, char);
1185 : template LIBMESH_EXPORT short command_line_value<short> (const std::string &, short);
1186 : template LIBMESH_EXPORT int command_line_value<int> (const std::string &, int);
1187 : template LIBMESH_EXPORT float command_line_value<float> (const std::string &, float);
1188 : template LIBMESH_EXPORT double command_line_value<double> (const std::string &, double);
1189 : template LIBMESH_EXPORT long double command_line_value<long double> (const std::string &, long double);
1190 : template LIBMESH_EXPORT std::string command_line_value<std::string> (const std::string &, std::string);
1191 :
1192 : template LIBMESH_EXPORT unsigned char command_line_value<unsigned char> (const std::vector<std::string> &, unsigned char);
1193 : template LIBMESH_EXPORT unsigned short command_line_value<unsigned short> (const std::vector<std::string> &, unsigned short);
1194 : template LIBMESH_EXPORT unsigned int command_line_value<unsigned int> (const std::vector<std::string> &, unsigned int);
1195 : template LIBMESH_EXPORT char command_line_value<char> (const std::vector<std::string> &, char);
1196 : template LIBMESH_EXPORT short command_line_value<short> (const std::vector<std::string> &, short);
1197 : template LIBMESH_EXPORT int command_line_value<int> (const std::vector<std::string> &, int);
1198 : template LIBMESH_EXPORT float command_line_value<float> (const std::vector<std::string> &, float);
1199 : template LIBMESH_EXPORT double command_line_value<double> (const std::vector<std::string> &, double);
1200 : template LIBMESH_EXPORT long double command_line_value<long double> (const std::vector<std::string> &, long double);
1201 : template LIBMESH_EXPORT std::string command_line_value<std::string> (const std::vector<std::string> &, std::string);
1202 :
1203 : template LIBMESH_EXPORT unsigned char command_line_next<unsigned char> (std::string, unsigned char);
1204 : template LIBMESH_EXPORT unsigned short command_line_next<unsigned short> (std::string, unsigned short);
1205 : template LIBMESH_EXPORT unsigned int command_line_next<unsigned int> (std::string, unsigned int);
1206 : template LIBMESH_EXPORT char command_line_next<char> (std::string, char);
1207 : template LIBMESH_EXPORT short command_line_next<short> (std::string, short);
1208 : template LIBMESH_EXPORT int command_line_next<int> (std::string, int);
1209 : template LIBMESH_EXPORT float command_line_next<float> (std::string, float);
1210 : template LIBMESH_EXPORT double command_line_next<double> (std::string, double);
1211 : template LIBMESH_EXPORT long double command_line_next<long double> (std::string, long double);
1212 : template LIBMESH_EXPORT std::string command_line_next<std::string> (std::string, std::string);
1213 :
1214 : template LIBMESH_EXPORT void command_line_vector<unsigned char> (const std::string &, std::vector<unsigned char> &);
1215 : template LIBMESH_EXPORT void command_line_vector<unsigned short>(const std::string &, std::vector<unsigned short> &);
1216 : template LIBMESH_EXPORT void command_line_vector<unsigned int> (const std::string &, std::vector<unsigned int> &);
1217 : template LIBMESH_EXPORT void command_line_vector<char> (const std::string &, std::vector<char> &);
1218 : template LIBMESH_EXPORT void command_line_vector<short> (const std::string &, std::vector<short> &);
1219 : template LIBMESH_EXPORT void command_line_vector<int> (const std::string &, std::vector<int> &);
1220 : template LIBMESH_EXPORT void command_line_vector<float> (const std::string &, std::vector<float> &);
1221 : template LIBMESH_EXPORT void command_line_vector<double> (const std::string &, std::vector<double> &);
1222 : template LIBMESH_EXPORT void command_line_vector<long double> (const std::string &, std::vector<long double> &);
1223 :
1224 : #ifdef LIBMESH_DEFAULT_QUADRUPLE_PRECISION
1225 : template LIBMESH_EXPORT Real command_line_value<Real> (const std::string &, Real);
1226 : template LIBMESH_EXPORT Real command_line_value<Real> (const std::vector<std::string> &, Real);
1227 : template LIBMESH_EXPORT Real command_line_next<Real> (std::string, Real);
1228 : template LIBMESH_EXPORT void command_line_vector<Real> (const std::string &, std::vector<Real> &);
1229 : #endif
1230 :
1231 : } // namespace libMesh
|