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 : bool libMesh::libMeshPrivateData::_is_initialized = false;
305 : SolverPackage libMesh::libMeshPrivateData::_solver_package =
306 : #if defined(LIBMESH_HAVE_PETSC) // PETSc is the default
307 : PETSC_SOLVERS;
308 : #elif defined(LIBMESH_TRILINOS_HAVE_AZTECOO) // Use Trilinos if PETSc isn't there
309 : TRILINOS_SOLVERS;
310 : #elif defined(LIBMESH_HAVE_EIGEN) // Use Eigen if neither are there
311 : EIGEN_SOLVERS;
312 : #elif defined(LIBMESH_HAVE_LASPACK) // Use LASPACK as a last resort
313 : LASPACK_SOLVERS;
314 : #else // No valid linear solver package at compile time
315 : INVALID_SOLVER_PACKAGE;
316 : #endif
317 :
318 :
319 :
320 : // ------------------------------------------------------------
321 : // libMesh functions
322 :
323 79692 : bool initialized()
324 : {
325 79692 : return libMeshPrivateData::_is_initialized;
326 : }
327 :
328 :
329 :
330 28740 : bool closed()
331 : {
332 28740 : return !libMeshPrivateData::_is_initialized;
333 : }
334 :
335 :
336 :
337 0 : void libmesh_abort()
338 : {
339 0 : libMesh::perflog.clear();
340 :
341 : // Now that we're done with output we should clean up our stream
342 : // buffers; if we fail to uninstall_thread_buffered_sync() when
343 : // needed we can end up seeing a segfault in iostreams destructors
344 0 : cleanup_stream_buffers();
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 : LibMeshInit::_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 16600 : LibMeshInit::LibMeshInit (int argc, const char * const * argv,
370 16600 : TIMPI::communicator COMM_WORLD_IN, int n_threads)
371 : {
372 : // should _not_ be initialized already.
373 468 : libmesh_assert (!libMesh::initialized());
374 :
375 : // Build a command-line parser.
376 32264 : command_line = std::make_unique<GetPot>(argc, argv);
377 :
378 : // Disable performance logging upon request
379 : {
380 32732 : if (libMesh::on_command_line ("--disable-perflog"))
381 0 : libMesh::perflog.disable_logging();
382 : }
383 :
384 47488 : auto check_empty_command_line_value = [](auto & cl, const std::string & option) {
385 47488 : libmesh_error_msg_if(cl.search(option),
386 : "Detected option " << option << " with no value. Did you forget '='?");
387 47488 : };
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 17068 : std::vector<std::string> n_threads_opt(2);
396 936 : n_threads_opt[0] = "--n_threads";
397 936 : n_threads_opt[1] = "--n-threads";
398 16600 : libMesh::libMeshPrivateData::_n_threads =
399 16600 : libMesh::command_line_value(n_threads_opt, n_threads);
400 :
401 16600 : if (libMesh::libMeshPrivateData::_n_threads == -1)
402 : {
403 46332 : for (auto & option : n_threads_opt)
404 30888 : check_empty_command_line_value(*command_line, option);
405 :
406 15444 : 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 16600 : omp_set_num_threads(libMesh::libMeshPrivateData::_n_threads);
422 : #endif
423 :
424 16132 : task_scheduler = std::make_unique<Threads::task_scheduler_init>(libMesh::n_threads());
425 15664 : }
426 :
427 : // Construct singletons who may be at risk of the
428 : // "static initialization order fiasco"
429 16600 : Singleton::setup();
430 :
431 : // Make sure the construction worked
432 468 : libmesh_assert(remote_elem);
433 :
434 16600 : const bool using_threads = libMesh::n_threads() > 1;
435 468 : 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 32732 : if (!libMesh::on_command_line ("--disable-mpi"))
441 : {
442 16600 : int mpi_thread_request = using_threads;
443 33668 : const auto mpi_thread_type = libMesh::command_line_value("--mpi-thread-type", std::string(""));
444 16600 : if (mpi_thread_type.empty())
445 : {
446 32732 : 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 16600 : this->_timpi_init =
480 : new TIMPI::TIMPIInit(argc, argv, mpi_thread_request,
481 16600 : handle_mpi_errors, COMM_WORLD_IN);
482 16600 : _comm = new Parallel::Communicator(this->_timpi_init->comm().get());
483 :
484 : const std::string timpi_sync =
485 33668 : libMesh::command_line_value("--timpi-sync", std::string("nbx"));
486 16600 : _comm->sync_type(timpi_sync);
487 :
488 16600 : 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 16600 : libMeshPrivateData::_processor_id =
494 936 : cast_int<processor_id_type>(this->comm().rank());
495 16600 : libMeshPrivateData::_n_processors =
496 936 : 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 32732 : 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 468 : 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 468 : 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 32760 : 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 32760 : && !libMesh::on_command_line ("--disable-mpi")
538 : #endif
539 : )
540 : {
541 : #ifdef LIBMESH_HAVE_MPI
542 16380 : 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 16380 : LibmeshPetscCallA(libMesh::GLOBAL_COMM_WORLD, PetscInitialized(&petsc_already_initialized));
552 16380 : if (petsc_already_initialized != PETSC_TRUE)
553 16380 : 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 16380 : if (!SlepcInitializeCalled)
562 : {
563 16380 : LibmeshPetscCallA(libMesh::GLOBAL_COMM_WORLD, SlepcInitialize (&argc, const_cast<char ***>(&argv), nullptr, nullptr));
564 16380 : 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 16380 : LibmeshPetscCallA(libMesh::GLOBAL_COMM_WORLD, DMRegister(DMLIBMESH, DMCreate_libMesh));
572 : }
573 : #endif
574 :
575 : #ifdef LIBMESH_HAVE_NETGEN
576 16600 : 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 32264 : command_line = std::make_unique<GetPot>(argc, argv);
596 :
597 : // Not syncing with stdio 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 : // However, not syncing the streams means thread safety is no longer
603 : // guaranteed and we have indeed seen thread sanitizer warnings
604 : // during concurrent writes to std::cout when toggling this boolean
605 : // to true. We default to preferring safety and correctness instead
606 : // of performance
607 32732 : if (libMesh::on_command_line ("--dont-sync-with-stdio"))
608 0 : std::ios::sync_with_stdio(false);
609 :
610 : // Honor the --separate-libmeshout command-line option.
611 : // When this is specified, the library uses an independent ostream
612 : // for libMesh::out/libMesh::err messages, and
613 : // std::cout and std::cerr are untouched by any other options
614 32732 : if (libMesh::on_command_line ("--separate-libmeshout"))
615 : {
616 : // Redirect. We'll share streambufs with cout/cerr for now, but
617 : // presumably anyone using this option will want to replace the
618 : // bufs later.
619 0 : std::ostream * newout = new std::ostream(std::cout.rdbuf());
620 0 : libMesh::out = *newout;
621 0 : std::ostream * newerr = new std::ostream(std::cerr.rdbuf());
622 0 : libMesh::err = *newerr;
623 : }
624 :
625 : // Process command line arguments for redirecting stdout/stderr.
626 : bool
627 16600 : cmdline_has_redirect_stdout = libMesh::on_command_line ("--redirect-stdout"),
628 16600 : cmdline_has_redirect_output = libMesh::on_command_line ("--redirect-output");
629 :
630 : // The --redirect-stdout command-line option has been deprecated in
631 : // favor of "--redirect-output basename".
632 : if (cmdline_has_redirect_stdout)
633 : libmesh_warning("The --redirect-stdout command line option has been deprecated. "
634 : "Use '--redirect-output basename' instead.");
635 :
636 : // Honor the "--redirect-stdout" and "--redirect-output basename"
637 : // command-line options. When one of these is specified, each
638 : // processor sends libMesh::out/libMesh::err messages to
639 : // stdout.processor.#### (default) or basename.processor.####.
640 16600 : if (cmdline_has_redirect_stdout || cmdline_has_redirect_output)
641 : {
642 0 : std::string basename = "stdout";
643 :
644 : // Look for following argument if using new API
645 0 : if (cmdline_has_redirect_output)
646 : {
647 : // Set the cursor to the correct location in the list of command line arguments.
648 0 : command_line->search(1, "--redirect-output");
649 :
650 : // Get the next option on the command line as a string.
651 0 : std::string next_string = "";
652 0 : next_string = command_line->next(next_string);
653 :
654 : // If the next string starts with a dash, we assume it's
655 : // another flag and not a file basename requested by the
656 : // user.
657 0 : if (next_string.size() > 0 && next_string.find_first_of("-") != 0)
658 0 : basename = next_string;
659 : }
660 :
661 0 : std::ostringstream filename;
662 0 : filename << basename << ".processor." << libMesh::global_processor_id();
663 0 : _ofstream = std::make_unique<std::ofstream>(filename.str().c_str());
664 :
665 : // Redirect, saving the original streambufs!
666 0 : out_buf = libMesh::out.rdbuf (_ofstream->rdbuf());
667 0 : err_buf = libMesh::err.rdbuf (_ofstream->rdbuf());
668 0 : }
669 :
670 : // redirect libMesh::out to nothing on all
671 : // other processors unless explicitly told
672 : // not to via the --keep-cout command-line argument.
673 32732 : if (!libMesh::on_command_line ("--keep-cout"))
674 16600 : if (libMesh::global_processor_id() != 0)
675 13806 : libMesh::out.rdbuf (nullptr);
676 :
677 : // Similarly, the user can request to drop cerr on all non-0 ranks.
678 : // By default, errors are printed on all ranks, but this can lead to
679 : // interleaved/unpredictable outputs when doing parallel regression
680 : // testing, which this option is designed to support.
681 32732 : if (libMesh::on_command_line ("--drop-cerr"))
682 0 : if (libMesh::global_processor_id() != 0)
683 0 : libMesh::err.rdbuf (nullptr);
684 :
685 : // Now that we've finished setting our stream buffers, let's wrap them (if they're non-null) in our thread-safe wrapper
686 32732 : if (!libMesh::on_command_line ("--disable-thread-safe-output"))
687 16600 : install_thread_buffered_sync();
688 :
689 : // Check command line to override printing
690 : // of reference count information.
691 32732 : if (libMesh::on_command_line("--disable-refcount-printing"))
692 0 : ReferenceCounter::disable_print_counter_info();
693 :
694 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
695 : // Set our terminate handler to write stack traces in the event of a
696 : // crash
697 16600 : _old_terminate_handler = std::set_terminate(libmesh_terminate_handler);
698 : #endif
699 :
700 :
701 32732 : if (libMesh::on_command_line("--enable-fpe"))
702 0 : libMesh::enableFPE(true);
703 :
704 32732 : if (libMesh::on_command_line("--enable-segv"))
705 0 : libMesh::enableSEGV(true);
706 :
707 32732 : if (libMesh::on_command_line("--enable-sigint"))
708 0 : libMesh::enableSIGINT(true);
709 :
710 : #if defined(LIBMESH_HAVE_HDF5) && !defined(_MSC_VER)
711 : // We may be running with ExodusII configured not to use HDF5 (in
712 : // which case user code which wants to lock files has to do flock()
713 : // itself) or with ExodusII configured to use HDF5 (which will
714 : // helpfully try to get an exclusive flock() itself, and then scream
715 : // and die if user code has already locked the file. To get
716 : // consistent behavior, we need to disable file locking. The only
717 : // reliable way I can see to do this is via an HDF5 environment
718 : // variable.
719 : //
720 : // If the user set this environment variable then we'll trust that
721 : // they know what they're doing. If not then we'll set FALSE,
722 : // because that's a better default for us than the unset default.
723 468 : setenv("HDF5_USE_FILE_LOCKING", "FALSE", /*overwrite=false*/0);
724 : #endif // LIBMESH_HAVE_HDF5
725 :
726 : // The library is now ready for use
727 16600 : libMeshPrivateData::_is_initialized = true;
728 :
729 :
730 : // Make sure these work. Library methods
731 : // depend on these being implemented properly,
732 : // so this is a good time to test them!
733 468 : libmesh_assert (libMesh::initialized());
734 468 : libmesh_assert (!libMesh::closed());
735 16600 : }
736 :
737 :
738 :
739 17536 : LibMeshInit::~LibMeshInit()
740 : {
741 : // Every processor had better be ready to exit at the same time.
742 : // Even if we're not doing parallel_only debugging, we don't want
743 : // one processor to try to exit until all others are done working.
744 :
745 : // We could be destructing here because we're unwinding the stack
746 : // due to a thrown exception, though. It's possible that an
747 : // application is catching exceptions outside of the LibMeshInit
748 : // scope, or that we're using a C++ compiler that does unwinding
749 : // for uncaught exceptions (the standard says whether to go straight
750 : // to terminate() or unwind first is "implementation-defined"). If
751 : // *that* is the case then we can't safely communicate with other
752 : // processors that might not all be unwinding too.
753 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
754 16600 : if (!std::uncaught_exceptions())
755 : #endif
756 16600 : this->comm().barrier();
757 :
758 : // We can't delete, finalize, etc. more than once without
759 : // reinitializing in between
760 468 : libmesh_exceptionless_assert(!libMesh::closed());
761 :
762 : // Delete reference counted singleton(s)
763 16600 : Singleton::cleanup();
764 :
765 : // Clear the thread task manager we started
766 468 : task_scheduler.reset();
767 :
768 : // If we have a memory leak, we want the details printed.
769 16600 : if (ReferenceCounter::n_objects() != 0)
770 0 : ReferenceCounter::enable_print_counter_info();
771 :
772 : // Ask the \p ReferenceCounter to print its reference count
773 : // information, if printing is enabled. This allows us to find
774 : // memory leaks.
775 : //
776 : // If we don't have any leaks, we'll print to cout, only if we've
777 : // been told to. If we do, we'll print to cerr, to make sure the
778 : // user doesn't miss a leak that's only on a processor other than 0.
779 16600 : if (ReferenceCounter::n_objects() == 0)
780 16600 : ReferenceCounter::print_info ();
781 :
782 : // Scream specifically if we detect a memory leak
783 16600 : if (ReferenceCounter::n_objects() != 0)
784 : {
785 0 : ReferenceCounter::print_info (libMesh::err);
786 :
787 0 : libMesh::err << "Memory leak detected!"
788 0 : << std::endl;
789 :
790 : #if !defined(LIBMESH_ENABLE_REFERENCE_COUNTING) || defined(NDEBUG)
791 :
792 : libMesh::err << "Compile in DEBUG mode with --enable-reference-counting"
793 : << std::endl
794 : << "for more information"
795 : << std::endl;
796 : #endif
797 : }
798 :
799 : // print the perflog to individual processor's file.
800 16600 : libMesh::perflog.print_log();
801 :
802 : // Now clear the logging object, we don't want it to print
803 : // a second time during the PerfLog destructor.
804 16600 : libMesh::perflog.clear();
805 :
806 : // Reconnect the output streams
807 : // (don't do this, or we will get messages from objects
808 : // that go out of scope after the following return)
809 : //std::cout.rdbuf(std::cerr.rdbuf());
810 :
811 :
812 : // Set the initialized() flag to false
813 16600 : libMeshPrivateData::_is_initialized = false;
814 :
815 16600 : cleanup_stream_buffers();
816 :
817 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
818 : // Reset the old terminate handler; maybe the user code wants to
819 : // keep doing C++ stuff after closing libMesh stuff.
820 16600 : std::set_terminate(_old_terminate_handler);
821 : #endif
822 :
823 : #ifdef LIBMESH_HAVE_NETGEN
824 16600 : nglib::Ng_Exit();
825 : #endif
826 :
827 32732 : if (libMesh::on_command_line("--enable-fpe"))
828 0 : libMesh::enableFPE(false);
829 :
830 : #if defined(LIBMESH_HAVE_PETSC)
831 : // Let PETSc know about all the command line objects that we
832 : // consumed without asking them, so we don't get unused option
833 : // warnings about those.
834 17316 : std::vector<std::string> cli_names = command_line_names();
835 546244 : for (const auto & name : cli_names)
836 529864 : if (!name.empty() && name[0] == '-')
837 : {
838 : // Newer PETSc can give me a double-free I'm having trouble
839 : // replicating; let's protect against trying to clear
840 : // already-used values
841 517202 : PetscBool used = PETSC_FALSE;
842 517202 : auto ierr = PetscOptionsUsed(NULL, name.c_str(), &used);
843 517202 : CHKERRABORT(libMesh::GLOBAL_COMM_WORLD, ierr);
844 517202 : if (used == PETSC_FALSE)
845 : {
846 517202 : ierr = PetscOptionsClearValue(NULL, name.c_str());
847 517202 : CHKERRABORT(libMesh::GLOBAL_COMM_WORLD, ierr);
848 : }
849 : }
850 :
851 : // Allow the user to bypass PETSc finalization
852 32760 : if (!libMesh::on_command_line ("--disable-petsc")
853 : #if defined(LIBMESH_HAVE_MPI)
854 32760 : && !libMesh::on_command_line ("--disable-mpi")
855 : #endif
856 : )
857 : {
858 468 : PetscErrorCode ierr = LIBMESH_PETSC_SUCCESS;
859 : # if defined(LIBMESH_HAVE_SLEPC)
860 16380 : if (libmesh_initialized_slepc)
861 16380 : ierr = SlepcFinalize();
862 : # else
863 : if (libmesh_initialized_petsc)
864 : ierr = PetscFinalize();
865 : # endif
866 16380 : CHKERRABORT(libMesh::GLOBAL_COMM_WORLD, ierr);
867 : }
868 : #endif
869 :
870 : #if defined(LIBMESH_HAVE_MPI) && defined(LIBMESH_HAVE_VTK)
871 : _vtk_mpi_controller->Finalize(/*finalized_externally=*/1);
872 : _vtk_mpi_controller->Delete();
873 : #endif
874 :
875 32732 : delete this->_comm;
876 :
877 : #if defined(LIBMESH_HAVE_MPI)
878 : // Allow the user to bypass MPI finalization
879 32732 : if (!libMesh::on_command_line ("--disable-mpi"))
880 : {
881 16600 : delete this->_timpi_init;
882 : }
883 : #else
884 : delete this->_timpi_init;
885 : #endif
886 16600 : }
887 :
888 :
889 0 : PerfLog & LibMeshInit::perf_log()
890 : {
891 0 : return libMesh::perflog;
892 : }
893 :
894 :
895 :
896 4747621 : void add_command_line_name(const std::string & name)
897 : {
898 : // Users had better not be asking about an empty string
899 123930 : libmesh_assert(!name.empty());
900 :
901 : static std::mutex command_line_names_mutex;
902 247860 : std::scoped_lock lock(command_line_names_mutex);
903 :
904 4623731 : command_line_name_set.insert(name);
905 4747621 : }
906 :
907 :
908 :
909 71 : void add_command_line_names(const GetPot & getpot)
910 : {
911 213 : for (auto & getter : {&GetPot::get_requested_arguments,
912 : &GetPot::get_requested_variables,
913 284 : &GetPot::get_requested_sections})
914 10591 : for (const std::string & name : (getpot.*getter)())
915 10372 : add_command_line_name(name);
916 71 : }
917 :
918 :
919 16380 : std::vector<std::string> command_line_names()
920 : {
921 : return std::vector<std::string>(command_line_name_set.begin(),
922 16380 : command_line_name_set.end());
923 : }
924 :
925 :
926 :
927 4681220 : bool on_command_line (std::string arg)
928 : {
929 : // Make sure the command line parser is ready for use. If it's not,
930 : // then we'll have to treat the command line as empty, for maximum
931 : // compatibility with programs that don't use LibMeshInit but
932 : // indirectly (e.g. via error handling code) query the command line.
933 4681220 : if (!command_line.get())
934 0 : return false;
935 :
936 : // Keep track of runtime queries, for later
937 4681220 : add_command_line_name(arg);
938 :
939 121856 : bool found_it = command_line->search(arg);
940 :
941 4681220 : if (!found_it)
942 : {
943 : // Try with all dashes instead of underscores
944 121298 : std::replace(arg.begin(), arg.end(), '_', '-');
945 121298 : found_it = command_line->search(arg);
946 : }
947 :
948 4666602 : if (!found_it)
949 : {
950 : // OK, try with all underscores instead of dashes
951 121296 : auto name_begin = arg.begin();
952 13988822 : while (*name_begin == '-')
953 242262 : ++name_begin;
954 121296 : std::replace(name_begin, arg.end(), '-', '_');
955 121296 : found_it = command_line->search(arg);
956 : }
957 :
958 121856 : return found_it;
959 : }
960 :
961 :
962 :
963 : template <typename T>
964 370497 : T command_line_value (const std::string & name, T value)
965 : {
966 : // Make sure the command line parser is ready for use
967 10722 : libmesh_assert(command_line.get());
968 :
969 : // only if the variable exists in the file
970 10722 : if (command_line->have_variable(name))
971 : {
972 2776 : value = (*command_line)(name, value);
973 :
974 : // Keep track of runtime queries, for later. GetPot splits
975 : // foo=bar into a separate name=value, so we can query for the
976 : // name, but as far as PETSc is concerned that's one CLI
977 : // argument. We'll store it that way.
978 120 : const std::string stringvalue =
979 2174 : (*command_line)(name, std::string());
980 4408 : add_command_line_name(name+"="+stringvalue);
981 : }
982 :
983 370497 : return value;
984 : }
985 :
986 : template <typename T>
987 16600 : T command_line_value (const std::vector<std::string> & names, T value)
988 : {
989 : // Make sure the command line parser is ready for use
990 468 : libmesh_assert(command_line.get());
991 :
992 : // Keep track of runtime queries, for later
993 49800 : for (const auto & entry : names)
994 : {
995 : // Keep track of runtime queries, for later. GetPot splits
996 : // foo=bar into a separate name=value, so we can query for the
997 : // name, but as far as PETSc is concerned that's one CLI
998 : // argument. We'll store it that way.
999 1872 : const std::string stringvalue =
1000 32264 : (*command_line)(entry, std::string());
1001 65464 : add_command_line_name(entry+"="+stringvalue);
1002 : }
1003 :
1004 : // Check for multiple options (return the first that matches)
1005 47488 : for (const auto & entry : names)
1006 594 : if (command_line->have_variable(entry))
1007 : {
1008 1156 : value = (*command_line)(entry, value);
1009 1156 : break;
1010 : }
1011 :
1012 16600 : return value;
1013 : }
1014 :
1015 :
1016 :
1017 : template <typename T>
1018 20315 : T command_line_next (std::string name, T value)
1019 : {
1020 : // Make sure the command line parser is ready for use
1021 776 : libmesh_assert(command_line.get());
1022 :
1023 : // Keep track of runtime queries, for later
1024 20315 : add_command_line_name(name);
1025 :
1026 : // on_command_line also puts the command_line cursor in the spot we
1027 : // need
1028 39854 : if (on_command_line(name))
1029 12920 : return command_line->next(value);
1030 :
1031 7285 : return value;
1032 : }
1033 :
1034 :
1035 :
1036 : template <typename T>
1037 280 : void command_line_vector (const std::string & name, std::vector<T> & vec)
1038 : {
1039 : // Make sure the command line parser is ready for use
1040 8 : libmesh_assert(command_line.get());
1041 :
1042 : // Keep track of runtime queries, for later
1043 280 : add_command_line_name(name);
1044 :
1045 : // only if the variable exists on the command line
1046 8 : if (command_line->have_variable(name))
1047 : {
1048 8 : unsigned size = command_line->vector_variable_size(name);
1049 280 : vec.resize(size);
1050 :
1051 560 : for (unsigned i=0; i<size; ++i)
1052 280 : vec[i] = (*command_line)(name, vec[i], i);
1053 : }
1054 280 : }
1055 :
1056 :
1057 2005787 : SolverPackage default_solver_package ()
1058 : {
1059 58644 : libmesh_assert (libMesh::initialized());
1060 :
1061 : static bool called = false;
1062 :
1063 : // Check the command line. Since the command line is
1064 : // unchanging it is sufficient to do this only once.
1065 2005787 : if (!called)
1066 : {
1067 15121 : called = true;
1068 :
1069 : #ifdef LIBMESH_HAVE_PETSC
1070 29402 : if (libMesh::on_command_line ("--use-petsc"))
1071 0 : libMeshPrivateData::_solver_package = PETSC_SOLVERS;
1072 : #endif
1073 :
1074 : #ifdef LIBMESH_TRILINOS_HAVE_AZTECOO
1075 : if (libMesh::on_command_line ("--use-trilinos") ||
1076 : libMesh::on_command_line ("--disable-petsc"))
1077 : libMeshPrivateData::_solver_package = TRILINOS_SOLVERS;
1078 : #endif
1079 :
1080 : #ifdef LIBMESH_HAVE_EIGEN
1081 44935 : if (libMesh::on_command_line ("--use-eigen" ) ||
1082 : #if defined(LIBMESH_HAVE_MPI)
1083 : // If the user bypassed MPI, we disable PETSc and Trilinos
1084 : // too
1085 31526 : libMesh::on_command_line ("--disable-mpi") ||
1086 : #endif
1087 30670 : libMesh::on_command_line ("--disable-petsc"))
1088 0 : libMeshPrivateData::_solver_package = EIGEN_SOLVERS;
1089 : #endif
1090 :
1091 : #ifdef LIBMESH_HAVE_LASPACK
1092 2140 : if (libMesh::on_command_line ("--use-laspack" ) ||
1093 : #if defined(LIBMESH_HAVE_MPI)
1094 : // If the user bypassed MPI, we disable PETSc and Trilinos
1095 : // too
1096 2996 : libMesh::on_command_line ("--disable-mpi") ||
1097 : #endif
1098 2140 : libMesh::on_command_line ("--disable-petsc"))
1099 0 : libMeshPrivateData::_solver_package = LASPACK_SOLVERS;
1100 : #endif
1101 :
1102 30242 : if (libMesh::on_command_line ("--disable-laspack") &&
1103 15121 : libMesh::on_command_line ("--disable-trilinos") &&
1104 30670 : libMesh::on_command_line ("--disable-eigen") &&
1105 : (
1106 : #if defined(LIBMESH_HAVE_MPI)
1107 : // If the user bypassed MPI, we disable PETSc too
1108 15121 : libMesh::on_command_line ("--disable-mpi") ||
1109 : #endif
1110 15121 : libMesh::on_command_line ("--disable-petsc")))
1111 0 : libMeshPrivateData::_solver_package = INVALID_SOLVER_PACKAGE;
1112 : }
1113 :
1114 :
1115 2005787 : return libMeshPrivateData::_solver_package;
1116 : }
1117 :
1118 :
1119 :
1120 : //-------------------------------------------------------------------------------
1121 : template LIBMESH_EXPORT unsigned char command_line_value<unsigned char> (const std::string &, unsigned char);
1122 : template LIBMESH_EXPORT unsigned short command_line_value<unsigned short> (const std::string &, unsigned short);
1123 : template LIBMESH_EXPORT unsigned int command_line_value<unsigned int> (const std::string &, unsigned int);
1124 : template LIBMESH_EXPORT char command_line_value<char> (const std::string &, char);
1125 : template LIBMESH_EXPORT short command_line_value<short> (const std::string &, short);
1126 : template LIBMESH_EXPORT int command_line_value<int> (const std::string &, int);
1127 : template LIBMESH_EXPORT float command_line_value<float> (const std::string &, float);
1128 : template LIBMESH_EXPORT double command_line_value<double> (const std::string &, double);
1129 : template LIBMESH_EXPORT long double command_line_value<long double> (const std::string &, long double);
1130 : template LIBMESH_EXPORT std::string command_line_value<std::string> (const std::string &, std::string);
1131 :
1132 : template LIBMESH_EXPORT unsigned char command_line_value<unsigned char> (const std::vector<std::string> &, unsigned char);
1133 : template LIBMESH_EXPORT unsigned short command_line_value<unsigned short> (const std::vector<std::string> &, unsigned short);
1134 : template LIBMESH_EXPORT unsigned int command_line_value<unsigned int> (const std::vector<std::string> &, unsigned int);
1135 : template LIBMESH_EXPORT char command_line_value<char> (const std::vector<std::string> &, char);
1136 : template LIBMESH_EXPORT short command_line_value<short> (const std::vector<std::string> &, short);
1137 : template LIBMESH_EXPORT int command_line_value<int> (const std::vector<std::string> &, int);
1138 : template LIBMESH_EXPORT float command_line_value<float> (const std::vector<std::string> &, float);
1139 : template LIBMESH_EXPORT double command_line_value<double> (const std::vector<std::string> &, double);
1140 : template LIBMESH_EXPORT long double command_line_value<long double> (const std::vector<std::string> &, long double);
1141 : template LIBMESH_EXPORT std::string command_line_value<std::string> (const std::vector<std::string> &, std::string);
1142 :
1143 : template LIBMESH_EXPORT unsigned char command_line_next<unsigned char> (std::string, unsigned char);
1144 : template LIBMESH_EXPORT unsigned short command_line_next<unsigned short> (std::string, unsigned short);
1145 : template LIBMESH_EXPORT unsigned int command_line_next<unsigned int> (std::string, unsigned int);
1146 : template LIBMESH_EXPORT char command_line_next<char> (std::string, char);
1147 : template LIBMESH_EXPORT short command_line_next<short> (std::string, short);
1148 : template LIBMESH_EXPORT int command_line_next<int> (std::string, int);
1149 : template LIBMESH_EXPORT float command_line_next<float> (std::string, float);
1150 : template LIBMESH_EXPORT double command_line_next<double> (std::string, double);
1151 : template LIBMESH_EXPORT long double command_line_next<long double> (std::string, long double);
1152 : template LIBMESH_EXPORT std::string command_line_next<std::string> (std::string, std::string);
1153 :
1154 : template LIBMESH_EXPORT void command_line_vector<unsigned char> (const std::string &, std::vector<unsigned char> &);
1155 : template LIBMESH_EXPORT void command_line_vector<unsigned short>(const std::string &, std::vector<unsigned short> &);
1156 : template LIBMESH_EXPORT void command_line_vector<unsigned int> (const std::string &, std::vector<unsigned int> &);
1157 : template LIBMESH_EXPORT void command_line_vector<char> (const std::string &, std::vector<char> &);
1158 : template LIBMESH_EXPORT void command_line_vector<short> (const std::string &, std::vector<short> &);
1159 : template LIBMESH_EXPORT void command_line_vector<int> (const std::string &, std::vector<int> &);
1160 : template LIBMESH_EXPORT void command_line_vector<float> (const std::string &, std::vector<float> &);
1161 : template LIBMESH_EXPORT void command_line_vector<double> (const std::string &, std::vector<double> &);
1162 : template LIBMESH_EXPORT void command_line_vector<long double> (const std::string &, std::vector<long double> &);
1163 :
1164 : #ifdef LIBMESH_DEFAULT_QUADRUPLE_PRECISION
1165 : template LIBMESH_EXPORT Real command_line_value<Real> (const std::string &, Real);
1166 : template LIBMESH_EXPORT Real command_line_value<Real> (const std::vector<std::string> &, Real);
1167 : template LIBMESH_EXPORT Real command_line_next<Real> (std::string, Real);
1168 : template LIBMESH_EXPORT void command_line_vector<Real> (const std::string &, std::vector<Real> &);
1169 : #endif
1170 :
1171 : } // namespace libMesh
|