MOOCHO (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
IterationPack_Algorithm.cpp
Go to the documentation of this file.
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 
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 
66 {
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)
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 
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 
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 {
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 {
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 {
263  steps_[step_poss - 1].step_ptr = step;
264 }
265 
267 {
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 {
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!" );
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 {
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 {
337 }
338 
340 {
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_
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.
356 
358  reconfigured_ = true;
359 }
360 
361 // algorithmic control
362 
363 void Algorithm::do_step_next(const std::string& step_name)
364 {
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 {
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 {
384  return *next_step_name_;
385 }
386 
388 {
390  return next_step_poss_;
391 }
392 
393 bool Algorithm::do_step(const std::string& step_name)
394 {
396  return imp_do_step( std::distance( steps_.begin() , step_itr_and_assert(step_name) ) + 1 );
397 }
398 
400 {
402  return imp_do_step(step_poss);
403 }
404 
405 void Algorithm::terminate(bool success)
406 {
409 }
410 
411 // start iterations
412 
414 {
416 
418 
419  track().initialize();
420 
421  try{
422 
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 
444 
445  overall_timer.start();
446  for(;;) {
447 
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
467  // Add to time for the full iteration
469  }
470 
471  // See if a step object called terminate(...)
473  EAlgoReturn algo_return;
474  if( static_interrupt_status == STOP_END_STEP ) {
475  algo_return = ( terminate_status_ == STATUS_TERMINATE_TRUE
478  static_interrupt_status = NOT_INTERRUPTED;
479  }
480  else {
481  algo_return = ( terminate_status_ == STATUS_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() ) {
504  }
505 
506  // Check if the maximum runtime has been exceeded.
507  if( ( overall_timer.read() / 60 ) >= max_run_time() ) {
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
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_;
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.
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 {
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 ) {
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 
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 
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.
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 
768 {
771  track().output_final(*this,algo_return);
772  return algo_return;
773 }
774 
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 
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 
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 
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 
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 )
908  if( static_interrupt_status == STOP_END_STEP ) {
909  terminate( static_interrupt_terminate_return );
910  return false;
911  }
912  return true;
913 }
914 
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 
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 
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 
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 
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
std::vector< double > step_times_t
void sig_handler_interrupt_algorithm(int signum)
void validate_not_in_state(ERunningState running_state) const
Validate that this is not in a specific running state.
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.
step_ptr_and_name< step_ptr_t > assoc_steps_ele_list_ele_t
std::string typeName(const T &t)
step_ptr_and_name< step_ptr_t > steps_ele_t
steps_t::iterator step_itr(const std::string &step_name)
Find a step given its name and throw a DoesNotExist exception if not found.
bool imp_do_step(poss_type step_poss)
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.
int MPI_Comm_size(MPI_Comm comm, int *size)
Definition: RTOp_mpi.c:71
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.
int MPI_Comm_rank(MPI_Comm comm, int *rank)
Definition: RTOp_mpi.c:77
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 name or id does not exist.
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.
value_type max_element(const Vector &v)
Compute the maximum element in a vector.
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.
int MPI_Init(int *argc, char ***argv)
Definition: RTOp_mpi.c:61
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.
void imp_inform_steps(inform_func_ptr_t inform_func_ptr)
T * get() const
virtual int num_steps() const
Return the number of main steps.
void validate_in_state(ERunningState running_state) const
Validate that this is in a specific running state.
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.
void validate_not_next_step(const std::string &step_name) const
Validate that the step_name in not the next step.
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.
const f_int f_dbl_prec const f_int f_int const f_int f_int const f_dbl_prec f_int f_int f_dbl_prec w[]
void imp_print_algorithm(std::ostream &out, bool print_steps) const
virtual void replace_step(poss_type step_poss, const step_ptr_t &step)
Replace the step object of an existing step.
Simple stopwatch object.
std::ostream * out
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.
steps_t::iterator step_itr_and_assert(const std::string &step_name)
Find a step given its name and throw a DoesNotExist exception if not found.
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.
int MPI_Allreduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
Definition: RTOp_mpi.c:164
std::list< assoc_steps_ele_list_ele_t > assoc_steps_ele_list_t
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()
static assoc_steps_ele_list_t::iterator assoc_step_itr(assoc_steps_ele_list_t &assoc_list, const std::string &assoc_step_name)
Find a an associated step given its name and throw a DoesNotExist exception if not found...
void validate_not_curr_step(poss_type step_poss) const
Validate that the step_poss in not the current step.
EDoStepType do_step_type(EAssocStepType assoc_step_type)
EAssocStepType -> EDoStepType.
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
EAlgoReturn finalize_algorithm(EAlgoReturn algo_return)
virtual void output_iteration(const Algorithm &algo) const
Output information about an iteration just completed.
Thrown if a member function is called while this is in an invalid running state.. ...
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.
Thrown if a member function is called while this is in an invalid running state.. ...
#define MPI_SUM
Definition: RTOp_mpi.h:74
virtual void remove_step(poss_type step_poss)
Remove an existing step object and all of its pre and post steps.
#define MPI_INT
Definition: RTOp_mpi.h:64
#define MPI_COMM_WORLD
Definition: RTOp_mpi.h:68
bool imp_do_assoc_steps(EAssocStepType type)
int n
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.
void change_running_state(ERunningState running_state)
Change the running state.
poss_type validate(poss_type step_poss, int past_end=0) const
Validate a step_poss and throw a DoesNotExist exception if it does not.