openModeller  Version 1.5.0
om_evaluate.cpp
Go to the documentation of this file.
1 #include <openmodeller/om.hh>
4 
5 #include "getopts/getopts.h"
6 
7 #include "om_cmd_utils.hh"
8 
9 #include <fstream> // file I/O for XML
10 #include <sstream> // ostringstream datatype
11 #include <stdio.h> // file I/O for log
12 #include <time.h> // used to limit the number of times that the progress is written to a file
13 #include <string> // string library
14 #include <stdexcept> // try/catch
15 
16 using namespace std;
17 
18 int get_values(AlgorithmPtr alg, EnvironmentPtr env, OccurrencesPtr occs, Scalar * values, int cnt);
19 
21 int main( int argc, char **argv ) {
22 
23  Options opts;
24  int option;
25 
26  // command-line parameters (short name, long name, description, take args)
27  opts.addOption( "v", "version" , "Display version info" , false );
28  opts.addOption( "r", "xml-req" , "(option 1) Model evaluation request file in XML", true );
29  opts.addOption( "o", "model" , "(option 2) Serialized model file" , true );
30  opts.addOption( "p", "points" , "(option 2) TAB-delimited file with points" , true );
31  opts.addOption( "s", "result" , "File to store evaluation result in XML" , true );
32  opts.addOption( "" , "log-level" , "Set the log level (debug, warn, info, error)" , true );
33  opts.addOption( "" , "log-file" , "Log file" , true );
34  opts.addOption( "" , "prog-file" , "File to store job progress" , true );
35  opts.addOption( "c", "config-file" , "Configuration file for openModeller" , true );
36 
37  std::string log_level("info");
38  std::string request_file;
39  std::string model_file;
40  std::string points_file;
41  std::string result_file;
42  std::string log_file;
43  std::string progress_file;
44  std::string config_file;
45 
46  if ( ! opts.parse( argc, argv ) ) {
47 
48  opts.showHelp( argv[0] );
49  }
50 
51  // Set up any related external resources
53 
54  OpenModeller om;
55 
56  while ( ( option = opts.cycle() ) >= 0 ) {
57 
58  switch ( option ) {
59 
60  case 0:
61  printf( "om_evaluate %s\n", om.getVersion().c_str() );
62  printf("This is free software; see the source for copying conditions. There is NO\n");
63  printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
64  exit(0);
65  break;
66  case 1:
67  request_file = opts.getArgs( option );
68  break;
69  case 2:
70  model_file = opts.getArgs( option );
71  break;
72  case 3:
73  points_file = opts.getArgs( option );
74  break;
75  case 4:
76  result_file = opts.getArgs( option );
77  break;
78  case 5:
79  log_level = opts.getArgs( option );
80  break;
81  case 6:
82  log_file = opts.getArgs( option );
83  break;
84  case 7:
85  progress_file = opts.getArgs( option );
86  break;
87  case 8:
88  config_file = opts.getArgs( option );
89  break;
90  default:
91  break;
92  }
93  }
94 
95  // Initialize progress data if user wants to track progress
96  progress_data prog_data;
97 
98  if ( ! progress_file.empty() ) {
99 
100  prog_data.file_name = progress_file;
101 
102  time( &prog_data.timestamp );
103 
104  prog_data.progress = -1.0; // queued
105 
106  // Always create initial file with progress 0
107  progressFileCallback( 0.0, &prog_data );
108  }
109 
110  // Log stuff
111 
112  Log::Level level_code = getLogLevel( log_level );
113 
114  if ( ! log_file.empty() ) {
115 
116  Log::instance()->set( level_code, log_file, "" );
117  }
118  else {
119 
120  // Just set the level - things will go to stderr
121  Log::instance()->setLevel( level_code );
122  }
123 
124  // om configuration
125  if ( ! config_file.empty() ) {
126 
127  Settings::loadConfig( config_file );
128  }
129 
130  // Check parameters
131 
132  if ( request_file.empty() ) {
133 
134  if ( model_file.empty() || points_file.empty() ) {
135 
136  printf( "Please specify either a test request file in XML or a serialized model and a TAB-delimited file with the points to be tested\n");
137 
138  // If user is tracking progress
139  if ( ! progress_file.empty() ) {
140 
141  // -2 means aborted
142  progressFileCallback( -2.0, &prog_data );
143  }
144 
145  exit(-1);
146  }
147  }
148  else {
149 
150  if ( ! model_file.empty() ) {
151 
152  Log::instance()->warn( "Model file parameter will be ignored (using XML request instead)\n" );
153  }
154  if ( ! points_file.empty() ) {
155 
156  Log::instance()->warn( "Points file parameter will be ignored (using XML request instead)\n");
157  }
158  }
159 
160  // Real work
161 
162  try {
163 
164  // Load algorithms and instantiate controller class
166 
167  // IMPORTANT: data is not deserialized through Sampler objects, which would be much simpler.
168  // The reason is that some of the input points may be masked out so they
169  // would be discarded when the sampler cross references occurrences and environment.
170  // The number of evaluations MUST match the number of input points.
171  AlgorithmPtr alg;
172  OccurrencesPtr presences;
173  OccurrencesPtr absences;
174  EnvironmentPtr env;
175 
176  if ( ! request_file.empty() ) {
177 
178  // Loading input from XML request
179 
180  Log::instance()->debug( "Loading input from XML\n" );
181 
182  ConfigurationPtr input = Configuration::readXml( request_file.c_str() );
183 
184  alg = AlgorithmFactory::newAlgorithm( input->getSubsection( "Algorithm" ) );
185 
186  // Load environment and occurrences separately
187  ConfigurationPtr sampler_config = input->getSubsection( "Sampler" );
188 
189  if ( ConstConfigurationPtr env_config = sampler_config->getSubsection( "Environment", false ) ) {
190 
191  env = createEnvironment();
192  env->setConfiguration( env_config );
193  }
194 
195  if ( ConstConfigurationPtr presences_config = sampler_config->getSubsection( "Presence", false ) ) {
196 
197  presences = new OccurrencesImpl(1.0);
198  presences->setConfiguration( presences_config );
199  }
200 
201  if ( ConstConfigurationPtr absences_config = sampler_config->getSubsection( "Absence", false ) ) {
202 
203  absences = new OccurrencesImpl(0.0);
204  absences->setConfiguration( absences_config );
205  }
206  }
207  else {
208 
209  // Loading input from serialized model + TAB-delimited points file
210 
211  ConfigurationPtr input = Configuration::readXml( model_file.c_str() );
212 
213  alg = AlgorithmFactory::newAlgorithm( input->getSubsection( "Algorithm" ) );
214 
215  Log::instance()->debug( "Loading training sampler to get layers, label and spatial reference\n" );
216 
217  SamplerPtr training_sampler = createSampler( input->getSubsection( "Sampler" ) );
218 
219  // IMPORTANT: environmental scenario is taken from training sampler!
220  env = training_sampler->getEnvironment();
221 
222  // IMPORTANT: label and spatial reference are taken from presence points of the training sampler!
223  OccurrencesPtr training_presences = training_sampler->getPresences();
224 
225  std::string label( training_presences->label() );
226  std::string spatial_ref( training_presences->coordSystem() );
227 
228  Log::instance()->debug( "Loading points %s %s\n", label.c_str(), spatial_ref.c_str() );
229 
230  OccurrencesReader* oc_reader = OccurrencesFactory::instance().create( points_file.c_str(), spatial_ref.c_str() );
231 
232  presences = oc_reader->getPresences( label.c_str() );
233  absences = oc_reader->getAbsences( label.c_str() );
234 
235  delete oc_reader;
236  }
237 
238  if ( ! alg->done() ) {
239 
240  Log::instance()->error( "No model could be found as part of the specified algorithm. Aborting.\n");
241 
242  // If user is tracking progress
243  if ( ! progress_file.empty() ) {
244 
245  // -2 means aborted
246  progressFileCallback( -2.0, &prog_data );
247  }
248 
249  exit(-1);
250  }
251 
252  if ( alg->needNormalization() ) {
253 
254  env->normalize( alg->getNormalizer() );
255  }
256 
257  ConfigurationPtr output( new ConfigurationImpl("Values") );
258 
259  int num_presences = 0;
260  int num_absences = 0;
261 
262  if ( presences ) {
263 
264  num_presences = presences->numOccurrences();
265  }
266 
267  if ( absences ) {
268 
269  num_absences = absences->numOccurrences();
270  }
271 
272  Log::instance()->debug( "Loaded %d presences and %d absences\n", num_presences, num_absences );
273 
274  // Evaluate model
275  Log::instance()->debug( "Starting evaluation\n" );
276 
277  Scalar * vs = new (nothrow) Scalar[num_presences + num_absences];
278  if ( ! vs ) {
279 
280  Log::instance()->error( "Not enough memory to allocate model values. Aborting.\n");
281 
282  // If user is tracking progress
283  if ( ! progress_file.empty() ) {
284 
285  // -2 means aborted
286  progressFileCallback( -2.0, &prog_data );
287  }
288 
289  exit(-1);
290  }
291  int cnt = 0;
292 
293  if ( presences ) {
294 
295  cnt = get_values(alg, env, presences, vs, cnt);
296  }
297  if ( absences ) {
298 
299  cnt = get_values(alg, env, absences, vs, cnt);
300  }
301 
302  int precision = 5;
303 
304  output->addNameValue( "V", vs, num_presences + num_absences, precision );
305 
306  std::ostringstream evaluation_output;
307 
308  Configuration::writeXml( output, evaluation_output );
309 
310  std::cerr << flush;
311 
312  // Write test output to file, if requested
313  if ( ! result_file.empty() ) {
314 
315  ofstream file( result_file.c_str() );
316  file << evaluation_output.str();
317  file.close();
318  }
319  else {
320 
321  // Otherwise send it to stdout
322  std::cout << evaluation_output.str().c_str() << endl << flush;
323  }
324 
325  // If user wants to track progress
326  if ( ! progress_file.empty() ) {
327 
328  // Indicate that the job is finished
329  progressFileCallback( 1.0, &prog_data );
330  }
331 
332  delete[] vs;
333  }
334  catch ( runtime_error e ) {
335 
336  // If user is tracking progress
337  if ( ! progress_file.empty() ) {
338 
339  // -2 means aborted
340  progressFileCallback( -2.0, &prog_data );
341  }
342 
343  printf( "om_evaluate aborted: %s\n", e.what() );
344  }
345 }
346 
347 /******************/
348 /*** get values ***/
349 int
350 get_values(AlgorithmPtr alg, EnvironmentPtr env, OccurrencesPtr occs, Scalar * values, int cnt) {
351 
354  Scalar val;
355 
356  if ( occs->numOccurrences() > 0 ) {
357 
358  oc = occs->begin();
359  end = occs->end();
360  Sample sample;
361 
362  while ( oc != end ) {
363 
364  // Use environmental data already provided by the point, if present
365  // (in this case it will always be unnormalized, so we need to check normalization)
366  if ( (*oc)->hasEnvironment() ) {
367 
368  if ( alg->needNormalization() ) {
369 
370  (*oc)->normalize( alg->getNormalizer(), env->numCategoricalLayers() );
371  }
372 
373  sample = (*oc)->environment();
374  }
375  else {
376 
377  sample = env->get( (*oc)->x(), (*oc)->y() );
378  }
379 
380  if ( sample.size() > 0 ) {
381 
382  //sample.dump();
383  val = alg->getValue( sample );
384  }
385  else {
386  val= -1.0;
387  }
388 
389  //printf( "val=%0.5f\n", val );
390  values[cnt] = val;
391  ++cnt;
392  ++oc;
393  }
394  }
395 
396  return cnt;
397 }
static void loadConfig(const std::string configFile)
Definition: Settings.cpp:100
void warn(const char *format,...)
'Warn' level.
Definition: Log.cpp:273
static ConfigurationPtr readXml(char const *filename)
static AlgorithmPtr newAlgorithm(std::string const id)
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
std::string file_name
Definition: om_cmd_utils.hh:42
static OccurrencesFactory & instance()
int get_values(AlgorithmPtr alg, EnvironmentPtr env, OccurrencesPtr occs, Scalar *values, int cnt)
Log::Level getLogLevel(std::string level)
virtual OccurrencesPtr getAbsences(const char *groupId)
int main(int argc, char **argv)
Main code.
Definition: om_evaluate.cpp:21
Level
Definition: Log.hh:54
void setLevel(Level level)
Definition: Log.hh:107
EnvironmentPtr createEnvironment(const std::vector< std::string > &categs, const std::vector< std::string > &maps, const std::string &mask_file)
Definition: Environment.cpp:55
SamplerPtr createSampler(const EnvironmentPtr &env, const OccurrencesPtr &presence, const OccurrencesPtr &absence)
Definition: Sampler.cpp:52
void error(const char *format,...)
'Error' level.
Definition: Log.cpp:290
void setupExternalResources()
Definition: os_specific.cpp:95
virtual OccurrencesPtr getPresences(const char *groupId)
void set(Level level, std::string fileName, char const *pref="")
Definition: Log.cpp:196
static void writeXml(const ConstConfigurationPtr &config, char const *fileaname)
static int searchDefaultDirs()
std::size_t size() const
Definition: Sample.hh:70
std::string getVersion()
std::vector< OccurrencePtr >::const_iterator const_iterator
Definition: Occurrences.hh:85
void debug(const char *format,...)
'Debug' level.
Definition: Log.cpp:237
time_t timestamp
Definition: om_cmd_utils.hh:43
Definition: Sample.hh:25
void progressFileCallback(float progress, void *progressData)
OccurrencesReader * create(const char *source, const char *coordSystem)