openModeller  Version 1.4.0
Algorithm.cpp
Go to the documentation of this file.
00001 
00028 #include <openmodeller/CallbackWrapper.hh>
00029 #include <openmodeller/Algorithm.hh>
00030 #include <openmodeller/AlgParameter.hh>
00031 #include <openmodeller/AlgorithmFactory.hh>
00032 #include <openmodeller/Log.hh>
00033 #include <openmodeller/Configuration.hh>
00034 #include <openmodeller/Environment.hh>
00035 #include <openmodeller/Exceptions.hh>
00036 
00037 #include <openmodeller/models/AlgoAdapterModel.hh>
00038 
00039 // AlgorithmImpl works as a Normalizer factory during deserialization, so 
00040 // all possible Normalizer implementation headers must be included here
00041 #include <openmodeller/ScaleNormalizer.hh>
00042 #include <openmodeller/MeanVarianceNormalizer.hh>
00043 
00044 //needed for atoi function
00045 #include <stdlib.h>
00046 
00047 using std::string;
00048 
00049 #undef DEBUG_MEMORY
00050 
00051 /*******************/
00052 /*** constructor ***/
00053 
00054 AlgorithmImpl::AlgorithmImpl( AlgMetadata const *metadata ) :
00055   ReferenceCountedObject(),
00056   _samp(),
00057   _normalizerPtr(0),
00058   _param(),
00059   _metadata( metadata )
00060 {
00061 #if defined(DEBUG_MEMORY)
00062   Log::instance()->debug( "AlgorithmImpl::AlgorithmImpl() at %x\n", this );
00063 #endif
00064 }
00065 
00066 
00067 /******************/
00068 /*** destructor ***/
00069 
00070 AlgorithmImpl::~AlgorithmImpl()
00071 {
00072 #if defined(DEBUG_MEMORY)
00073   Log::instance()->debug("AlgorithmImpl::~AlgorithmImpl() at %x\n",this);
00074 #endif
00075 
00076   if ( _normalizerPtr ) {
00077 
00078     delete _normalizerPtr;
00079   }
00080 }
00081 
00082 /*********************/
00083 /*** configuration ***/
00084 
00085 ConfigurationPtr
00086 AlgorithmImpl::getConfiguration() const
00087 {
00088   ConfigurationPtr config( new ConfigurationImpl("Algorithm") );
00089 
00090   config->addNameValue( "Id", _metadata->id );
00091   config->addNameValue( "Version", _metadata->version );
00092 
00093   ConfigurationPtr param_config( new ConfigurationImpl("Parameters") );
00094   ParamSetType::const_iterator p = _param.begin();
00095   for( ; p != _param.end() ; ++p ) {
00096 
00097     ConfigurationPtr cfg( new ConfigurationImpl("Parameter") );
00098     param_config->addSubsection( cfg );
00099     cfg->addNameValue( "Id", p->first );
00100     cfg->addNameValue( "Value", p->second );
00101   }
00102 
00103   config->addSubsection( param_config );
00104 
00105   if ( _normalizerPtr ) {
00106 
00107     config->addSubsection( _normalizerPtr->getConfiguration() );
00108   }
00109 
00110   // Wrapper model element
00111   ConfigurationPtr model_config( new ConfigurationImpl("Model") );
00112 
00113   _getConfiguration( model_config );
00114 
00115   config->addSubsection( model_config );
00116 
00117   return config;
00118 }
00119 
00120 void
00121 AlgorithmImpl::setConfiguration( const ConstConfigurationPtr &config )
00122 {
00123   // Important: this code runs in the following situations:
00124   // 1- Loading a fully serialized algorithm, i.e. an algorithm that was just
00125   //    run and has all its properties filled with content (parameters & model).
00126   // 2- Loading a createModel request which contains only the algorithm id
00127   //    and its parameters.
00128   // 3- Loading only the serialized model of an algorithm.
00129 
00130   try { 
00131 
00132     ConstConfigurationPtr param_config = config->getSubsection( "Parameters" );
00133   
00134     Configuration::subsection_list params = param_config->getAllSubsections();
00135 
00136     _param.clear();
00137 
00138     Configuration::subsection_list::const_iterator nv;
00139 
00140     for ( nv = params.begin(); nv != params.end(); ) {
00141 
00142       string id = (*nv)->getAttribute( "Id" );
00143       string value = (*nv)->getAttribute( "Value" );
00144       _param.insert( ParamSetValueType( id, value ) );
00145       ++nv;
00146     }
00147   }
00148   catch( SubsectionNotFound& e ) {
00149     UNUSED(e);
00150     // In this case the XML has probably just the model definition that will be 
00151     // loaded below.
00152   }
00153 
00154   ConstConfigurationPtr norm_config;
00155 
00156   bool found_normalization_section = false;
00157 
00158   try { 
00159 
00160     norm_config = config->getSubsection( "Normalization" );
00161 
00162     found_normalization_section = true;
00163   }
00164   catch( SubsectionNotFound& e ) {
00165     UNUSED(e);
00166     // No need to set _normalizerPtr to null, because alg already initializes
00167     // a default normalizer. Setting it to null will in fact make algorithms
00168     // crash if you run them with om_create (deserializing from an XML request).
00169   }
00170 
00171   if ( found_normalization_section ) {
00172 
00173     try { 
00174 
00175       std::string norm_class = norm_config->getAttribute( "Class" );
00176 
00177       if ( norm_class == "ScaleNormalizer" ) {
00178 
00179         _normalizerPtr = new ScaleNormalizer();
00180       }
00181       else if ( norm_class == "MeanVarianceNormalizer" ) {
00182 
00183         _normalizerPtr = new MeanVarianceNormalizer();
00184       }
00185       else {
00186 
00187         string msg( "Unknown normalizer class: " );
00188         msg.append( norm_class );
00189 
00190         Log::instance()->error( msg.c_str() );
00191 
00192         throw AlgorithmException( msg.c_str() );
00193       }
00194     }
00195     catch( AttributeNotFound& e ) {
00196 
00197       UNUSED (e);
00198 
00199       // Backwards compatibility
00200       _normalizerPtr = new ScaleNormalizer();
00201     }
00202 
00203     _normalizerPtr->setConfiguration( norm_config );
00204   }
00205 
00206   // Get wrapper model element
00207   try { 
00208 
00209     ConstConfigurationPtr model_config = config->getSubsection( "Model" );
00210 
00211     _setConfiguration( model_config );
00212   }
00213   catch( SubsectionNotFound& e ) {
00214     UNUSED (e);
00215   }
00216 }
00217 
00218 /*******************/
00219 /*** set Sampler ***/
00220 void
00221 AlgorithmImpl::setSampler( const SamplerPtr& samp )
00222 {
00223   _samp = samp;
00224 }
00225 
00226 /**********************/
00227 /*** set Parameters ***/
00228 void
00229 AlgorithmImpl::setParameters( int nparam, AlgParameter const *param )
00230 {
00231   _param.clear();
00232 
00233   // Copy 'param' to '_alg_param'.
00234   AlgParameter const *end = param + nparam;
00235 
00236   while ( param < end ) {
00237 
00238     _param.insert( ParamSetValueType( param->id(), param->value() ) );
00239 
00240     ++param;
00241   }
00242 }
00243 
00244 void
00245 AlgorithmImpl::setParameters( const ParamSetType &params )
00246 {
00247   _param.clear();
00248   _param = params;
00249 }
00250 
00251 /**********************/
00252 /*** get fresh copy ***/
00253 AlgorithmPtr 
00254 AlgorithmImpl::getFreshCopy()
00255 {
00256   if ( ! _metadata ) {
00257 
00258     std::string msg = "Cannot produce copies of an algorithm without metadata.\n";
00259 
00260     Log::instance()->error( msg.c_str() );
00261 
00262     throw AlgorithmException( msg.c_str() );
00263   }
00264 
00265   AlgorithmPtr copy = AlgorithmFactory::newAlgorithm( _metadata->id );
00266 
00267   copy->setParameters( _param );
00268 
00269   return copy;
00270 }
00271 
00272 /*********************/
00273 /*** get Parameter ***/
00274 int
00275 AlgorithmImpl::getParameter( string const &id, string *value )
00276 {
00277   ParamSetType::const_iterator pos = _param.find( id );
00278 
00279   if ( pos == _param.end() ) {
00280 
00281     return 0;
00282   }
00283    
00284   *value = pos->second;
00285 
00286   return 1;
00287 }
00288 
00289 
00290 /*********************/
00291 /*** get Parameter ***/
00292 int
00293 AlgorithmImpl::getParameter( string const &id, int *value )
00294 {
00295   string str_value;
00296 
00297   if ( ! getParameter( id, &str_value ) )
00298     return 0;
00299 
00300   *value = atoi( str_value.c_str() );
00301   return 1;
00302 }
00303 
00304 
00305 /*********************/
00306 /*** get Parameter ***/
00307 int
00308 AlgorithmImpl::getParameter( string const &id, double *value )
00309 {
00310   string str_value;
00311 
00312   if ( ! getParameter( id, &str_value ) )
00313     return 0;
00314 
00315   *value = atof( str_value.c_str() );
00316   return 1;
00317 }
00318 
00319 
00320 /*********************/
00321 /*** get Parameter ***/
00322 int
00323 AlgorithmImpl::getParameter( string const &id, float *value )
00324 {
00325   string str_value;
00326 
00327   if ( ! getParameter( id, &str_value ) )
00328     return 0;
00329 
00330   *value = float( atof( str_value.c_str() ) );
00331   return 1;
00332 }
00333 
00334 
00335 /**********************/
00336 /*** get Normalizer ***/
00337 Normalizer * 
00338 AlgorithmImpl::getNormalizer() const
00339 {
00340   if ( _normalizerPtr ) {
00341 
00342     return _normalizerPtr->getCopy();
00343   }
00344 
00345   return 0;
00346 }
00347 
00348 
00349 void
00350 AlgorithmImpl::setNormalization( const SamplerPtr& samp) const
00351 {
00352     samp->normalize( _normalizerPtr );
00353 }
00354 
00355 void
00356 AlgorithmImpl::setNormalization( const EnvironmentPtr& env) const
00357 {
00358     env->normalize( _normalizerPtr );
00359 }
00360 
00361 Model
00362 AlgorithmImpl::createModel( const SamplerPtr& samp, CallbackWrapper *callbackWrapper ) {
00363 
00364   if ( !samp ) {
00365 
00366     std::string msg = "Sampler not specified.\n";
00367 
00368     Log::instance()->error( msg.c_str() );
00369 
00370     throw AlgorithmException( msg.c_str() );
00371   }
00372 
00373   if ( !samp->numPresence() && !samp->numAbsence() ) {
00374 
00375     std::string msg = "Cannot create model without any presence or absence point.\n";
00376 
00377     Log::instance()->error( msg.c_str() );
00378 
00379     throw AlgorithmException( msg.c_str() );
00380   }
00381 
00382   setSampler( samp );
00383 
00384   if ( needNormalization() ) {
00385 
00386     if ( !_samp->isNormalized() ) {
00387 
00388       Log::instance()->info( "Computing normalization\n" );
00389 
00390       if ( _normalizerPtr ) {
00391 
00392         _normalizerPtr->computeNormalization( _samp );
00393 
00394         setNormalization( _samp );
00395       }
00396       else {
00397 
00398         std::string msg = "Normalizer not specified.\n";
00399 
00400         Log::instance()->error( msg.c_str() );
00401 
00402         throw AlgorithmException( msg.c_str() );
00403       }
00404     }
00405   }
00406   else {
00407 
00408     if ( _samp->isNormalized() ) {
00409 
00410       _samp->resetNormalization();
00411     }    
00412   }
00413 
00414   if ( ! initialize() ) {
00415 
00416     std::string msg = "Algorithm could not be initialized.\n";
00417 
00418     Log::instance()->error( msg.c_str() );
00419 
00420     throw AlgorithmException( msg.c_str() );
00421   }
00422 
00423   // Generate model.
00424   int ncycle = 0;
00425   int resultFlag = 1;
00426   int doneFlag = 0;
00427   bool abort = false;
00428 
00429   while ( resultFlag && ! doneFlag ) {
00430 
00431     if ( callbackWrapper ) {
00432 
00433       try {
00434 
00435         abort = callbackWrapper->abortionRequested();
00436 
00437         if ( abort ) {
00438 
00439           Log::instance()->error( "Model creation aborted.\n" );
00440           break;
00441         }
00442       }
00443       catch ( char * message ) {
00444 
00445         string error( "Exception in abort callback: " );
00446         error += message;
00447         Log::instance()->error( error.c_str() );
00448         throw AlgorithmException( error.c_str() );
00449       }
00450       catch (...) {}
00451     }
00452 
00453     // I moved thee two calls out of the while() 
00454     // above and into separate calls because
00455     // when run in a thread we need to catch 
00456     // exceptions properly TS
00457     try {
00458 
00459       resultFlag = iterate();
00460       doneFlag   = done();
00461     }
00462     catch ( char * message ) {
00463 
00464       string error( "Exception in model iteration: " );
00465       error += message;
00466       Log::instance()->error( error.c_str() );
00467       throw AlgorithmException( error.c_str() );
00468     }
00469 
00470     ncycle++;
00471 
00472     if ( callbackWrapper ) {
00473 
00474       try {
00475 
00476         callbackWrapper->notifyModelCreationProgress( getProgress() );
00477       }
00478       catch ( char * message ) {
00479 
00480         string error( "Exception in get progress: " );
00481         error += message;
00482         Log::instance()->error( error.c_str() );
00483         throw AlgorithmException( error.c_str() );
00484       }
00485       catch (...) {}
00486     }
00487   }
00488 
00489   if ( abort ) {
00490 
00491     std::string msg = "Model creation aborted.\n";
00492 
00493     Log::instance()->error( msg.c_str() );
00494 
00495     throw AlgorithmException( msg.c_str() );
00496   }
00497 
00498   if ( ! done() ) {
00499 
00500     std::string msg = "Algorithm could not produce a model.\n";
00501 
00502     Log::instance()->error( msg.c_str() );
00503 
00504     throw AlgorithmException( msg.c_str() );
00505   }
00506 
00507   if ( ! finalize() ) {
00508 
00509     std::string msg = "Algorithm could not be finalized.\n";
00510 
00511     Log::instance()->error( msg.c_str() );
00512 
00513     throw AlgorithmException( msg.c_str() );
00514   }
00515 
00516   if ( callbackWrapper ) {
00517 
00518     try {
00519 
00520       callbackWrapper->notifyModelCreationProgress( 1.0 );
00521     }
00522     catch ( char * message ) {
00523 
00524       string error( "Exception when finalizing progress: " );
00525       error += message;
00526       Log::instance()->error( error.c_str() );
00527       throw AlgorithmException( error.c_str() );
00528     }
00529     catch (...) {}
00530   }
00531   
00532   return getModel();
00533 }
00534 
00535 Model
00536 AlgorithmImpl::getModel() const
00537 {
00538   // Need the ugly const_cast to cast away constness of this.
00539   // ConstAlgorithmPtr must be initialized with the PlainPoinerType = AlgorithmImpl *
00540   // and not with the const AlgorithmImpl*.
00541   // Once the ConstAlgorihtmPtr is created, then it behaves as if its const.
00542   return Model( new AlgoAdapterModelImpl( ConstAlgorithmPtr( const_cast<AlgorithmImpl*>(this) )));
00543 }