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:        ProcessApplicInterface
10 //- Description:  Derived class for the case when analysis code simulators use
11 //-               fork\exec\wait to provide the function evaluations
12 //- Owner:        Mike Eldred
13 //- Version: $Id: ProcessApplicInterface.hpp 6492 2009-12-19 00:04:28Z briadam $
14 
15 #ifndef PROCESS_APPLIC_INTERFACE_H
16 #define PROCESS_APPLIC_INTERFACE_H
17 
18 #include "ApplicationInterface.hpp"
19 #ifdef _WIN32
20 typedef intptr_t pid_t;
21 #endif
22 
23 #include <boost/tuple/tuple.hpp>
24 #include <boost/filesystem/path.hpp>
25 namespace bfs = boost::filesystem;
26 
27 namespace Dakota {
28 
29 
30 /// Substitute parameters and results file names into driver strings
31 String substitute_params_and_results(const String &driver, const String &params, const String &results);
32 
33 
34 /// Triplet of filesystem paths: e.g., params, results, workdir
35 typedef boost::tuple<bfs::path, bfs::path, bfs::path> PathTriple;
36 
37 
38 /// Derived application interface class that spawns a simulation code
39 /// using a separate process and communicates with it through files.
40 
41 /** ProcessApplicInterface is subclassed for process handles or file
42     completion testing. */
43 
44 class ProcessApplicInterface: public ApplicationInterface
45 {
46 public:
47 
48   //
49   //- Heading: Constructors and destructor
50   //
51 
52   /// constructor
53   ProcessApplicInterface(const ProblemDescDB& problem_db);
54   /// destructor
55   ~ProcessApplicInterface();
56 
57 protected:
58 
59   //
60   //- Heading: Virtual function redefinitions
61   //
62 
63   void derived_map(const Variables& vars, const ActiveSet& set,
64 		   Response& response, int fn_eval_id);
65   void derived_map_asynch(const ParamResponsePair& pair);
66 
67   void wait_local_evaluations(PRPQueue& prp_queue);
68   void test_local_evaluations(PRPQueue& prp_queue);
69 
70   const StringArray& analysis_drivers() const;
71 
72   void file_cleanup() const;
73 
74   void file_and_workdir_cleanup(const bfs::path &params_path,
75       const bfs::path &results_path,
76       const bfs::path &workdir_path,
77       const String &tag) const;
78 
79   /// Remove (potentially autotagged for multiple programs) parameters
80   /// and results files with passed root names
81   void remove_params_results_files(const bfs::path& params_path,
82 				   const bfs::path& results_path) const;
83 
84 
85   /// Utility to automatically tag parameters and results files with
86   /// passed root names (the files may already need per-program
87   /// tagging)
88   void autotag_files(const bfs::path& params_path,
89 		     const bfs::path& results_path,
90 		     const String& eval_id_tag
91 		     //, const bfs::path dest_dir = bfs::path()
92 		     ) const;
93 
94 
95   //
96   //- Heading: New virtual functions
97   //
98 
99   /// version of wait_local_evaluations() managing of set of individual
100   /// asynchronous evaluations
101   virtual void wait_local_evaluation_sequence(PRPQueue& prp_queue) = 0;
102   /// version of test_local_evaluations() managing of set of individual
103   /// asynchronous evaluations
104   virtual void test_local_evaluation_sequence(PRPQueue& prp_queue) = 0;
105 
106   /// bookkeeping of process and evaluation ids for asynchronous maps
107   virtual void map_bookkeeping(pid_t pid, int fn_eval_id) = 0;
108 
109   /// Spawn the evaluation by managing the input filter, analysis drivers,
110   /// and output filter.  Called from derived_map() & derived_map_asynch().
111   virtual pid_t create_evaluation_process(bool block_flag) = 0;
112 
113   //
114   //- Heading: Methods
115   //
116 
117   /// batch version of wait_local_evaluations()
118   void wait_local_evaluation_batch(PRPQueue& prp_queue);
119   /// batch version of test_local_evaluations()
120   void test_local_evaluation_batch(PRPQueue& prp_queue);
121 
122 /// execute analyses synchronously on the local processor
123   void synchronous_local_analyses(int start, int end, int step);
124 
125   //void clear_bookkeeping(); // virtual fn redefinition: clear processIdMap
126 
127   /// define modified filenames from user input by handling Unix temp
128   /// file and optionally tagging with given eval_id_tag
129   void define_filenames(const String& eval_id_tag);
130 
131   /// write the parameters data and response request data to one or
132   /// more parameters files (using one or more invocations of
133   /// write_parameters_file()) in either standard or aprepro format
134   void write_parameters_files(const Variables& vars,     const ActiveSet& set,
135 			      const Response&  response, const int id);
136 
137   /// read the response object from one or more results files using
138   /// full eval_id_tag passed
139   void read_results_files(Response& response, const int id,
140 			  const String& eval_id_tag);
141 
142   /// construct a work directory name (tmp or named), with optional tag
143   bfs::path get_workdir_name();
144 
145   /// set PATH, environment variables, and change directory prior to
146   /// fork/system/spawn
147   void prepare_process_environment();
148 
149   /// reset PATH and current directory after system/spawn (workdir case)
150   void reset_process_environment();
151 
152   //
153   //- Heading: Data
154   //
155 
156   /// flags tagging of parameter/results files
157   bool fileTagFlag;
158   /// flags retention of parameter/results files
159   bool fileSaveFlag;
160   /// flag indicating use of passing of filenames as command line arguments to
161   /// the analysis drivers and input/output filters
162   bool commandLineArgs;
163   /// flag indicating use of the APREPRO (the Sandia "A PRE PROcessor" utility)
164   /// format for parameter files
165   bool apreproFlag;
166   /// results file format
167   unsigned short resultsFileFormat;
168   /// flag indicating the need for separate parameters files for multiple
169   /// analysis drivers
170   bool multipleParamsFiles;
171 
172   /// the name of the input filter (input_filter user specification)
173   std::string iFilterName;
174   /// the name of the output filter (output_filter user specification)
175   std::string oFilterName;
176   /// the names of the analysis code programs (analysis_drivers user
177   /// specification)
178   std::vector<String> programNames;
179   /// the name of the parameters file from user specification
180   std::string specifiedParamsFileName;
181   /// the parameters file name actually used (modified with tagging or
182   /// temp files); only valid from define_filenames to write_parameters_files
183   std::string paramsFileName;
184 
185   /// actual, qualified name of the params file written, possibly with workdir
186   std::string paramsFileWritten;
187 
188   /// the name of the results file from user specification
189   std::string specifiedResultsFileName;
190   /// the results file name actually used (modified with tagging or
191   /// temp files); only valid from define_filenames to write_parameters_files
192   std::string resultsFileName;
193 
194   /// actual, qualified name of the results file written, possibly with workdir
195   std::string resultsFileWritten;
196 
197   /// complete evalIdTag, possibly including hierarchical tagging and
198   /// final eval id, but not program numbers, for passing to
199   /// write_parameters_files
200   std::string fullEvalId;
201 
202   /// by default analysis code interfaces delete results files if they
203   /// exist; user may override with this flag and we'll try to gather
204   /// and only fork if needed
205   bool allowExistingResults;
206 
207   /// Maps function evaluation ID to triples (parameters, results, and
208   /// workdir) paths used in spawning function evaluations.  Workdir
209   /// will be empty if not created specifically for this eval.
210   std::map<int, PathTriple> fileNameMap;
211 
212   // work_directory creation/removal controls
213 
214   /// whether to use a work_directory
215   bool useWorkdir;
216   /// work_directory name, if specified...
217   std::string workDirName;
218   /// whether to tag the working directory
219   bool dirTag;
220   /// whether dir_save was specified
221   bool dirSave;
222   /// active working directory for this evaluation; valid only from
223   /// define_filenames to create_evaluation_process
224   bfs::path curWorkdir;
225 
226   /// non-empty if created for this eval; valid only from
227   /// define_filenames to write_parameters_files
228   bfs::path createdDir;
229 
230   // work directory population controls
231 
232   /// template directory (if specified)
233   StringArray linkFiles;
234   /// template files (if specified)
235   StringArray copyFiles;
236   /// whether to replace existing files
237   bool templateReplace;
238 
239 private:
240 
241   //
242   //- Heading: Convenience functions
243   //
244 
245   /// write the variables, active set vector, derivative variables vector,
246   /// and analysis components to the specified parameters file in either
247   /// standard or aprepro format
248   void write_parameters_file(const Variables& vars, const ActiveSet& set,
249 			     const Response& response, const std::string& prog,
250 			     const std::vector<String>& an_comps,
251 			     const std::string& params_fname,
252                              const bool file_mode_out = true);
253 
254   /// Open and read the results file at path, properly handling errors
255   void read_results_file(Response &response, const bfs::path &path,
256       const int id);
257   //
258   //- Heading: Data
259   //
260 
261 };
262 
263 
264 /** Execute analyses synchronously in succession on the local
265     processor (start to end in step increments).  Modeled after
266     ApplicationInterface::synchronous_local_evaluations(). */
267 inline void ProcessApplicInterface::
synchronous_local_analyses(int start,int end,int step)268 synchronous_local_analyses(int start, int end, int step)
269 {
270   for (int analysis_id=start; analysis_id<=end; analysis_id+=step)
271     synchronous_local_analysis(analysis_id);
272 }
273 
274 
analysis_drivers() const275 inline const StringArray& ProcessApplicInterface::analysis_drivers() const
276 { return programNames; }
277 
278 } // namespace Dakota
279 
280 #endif
281