openModeller  Version 1.5.0
virtual_niche.cpp
Go to the documentation of this file.
1 
28 #include "virtual_niche.hh"
29 
32 #include <openmodeller/Random.hh>
33 
34 #include <stdio.h>
35 #include <cmath>
36 #include <vector>
37 
38 using namespace std;
39 
40 #ifndef PI
41 #define PI 3.141592653589793238462643
42 #endif
43 
44 /****************************************************************/
45 /********************** Algorithm's Metadata ********************/
46 
47 #define NUM_PARAM 4
48 
49 #define BACKGROUND_ID "NumberOfBackgroundPoints"
50 #define USE_ABSENCES_ID "UseAbsencesAsBackground"
51 #define THRESHOLD_ID "SuitabilityThreshold"
52 #define STD_FACTOR_ID "StandardDeviationFactor"
53 
54 /****************************/
55 /*** Algorithm parameters ***/
56 
58 
59  // Number of background points to be generated
60  {
61  BACKGROUND_ID, // Id.
62  "Number of background points", // Name.
63  Integer, // Type.
64  "Number of background points to be generated.", // Overview
65  "Number of background points to be generated, which will be used to estimate the standard deviation of each variable in the area of interest.", // Description.
66  1, // Not zero if the parameter has lower limit.
67  0, // Parameter's lower limit.
68  1, // Not zero if the parameter has upper limit.
69  10000, // Parameter's upper limit.
70  "10000" // Parameter's typical (default) value.
71  },
72  // Use absence points as background
73  {
74  USE_ABSENCES_ID, // Id.
75  " Use absence points as background", // Name.
76  Integer, // Type.
77  " Use absence points as background", // Overview
78  "When absence points are provided, this parameter can be used to instruct the algorithm to use them as background points. This would prevent the algorithm to randomly generate them, also facilitating comparisons between different algorithms.", // Description.
79  1, // Not zero if the parameter has lower limit.
80  0, // Parameter's lower limit.
81  1, // Not zero if the parameter has upper limit.
82  1, // Parameter's upper limit.
83  "0" // Parameter's typical (default) value.
84  },
85  // Suitability threshold
86  {
87  THRESHOLD_ID, // Id.
88  "Suitability threshold", // Name.
89  Real, // Type.
90  "Suitability threshold to get a binary niche.", // Overview
91  "Suitability threshold to get a binary niche. Use 1 if you want to keep the continuous niche.", // Description.
92  1, // Not zero if the parameter has lower limit.
93  0, // Parameter's lower limit.
94  1, // Not zero if the parameter has upper limit.
95  1, // Parameter's upper limit.
96  "1.0" // Parameter's typical (default) value.
97  },
98  // Standard Deviation Factor
99  {
100  STD_FACTOR_ID, // Id.
101  "Standard deviation factor", // Name.
102  Real, // Type.
103  "Standard deviation factor.", // Overview
104  "Factor (x) used to control the minimum limit of the random standard deviation for each variable. The random standard deviation will be a value between [x*S, S], where S is the standard deviation of the entire native region. Increase the factor to get larger niches, especially when using many environmental variables.", // Description.
105  1, // Not zero if the parameter has lower limit.
106  0, // Parameter's lower limit.
107  1, // Not zero if the parameter has upper limit.
108  1, // Parameter's upper limit.
109  "0.0" // Parameter's typical (default) value.
110  },
111 };
112 
113 /**************************/
114 /*** Algorithm metadata ***/
115 
117 
118  "VNG", // Id
119  "Virtual Niche Generator", // Name
120  "0.2", // Version
121 
122  // Overview
123  "Algorithm used to create virtual niches using the\
124  first presence point as a reference for optimum\
125  environmental conditions. The niche is represented by\
126  a multivariate Gaussian distribution with the mean value\
127  based on the optimum conditions and a random standard\
128  deviation smaller than the standard deviation of the\
129  region of interest. Suitability is calculated by assuming\
130  independence between all variables.",
131  // Description.
132  "Algorithm used to create virtual niches using the\
133  first presence point as a reference for optimum\
134  environmental conditions. The niche is represented by\
135  a multivariate Gaussian distribution with the mean value\
136  based on the optimum conditions and a random standard\
137  deviation. Suitability is calculated by assuming\
138  independence between all variables, i.e., the final\
139  value is the product of the individual suitability\
140  for each variable. Individual suitabilities are\
141  calculated as the result of the Gaussian probability\
142  density function scaled by a factor to make the\
143  optimum condition correspond to 1. Standard deviations\
144  for each variable are randomly chosen within the range\
145  [x*S, S], where S is the standard deviation of the entire\
146  native region (calculated based on the background\
147  points) and x is the standard deviation factor parameter\
148  between 0 and 1.",
149 
150  "Renato De Giovanni", // Author
151 
152  // Bibliography.
153  "renato [at] cria.org.br",
154 
155  "Renato De Giovanni", // Code author
156  "renato [at] cria.org.br", // Code author's contact
157 
158  0, // Does not accept categorical data.
159  0, // Does not need (pseudo)absence points.
160 
161  NUM_PARAM,
162  parameters
163 };
164 
165 
166 
167 /****************************************************************/
168 /****************** Algorithm's factory function ****************/
169 
170 OM_ALG_DLL_EXPORT
173 {
174  return new VirtualNicheGenerator();
175 }
176 
177 OM_ALG_DLL_EXPORT
178 AlgMetadata const *
180 {
181  return &metadata;
182 }
183 
184 
185 /****************************************************************/
186 /**************************** EnvelopeScore ***************************/
187 
188 /*******************/
189 /*** constructor ***/
190 
193  _done( false ),
194  _minimum(),
195  _maximum(),
196  _mean(),
197  _std(),
198  _scale(),
199  _threshold(1.0),
200  _std_factor(0.0)
201 { }
202 
203 
204 /******************/
205 /*** destructor ***/
206 
208 {
209 }
210 
211 
212 /******************/
213 /*** initialize ***/
214 int
216 {
217  Log::instance()->warn( "This algorithm creates virtual niches - do not use it to generate models for real species!\n" );
218 
219  if ( ! getParameter( THRESHOLD_ID, &_threshold ) ) {
220 
221  _threshold = 1.0;
222  }
223 
224  // Check number of points
225  if ( _samp->numPresence() > 1 ) {
226 
227  Log::instance()->warn( "Virtual Niche uses only one point (the first). All other points will be ignored.\n" );
228  }
229 
230  // Background points
231  bool use_absences_as_background = false;
232  int use_abs;
233  int num_absences = 0;
234  if ( getParameter( USE_ABSENCES_ID, &use_abs ) && use_abs == 1 ) {
235 
236  use_absences_as_background = true;
237  }
238 
239  if ( use_absences_as_background ) {
240 
241  num_absences = _samp->numAbsence();
242 
243  if ( num_absences ) {
244 
245  _num_background = num_absences;
246  }
247  else {
248 
249  Log::instance()->warn( "No absence points provided. Generating 10000 background points.\n" );
250  _num_background = 10000;
251  }
252  }
253  else {
254 
256 
257  Log::instance()->warn( "Parameter '" BACKGROUND_ID "' unspecified. Using default value (10000).\n");
258 
259  _num_background = 10000;
260  }
261 
262  if ( _num_background <= 0 ) {
263 
264  Log::instance()->warn( "Parameter '" BACKGROUND_ID "' must be greater than zero.\n" );
265  return 0;
266  }
267  }
268 
269  OccurrencesPtr presences = _samp->getPresences();
270 
271  _background = new OccurrencesImpl( presences->label(), presences->coordSystem() );
272 
273  if ( use_absences_as_background && num_absences >=0 ) {
274 
275  _background->appendFrom( _samp->getAbsences() );
276  }
277  else {
278 
279  // Generate random background points
280  Log::instance()->info( "Generating random background points.\n" );
281 
282  for ( int i = 0; i < _num_background; ++i ) {
283 
284  OccurrencePtr oc = _samp->getPseudoAbsence();
285  _background->insert( oc );
286  }
287  }
288 
289  if ( ! getParameter( STD_FACTOR_ID, &_std_factor ) ) {
290 
291  Log::instance()->warn( "Parameter '" STD_FACTOR_ID "' unspecified. Using default value (0).\n");
292 
293  _std_factor = 0.0;
294  }
295 
296  if ( _std_factor < 0.0 ) {
297 
298  _std_factor = 0.0;
299  }
300  else {
301 
302  if ( _std_factor > 1.0 ) {
303 
304  _std_factor = 1.0;
305  }
306  }
307 
308  return 1;
309 }
310 
311 
312 /***************/
313 /*** iterate ***/
314 int
316 {
317  Log::instance()->info( "Generating virtual niche.\n" );
318 
319  // Mean of the normal distribution is the environmental value on the first point
320  _mean = _samp->getPresence(0)->environment();
321 
322  EnvironmentPtr env = _samp->getEnvironment();
323 
324  // Minimum and maximum values for each environmental variable for the whole layer
325  env->getExtremes(&_minimum, &_maximum);
326 
327  // Estimate standard deviation in the whole region of interest using background pts
328  Sample background_std = Sample(_mean.size(), 0.0);
329  Sample background_mean = Sample(_mean.size(), 0.0);
330 
333 
334  // Compute mean
335  while ( oc != end ) {
336 
337  Sample tmp( (*oc)->environment() );
338  background_mean += tmp;
339  ++oc;
340  }
341  background_mean /= Scalar( _num_background );
342 
343  oc = _background->begin();
344  end = _background->end();
345 
346  // Compute variance
347  while ( oc != end ) {
348 
349  Sample tmp( (*oc)->environment() );
350  tmp -= background_mean;
351  tmp *= tmp;
352  background_std += tmp;
353  ++oc;
354  }
355 
356  Scalar npts = Scalar( _num_background - 1 );
357 
358  // Now divide and root to get deviation
359  background_std /= npts;
360  background_std.sqrt();
361 
362  // Get a random standard deviation for each variable for the niche function
363  _std = _mean; // just initialize the sample
364  Sample max_pdf_val = Sample(_mean.size(), 1.0); // just initialize the sample
365 
366  Random random;
367 
368  for (int i = 0; i < _samp->numIndependent(); ++i) {
369 
370  // Random standard deviation, restricting the interval using std factor
371  // to avoid too constrained niches
372  _std[i] = random(_std_factor*background_std[i], background_std[i]);
373 
374  // Maximum value of the probability density function
375  max_pdf_val[i] = pdf(_mean[i], _std[i], _mean[i]);
376  }
377 
378  _scale = Sample(_mean.size(), 1.0);
379  _scale /= max_pdf_val;
380 
381  dump();
382 
383  _done = true;
384 
385  return 1;
386 }
387 
388 
389 /************/
390 /*** done ***/
391 int
393 {
394  // This is not an iterative algorithm.
395  return _done;
396 }
397 
398 
399 /*****************/
400 /*** get Value ***/
401 Scalar
403 {
404  Scalar suitability = 1.0;
405 
406  for (unsigned int i=0; i < x.size(); i++) {
407 
408  Scalar pdf_value = pdf(_mean[i], _std[i], x[i]);
409 
410  suitability *= pdf_value*_scale[i];
411  }
412 
413  if ( _threshold < 1.0 ) {
414 
415  return (suitability < _threshold) ? 0.0 : 1.0;
416  }
417 
418  return suitability;
419 }
420 
421 
422 /***********************/
423 /*** get Convergence ***/
424 int
426 {
427  *val = 1.0;
428  return 1;
429 }
430 
431 
432 /****************************************************************/
433 /****************** configuration *******************************/
434 void
436 {
437  if ( !_done )
438  return;
439 
440  ConfigurationPtr model_config( new ConfigurationImpl("VirtualNiche") );
441  config->addSubsection( model_config );
442 
443  model_config->addNameValue( "Minimum" , _minimum );
444  model_config->addNameValue( "Maximum" , _maximum );
445  model_config->addNameValue( "Mean" , _mean );
446  model_config->addNameValue( "Std" , _std );
447  model_config->addNameValue( "Scale" , _scale );
448  model_config->addNameValue( "Threshold", _threshold );
449 }
450 
451 void
453 {
454  ConstConfigurationPtr model_config = config->getSubsection("VirtualNiche");
455 
456  if (!model_config)
457  return;
458 
459  _done = true;
460 
461  _minimum = model_config->getAttributeAsSample( "Minimum" );
462  _maximum = model_config->getAttributeAsSample( "Maximum" );
463  _mean = model_config->getAttributeAsSample( "Mean" );
464  _std = model_config->getAttributeAsSample( "Std" );
465  _scale = model_config->getAttributeAsSample( "Scale" );
466  _threshold = model_config->getAttributeAsDouble( "Threshold", 1.0 );
467 
468  return;
469 }
470 
471 /************/
472 /*** dump ***/
473 void
475 {
476  Log::instance()->info( "Result for %d dimensions (variables)\n", _minimum.size() );
477 
478  for ( unsigned int i = 0; i < _minimum.size(); i++ ) {
479 
480  Log::instance()->info( "Variable %02d:\n", i );
481  Log::instance()->info( " Minimum : %f\n", _minimum[i] );
482  Log::instance()->info( " Mean : %f\n", _mean[i] );
483  Log::instance()->info( " Maximum : %f\n", _maximum[i] );
484  Log::instance()->info( " Std : %f\n", _std[i] );
485  Log::instance()->info( " Scale : %f\n", _scale[i] );
486  }
487 }
488 
489 /***********/
490 /*** pdf ***/
491 Scalar
493 {
494  return (1.0/(std*sqrt(2.0*PI)))*exp(-0.5*pow((val-mean)/std, 2));
495 }
496 
497 
Scalar getValue(const Sample &x) const
void warn(const char *format,...)
'Warn' level.
Definition: Log.cpp:273
OM_ALG_DLL_EXPORT AlgMetadata const * algorithmMetadata()
int getConvergence(Scalar *const val) const
#define USE_ABSENCES_ID
Scalar _std_factor
Threshold to get a binary niche.
double Scalar
Type of map values.
Definition: om_defs.hh:39
static Log * instance()
Returns the instance pointer, creating the object on the first call.
Definition: Log.cpp:45
Sample _std
Average for the normal distribution.
Sample _mean
Maximum value for each variable.
virtual void _setConfiguration(const ConstConfigurationPtr &)
Scalar _threshold
Factors to multiply the PDF values.
Sample _maximum
Mininum value for each variable.
Definition: Random.hh:44
int getParameter(std::string const &name, std::string *value)
static AlgParamMetadata parameters[NUM_PARAM]
OccurrencesPtr _background
true if the algorithm is finished.
#define PI
virtual void _getConfiguration(ConfigurationPtr &) const
int _scale
Definition: om_niche.cpp:47
std::size_t size() const
Definition: Sample.hh:70
Sample & sqrt()
Definition: Sample.cpp:445
#define THRESHOLD_ID
OM_ALG_DLL_EXPORT AlgorithmImpl * algorithmFactory()
Sample _scale
Standard deviation for the normal distribution.
SamplerPtr _samp
Definition: Algorithm.hh:245
void info(const char *format,...)
'Info' level.
Definition: Log.cpp:256
#define BACKGROUND_ID
Scalar pdf(Scalar avg, Scalar std, Scalar val) const
std::vector< OccurrencePtr >::const_iterator const_iterator
Definition: Occurrences.hh:85
#define STD_FACTOR_ID
#define NUM_PARAM
static AlgMetadata metadata
Definition: Sample.hh:25