openModeller
Version 1.4.0
|
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 ¶ms ) 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 }