LCOV - code coverage report
Current view: top level - src/base - libmesh.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4476 (4beb67) with base a68cc6 Lines: 229 296 77.4 %
Date: 2026-06-03 20:22:46 Functions: 25 58 43.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14