1 /*  _______________________________________________________________________
2 
3     DAKOTA: Design Analysis Kit for Optimization and Terascale Applications
4     Copyright 2014-2020 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
5     This software is distributed under the GNU Lesser General Public License.
6     For more information, see the README file in the top Dakota directory.
7     _______________________________________________________________________ */
8 
9 //- Class:        global_defs
10 //- Description:  Global object initializations and global function
11 //-               implementations
12 //- Owner:        Mike Eldred
13 
14 #include <system_error>
15 #include <boost/math/constants/constants.hpp>
16 #include "dakota_global_defs.hpp"
17 #include "ParamResponsePair.hpp"
18 #include "PRPMultiIndex.hpp"
19 #include "DakotaGraphics.hpp"
20 #include "DakotaInterface.hpp"
21 #include "ParallelLibrary.hpp"
22 #include "ProblemDescDB.hpp"
23 #include "ResultsManager.hpp"
24 #include "EvaluationStore.hpp"
25 
26 // Toggle for MPI debug hold
27 //#define MPI_DEBUG
28 
29 #if defined(MPI_DEBUG) && defined(MPICH_NAME)
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #endif
35 
36 
37 static const char rcsId[]="@(#) $Id: dakota_global_defs.cpp 6716 2010-04-03 18:35:08Z wjbohnh $";
38 
39 
40 namespace Dakota {
41 
42 // --------------------------
43 // Instantiate global objects
44 // --------------------------
45 
46 double PI = boost::math::constants::pi<double>();
47 double HALF_LOG_2PI = std::log(2.0*PI)/2.0;
48 
49 /// by default Dakota exits or calls MPI_Abort on errors
50 short abort_mode = ABORT_EXITS;
51 
52 std::ostream* dakota_cout = &std::cout; ///< DAKOTA stdout initially points to
53   ///< std::cout, but may be redirected to a tagged ofstream if there are
54   ///< concurrent iterators.
55 std::ostream* dakota_cerr = &std::cerr; ///< DAKOTA stderr initially points to
56   ///< std::cerr, but may be redirected to a tagged ofstream if there are
57   ///< concurrent iterators.
58 PRPCache data_pairs;          ///< contains all parameter/response pairs.
59 
60 /// Global results database for iterator results
61 ResultsManager iterator_results_db;
62 /// Global database for evaluation storage
63 EvaluationStore evaluation_store_db;
64 
65 
66 int write_precision = 10;     ///< used in ostream data output functions
67                               ///< (restart_util.cpp overrides default value)
68 
69 MPIManager      dummy_mpi_mgr; ///< dummy MPIManager for ref initialization
70 ProgramOptions  dummy_prg_opt; ///< dummy ProgramOptions for ref initialization
71 OutputManager   dummy_out_mgr; ///< dummy OutputManager for ref initialization
72 ParallelLibrary dummy_lib;     ///< dummy ParallelLibrary for ref initialization
73 ProblemDescDB   dummy_db;      ///< dummy ProblemDescDB for ref initialization
74 
75 #ifdef DAKOTA_MODELCENTER
76 int mc_ptr_int = 0;           ///< global pointer for ModelCenter API
77 int dc_ptr_int = 0;           ///< global pointer for ModelCenter eval DB
78 #endif // DAKOTA_MODELCENTER
79 
80 ProblemDescDB *Dak_pddb;      ///< set by ProblemDescDB, for use in parsing
81 
82 
83 // -----------------------
84 // Define global functions
85 // -----------------------
abort_handler(int code)86 void abort_handler(int code)
87 {
88   // WEH - uncomment this code if you want signals to generate a corefile.
89   //       This is handy for debugging infinite loops ... which can be
90   //       difficult to debug within GDB.
91   //abort();
92 
93   // BMA TODO: Do we want to maintain this?
94   // BMA NOTE: If so, on Unix, could use strsignal() to get a friendly name.
95   if (code > 1) // code = 2 (Cntl-C signal), 0 (normal), & -1/1 (abnormal)
96     Cout << "\nDakota caught signal " << code << std::endl;
97 
98   // Clean up
99   Cout << std::flush; // flush cout or ofstream redirection
100   Cerr << std::flush; // flush cerr or ofstream redirection
101   iterator_results_db.close(); // flush output files/databases
102 
103   if (Dak_pddb) {
104     // cleanup parameters/results files
105     InterfaceList &ifaces = Dak_pddb->interface_list();
106     for (InterfaceList::iterator It = ifaces.begin(); It != ifaces.end(); ++It)
107       It->file_cleanup(); // virtual fn defined for ProcessApplicInterface
108     // properly terminate in parallel
109     Dak_pddb->parallel_library().abort_helper(code);
110   }
111   else {
112     abort_throw_or_exit(code);
113   }
114 }
115 
116 
117 /** Throw a system_error or call std::exit, with (256 +
118     dakota_code), where dakota_code < 0
119 
120     RATIONALE:
121      * Avoid common "standard" exit codes and signals (signum.h) as
122        well as uncaught signals / uncatchable SIGKILL which return 128
123        + <signum> on Linux = [129, 192]
124 
125      * Return a value in [0,255] since some operating systems only
126        return the 8 least significant bits, leaves [193, 255] for
127        Dakota.  This should make return codes consistent
128        cross-platform.  */
abort_throw_or_exit(int dakota_code)129 void abort_throw_or_exit(int dakota_code)
130 {
131   int os_code = 256 + dakota_code;
132   if (abort_mode == ABORT_THROWS) {
133     // throw an error that inherits from std::runtime_error and embeds
134     // the error code
135     std::error_code ecode(os_code, std::generic_category());
136     throw(std::system_error(ecode, "Dakota aborted"));
137   }
138   else
139     std::exit(os_code); // or std::exit(EXIT_FAILURE) from /usr/include/stdlib.h
140 }
141 
142 
143 /// Tie various signal handlers to Dakota's abort_handler function
register_signal_handlers()144 void register_signal_handlers()
145 {
146 #if defined(__MINGW32__) || defined(_MSC_VER)
147   std::signal(SIGBREAK, Dakota::abort_handler);
148 #else
149   // BMA: SIGKILL can't be caught; consider removing:
150   std::signal(SIGKILL,  Dakota::abort_handler);
151 #endif
152   std::signal(SIGTERM,  Dakota::abort_handler);
153   std::signal(SIGINT,   Dakota::abort_handler);
154 }
155 
156 
157 /** See details in code for details, depending on MPI implementation in use. */
mpi_debug_hold()158 void mpi_debug_hold()
159 {
160 #ifdef MPI_DEBUG
161   // hold parallel job prior to MPI_Init() in order to attach debugger to
162   // master process.  Then step past ParallelLibrary instantiation and attach
163   // debugger to other processes.
164 //#ifdef MPICH2
165 #ifdef MPICH_NAME
166   // To use this approach, set $DAKOTA_DEBUGPIPE to a suitable name,
167   // and create $DAKOTA_DEBUGPIPE by executing "mkfifo $DAKOTA_DEBUGPIPE".
168   // After invoking "mpirun ... dakota ...", find the processes, invoke
169   // a debugger on them, set breakpoints, and execute "echo >$DAKOTA_DEBUGPIPE"
170   // to write something to $DAKOTA_DEBUGPIPE, thus releasing dakota from
171   // a wait at the open invocation below.
172   char *pname; int dfd;
173   if ( ( pname = getenv("DAKOTA_DEBUGPIPE") ) &&
174        ( dfd = open(pname,O_RDONLY) ) > 0 ) {
175     char buf[80];
176     read(dfd,buf,sizeof(buf));
177     close(dfd);
178   }
179 #else
180   // This simple scheme has been observed to fail with MPICH2
181   int test;
182   std::cin >> test;
183 #endif // MPICH2
184 #endif // MPI_DEBUG
185 }
186 
187 } // namespace Dakota
188