Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2026 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 : #include "libmesh/thread_buffered_syncbuf.h"
33 :
34 : // TIMPI includes
35 : #include "timpi/communicator.h"
36 : #include "timpi/timpi_init.h"
37 :
38 : // C/C++ includes
39 : #include <cstdlib>
40 : #include <iostream>
41 : #include <fstream>
42 :
43 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
44 : #include <exception>
45 : #include <optional>
46 : #endif
47 :
48 : #ifdef LIBMESH_HAVE_OPENMP
49 : #include <omp.h>
50 : #endif
51 :
52 : #include "stdlib.h" // C, not C++ - we need setenv() from POSIX
53 :
54 :
55 : #if defined(LIBMESH_HAVE_MPI)
56 : # include "libmesh/ignore_warnings.h"
57 : # include <mpi.h>
58 : # include "libmesh/restore_warnings.h"
59 : #endif // #if defined(LIBMESH_HAVE_MPI)
60 :
61 : #if defined(LIBMESH_HAVE_PETSC)
62 : # include "libmesh/petsc_solver_exception.h"
63 : # include <petsc.h>
64 : # include <petscerror.h>
65 : # include "libmesh/petscdmlibmesh.h"
66 : # if defined(LIBMESH_HAVE_SLEPC)
67 : // Ignore unused variable warnings from SLEPc
68 : # include "libmesh/ignore_warnings.h"
69 : # include "libmesh/slepc_macro.h"
70 : # include <slepc.h>
71 : # include "libmesh/restore_warnings.h"
72 : # endif // #if defined(LIBMESH_HAVE_SLEPC)
73 : #endif // #if defined(LIBMESH_HAVE_PETSC)
74 :
75 : #ifdef LIBMESH_HAVE_NETGEN
76 : // We need the nglib namespace, because it's used everywhere in nglib
77 : // and we don't get binary compatibility without it.
78 : //
79 : // We need the nglib namespace *here*, because somehow nobody ever
80 : // figured out to just put it in nglib.h?
81 : namespace nglib {
82 : #include "netgen/nglib/nglib.h"
83 : }
84 : #endif
85 :
86 : // If we're using MPI and VTK has been detected, we need to do some
87 : // MPI initialize/finalize stuff for VTK.
88 : #if defined(LIBMESH_HAVE_MPI) && defined(LIBMESH_HAVE_VTK)
89 : #include "libmesh/ignore_warnings.h"
90 : # include "vtkMPIController.h"
91 : #include "libmesh/restore_warnings.h"
92 : #endif
93 :
94 : #ifdef PETSC_HAVE_UMPIRE
95 : #include "umpire/util/io.hpp"
96 : #endif
97 :
98 : #include <mutex>
99 :
100 : // --------------------------------------------------------
101 : // Local anonymous namespace to hold miscellaneous bits
102 : namespace {
103 :
104 : std::unique_ptr<GetPot> command_line;
105 :
106 : std::set<std::string> command_line_name_set;
107 :
108 : std::unique_ptr<std::ofstream> _ofstream;
109 : // If std::cout and std::cerr are redirected, we need to
110 : // be a little careful and save the original streambuf objects,
111 : // replacing them in the destructor before program termination.
112 : std::streambuf * out_buf (nullptr);
113 : std::streambuf * err_buf (nullptr);
114 :
115 : std::unique_ptr<libMesh::Threads::task_scheduler_init> task_scheduler;
116 : #if defined(LIBMESH_HAVE_PETSC)
117 : bool libmesh_initialized_petsc = false;
118 : #endif
119 : #if defined(LIBMESH_HAVE_SLEPC)
120 : bool libmesh_initialized_slepc = false;
121 : #endif
122 :
123 : } // anonymous namespace
124 :
125 :
126 :
127 : #ifdef LIBMESH_HAVE_MPI
128 0 : void libMesh_MPI_Handler (MPI_Comm *, int *, ...)
129 : {
130 0 : libmesh_not_implemented();
131 : }
132 : #endif
133 :
134 :
135 : namespace libMesh
136 : {
137 :
138 : /**
139 : * Namespaces don't provide private data,
140 : * so let's take the data we would like
141 : * private and put it in an obnoxious
142 : * namespace. At least that way it is a
143 : * pain to use, thus discouraging errors.
144 : */
145 : namespace libMeshPrivateData {
146 :
147 : /**
148 : * Flag that tells if \p init() has been called.
149 : */
150 : extern bool _is_initialized;
151 :
152 : /**
153 : * The default solver package to use.
154 : */
155 : extern SolverPackage _solver_package;
156 : }
157 :
158 :
159 : // ------------------------------------------------------------
160 : // libMesh data initialization
161 : #ifdef LIBMESH_HAVE_MPI
162 : MPI_Comm GLOBAL_COMM_WORLD = MPI_COMM_NULL;
163 : #else
164 : int GLOBAL_COMM_WORLD = 0;
165 : #endif
166 :
167 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
168 : std::terminate_handler LibMeshInit::_old_terminate_handler;
169 : #endif
170 :
171 : OStreamProxy out(std::cout);
172 : OStreamProxy err(std::cerr);
173 :
174 : // Our thread-safe wrappers and the “pre-wrap” sink pointers
175 : std::unique_ptr<ThreadBufferedSyncbuf> _out_syncd_thread_buffer;
176 : std::unique_ptr<ThreadBufferedSyncbuf> _err_syncd_thread_buffer;
177 : std::streambuf * _out_prewrap_buf = nullptr;
178 : std::streambuf * _err_prewrap_buf = nullptr;
179 :
180 : // Install after redirection/drop decisions
181 16600 : void install_thread_buffered_sync()
182 : {
183 702 : auto check_stored_buffer = [](const auto * const libmesh_dbg_var(stored_buffer)) {
184 702 : libmesh_assert_msg(!stored_buffer,
185 : "Oops, we've already stored a prewrapped buffer. We must be calling this "
186 : "function a second time in which case we're going to lose the already "
187 : "stored prewrapped buffer forever");
188 702 : };
189 :
190 : // libMesh::out
191 17068 : if (auto * ob = libMesh::out.rdbuf(); ob)
192 : {
193 234 : check_stored_buffer(_out_prewrap_buf);
194 2794 : _out_prewrap_buf = ob;
195 : _out_syncd_thread_buffer =
196 5354 : std::make_unique<ThreadBufferedSyncbuf>(*ob, /*flush_on_newline=*/true);
197 2794 : libMesh::out.rdbuf(_out_syncd_thread_buffer.get());
198 : }
199 :
200 : // libMesh::err
201 17068 : if (auto * eb = libMesh::err.rdbuf(); eb)
202 : {
203 468 : check_stored_buffer(_err_prewrap_buf);
204 16600 : _err_prewrap_buf = eb;
205 : _err_syncd_thread_buffer =
206 32732 : std::make_unique<ThreadBufferedSyncbuf>(*eb, /*flush_on_newline=*/true);
207 16600 : libMesh::err.rdbuf(_err_syncd_thread_buffer.get());
208 : }
209 16600 : }
210 :
211 : // Uninstall before restoring/redirection teardown
212 16600 : void uninstall_thread_buffered_sync()
213 : {
214 16600 : if (_out_syncd_thread_buffer)
215 : {
216 : // flush any thread-local leftovers on this thread
217 234 : libMesh::out << std::flush;
218 2794 : libMesh::out.rdbuf(_out_prewrap_buf);
219 234 : _out_syncd_thread_buffer.reset();
220 2794 : _out_prewrap_buf = nullptr;
221 : }
222 16600 : if (_err_syncd_thread_buffer)
223 : {
224 468 : libMesh::err << std::flush;
225 16600 : libMesh::err.rdbuf(_err_prewrap_buf);
226 : #ifdef PETSC_HAVE_UMPIRE
227 : // Our libMesh::out and libMesh::err stream proxies are very thin wrappers around,
228 : // by default, std::cout and std::cerr. So when other libraries or users access the
229 : // rdbuf of those streams, then they directly access our thread sync'd custom stream
230 : // buffer. Umpire doesn't use the rdbuf of std::cout, but they *do* use the rdbuf of
231 : // std::cerr, which means they're using our thread sync'd stream buffer. Consequently,
232 : // we must release umpire's reference to our buffer before we destroy it
233 : umpire::util::finalize_io();
234 : #endif
235 468 : _err_syncd_thread_buffer.reset();
236 16600 : _err_prewrap_buf = nullptr;
237 : }
238 16600 : }
239 :
240 :
241 : /**
242 : * Helper to do cleanup from both destructor and terminate
243 : */
244 16600 : void cleanup_stream_buffers()
245 : {
246 : // Before resetting the stream buffers, let's remove our thread wrappers
247 32732 : if (!libMesh::on_command_line ("--disable-thread-safe-output"))
248 16600 : uninstall_thread_buffered_sync();
249 :
250 34136 : if (libMesh::on_command_line ("--redirect-stdout") ||
251 33668 : libMesh::on_command_line ("--redirect-output"))
252 : {
253 : // If stdout/stderr were redirected to files, reset them now.
254 0 : libMesh::out.rdbuf (out_buf);
255 0 : libMesh::err.rdbuf (err_buf);
256 : }
257 :
258 : // If we built our own output streams, we want to clean them up.
259 32732 : if (libMesh::on_command_line ("--separate-libmeshout"))
260 : {
261 0 : delete libMesh::out.get();
262 0 : delete libMesh::err.get();
263 :
264 0 : libMesh::out.reset(std::cout);
265 0 : libMesh::err.reset(std::cerr);
266 : }
267 16600 : }
268 :
269 :
270 : bool warned_about_auto_ptr(false);
271 :
272 : PerfLog perflog ("libMesh",
273 : #ifdef LIBMESH_ENABLE_PERFORMANCE_LOGGING
274 : true
275 : #else
276 : false
277 : #endif
278 : );
279 :
280 :
281 : #ifdef LIBMESH_USE_COMPLEX_NUMBERS
282 : const Number imaginary (0., 1.);
283 : // const Number zero (0., 0.);
284 : #else
285 : // const Number zero = 0.;
286 : #endif
287 :
288 : // This is now a static constant in the header; no reason not to let
289 : // the compiler inline it.
290 :
291 : // const unsigned int invalid_uint = static_cast<unsigned int>(-1);
292 :
293 :
294 :
295 : // ------------------------------------------------------------
296 : // libMesh::libMeshPrivateData data initialization
297 : #ifdef LIBMESH_HAVE_MPI
298 : MPI_Errhandler libmesh_errhandler;
299 :
300 : processor_id_type libMesh::libMeshPrivateData::_n_processors = 1;
301 : processor_id_type libMesh::libMeshPrivateData::_processor_id = 0;
302 : #endif
303 : int libMesh::libMeshPrivateData::_n_threads = 1; /* Threads::task_scheduler_init::automatic; */
304 : unsigned int libMesh::libMeshPrivateData::_default_grainsize = 1000;
305 : bool libMesh::libMeshPrivateData::_is_initialized = false;
306 : SolverPackage libMesh::libMeshPrivateData::_solver_package =
307 : #if defined(LIBMESH_HAVE_PETSC) // PETSc is the default
308 : PETSC_SOLVERS;
309 : #elif defined(LIBMESH_TRILINOS_HAVE_AZTECOO) // Use Trilinos if PETSc isn't there
310 : TRILINOS_SOLVERS;
311 : #elif defined(LIBMESH_HAVE_EIGEN) // Use Eigen if neither are there
312 : EIGEN_SOLVERS;
313 : #elif defined(LIBMESH_HAVE_LASPACK) // Use LASPACK as a last resort
314 : LASPACK_SOLVERS;
315 : #else // No valid linear solver package at compile time
316 : INVALID_SOLVER_PACKAGE;
317 : #endif
318 :
319 :
320 :
321 : // ------------------------------------------------------------
322 : // libMesh functions
323 :
324 79644 : bool initialized()
325 : {
326 79644 : return libMeshPrivateData::_is_initialized;
327 : }
328 :
329 :
330 :
331 28692 : bool closed()
332 : {
333 28692 : return !libMeshPrivateData::_is_initialized;
334 : }
335 :
336 :
337 :
338 0 : void libmesh_abort()
339 : {
340 0 : libMesh::perflog.clear();
341 :
342 : // Now that we're done with output we should clean up our stream
343 : // buffers; if we fail to uninstall_thread_buffered_sync() when
344 : // needed we can end up seeing a segfault in iostreams destructors
345 0 : cleanup_stream_buffers();
346 :
347 : // If we have MPI and it has been initialized, we need to be sure
348 : // and call MPI_Abort instead of std::abort, so that the parallel
349 : // job can die nicely.
350 : #if defined(LIBMESH_HAVE_MPI)
351 : int mpi_initialized;
352 0 : MPI_Initialized (&mpi_initialized);
353 :
354 0 : if (mpi_initialized)
355 0 : MPI_Abort(libMesh::GLOBAL_COMM_WORLD, 1);
356 : #endif
357 :
358 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
359 : // The system terminate_handler may do useful things, or the user
360 : // may have set their own terminate handler that we want to call.
361 0 : LibMeshInit::_old_terminate_handler();
362 : #endif
363 :
364 : // The last attempt to die if nothing else has killed us
365 0 : std::abort();
366 : }
367 :
368 :
369 :
370 16600 : LibMeshInit::LibMeshInit (int argc, const char * const * argv,
371 16600 : TIMPI::communicator COMM_WORLD_IN, int n_threads)
372 : {
373 : // should _not_ be initialized already.
374 468 : libmesh_assert (!libMesh::initialized());
375 :
376 : // Build a command-line parser.
377 32264 : command_line = std::make_unique<GetPot>(argc, argv);
378 :
379 : // Disable performance logging upon request
380 : {
381 32732 : if (libMesh::on_command_line ("--disable-perflog"))
382 0 : libMesh::perflog.disable_logging();
383 : }
384 :
385 47488 : auto check_empty_command_line_value = [](auto & cl, const std::string & option) {
386 47488 : libmesh_error_msg_if(cl.search(option),
387 : "Detected option " << option << " with no value. Did you forget '='?");
388 47488 : };
389 :
390 : // Build a task scheduler
391 : {
392 : // Get the requested number of threads, defaults to 1 to avoid MPI and
393 : // multithreading competition. If you would like to use MPI and multithreading
394 : // at the same time then (n_mpi_processes_per_node)x(n_threads) should be the
395 : // number of processing cores per node.
396 17068 : std::vector<std::string> n_threads_opt(2);
397 936 : n_threads_opt[0] = "--n_threads";
398 936 : n_threads_opt[1] = "--n-threads";
399 16600 : libMesh::libMeshPrivateData::_n_threads =
400 16600 : libMesh::command_line_value(n_threads_opt, n_threads);
401 :
402 16600 : if (libMesh::libMeshPrivateData::_n_threads == -1)
403 : {
404 46332 : for (auto & option : n_threads_opt)
405 30888 : check_empty_command_line_value(*command_line, option);
406 :
407 15444 : libMesh::libMeshPrivateData::_n_threads = 1;
408 : }
409 :
410 : // If there's no threading model active, force _n_threads==1
411 : #if !LIBMESH_USING_THREADS
412 : if (libMesh::libMeshPrivateData::_n_threads != 1)
413 : {
414 : libMesh::libMeshPrivateData::_n_threads = 1;
415 : libmesh_warning("Warning: You requested --n-threads>1 but no threading model is active!\n"
416 : << "Forcing --n-threads==1 instead!");
417 : }
418 : #endif
419 :
420 : // Set the number of OpenMP threads to the same as the number of threads libMesh is going to use
421 : #ifdef LIBMESH_HAVE_OPENMP
422 16600 : omp_set_num_threads(libMesh::libMeshPrivateData::_n_threads);
423 : #endif
424 :
425 16132 : task_scheduler = std::make_unique<Threads::task_scheduler_init>(libMesh::n_threads());
426 15664 : }
427 :
428 : // The optimal minimum chunk size for threading is probably fairly
429 : // system-dependent.
430 16600 : libMesh::libMeshPrivateData::_default_grainsize =
431 16600 : libMesh::command_line_value("--default-grainsize",
432 : libMesh::libMeshPrivateData::_default_grainsize);
433 :
434 : // Construct singletons who may be at risk of the
435 : // "static initialization order fiasco"
436 16600 : Singleton::setup();
437 :
438 : // Make sure the construction worked
439 468 : libmesh_assert(remote_elem);
440 :
441 16600 : const bool using_threads = libMesh::n_threads() > 1;
442 468 : const bool handle_mpi_errors = false; // libMesh does this
443 :
444 : #if defined(LIBMESH_HAVE_MPI)
445 :
446 : // Allow the user to bypass MPI initialization
447 32732 : if (!libMesh::on_command_line ("--disable-mpi"))
448 : {
449 16600 : int mpi_thread_request = using_threads;
450 33668 : const auto mpi_thread_type = libMesh::command_line_value("--mpi-thread-type", std::string(""));
451 16600 : if (mpi_thread_type.empty())
452 : {
453 32732 : check_empty_command_line_value(*command_line, "--mpi-thread-type");
454 : #if defined(PETSC_HAVE_STRUMPACK) && defined(PETSC_HAVE_SLATE)
455 : // For GPU computations, the solver strumpack uses slate which always requests
456 : // MPI_THREAD_MULTIPLE. The solution here is not perfect because the run may never be
457 : // using strumpack, but we believe it's better to force the MPI library to use locks
458 : // whenever it accesses the message queue, that is, when processing any sends and receive,
459 : // than it is to require users to pre-announce/signal what solvers they are using through
460 : // --mpi-thread-type
461 : mpi_thread_request = 3;
462 : #endif
463 : }
464 : else
465 : {
466 0 : if (mpi_thread_type == "single")
467 : {
468 0 : if (using_threads)
469 0 : libmesh_error_msg("We are using threads, so we require more mpi thread support "
470 : "than '--mpi-thread-type=single'");
471 0 : mpi_thread_request = 0;
472 : }
473 0 : else if (mpi_thread_type == "funneled")
474 0 : mpi_thread_request = 1;
475 0 : else if (mpi_thread_type == "serialized")
476 0 : mpi_thread_request = 2;
477 0 : else if (mpi_thread_type == "multiple")
478 0 : mpi_thread_request = 3;
479 : else
480 0 : libmesh_error_msg(
481 : "Unsupported mpi thread type '"
482 : << mpi_thread_type
483 : << "'. Allowed options are 'single', 'funneled', 'serialized', and 'multiple'");
484 : }
485 :
486 16600 : this->_timpi_init =
487 : new TIMPI::TIMPIInit(argc, argv, mpi_thread_request,
488 16600 : handle_mpi_errors, COMM_WORLD_IN);
489 16600 : _comm = new Parallel::Communicator(this->_timpi_init->comm().get());
490 :
491 : const std::string timpi_sync =
492 33668 : libMesh::command_line_value("--timpi-sync", std::string("nbx"));
493 16600 : _comm->sync_type(timpi_sync);
494 :
495 16600 : libMesh::GLOBAL_COMM_WORLD = COMM_WORLD_IN;
496 :
497 : //MPI_Comm_set_name not supported in at least SGI MPT's MPI implementation
498 : //MPI_Comm_set_name (libMesh::COMM_WORLD, "libMesh::COMM_WORLD");
499 :
500 16600 : libMeshPrivateData::_processor_id =
501 936 : cast_int<processor_id_type>(this->comm().rank());
502 16600 : libMeshPrivateData::_n_processors =
503 936 : cast_int<processor_id_type>(this->comm().size());
504 :
505 : // Set up an MPI error handler if requested. This helps us get
506 : // into a debugger with a proper stack when an MPI error occurs.
507 32732 : if (libMesh::on_command_line ("--handle-mpi-errors"))
508 : {
509 0 : timpi_call_mpi
510 : (MPI_Comm_create_errhandler(libMesh_MPI_Handler, &libmesh_errhandler));
511 0 : timpi_call_mpi
512 : (MPI_Comm_set_errhandler(libMesh::GLOBAL_COMM_WORLD, libmesh_errhandler));
513 0 : timpi_call_mpi
514 : (MPI_Comm_set_errhandler(MPI_COMM_WORLD, libmesh_errhandler));
515 : }
516 : }
517 :
518 : // Could we have gotten bad values from the above calls?
519 468 : libmesh_assert_greater (libMeshPrivateData::_n_processors, 0);
520 :
521 : // The cast_int already tested _processor_id>=0
522 : // libmesh_assert_greater_equal (libMeshPrivateData::_processor_id, 0);
523 :
524 : // Let's be sure we properly initialize on every processor at once:
525 468 : libmesh_parallel_only(this->comm());
526 :
527 : #else
528 : libmesh_ignore(COMM_WORLD_IN);
529 : this->_timpi_init =
530 : new TIMPI::TIMPIInit(argc, argv, using_threads,
531 : handle_mpi_errors);
532 : _comm = new Parallel::Communicator(this->_timpi_init->comm().get());
533 : #endif
534 :
535 : #if defined(LIBMESH_HAVE_PETSC)
536 :
537 : // Allow the user to bypass PETSc initialization
538 32760 : if (!libMesh::on_command_line ("--disable-petsc")
539 :
540 : #if defined(LIBMESH_HAVE_MPI)
541 : // If the user bypassed MPI, we'd better be safe and assume that
542 : // PETSc was built to require it; otherwise PETSc initialization
543 : // dies.
544 32760 : && !libMesh::on_command_line ("--disable-mpi")
545 : #endif
546 : )
547 : {
548 : #ifdef LIBMESH_HAVE_MPI
549 16380 : PETSC_COMM_WORLD = libMesh::GLOBAL_COMM_WORLD;
550 : #else
551 : // PETSc --with-mpi=0 doesn't like our default "communicator" 0
552 : this->_comm->get() = PETSC_COMM_SELF;
553 : #endif
554 :
555 : // Check whether the calling program has already initialized
556 : // PETSc, and avoid duplicate Initialize/Finalize
557 : PetscBool petsc_already_initialized;
558 16380 : LibmeshPetscCallA(libMesh::GLOBAL_COMM_WORLD, PetscInitialized(&petsc_already_initialized));
559 16380 : if (petsc_already_initialized != PETSC_TRUE)
560 16380 : libmesh_initialized_petsc = true;
561 : # if defined(LIBMESH_HAVE_SLEPC)
562 :
563 : // If SLEPc allows us to check whether the calling program
564 : // has already initialized it, we do that, and avoid
565 : // duplicate Initialize/Finalize.
566 : // We assume that SLEPc will handle PETSc appropriately,
567 : // which it does in the versions we've checked.
568 16380 : if (!SlepcInitializeCalled)
569 : {
570 16380 : LibmeshPetscCallA(libMesh::GLOBAL_COMM_WORLD, SlepcInitialize (&argc, const_cast<char ***>(&argv), nullptr, nullptr));
571 16380 : libmesh_initialized_slepc = true;
572 : }
573 : # else
574 : if (libmesh_initialized_petsc)
575 : LibmeshPetscCallA(libMesh::GLOBAL_COMM_WORLD, PetscInitialize (&argc, const_cast<char ***>(&argv), nullptr, nullptr));
576 : # endif
577 : // Register the reference implementation of DMlibMesh
578 16380 : LibmeshPetscCallA(libMesh::GLOBAL_COMM_WORLD, DMRegister(DMLIBMESH, DMCreate_libMesh));
579 : }
580 : #endif
581 :
582 : #ifdef LIBMESH_HAVE_NETGEN
583 16600 : nglib::Ng_Init();
584 : #endif
585 :
586 : #if defined(LIBMESH_HAVE_MPI) && defined(LIBMESH_HAVE_VTK)
587 : // Do MPI initialization for VTK.
588 : _vtk_mpi_controller = vtkMPIController::New();
589 : _vtk_mpi_controller->Initialize(&argc, const_cast<char ***>(&argv), /*initialized_externally=*/1);
590 : _vtk_mpi_controller->SetGlobalController(_vtk_mpi_controller);
591 : #endif
592 :
593 : // Re-parse the command-line arguments. Note that PETSc and MPI
594 : // initialization above may have removed command line arguments
595 : // that are not relevant to this application in the above calls.
596 : // We don't want a false-positive by detecting those arguments.
597 : //
598 : // Note: this seems overly paranoid/like it should be unnecessary,
599 : // plus we were doing it wrong for many years and not clearing the
600 : // existing GetPot object before re-parsing the command line, so all
601 : // the command line arguments appeared twice in the GetPot object...
602 32264 : command_line = std::make_unique<GetPot>(argc, argv);
603 :
604 : // Not syncing with stdio is an optimization when simultaneous
605 : // C and C++ style access to output streams is not required.
606 : // The amount of benefit which occurs is probably implementation
607 : // defined, and may be nothing. On the other hand, I have seen
608 : // some IO tests where IO performance improves by a factor of two.
609 : // However, not syncing the streams means thread safety is no longer
610 : // guaranteed and we have indeed seen thread sanitizer warnings
611 : // during concurrent writes to std::cout when toggling this boolean
612 : // to true. We default to preferring safety and correctness instead
613 : // of performance
614 32732 : if (libMesh::on_command_line ("--dont-sync-with-stdio"))
615 0 : std::ios::sync_with_stdio(false);
616 :
617 : // Honor the --separate-libmeshout command-line option.
618 : // When this is specified, the library uses an independent ostream
619 : // for libMesh::out/libMesh::err messages, and
620 : // std::cout and std::cerr are untouched by any other options
621 32732 : if (libMesh::on_command_line ("--separate-libmeshout"))
622 : {
623 : // Redirect. We'll share streambufs with cout/cerr for now, but
624 : // presumably anyone using this option will want to replace the
625 : // bufs later.
626 0 : std::ostream * newout = new std::ostream(std::cout.rdbuf());
627 0 : libMesh::out = *newout;
628 0 : std::ostream * newerr = new std::ostream(std::cerr.rdbuf());
629 0 : libMesh::err = *newerr;
630 : }
631 :
632 : // Process command line arguments for redirecting stdout/stderr.
633 : bool
634 16600 : cmdline_has_redirect_stdout = libMesh::on_command_line ("--redirect-stdout"),
635 16600 : cmdline_has_redirect_output = libMesh::on_command_line ("--redirect-output");
636 :
637 : // The --redirect-stdout command-line option has been deprecated in
638 : // favor of "--redirect-output basename".
639 : if (cmdline_has_redirect_stdout)
640 : libmesh_warning("The --redirect-stdout command line option has been deprecated. "
641 : "Use '--redirect-output basename' instead.");
642 :
643 : // Honor the "--redirect-stdout" and "--redirect-output basename"
644 : // command-line options. When one of these is specified, each
645 : // processor sends libMesh::out/libMesh::err messages to
646 : // stdout.processor.#### (default) or basename.processor.####.
647 16600 : if (cmdline_has_redirect_stdout || cmdline_has_redirect_output)
648 : {
649 0 : std::string basename = "stdout";
650 :
651 : // Look for following argument if using new API
652 0 : if (cmdline_has_redirect_output)
653 : {
654 : // Set the cursor to the correct location in the list of command line arguments.
655 0 : command_line->search(1, "--redirect-output");
656 :
657 : // Get the next option on the command line as a string.
658 0 : std::string next_string = "";
659 0 : next_string = command_line->next(next_string);
660 :
661 : // If the next string starts with a dash, we assume it's
662 : // another flag and not a file basename requested by the
663 : // user.
664 0 : if (next_string.size() > 0 && next_string.find_first_of("-") != 0)
665 0 : basename = next_string;
666 : }
667 :
668 0 : std::ostringstream filename;
669 0 : filename << basename << ".processor." << libMesh::global_processor_id();
670 0 : _ofstream = std::make_unique<std::ofstream>(filename.str().c_str());
671 :
672 : // Redirect, saving the original streambufs!
673 0 : out_buf = libMesh::out.rdbuf (_ofstream->rdbuf());
674 0 : err_buf = libMesh::err.rdbuf (_ofstream->rdbuf());
675 0 : }
676 :
677 : // redirect libMesh::out to nothing on all
678 : // other processors unless explicitly told
679 : // not to via the --keep-cout command-line argument.
680 32732 : if (!libMesh::on_command_line ("--keep-cout"))
681 16600 : if (libMesh::global_processor_id() != 0)
682 13806 : libMesh::out.rdbuf (nullptr);
683 :
684 : // Similarly, the user can request to drop cerr on all non-0 ranks.
685 : // By default, errors are printed on all ranks, but this can lead to
686 : // interleaved/unpredictable outputs when doing parallel regression
687 : // testing, which this option is designed to support.
688 32732 : if (libMesh::on_command_line ("--drop-cerr"))
689 0 : if (libMesh::global_processor_id() != 0)
690 0 : libMesh::err.rdbuf (nullptr);
691 :
692 : // Now that we've finished setting our stream buffers, let's wrap them (if they're non-null) in our thread-safe wrapper
693 32732 : if (!libMesh::on_command_line ("--disable-thread-safe-output"))
694 16600 : install_thread_buffered_sync();
695 :
696 : // Check command line to override printing
697 : // of reference count information.
698 32732 : if (libMesh::on_command_line("--disable-refcount-printing"))
699 0 : ReferenceCounter::disable_print_counter_info();
700 :
701 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
702 : // Set our terminate handler to write stack traces in the event of a
703 : // crash
704 16600 : _old_terminate_handler = std::set_terminate(libmesh_terminate_handler);
705 : #endif
706 :
707 :
708 32732 : if (libMesh::on_command_line("--enable-fpe"))
709 0 : libMesh::enableFPE(true);
710 :
711 32732 : if (libMesh::on_command_line("--enable-segv"))
712 0 : libMesh::enableSEGV(true);
713 :
714 32732 : if (libMesh::on_command_line("--enable-sigint"))
715 0 : libMesh::enableSIGINT(true);
716 :
717 : #if defined(LIBMESH_HAVE_HDF5) && !defined(_MSC_VER)
718 : // We may be running with ExodusII configured not to use HDF5 (in
719 : // which case user code which wants to lock files has to do flock()
720 : // itself) or with ExodusII configured to use HDF5 (which will
721 : // helpfully try to get an exclusive flock() itself, and then scream
722 : // and die if user code has already locked the file. To get
723 : // consistent behavior, we need to disable file locking. The only
724 : // reliable way I can see to do this is via an HDF5 environment
725 : // variable.
726 : //
727 : // If the user set this environment variable then we'll trust that
728 : // they know what they're doing. If not then we'll set FALSE,
729 : // because that's a better default for us than the unset default.
730 468 : setenv("HDF5_USE_FILE_LOCKING", "FALSE", /*overwrite=false*/0);
731 : #endif // LIBMESH_HAVE_HDF5
732 :
733 : // The library is now ready for use
734 16600 : libMeshPrivateData::_is_initialized = true;
735 :
736 :
737 : // Make sure these work. Library methods
738 : // depend on these being implemented properly,
739 : // so this is a good time to test them!
740 468 : libmesh_assert (libMesh::initialized());
741 468 : libmesh_assert (!libMesh::closed());
742 16600 : }
743 :
744 :
745 :
746 17536 : LibMeshInit::~LibMeshInit()
747 : {
748 : // Every processor had better be ready to exit at the same time.
749 : // Even if we're not doing parallel_only debugging, we don't want
750 : // one processor to try to exit until all others are done working.
751 :
752 : // We could be destructing here because we're unwinding the stack
753 : // due to a thrown exception, though. It's possible that an
754 : // application is catching exceptions outside of the LibMeshInit
755 : // scope, or that we're using a C++ compiler that does unwinding
756 : // for uncaught exceptions (the standard says whether to go straight
757 : // to terminate() or unwind first is "implementation-defined"). If
758 : // *that* is the case then we can't safely communicate with other
759 : // processors that might not all be unwinding too.
760 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
761 16600 : if (!std::uncaught_exceptions())
762 : #endif
763 16600 : this->comm().barrier();
764 :
765 : // We can't delete, finalize, etc. more than once without
766 : // reinitializing in between
767 468 : libmesh_exceptionless_assert(!libMesh::closed());
768 :
769 : // Delete reference counted singleton(s)
770 16600 : Singleton::cleanup();
771 :
772 : // Clear the thread task manager we started
773 468 : task_scheduler.reset();
774 :
775 : // If we have a memory leak, we want the details printed.
776 16600 : if (ReferenceCounter::n_objects() != 0)
777 0 : ReferenceCounter::enable_print_counter_info();
778 :
779 : // Ask the \p ReferenceCounter to print its reference count
780 : // information, if printing is enabled. This allows us to find
781 : // memory leaks.
782 : //
783 : // If we don't have any leaks, we'll print to cout, only if we've
784 : // been told to. If we do, we'll print to cerr, to make sure the
785 : // user doesn't miss a leak that's only on a processor other than 0.
786 16600 : if (ReferenceCounter::n_objects() == 0)
787 16600 : ReferenceCounter::print_info ();
788 :
789 : // Scream specifically if we detect a memory leak
790 16600 : if (ReferenceCounter::n_objects() != 0)
791 : {
792 0 : ReferenceCounter::print_info (libMesh::err);
793 :
794 0 : libMesh::err << "Memory leak detected!"
795 0 : << std::endl;
796 :
797 : #if !defined(LIBMESH_ENABLE_REFERENCE_COUNTING) || defined(NDEBUG)
798 :
799 : libMesh::err << "Compile in DEBUG mode with --enable-reference-counting"
800 : << std::endl
801 : << "for more information"
802 : << std::endl;
803 : #endif
804 : }
805 :
806 : // print the perflog to individual processor's file.
807 16600 : libMesh::perflog.print_log();
808 :
809 : // Now clear the logging object, we don't want it to print
810 : // a second time during the PerfLog destructor.
811 16600 : libMesh::perflog.clear();
812 :
813 : // Reconnect the output streams
814 : // (don't do this, or we will get messages from objects
815 : // that go out of scope after the following return)
816 : //std::cout.rdbuf(std::cerr.rdbuf());
817 :
818 :
819 : // Set the initialized() flag to false
820 16600 : libMeshPrivateData::_is_initialized = false;
821 :
822 16600 : cleanup_stream_buffers();
823 :
824 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
825 : // Reset the old terminate handler; maybe the user code wants to
826 : // keep doing C++ stuff after closing libMesh stuff.
827 16600 : std::set_terminate(_old_terminate_handler);
828 : #endif
829 :
830 : #ifdef LIBMESH_HAVE_NETGEN
831 16600 : nglib::Ng_Exit();
832 : #endif
833 :
834 32732 : if (libMesh::on_command_line("--enable-fpe"))
835 0 : libMesh::enableFPE(false);
836 :
837 : #if defined(LIBMESH_HAVE_PETSC)
838 : // Let PETSc know about all the command line objects that we
839 : // consumed without asking them, so we don't get unused option
840 : // warnings about those.
841 17316 : std::vector<std::string> cli_names = command_line_names();
842 546244 : for (const auto & name : cli_names)
843 529864 : if (!name.empty() && name[0] == '-')
844 : {
845 : // Newer PETSc can give me a double-free I'm having trouble
846 : // replicating; let's protect against trying to clear
847 : // already-used values
848 517202 : PetscBool used = PETSC_FALSE;
849 517202 : auto ierr = PetscOptionsUsed(NULL, name.c_str(), &used);
850 517202 : CHKERRABORT(libMesh::GLOBAL_COMM_WORLD, ierr);
851 517202 : if (used == PETSC_FALSE)
852 : {
853 517202 : ierr = PetscOptionsClearValue(NULL, name.c_str());
854 517202 : CHKERRABORT(libMesh::GLOBAL_COMM_WORLD, ierr);
855 : }
856 : }
857 :
858 : // Allow the user to bypass PETSc finalization
859 32760 : if (!libMesh::on_command_line ("--disable-petsc")
860 : #if defined(LIBMESH_HAVE_MPI)
861 32760 : && !libMesh::on_command_line ("--disable-mpi")
862 : #endif
863 : )
864 : {
865 468 : PetscErrorCode ierr = LIBMESH_PETSC_SUCCESS;
866 : # if defined(LIBMESH_HAVE_SLEPC)
867 16380 : if (libmesh_initialized_slepc)
868 16380 : ierr = SlepcFinalize();
869 : # else
870 : if (libmesh_initialized_petsc)
871 : ierr = PetscFinalize();
872 : # endif
873 16380 : CHKERRABORT(libMesh::GLOBAL_COMM_WORLD, ierr);
874 : }
875 : #endif
876 :
877 : #if defined(LIBMESH_HAVE_MPI) && defined(LIBMESH_HAVE_VTK)
878 : _vtk_mpi_controller->Finalize(/*finalized_externally=*/1);
879 : _vtk_mpi_controller->Delete();
880 : #endif
881 :
882 32732 : delete this->_comm;
883 :
884 : #if defined(LIBMESH_HAVE_MPI)
885 : // Allow the user to bypass MPI finalization
886 32732 : if (!libMesh::on_command_line ("--disable-mpi"))
887 : {
888 16600 : delete this->_timpi_init;
889 : }
890 : #else
891 : delete this->_timpi_init;
892 : #endif
893 16600 : }
894 :
895 :
896 0 : PerfLog & LibMeshInit::perf_log()
897 : {
898 0 : return libMesh::perflog;
899 : }
900 :
901 :
902 :
903 4734919 : void add_command_line_name(const std::string & name)
904 : {
905 : // Users had better not be asking about an empty string
906 123714 : libmesh_assert(!name.empty());
907 :
908 : static std::mutex command_line_names_mutex;
909 247428 : std::scoped_lock lock(command_line_names_mutex);
910 :
911 4611245 : command_line_name_set.insert(name);
912 4734919 : }
913 :
914 :
915 :
916 71 : void add_command_line_names(const GetPot & getpot)
917 : {
918 213 : for (auto & getter : {&GetPot::get_requested_arguments,
919 : &GetPot::get_requested_variables,
920 284 : &GetPot::get_requested_sections})
921 10591 : for (const std::string & name : (getpot.*getter)())
922 10372 : add_command_line_name(name);
923 71 : }
924 :
925 :
926 16380 : std::vector<std::string> command_line_names()
927 : {
928 : return std::vector<std::string>(command_line_name_set.begin(),
929 16380 : command_line_name_set.end());
930 : }
931 :
932 :
933 :
934 4668518 : bool on_command_line (std::string arg)
935 : {
936 : // Make sure the command line parser is ready for use. If it's not,
937 : // then we'll have to treat the command line as empty, for maximum
938 : // compatibility with programs that don't use LibMeshInit but
939 : // indirectly (e.g. via error handling code) query the command line.
940 4668518 : if (!command_line.get())
941 0 : return false;
942 :
943 : // Keep track of runtime queries, for later
944 4668518 : add_command_line_name(arg);
945 :
946 121640 : bool found_it = command_line->search(arg);
947 :
948 4668518 : if (!found_it)
949 : {
950 : // Try with all dashes instead of underscores
951 121082 : std::replace(arg.begin(), arg.end(), '_', '-');
952 121082 : found_it = command_line->search(arg);
953 : }
954 :
955 4653900 : if (!found_it)
956 : {
957 : // OK, try with all underscores instead of dashes
958 121080 : auto name_begin = arg.begin();
959 13950716 : while (*name_begin == '-')
960 241830 : ++name_begin;
961 121080 : std::replace(name_begin, arg.end(), '-', '_');
962 121080 : found_it = command_line->search(arg);
963 : }
964 :
965 121640 : return found_it;
966 : }
967 :
968 :
969 :
970 : template <typename T>
971 386245 : T command_line_value (const std::string & name, T value)
972 : {
973 : // Make sure the command line parser is ready for use
974 11166 : libmesh_assert(command_line.get());
975 :
976 : // only if the variable exists in the file
977 11166 : if (command_line->have_variable(name))
978 : {
979 2776 : value = (*command_line)(name, value);
980 :
981 : // Keep track of runtime queries, for later. GetPot splits
982 : // foo=bar into a separate name=value, so we can query for the
983 : // name, but as far as PETSc is concerned that's one CLI
984 : // argument. We'll store it that way.
985 120 : const std::string stringvalue =
986 2174 : (*command_line)(name, std::string());
987 4408 : add_command_line_name(name+"="+stringvalue);
988 : }
989 :
990 386245 : return value;
991 : }
992 :
993 : template <typename T>
994 16600 : T command_line_value (const std::vector<std::string> & names, T value)
995 : {
996 : // Make sure the command line parser is ready for use
997 468 : libmesh_assert(command_line.get());
998 :
999 : // Keep track of runtime queries, for later
1000 49800 : for (const auto & entry : names)
1001 : {
1002 : // Keep track of runtime queries, for later. GetPot splits
1003 : // foo=bar into a separate name=value, so we can query for the
1004 : // name, but as far as PETSc is concerned that's one CLI
1005 : // argument. We'll store it that way.
1006 1872 : const std::string stringvalue =
1007 32264 : (*command_line)(entry, std::string());
1008 65464 : add_command_line_name(entry+"="+stringvalue);
1009 : }
1010 :
1011 : // Check for multiple options (return the first that matches)
1012 47488 : for (const auto & entry : names)
1013 594 : if (command_line->have_variable(entry))
1014 : {
1015 1156 : value = (*command_line)(entry, value);
1016 1156 : break;
1017 : }
1018 :
1019 16600 : return value;
1020 : }
1021 :
1022 :
1023 :
1024 : template <typename T>
1025 20315 : T command_line_next (std::string name, T value)
1026 : {
1027 : // Make sure the command line parser is ready for use
1028 776 : libmesh_assert(command_line.get());
1029 :
1030 : // Keep track of runtime queries, for later
1031 20315 : add_command_line_name(name);
1032 :
1033 : // on_command_line also puts the command_line cursor in the spot we
1034 : // need
1035 39854 : if (on_command_line(name))
1036 12920 : return command_line->next(value);
1037 :
1038 7285 : return value;
1039 : }
1040 :
1041 :
1042 :
1043 : template <typename T>
1044 280 : void command_line_vector (const std::string & name, std::vector<T> & vec)
1045 : {
1046 : // Make sure the command line parser is ready for use
1047 8 : libmesh_assert(command_line.get());
1048 :
1049 : // Keep track of runtime queries, for later
1050 280 : add_command_line_name(name);
1051 :
1052 : // only if the variable exists on the command line
1053 8 : if (command_line->have_variable(name))
1054 : {
1055 8 : unsigned size = command_line->vector_variable_size(name);
1056 280 : vec.resize(size);
1057 :
1058 560 : for (unsigned i=0; i<size; ++i)
1059 280 : vec[i] = (*command_line)(name, vec[i], i);
1060 : }
1061 280 : }
1062 :
1063 :
1064 2005774 : SolverPackage default_solver_package ()
1065 : {
1066 58644 : libmesh_assert (libMesh::initialized());
1067 :
1068 : static bool called = false;
1069 :
1070 : // Check the command line. Since the command line is
1071 : // unchanging it is sufficient to do this only once.
1072 2005774 : if (!called)
1073 : {
1074 15121 : called = true;
1075 :
1076 : #ifdef LIBMESH_HAVE_PETSC
1077 29402 : if (libMesh::on_command_line ("--use-petsc"))
1078 0 : libMeshPrivateData::_solver_package = PETSC_SOLVERS;
1079 : #endif
1080 :
1081 : #ifdef LIBMESH_TRILINOS_HAVE_AZTECOO
1082 : if (libMesh::on_command_line ("--use-trilinos") ||
1083 : libMesh::on_command_line ("--disable-petsc"))
1084 : libMeshPrivateData::_solver_package = TRILINOS_SOLVERS;
1085 : #endif
1086 :
1087 : #ifdef LIBMESH_HAVE_EIGEN
1088 44935 : if (libMesh::on_command_line ("--use-eigen" ) ||
1089 : #if defined(LIBMESH_HAVE_MPI)
1090 : // If the user bypassed MPI, we disable PETSc and Trilinos
1091 : // too
1092 31526 : libMesh::on_command_line ("--disable-mpi") ||
1093 : #endif
1094 30670 : libMesh::on_command_line ("--disable-petsc"))
1095 0 : libMeshPrivateData::_solver_package = EIGEN_SOLVERS;
1096 : #endif
1097 :
1098 : #ifdef LIBMESH_HAVE_LASPACK
1099 2140 : if (libMesh::on_command_line ("--use-laspack" ) ||
1100 : #if defined(LIBMESH_HAVE_MPI)
1101 : // If the user bypassed MPI, we disable PETSc and Trilinos
1102 : // too
1103 2996 : libMesh::on_command_line ("--disable-mpi") ||
1104 : #endif
1105 2140 : libMesh::on_command_line ("--disable-petsc"))
1106 0 : libMeshPrivateData::_solver_package = LASPACK_SOLVERS;
1107 : #endif
1108 :
1109 30242 : if (libMesh::on_command_line ("--disable-laspack") &&
1110 15121 : libMesh::on_command_line ("--disable-trilinos") &&
1111 30670 : libMesh::on_command_line ("--disable-eigen") &&
1112 : (
1113 : #if defined(LIBMESH_HAVE_MPI)
1114 : // If the user bypassed MPI, we disable PETSc too
1115 15121 : libMesh::on_command_line ("--disable-mpi") ||
1116 : #endif
1117 15121 : libMesh::on_command_line ("--disable-petsc")))
1118 0 : libMeshPrivateData::_solver_package = INVALID_SOLVER_PACKAGE;
1119 : }
1120 :
1121 :
1122 2005774 : return libMeshPrivateData::_solver_package;
1123 : }
1124 :
1125 :
1126 :
1127 : //-------------------------------------------------------------------------------
1128 : template LIBMESH_EXPORT unsigned char command_line_value<unsigned char> (const std::string &, unsigned char);
1129 : template LIBMESH_EXPORT unsigned short command_line_value<unsigned short> (const std::string &, unsigned short);
1130 : template LIBMESH_EXPORT unsigned int command_line_value<unsigned int> (const std::string &, unsigned int);
1131 : template LIBMESH_EXPORT char command_line_value<char> (const std::string &, char);
1132 : template LIBMESH_EXPORT short command_line_value<short> (const std::string &, short);
1133 : template LIBMESH_EXPORT int command_line_value<int> (const std::string &, int);
1134 : template LIBMESH_EXPORT float command_line_value<float> (const std::string &, float);
1135 : template LIBMESH_EXPORT double command_line_value<double> (const std::string &, double);
1136 : template LIBMESH_EXPORT long double command_line_value<long double> (const std::string &, long double);
1137 : template LIBMESH_EXPORT std::string command_line_value<std::string> (const std::string &, std::string);
1138 :
1139 : template LIBMESH_EXPORT unsigned char command_line_value<unsigned char> (const std::vector<std::string> &, unsigned char);
1140 : template LIBMESH_EXPORT unsigned short command_line_value<unsigned short> (const std::vector<std::string> &, unsigned short);
1141 : template LIBMESH_EXPORT unsigned int command_line_value<unsigned int> (const std::vector<std::string> &, unsigned int);
1142 : template LIBMESH_EXPORT char command_line_value<char> (const std::vector<std::string> &, char);
1143 : template LIBMESH_EXPORT short command_line_value<short> (const std::vector<std::string> &, short);
1144 : template LIBMESH_EXPORT int command_line_value<int> (const std::vector<std::string> &, int);
1145 : template LIBMESH_EXPORT float command_line_value<float> (const std::vector<std::string> &, float);
1146 : template LIBMESH_EXPORT double command_line_value<double> (const std::vector<std::string> &, double);
1147 : template LIBMESH_EXPORT long double command_line_value<long double> (const std::vector<std::string> &, long double);
1148 : template LIBMESH_EXPORT std::string command_line_value<std::string> (const std::vector<std::string> &, std::string);
1149 :
1150 : template LIBMESH_EXPORT unsigned char command_line_next<unsigned char> (std::string, unsigned char);
1151 : template LIBMESH_EXPORT unsigned short command_line_next<unsigned short> (std::string, unsigned short);
1152 : template LIBMESH_EXPORT unsigned int command_line_next<unsigned int> (std::string, unsigned int);
1153 : template LIBMESH_EXPORT char command_line_next<char> (std::string, char);
1154 : template LIBMESH_EXPORT short command_line_next<short> (std::string, short);
1155 : template LIBMESH_EXPORT int command_line_next<int> (std::string, int);
1156 : template LIBMESH_EXPORT float command_line_next<float> (std::string, float);
1157 : template LIBMESH_EXPORT double command_line_next<double> (std::string, double);
1158 : template LIBMESH_EXPORT long double command_line_next<long double> (std::string, long double);
1159 : template LIBMESH_EXPORT std::string command_line_next<std::string> (std::string, std::string);
1160 :
1161 : template LIBMESH_EXPORT void command_line_vector<unsigned char> (const std::string &, std::vector<unsigned char> &);
1162 : template LIBMESH_EXPORT void command_line_vector<unsigned short>(const std::string &, std::vector<unsigned short> &);
1163 : template LIBMESH_EXPORT void command_line_vector<unsigned int> (const std::string &, std::vector<unsigned int> &);
1164 : template LIBMESH_EXPORT void command_line_vector<char> (const std::string &, std::vector<char> &);
1165 : template LIBMESH_EXPORT void command_line_vector<short> (const std::string &, std::vector<short> &);
1166 : template LIBMESH_EXPORT void command_line_vector<int> (const std::string &, std::vector<int> &);
1167 : template LIBMESH_EXPORT void command_line_vector<float> (const std::string &, std::vector<float> &);
1168 : template LIBMESH_EXPORT void command_line_vector<double> (const std::string &, std::vector<double> &);
1169 : template LIBMESH_EXPORT void command_line_vector<long double> (const std::string &, std::vector<long double> &);
1170 :
1171 : #ifdef LIBMESH_DEFAULT_QUADRUPLE_PRECISION
1172 : template LIBMESH_EXPORT Real command_line_value<Real> (const std::string &, Real);
1173 : template LIBMESH_EXPORT Real command_line_value<Real> (const std::vector<std::string> &, Real);
1174 : template LIBMESH_EXPORT Real command_line_next<Real> (std::string, Real);
1175 : template LIBMESH_EXPORT void command_line_vector<Real> (const std::string &, std::vector<Real> &);
1176 : #endif
1177 :
1178 : } // namespace libMesh
|