openModeller  Version 1.5.0
aquamaps.cpp
Go to the documentation of this file.
1 
28 #include "aquamaps.hh"
29 
33 
34 #include <string.h>
35 #include <stdio.h>
36 #include <math.h>
37 #include <sstream>
38 #include <fstream>
39 #include <sqlite3.h>
40 
41 // Algorithm is included for std::min and std::max.
42 #include <algorithm>
43 
44 using namespace std;
45 
46 
47 /****************************************************************/
48 /********************** Algorithm's Metadata ********************/
49 
50 #define NUM_PARAM 7
51 
52 /*************************************/
53 /*** Algorithm parameters metadata ***/
54 
55 #define PARAM_USE_SURFACE_LAYERS "UseSurfaceLayers"
56 #define PARAM_USE_DEPTH_RANGE "UseDepthRange"
57 #define PARAM_USE_ICE_CONCENTRATION "UseIceConcentration"
58 #define PARAM_USE_DISTANCE_TO_LAND "UseDistanceToLand"
59 #define PARAM_USE_PRIMARY_PRODUCTION "UsePrimaryProduction"
60 #define PARAM_USE_SALINITY "UseSalinity"
61 #define PARAM_USE_TEMPERATURE "UseTemperature"
62 
63 static AlgParamMetadata parameters[NUM_PARAM] = { // Parameters
64  {
66  "Use surface layers (only for temperature and salinity)", // Name
67  Integer, // Type
68  "Use surface layers (1=yes, 0=no, -1=let the algorithm decide)", // Overview
69  "Use surface layers (1=yes, 0=no, -1=let the algorithm decide). By default (-1), aquamaps will try to find the species' depth range in its internal database. If the minimum depth is equals or less than 200m, then aquamaps will use sea surface layers for temperature and salinity. Otherwise it will use bottom layers. This parameter can be used to force aquamaps to use surface or bottom layers.", // Description
70  1, // Not zero if the parameter has lower limit
71  -1, // Parameter's lower limit
72  1, // Not zero if the parameter has upper limit
73  1, // Parameter's upper limit
74  "-1" // Parameter's typical (default) value
75  },
76  {
78  "Use depth range", // Name
79  Integer, // Type
80  "Use depth range when calculating probabilities", // Overview
81  "Use depth range provided by experts (if available) when calculating probabilities", // Description
82  1, // Not zero if the parameter has lower limit
83  0, // Parameter's lower limit
84  1, // Not zero if the parameter has upper limit
85  1, // Parameter's upper limit
86  "1" // Parameter's typical (default) value
87  },
88  {
90  "Use ice concentration", // Name
91  Integer, // Type
92  "Use ice concentration envelope when calculating probabilities", // Overview
93  "Use ice concentration when calculating probabilities", // Description
94  1, // Not zero if the parameter has lower limit
95  0, // Parameter's lower limit
96  1, // Not zero if the parameter has upper limit
97  1, // Parameter's upper limit
98  "1" // Parameter's typical (default) value
99  },
100  {
102  "Use distance to land", // Name
103  Integer, // Type
104  "Use distance to land envelope when calculating probabilities", // Overview
105  "Use distance to land envelope when calculating probabilities", // Description
106  1, // Not zero if the parameter has lower limit
107  0, // Parameter's lower limit
108  1, // Not zero if the parameter has upper limit
109  1, // Parameter's upper limit
110  "0" // Parameter's typical (default) value
111  },
112  {
114  "Use primary production", // Name
115  Integer, // Type
116  "Use primary production envelope when calculating probabilities", // Overview
117  "Use primary production envelope when calculating probabilities", // Description
118  1, // Not zero if the parameter has lower limit
119  0, // Parameter's lower limit
120  1, // Not zero if the parameter has upper limit
121  1, // Parameter's upper limit
122  "1" // Parameter's typical (default) value
123  },
124  {
125  PARAM_USE_SALINITY, // Id
126  "Use salinity", // Name
127  Integer, // Type
128  "Use salinity envelope when calculating probabilities", // Overview
129  "Use salinity envelope when calculating probabilities", // Description
130  1, // Not zero if the parameter has lower limit
131  0, // Parameter's lower limit
132  1, // Not zero if the parameter has upper limit
133  1, // Parameter's upper limit
134  "1" // Parameter's typical (default) value
135  },
136  {
137  PARAM_USE_TEMPERATURE, // Id
138  "Use temperature", // Name
139  Integer, // Type
140  "Use temperature envelope when calculating probabilities", // Overview
141  "Use temperature envelope when calculating probabilities", // Description
142  1, // Not zero if the parameter has lower limit
143  0, // Parameter's lower limit
144  1, // Not zero if the parameter has upper limit
145  1, // Parameter's upper limit
146  "1" // Parameter's typical (default) value
147  },
148 };
149 
150 
151 /************************************/
152 /*** Algorithm's general metadata ***/
153 
155 
156  "AQUAMAPS", // Id.
157  "AquaMaps (beta version)", // Name.
158  "0.3", // Version.
159 
160  // Overview
161  "Environmental envelope modelling algorithm for marine organisms. \
162 Needs 9 predefined layers (see detailed description) to calculate the \
163 preferred and accepted envelopes, and also needs a scientific name (genus \
164 plus species) labeling each occurrence group." ,
165 
166  // Description.
167  "AquaMaps is a niche modelling tool developed as part of the Incofish \
168 project and particularly tailored towards modelling marine organisms distribution.\n \
169 The basic idea follows the environmental envelope type modelling approach, \
170 where each variable has an associated preferred range and a broader accepted \
171 range. Within the preferred range the probabilty of presence is 1, between the \
172 preferred range and the acceptable range the probability varies from 1 to 0 \
173 (linear decay), and outside the accepted range the probability is 0. The \
174 overall probability is calculated by multiplying all individual probabilities.\n\
175 This algorithm differs from other traditional ones since it requires a specific \
176 set of layers to work, which should also be in this order: maximum depth in meters, \
177 minimum depth in meters, mean annual sea ice concentration, mean annual distance to \
178 land in kilometers, mean annual primary production (chlorophyll A, measured in \
179 mgC per square meter per day), mean annual bottom salinity in psu, mean annual \
180 surface salinity in psu, mean annual bottom temperature in celsius, mean annual \
181 surface temperature in celsius. These layers can be downloaded from: \n\
182 http://openmodeller.cria.org.br/download/marine2.zip \n\
183 Preferred ranges are usually calculated based on percentiles 10th and 90th. \
184 They are further adjusted using interquartile values but also ensuring a minimum \
185 envelope size based on pre-defined values. Under certain circumstances, AquaMaps can \
186 make use of expert information to define the envelopes. This can happen for mammals \
187 (any envelope) or for fishes (depth range envelope). Expert information comes from \
188 FishBase and is stored in a local SQLite database (aquamaps.db) accessed by the \
189 algorithm. To find information in the database, all occurrences provided to \
190 openModeller must be labeled with the scientific name (only genus and species). \
191 Matches are exact, using case-sensitive equals operation. In this version, the \
192 internal database contains information for more then 7000 marine species.",
193 
194  "Kaschner, K., J. S. Ready, E. Agbayani, J. Rius, K. Kesner-Reyes, P. D. Eastwood, A. B. South, S. O. Kullander, T. Rees, C. H. Close, R. Watson, D. Pauly, and R. Froese", // Authors
195 
196  // Bibliography.
197  "Kaschner, K., J. S. Ready, E. Agbayani, J. Rius, K. Kesner-Reyes, P. D. Eastwood, A. B. South, S. O. Kullander, T. Rees, C. H. Close, R. Watson, D. Pauly, and R. Froese. 2007 AquaMaps: Predicted range maps for aquatic species. World wide web electronic publication, www.aquamaps.org, Version 12/2007.",
198 
199  "Renato De Giovanni", // Code author.
200  "renato [at] cria dot org dot br", // Code author's contact.
201 
202  0, // Does not accept categorical data.
203  0, // Does not need (pseudo)absence points.
204 
205  NUM_PARAM, // Algorithm's parameters.
206  parameters
207 };
208 
209 
210 
211 /****************************************************************/
212 /****************** Algorithm's factory function ****************/
213 
214 OM_ALG_DLL_EXPORT
217 {
218  return new AquaMaps();
219 }
220 
221 OM_ALG_DLL_EXPORT
222 AlgMetadata const *
224 {
225  return &metadata;
226 }
227 
228 
229 /****************************************************************/
230 /**************************** AquaMaps **************************/
231 
232 /*******************/
233 /*** constructor ***/
234 
237  _use_layer( NULL ),
238  _lower_limit( 7, SURFACE_LOWER_LIMIT ),
239  _upper_limit( 7, SURFACE_UPPER_LIMIT ),
240  _inner_size( 7, INNER_SIZE ),
241  _minimum(),
242  _maximum(),
243  _pref_minimum(),
244  _pref_maximum(),
245  _pelagic(-1),
246  _use_surface_layers(-1),
247  _has_expert_range( NULL ),
248  _progress( 0.0 )
249 {
250 }
251 
252 /******************/
253 /*** destructor ***/
254 
256 {
257  if ( _use_layer ) {
258 
259  delete[] _use_layer;
260  }
261 
262  if ( _has_expert_range ) {
263 
264  delete[] _has_expert_range;
265  }
266 }
267 
268 /******************/
269 /*** initialize ***/
270 int
272 {
273  _has_expert_range = new bool[7];
274 
275  // Initialize array
276  for ( int i = 0; i < 7; ++i ) {
277 
278  _has_expert_range[i] = false;
279  }
280 
281  // Parameter UseSurfaceLayers
283 
284  _use_surface_layers = -1;
285  }
286 
287  _use_layer = new int[7];
288 
289  // Parameter UseDepthRange
291 
292  return 0;
293  }
294  else {
295 
296  _use_layer[MINDEPTH] = _use_layer[MAXDEPTH]; // just repeat the value
297  }
298 
299  // Parameter UseIceConcentration
301 
302  return 0;
303  }
304 
305  // Parameter UseDistanceToLand
307 
308  return 0;
309  }
310 
311  // Parameter UsePrimaryProduction
313 
314  return 0;
315  }
316 
317  // Parameter UseSalinity
319 
320  return 0;
321  }
322 
323  // Parameter UseTemperature
325 
326  return 0;
327  }
328 
329  // Number of independent variables.
330  int dim = _samp->numIndependent();
331  Log::instance()->info( "Reading %d-dimensional occurrence points.\n", dim );
332 
333  // Check the number of layers.
334  if ( dim != 9 ) {
335 
336  Log::instance()->error( "AquaMaps needs precisely 9 layers to work, and they should be in this order: maximum depth in meters, minimum depth in meters, mean annual sea ice concentration, mean annual distance to land in Kilometers, mean annual primary production (chlorophyll A), mean annual sea bottom salinity in psu,, mean annual sea surface salinity in psu, mean annual sea bottom temperature in Celsius, mean annual sea surface temperature in Celsius.\n" );
337  return 0;
338  }
339 
340  // Remove duplicates accross geography
341  _samp->spatiallyUnique();
342 
343  // Check the number of sampled points.
344  int npnt = _samp->numPresence();
345 
346  if ( npnt < 5 ) {
347 
348  Log::instance()->error( "AquaMaps needs at least 5 points inside the mask!\n" );
349  return 0;
350  }
351 
352  return 1;
353 }
354 
355 
356 /***************/
357 /*** iterate ***/
358 int
360 {
361  Log::instance()->info( "Using %d points to find AquaMaps envelopes.\n", _samp->numPresence() );
362 
363  _calculateEnvelopes( _samp->getPresences() );
364 
365  return 1;
366 }
367 
368 
369 /***********************/
370 /*** get Convergence ***/
371 int
372 AquaMaps::getConvergence( Scalar * const val ) const
373 {
374  *val = 1.0;
375  return 1;
376 }
377 
378 
379 /********************/
380 /*** get Progress ***/
381 float
383 {
384  return _progress;
385 }
386 
387 
388 /************/
389 /*** done ***/
390 int
392 {
393  // This is not an iterative algorithm.
394  return ( _progress > 0.99 ) ? 1 : 0;
395 }
396 
397 
398 /*******************************/
399 /*** get and check parameter ***/
400 int
401 AquaMaps::_getAndCheckParameter( std::string const &name, int * value )
402 {
403  // Parameter UseSalinity
404  if ( ! getParameter( name, value ) ) {
405 
406  Log::instance()->error( "Parameter '%s' not passed.\n", name.c_str() );
407  return 0;
408  }
409  // Check if value is 0 or 1
410  if ( *value != 0 && *value != 1 ) {
411 
412  Log::instance()->error( "Parameter '%s' not set properly. It must be 0 or 1.\n", name.c_str() );
413  return 0;
414  }
415 
416  return 1;
417 }
418 
419 
420 /***************************/
421 /*** calculate envelopes ***/
422 void
424 {
425  Log::instance()->debug("Species is: %s\n", occs->label());
426  Log::instance()->debug("Layers are:\n");
427  Log::instance()->debug("0 = Maximum depth\n");
428  Log::instance()->debug("1 = Minimum depth\n");
429  Log::instance()->debug("2 = Ice concentration\n");
430  Log::instance()->debug("3 = Distance to land\n");
431  Log::instance()->debug("4 = Primary production (chlorophyll A)\n");
432  Log::instance()->debug("5 = Salinity bottom\n");
433  Log::instance()->debug("6 = Salinity surface\n");
434  Log::instance()->debug("7 = Temperature bottom\n");
435  Log::instance()->debug("8 = Temperature surface\n");
436 
437  // Compute min, pref_min, pref_max and max
438  OccurrencesImpl::const_iterator oc = occs->begin();
439  OccurrencesImpl::const_iterator ocEnd = occs->end();
440 
441  // Intialize _minimum, _maximum, _pref_minimum, and _pref_maximum
442  // to the values of the first point, and increment
443  // to get it out of the next loop.
444  Sample const & sample = (*oc)->environment();
445  _minimum = sample;
446  _pref_minimum = sample;
447  _pref_maximum = sample;
448  _maximum = sample;
449  Sample mean = sample;
450  ++oc;
451 
452  // Load default min/max
453  while ( oc != ocEnd ) {
454 
455  Sample const& sample = (*oc)->environment();
456 
457  // Default min/max will be the actual min/max values
458  _minimum &= sample;
459  _maximum |= sample;
460 
461  mean += sample;
462 
463  ++oc;
464  }
465 
466  mean /= occs->numOccurrences();
467 
468  int num_layers = _minimum.size();
469 
470  _progress = 1.0f/num_layers; // this is arbitrary
471 
472  // Default values for depth ranges
475 
476  // Try to get expert information about depth range from database
477  _readSpeciesData( occs->label() );
478 
479  if ( _use_surface_layers == -1 ) {
480 
482  }
483 
484  if ( ! _use_surface_layers ) {
485 
486  Log::instance()->info("Using bottom layers.\n");
487 
488  for ( int i = 0; i < 7; ++i ) {
489 
492  }
493  }
494  else {
495 
496  Log::instance()->info("Using surface layers.\n");
497  }
498 
499  _progress = 2.0f/num_layers; // this is arbitrary
500 
501  // Get matrix data structure so that we can sort values for each layer
502  std::vector<ScalarVector> matrix = occs->getEnvironmentMatrix();
503 
504  Scalar nodata = -1.0;
505 
506  // For each layer (except min/max depth), calculate the percentiles and set
507  // default values for the prefered min/max
508  ScalarVector::iterator lStart, lEnd;
509 
510  for ( int j = 2; j < num_layers; j++ ) {
511 
512  if ( _use_surface_layers ) {
513 
514  // Ignore bottom layers
515  if ( j == 5 || j == 7 ) {
516 
517  _progress = (float)(j+1)/num_layers;
518 
519  _minimum[j] = _minimum[j] = _pref_minimum[j] = _pref_minimum[j] = nodata;
520 
521  continue;
522  }
523  }
524  else {
525 
526  // Ignore surface layers
527  if ( j == 6 || j == 8 ) {
528 
529  _progress = (float)(j+1)/num_layers;
530 
531  _minimum[j] = _minimum[j] = _pref_minimum[j] = _pref_minimum[j] = nodata;
532 
533  continue;
534  }
535  }
536 
537  if ( ( j == 5 || j == 6 ) && _has_expert_range[SALINITY] ) {
538 
539  _progress = (float)(j+1)/num_layers;
540 
541  continue;
542  }
543 
544  if ( ( j == 7 || j == 8 ) && _has_expert_range[TEMPERATURE] ) {
545 
546  _progress = (float)(j+1)/num_layers;
547 
548  continue;
549  }
550 
551  Log::instance()->debug("--------------------------------\n", j);
552  Log::instance()->debug("Calculating envelope for layer %d\n", j);
553  Log::instance()->debug("--------------------------------\n", j);
554 
555  // 0 = Maximum depth
556  // 1 = Minimum depth
557  // 2 = Ice concentration
558  // 3 = Distance to land
559  // 4 = Primary production (chlorophyll A)
560  // 5 = Salinity bottom
561  // 6 = Salinity surface
562  // 7 = Temperature bottom
563  // 8 = Temperature surface
564 
565  lStart = matrix[j].begin();
566  lEnd = matrix[j].end();
567  sort( lStart, lEnd );
568 
569  int numOccurrences = occs->numOccurrences();
570 
571  // Just for debugging
572  //ostringstream debug;
573  //debug << "row -->";
574  //for ( int w = 0; w < numOccurrences; w++ ) {
575 
576  //debug << " [" << j << "," << w << "]=" << matrix[j][w];
577  //}
578  //debug << "\n";
579  //Log::instance()->debug( debug.str().c_str() );
580 
581  // Calculate percentiles
582  Scalar v10, v25, v75, v90;
583 
584  _percentile( &v10, numOccurrences, 0.10, &matrix, j );
585  _percentile( &v25, numOccurrences, 0.25, &matrix, j );
586  _percentile( &v75, numOccurrences, 0.75, &matrix, j );
587  _percentile( &v90, numOccurrences, 0.90, &matrix, j );
588 
589  Log::instance()->debug("10th percentile: %f\n", v10);
590  Log::instance()->debug("25th percentile: %f\n", v25);
591  Log::instance()->debug("75th percentile: %f\n", v75);
592  Log::instance()->debug("90th percentile: %f\n", v90);
593 
594  Scalar interquartile = fabs( v25 - v75 );
595 
596  Log::instance()->debug("Interquartile: %f\n", interquartile);
597 
598  Scalar adjmin = v25 - ( 1.5 * interquartile );
599  Scalar adjmax = v75 + ( 1.5 * interquartile );
600 
601  Log::instance()->debug("Adjmin: %f\n", adjmin);
602  Log::instance()->debug("Adjmax: %f\n", adjmax);
603 
604  _pref_minimum[j] = v10;
605  _pref_maximum[j] = v90;
606 
607  Log::instance()->debug("_Before adjustments_\n");
608  Log::instance()->debug("min: %f\n", _minimum[j]);
609  Log::instance()->debug("prefmin: %f\n", _pref_minimum[j]);
610  Log::instance()->debug("prefmax: %f\n", _pref_maximum[j]);
611  Log::instance()->debug("max: %f\n", _maximum[j]);
612 
613  // Make the interquartile adjusting and ensure the envelope sizes
614  // for all variables except ice concentration
615  if ( j > 2 ) {
616 
617  _adjustInterquartile( j, adjmin, adjmax );
618  _ensureEnvelopeSize( j );
619  }
620  else {
621 
622  if ( _minimum[j] == 0.0) {
623 
624  _minimum[j] = mean[j] - 1.0; // black magic copied from original vb code
625  }
626  }
627 
628  Log::instance()->debug("_After adjustments_\n");
629  Log::instance()->debug("min: %f\n", _minimum[j]);
630  Log::instance()->debug("prefmin: %f\n", _pref_minimum[j]);
631  Log::instance()->debug("prefmax: %f\n", _pref_maximum[j]);
632  Log::instance()->debug("max: %f\n", _maximum[j]);
633 
634  _progress = (float)(j+1)/num_layers;
635  }
636 }
637 
638 
639 /******************/
640 /*** percentile ***/
641 void
642 AquaMaps::_percentile( Scalar *result, int n, double percent, std::vector<ScalarVector> *matrix, int layerIndex )
643 {
644  int iPrev, iNext;
645 
646  Scalar k = n * percent;
647 
648  iPrev = (int) floor( k );
649  iNext = (int) ceil( k );
650 
651  // Subtract 1 from the result since arrays begin with position 0
652  --iPrev;
653  --iNext;
654 
655  if ( iPrev == iNext ) {
656 
657  // If k is an integer, use the mean between the two positions
658  *result = ( (*matrix)[layerIndex][iPrev] + (*matrix)[layerIndex][iNext] ) / 2;
659  }
660  else {
661 
662  // If k is not an integer, use the next as a reference
663  *result = (*matrix)[layerIndex][iNext];
664  }
665 }
666 
667 
668 /***********************/
669 /*** read depth data ***/
670 void
671 AquaMaps::_readSpeciesData( const char *species )
672 {
673  string dbfullname = omDataPath();
674 
675 #ifndef WIN32
676  dbfullname.append( "/" );
677 #else
678  dbfullname.append( "\\" );
679 #endif
680 
681  dbfullname.append( "aquamaps.db" );
682 
683  Log::instance()->debug( "Trying database: %s\n", dbfullname.c_str() );
684 
685  ifstream dbfile( dbfullname.c_str(), ios::in );
686 
687  if ( ! dbfile ) {
688 
689  Log::instance()->warn( "Could not find internal database with species data.\n" );
690  return;
691  }
692 
693  Log::instance()->info( "Using internal database with species data.\n" );
694 
695  sqlite3 *db;
696 
697  int rc = sqlite3_open( dbfullname.c_str(), &db);
698 
699  if ( rc ) {
700 
701  // This will likely never happen since on open, sqlite creates the
702  // database if it does not exist.
703  Log::instance()->warn( "Could not open internal database: %s\n", sqlite3_errmsg( db ) );
704  sqlite3_close( db );
705  return;
706  }
707 
708  // Prepare the sql statement
709  const char *pzTail;
710 
711  sqlite3_stmt *ppStmt;
712 
713  char* sql = sqlite3_mprintf( "select pelagic, provider, depthmin, depthmax, depthprefmin, depthprefmax, iceconmin, iceconmax, iceconprefmin, iceconprefmax, landdistmin, landdistmax, landdistprefmin, landdistprefmax, primprodmin, primprodmax, primprodprefmin, primprodprefmax, salinitymin, salinitymax, salinityprefmin, salinityprefmax, tempmin, tempmax, tempprefmin, tempprefmax from spinfo where species = '%q'", species );
714 
715  rc = sqlite3_prepare( db, sql, strlen( sql ), &ppStmt, &pzTail );
716 
717  if ( rc == SQLITE_OK ) {
718 
719  // Fecth data
720  int result_code = sqlite3_step( ppStmt );
721 
722  if ( result_code == SQLITE_ROW ) {
723 
724  int pelagic = sqlite3_column_int( ppStmt, 0 );
725  const char * provider = (char *)sqlite3_column_text( ppStmt, 1 );
726  double depthmin = sqlite3_column_double( ppStmt, 2 );
727  double depthmax = sqlite3_column_double( ppStmt, 3 );
728  double depthprefmin = sqlite3_column_double( ppStmt, 4 );
729  double depthprefmax = sqlite3_column_double( ppStmt, 5 );
730 
731  _pelagic = pelagic;
732 
733  // Repeat the information for both min and max depth for symmetry
734  _minimum[MAXDEPTH] = depthmin;
735  _minimum[MINDEPTH] = depthmin;
736  _maximum[MAXDEPTH] = depthmax;
737  _maximum[MINDEPTH] = depthmax;
738  _pref_minimum[MAXDEPTH] = depthprefmin;
739  _pref_minimum[MINDEPTH] = depthprefmin;
740  _pref_maximum[MAXDEPTH] = depthprefmax;
741  _pref_maximum[MINDEPTH] = depthprefmax;
742 
743  Log::instance()->debug("Values from expert database:\n");
744  Log::instance()->debug("provider: %s\n", provider);
745  Log::instance()->debug("pelagic: %i\n", pelagic);
746  Log::instance()->debug("depthmin: %f\n", depthmin);
747  Log::instance()->debug("depthmax: %f\n", depthmax);
748  Log::instance()->debug("depthprefmin: %f\n", depthprefmin);
749  Log::instance()->debug("depthprefmax: %f\n", depthprefmax);
750 
751  if ( sqlite3_column_bytes( ppStmt, 1 ) ) {
752 
753  string prov_code( provider );
754 
755  if ( prov_code == "MM" ) {
756 
757  Log::instance()->info( "Looks like a mammal\n" );
758 
759  for ( int i = ICE_CONCENTRATION; i < TEMPERATURE + 1; ++i ) {
760 
761  _has_expert_range[i] = _hasExpertRange( ppStmt, i );
762 
763  if ( _has_expert_range[i] ) {
764 
765  Log::instance()->info( "Found expert range for variable %s\n", NAME[i].c_str() );
766 
767  Log::instance()->debug("min: %f\n", _minimum[i]);
768  Log::instance()->debug("max: %f\n", _maximum[i]);
769  Log::instance()->debug("prefmin: %f\n", _pref_minimum[i]);
770  Log::instance()->debug("prefmax: %f\n", _pref_maximum[i]);
771  }
772  }
773  }
774  }
775  }
776  else if ( result_code == SQLITE_DONE ) {
777 
778  Log::instance()->warn( "'%s' not found in species database\n", species );
779  }
780  else {
781 
782  Log::instance()->warn( "Could not fetch data from species database: %s\n", sqlite3_errmsg( db ) );
783  }
784  }
785  else {
786 
787  Log::instance()->warn( "Could not prepare SQL statement to query species database: %s\n", sqlite3_errmsg( db ) );
788  }
789 
790  // free memory
791  sqlite3_free( sql );
792 
793  // close the statement
794  sqlite3_finalize( ppStmt );
795 
796  // close the database
797  sqlite3_close( db );
798 }
799 
800 
801 /****************************/
802 /*** ensure envelope size ***/
803 bool
804 AquaMaps::_hasExpertRange( sqlite3_stmt * stmt, int varIndex )
805 {
806  int index;
807 
808  if ( varIndex == ICE_CONCENTRATION ) {
809 
810  index = 6;
811  }
812  else if ( varIndex == DISTANCE_TO_LAND ) {
813 
814  index = 10;
815  }
816  else if ( varIndex == PRIMARY_PRODUCTION ) {
817 
818  index = 14;
819  }
820  else if ( varIndex == SALINITY ) {
821 
822  index = 18;
823  }
824  else if ( varIndex == TEMPERATURE ) {
825 
826  index = 22;
827  }
828  else {
829 
830  return false;
831  }
832 
833  if ( ! sqlite3_column_bytes( stmt, index ) ) {
834 
835  return false;
836  }
837 
838  double value = sqlite3_column_double( stmt, index );
839 
840  _minimum[varIndex] = value;
841 
842  ++index;
843 
844  if ( ! sqlite3_column_bytes( stmt, index ) ) {
845 
846  return false;
847  }
848 
849  value = sqlite3_column_double( stmt, index );
850 
851  _maximum[varIndex] = value;
852 
853  ++index;
854 
855  if ( ! sqlite3_column_bytes( stmt, index ) ) {
856 
857  return false;
858  }
859 
860  value = sqlite3_column_double( stmt, index );
861 
862  _pref_minimum[varIndex] = value;
863 
864  ++index;
865 
866  if ( ! sqlite3_column_bytes( stmt, index ) ) {
867 
868  return false;
869  }
870 
871  value = sqlite3_column_double( stmt, index );
872 
873  _pref_maximum[varIndex] = value;
874 
875  return true;
876 }
877 
878 
879 /****************************/
880 /*** ensure envelope size ***/
881 void
882 AquaMaps::_adjustInterquartile( int layerIndex, Scalar adjmin, Scalar adjmax )
883 {
884  if ( adjmin > _lower_limit[_getRelatedIndex(layerIndex)] && adjmin < _minimum[layerIndex] ) {
885 
886  _minimum[layerIndex] = adjmin;
887  }
888 
889  if ( adjmax < _upper_limit[_getRelatedIndex(layerIndex)] && adjmax > _maximum[layerIndex] ) {
890 
891  _maximum[layerIndex] = adjmax;
892  }
893 }
894 
895 
896 /****************************/
897 /*** ensure envelope size ***/
898 void
900 {
901  Scalar halfSize = _inner_size[_getRelatedIndex(layerIndex)]/2;
902 
903  // Try to ensure that the prefered envelope has the specified size
904  // (but only change if the new values are still within the accepted envelope)
905  if ( _pref_maximum[layerIndex] - _pref_minimum[layerIndex] < _inner_size[_getRelatedIndex(layerIndex)] ) {
906 
907  Scalar center = (_pref_minimum[layerIndex] + _pref_maximum[layerIndex]) / 2;
908 
909  Scalar new_pref_min = center - halfSize;
910 
911  if ( new_pref_min >= _minimum[layerIndex] ) {
912 
913  _pref_minimum[layerIndex] = new_pref_min;
914  }
915 
916  Scalar new_pref_max = center + halfSize;
917 
918  if ( new_pref_max <= _maximum[layerIndex] ) {
919 
920  _pref_maximum[layerIndex] = new_pref_max;
921  }
922  }
923 
924  // Ensure that the distance between the envelopes has half the specified size
925  // (but changes should never exceed the allowed limits!)
926  if ( _pref_minimum[layerIndex] - _minimum[layerIndex] < halfSize ) {
927 
928  Scalar new_min = _pref_minimum[layerIndex] - halfSize;
929 
930  if ( new_min > _lower_limit[_getRelatedIndex(layerIndex)] ) {
931 
932  _minimum[layerIndex] = new_min;
933  }
934  else {
935 
936  _minimum[layerIndex] = _lower_limit[_getRelatedIndex(layerIndex)];
937  }
938  }
939 
940  if ( _maximum[layerIndex] - _pref_maximum[layerIndex] < halfSize ) {
941 
942  Scalar new_max = _pref_maximum[layerIndex] + halfSize;
943 
944  if ( new_max < _upper_limit[_getRelatedIndex(layerIndex)] ) {
945 
946  _maximum[layerIndex] = new_max;
947  }
948  else {
949 
950  _maximum[layerIndex] = _upper_limit[_getRelatedIndex(layerIndex)];
951  }
952  }
953 }
954 
955 
956 /*****************/
957 /*** get Value ***/
958 Scalar
959 AquaMaps::getValue( const Sample& x ) const
960 {
961  // Final probability is the multiplication of all
962  // individual probabilities
963  Scalar prob = 1.0;
964 
965  int num_variables_used = 0;
966 
967  // Depth probability
968 
969  if ( _use_layer[MAXDEPTH] ) { // If user wants to use depth range
970 
971  ++num_variables_used;
972 
973  if ( _maximum[MAXDEPTH] != 9999 ) { // If there is a depth range in the internal database
974 
975  // Probability of occurrence is zero if depth at this point is less
976  // than the minimum depth for the species.
977  // note: using maximum depth layer here
978  if ( x[MAXDEPTH] < _minimum[MAXDEPTH] ) {
979 
980  return 0.0;
981  }
982 
983  // Point is sufficiently deep, but still not enough for the prefered range
984  // note: using maximum depth layer here
985  if ( x[MAXDEPTH] >= _minimum[MAXDEPTH] && x[MAXDEPTH] < _pref_minimum[MAXDEPTH] ) {
986 
987  // Linear decay
988  prob *= (x[MAXDEPTH] - _minimum[MAXDEPTH]) / (_pref_minimum[MAXDEPTH] - _minimum[MAXDEPTH]);
989  }
990  // Point is sufficiently deep for the prefered range
991  // Note: pelagic means "belonging to the upper layers of the open sea". Or in other
992  // words, no need to feed at the bottom of the sea.
993  else if ( _pelagic == 1 ) {
994 
995  // Just keep prob as 1
996  }
997  // Species needs to feed at the bottom of the sea (or there's no data about this)
998  // and point is within the prefered range
999  // note: the inner envelope logic makes use of both minimum and maximum depth layers.
1000  else if ( x[MAXDEPTH] >= _pref_minimum[MAXDEPTH] && x[MINDEPTH] <= _pref_maximum[MINDEPTH] ) {
1001 
1002  // Just keep prob as 1
1003  }
1004  // Species needs to feed at the bottom of the sea (or there's no data about this) and
1005  // point is deeper than the prefered maximum depth but not so deep as the maximum
1006  // note: using minimum depth layer here
1007  else if ( x[MINDEPTH] >= _pref_maximum[MINDEPTH] && x[MINDEPTH] < _maximum[MINDEPTH] ) {
1008 
1009  // Linear decay
1010  prob *= (_maximum[MINDEPTH] - x[MINDEPTH]) / (_maximum[MINDEPTH] - _pref_maximum[MINDEPTH]);
1011  }
1012  // Species needs to feed at the bottom of the sea (or there's no data about this)
1013  // but depth at the point is greater then the maximum accepted depth
1014  else {
1015 
1016  return 0.0;
1017  }
1018  }
1019  else { // If there is no depth range
1020 
1021  // Just keep prob as 1
1022  }
1023  }
1024  else { // If user doesn't want to use depth ranges
1025 
1026  // Just keep prob as 1
1027  }
1028 
1029  // For all layers except min/max depths
1030 
1031  int numLayers = x.size();
1032 
1033  for ( int i = 2; i < numLayers; i++ ) {
1034 
1035  // Ignore layer if user doesn't want to use it
1036  if ( i < 5 ) {
1037 
1038  if ( ! _use_layer[i] ) {
1039 
1040  continue;
1041  }
1042  }
1043  else if ( i < 7 ) {
1044 
1045  if ( ! _use_layer[SALINITY] ) {
1046 
1047  continue;
1048  }
1049  }
1050  else {
1051 
1052  if ( ! _use_layer[TEMPERATURE] ) {
1053 
1054  continue;
1055  }
1056  }
1057 
1058  if ( _use_surface_layers ) {
1059 
1060  // Ignore bottom layers
1061  if ( i == 5 || i == 7 ) {
1062 
1063  continue;
1064  }
1065  }
1066  else
1067  {
1068  // Ignore surface layers
1069  if ( i == 6 || i == 8 ) {
1070 
1071  continue;
1072  }
1073  }
1074 
1075  ++num_variables_used;
1076 
1077  // Probability zero for points outside the envelope
1078  if ( x[i] < _minimum[i] || x[i] > _maximum[i] ) {
1079 
1080  return 0.0;
1081  }
1082 
1083  // Linear decay for points outside the prefered envelope
1084  if ( x[i] < _pref_minimum[i] ) {
1085 
1086  prob *= (x[i] - _minimum[i]) / (_pref_minimum[i] - _minimum[i]);
1087  }
1088  // Linear decay for points outside the prefered envelope
1089  else if ( x[i] > _pref_maximum[i] ) {
1090 
1091  prob *= (_maximum[i] - x[i]) / (_maximum[i] - _pref_maximum[i]);
1092  }
1093  else {
1094 
1095  // No need to check inside preferred envelope - probability is 1 there, so
1096  // it would not change the final value
1097  }
1098  }
1099 
1100  // Return probability product
1101  //return prob;
1102 
1103  // Return geometric mean
1104  return pow( prob, (Scalar)1/num_variables_used );
1105 }
1106 
1107 
1108 /****************************************************************/
1109 /****************** configuration *******************************/
1110 void
1112 {
1113  if ( ! done() ) {
1114 
1115  return;
1116  }
1117 
1118  ConfigurationPtr model_config( new ConfigurationImpl( "AquaMaps" ) );
1119  config->addSubsection( model_config );
1120 
1121  model_config->addNameValue( "UseLayer", _use_layer, 7 );
1122  model_config->addNameValue( "UseSurfaceLayers", _use_surface_layers );
1123  model_config->addNameValue( "Pelagic", _pelagic );
1124  model_config->addNameValue( "Minimum", _minimum );
1125  model_config->addNameValue( "PreferedMinimum", _pref_minimum );
1126  model_config->addNameValue( "PreferedMaximum", _pref_maximum );
1127  model_config->addNameValue( "Maximum", _maximum );
1128 }
1129 
1130 
1131 void
1133 {
1134  ConstConfigurationPtr model_config = config->getSubsection( "AquaMaps", false );
1135 
1136  if ( ! model_config ) {
1137 
1138  return;
1139  }
1140 
1141  try {
1142 
1143  int size;
1144 
1145  model_config->getAttributeAsIntArray( "UseLayer", &_use_layer, &size );
1146 
1147  _use_surface_layers = model_config->getAttributeAsInt( "UseSurfaceLayers", -1 );
1148  }
1149  catch ( AttributeNotFound& exception ) {
1150 
1151  Log::instance()->error( "Could not find attribute '%s' in serialized model. You may be trying to load a model that was generated with an older version (< 0.2) of this algorithm.\n", exception.getName().c_str() );
1152 
1153  return;
1154  }
1155 
1156  _pelagic = model_config->getAttributeAsInt( "Pelagic", -1 );
1157  _minimum = model_config->getAttributeAsSample( "Minimum" );
1158  _pref_minimum = model_config->getAttributeAsSample( "PreferedMinimum" );
1159  _pref_maximum = model_config->getAttributeAsSample( "PreferedMaximum" );
1160  _maximum = model_config->getAttributeAsSample( "Maximum" );
1161 
1162  _progress = 1.0;
1163 
1164  return;
1165 }
1166 
1167 
1168 /********************/
1169 /*** log Envelope ***/
1170 void
1172 {
1173  Log::instance()->info( "Envelope with %d dimensions (variables).\n\n", _minimum.size() );
1174 
1175  for ( unsigned int i = 0; i < _minimum.size(); i++ ) {
1176 
1177  Log::instance()->info( "Variable %02d:", i );
1178  Log::instance()->info( " Minimum : %f\n", _minimum[i] );
1179  Log::instance()->info( " Prefered Minimum: %f\n", _pref_minimum[i] );
1180  Log::instance()->info( " Prefered Maximum: %f\n", _pref_maximum[i] );
1181  Log::instance()->info( " Maximum : %f\n", _maximum[i] );
1182  Log::instance()->info( "\n" );
1183  }
1184 }
1185 
1186 int
1188 {
1189  if ( index == 8 ) {
1190 
1191  return index - 2;
1192  }
1193  else if ( index > 5 ) {
1194 
1195  return index - 1;
1196  }
1197 
1198  return index;
1199 }
std::string omDataPath(std::string dir)
OM_ALG_DLL_EXPORT AlgMetadata const * algorithmMetadata()
Definition: aquamaps.cpp:223
Sample _upper_limit
Definition: aquamaps.hh:249
void warn(const char *format,...)
'Warn' level.
Definition: Log.cpp:273
void _logEnvelope()
Definition: aquamaps.cpp:1171
const int TEMPERATURE
Definition: aquamaps.hh:177
const int MAXDEPTH
Definition: aquamaps.hh:171
Sample _maximum
Definition: aquamaps.hh:258
int * _use_layer
Definition: aquamaps.hh:243
double Scalar
Type of map values.
Definition: om_defs.hh:39
Sample _minimum
Definition: aquamaps.hh:255
const std::string & getName() const
Definition: Exceptions.hh:40
void _calculateEnvelopes(const OccurrencesPtr &)
Definition: aquamaps.cpp:423
bool * _has_expert_range
Definition: aquamaps.hh:277
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: aquamaps.cpp:959
virtual void _setConfiguration(const ConstConfigurationPtr &)
Definition: aquamaps.cpp:1132
OM_ALG_DLL_EXPORT AlgorithmImpl * algorithmFactory()
Definition: aquamaps.cpp:216
const Scalar INNER_SIZE[7]
Definition: aquamaps.hh:153
void error(const char *format,...)
'Error' level.
Definition: Log.cpp:290
Sample _pref_minimum
Definition: aquamaps.hh:261
int getParameter(std::string const &name, std::string *value)
#define PARAM_USE_DEPTH_RANGE
Definition: aquamaps.cpp:56
#define PARAM_USE_PRIMARY_PRODUCTION
Definition: aquamaps.cpp:59
void _adjustInterquartile(int layerIndex, Scalar adjmin, Scalar adjmax)
Definition: aquamaps.cpp:882
int done() const
Definition: aquamaps.cpp:391
Sample _inner_size
Definition: aquamaps.hh:252
const int ICE_CONCENTRATION
Definition: aquamaps.hh:173
int _getAndCheckParameter(std::string const &name, int *value)
Definition: aquamaps.cpp:401
int _use_surface_layers
Definition: aquamaps.hh:274
const Scalar BOTTOM_UPPER_LIMIT[7]
Definition: aquamaps.hh:145
bool _hasExpertRange(sqlite3_stmt *stmt, int varIndex)
Definition: aquamaps.cpp:804
int initialize()
Definition: aquamaps.cpp:271
Sample _pref_maximum
Definition: aquamaps.hh:264
const int MINDEPTH
Definition: aquamaps.hh:172
#define PARAM_USE_ICE_CONCENTRATION
Definition: aquamaps.cpp:57
float getProgress() const
Definition: aquamaps.cpp:382
const Scalar DEPTH_LIMIT
Definition: aquamaps.hh:83
std::size_t size() const
Definition: Sample.hh:70
#define PARAM_USE_TEMPERATURE
Definition: aquamaps.cpp:61
void _ensureEnvelopeSize(int layerIndex)
Definition: aquamaps.cpp:899
void _readSpeciesData(const char *species)
Definition: aquamaps.cpp:671
#define PARAM_USE_DISTANCE_TO_LAND
Definition: aquamaps.cpp:58
#define NUM_PARAM
Definition: aquamaps.cpp:50
int _pelagic
Definition: aquamaps.hh:269
SamplerPtr _samp
Definition: Algorithm.hh:245
void info(const char *format,...)
'Info' level.
Definition: Log.cpp:256
#define PARAM_USE_SURFACE_LAYERS
Definition: aquamaps.cpp:55
void _percentile(Scalar *result, int n, double percent, std::vector< ScalarVector > *matrix, int layerIndex)
Definition: aquamaps.cpp:642
virtual void _getConfiguration(ConfigurationPtr &) const
Definition: aquamaps.cpp:1111
const Scalar SURFACE_UPPER_LIMIT[7]
Definition: aquamaps.hh:137
#define PARAM_USE_SALINITY
Definition: aquamaps.cpp:60
float _progress
Definition: aquamaps.hh:280
Sample _lower_limit
Definition: aquamaps.hh:246
static AlgMetadata metadata
Definition: aquamaps.cpp:154
const Scalar SURFACE_LOWER_LIMIT[7]
Definition: aquamaps.hh:121
std::vector< OccurrencePtr >::const_iterator const_iterator
Definition: Occurrences.hh:85
int iterate()
Definition: aquamaps.cpp:359
const Scalar BOTTOM_LOWER_LIMIT[7]
Definition: aquamaps.hh:129
const int DISTANCE_TO_LAND
Definition: aquamaps.hh:174
int _getRelatedIndex(int index)
Definition: aquamaps.cpp:1187
const int SALINITY
Definition: aquamaps.hh:176
int getConvergence(Scalar *const val) const
Definition: aquamaps.cpp:372
void debug(const char *format,...)
'Debug' level.
Definition: Log.cpp:237
const int PRIMARY_PRODUCTION
Definition: aquamaps.hh:175
static AlgParamMetadata parameters[NUM_PARAM]
Definition: aquamaps.cpp:63
Definition: Sample.hh:25
const std::string NAME[7]
Definition: aquamaps.hh:161