IterationPack: General framework for building iterative algorithms  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
IterationPack_Algorithm.cpp
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Moocho: Multi-functional Object-Oriented arCHitecture for Optimization
5 // Copyright (2003) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #include <signal.h>
43 
44 #include <iterator>
45 #include <numeric>
46 
47 #include "IterationPack_Algorithm.hpp"
48 #include "StopWatchPack_stopwatch.hpp"
49 #include "Teuchos_Assert.hpp"
52 
53 #ifdef HAVE_MPI
54 #include "mpi.h"
55 #endif
56 
57 // Define to see MPI/interrupt deugging output
58 //#define ITERATION_PACK_ALGORITHM_SHOW_MPI_DEBUG_INFO
59 
60 // Define of the MPI implementation receives signals on all processes
61 //#define ITERATION_PACK_ALGORITHM_SIGNALS_ON_ALL_PROCESSES;
62 
63 extern "C" {
64 
65 void sig_handler_interrupt_algorithm( int signum )
66 {
67  IterationPack::Algorithm::interrupt();
68 }
69 
70 } // extern "C"
71 
72 namespace {
73 
74 // Helper functions
75 
76 template< class T >
77 inline
78 T my_max( const T& v1, const T& v2 ) { return v1 > v2 ? v1 : v2; }
79 
80 // Private static data for IterationPack::Algorithm.
81 // I put it here so that I can modify it without affecting the
82 // header file and avoiding unnecessary recompilations.
83 
84 enum EInterruptStatus { NOT_INTERRUPTED=0, STOP_END_STEP=1, STOP_END_ITER=2, ABORT_PROGRAM=3 };
85 
86 int static_mpi_initialized = false;
87 int static_num_running_algorithms = 0;
88 int static_num_proc = 0; // Flag that no algorithm has been even allocated yet!
89 int static_proc_rank = 0;
90 bool static_interrupt_called = false;
91 bool static_processed_user_interrupt = false;
92 EInterruptStatus static_interrupt_status = NOT_INTERRUPTED;
93 bool static_interrupt_terminate_return = false;
94 
95 } // end namespace
96 
97 // ToDo: change step_itr and assoc_step_itr to just return iterators without
98 // asserting if the names exist. This will be more useful.
99 
100 namespace IterationPack {
101 
102 // constructors / destructor
103 
105  :running_state_(NOT_RUNNING), max_iter_(100)
106  ,max_run_time_(std::numeric_limits<double>::max())
107  ,next_step_name_(0), do_step_next_called_(false), reconfigured_(false)
108  ,time_stats_computed_(false)
109 {
110  // Set MPI info
111  static_num_proc = 1;
112  static_proc_rank = 0;
113 #ifdef HAVE_MPI
114  // If MPI is not initialized then this must be because the code was
115  // compiled with support for MPI but it not actually using it.
116  // Therefore, we will initialize MPI but not bother to finialize it.
117  if(!static_mpi_initialized) {
118  int mpi_initialized = false;
119  MPI_Initialized(&mpi_initialized);
120  if(!mpi_initialized) {
121  int argc = 1;
122  char arg_str[] = "dummy_prg";
123  char *arg_str_ptr = arg_str;
124  char **argv = &arg_str_ptr;
125  MPI_Init( &argc, &argv );
126  }
127  static_mpi_initialized = true;
128  }
129  // ToDo: Allow the specification of another communicator if needed!
130  MPI_Comm_size( MPI_COMM_WORLD, &static_num_proc );
131  MPI_Comm_rank( MPI_COMM_WORLD, &static_proc_rank );
132 #ifdef ITERATION_PACK_ALGORITHM_SHOW_MPI_DEBUG_INFO
133  std::cerr << "\np=" << static_proc_rank << ": Algorithm::Algorithm() being called (num_proc = "<<static_num_proc<<") ... \n";
134 #endif
135 #endif // HAVE_MPI
136 }
137 
139 {}
140 
141 // maximum iterations
142 
143 void Algorithm::max_iter(size_t max_iter)
144 { max_iter_ = max_iter; }
145 
146 size_t Algorithm::max_iter() const
147 { return max_iter_; }
148 
149 // maximum run tine
150 
151 void Algorithm::max_run_time(double max_run_time)
152 { max_run_time_ = max_run_time; }
153 
155 { return max_run_time_; }
156 
157 
158 // step information / access
159 
161 { return steps_.size(); }
162 
163 Algorithm::poss_type Algorithm::get_step_poss(const std::string& step_name) const
164 {
165  steps_t::const_iterator itr = step_itr(step_name);
166  return itr == steps_.end() ? DOES_NOT_EXIST : std::distance( steps_.begin(), itr ) + 1;
167 }
168 
169 const std::string& Algorithm::get_step_name(poss_type step_poss) const
170 { return steps_[validate(step_poss) - 1].name; }
171 
173 { return steps_[validate(step_poss) - 1].step_ptr; }
174 
176 { return steps_[validate(step_poss) - 1].step_ptr; }
177 
178 // pre/post step information / access
179 
180 int Algorithm::num_assoc_steps(poss_type step_poss, EAssocStepType type) const
181 { return assoc_steps_[validate(step_poss) - 1][type].size(); }
182 
184  ,const std::string& assoc_step_name) const
185 {
186  // ToDo: change to return DOES_NOT_EXIST if it does not exist.
187  const assoc_steps_ele_list_t &assoc_list = assoc_steps_[validate(step_poss) - 1][type];
188  assoc_steps_ele_list_t::const_iterator itr = assoc_step_itr(assoc_list,assoc_step_name);
189  return itr == assoc_list.end() ? DOES_NOT_EXIST : std::distance( assoc_list.begin() , itr ) + 1;
190 }
191 
192 const std::string& Algorithm::get_assoc_step_name(poss_type step_poss, EAssocStepType type
193  , poss_type assoc_step_poss) const
194 {
195  const assoc_steps_ele_list_t &assoc_list= assoc_steps_[validate(step_poss) - 1][type];
196  validate(assoc_list,assoc_step_poss);
197  assoc_steps_ele_list_t::const_iterator itr = assoc_list.begin();
198  std::advance( itr, assoc_step_poss - 1 );
199  return (*itr).name;
200 }
201 
203  , poss_type assoc_step_poss)
204 {
205  assoc_steps_ele_list_t &assoc_list= assoc_steps_[validate(step_poss) - 1][type];
206  validate(assoc_list,assoc_step_poss);
207  assoc_steps_ele_list_t::iterator itr = assoc_list.begin();
208  std::advance( itr, assoc_step_poss - 1 );
209  return (*itr).step_ptr;
210 }
211 
212 const Algorithm::step_ptr_t& Algorithm::get_assoc_step(poss_type step_poss, EAssocStepType type
213  , poss_type assoc_step_poss) const
214 {
215  const assoc_steps_ele_list_t &assoc_list= assoc_steps_[validate(step_poss) - 1][type];
216  validate(assoc_list,assoc_step_poss);
217  assoc_steps_ele_list_t::const_iterator itr = assoc_list.begin();
218  std::advance( itr, assoc_step_poss - 1 );
219  return (*itr).step_ptr;
220 }
221 
222 // step manipulation
223 
224 void Algorithm::insert_step(poss_type step_poss, const std::string& step_name, const step_ptr_t& step)
225 {
226  validate_not_in_state(RUNNING);
228  step.get() == NULL, std::invalid_argument
229  ,"Algorithm::insert_step(...) : A step with the name = \'" << step_name
230  << "\' being inserted into the position = " << step_poss
231  << " has step.get() == NULL!" );
232  // Make sure a step with this name does not already exist.
233  steps_t::iterator itr;
234  if( steps_.end() != ( itr = step_itr(step_name) ) )
236  true, AlreadyExists
237  ,"Algorithm::insert_step(...) : A step with the name = " << step_name
238  << " already exists at step_poss = " << std::distance(steps_.begin(),itr) + 1 );
239  // insert the step in such a way that any container can be used for steps_
240  itr = steps_.begin();
241  std::advance ( itr , validate(step_poss,+1) - 1 );
242  steps_.insert( itr , steps_ele_t(step,step_name) );
243  // insert the assoc_step element in such a way that any container can be used for assoc_steps_
244  assoc_steps_t::iterator a_itr = assoc_steps_.begin();
245  std::advance ( a_itr , step_poss - 1 );
246  assoc_steps_.insert( a_itr , assoc_steps_ele_t() );
247 }
248 
249 void Algorithm::change_step_name(poss_type step_poss, const std::string& new_name)
250 {
251  validate_not_in_state(RUNNING);
252  if(running_state() == RUNNING_BEING_CONFIGURED) {
253  validate_not_curr_step(validate(step_poss));
254  validate_not_next_step(steps_[step_poss - 1].name);
255  }
256  steps_[step_poss - 1].name = new_name;
257 }
258 
259 void Algorithm::replace_step(poss_type step_poss, const step_ptr_t& step)
260 {
261  validate_not_in_state(RUNNING);
262  if(running_state() == RUNNING_BEING_CONFIGURED) validate_not_curr_step(validate(step_poss));
263  steps_[step_poss - 1].step_ptr = step;
264 }
265 
267 {
268  validate_not_in_state(RUNNING);
269  if(running_state() == RUNNING_BEING_CONFIGURED) {
270  validate_not_curr_step(validate(step_poss));
271  validate_not_next_step(steps_[step_poss - 1].name);
272  }
273  // remove the step in such a way that any container can be used for steps_
274  steps_t::iterator itr = steps_.begin();
275  std::advance ( itr , validate(step_poss) - 1 );
276  steps_.erase( itr );
277  // remove the assoc_step element in such a way that any container can be used for assoc_steps_
278  assoc_steps_t::iterator a_itr = assoc_steps_.begin();
279  std::advance ( a_itr , step_poss - 1 );
280  assoc_steps_.erase( a_itr );
281 }
282 
283 // pre/post step manipulation
284 
285 void Algorithm::insert_assoc_step(poss_type step_poss, EAssocStepType type, poss_type assoc_step_poss
286  , const std::string& assoc_step_name, const step_ptr_t& assoc_step)
287 {
288  validate_not_in_state(RUNNING);
290  assoc_step.get() == NULL, std::invalid_argument
291  ,"Algorithm::insert_assoc_step(...) : A step with the name = \'" << assoc_step_name
292  << "\' being inserted into the position = " << step_poss
293  << "." << ( type == PRE_STEP
294  ? (int)assoc_step_poss - num_assoc_steps(step_poss,type) - 1
295  : assoc_step_poss )
296  << " has assoc_step.get() == NULL!" );
297  if(running_state() == RUNNING_BEING_CONFIGURED) validate_not_curr_step(validate(step_poss));
298  // Make sure an associated step with this name does not already exist.
299  assoc_steps_ele_list_t &assoc_list = assoc_steps_[step_poss - 1][type];
300  validate(assoc_list,assoc_step_poss,+1);
301  assoc_steps_ele_list_t::iterator itr = assoc_list.begin();
302  char assoc_type_name[2][10] = { "PRE_STEP" , "POST_STEP" };
303  if( assoc_list.end() != ( itr = assoc_step_itr(assoc_list,assoc_step_name) ) )
305  true, AlreadyExists
306  ,"Algorithm::insert_assoc_step(...) : An associated step of type = "
307  << assoc_type_name[type]
308  << " with the name = " << assoc_step_name
309  << " already exists at step_poss = " << step_poss
310  << " and assoc_step_poss = " << std::distance(assoc_list.begin(),itr) + 1 );
311  // insert an associated step in such a way that any container could be used.
312  itr = assoc_list.begin();
313  std::advance( itr, assoc_step_poss - 1 );
314  assoc_list.insert( itr , assoc_steps_ele_list_ele_t(assoc_step,assoc_step_name) );
315 }
316 
317 void Algorithm::remove_assoc_step(poss_type step_poss, EAssocStepType type, poss_type assoc_step_poss)
318 {
319  validate_not_in_state(RUNNING);
320  if(running_state() == RUNNING_BEING_CONFIGURED) validate_not_curr_step(validate(step_poss));
321  validate(step_poss);
322  assoc_steps_ele_list_t &assos_list = assoc_steps_[step_poss - 1][type];
323  validate(assos_list,assoc_step_poss);
324  assoc_steps_ele_list_t::iterator itr = assos_list.begin();
325  std::advance( itr, assoc_step_poss - 1 );
326  assos_list.erase( itr );
327 }
328 
329 // runtime configuration updating control
330 
332 {
333  validate_in_state(RUNNING);
334  saved_next_step_name_ = *next_step_name_;
335  saved_curr_step_name_ = steps_[curr_step_poss_ - 1].name;
336  change_running_state(RUNNING_BEING_CONFIGURED);
337 }
338 
340 {
341  validate_in_state(RUNNING_BEING_CONFIGURED);
342 
343  // update next_step_poss_ and next_step_name_.
344  steps_t::iterator itr = step_itr(saved_next_step_name_);
345  TEUCHOS_TEST_FOR_EXCEPT( !( itr != steps_.end() ) ); // the step with this name should not have been deleted or changed.
346  next_step_poss_ = std::distance( steps_.begin() , itr ) + 1;
347  next_step_name_ = &(*itr).name;
348 
349  // update curr_step_poss_
350  itr = step_itr(saved_curr_step_name_);
351  TEUCHOS_TEST_FOR_EXCEPT( !( itr != steps_.end() ) ); // the step with this name should not have been deleted or changed.
352  curr_step_poss_ = std::distance( steps_.begin() , itr ) + 1;
353 
354  // inform the step objects that *this has changes.
355  imp_inform_steps( &AlgorithmStep::inform_updated );
356 
357  change_running_state(RUNNING);
358  reconfigured_ = true;
359 }
360 
361 // algorithmic control
362 
363 void Algorithm::do_step_next(const std::string& step_name)
364 {
365  validate_in_state(RUNNING);
366  steps_t::iterator itr = step_itr_and_assert(step_name);
367  next_step_poss_ = std::distance( steps_.begin() , itr ) + 1;
368  next_step_name_ = &(*itr).name;
369  do_step_next_called_ = true;
370 }
371 
373 {
374  validate_in_state(RUNNING);
375  const steps_ele_t &ele = steps_[validate(step_poss) - 1];
376  next_step_poss_ = step_poss;
377  next_step_name_ = &ele.name;
378  do_step_next_called_ = true;
379 }
380 
381 const std::string& Algorithm::what_is_next_step_name() const
382 {
383  validate_in_state(RUNNING);
384  return *next_step_name_;
385 }
386 
388 {
389  validate_in_state(RUNNING);
390  return next_step_poss_;
391 }
392 
393 bool Algorithm::do_step(const std::string& step_name)
394 {
395  validate_in_state(RUNNING);
396  return imp_do_step( std::distance( steps_.begin() , step_itr_and_assert(step_name) ) + 1 );
397 }
398 
400 {
401  validate_in_state(RUNNING);
402  return imp_do_step(step_poss);
403 }
404 
405 void Algorithm::terminate(bool success)
406 {
407  validate_in_state(RUNNING);
408  terminate_status_ = success ? STATUS_TERMINATE_TRUE : STATUS_TERMINATE_FALSE;
409 }
410 
411 // start iterations
412 
413 EAlgoReturn Algorithm::do_algorithm(poss_type step_poss)
414 {
416 
417  validate_in_state(NOT_RUNNING);
418 
419  track().initialize();
420 
421  try{
422 
423  terminate_status_ = STATUS_KEEP_RUNNING;
424  change_running_state(RUNNING);
425 
426  first_k_ = state().k();
427  next_step_poss_ = validate(step_poss);
428  next_step_name_ = &steps_[step_poss - 1].name;
429 
430  // Prepair for timing algorithm
431  step_times_.resize( algo_timing_ ? (num_steps()+1) * (max_iter()+1+NUM_STEP_TIME_STATS) : 0 );
432  if( algo_timing_ ) {
433 // step_times_[ max_iter() ] = 0.0; // flag for statistics not calc. yet.
434 // // set iteration totals to zero
435 // if( step_times_[(max_iter() + 1 + 5) * num_steps()] != 0.0 )
436 // std::fill_n( step_times_.begin() + (max_iter() + 1 + 5) * num_steps(), max_iter(), 0.0 );
437  std::fill_n( step_times_.begin(), step_times_.size(), 0.0 ); // Try setting everything to zero?
438  time_stats_computed_ = false;
439  }
440  stopwatch step_timer;
441  stopwatch overall_timer;
442 
443  imp_inform_steps( &AlgorithmStep::initialize_step );
444 
445  overall_timer.start();
446  for(;;) {
447 
448  curr_step_poss_ = next_step_poss_;
449  // Note that curr_step_poss_ may change if there is a runtime
450  // change in the configuration of the steps.
451 
452  bool keep_on = true;
453 
454  // Execute the steps for this step
455 
456  if( algo_timing_ ) {
457  step_timer.reset();
458  step_timer.start();
459  }
460 
461  keep_on = imp_do_step(curr_step_poss_);
462 
463  if( algo_timing_ ) {
464  const double time = my_max(step_timer.stop(),-1e-50); // negative somehow (g++ -O2 ?)
465  // time for step k for the iteration
466  step_times_[state().k()-first_k_+(curr_step_poss_-1)*(max_iter()+1+NUM_STEP_TIME_STATS)] = time;
467  // Add to time for the full iteration
468  step_times_[state().k()-first_k_+(num_steps())*(max_iter()+1+NUM_STEP_TIME_STATS)] += time;
469  }
470 
471  // See if a step object called terminate(...)
472  if(terminate_status_ != STATUS_KEEP_RUNNING) {
473  EAlgoReturn algo_return;
474  if( static_interrupt_status == STOP_END_STEP ) {
475  algo_return = ( terminate_status_ == STATUS_TERMINATE_TRUE
476  ? INTERRUPTED_TERMINATE_TRUE
477  : INTERRUPTED_TERMINATE_FALSE );
478  static_interrupt_status = NOT_INTERRUPTED;
479  }
480  else {
481  algo_return = ( terminate_status_ == STATUS_TERMINATE_TRUE
482  ? TERMINATE_TRUE
483  : TERMINATE_FALSE );
484  }
485  return finalize_algorithm(algo_return);
486  }
487 
488  if(keep_on) {
489 
490  // All the step objects returned true so increment the step and loop around
491 
492  if( curr_step_poss_ == static_cast<poss_type>(num_steps()) ) {
493 
494  //
495  // This is the last step in the algorithm
496  //
497 
498  // Output this iteration
499  track().output_iteration(*this);
500 
501  // Check if the maximum number of iterations has been exceeded.
502  if( state().k() - first_k_ >= max_iter() ) {
503  return finalize_algorithm(MAX_ITER_EXCEEDED);
504  }
505 
506  // Check if the maximum runtime has been exceeded.
507  if( ( overall_timer.read() / 60 ) >= max_run_time() ) {
508  return finalize_algorithm(MAX_RUN_TIME_EXCEEDED);
509  }
510 
511  // Set if the algorithm was interrupted
512  if( static_interrupt_status == STOP_END_ITER ) {
513  static_interrupt_status = NOT_INTERRUPTED;
514  const EAlgoReturn algo_return = ( static_interrupt_terminate_return
515  ? INTERRUPTED_TERMINATE_TRUE
516  : INTERRUPTED_TERMINATE_FALSE );
517  return finalize_algorithm(algo_return);
518  }
519 
520  // Transition the iteration quantities to k = k + 1
521  state().next_iteration();
522 
523  // Setup to start the major loop over again
524  next_step_poss_ = 1;
525  next_step_name_ = &steps_[0].name;
526 
527  }
528  else {
529 
530  // else just increment the step
531  ++next_step_poss_;
532  next_step_name_ = &steps_[next_step_poss_ - 1].name;
533 
534  }
535 
536  continue; // loop around
537 
538  }
539  else {
540  // some step object returned false from its do_step(..) operation so it
541  // should have called do_step_next(...) to request a jump to
542  // a specific operation.
543  if(!do_step_next_called_)
546  ,"EAlgoReturn Algorithm::do_algorithm(...) :"
547  " A step object returned false from its do_step(...) operation"
548  " without calling do_step_next(...) to request jump to a specific"
549  " step." );
550  do_step_next_called_ = false;
551  // just loop around and do the step that the step object requested
552  // by changing next_step_poss_ by its call to do_step_next(...).
553  }
554  } // end for(;;)
555 
556  } // end try
557  catch(...) {
558  try {
559  finalize_algorithm(TERMINATE_FALSE);
560  }
561  catch(...) {
562  // We tried to finalize gracefully but we failed!
563  }
564  throw;
565  }
566 }
567 
568 // algorithm information output
569 
570 void Algorithm::print_steps(std::ostream& out) const
571 {
572  out << "\n*** Algorithm Steps ***\n\n";
573  imp_print_algorithm(out,false);
574  out << std::endl;
575 }
576 
577 void Algorithm::print_algorithm(std::ostream& out) const
578 {
579  out << "\n*** Iteration Quantities ***\n\n";
580  state().dump_iter_quant(out);
581  out << std::endl;
582  out << "\n*** Algorithm Description ***\n\n";
583  imp_print_algorithm(out,true);
584  out << std::endl;
585 }
586 
587 // Algorithm Timing.
588 
589 void Algorithm::set_algo_timing( bool algo_timing ) {
590  validate_not_in_state(RUNNING);
591  algo_timing_ = algo_timing;
592 }
593 
595  return algo_timing_;
596 }
597 
598 void Algorithm::print_algorithm_times( std::ostream& out ) const
599 {
600  using std::setw;
601  using std::endl;
602 
603  validate_not_in_state(RUNNING);
604 
605  if( step_times_.size() == 0 ) {
606  out << "No step timing was performed\n";
607  return;
608  }
609 
610  const int w = 10;
611  const int prec = 4;
612  const int n = num_steps(); // Total steps
613  const int m = state().k() - first_k_ + 1; // Total number of iterations performed
614  const int mm = max_iter()+1; // Total number of possible iterations
615  const int mmm = mm + NUM_STEP_TIME_STATS; // total entries in a step_i row
616 
617  // Print the header.
618  out << "\n\n**************************************\n"
619  << "*** Algorithm step CPU times (sec) ***\n";
620 
621  // Print the step names.
622  out << "\nStep names"
623  << "\n----------\n";
624  {for( int i = 1; i <= n; ++i ) {
625  out << i << ") \"" << get_step_name(i) << "\"\n";
626  }}
627  out << n+1 << ") Iteration total\n";
628  out << endl;
629 
630  out << std::right << std::setprecision(prec);
631 
632  // Print table header
633  out << setw(w) << "" << " steps 1..." << n+1 << " ->\n\n";
634 
635  // print step numbers
636  out << setw(w) << " iter k";
637  {for( int i = 1; i <= n+1; ++i ) {
638  out << setw(w) << i;
639  }}
640  out << endl;
641  out << setw(w) << "--------";
642  {for( int i = 1; i <= n+1; ++i ) {
643  out << setw(w) << "--------";
644  }}
645  out << endl;
646  // Print the step times.
647  {for( int k = 0; k < m; ++k ) {
648  out << setw(w) << first_k_ + k;
649  {for( int i = 0; i < n+1; ++i ) {
650  out << setw(w) << step_times_[k+i*mmm];
651  }}
652  out << endl;
653  }}
654 
655  // Compute the (1) totals for each step, the (2) average, (3) min and (4) max times
656  // per iteration for each step and the (5) precentages for each step.
657 
658  compute_final_time_stats();
659 
660  // Ouput time statistics.
661 
662  out << setw(w) << "--------";
663  {for( int i = 1; i <= n+1; ++i ) {
664  out << setw(w) << "--------";
665  }}
666 
667  // Output the total times for each step.
668  out << endl;
669  out << setw(w) << "total(sec)";
670  {for( int i = 0; i < n+1; ++i ) {
671  const double *step_i_times = &step_times_[i*mmm];
672  out << setw(w) << step_i_times[ mm + TIME_STAT_TOTALS_OFFSET ];
673  }}
674  out << endl;
675 
676  // Output the average times per iteration
677  out << setw(w) << "av(sec)/k";
678  {for( int i = 0; i < n+1; ++i ) {
679  const double *step_i_times = &step_times_[i*mmm];
680  out << setw(w) << step_i_times[ mm + TIME_STAT_AV_OFFSET ];
681  }}
682  out << endl;
683 
684  // Output the min times per iteration
685  out << setw(w) << "min(sec)";
686  {for( int i = 0; i < n+1; ++i ) {
687  const double *step_i_times = &step_times_[i*mmm];
688  out << setw(w) << step_i_times[ mm + TIME_STAT_MIN_OFFSET ];
689  }}
690  out << endl;
691 
692  // Output the max times per iteration
693  out << setw(w) << "max(sec)";
694  {for( int i = 0; i < n+1; ++i ) {
695  const double *step_i_times = &step_times_[i*mmm];
696  out << setw(w) << step_i_times[ mm + TIME_STAT_MAX_OFFSET ];
697  }}
698  out << endl;
699 
700  // Output the precentage times for each step.
701  out << setw(w) << "% total";
702  {for( int i = 0; i < n+1; ++i ) {
703  const double *step_i_times = &step_times_[i*mmm];
704  out << setw(w) << step_i_times[ mm + TIME_STAT_PERCENT_OFFSET ] * 100.0;
705  }}
706  out << endl;
707 
708 
709  // Print total time for entire algorithm.
710  out << "------------------------------" << endl
711  << "total CPU time = " << total_time_ << " sec\n";;
712 }
713 
714 
715 void Algorithm::get_step_times_k( int offset, double step_times[] ) const
716 {
718  step_times_.size() == 0, std::logic_error
719  ,"Algorithm::get_step_times_k(...) : times requested, but no times calculated!"
720  );
722  offset > 0, std::invalid_argument
723  ,"Algorithm::get_step_times_k(...) : Can\'t get times for an iteratin that has not occured yet!."
724  );
725 
726  const int n = num_steps(); // Total steps
727  //const int m = state().k() - first_k_ + 1; // Total number of iterations performed
728  const int mm = max_iter()+1; // Total number of possible iterations
729  const int mmm = mm + NUM_STEP_TIME_STATS; // total entries in a step_i row
730 
731  const int k = state().k() + offset;
732  {for (int step = 0; step < n+1; ++step) {
733  step_times[step] = step_times_[step*mmm + k];
734  }}
735 
736 }
737 
738 void Algorithm::get_final_step_stats( size_t step, double* total, double* average, double* min, double* max, double* percent) const
739 {
740  // Compute the (1) totals for each step, the (2) average, (3) min and (4) max times
741  // per iteration for each step and the (5) precentages for each step.
742  compute_final_time_stats();
743 
744  //const int n = num_steps(); // Total steps
745  //const int m = state().k() - first_k_ + 1; // Total number of iterations performed
746  const int mm = max_iter()+1; // Total number of possible iterations
747  const int mmm = mm + NUM_STEP_TIME_STATS; // total entries in a step_i row
748 
749  double* step_i_times = &const_cast<step_times_t&>(step_times_)[step*mmm];
750  if (total) {
751  *total = step_i_times[mm + TIME_STAT_TOTALS_OFFSET];
752  }
753  if (average) {
754  *average = step_i_times[mm + TIME_STAT_AV_OFFSET];
755  }
756  if (min) {
757  *min = step_i_times[mm + TIME_STAT_MIN_OFFSET];
758  }
759  if (max) {
760  *max = step_i_times[mm + TIME_STAT_MAX_OFFSET];
761  }
762  if (percent) {
763  *percent = step_i_times[mm + TIME_STAT_PERCENT_OFFSET];
764  }
765 }
766 
767 EAlgoReturn Algorithm::finalize_algorithm( EAlgoReturn algo_return )
768 {
769  change_running_state(NOT_RUNNING);
770  imp_inform_steps( &AlgorithmStep::finalize_step );
771  track().output_final(*this,algo_return);
772  return algo_return;
773 }
774 
775 void Algorithm::compute_final_time_stats() const
776 {
777  if (!time_stats_computed_) {
778  time_stats_computed_ = true;
779 
780  const int n = num_steps(); // Total steps
781  const int m = state().k() - first_k_ + 1; // Total number of iterations performed
782  const int mm = max_iter()+1; // Total number of possible iterations
783  const int mmm = mm + NUM_STEP_TIME_STATS; // total entries in a step_i row
784 
785  // compute totals for each step (1...n) and the full iteration (n+1)
786  double &_total_time = const_cast<double&>(total_time_);
787  _total_time = 0.0;
788 
789  {for( int i = 0; i < n+1; ++i ) {
790  double *step_i_times = &const_cast<step_times_t&>(step_times_)[i*mmm];
791  // compute total step times (and total algorithm time)
792  const double
793  step_time = std::accumulate( step_i_times, step_i_times + m, (double)0.0 );
794  if(i < n)
795  _total_time += step_time;
796  step_i_times[ mm + TIME_STAT_TOTALS_OFFSET ] = step_time;
797  // compute average per step.
798  step_i_times[ mm + TIME_STAT_AV_OFFSET ] = step_time / m;
799  // compute min per step
800  step_i_times[ mm + TIME_STAT_MIN_OFFSET ]= *std::min_element( step_i_times, step_i_times + m );
801  // compute max per step
802  step_i_times[ mm + TIME_STAT_MAX_OFFSET ]= *std::max_element( step_i_times, step_i_times + m );
803  }}
804 
805  {for( int i = 0; i < n+1; ++i ) {
806  double *step_i_times = &const_cast<step_times_t&>(step_times_)[i*mmm];
807  // compute fractions for each step.
808  step_i_times[ mm + TIME_STAT_PERCENT_OFFSET ]
809  = step_i_times[ mm + TIME_STAT_TOTALS_OFFSET ] / total_time_;
810  }}
811  }
812 }
813 
814 // private
815 
816 void Algorithm::change_running_state(ERunningState _running_state)
817 {
818  if( running_state() != RUNNING && _running_state == RUNNING ) {
819  if( static_num_running_algorithms == 0 ) {
820  // Register the signal handler for the SIGINT
821  signal( SIGINT, &sig_handler_interrupt_algorithm );
822  static_interrupt_called = false;
823  static_processed_user_interrupt = false;
824  }
825  ++static_num_running_algorithms;
826  }
827  else if( running_state() != NOT_RUNNING && _running_state == NOT_RUNNING ) {
828  --static_num_running_algorithms;
829  if( static_num_running_algorithms == 0 ) {
830  // Put back the default signal handler
831  signal( SIGINT, SIG_DFL );
832  static_interrupt_called = false;
833  static_processed_user_interrupt = false;
834  }
835  }
836  running_state_ = _running_state;
837 }
838 
839 void Algorithm::validate_in_state(ERunningState _running_state) const {
840  const char running_state_name[3][25] = { "NOT_RUNNING" , "RUNNING", "RUNNING_BEING_CONFIGURED" };
841  if(running_state() != _running_state)
843  true, InvalidRunningState
844  ,"Algorithm::validate_in_state(...) : The condition running_state() == "
845  << running_state_name[running_state()] << " has been violated with "
846  << " running_state = " << running_state_name[_running_state] );
847 }
848 
849 void Algorithm::validate_not_in_state(ERunningState _running_state) const {
850  const char running_state_name[3][25] = { "NOT_RUNNING" , "RUNNING", "RUNNING_BEING_CONFIGURED" };
851  if(running_state() == _running_state)
853  true, InvalidRunningState
854  ,"Algorithm::validate_not_in_state(...) : The condition running_state() != "
855  << running_state_name[running_state()] << " has been violated" );
856 }
857 
858 void Algorithm::validate_not_curr_step(poss_type step_poss) const {
859  if(step_poss == curr_step_poss_)
861  true, InvalidConfigChange
862  ,"Algorithm::validate_not_curr_step(step_poss="<<step_poss<<") : "
863  "Error, You can not modify the step being currently executed" );
864 }
865 
866 void Algorithm::validate_not_next_step(const std::string& step_name) const {
867  if( step_name == saved_next_step_name_ )
869  true, InvalidConfigChange,
870  "Algorithm::validate_not_next_step(step_name): "
871  "Error, You can not modify name or remove the step given by "
872  "step_name = what_is_next_name() = " << step_name );
873 }
874 
875 Algorithm::steps_t::iterator Algorithm::step_itr_and_assert(const std::string& step_name)
876 {
877  steps_t::iterator itr = step_itr(step_name);
878  if(itr == steps_.end())
880  true, DoesNotExist
881  ,"Algorithm::step_itr(...) : A step with the name "
882  << step_name << " does not exist." );
883  return itr;
884 }
885 
886 Algorithm::steps_t::const_iterator Algorithm::step_itr_and_assert(const std::string& step_name) const
887 {
888  steps_t::const_iterator itr = step_itr(step_name);
889  if(itr == steps_.end())
891  true, DoesNotExist
892  ,"Algorithm::step_itr(...) : A step with the name "
893  << step_name << " does not exist." );
894  return itr;
895 }
896 
897 bool Algorithm::imp_do_step(poss_type step_poss) {
898  curr_step_poss_ = step_poss;
899  // do the pre steps in order
900  if( !imp_do_assoc_steps(PRE_STEP) ) return false;
901  // do the main step
902  if( !steps_[curr_step_poss_-1].step_ptr->do_step(*this, curr_step_poss_, DO_MAIN_STEP, 0) ) return false;
903  // do the post steps in order
904  if( !imp_do_assoc_steps(POST_STEP) ) return false;
905  // if you get here all the pre steps, step, and post steps returned true.
906  if( static_interrupt_status == NOT_INTERRUPTED )
907  look_for_interrupt();
908  if( static_interrupt_status == STOP_END_STEP ) {
909  terminate( static_interrupt_terminate_return );
910  return false;
911  }
912  return true;
913 }
914 
915 bool Algorithm::imp_do_assoc_steps(EAssocStepType type) {
916  assoc_steps_ele_list_t *assoc_list = &assoc_steps_[curr_step_poss_ - 1][type];
917  assoc_steps_ele_list_t::iterator itr = assoc_list->begin();
918  int n = assoc_list->size();
919  for(int i = 1; i <= n; ++itr, ++i) {
920  if(reconfigured_) {
921  // The associated step just has reconfigured *this
922  // so we must update our pointers and iterators.
923  // Since it is not allowed for this step or its associated steps
924  // to have been changed, the next associated step to
925  // execute will not change.
926  assoc_list = &assoc_steps_[curr_step_poss_ - 1][type];
927  itr = assoc_list->begin();
928  std::advance( itr, i - 1 );
929  reconfigured_ = false; // This works as long as no one else needs to know
930  // if *this has been reconfigured.
931  }
932  if( !(*(*itr).step_ptr).do_step(*this, curr_step_poss_, do_step_type(type), i) ) return false;
933  }
934  return true; // All the associated steps returned true.
935 }
936 
937 void Algorithm::imp_inform_steps(inform_func_ptr_t inform_func_ptr)
938 {
939  steps_t::const_iterator s_itr = steps_.begin();
940  assoc_steps_t::const_iterator a_itr = assoc_steps_.begin();
941  poss_type step_i = 1;
942  for(; step_i <= static_cast<poss_type>(num_steps()); ++step_i, ++s_itr, ++a_itr) {
943  // pre_steps (e.q. 2.-3, 2.-2, 2.-1)
944  const assoc_steps_ele_list_t &pre_steps = (*a_itr)[PRE_STEP];
945  assoc_steps_ele_list_t::const_iterator pre_step_itr = pre_steps.begin();
946  for(int pre_step_i = - pre_steps.size(); pre_step_i < 0; ++pre_step_i, ++pre_step_itr) {
947  ((&*(*pre_step_itr).step_ptr)->*inform_func_ptr)(
948  *this, step_i, DO_PRE_STEP, pre_steps.size()+pre_step_i+1
949  );
950  }
951  // The main step.
952  ((&*(*s_itr).step_ptr)->*inform_func_ptr)( *this, step_i, DO_MAIN_STEP, 0 );
953  // post_steps (e.q. 2.1, 2.2, 2.3)
954  const assoc_steps_ele_list_t &post_steps = (*a_itr)[POST_STEP];
955  assoc_steps_ele_list_t::const_iterator post_step_itr = post_steps.begin();
956  for(int post_step_i = 1; post_step_i <= static_cast<int>(post_steps.size()); ++post_step_i, ++post_step_itr) {
957  ((&*(*post_step_itr).step_ptr)->*inform_func_ptr)(
958  *this, step_i, DO_POST_STEP, post_step_i
959  );
960  }
961  }
962 }
963 
964 void Algorithm::imp_print_algorithm(std::ostream& out, bool print_steps) const
965 {
966  using Teuchos::typeName;
967  const std::string leading_str = " ";
968 
969  steps_t::const_iterator s_itr = steps_.begin();
970  assoc_steps_t::const_iterator a_itr = assoc_steps_.begin();
971  poss_type step_i = 1;
972  for(; step_i <= static_cast<poss_type>(num_steps()); ++step_i, ++s_itr, ++a_itr) {
973  // list pre_steps (e.q. 2.-3, 2.-2, 2.-1)
974  const assoc_steps_ele_list_t &pre_steps = (*a_itr)[PRE_STEP];
975  assoc_steps_ele_list_t::const_iterator pre_step_itr = pre_steps.begin();
976  for(int pre_step_i = - pre_steps.size(); pre_step_i < 0; ++pre_step_i, ++pre_step_itr) {
977  out << step_i << "." << pre_step_i << ". \""
978  << (*pre_step_itr).name << "\"\n"
979  << leading_str << "(" << typeName(*(*pre_step_itr).step_ptr) << ")\n";
980  if(print_steps) {
981  (*(*pre_step_itr).step_ptr).print_step( *this, step_i, DO_PRE_STEP
982  , pre_steps.size()+pre_step_i+1, out, leading_str );
983  out << std::endl;
984  }
985  }
986  // The main step.
987  out << step_i << ". \"" << (*s_itr).name
988  << "\"\n"
989  << leading_str << "(" << typeName(*(*s_itr).step_ptr) << ")\n";
990  if(print_steps) {
991  (*(*s_itr).step_ptr).print_step( *this, step_i, DO_MAIN_STEP, 0, out, leading_str );
992  out << std::endl;
993  }
994  // list post_steps (e.q. 2.1, 2.2, 2.3)
995  const assoc_steps_ele_list_t &post_steps = (*a_itr)[POST_STEP];
996  assoc_steps_ele_list_t::const_iterator post_step_itr = post_steps.begin();
997  for(int post_step_i = 1; post_step_i <= static_cast<poss_type>(post_steps.size()); ++post_step_i, ++post_step_itr) {
998  out << step_i << "." << post_step_i << ". \""
999  << (*post_step_itr).name << "\"\n"
1000  << leading_str << "(" << typeName(*(*post_step_itr).step_ptr) << ")\n";
1001  if(print_steps) {
1002  (*(*post_step_itr).step_ptr).print_step( *this, step_i, DO_POST_STEP, post_step_i
1003  , out, leading_str );
1004  out << std::endl;
1005  }
1006  }
1007  }
1008  if(print_steps) {
1009  out
1010  << step_i << ". \"Major Loop\" :\n"
1011  << " if k >= max_iter then\n"
1012  << " terminate the algorithm\n"
1013  << " elseif run_time() >= max_run_time then\n"
1014  << " terminate the algorithm\n"
1015  << " else\n"
1016  << " k = k + 1\n"
1017  << " goto 1\n"
1018  << " end\n";
1019  }
1020 }
1021 
1022 // validate poss
1023 
1024 Algorithm::poss_type Algorithm::validate(poss_type step_poss, int past_end) const
1025 {
1026 
1028  step_poss < 1 || steps_.size() + past_end < step_poss, DoesNotExist
1029  ,"Algorithm::validate(step_poss) : The step_poss = " << step_poss
1030  << " is not in range of 1 to " << steps_.size() + past_end );
1031  return step_poss;
1032 }
1033 
1034 Algorithm::poss_type Algorithm::validate(const assoc_steps_ele_list_t& assoc_list
1035  , poss_type assoc_step_poss, int past_end) const
1036 {
1038  assoc_step_poss < 1 || assoc_list.size() + past_end < assoc_step_poss, DoesNotExist
1039  ,"Algorithm::validate(assoc_list,assoc_step_poss) : The assoc_step_poss = "
1040  << assoc_step_poss << " is not in range of 1 to " << assoc_list.size() + past_end );
1041  return assoc_step_poss;
1042 }
1043 
1044 void Algorithm::look_for_interrupt()
1045 {
1046  //
1047  // Get the mode of aborting from the user!
1048  //
1049  if( static_interrupt_called && !static_processed_user_interrupt && static_proc_rank == 0 ) {
1050  // Allow for another interrupt possibly
1051  static_interrupt_called = false;
1052  //
1053  // Get the response from the user
1054  //
1055  enum EResponse { R_ABORT_NOW, R_CONTINUE, R_STOP_END_STEP, R_STOP_END_ITER };
1056  EResponse response = R_ABORT_NOW;
1057  const int max_tries = 3;
1058  bool valid_response = false;
1059  for( int tries = 0; !valid_response && tries < max_tries; ++tries ) {
1060  std::cerr
1061  << "\nIterationPack::Algorithm: Received signal SIGINT."
1062  << "\nJust completed current step curr_step_name = \""
1063  << get_step_name(curr_step_poss_) << "\", curr_step_poss = "
1064  << curr_step_poss_ << " of steps [1..." << num_steps() << "]."
1065  << "\nDo you want to:\n"
1066  << " (a) Abort the program immediately?\n"
1067  << " (c) Continue with the algorithm?\n"
1068  << " (s) Gracefully terminate the algorithm at the end of this step?\n"
1069  << " (i) Gracefully terminate the algorithm at the end of this iteration?\n"
1070  << "Answer a, c, s or i ? ";
1071  char abort_mode = 'a';
1072  std::cin >> abort_mode;
1073  if( abort_mode == 'a' ) {
1074  response = R_ABORT_NOW;
1075  valid_response = true;
1076  }
1077  else if( abort_mode == 'c' ) {
1078  response = R_CONTINUE;
1079  valid_response = true;
1080  }
1081  else if( abort_mode == 's' || abort_mode == 'i' ) {
1082  if( abort_mode == 's')
1083  response = R_STOP_END_STEP;
1084  else
1085  response = R_STOP_END_ITER;
1086  std::cerr
1087  << "\nTerminate the algorithm with true (t) or false (f) ? ";
1088  std::cin >> abort_mode;
1089  if( abort_mode == 't' ) {
1090  static_interrupt_terminate_return = true;
1091  valid_response = true;
1092  }
1093  else if( abort_mode == 'f' ) {
1094  static_interrupt_terminate_return = false;
1095  valid_response = true;
1096  }
1097  else {
1098  std::cerr << "Invalid response! Expecting \'t\' or \'f\'\n";
1099  }
1100  }
1101  else {
1102  std::cerr << "\nInvalid response! Expecting \'a\', \'c\', \'s\' or \'i\'\n";
1103  }
1104  std::cerr << std::endl;
1105  }
1106  if(!valid_response) {
1107  std::cerr << "Three strikes, you are out!\n";
1108  }
1109  //
1110  // Interpret the response
1111  //
1112  switch(response) {
1113  case R_ABORT_NOW: {
1114  static_interrupt_status = ABORT_PROGRAM;
1115  break;
1116  }
1117  case R_CONTINUE: {
1118  static_interrupt_status = NOT_INTERRUPTED;
1119  break;
1120  }
1121  case R_STOP_END_STEP: {
1122  static_interrupt_status = STOP_END_STEP;
1123  break;
1124  }
1125  case R_STOP_END_ITER: {
1126  static_interrupt_status = STOP_END_ITER;
1127  break;
1128  }
1129  default: {
1131  }
1132  }
1133  static_processed_user_interrupt = true;
1134  }
1135  else if( interrupt_file_name().length() && !static_processed_user_interrupt && static_proc_rank == 0 ) {
1136  //
1137  // If there was not an interactive interrupt then look for an
1138  // interrupt file if we have not already done this
1139  // (static_processed_user_interrupt).
1140  //
1141  std::ifstream interrupt_file(interrupt_file_name().c_str());
1142  if(interrupt_file) {
1143  std::cerr
1144  << "\nIterationPack::Algorithm: Found the interrupt file \""<<interrupt_file_name()<<"\"!"
1145  << "\nJust completed current step curr_step_name = \""
1146  << get_step_name(curr_step_poss_) << "\", curr_step_poss = "
1147  << curr_step_poss_ << " of steps [1..." << num_steps() << "].\n";
1148  char abort_mode = 0;
1149  interrupt_file >> abort_mode;
1150  std::cerr << "Read a value of abort_mode = \'"<<abort_mode<<"\': ";
1151  if( abort_mode == 'a' ) {
1152  std::cerr << "Will abort the program immediatly!\n";
1153  static_interrupt_status = ABORT_PROGRAM;
1154  }
1155  else if( abort_mode == 's' || abort_mode == 'i' ) {
1156  if( abort_mode == 's') {
1157  std::cerr << "Will abort the program gracefully at the end of this step!\n";
1158  static_interrupt_status = STOP_END_STEP;
1159  }
1160  else {
1161  std::cerr << "Will abort the program gracefully at the end of this iteration!\n";
1162  static_interrupt_status = STOP_END_ITER;
1163  }
1165  interrupt_file.eof(), std::logic_error,
1166  "IterationPack::Algorithm: Error, expected input for terminate_bool option from the "
1167  "file \""<<interrupt_file_name()<<"\"!"
1168  );
1169  char terminate_bool = 0;
1170  interrupt_file >> terminate_bool;
1171  std::cerr << "Read a value of terminate_bool = \'"<<terminate_bool<<"\': ";
1172  if( terminate_bool == 't' ) {
1173  std::cerr << "Will return a success flag!\n";
1174  static_interrupt_terminate_return = true;
1175  }
1176  else if( terminate_bool == 'f' ) {
1177  std::cerr << "Will return a failure flag!\n";
1178  static_interrupt_terminate_return = false;
1179  }
1180  else {
1182  true, std::logic_error
1183  ,"Error, the value of terminate_bool = \'"<<terminate_bool<<"\' is not "
1184  "valid! Valid values include only \'t\' or \'f\'\n"
1185  );
1186  }
1187  }
1188  else {
1190  true, std::logic_error
1191  ,"Error, the value of abort_mode = \'"<<abort_mode<<"\' is not "
1192  "valid! Valid values include only \'a\', \'s\' or \'i\'\n"
1193  );
1194  }
1195  std::cerr << std::endl;
1196  static_processed_user_interrupt = true;
1197  }
1198  }
1199  //
1200  // Make sure that all of the processes get the same
1201  // response
1202  //
1203 #ifdef HAVE_MPI
1204  const bool query_for_interrupt = true; // ToDo: Make this an external option!
1205  if( static_num_proc > 1 && query_for_interrupt ) {
1206  //
1207  // Here we will do a global reduction to see of a processor has
1208  // recieved an interrupt. Here we will do a sum operation since only the
1209  // root process should be getting these options.
1210  //
1211  int sendbuf[2] = { 0, 0 };
1212  int recvbuf[2] = { 0, 0 };
1213  if(static_proc_rank == 0) {
1214  sendbuf[0] = (int)static_interrupt_status;
1215  sendbuf[1] = static_interrupt_terminate_return ? 1 : 0;
1216  }
1217  // Note: this global reduction will synchronize all of the processors!
1218 #ifdef ITERATION_PACK_ALGORITHM_SHOW_MPI_DEBUG_INFO
1219  std::cerr << "\np="<<static_proc_rank<<": IterationPack::Algorithm::interrupt(): Calling MPI_Allreduce(...) ...\n";
1220 #endif
1221  MPI_Allreduce(
1222  sendbuf // sendbuf
1223  ,recvbuf // recvbuf
1224  ,2 // count
1225  ,MPI_INT // datatype
1226  ,MPI_SUM // op
1227  ,MPI_COMM_WORLD // comm (ToDo: Make more general?)
1228  );
1229 #ifdef ITERATION_PACK_ALGORITHM_SHOW_MPI_DEBUG_INFO
1230  std::cerr
1231  << "\np="<<static_proc_rank<<": IterationPack::Algorithm::interrupt(): After MPI_Allreduce(...)"
1232  << "\np="<<static_proc_rank<<": recvbuf[0] = " << recvbuf[0] << ", recvbuf[1] = " << recvbuf[1] << std::endl;
1233 #endif
1234  // Set static_interrupt_status
1235  switch( (EInterruptStatus)recvbuf[0] ) {
1236  case NOT_INTERRUPTED:
1237  static_interrupt_status = NOT_INTERRUPTED;
1238  break;
1239  case STOP_END_STEP:
1240  static_interrupt_status = STOP_END_STEP;
1241  break;
1242  case STOP_END_ITER:
1243  static_interrupt_status = STOP_END_ITER;
1244  break;
1245  case ABORT_PROGRAM:
1246  static_interrupt_status = ABORT_PROGRAM;
1247  break;
1248  default:
1249  std::cerr
1250  << "p=" << static_proc_rank << ": Algorithm::look_for_interrupt(): Error, the globally reduced value of "
1251  "recvbuf[0] = " << recvbuf[0] << " is not valid!";
1252  std::abort();
1253  }
1254  // Set static_interrupt_terminate_return
1255  static_interrupt_terminate_return = ( recvbuf[1] == 0 ? false : true );
1256  }
1257  //
1258  // Abort the program now if the user did not already press Ctrl-C again!
1259  //
1260  if( static_interrupt_status == ABORT_PROGRAM ) {
1261  if( static_proc_rank == 0 ) {
1262  std::cerr << "\nAborting the program now!\n";
1263  }
1264  std::abort();
1265  }
1266 #endif
1267 }
1268 
1269 // static
1270 
1271 void Algorithm::interrupt()
1272 {
1273  //
1274  // This function assumes that every process will recieve the same
1275  // signal which I found to be the case with MPICH. I am not clear
1276  // what the MPI standard says about interrupts so I can not
1277  // guarantee that this is 100% portable. If other behavior is
1278  // needed, this will have to be compiled in differently.
1279  //
1280  // Note: I have found that on MPICH that you can not guarantee that
1281  // only a single signal will be sent to a slave process so this
1282  // function will ignore interupts for slave processes.
1283  //
1284  // Note that you have to be very careful what you do inside of a
1285  // signal handler and in general you should only be setting flags or
1286  // aborting.
1287  //
1288  static_processed_user_interrupt = false;
1289 #ifdef ITERATION_PACK_ALGORITHM_SHOW_MPI_DEBUG_INFO
1290  std::cerr << "\np="<<static_proc_rank<<": IterationPack::Algorithm::interrupt() called!\n";
1291 #endif
1292  //
1293  // See if an algorithm is possibly even running yet!
1294  //
1295  if( static_num_proc == 0 ) {
1296  if( static_proc_rank == 0 )
1297  std::cerr
1298  << "\nIterationPack::Algorithm::interrupt(): Received signal SIGINT but an Algorithm "
1299  << "object has not been allocated yet and no algorithm is running.\n"
1300  << "\nAborting the program now!\n";
1301  std::abort();
1302  return; // Should not be called!
1303  }
1304  //
1305  // See if we are going to query for an interrupt when running in MPI mode
1306  //
1307  const bool query_for_interrupt = true; // ToDo: Make this an external option!
1308  if( !query_for_interrupt && static_num_proc > 1 ) {
1309  if( static_proc_rank == 0 ) {
1310  std::cerr
1311  << "\nIterationPack::Algorithm::interrupt(): Received signal SIGINT but num_proc = "
1312  << static_num_proc << " > 1 and query_for_interrupt = false so:\n"
1313  << "\nAborting the program now!\n";
1314  }
1315  std::abort();
1316  return; // Should not be called!
1317  }
1318  //
1319  // Remember that this interrupt has been called!
1320  //
1321  if( static_proc_rank == 0 ) {
1322  std::cerr
1323  << "\nIterationPack::Algorithm::interrupt(): Received signal SIGINT. "
1324  << "Wait for the end of the current step and respond to an interactive query, "
1325  << "kill the process by sending another signal (i.e. SIGKILL).\n";
1326  }
1327  static_interrupt_called = true;
1328 }
1329 
1330 } // end namespace IterationPack
virtual EAlgoReturn do_algorithm(poss_type step_poss=1)
Called by clients to begin an algorithm.
virtual void initialize()
Reinitialize the track object right before it is used.
Algorithm()
Constructs an algorithm with no steps and a default of max_iter() == 100.
virtual poss_type get_step_poss(const std::string &step_name) const
Return the possition in the major loop of a named step.
ERunningState running_state() const
Return the current running state of this algorithm object.
virtual void print_steps(std::ostream &out) const
Print out just a listing of the steps, their positions in the algorithm and the subclasses.
virtual void begin_config_update()
Changes from running_state() == RUNNING to running_state() == RUNNING_BEING_CONFIGURED.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
virtual void insert_assoc_step(poss_type step_poss, EAssocStepType type, poss_type assoc_step_poss, const std::string &assoc_step_name, const step_ptr_t &assoc_step)
Insert an pre or post step into for the main step step_poss into the possition assoc_step_poss.
Thrown if an invalid control protocal is used.
void get_step_times_k(int offset, double step_times[]) const
Returns the step_times for iteration offset.
virtual const std::string & what_is_next_step_name() const
Returns the name of the next step this will call the next time it calls a step.
void get_final_step_stats(size_t step, double *total, double *average, double *min, double *max, double *percent) const
Returns the final statistics for a given step Do not call when algorithm is running.
virtual void insert_step(poss_type step_poss, const std::string &step_name, const step_ptr_t &step)
Insert a step object with the name step_name into the possition step_poss.
T * get() const
virtual int num_steps() const
Return the number of main steps.
virtual void change_step_name(poss_type step_poss, const std::string &new_name)
Change the name of an existing step.
virtual void output_final(const Algorithm &algo, EAlgoReturn algo_return) const
Output information about a just completed algorithm.
virtual void dump_iter_quant(std::ostream &out) const
iteration quantity information dumping.
virtual void print_algorithm(std::ostream &out) const
Print out the entire algorithm by calling print_step(...) on the step objects.
virtual bool do_step(const std::string &step_name)
Calls do_step() on all of the pre step objects the step object and the post step objects in order for...
virtual void terminate(bool success)
Called by step objects to terminate the algorithm.
virtual void replace_step(poss_type step_poss, const step_ptr_t &step)
Replace the step object of an existing step.
virtual void initialize_step(Algorithm &algo, poss_type step_poss, EDoStepType type, poss_type assoc_step_poss)
Called by Algorithm just before the algorithm is run.
virtual void do_step_next(const std::string &step_name)
Called by step objects to set the step (given its name) that this will envoke the next time this call...
virtual poss_type what_is_next_step_poss() const
Returns the possition of the next step this will call the next time it calls a step.
virtual poss_type get_assoc_step_poss(poss_type step_poss, EAssocStepType type, const std::string &assoc_step_name) const
Return the possition of the pre or post step for the main step_poss.
AlgorithmTracker & track()
virtual int num_assoc_steps(poss_type step_poss, EAssocStepType type) const
Return the number of pre or post steps for the main step step_poss.
virtual step_ptr_t & get_assoc_step(poss_type step_poss, EAssocStepType type, poss_type assoc_step_poss)
Return the RCP<...> object for the associated step object at step_poss and assoc_step_poss.
virtual step_ptr_t & get_step(poss_type step_poss)
Return the RCP<...> object for the step object at step_poss.
virtual void inform_updated(Algorithm &algo, poss_type step_poss, EDoStepType type, poss_type assoc_step_poss)
Called by Algorithm to inform when a runtime configuration change is finihed.
AlgorithmState & state()
virtual void end_config_update()
Changes from running_state() == RUNNING_BEING_CONFIGURED to running_state() == RUNNING.
virtual const std::string & get_step_name(poss_type step_poss) const
Return the name of a step given its possition.
virtual double max_run_time() const
virtual void output_iteration(const Algorithm &algo) const
Output information about an iteration just completed.
virtual void finalize_step(Algorithm &algo, poss_type step_poss, EDoStepType type, poss_type assoc_step_poss)
Called by Algorithm just after an algorithm is terminiated.
virtual void remove_assoc_step(poss_type step_poss, EAssocStepType type, poss_type assoc_step_poss)
Remove an pre or post step for the main step step_poss in the possition assoc_step_poss.
virtual void print_algorithm_times(std::ostream &out) const
Outputs table of times for each step, cummulative times and other statistics.
virtual const std::string & get_assoc_step_name(poss_type step_poss, EAssocStepType type, poss_type assoc_step_poss) const
Return the name of the pre or post step at step_poss and at assoc_step_poss.
virtual void remove_step(poss_type step_poss)
Remove an existing step object and all of its pre and post steps.
virtual size_t max_iter() const
virtual void set_algo_timing(bool algo_timing)
Causes algorithm to be timed.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
virtual void next_iteration(bool incr_k=true)
iteration quantity forwarding.
std::string typeName(const T &t)