openModeller  Version 1.5.0
bioclim.cpp
Go to the documentation of this file.
1 
28 #include "bioclim.hh"
29 
31 
33 
34 #include <string.h>
35 #include <stdio.h>
36 #include <math.h>
37 
38 /****************************************************************/
39 /********************** Algorithm's Metadata ********************/
40 
41 #define NUM_PARAM 1
42 
43 #define CUTOFF_ID "StandardDeviationCutoff"
44 
45 
46 /*************************************/
47 /*** Algorithm parameters metadata ***/
48 
50 
51  // Metadata of the first parameter.
52  {
53  CUTOFF_ID, // Id
54  "Standard deviation cutoff", // Name.
55  Real, // Type.
56 
57  // Overview
58  "The envelope is determined by multiplying this parameter and the\
59  standard deviation.",
60 
61  // Description.
62  "Standard deviation cutoff for all bioclimatic envelopes.\n\
63  Examples of (fraction of inclusion, parameter value) are:\n\
64  (50.0%, 0.674); (68.3%, 1.000); (90.0%, 1.645); (95.0%, 1.960);\
65  (99.7%, 3.000)",
66 
67  1, // Not zero if the parameter has lower limit.
68  0.0, // Parameter's lower limit.
69  0, // Not zero if the parameter has upper limit.
70  0.0, // Parameter's upper limit.
71  "0.674" // Parameter's typical (default) value.
72  },
73 };
74 
75 
76 /************************************/
77 /*** Algorithm's general metadata ***/
78 
80 
81  "BIOCLIM", // Id.
82  "Bioclim", // Name.
83  "0.2", // Version.
84 
85  // Overview
86  "Uses mean and standard deviation for each environmental\
87  variable separately to calculate bioclimatic envelopes.\
88  Level of fitness between the environmental values on a point\
89  and the respective envelopes classifies points as\
90  Suitable, Marginal, or Unsuitable for presence.",
91 
92  // Description.
93  "Implements the Bioclimatic Envelope Algorithm.\
94  For each given environmental variable the algorithm finds the mean\
95  and standard deviation (assuming normal distribution) associated\
96  to the occurrence points. Each variable has its own envelope\
97  represented by the interval [m - c*s, m + c*s], where 'm' is the\
98  mean; 'c' is the cutoff input parameter; and 's' is the standard\
99  deviation. Besides the envelope, each environmental variable has\
100  additional upper and lower limits taken from the maximum and\
101  minimum values related to the set of occurrence points.\nIn this\
102  model, any point can be classified as:\n\
103  Suitable: if all associated environmental values fall within\
104  the calculated envelopes;\n\
105  Marginal: if one or more associated environmental value falls\
106  outside the calculated envelope, but still within the upper and\
107  lower limits.\n\
108  Unsuitable: if one or more associated enviromental value falls\
109  outside the upper and lower limits.\n\
110 Bioclim's categorical output is mapped to probabilities\
111  of 1.0, 0.5 and 0.0 respectively.",
112 
113  "Nix, H. A.", // Author
114 
115  // Bibliography.
116  "Nix, H.A. (1986) A biogeographic analysis of Australian elapid\
117  snakes. In: Atlas of Elapid Snakes of Australia. (Ed.) R. Longmore,\
118  pp. 4-15. Australian Flora and Fauna Series Number 7. Australian\
119  Government Publishing Service: Canberra.",
120 
121  "Mauro Muņoz, // Code author. "mesmunoz [at] gmail.com", // Code author's contact. 0, // Does not accept categorical data. 0, // Does not need (pseudo)absence points. NUM_PARAM, // Algorithm's parameters. parameters }; /****************************************************************/ /****************** Algorithm's factory function ****************/ OM_ALG_DLL_EXPORT AlgorithmImpl * algorithmFactory() { return new Bioclim(); } OM_ALG_DLL_EXPORT AlgMetadata const * algorithmMetadata() { return &metadata; } /****************************************************************/ /**************************** Bioclim ***************************/ /*******************/ /*** constructor ***/ Bioclim::Bioclim() : AlgorithmImpl( &metadata ), _done( false ), _minimum(), _maximum(), _mean(), _std_dev() { } /******************/ /*** destructor ***/ Bioclim::~Bioclim() { } /******************/ /*** initialize ***/ int Bioclim::initialize() { Scalar cutoff = 0.0; // Read and check the standard deviation cutoff parameter. if ( ! getParameter( CUTOFF_ID, &cutoff ) ) { Log::instance()->error( "Parameter " CUTOFF_ID " not set properly.\n" ); return 0; } if ( cutoff <= 0 ) { Log::instance()->warn( "Bioclim - parameter out of range: %f\n", cutoff ); return 0; } // Number of independent variables. int dim = _samp->numIndependent(); Log::instance()->info( "Reading %d-dimensional occurrence points.\n", dim ); // Check the number of sampled points. int npnt = _samp->numPresence(); if ( npnt < 2 ) { Log::instance()->error( "Bioclim needs at least 2 points inside the mask!\n" ); return 0; } Log::instance()->info( "Using %d points to find the bioclimatic envelope.\n", npnt ); computeStats( _samp->getPresences() ); _std_dev *= cutoff; _done = true; return 1; } /***************/ /*** iterate ***/ int Bioclim::iterate() { return 1; } /************/ /*** done ***/ int Bioclim::done() const { // This is not an iterative algorithm. return _done; } /*****************/ /*** get Value ***/ Scalar Bioclim::getValue( const Sample& x ) const { // Zero if some point valuble is outside its respective envelope. Scalar outside_envelope = 0; // Finds the distance from each variable mean to the respective // point value. Sample dif = x; dif -= _mean; for( unsigned int i=0; i<x.size(); i++) { if ( x[i] < _minimum[i] || x[i] > _maximum[i] ) { return 0.0; } if ( ! outside_envelope ) { Scalar cutoff = _std_dev[i]; // If some x[i] is out of its bioclimatic envelope, predicts // no occurrence. if ( dif[i] > cutoff || dif[i] < -cutoff ) { outside_envelope = 1; } } } // If all point values are within the envelope, returns probability // 1.0. Else, if some point is outside the envelope but inside // the upper and lower ranges, returns 0.5 of probability. return outside_envelope ? 0.5 : 1.0; } /***********************/ /*** get Convergence ***/ int Bioclim::getConvergence( Scalar * const val ) const { *val = 1.0; return 1; } /*******************/ /*** get Minimum ***/ void Bioclim::computeStats( const OccurrencesPtr& occs ) { // Compute min, max, and mean { OccurrencesImpl::const_iterator oc = occs->begin(); OccurrencesImpl::const_iterator end = occs->end(); // Intialize _minimum, _maximum, and _mean // to the values of the first point, and increment // to get it out of the loop. Sample const & sample = (*oc)->environment(); _minimum = sample; _maximum = sample; _mean = sample; ++oc; // For each Occurrence, update the // statistics for _minimum, _maximum, and _mean while ( oc != end ) { Sample const& sample = (*oc)->environment(); _mean += sample; _minimum &= sample; _maximum |= sample; ++oc; } // Divide for the mean. _mean /= Scalar( occs->numOccurrences() ); } // Now compute the std deviation by first computing the variance. { _std_dev.resize( _mean.size() ); OccurrencesImpl::const_iterator oc = occs->begin(); OccurrencesImpl::const_iterator end = occs->end(); // Now we compute the variance. while ( oc != end ) { Sample tmp( (*oc)->environment() ); tmp -= _mean; tmp *= tmp; _std_dev += tmp; ++oc; } // In variance, we divide by (npnt - 1), not npnt! Scalar npts = Scalar( occs->numOccurrences() - 1 ); // Now divide and root to get deviation. _std_dev /= npts; _std_dev.sqrt(); } } /****************************************************************/ /****************** configuration *******************************/ void Bioclim::_getConfiguration( ConfigurationPtr& config ) const { if ( !_done ) return; ConfigurationPtr model_config( new ConfigurationImpl("Bioclim") ); config->addSubsection( model_config ); model_config->addNameValue( "Mean", _mean ); model_config->addNameValue( "StdDev", _std_dev ); model_config->addNameValue( "Minimum", _minimum ); model_config->addNameValue( "Maximum", _maximum ); } void Bioclim::_setConfiguration( const ConstConfigurationPtr& config ) { ConstConfigurationPtr model_config = config->getSubsection( "Bioclim" ); if (!model_config) return; _done = true; _mean = model_config->getAttributeAsSample( "Mean" ); _std_dev = model_config->getAttributeAsSample( "StdDev" ); _minimum = model_config->getAttributeAsSample( "Minimum" ); _maximum = model_config->getAttributeAsSample( "Maximum" ); return; } /********************/ /*** log Envelope ***/ void Bioclim::logEnvelope() { Log::instance()->info( "Envelope with %d dimensions (variables).\n\n", _mean.size() ); for ( unsigned int i = 0; i < _mean.size(); i++ ) { Log::instance()->info( "Variable %02d:", i ); Log::instance()->info( " Mean : %f\n", _mean[i] ); Log::instance()->info( " Deviation: %f\n", _std_dev[i] ); Log::instance()->info( " Minimum : %f\n", _minimum[i] ); Log::instance()->info( " Maximum : %f\n", _maximum[i] ); Log::instance()->info( "\n" ); } } ", // Code author.
122  "mesmunoz [at] gmail.com", // Code author's contact.
123 
124  0, // Does not accept categorical data.
125  0, // Does not need (pseudo)absence points.
126 
127  NUM_PARAM, // Algorithm's parameters.
128  parameters
129 };
130 
131 
132 
133 /****************************************************************/
134 /****************** Algorithm's factory function ****************/
135 
136 OM_ALG_DLL_EXPORT
139 {
140  return new Bioclim();
141 }
142 
143 OM_ALG_DLL_EXPORT
144 AlgMetadata const *
146 {
147  return &metadata;
148 }
149 
150 
151 /****************************************************************/
152 /**************************** Bioclim ***************************/
153 
154 /*******************/
155 /*** constructor ***/
156 
158  AlgorithmImpl( &metadata ),
159  _done( false ),
160  _minimum(),
161  _maximum(),
162  _mean(),
163  _std_dev()
164 { }
165 
166 
167 /******************/
168 /*** destructor ***/
169 
171 {
172 }
173 
174 
175 /******************/
176 /*** initialize ***/
177 int
179 {
180  Scalar cutoff = 0.0;
181  // Read and check the standard deviation cutoff parameter.
182  if ( ! getParameter( CUTOFF_ID, &cutoff ) ) {
183  Log::instance()->error( "Parameter " CUTOFF_ID " not set properly.\n" );
184  return 0;
185  }
186 
187  if ( cutoff <= 0 ) {
188  Log::instance()->warn( "Bioclim - parameter out of range: %f\n", cutoff );
189  return 0;
190  }
191 
192  // Number of independent variables.
193  int dim = _samp->numIndependent();
194  Log::instance()->info( "Reading %d-dimensional occurrence points.\n", dim );
195 
196  // Check the number of sampled points.
197  int npnt = _samp->numPresence();
198  if ( npnt < 2 ) {
199  Log::instance()->error( "Bioclim needs at least 2 points inside the mask!\n" );
200  return 0;
201  }
202 
203  Log::instance()->info( "Using %d points to find the bioclimatic envelope.\n", npnt );
204 
205  computeStats( _samp->getPresences() );
206 
207  _std_dev *= cutoff;
208 
209  _done = true;
210 
211  return 1;
212 }
213 
214 
215 /***************/
216 /*** iterate ***/
217 int
219 {
220  return 1;
221 }
222 
223 
224 /************/
225 /*** done ***/
226 int
228 {
229  // This is not an iterative algorithm.
230  return _done;
231 }
232 
233 
234 /*****************/
235 /*** get Value ***/
236 Scalar
237 Bioclim::getValue( const Sample& x ) const
238 {
239  // Zero if some point valuble is outside its respective envelope.
240  Scalar outside_envelope = 0;
241 
242  // Finds the distance from each variable mean to the respective
243  // point value.
244  Sample dif = x;
245  dif -= _mean;
246 
247  for( unsigned int i=0; i<x.size(); i++) {
248 
249  if ( x[i] < _minimum[i] || x[i] > _maximum[i] ) {
250  return 0.0;
251  }
252 
253  if ( ! outside_envelope ) {
254 
255  Scalar cutoff = _std_dev[i];
256 
257  // If some x[i] is out of its bioclimatic envelope, predicts
258  // no occurrence.
259  if ( dif[i] > cutoff || dif[i] < -cutoff ) {
260  outside_envelope = 1;
261  }
262  }
263 
264  }
265 
266  // If all point values are within the envelope, returns probability
267  // 1.0. Else, if some point is outside the envelope but inside
268  // the upper and lower ranges, returns 0.5 of probability.
269  return outside_envelope ? 0.5 : 1.0;
270 }
271 
272 
273 /***********************/
274 /*** get Convergence ***/
275 int
276 Bioclim::getConvergence( Scalar * const val ) const
277 {
278  *val = 1.0;
279  return 1;
280 }
281 
282 
283 /*******************/
284 /*** get Minimum ***/
285 void
287 {
288 
289  // Compute min, max, and mean
290  {
291  OccurrencesImpl::const_iterator oc = occs->begin();
292  OccurrencesImpl::const_iterator end = occs->end();
293 
294  // Intialize _minimum, _maximum, and _mean
295  // to the values of the first point, and increment
296  // to get it out of the loop.
297  Sample const & sample = (*oc)->environment();
298  _minimum = sample;
299  _maximum = sample;
300  _mean = sample;
301 
302  ++oc;
303 
304  // For each Occurrence, update the
305  // statistics for _minimum, _maximum, and _mean
306 
307  while ( oc != end ) {
308 
309  Sample const& sample = (*oc)->environment();
310 
311  _mean += sample;
312  _minimum &= sample;
313  _maximum |= sample;
314 
315  ++oc;
316  }
317 
318  // Divide for the mean.
319  _mean /= Scalar( occs->numOccurrences() );
320 
321  }
322 
323  // Now compute the std deviation by first computing the variance.
324  {
325 
326  _std_dev.resize( _mean.size() );
327  OccurrencesImpl::const_iterator oc = occs->begin();
328  OccurrencesImpl::const_iterator end = occs->end();
329 
330  // Now we compute the variance.
331  while ( oc != end ) {
332  Sample tmp( (*oc)->environment() );
333  tmp -= _mean;
334  tmp *= tmp;
335  _std_dev += tmp;
336  ++oc;
337  }
338 
339  // In variance, we divide by (npnt - 1), not npnt!
340  Scalar npts = Scalar( occs->numOccurrences() - 1 );
341 
342  // Now divide and root to get deviation.
343  _std_dev /= npts;
344  _std_dev.sqrt();
345  }
346 
347 }
348 
349 /****************************************************************/
350 /****************** configuration *******************************/
351 void
353 {
354  if ( !_done )
355  return;
356 
357  ConfigurationPtr model_config( new ConfigurationImpl("Bioclim") );
358  config->addSubsection( model_config );
359 
360  model_config->addNameValue( "Mean", _mean );
361  model_config->addNameValue( "StdDev", _std_dev );
362  model_config->addNameValue( "Minimum", _minimum );
363  model_config->addNameValue( "Maximum", _maximum );
364 
365 }
366 
367 void
369 {
370  ConstConfigurationPtr model_config = config->getSubsection( "Bioclim" );
371 
372  if (!model_config)
373  return;
374 
375  _done = true;
376 
377  _mean = model_config->getAttributeAsSample( "Mean" );
378  _std_dev = model_config->getAttributeAsSample( "StdDev" );
379  _minimum = model_config->getAttributeAsSample( "Minimum" );
380  _maximum = model_config->getAttributeAsSample( "Maximum" );
381 
382  return;
383 }
384 
385 /********************/
386 /*** log Envelope ***/
387 void
389 {
390  Log::instance()->info( "Envelope with %d dimensions (variables).\n\n", _mean.size() );
391 
392  for ( unsigned int i = 0; i < _mean.size(); i++ )
393  {
394  Log::instance()->info( "Variable %02d:", i );
395  Log::instance()->info( " Mean : %f\n", _mean[i] );
396  Log::instance()->info( " Deviation: %f\n", _std_dev[i] );
397  Log::instance()->info( " Minimum : %f\n", _minimum[i] );
398  Log::instance()->info( " Maximum : %f\n", _maximum[i] );
399  Log::instance()->info( "\n" );
400  }
401 }
Sample _maximum
Mininum value for each variable.
Definition: bioclim.hh:73
int iterate()
Definition: bioclim.cpp:218
void warn(const char *format,...)
'Warn' level.
Definition: Log.cpp:273
static AlgParamMetadata parameters[NUM_PARAM]
Definition: bioclim.cpp:49
int initialize()
Definition: bioclim.cpp:178
double Scalar
Type of map values.
Definition: om_defs.hh:39
Sample _minimum
is true if the algorithm is finished.
Definition: bioclim.hh:72
int getConvergence(Scalar *const val) const
Definition: bioclim.cpp:276
bool _done
Definition: bioclim.hh:70
static Log * instance()
Returns the instance pointer, creating the object on the first call.
Definition: Log.cpp:45
Scalar getValue(const Sample &x) const
Definition: bioclim.cpp:237
~Bioclim()
Definition: bioclim.cpp:170
void error(const char *format,...)
'Error' level.
Definition: Log.cpp:290
int getParameter(std::string const &name, std::string *value)
void computeStats(const OccurrencesPtr &)
Definition: bioclim.cpp:286
void _getConfiguration(ConfigurationPtr &) const
Definition: bioclim.cpp:352
#define CUTOFF_ID
Definition: bioclim.cpp:43
void resize(std::size_t size)
Definition: Sample.cpp:153
OM_ALG_DLL_EXPORT AlgMetadata const * algorithmMetadata()
Definition: bioclim.cpp:145
Sample _std_dev
Mean of sampled points.
Definition: bioclim.hh:75
#define NUM_PARAM
Definition: bioclim.cpp:41
void logEnvelope()
Definition: bioclim.cpp:388
std::size_t size() const
Definition: Sample.hh:70
Sample & sqrt()
Definition: Sample.cpp:445
Sample _mean
Maximum value for each variable.
Definition: bioclim.hh:74
void _setConfiguration(const ConstConfigurationPtr &)
Definition: bioclim.cpp:368
Bioclim()
Definition: bioclim.cpp:157
SamplerPtr _samp
Definition: Algorithm.hh:245
void info(const char *format,...)
'Info' level.
Definition: Log.cpp:256
static AlgMetadata metadata
Definition: bioclim.cpp:79
int done() const
Definition: bioclim.cpp:227
OM_ALG_DLL_EXPORT AlgorithmImpl * algorithmFactory()
Definition: bioclim.cpp:138
std::vector< OccurrencePtr >::const_iterator const_iterator
Definition: Occurrences.hh:85
Definition: Sample.hh:25