openModeller
Version 1.4.0
|
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