IterationPack_Algorithm.cpp

00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 // Moocho: Multi-functional Object-Oriented arCHitecture for Optimization
00005 //                  Copyright (2003) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 #include <signal.h>
00030 
00031 #include <iterator>
00032 #include <numeric>
00033 
00034 #include "IterationPack_Algorithm.hpp"
00035 #include "StopWatchPack_stopwatch.hpp"
00036 #include "Teuchos_TestForException.hpp"
00037 #include "Teuchos_TypeNameTraits.hpp"
00038 
00039 #ifdef HAVE_MPI
00040 #include "mpi.h"
00041 #endif
00042 
00043 // Define to see MPI/interrupt deugging output
00044 //#define ITERATION_PACK_ALGORITHM_SHOW_MPI_DEBUG_INFO
00045 
00046 // Define of the MPI implementation receives signals on all processes
00047 //#define ITERATION_PACK_ALGORITHM_SIGNALS_ON_ALL_PROCESSES;
00048 
00049 extern "C" {
00050 
00051 void sig_handler_interrupt_algorithm( int signum )
00052 {
00053   IterationPack::Algorithm::interrupt();
00054 }
00055 
00056 } // extern "C"
00057 
00058 namespace {
00059 
00060 // Helper functions
00061 
00062 template< class T >
00063 inline
00064 T my_max( const T& v1, const T& v2 ) { return v1 > v2 ? v1 : v2; }
00065 
00066 // Private static data for IterationPack::Algorithm.
00067 // I put it here so that I can modify it without affecting the
00068 // header file and avoiding unnecessary recompilations.
00069 
00070 enum EInterruptStatus { NOT_INTERRUPTED=0, STOP_END_STEP=1, STOP_END_ITER=2, ABORT_PROGRAM=3 };
00071 
00072 int static_mpi_initialized = false;
00073 int static_num_running_algorithms = 0;
00074 int static_num_proc = 0; // Flag that no algorithm has been even allocated yet!
00075 int static_proc_rank = 0;
00076 bool static_interrupt_called = false;
00077 bool static_processed_user_interrupt = false;
00078 EInterruptStatus static_interrupt_status = NOT_INTERRUPTED;
00079 bool static_interrupt_terminate_return = false;
00080 
00081 } // end namespace
00082 
00083 // ToDo: change step_itr and assoc_step_itr to just return iterators without
00084 // asserting if the names exist.  This will be more useful.
00085 
00086 namespace IterationPack {
00087 
00088 // constructors / destructor
00089 
00090 Algorithm::Algorithm()
00091   :running_state_(NOT_RUNNING), max_iter_(100)
00092   ,max_run_time_(std::numeric_limits<double>::max())
00093   ,next_step_name_(0), do_step_next_called_(false), reconfigured_(false)
00094   ,time_stats_computed_(false)
00095 {
00096   // Set MPI info
00097   static_num_proc = 1;
00098   static_proc_rank = 0;
00099 #ifdef HAVE_MPI
00100   // If MPI is not initialized then this must be because the code was
00101   // compiled with support for MPI but it not actually using it.
00102   // Therefore, we will initialize MPI but not bother to finialize it.
00103   if(!static_mpi_initialized) {
00104     int mpi_initialized = false;
00105     MPI_Initialized(&mpi_initialized);
00106     if(!mpi_initialized) {
00107       int argc = 1;
00108       char arg_str[] = "dummy_prg";
00109       char *arg_str_ptr = arg_str;
00110       char **argv = &arg_str_ptr;
00111       MPI_Init( &argc, &argv );
00112     }
00113     static_mpi_initialized = true;
00114   }
00115   // ToDo: Allow the specification of another communicator if needed!
00116   MPI_Comm_size( MPI_COMM_WORLD, &static_num_proc );
00117   MPI_Comm_rank( MPI_COMM_WORLD, &static_proc_rank );
00118 #ifdef ITERATION_PACK_ALGORITHM_SHOW_MPI_DEBUG_INFO
00119   std::cerr << "\np=" << static_proc_rank << ": Algorithm::Algorithm() being called (num_proc = "<<static_num_proc<<") ... \n";
00120 #endif
00121 #endif // HAVE_MPI
00122 }
00123 
00124 Algorithm::~Algorithm()
00125 {}
00126 
00127 // maximum iterations
00128 
00129 void Algorithm::max_iter(size_t max_iter)
00130 { max_iter_ = max_iter; }
00131 
00132 size_t Algorithm::max_iter() const
00133 { return max_iter_; }
00134 
00135 // maximum run tine
00136 
00137 void Algorithm::max_run_time(double max_run_time)
00138 { max_run_time_ = max_run_time; }
00139 
00140 double Algorithm::max_run_time() const
00141 { return max_run_time_; }
00142 
00143 
00144 // step information / access
00145 
00146 int Algorithm::num_steps() const
00147 { return steps_.size(); }
00148 
00149 Algorithm::poss_type Algorithm::get_step_poss(const std::string& step_name) const
00150 { 
00151   steps_t::const_iterator itr = step_itr(step_name);
00152   return itr == steps_.end() ? DOES_NOT_EXIST : std::distance( steps_.begin(), itr ) + 1;
00153 }
00154 
00155 const std::string& Algorithm::get_step_name(poss_type step_poss) const
00156 { return steps_[validate(step_poss) - 1].name; }
00157 
00158 Algorithm::step_ptr_t& Algorithm::get_step(poss_type step_poss)
00159 { return steps_[validate(step_poss) - 1].step_ptr; }
00160 
00161 const Algorithm::step_ptr_t& Algorithm::get_step(poss_type step_poss) const
00162 { return steps_[validate(step_poss) - 1].step_ptr; }
00163 
00164 // pre/post step information / access
00165 
00166 int Algorithm::num_assoc_steps(poss_type step_poss, EAssocStepType type) const
00167 { return assoc_steps_[validate(step_poss) - 1][type].size(); }
00168 
00169 Algorithm::poss_type Algorithm::get_assoc_step_poss(poss_type step_poss, EAssocStepType type
00170   ,const std::string& assoc_step_name) const
00171 { 
00172   // ToDo: change to return DOES_NOT_EXIST if it does not exist.
00173   const assoc_steps_ele_list_t &assoc_list = assoc_steps_[validate(step_poss) - 1][type];
00174   assoc_steps_ele_list_t::const_iterator itr = assoc_step_itr(assoc_list,assoc_step_name);
00175   return itr == assoc_list.end() ? DOES_NOT_EXIST : std::distance( assoc_list.begin() , itr ) + 1;
00176 }
00177 
00178 const std::string& Algorithm::get_assoc_step_name(poss_type step_poss, EAssocStepType type
00179   , poss_type assoc_step_poss) const
00180 {
00181   const assoc_steps_ele_list_t &assoc_list= assoc_steps_[validate(step_poss) - 1][type];
00182   validate(assoc_list,assoc_step_poss);
00183   assoc_steps_ele_list_t::const_iterator itr = assoc_list.begin();
00184   std::advance( itr, assoc_step_poss - 1 );
00185   return (*itr).name;
00186 }
00187 
00188 Algorithm::step_ptr_t& Algorithm::get_assoc_step(poss_type step_poss, EAssocStepType type
00189   , poss_type assoc_step_poss)
00190 {
00191   assoc_steps_ele_list_t &assoc_list= assoc_steps_[validate(step_poss) - 1][type];
00192   validate(assoc_list,assoc_step_poss);
00193   assoc_steps_ele_list_t::iterator itr = assoc_list.begin();
00194   std::advance( itr, assoc_step_poss - 1 );
00195   return (*itr).step_ptr;
00196 }
00197 
00198 const Algorithm::step_ptr_t& Algorithm::get_assoc_step(poss_type step_poss, EAssocStepType type
00199   , poss_type assoc_step_poss) const
00200 {
00201   const assoc_steps_ele_list_t &assoc_list= assoc_steps_[validate(step_poss) - 1][type];
00202   validate(assoc_list,assoc_step_poss);
00203   assoc_steps_ele_list_t::const_iterator itr = assoc_list.begin();
00204   std::advance( itr, assoc_step_poss - 1 );
00205   return (*itr).step_ptr;
00206 }
00207 
00208 // step manipulation
00209 
00210 void Algorithm::insert_step(poss_type step_poss, const std::string& step_name, const step_ptr_t& step)
00211 {
00212   validate_not_in_state(RUNNING);
00213   TEST_FOR_EXCEPTION(
00214     step.get() == NULL, std::invalid_argument
00215     ,"Algorithm::insert_step(...) : A step with the name = \'" << step_name
00216     << "\' being inserted into the position  = " << step_poss
00217     << " has step.get() == NULL!" );
00218   // Make sure a step with this name does not already exist.
00219   steps_t::iterator itr;
00220   if( steps_.end() != ( itr = step_itr(step_name) ) )
00221     TEST_FOR_EXCEPTION(
00222       true, AlreadyExists
00223       ,"Algorithm::insert_step(...) : A step with the name = " << step_name
00224       << " already exists at step_poss = " << std::distance(steps_.begin(),itr) + 1 );
00225   // insert the step in such a way that any container can be used for steps_
00226   itr = steps_.begin();
00227   std::advance ( itr , validate(step_poss,+1) - 1 );
00228   steps_.insert( itr , steps_ele_t(step,step_name) );
00229   // insert the assoc_step element in such a way that any container can be used for assoc_steps_
00230   assoc_steps_t::iterator a_itr = assoc_steps_.begin();
00231   std::advance ( a_itr , step_poss - 1 );
00232   assoc_steps_.insert( a_itr , assoc_steps_ele_t() );
00233 }
00234 
00235 void Algorithm::change_step_name(poss_type step_poss, const std::string& new_name)
00236 {
00237   validate_not_in_state(RUNNING);
00238   if(running_state() == RUNNING_BEING_CONFIGURED) {
00239     validate_not_curr_step(validate(step_poss));
00240     validate_not_next_step(steps_[step_poss - 1].name);
00241   }
00242   steps_[step_poss - 1].name = new_name;
00243 }
00244 
00245 void Algorithm::replace_step(poss_type step_poss, const step_ptr_t& step)
00246 {
00247   validate_not_in_state(RUNNING);
00248   if(running_state() == RUNNING_BEING_CONFIGURED) validate_not_curr_step(validate(step_poss));
00249   steps_[step_poss - 1].step_ptr = step;
00250 }
00251 
00252 void Algorithm::remove_step(poss_type step_poss)
00253 {
00254   validate_not_in_state(RUNNING);
00255   if(running_state() == RUNNING_BEING_CONFIGURED) {
00256     validate_not_curr_step(validate(step_poss));
00257     validate_not_next_step(steps_[step_poss - 1].name);
00258   }
00259   // remove the step in such a way that any container can be used for steps_
00260   steps_t::iterator itr = steps_.begin();
00261   std::advance ( itr , validate(step_poss) - 1 );
00262   steps_.erase( itr );
00263   // remove the assoc_step element in such a way that any container can be used for assoc_steps_
00264   assoc_steps_t::iterator a_itr = assoc_steps_.begin();
00265   std::advance ( a_itr , step_poss - 1 );
00266   assoc_steps_.erase( a_itr );
00267 }
00268 
00269 // pre/post step manipulation
00270 
00271 void Algorithm::insert_assoc_step(poss_type step_poss, EAssocStepType type, poss_type assoc_step_poss
00272   , const std::string& assoc_step_name, const step_ptr_t& assoc_step)
00273 {
00274   validate_not_in_state(RUNNING);
00275   TEST_FOR_EXCEPTION(
00276     assoc_step.get() == NULL, std::invalid_argument
00277     ,"Algorithm::insert_assoc_step(...) : A step with the name = \'" << assoc_step_name
00278     << "\' being inserted into the position  = " << step_poss
00279     << "." << ( type == PRE_STEP
00280           ? (int)assoc_step_poss - num_assoc_steps(step_poss,type) - 1
00281           : assoc_step_poss )
00282     << " has assoc_step.get() == NULL!" );
00283   if(running_state() == RUNNING_BEING_CONFIGURED) validate_not_curr_step(validate(step_poss));
00284   // Make sure an associated step with this name does not already exist.
00285   assoc_steps_ele_list_t &assoc_list = assoc_steps_[step_poss - 1][type];
00286   validate(assoc_list,assoc_step_poss,+1);
00287   assoc_steps_ele_list_t::iterator itr = assoc_list.begin();
00288   char assoc_type_name[2][10] = { "PRE_STEP" , "POST_STEP" };
00289   if( assoc_list.end() != ( itr = assoc_step_itr(assoc_list,assoc_step_name) ) )
00290     TEST_FOR_EXCEPTION(
00291       true, AlreadyExists
00292       ,"Algorithm::insert_assoc_step(...) : An associated step of type = "
00293       <<  assoc_type_name[type]
00294       << " with the name = " << assoc_step_name
00295       << " already exists at step_poss = " << step_poss
00296       << " and assoc_step_poss = " <<  std::distance(assoc_list.begin(),itr) + 1 );
00297   // insert an associated step in such a way that any container could be used.
00298   itr = assoc_list.begin();
00299   std::advance( itr, assoc_step_poss - 1 );
00300   assoc_list.insert( itr , assoc_steps_ele_list_ele_t(assoc_step,assoc_step_name) );
00301 }
00302 
00303 void Algorithm::remove_assoc_step(poss_type step_poss, EAssocStepType type, poss_type assoc_step_poss)
00304 {
00305   validate_not_in_state(RUNNING);
00306   if(running_state() == RUNNING_BEING_CONFIGURED) validate_not_curr_step(validate(step_poss));
00307   validate(step_poss);
00308   assoc_steps_ele_list_t &assos_list = assoc_steps_[step_poss - 1][type];
00309   validate(assos_list,assoc_step_poss);
00310   assoc_steps_ele_list_t::iterator itr = assos_list.begin();
00311   std::advance( itr, assoc_step_poss - 1 );
00312   assos_list.erase( itr );
00313 }
00314 
00315 //  runtime configuration updating control
00316 
00317 void Algorithm::begin_config_update()
00318 {
00319   validate_in_state(RUNNING);
00320   saved_next_step_name_ = *next_step_name_;
00321   saved_curr_step_name_ = steps_[curr_step_poss_ - 1].name;
00322   change_running_state(RUNNING_BEING_CONFIGURED);
00323 }
00324 
00325 void Algorithm::end_config_update()
00326 {
00327   validate_in_state(RUNNING_BEING_CONFIGURED);
00328 
00329   // update next_step_poss_ and next_step_name_.
00330   steps_t::iterator itr = step_itr(saved_next_step_name_);
00331   TEST_FOR_EXCEPT( !(  itr != steps_.end()  ) );  // the step with this name should not have been deleted or changed.
00332   next_step_poss_ = std::distance( steps_.begin() , itr ) + 1;
00333   next_step_name_ = &(*itr).name;
00334 
00335   // update curr_step_poss_
00336   itr = step_itr(saved_curr_step_name_);
00337   TEST_FOR_EXCEPT( !(  itr != steps_.end()  ) );  // the step with this name should not have been deleted or changed.
00338   curr_step_poss_ = std::distance( steps_.begin() , itr ) + 1;
00339 
00340   // inform the step objects that *this has changes.
00341   imp_inform_steps( &AlgorithmStep::inform_updated );
00342 
00343   change_running_state(RUNNING);
00344   reconfigured_ = true;
00345 }
00346 
00347 // algorithmic control
00348 
00349 void Algorithm::do_step_next(const std::string& step_name)
00350 {
00351   validate_in_state(RUNNING);
00352   steps_t::iterator itr = step_itr_and_assert(step_name);
00353   next_step_poss_ = std::distance( steps_.begin() , itr ) + 1;
00354   next_step_name_ = &(*itr).name;
00355   do_step_next_called_ = true;
00356 }
00357 
00358 void Algorithm::do_step_next(poss_type step_poss)
00359 {
00360   validate_in_state(RUNNING);
00361   const steps_ele_t &ele = steps_[validate(step_poss) - 1];
00362   next_step_poss_ = step_poss;
00363   next_step_name_ = &ele.name;
00364   do_step_next_called_ = true;
00365 }
00366 
00367 const std::string& Algorithm::what_is_next_step_name() const
00368 {
00369   validate_in_state(RUNNING);
00370   return *next_step_name_;
00371 }
00372 
00373 Algorithm::poss_type Algorithm::what_is_next_step_poss() const
00374 { 
00375   validate_in_state(RUNNING);
00376   return next_step_poss_;
00377 }
00378 
00379 bool Algorithm::do_step(const std::string& step_name)
00380 {
00381   validate_in_state(RUNNING);
00382   return imp_do_step( std::distance( steps_.begin() , step_itr_and_assert(step_name) ) + 1 );
00383 }
00384 
00385 bool Algorithm::do_step(poss_type step_poss)
00386 {
00387   validate_in_state(RUNNING);
00388   return imp_do_step(step_poss);
00389 }
00390 
00391 void Algorithm::terminate(bool success)
00392 { 
00393   validate_in_state(RUNNING);
00394   terminate_status_ = success ? STATUS_TERMINATE_TRUE : STATUS_TERMINATE_FALSE;
00395 }
00396 
00397 // start iterations
00398 
00399 EAlgoReturn Algorithm::do_algorithm(poss_type step_poss)
00400 {
00401   using StopWatchPack::stopwatch;
00402 
00403   validate_in_state(NOT_RUNNING);
00404 
00405   track().initialize();
00406 
00407   try{
00408   
00409   terminate_status_ = STATUS_KEEP_RUNNING;
00410   change_running_state(RUNNING);
00411 
00412   first_k_ = state().k();
00413   next_step_poss_ = validate(step_poss);
00414   next_step_name_ = &steps_[step_poss - 1].name;
00415   
00416   // Prepair for timing algorithm
00417   step_times_.resize( algo_timing_ ? (num_steps()+1) * (max_iter()+1+NUM_STEP_TIME_STATS) : 0 );
00418   if( algo_timing_ ) {
00419 //    step_times_[ max_iter() ] = 0.0;  // flag for statistics not calc. yet.
00420 //    // set iteration totals to zero
00421 //    if( step_times_[(max_iter() + 1 + 5) * num_steps()] != 0.0 )
00422 //      std::fill_n( step_times_.begin() + (max_iter() + 1 + 5) * num_steps(), max_iter(), 0.0 );
00423     std::fill_n( step_times_.begin(), step_times_.size(), 0.0 );  // Try setting everything to zero?
00424     time_stats_computed_ = false;
00425   }
00426   stopwatch step_timer;
00427   stopwatch overall_timer;
00428 
00429   imp_inform_steps( &AlgorithmStep::initialize_step );
00430 
00431   overall_timer.start();
00432   for(;;) {
00433 
00434     curr_step_poss_ = next_step_poss_;
00435     // Note that curr_step_poss_ may change if there is a runtime
00436     // change in the configuration of the steps.
00437 
00438     bool keep_on = true;
00439 
00440     // Execute the steps for this step
00441     
00442     if( algo_timing_ ) {
00443       step_timer.reset();
00444       step_timer.start();
00445     }
00446 
00447     keep_on = imp_do_step(curr_step_poss_);
00448 
00449     if( algo_timing_ ) {
00450       const double time = my_max(step_timer.stop(),-1e-50); // negative somehow (g++ -O2 ?)
00451       // time for step k for the iteration
00452       step_times_[state().k()-first_k_+(curr_step_poss_-1)*(max_iter()+1+NUM_STEP_TIME_STATS)] = time;
00453       // Add to time for the full iteration
00454       step_times_[state().k()-first_k_+(num_steps())*(max_iter()+1+NUM_STEP_TIME_STATS)] += time;
00455     }
00456 
00457     // See if a step object called terminate(...)
00458     if(terminate_status_ != STATUS_KEEP_RUNNING) {
00459       EAlgoReturn algo_return;
00460       if( static_interrupt_status == STOP_END_STEP ) {
00461         algo_return = ( terminate_status_ == STATUS_TERMINATE_TRUE
00462                         ? INTERRUPTED_TERMINATE_TRUE
00463                         : INTERRUPTED_TERMINATE_FALSE );
00464         static_interrupt_status = NOT_INTERRUPTED;
00465       }
00466       else {
00467         algo_return = ( terminate_status_ == STATUS_TERMINATE_TRUE
00468                         ? TERMINATE_TRUE
00469                         : TERMINATE_FALSE );
00470       }
00471       return finalize_algorithm(algo_return);
00472     }
00473 
00474     if(keep_on) {
00475 
00476       // All the step objects returned true so increment the step and loop around
00477 
00478       if( curr_step_poss_ == static_cast<poss_type>(num_steps()) ) {
00479 
00480         //
00481         // This is the last step in the algorithm
00482         //
00483   
00484         // Output this iteration
00485         track().output_iteration(*this);
00486 
00487         // Check if the maximum number of iterations has been exceeded.
00488         if( state().k() - first_k_ >= max_iter() ) {
00489           return finalize_algorithm(MAX_ITER_EXCEEDED);
00490         }
00491 
00492         // Check if the maximum runtime has been exceeded.
00493         if( ( overall_timer.read() / 60 ) >= max_run_time() ) {
00494           return finalize_algorithm(MAX_RUN_TIME_EXCEEDED);
00495         }
00496 
00497         // Set if the algorithm was interrupted
00498         if( static_interrupt_status == STOP_END_ITER ) {
00499           static_interrupt_status = NOT_INTERRUPTED;
00500           const EAlgoReturn algo_return = ( static_interrupt_terminate_return
00501                                             ? INTERRUPTED_TERMINATE_TRUE
00502                                             : INTERRUPTED_TERMINATE_FALSE );
00503           return finalize_algorithm(algo_return);
00504         }
00505 
00506         // Transition the iteration quantities to k = k + 1
00507         state().next_iteration();
00508 
00509         // Setup to start the major loop over again
00510         next_step_poss_ = 1;
00511         next_step_name_ = &steps_[0].name;
00512 
00513       }
00514       else {
00515 
00516         // else just increment the step
00517         ++next_step_poss_;
00518         next_step_name_ = &steps_[next_step_poss_ - 1].name;
00519 
00520       }
00521 
00522       continue; // loop around
00523 
00524     }
00525     else {
00526       // some step object returned false from its do_step(..) operation so it
00527       // should have called do_step_next(...) to request a jump to
00528       // a specific operation.
00529       if(!do_step_next_called_)
00530         TEST_FOR_EXCEPTION(
00531           true, InvalidControlProtocal
00532           ,"EAlgoReturn Algorithm::do_algorithm(...) :"
00533           " A step object returned false from its do_step(...) operation"
00534           " without calling do_step_next(...) to request jump to a specific"
00535           " step." );
00536       do_step_next_called_ = false;
00537       // just loop around and do the step that the step object requested
00538       // by changing next_step_poss_ by its call to do_step_next(...).
00539     }
00540   } // end for(;;)
00541 
00542   } // end try
00543   catch(...) {
00544     try {
00545       finalize_algorithm(TERMINATE_FALSE);
00546     }
00547     catch(...) {
00548       // We tried to finalize gracefully but we failed!
00549     }
00550     throw;
00551   }
00552 }
00553 
00554 // algorithm information output
00555 
00556 void Algorithm::print_steps(std::ostream& out) const
00557 {
00558   out << "\n*** Algorithm Steps ***\n\n";
00559   imp_print_algorithm(out,false);
00560   out << std::endl;
00561 }
00562 
00563 void Algorithm::print_algorithm(std::ostream& out) const
00564 {
00565   out << "\n*** Iteration Quantities ***\n\n";
00566   state().dump_iter_quant(out);
00567   out << std::endl;
00568   out << "\n*** Algorithm Description ***\n\n";
00569   imp_print_algorithm(out,true);
00570   out << std::endl;
00571 }
00572 
00573 // Algorithm Timing.
00574 
00575 void Algorithm::set_algo_timing( bool algo_timing ) {
00576    validate_not_in_state(RUNNING);
00577   algo_timing_ = algo_timing;
00578 }
00579 
00580 bool Algorithm::algo_timing() const {
00581   return algo_timing_;
00582 }
00583 
00584 void Algorithm::print_algorithm_times( std::ostream& out ) const
00585 {
00586   using std::setw;
00587   using std::endl;
00588 
00589   validate_not_in_state(RUNNING);
00590 
00591   if( step_times_.size() == 0 ) {
00592     out << "No step timing was performed\n";
00593     return;
00594   }
00595 
00596   const int w = 10;
00597   const int prec = 4;
00598   const int n = num_steps();          // Total steps
00599   const int m = state().k() - first_k_ + 1; // Total number of iterations performed
00600   const int mm = max_iter()+1;        // Total number of possible iterations
00601   const int mmm = mm + NUM_STEP_TIME_STATS; // total entries in a step_i row
00602    
00603   // Print the header.
00604   out << "\n\n**************************************\n"
00605     << "*** Algorithm step CPU times (sec) ***\n";
00606 
00607   // Print the step names.
00608   out << "\nStep names"
00609     << "\n----------\n";
00610   {for( int i = 1; i <= n; ++i ) {
00611     out << i << ") \"" << get_step_name(i) << "\"\n"; 
00612   }}
00613   out << n+1 << ") Iteration total\n";  
00614   out << endl;
00615 
00616   out << std::right << std::setprecision(prec);
00617 
00618   // Print table header
00619   out << setw(w) << "" << "  steps 1..." << n+1 << " ->\n\n";
00620   
00621   // print step numbers
00622   out << setw(w)  << " iter k";
00623   {for( int i = 1; i <= n+1; ++i ) {
00624     out << setw(w) << i;  
00625   }}
00626   out << endl;
00627   out << setw(w)  << "--------";
00628   {for( int i = 1; i <= n+1; ++i ) {
00629     out << setw(w) << "--------"; 
00630   }}
00631   out << endl;
00632   // Print the step times.
00633   {for( int k = 0; k < m; ++k ) {
00634     out << setw(w)  << first_k_ + k;
00635     {for( int i = 0; i < n+1; ++i ) {
00636       out << setw(w) << step_times_[k+i*mmm]; 
00637     }}
00638     out << endl;
00639   }}
00640 
00641   // Compute the (1) totals for each step, the (2) average, (3) min and (4) max times
00642   // per iteration for each step and the (5) precentages for each step.
00643 
00644   compute_final_time_stats();
00645 
00646   // Ouput time statistics.
00647   
00648   out << setw(w)  << "--------";
00649   {for( int i = 1; i <= n+1; ++i ) {
00650     out << setw(w) << "--------"; 
00651   }}
00652 
00653   // Output the total times for each step.
00654   out << endl;
00655   out << setw(w)  << "total(sec)";
00656   {for( int i = 0; i < n+1; ++i ) {
00657     const double *step_i_times = &step_times_[i*mmm];
00658     out << setw(w) << step_i_times[ mm + TIME_STAT_TOTALS_OFFSET ]; 
00659   }}
00660   out << endl;
00661 
00662   // Output the average times per iteration
00663   out << setw(w)  << "av(sec)/k";
00664   {for( int i = 0; i < n+1; ++i ) {
00665     const double *step_i_times = &step_times_[i*mmm];
00666     out << setw(w) << step_i_times[ mm + TIME_STAT_AV_OFFSET ]; 
00667   }}
00668   out << endl;
00669 
00670   // Output the min times per iteration
00671   out << setw(w)  << "min(sec)";
00672   {for( int i = 0; i < n+1; ++i ) {
00673     const double *step_i_times = &step_times_[i*mmm];
00674     out << setw(w) << step_i_times[ mm + TIME_STAT_MIN_OFFSET ];  
00675   }}
00676   out << endl;
00677 
00678   // Output the max times per iteration
00679   out << setw(w)  << "max(sec)";
00680   {for( int i = 0; i < n+1; ++i ) {
00681     const double *step_i_times = &step_times_[i*mmm];
00682     out << setw(w) << step_i_times[ mm + TIME_STAT_MAX_OFFSET ];  
00683   }}
00684   out << endl;
00685 
00686   // Output the precentage times for each step.
00687   out << setw(w)  << "% total";
00688   {for( int i = 0; i < n+1; ++i ) {
00689     const double *step_i_times = &step_times_[i*mmm];
00690     out << setw(w) << step_i_times[ mm + TIME_STAT_PERCENT_OFFSET ] * 100.0;  
00691   }}
00692   out << endl;
00693 
00694 
00695   // Print total time for entire algorithm.
00696   out << "------------------------------" << endl
00697     << "total CPU time = " << total_time_ << " sec\n";;
00698 }
00699 
00700 
00701 void Algorithm::get_step_times_k( int offset, double step_times[] ) const
00702 {
00703   TEST_FOR_EXCEPTION(
00704     step_times_.size() == 0, std::logic_error
00705     ,"Algorithm::get_step_times_k(...) : times requested, but no times calculated!"
00706     );
00707   TEST_FOR_EXCEPTION(
00708     offset > 0, std::invalid_argument
00709     ,"Algorithm::get_step_times_k(...) : Can\'t get times for an iteratin that has not occured yet!."
00710     );
00711 
00712   const int n = num_steps();          // Total steps
00713   //const int m = state().k() - first_k_ + 1; // Total number of iterations performed
00714   const int mm = max_iter()+1;        // Total number of possible iterations
00715   const int mmm = mm + NUM_STEP_TIME_STATS; // total entries in a step_i row
00716   
00717   const int k = state().k() + offset;
00718   {for (int step = 0; step < n+1; ++step) {
00719     step_times[step] = step_times_[step*mmm + k];   
00720   }}
00721 
00722 }
00723 
00724 void Algorithm::get_final_step_stats( size_t step, double* total, double* average, double* min, double* max, double* percent) const
00725 {
00726   // Compute the (1) totals for each step, the (2) average, (3) min and (4) max times
00727   // per iteration for each step and the (5) precentages for each step.
00728   compute_final_time_stats();
00729 
00730   //const int n = num_steps();          // Total steps
00731   //const int m = state().k() - first_k_ + 1; // Total number of iterations performed
00732   const int mm = max_iter()+1;        // Total number of possible iterations
00733   const int mmm = mm + NUM_STEP_TIME_STATS; // total entries in a step_i row
00734 
00735   double* step_i_times = &const_cast<step_times_t&>(step_times_)[step*mmm];
00736   if (total) {
00737     *total   = step_i_times[mm + TIME_STAT_TOTALS_OFFSET];
00738   }
00739   if (average) {
00740     *average = step_i_times[mm + TIME_STAT_AV_OFFSET];
00741   }
00742   if (min) {
00743     *min     = step_i_times[mm + TIME_STAT_MIN_OFFSET];
00744   }
00745   if (max) {
00746     *max     = step_i_times[mm + TIME_STAT_MAX_OFFSET];
00747   }
00748   if (percent) {
00749     *percent = step_i_times[mm + TIME_STAT_PERCENT_OFFSET];
00750   }
00751 }
00752 
00753 EAlgoReturn Algorithm::finalize_algorithm( EAlgoReturn algo_return )
00754 {
00755   change_running_state(NOT_RUNNING);
00756   imp_inform_steps( &AlgorithmStep::finalize_step );
00757   track().output_final(*this,algo_return);
00758   return algo_return;
00759 }
00760 
00761 void Algorithm::compute_final_time_stats() const
00762 {
00763   if (!time_stats_computed_) {
00764     time_stats_computed_ = true;
00765     
00766     const int n = num_steps();          // Total steps
00767     const int m = state().k() - first_k_ + 1; // Total number of iterations performed
00768     const int mm = max_iter()+1;        // Total number of possible iterations
00769     const int mmm = mm + NUM_STEP_TIME_STATS; // total entries in a step_i row
00770     
00771     // compute totals for each step (1...n) and the full iteration (n+1)
00772     double &_total_time = const_cast<double&>(total_time_);
00773     _total_time = 0.0;
00774     
00775     {for( int i = 0; i < n+1; ++i ) {
00776       double *step_i_times = &const_cast<step_times_t&>(step_times_)[i*mmm];
00777       // compute total step times (and total algorithm time)
00778       const double
00779         step_time = std::accumulate( step_i_times, step_i_times + m, (double)0.0 );
00780       if(i < n)
00781         _total_time += step_time;
00782       step_i_times[ mm + TIME_STAT_TOTALS_OFFSET ] = step_time;
00783       // compute average per step.
00784       step_i_times[ mm + TIME_STAT_AV_OFFSET ] = step_time / m;
00785       // compute min per step
00786       step_i_times[ mm + TIME_STAT_MIN_OFFSET ]= *std::min_element( step_i_times, step_i_times + m );
00787       // compute max per step
00788       step_i_times[ mm + TIME_STAT_MAX_OFFSET ]= *std::max_element( step_i_times, step_i_times + m );
00789     }}
00790     
00791     {for( int i = 0; i < n+1; ++i ) {
00792       double *step_i_times = &const_cast<step_times_t&>(step_times_)[i*mmm];
00793       // compute fractions for each step.
00794       step_i_times[ mm + TIME_STAT_PERCENT_OFFSET ]
00795         = step_i_times[ mm + TIME_STAT_TOTALS_OFFSET ] / total_time_;
00796     }}
00797   }
00798 }
00799 
00800 // private
00801 
00802 void Algorithm::change_running_state(ERunningState _running_state)
00803 {
00804   if( running_state() != RUNNING && _running_state == RUNNING ) {
00805     if( static_num_running_algorithms == 0 ) {
00806       // Register the signal handler for the SIGINT
00807       signal( SIGINT, &sig_handler_interrupt_algorithm );
00808       static_interrupt_called = false;
00809       static_processed_user_interrupt = false;
00810     }
00811     ++static_num_running_algorithms;
00812   }
00813   else if( running_state() != NOT_RUNNING && _running_state == NOT_RUNNING ) {
00814     --static_num_running_algorithms;
00815     if( static_num_running_algorithms == 0 ) {
00816       // Put back the default signal handler
00817       signal( SIGINT, SIG_DFL );
00818       static_interrupt_called = false;
00819       static_processed_user_interrupt = false;
00820     }
00821   }
00822   running_state_ = _running_state;
00823 }
00824 
00825 void Algorithm::validate_in_state(ERunningState _running_state) const {
00826   const char running_state_name[3][25] = { "NOT_RUNNING" , "RUNNING", "RUNNING_BEING_CONFIGURED" };
00827   if(running_state() != _running_state)
00828     TEST_FOR_EXCEPTION(
00829       true, InvalidRunningState
00830       ,"Algorithm::validate_in_state(...) : The condition running_state() == "
00831       << running_state_name[running_state()] << " has been violated with "
00832       << " running_state = " << running_state_name[_running_state] );
00833 }
00834 
00835 void Algorithm::validate_not_in_state(ERunningState _running_state) const {
00836   const char running_state_name[3][25] = { "NOT_RUNNING" , "RUNNING", "RUNNING_BEING_CONFIGURED" };
00837   if(running_state() == _running_state)
00838     TEST_FOR_EXCEPTION(
00839       true, InvalidRunningState
00840       ,"Algorithm::validate_not_in_state(...) : The condition running_state() != "
00841       << running_state_name[running_state()] << " has been violated" );
00842 }
00843 
00844 void Algorithm::validate_not_curr_step(poss_type step_poss) const {
00845   if(step_poss == curr_step_poss_)
00846     TEST_FOR_EXCEPTION(
00847       true, InvalidConfigChange
00848       ,"Algorithm::validate_not_curr_step(step_poss="<<step_poss<<") : "
00849       "Error, You can not modify the step being currently executed" );
00850 }
00851 
00852 void Algorithm::validate_not_next_step(const std::string& step_name) const {
00853   if( step_name == saved_next_step_name_ )
00854     TEST_FOR_EXCEPTION(
00855       true, InvalidConfigChange,
00856       "Algorithm::validate_not_next_step(step_name): "
00857       "Error, You can not modify name or remove the step given by "
00858       "step_name = what_is_next_name() = " << step_name );
00859 }
00860 
00861 Algorithm::steps_t::iterator Algorithm::step_itr_and_assert(const std::string& step_name)
00862 {
00863   steps_t::iterator itr = step_itr(step_name);
00864   if(itr == steps_.end())
00865     TEST_FOR_EXCEPTION(
00866       true, DoesNotExist
00867       ,"Algorithm::step_itr(...) : A step with the name "
00868       << step_name << " does not exist." );
00869   return itr; 
00870 }
00871 
00872 Algorithm::steps_t::const_iterator Algorithm::step_itr_and_assert(const std::string& step_name) const
00873 {
00874   steps_t::const_iterator itr = step_itr(step_name);
00875   if(itr == steps_.end())
00876     TEST_FOR_EXCEPTION(
00877       true, DoesNotExist
00878       ,"Algorithm::step_itr(...) : A step with the name "
00879       << step_name << " does not exist." );
00880   return itr; 
00881 }
00882 
00883 bool Algorithm::imp_do_step(poss_type step_poss) {
00884   curr_step_poss_ = step_poss;
00885   // do the pre steps in order
00886   if( !imp_do_assoc_steps(PRE_STEP) ) return false;
00887   // do the main step
00888   if( !steps_[curr_step_poss_-1].step_ptr->do_step(*this, curr_step_poss_, DO_MAIN_STEP, 0) ) return false;
00889   // do the post steps in order
00890   if( !imp_do_assoc_steps(POST_STEP) ) return false;
00891   // if you get here all the pre steps, step, and post steps returned true.
00892   if( static_interrupt_status == NOT_INTERRUPTED )
00893     look_for_interrupt();
00894   if( static_interrupt_status == STOP_END_STEP ) {
00895     terminate( static_interrupt_terminate_return );
00896     return false;
00897   }
00898   return true;
00899 }
00900 
00901 bool Algorithm::imp_do_assoc_steps(EAssocStepType type) {
00902   assoc_steps_ele_list_t        *assoc_list = &assoc_steps_[curr_step_poss_ - 1][type];
00903   assoc_steps_ele_list_t::iterator  itr     = assoc_list->begin();
00904   int                 n     = assoc_list->size();
00905   for(int i = 1; i <= n; ++itr, ++i) {
00906     if(reconfigured_) {
00907       // The associated step just has reconfigured *this
00908       // so we must update our pointers and iterators.
00909       // Since it is not allowed for this step or its associated steps
00910       // to have been changed, the next associated step to
00911       // execute will not change.
00912       assoc_list  = &assoc_steps_[curr_step_poss_ - 1][type];
00913       itr     = assoc_list->begin();
00914       std::advance( itr, i - 1 );
00915       reconfigured_ = false;  // This works as long as no one else needs to know
00916                   // if *this has been reconfigured.
00917     }
00918     if( !(*(*itr).step_ptr).do_step(*this, curr_step_poss_, do_step_type(type), i) ) return false;
00919   }
00920   return true;  // All the associated steps returned true.
00921 }
00922 
00923 void Algorithm::imp_inform_steps(inform_func_ptr_t inform_func_ptr)
00924 {
00925   steps_t::const_iterator         s_itr = steps_.begin();
00926   assoc_steps_t::const_iterator   a_itr = assoc_steps_.begin();
00927   poss_type step_i = 1;
00928   for(; step_i <= static_cast<poss_type>(num_steps()); ++step_i, ++s_itr, ++a_itr) {
00929     // pre_steps (e.q. 2.-3, 2.-2, 2.-1)
00930     const assoc_steps_ele_list_t &pre_steps = (*a_itr)[PRE_STEP];
00931     assoc_steps_ele_list_t::const_iterator pre_step_itr = pre_steps.begin();
00932     for(int pre_step_i = - pre_steps.size(); pre_step_i < 0; ++pre_step_i, ++pre_step_itr) {
00933       ((&*(*pre_step_itr).step_ptr)->*inform_func_ptr)(
00934         *this, step_i, DO_PRE_STEP, pre_steps.size()+pre_step_i+1
00935         );
00936     }
00937     // The main step.
00938     ((&*(*s_itr).step_ptr)->*inform_func_ptr)( *this, step_i, DO_MAIN_STEP, 0 );
00939     // post_steps (e.q. 2.1, 2.2, 2.3)
00940     const assoc_steps_ele_list_t &post_steps = (*a_itr)[POST_STEP];
00941     assoc_steps_ele_list_t::const_iterator post_step_itr = post_steps.begin();
00942     for(int post_step_i = 1; post_step_i <= static_cast<int>(post_steps.size()); ++post_step_i, ++post_step_itr) {
00943       ((&*(*post_step_itr).step_ptr)->*inform_func_ptr)(
00944         *this, step_i, DO_POST_STEP, post_step_i
00945         );
00946     }
00947   }
00948 }
00949 
00950 void Algorithm::imp_print_algorithm(std::ostream& out, bool print_steps) const
00951 {
00952   using Teuchos::typeName;
00953   const std::string leading_str = "    ";
00954   
00955   steps_t::const_iterator          s_itr = steps_.begin();
00956   assoc_steps_t::const_iterator    a_itr = assoc_steps_.begin();
00957   poss_type step_i = 1;
00958   for(; step_i <= static_cast<poss_type>(num_steps()); ++step_i, ++s_itr, ++a_itr) {
00959     // list pre_steps (e.q. 2.-3, 2.-2, 2.-1)
00960     const assoc_steps_ele_list_t &pre_steps = (*a_itr)[PRE_STEP];
00961     assoc_steps_ele_list_t::const_iterator pre_step_itr = pre_steps.begin();
00962     for(int pre_step_i = - pre_steps.size(); pre_step_i < 0; ++pre_step_i, ++pre_step_itr) {
00963       out   << step_i << "." << pre_step_i << ". \""
00964           << (*pre_step_itr).name << "\"\n"
00965           << leading_str << "(" << typeName(*(*pre_step_itr).step_ptr) << ")\n";
00966       if(print_steps) {
00967         (*(*pre_step_itr).step_ptr).print_step( *this, step_i, DO_PRE_STEP
00968           , pre_steps.size()+pre_step_i+1, out, leading_str );
00969         out << std::endl;
00970       }
00971     }
00972     // The main step.
00973     out   << step_i << ". \"" << (*s_itr).name
00974         << "\"\n"
00975         << leading_str << "(" << typeName(*(*s_itr).step_ptr) << ")\n";
00976     if(print_steps) {
00977       (*(*s_itr).step_ptr).print_step( *this, step_i, DO_MAIN_STEP, 0, out, leading_str );
00978       out << std::endl;
00979     }
00980     // list post_steps (e.q. 2.1, 2.2, 2.3)
00981     const assoc_steps_ele_list_t &post_steps = (*a_itr)[POST_STEP];
00982     assoc_steps_ele_list_t::const_iterator post_step_itr = post_steps.begin();
00983     for(int post_step_i = 1; post_step_i <= static_cast<poss_type>(post_steps.size()); ++post_step_i, ++post_step_itr) {
00984       out   << step_i << "." << post_step_i << ". \""
00985           << (*post_step_itr).name << "\"\n"
00986           << leading_str << "(" << typeName(*(*post_step_itr).step_ptr) << ")\n";
00987       if(print_steps) {
00988         (*(*post_step_itr).step_ptr).print_step( *this, step_i, DO_POST_STEP, post_step_i
00989           , out, leading_str );
00990         out << std::endl;
00991       }
00992     }
00993   }
00994   if(print_steps) {
00995     out
00996       << step_i << ". \"Major Loop\" :\n"
00997       << "    if k >= max_iter then\n"
00998       << "        terminate the algorithm\n"
00999       << "    elseif run_time() >= max_run_time then\n"
01000       << "        terminate the algorithm\n"
01001       << "    else\n"
01002       << "        k = k + 1\n"
01003       << "        goto 1\n"
01004       << "    end\n";
01005   }
01006 }
01007 
01008 // validate poss
01009 
01010 Algorithm::poss_type Algorithm::validate(poss_type step_poss, int past_end) const
01011 {
01012     
01013   TEST_FOR_EXCEPTION(
01014     step_poss < 1 || steps_.size() + past_end < step_poss, DoesNotExist
01015     ,"Algorithm::validate(step_poss) : The step_poss = " << step_poss
01016     << " is not in range of 1 to " << steps_.size() + past_end );
01017   return step_poss;
01018 } 
01019 
01020 Algorithm::poss_type Algorithm::validate(const assoc_steps_ele_list_t& assoc_list
01021   , poss_type assoc_step_poss, int past_end) const
01022 {
01023   TEST_FOR_EXCEPTION(
01024     assoc_step_poss < 1 || assoc_list.size() + past_end < assoc_step_poss, DoesNotExist
01025     ,"Algorithm::validate(assoc_list,assoc_step_poss) : The assoc_step_poss = "
01026     << assoc_step_poss << " is not in range of 1 to " << assoc_list.size() + past_end );
01027   return assoc_step_poss;
01028 }
01029 
01030 void Algorithm::look_for_interrupt()
01031 {
01032   //
01033   // Get the mode of aborting from the user!
01034   //
01035   if( static_interrupt_called && !static_processed_user_interrupt && static_proc_rank == 0 ) {
01036     // Allow for another interrupt possibly
01037     static_interrupt_called = false;
01038     //
01039     // Get the response from the user
01040     //
01041     enum EResponse { R_ABORT_NOW, R_CONTINUE, R_STOP_END_STEP, R_STOP_END_ITER };
01042     EResponse response = R_ABORT_NOW;
01043     const int max_tries = 3;
01044     bool valid_response = false;
01045     for( int tries = 0; !valid_response && tries < max_tries; ++tries ) {
01046       std::cerr
01047         << "\nIterationPack::Algorithm: Received signal SIGINT."
01048         << "\nJust completed current step curr_step_name = \""
01049         << get_step_name(curr_step_poss_) << "\",  curr_step_poss = "
01050         << curr_step_poss_ << " of steps [1..." << num_steps() << "]."
01051         << "\nDo you want to:\n"
01052         << "  (a) Abort the program immediately?\n"
01053         << "  (c) Continue with the algorithm?\n"
01054         << "  (s) Gracefully terminate the algorithm at the end of this step?\n"
01055         << "  (i) Gracefully terminate the algorithm at the end of this iteration?\n"
01056         << "Answer a, c, s or i ? ";
01057       char abort_mode;
01058       std::cin >> abort_mode;
01059       if( abort_mode == 'a' ) {
01060         response = R_ABORT_NOW;
01061         valid_response = true;
01062       }
01063       else if( abort_mode == 'c' ) {
01064         response = R_CONTINUE;
01065         valid_response = true;
01066       }
01067       else if( abort_mode == 's' || abort_mode == 'i' ) {
01068         if( abort_mode == 's')
01069           response = R_STOP_END_STEP;
01070         else
01071           response = R_STOP_END_ITER;
01072         std::cerr
01073           << "\nTerminate the algorithm with true (t) or false (f) ? ";
01074         std::cin >> abort_mode;
01075         if( abort_mode == 't' ) {
01076           static_interrupt_terminate_return = true;
01077           valid_response = true;
01078         }
01079         else if( abort_mode == 'f' ) {
01080           static_interrupt_terminate_return = false;
01081           valid_response = true;
01082         }
01083         else {
01084           std::cerr << "Invalid response! Expecting \'t\' or \'f\'\n";
01085         }
01086       }
01087       else {
01088         std::cerr << "\nInvalid response! Expecting \'a\', \'c\', \'s\' or \'i\'\n";
01089       }
01090       std::cerr << std::endl;
01091     }
01092     if(!valid_response) {
01093       std::cerr << "Three strikes, you are out!\n";
01094     }
01095     //
01096     // Interpret the response
01097     //
01098     switch(response) {
01099       case R_ABORT_NOW: {
01100         static_interrupt_status = ABORT_PROGRAM;
01101         break;
01102       }
01103       case R_CONTINUE: {
01104         static_interrupt_status = NOT_INTERRUPTED;
01105         break;
01106       }
01107       case R_STOP_END_STEP: {
01108         static_interrupt_status = STOP_END_STEP;
01109         break;
01110       }
01111       case R_STOP_END_ITER: {
01112         static_interrupt_status = STOP_END_ITER;
01113         break;
01114       }
01115       default: {
01116         TEST_FOR_EXCEPT(true);
01117       }
01118     }
01119     static_processed_user_interrupt = true;
01120   }
01121   else if( interrupt_file_name().length() && !static_processed_user_interrupt && static_proc_rank == 0 ) {
01122     //
01123     // If there was not an interactive interrupt then look for an
01124     // interrupt file if we have not already done this
01125     // (static_processed_user_interrupt).
01126     //
01127     std::ifstream interrupt_file(interrupt_file_name().c_str());
01128     if(interrupt_file) {
01129       std::cerr
01130         << "\nIterationPack::Algorithm: Found the interrupt file \""<<interrupt_file_name()<<"\"!"
01131         << "\nJust completed current step curr_step_name = \""
01132         << get_step_name(curr_step_poss_) << "\",  curr_step_poss = "
01133         << curr_step_poss_ << " of steps [1..." << num_steps() << "].\n";
01134       char abort_mode = 0;
01135       interrupt_file >> abort_mode;
01136       std::cerr << "Read a value of abort_mode = \'"<<abort_mode<<"\': ";
01137       if( abort_mode == 'a' ) {
01138         std::cerr << "Will abort the program immediatly!\n";
01139         static_interrupt_status = ABORT_PROGRAM;
01140       }
01141       else if( abort_mode == 's' || abort_mode == 'i' ) {
01142         if( abort_mode == 's') {
01143           std::cerr << "Will abort the program gracefully at the end of this step!\n";
01144           static_interrupt_status = STOP_END_STEP;
01145         }
01146         else {
01147           std::cerr << "Will abort the program gracefully at the end of this iteration!\n";
01148           static_interrupt_status = STOP_END_ITER;
01149         }
01150         TEST_FOR_EXCEPTION(
01151           interrupt_file.eof(), std::logic_error,
01152           "IterationPack::Algorithm: Error, expected input for terminate_bool option from the "
01153           "file \""<<interrupt_file_name()<<"\"!"
01154           );
01155         char terminate_bool = 0;
01156         interrupt_file >> terminate_bool;
01157         std::cerr << "Read a value of terminate_bool = \'"<<terminate_bool<<"\': ";
01158         if( terminate_bool == 't' ) {
01159           std::cerr << "Will return a success flag!\n";
01160           static_interrupt_terminate_return = true;
01161         }
01162         else if( terminate_bool == 'f' ) {
01163           std::cerr << "Will return a failure flag!\n";
01164           static_interrupt_terminate_return = false;
01165         }
01166         else {
01167           TEST_FOR_EXCEPTION(
01168             true, std::logic_error
01169             ,"Error, the value of terminate_bool = \'"<<terminate_bool<<"\' is not "
01170             "valid!  Valid values include only \'t\' or \'f\'\n"
01171             );
01172         }
01173       }
01174       else {
01175         TEST_FOR_EXCEPTION(
01176           true, std::logic_error
01177           ,"Error, the value of abort_mode = \'"<<abort_mode<<"\' is not "
01178           "valid!  Valid values include only \'a\', \'s\' or \'i\'\n"
01179           );
01180       }
01181       std::cerr << std::endl;
01182       static_processed_user_interrupt = true;
01183     }
01184   }
01185   //
01186   // Make sure that all of the processes get the same
01187   // response
01188   //
01189 #ifdef HAVE_MPI
01190   const bool query_for_interrupt = true; // ToDo: Make this an external option!
01191   if( static_num_proc > 1 && query_for_interrupt ) {
01192     //
01193     // Here we will do a global reduction to see of a processor has
01194     // recieved an interrupt.  Here we will do a sum operation since only the
01195     // root process should be getting these options.
01196     //
01197     int sendbuf[2] = { 0, 0 };
01198     int recvbuf[2] = { 0, 0 };
01199     if(static_proc_rank == 0) {
01200       sendbuf[0] = (int)static_interrupt_status;
01201       sendbuf[1] = static_interrupt_terminate_return ? 1 : 0;
01202     }
01203     // Note: this global reduction will synchronize all of the processors!
01204 #ifdef ITERATION_PACK_ALGORITHM_SHOW_MPI_DEBUG_INFO
01205     std::cerr << "\np="<<static_proc_rank<<": IterationPack::Algorithm::interrupt(): Calling MPI_Allreduce(...) ...\n";
01206 #endif
01207     MPI_Allreduce(
01208       sendbuf                  // sendbuf
01209       ,recvbuf                 // recvbuf
01210       ,2                       // count
01211       ,MPI_INT                 // datatype
01212       ,MPI_SUM                 // op
01213       ,MPI_COMM_WORLD          // comm (ToDo: Make more general?)
01214       );
01215 #ifdef ITERATION_PACK_ALGORITHM_SHOW_MPI_DEBUG_INFO
01216     std::cerr
01217       << "\np="<<static_proc_rank<<": IterationPack::Algorithm::interrupt(): After MPI_Allreduce(...)"
01218       << "\np="<<static_proc_rank<<": recvbuf[0] = " << recvbuf[0] << ", recvbuf[1] = " << recvbuf[1] << std::endl;
01219 #endif
01220     // Set static_interrupt_status
01221     switch( (EInterruptStatus)recvbuf[0] ) {
01222       case NOT_INTERRUPTED:
01223         static_interrupt_status = NOT_INTERRUPTED;
01224         break;
01225       case STOP_END_STEP:
01226         static_interrupt_status = STOP_END_STEP;
01227         break;
01228       case STOP_END_ITER:
01229         static_interrupt_status = STOP_END_ITER;
01230         break;
01231       case ABORT_PROGRAM:
01232         static_interrupt_status = ABORT_PROGRAM;
01233         break;
01234       default:
01235         std::cerr
01236           << "p=" << static_proc_rank << ": Algorithm::look_for_interrupt(): Error, the globally reduced value of "
01237           "recvbuf[0] = " << recvbuf[0] << " is not valid!";
01238         std::abort();
01239     }
01240     // Set static_interrupt_terminate_return
01241     static_interrupt_terminate_return = ( recvbuf[1] == 0 ? false : true );
01242   }
01243   //
01244   // Abort the program now if the user did not already press Ctrl-C again!
01245   //
01246   if( static_interrupt_status == ABORT_PROGRAM ) {
01247     if( static_proc_rank == 0 ) {
01248       std::cerr << "\nAborting the program now!\n";
01249     }
01250     std::abort();
01251   }
01252 #endif
01253 }
01254 
01255 // static
01256 
01257 void Algorithm::interrupt()
01258 {
01259   //
01260   // This function assumes that every process will recieve the same
01261   // signal which I found to be the case with MPICH.  I am not clear
01262   // what the MPI standard says about interrupts so I can not
01263   // guarantee that this is 100% portable.  If other behavior is
01264   // needed, this will have to be compiled in differently.
01265   //
01266   // Note: I have found that on MPICH that you can not guarantee that
01267   // only a single signal will be sent to a slave process so this
01268   // function will ignore interupts for slave processes.
01269   //
01270   // Note that you have to be very careful what you do inside of a
01271   // signal handler and in general you should only be setting flags or
01272   // aborting.
01273   //
01274   static_processed_user_interrupt = false;
01275 #ifdef ITERATION_PACK_ALGORITHM_SHOW_MPI_DEBUG_INFO
01276   std::cerr << "\np="<<static_proc_rank<<": IterationPack::Algorithm::interrupt() called!\n";
01277 #endif
01278   //
01279   // See if an algorithm is possibly even running yet!
01280   //
01281   if( static_num_proc == 0 ) {
01282     if( static_proc_rank == 0 )
01283       std::cerr
01284         << "\nIterationPack::Algorithm::interrupt(): Received signal SIGINT but an Algorithm "
01285         << "object has not been allocated yet and no algorithm is running.\n"
01286         << "\nAborting the program now!\n";
01287     std::abort();
01288     return;  // Should not be called!
01289   }
01290   //
01291   // See if we are going to query for an interrupt when running in MPI mode
01292   //
01293   const bool query_for_interrupt = true; // ToDo: Make this an external option!
01294   if( !query_for_interrupt && static_num_proc > 1 ) {
01295     if( static_proc_rank == 0 ) {
01296       std::cerr
01297         << "\nIterationPack::Algorithm::interrupt(): Received signal SIGINT but num_proc = "
01298         << static_num_proc << " > 1 and query_for_interrupt = false so:\n"
01299         << "\nAborting the program now!\n";
01300     }
01301     std::abort();
01302     return;  // Should not be called!
01303   }
01304   //
01305   // Remember that this interrupt has been called!
01306   //
01307   if( static_proc_rank == 0 ) {
01308     std::cerr
01309       << "\nIterationPack::Algorithm::interrupt(): Received signal SIGINT.  "
01310       << "Wait for the end of the current step and respond to an interactive query,  "
01311       << "kill the process by sending another signal (i.e. SIGKILL).\n";
01312   }
01313   static_interrupt_called = true;
01314 }
01315 
01316 } // end namespace IterationPack

Generated on Wed May 12 21:50:28 2010 for IterationPack: General framework for building iterative algorithms by  doxygen 1.4.7