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