openModeller  Version 1.5.0
Algorithm.cpp
Go to the documentation of this file.
1 
32 #include <openmodeller/Log.hh>
36 
38 
39 // AlgorithmImpl works as a Normalizer factory during deserialization, so
40 // all possible Normalizer implementation headers must be included here
43 
44 //needed for atoi function
45 #include <stdlib.h>
46 
47 using std::string;
48 
49 #undef DEBUG_MEMORY
50 
51 /*******************/
52 /*** constructor ***/
53 
56  _samp(),
57  _normalizerPtr(0),
58  _param(),
59  _metadata( metadata )
60 {
61 #if defined(DEBUG_MEMORY)
62  Log::instance()->debug( "AlgorithmImpl::AlgorithmImpl() at %x\n", this );
63 #endif
64 }
65 
66 
67 /******************/
68 /*** destructor ***/
69 
71 {
72 #if defined(DEBUG_MEMORY)
73  Log::instance()->debug("AlgorithmImpl::~AlgorithmImpl() at %x\n",this);
74 #endif
75 
76  if ( _normalizerPtr ) {
77 
78  delete _normalizerPtr;
79  }
80 }
81 
82 /*********************/
83 /*** configuration ***/
84 
87 {
88  ConfigurationPtr config( new ConfigurationImpl("Algorithm") );
89 
90  config->addNameValue( "Id", _metadata->id );
91  config->addNameValue( "Version", _metadata->version );
92 
93  ConfigurationPtr param_config( new ConfigurationImpl("Parameters") );
94  ParamSetType::const_iterator p = _param.begin();
95  for( ; p != _param.end() ; ++p ) {
96 
97  ConfigurationPtr cfg( new ConfigurationImpl("Parameter") );
98  param_config->addSubsection( cfg );
99  cfg->addNameValue( "Id", p->first );
100  cfg->addNameValue( "Value", p->second );
101  }
102 
103  config->addSubsection( param_config );
104 
105  if ( _normalizerPtr ) {
106 
107  config->addSubsection( _normalizerPtr->getConfiguration() );
108  }
109 
110  // Wrapper model element
111  ConfigurationPtr model_config( new ConfigurationImpl("Model") );
112 
113  _getConfiguration( model_config );
114 
115  config->addSubsection( model_config );
116 
117  return config;
118 }
119 
120 void
122 {
123  // Important: this code runs in the following situations:
124  // 1- Loading a fully serialized algorithm, i.e. an algorithm that was just
125  // run and has all its properties filled with content (parameters & model).
126  // 2- Loading a createModel request which contains only the algorithm id
127  // and its parameters.
128  // 3- Loading only the serialized model of an algorithm.
129 
130  try {
131 
132  ConstConfigurationPtr param_config = config->getSubsection( "Parameters" );
133 
134  Configuration::subsection_list params = param_config->getAllSubsections();
135 
136  _param.clear();
137 
138  Configuration::subsection_list::const_iterator nv;
139 
140  for ( nv = params.begin(); nv != params.end(); ) {
141 
142  string id = (*nv)->getAttribute( "Id" );
143  string value = (*nv)->getAttribute( "Value" );
144  _param.insert( ParamSetValueType( id, value ) );
145  ++nv;
146  }
147  }
148  catch( SubsectionNotFound& e ) {
149  UNUSED(e);
150  // In this case the XML has probably just the model definition that will be
151  // loaded below.
152  }
153 
154  ConstConfigurationPtr norm_config;
155 
156  bool found_normalization_section = false;
157 
158  try {
159 
160  norm_config = config->getSubsection( "Normalization" );
161 
162  found_normalization_section = true;
163  }
164  catch( SubsectionNotFound& e ) {
165  UNUSED(e);
166  // No need to set _normalizerPtr to null, because alg already initializes
167  // a default normalizer. Setting it to null will in fact make algorithms
168  // crash if you run them with om_create (deserializing from an XML request).
169  }
170 
171  if ( found_normalization_section ) {
172 
173  try {
174 
175  std::string norm_class = norm_config->getAttribute( "Class" );
176 
177  if ( norm_class == "ScaleNormalizer" ) {
178 
180  }
181  else if ( norm_class == "MeanVarianceNormalizer" ) {
182 
184  }
185  else {
186 
187  string msg( "Unknown normalizer class: " );
188  msg.append( norm_class );
189 
190  Log::instance()->error( msg.c_str() );
191 
192  throw AlgorithmException( msg.c_str() );
193  }
194  }
195  catch( AttributeNotFound& e ) {
196 
197  UNUSED (e);
198 
199  // Backwards compatibility
201  }
202 
203  _normalizerPtr->setConfiguration( norm_config );
204  }
205 
206  // Get wrapper model element
207  try {
208 
209  ConstConfigurationPtr model_config = config->getSubsection( "Model" );
210 
211  _setConfiguration( model_config );
212  }
213  catch( SubsectionNotFound& e ) {
214  UNUSED (e);
215  }
216 }
217 
218 /*******************/
219 /*** set Sampler ***/
220 void
222 {
223  _samp = samp;
224 }
225 
226 /**********************/
227 /*** set Parameters ***/
228 void
229 AlgorithmImpl::setParameters( int nparam, AlgParameter const *param )
230 {
231  _param.clear();
232 
233  // Copy 'param' to '_alg_param'.
234  AlgParameter const *end = param + nparam;
235 
236  while ( param < end ) {
237 
238  _param.insert( ParamSetValueType( param->id(), param->value() ) );
239 
240  ++param;
241  }
242 }
243 
244 void
246 {
247  _param.clear();
248  _param = params;
249 }
250 
251 /**********************/
252 /*** get fresh copy ***/
255 {
256  if ( ! _metadata ) {
257 
258  std::string msg = "Cannot produce copies of an algorithm without metadata.\n";
259 
260  Log::instance()->error( msg.c_str() );
261 
262  throw AlgorithmException( msg.c_str() );
263  }
264 
266 
267  copy->setParameters( _param );
268 
269  return copy;
270 }
271 
272 /*********************/
273 /*** get Parameter ***/
274 int
275 AlgorithmImpl::getParameter( string const &id, string *value )
276 {
277  ParamSetType::const_iterator pos = _param.find( id );
278 
279  if ( pos == _param.end() ) {
280 
281  return 0;
282  }
283 
284  *value = pos->second;
285 
286  return 1;
287 }
288 
289 
290 /*********************/
291 /*** get Parameter ***/
292 int
293 AlgorithmImpl::getParameter( string const &id, int *value )
294 {
295  string str_value;
296 
297  if ( ! getParameter( id, &str_value ) )
298  return 0;
299 
300  *value = atoi( str_value.c_str() );
301  return 1;
302 }
303 
304 
305 /*********************/
306 /*** get Parameter ***/
307 int
308 AlgorithmImpl::getParameter( string const &id, double *value )
309 {
310  string str_value;
311 
312  if ( ! getParameter( id, &str_value ) )
313  return 0;
314 
315  *value = atof( str_value.c_str() );
316  return 1;
317 }
318 
319 
320 /*********************/
321 /*** get Parameter ***/
322 int
323 AlgorithmImpl::getParameter( string const &id, float *value )
324 {
325  string str_value;
326 
327  if ( ! getParameter( id, &str_value ) )
328  return 0;
329 
330  *value = float( atof( str_value.c_str() ) );
331  return 1;
332 }
333 
334 
335 /**********************/
336 /*** get Normalizer ***/
337 Normalizer *
339 {
340  if ( _normalizerPtr ) {
341 
342  return _normalizerPtr->getCopy();
343  }
344 
345  return 0;
346 }
347 
348 
349 void
351 {
352  samp->normalize( _normalizerPtr );
353 }
354 
355 void
357 {
358  env->normalize( _normalizerPtr );
359 }
360 
361 Model
362 AlgorithmImpl::createModel( const SamplerPtr& samp, CallbackWrapper *callbackWrapper ) {
363 
364  if ( !samp ) {
365 
366  std::string msg = "Sampler not specified.\n";
367 
368  Log::instance()->error( msg.c_str() );
369 
370  throw AlgorithmException( msg.c_str() );
371  }
372 
373  if ( !samp->numPresence() && !samp->numAbsence() ) {
374 
375  std::string msg = "Cannot create model without any presence or absence point.\n";
376 
377  Log::instance()->error( msg.c_str() );
378 
379  throw AlgorithmException( msg.c_str() );
380  }
381 
382  setSampler( samp );
383 
384  if ( needNormalization() ) {
385 
386  if ( !_samp->isNormalized() ) {
387 
388  Log::instance()->info( "Computing normalization\n" );
389 
390  if ( _normalizerPtr ) {
391 
393 
395  }
396  else {
397 
398  std::string msg = "Normalizer not specified.\n";
399 
400  Log::instance()->error( msg.c_str() );
401 
402  throw AlgorithmException( msg.c_str() );
403  }
404  }
405  }
406  else {
407 
408  if ( _samp->isNormalized() ) {
409 
410  _samp->resetNormalization();
411  }
412  }
413 
414  if ( ! initialize() ) {
415 
416  std::string msg = "Algorithm could not be initialized.\n";
417 
418  Log::instance()->error( msg.c_str() );
419 
420  throw AlgorithmException( msg.c_str() );
421  }
422 
423  // Generate model.
424  int ncycle = 0;
425  int resultFlag = 1;
426  int doneFlag = 0;
427  bool abort = false;
428 
429  while ( resultFlag && ! doneFlag ) {
430 
431  if ( callbackWrapper ) {
432 
433  try {
434 
435  abort = callbackWrapper->abortionRequested();
436 
437  if ( abort ) {
438 
439  Log::instance()->error( "Model creation aborted.\n" );
440  break;
441  }
442  }
443  catch ( char * message ) {
444 
445  string error( "Exception in abort callback: " );
446  error += message;
447  Log::instance()->error( error.c_str() );
448  throw AlgorithmException( error.c_str() );
449  }
450  catch (...) {}
451  }
452 
453  // I moved thee two calls out of the while()
454  // above and into separate calls because
455  // when run in a thread we need to catch
456  // exceptions properly TS
457  try {
458 
459  resultFlag = iterate();
460  doneFlag = done();
461  }
462  catch ( char * message ) {
463 
464  string error( "Exception in model iteration: " );
465  error += message;
466  Log::instance()->error( error.c_str() );
467  throw AlgorithmException( error.c_str() );
468  }
469 
470  ncycle++;
471 
472  if ( callbackWrapper ) {
473 
474  try {
475 
476  callbackWrapper->notifyModelCreationProgress( getProgress() );
477  }
478  catch ( char * message ) {
479 
480  string error( "Exception in get progress: " );
481  error += message;
482  Log::instance()->error( error.c_str() );
483  throw AlgorithmException( error.c_str() );
484  }
485  catch (...) {}
486  }
487  }
488 
489  if ( abort ) {
490 
491  std::string msg = "Model creation aborted.\n";
492 
493  Log::instance()->error( msg.c_str() );
494 
495  throw AlgorithmException( msg.c_str() );
496  }
497 
498  if ( ! done() ) {
499 
500  std::string msg = "Algorithm could not produce a model.\n";
501 
502  Log::instance()->error( msg.c_str() );
503 
504  throw AlgorithmException( msg.c_str() );
505  }
506 
507  if ( ! finalize() ) {
508 
509  std::string msg = "Algorithm could not be finalized.\n";
510 
511  Log::instance()->error( msg.c_str() );
512 
513  throw AlgorithmException( msg.c_str() );
514  }
515 
516  if ( callbackWrapper ) {
517 
518  try {
519 
520  callbackWrapper->notifyModelCreationProgress( 1.0 );
521  }
522  catch ( char * message ) {
523 
524  string error( "Exception when finalizing progress: " );
525  error += message;
526  Log::instance()->error( error.c_str() );
527  throw AlgorithmException( error.c_str() );
528  }
529  catch (...) {}
530  }
531 
532  return getModel();
533 }
534 
535 Model
537 {
538  // Need the ugly const_cast to cast away constness of this.
539  // ConstAlgorithmPtr must be initialized with the PlainPoinerType = AlgorithmImpl *
540  // and not with the const AlgorithmImpl*.
541  // Once the ConstAlgorihtmPtr is created, then it behaves as if its const.
542  return Model( new AlgoAdapterModelImpl( ConstAlgorithmPtr( const_cast<AlgorithmImpl*>(this) )));
543 }
Model createModel(const SamplerPtr &samp, CallbackWrapper *func=0)
Definition: Algorithm.cpp:362
Normalizer * getNormalizer() const
Definition: Algorithm.cpp:338
std::vector< ConfigurationPtr > subsection_list
AlgMetadata const * _metadata
Definition: Algorithm.hh:253
static AlgorithmPtr newAlgorithm(std::string const id)
virtual int initialize()=0
AlgorithmImpl(AlgMetadata const *metadata)
Definition: Algorithm.cpp:54
virtual ConfigurationPtr getConfiguration() const =0
virtual Model getModel() const
Definition: Algorithm.cpp:536
ReferenceCountedPointer< ModelImpl > Model
Definition: Model.hh:38
static Log * instance()
Returns the instance pointer, creating the object on the first call.
Definition: Log.cpp:45
std::string id
Identifier to be used by programmers.
Definition: AlgMetadata.hh:75
virtual int finalize()
Definition: Algorithm.hh:137
virtual int done() const
Definition: Algorithm.hh:140
AlgorithmPtr getFreshCopy()
Definition: Algorithm.cpp:254
void error(const char *format,...)
'Error' level.
Definition: Log.cpp:290
int getParameter(std::string const &name, std::string *value)
virtual int iterate()
Definition: Algorithm.hh:132
ReferenceCountedPointer< const AlgorithmImpl > ConstAlgorithmPtr
Definition: Algorithm.hh:56
void setNormalization(const SamplerPtr &samp) const
Definition: Algorithm.cpp:350
#define UNUSED(symbol)
Definition: os_specific.hh:55
void setParameters(int nparam, AlgParameter const *param)
Definition: Algorithm.cpp:229
virtual void _setConfiguration(const ConstConfigurationPtr &)
Definition: Algorithm.hh:200
std::map< icstring, std::string > ParamSetType
Definition: Algorithm.hh:84
void notifyModelCreationProgress(float progress)
virtual void _getConfiguration(ConfigurationPtr &) const
Definition: Algorithm.hh:199
void setConfiguration(const ConstConfigurationPtr &)
Definition: Algorithm.cpp:121
virtual int needNormalization()
Definition: Algorithm.hh:155
std::string const value() const
Definition: AlgParameter.hh:62
virtual ~AlgorithmImpl()
Definition: Algorithm.cpp:70
ConfigurationPtr getConfiguration() const
Definition: Algorithm.cpp:86
std::string const id() const
Definition: AlgParameter.hh:56
void setSampler(const SamplerPtr &samp)
Definition: Algorithm.cpp:221
virtual void setConfiguration(const ConstConfigurationPtr &)=0
SamplerPtr _samp
Definition: Algorithm.hh:245
void info(const char *format,...)
'Info' level.
Definition: Log.cpp:256
std::string version
Built version.
Definition: AlgMetadata.hh:77
ParamSetType::value_type ParamSetValueType
Definition: Algorithm.hh:257
virtual void computeNormalization(const ReferenceCountedPointer< const SamplerImpl > &samplerPtr)=0
ParamSetType _param
Definition: Algorithm.hh:249
void debug(const char *format,...)
'Debug' level.
Definition: Log.cpp:237
virtual float getProgress() const
Definition: Algorithm.hh:146
virtual Normalizer * getCopy()=0
Normalizer * _normalizerPtr
Definition: Algorithm.hh:247
AlgMetadata metadata
Definition: garp.cpp:134
static char error[256]
Definition: FileParser.cpp:42