LCOV - code coverage report
Current view: top level - src/base - libmesh.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4249 (f45222) with base 7cab9a Lines: 220 338 65.1 %
Date: 2025-09-10 12:25:45 Functions: 23 60 38.3 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.14