openModeller  Version 1.4.0
virtual_niche.cpp
Go to the documentation of this file.
00001 
00028 #include "virtual_niche.hh"
00029 
00030 #include <openmodeller/Configuration.hh>
00031 #include <openmodeller/Exceptions.hh>
00032 #include <openmodeller/Random.hh>
00033 
00034 #include <stdio.h>
00035 #include <cmath>
00036 #include <vector>
00037 
00038 using namespace std;
00039 
00040 #ifndef PI
00041 #define PI 3.141592653589793238462643
00042 #endif
00043 
00044 /****************************************************************/
00045 /********************** Algorithm's Metadata ********************/
00046 
00047 #define NUM_PARAM 3
00048 
00049 #define BACKGROUND_ID   "NumberOfBackgroundPoints"
00050 #define USE_ABSENCES_ID "UseAbsencesAsBackground"
00051 #define THRESHOLD_ID    "SuitabilityThreshold"
00052 
00053 /****************************/
00054 /*** Algorithm parameters ***/
00055 
00056 static AlgParamMetadata parameters[NUM_PARAM] = {
00057   
00058   // Number of background points to be generated
00059   {
00060     BACKGROUND_ID,                 // Id.
00061     "Number of background points", // Name.
00062     Integer,                       // Type.
00063     "Number of background points to be generated.", // Overview
00064     "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.
00065     1,      // Not zero if the parameter has lower limit.
00066     0,      // Parameter's lower limit.
00067     1,      // Not zero if the parameter has upper limit.
00068     10000,  // Parameter's upper limit.
00069     "10000" // Parameter's typical (default) value.
00070   },
00071   // Use absence points as background
00072   {
00073     USE_ABSENCES_ID,     // Id.
00074     " Use absence points as background", // Name.
00075     Integer,  // Type.
00076     " Use absence points as background", // Overview
00077     "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.
00078     1,   // Not zero if the parameter has lower limit.
00079     0,   // Parameter's lower limit.
00080     1,   // Not zero if the parameter has upper limit.
00081     1,   // Parameter's upper limit.
00082     "0"  // Parameter's typical (default) value.
00083   },
00084   // Suitability threshold
00085   {
00086     THRESHOLD_ID,            // Id.
00087     "Suitability threshold", // Name.
00088     Real,                    // Type.
00089     "Suitability threshold to get a binary niche.", // Overview
00090     "Suitability threshold to get a binary niche. Use 1 if you want to keep the continuous niche.", // Description.
00091     1,      // Not zero if the parameter has lower limit.
00092     0,      // Parameter's lower limit.
00093     1,      // Not zero if the parameter has upper limit.
00094     1,      // Parameter's upper limit.
00095     "1.0"   // Parameter's typical (default) value.
00096   },
00097 };
00098 
00099 /**************************/
00100 /*** Algorithm metadata ***/
00101 
00102 static AlgMetadata metadata = {
00103 
00104   "VNG",                     // Id
00105   "Virtual Niche Generator", // Name
00106   "0.1",                     // Version
00107 
00108   // Overview
00109   "Algorithm used to create virtual niches using the\
00110  first presence point as a reference for optimum\
00111  environmental conditions. The niche is represented by\
00112  a multivariate Gaussian distribution with the mean value\
00113  based on the optimum conditions and a random standard\
00114  deviation smaller than the standard deviation of the\
00115  region of interest. Suitability is calculated by assuming\
00116  independence between all variables.",
00117   // Description.
00118   "Algorithm used to create virtual niches using the\
00119  first presence point as a reference for optimum\
00120  environmental conditions. The niche is represented by\
00121  a multivariate Gaussian distribution with the mean value\
00122  based on the optimum conditions and a random standard\
00123  deviation smaller than the standard deviation of the\
00124  region of interest. Suitability is calculated by assuming\
00125  independence between all variables, i.e., the final\
00126  value is the product of the individual suitability\
00127  for each variable. Individual suitabilities are\
00128  calculated as the result of the Gaussian probability\
00129  density function scaled by a factor to make the\
00130  optimum condition correspond to 1. Standard deviations\
00131  are randomly chosen within the maximum range between\
00132  the mean and the extreme values of each variable.",
00133 
00134   "Renato De Giovanni",  // Author
00135 
00136   // Bibliography.
00137   "renato [at] cria.org.br",
00138 
00139   "Renato De Giovanni",      // Code author
00140   "renato [at] cria.org.br", // Code author's contact
00141 
00142   0,  // Does not accept categorical data.
00143   0,  // Does not need (pseudo)absence points.
00144 
00145   NUM_PARAM,
00146   parameters
00147 };
00148 
00149 
00150 
00151 /****************************************************************/
00152 /****************** Algorithm's factory function ****************/
00153 
00154 OM_ALG_DLL_EXPORT
00155 AlgorithmImpl *
00156 algorithmFactory()
00157 {
00158   return new VirtualNicheGenerator();
00159 }
00160 
00161 OM_ALG_DLL_EXPORT
00162 AlgMetadata const *
00163 algorithmMetadata()
00164 {
00165   return &metadata;
00166 }
00167 
00168 
00169 /****************************************************************/
00170 /**************************** EnvelopeScore ***************************/
00171 
00172 /*******************/
00173 /*** constructor ***/
00174 
00175 VirtualNicheGenerator::VirtualNicheGenerator() :
00176   AlgorithmImpl( &metadata ),
00177   _done( false ),
00178   _minimum(),
00179   _maximum(),
00180   _mean(),
00181   _std(),
00182   _scale(),
00183   _threshold(1.0)
00184 { }
00185 
00186 
00187 /******************/
00188 /*** destructor ***/
00189 
00190 VirtualNicheGenerator::~VirtualNicheGenerator()
00191 {
00192 }
00193 
00194 
00195 /******************/
00196 /*** initialize ***/
00197 int
00198 VirtualNicheGenerator::initialize()
00199 {
00200   Log::instance()->warn( "This algorithm creates virtual niches - do not use it to generate models for real species!\n" );
00201 
00202   if ( ! getParameter( THRESHOLD_ID, &_threshold ) ) {
00203 
00204     _threshold = 1.0;
00205   }
00206 
00207   // Check number of points
00208   if ( _samp->numPresence() > 1 ) {
00209 
00210     Log::instance()->warn( "Virtual Niche uses only one point (the first). All other points will be ignored.\n" );
00211   }
00212 
00213   // Background points
00214   bool use_absences_as_background = false;
00215   int use_abs;
00216   int num_absences = 0;
00217   if ( getParameter( USE_ABSENCES_ID, &use_abs ) && use_abs == 1 ) {
00218 
00219     use_absences_as_background = true;
00220   }
00221 
00222   if ( use_absences_as_background ) {
00223 
00224     num_absences = _samp->numAbsence();
00225 
00226     if ( num_absences ) {
00227 
00228       _num_background = num_absences;
00229     }
00230     else {
00231 
00232       Log::instance()->warn( "No absence points provided. Generating 10000 background points.\n" );
00233       _num_background = 10000;
00234     }
00235   }
00236   else {
00237 
00238     if ( ! getParameter( BACKGROUND_ID, &_num_background ) ) {
00239 
00240       Log::instance()->warn( "Parameter '" BACKGROUND_ID "' unspecified. Using default value (10000).\n");
00241 
00242       _num_background = 10000;
00243     }
00244 
00245     if ( _num_background <= 0 ) {
00246   
00247       Log::instance()->warn( "Parameter '" BACKGROUND_ID "' must be greater than zero.\n" );
00248       return 0;
00249     }
00250   }
00251 
00252   OccurrencesPtr presences = _samp->getPresences();
00253 
00254   _background = new OccurrencesImpl( presences->name(), presences->coordSystem() );
00255 
00256   if ( use_absences_as_background && num_absences >=0 ) {
00257 
00258     _background->appendFrom( _samp->getAbsences() );
00259   }
00260   else {
00261 
00262     // Generate random background points
00263     Log::instance()->info( "Generating random background points.\n" );
00264 
00265     for ( int i = 0; i < _num_background; ++i ) {
00266 
00267       OccurrencePtr oc = _samp->getPseudoAbsence();
00268       _background->insert( oc ); 
00269     }
00270   }
00271 
00272   return 1;
00273 }
00274 
00275 
00276 /***************/
00277 /*** iterate ***/
00278 int
00279 VirtualNicheGenerator::iterate()
00280 {
00281   Log::instance()->info( "Generating virtual niche.\n" );
00282 
00283   // Mean of the normal distribution is the environmental value on the first point
00284   _mean = _samp->getPresence(0)->environment();
00285 
00286   EnvironmentPtr env = _samp->getEnvironment();
00287 
00288   // Minimum and maximum values for each environmental variable for the whole layer
00289   env->getExtremes(&_minimum, &_maximum);
00290 
00291   // Estimate standard deviation in the whole region of interest using background pts
00292   Sample background_std = Sample(_mean.size(), 0.0);
00293   Sample background_mean = Sample(_mean.size(), 0.0);
00294 
00295   OccurrencesImpl::const_iterator oc = _background->begin();
00296   OccurrencesImpl::const_iterator end = _background->end();
00297 
00298   // Compute mean
00299   while ( oc != end ) {
00300 
00301     Sample tmp( (*oc)->environment() );
00302     background_mean += tmp;
00303     ++oc;
00304   }
00305   background_mean /= Scalar( _num_background );
00306 
00307   oc = _background->begin();
00308   end = _background->end();
00309 
00310   // Compute variance
00311   while ( oc != end ) {
00312 
00313     Sample tmp( (*oc)->environment() );
00314     tmp -= background_mean;
00315     tmp *= tmp;
00316     background_std += tmp;
00317     ++oc;
00318   }
00319 
00320   Scalar npts = Scalar( _num_background - 1 );
00321 
00322   // Now divide and root to get deviation
00323   background_std /= npts;
00324   background_std.sqrt();
00325 
00326   // Get a random standard deviation for each variable for the niche function
00327   _std = _mean; // just initialize the sample
00328   Sample max_pdf_val = Sample(_mean.size(), 1.0); // just initialize the sample
00329 
00330   Random random;
00331 
00332   for (int i = 0; i < _samp->numIndependent(); ++i) {
00333 
00334     // Random standard deviation
00335     _std[i] = random(0.0, background_std[i]);
00336 
00337     // Maximum value of the probability density function
00338     max_pdf_val[i] = pdf(_mean[i], _std[i], _mean[i]);
00339   }
00340 
00341   _scale = Sample(_mean.size(), 1.0);
00342   _scale /= max_pdf_val;
00343 
00344   dump();
00345 
00346   _done = true;
00347 
00348   return 1;
00349 }
00350 
00351 
00352 /************/
00353 /*** done ***/
00354 int
00355 VirtualNicheGenerator::done() const
00356 {
00357   // This is not an iterative algorithm.
00358   return _done;
00359 }
00360 
00361 
00362 /*****************/
00363 /*** get Value ***/
00364 Scalar
00365 VirtualNicheGenerator::getValue( const Sample& x ) const
00366 {
00367   Scalar suitability = 1.0;
00368 
00369   for (unsigned int i=0; i < x.size(); i++) {
00370 
00371     Scalar pdf_value = pdf(_mean[i], _std[i], x[i]);
00372 
00373     suitability *= pdf_value*_scale[i];
00374   }
00375 
00376   if ( _threshold < 1.0 ) {
00377 
00378     return (suitability < _threshold) ? 0.0 : 1.0;
00379   }
00380 
00381   return suitability;
00382 }
00383 
00384 
00385 /***********************/
00386 /*** get Convergence ***/
00387 int
00388 VirtualNicheGenerator::getConvergence( Scalar * const val ) const
00389 {
00390   *val = 1.0;
00391   return 1;
00392 }
00393 
00394 
00395 /****************************************************************/
00396 /****************** configuration *******************************/
00397 void
00398 VirtualNicheGenerator::_getConfiguration( ConfigurationPtr& config ) const
00399 {
00400   if ( !_done )
00401     return;
00402 
00403   ConfigurationPtr model_config( new ConfigurationImpl("VirtualNiche") );
00404   config->addSubsection( model_config );
00405 
00406   model_config->addNameValue( "Minimum"  , _minimum );
00407   model_config->addNameValue( "Maximum"  , _maximum );
00408   model_config->addNameValue( "Mean"     , _mean );
00409   model_config->addNameValue( "Std"      , _std );
00410   model_config->addNameValue( "Scale"    , _scale );
00411   model_config->addNameValue( "Threshold", _threshold );
00412 }
00413 
00414 void
00415 VirtualNicheGenerator::_setConfiguration( const ConstConfigurationPtr& config )
00416 {
00417   ConstConfigurationPtr model_config = config->getSubsection("VirtualNiche");
00418 
00419   if (!model_config)
00420     return;
00421 
00422   _done = true;
00423 
00424   _minimum   = model_config->getAttributeAsSample( "Minimum" );
00425   _maximum   = model_config->getAttributeAsSample( "Maximum" );
00426   _mean      = model_config->getAttributeAsSample( "Mean" );
00427   _std       = model_config->getAttributeAsSample( "Std" );
00428   _scale     = model_config->getAttributeAsSample( "Scale" );
00429   _threshold = model_config->getAttributeAsDouble( "Threshold", 1.0 );
00430 
00431   return;
00432 }
00433 
00434 /************/
00435 /*** dump ***/
00436 void
00437 VirtualNicheGenerator::dump()
00438 {
00439   Log::instance()->info( "Result for %d dimensions (variables)\n", _minimum.size() );
00440 
00441   for ( unsigned int i = 0; i < _minimum.size(); i++ ) {
00442 
00443     Log::instance()->info( "Variable %02d:\n", i );
00444     Log::instance()->info( " Minimum  : %f\n", _minimum[i] );
00445     Log::instance()->info( " Mean     : %f\n", _mean[i] );
00446     Log::instance()->info( " Maximum  : %f\n", _maximum[i] );
00447     Log::instance()->info( " Std      : %f\n", _std[i] );
00448   }
00449 }
00450 
00451 /***********/
00452 /*** pdf ***/
00453 Scalar
00454 VirtualNicheGenerator::pdf(Scalar mean, Scalar std, Scalar val) const
00455 {
00456   return (1.0/std*(sqrt(2.0*PI)))*exp(-0.5*pow((val-mean)/std, 2));
00457 }
00458 
00459