TECA
The Toolkit for Extreme Climate Analysis
teca_algorithm.h
1 #ifndef teca_algorithm_h
2 #define teca_algorithm_h
3 
4 #include "teca_config.h"
5 #include "teca_shared_object.h"
6 #include "teca_dataset.h"
7 #include "teca_algorithm_executive.h"
8 #include "teca_metadata.h"
9 #include "teca_program_options.h"
10 #include "teca_mpi.h"
11 
12 #include <vector>
13 #include <utility>
14 #include <iosfwd>
15 #include <initializer_list>
16 #include <functional>
17 
18 class teca_algorithm_internals;
19 
20 TECA_SHARED_OBJECT_FORWARD_DECL(teca_algorithm)
21 
22 /// An output port packages an algorithm and a port number
23 using teca_algorithm_output_port
24  = std::pair<p_teca_algorithm, unsigned int>;
25 
26 /// get the algorithm from the output port
27 inline
28 p_teca_algorithm &get_algorithm(teca_algorithm_output_port &op)
29 { return op.first; }
30 
31 /// get port number from the output port
32 inline
33 unsigned int &get_port(teca_algorithm_output_port &op)
34 { return op.second; }
35 
36 /* this is a convenience macro to be used to declare a static New method that
37  * will be used to construct new objects in shared_ptr's. This manages the
38  * details of interoperability with std C++11 shared pointer
39  */
40 #define TECA_ALGORITHM_STATIC_NEW(T) \
41  \
42 /** Returns an instance of T */ \
43 static p_##T New() \
44 { \
45  return p_##T(new T); \
46 } \
47  \
48 /** Enables the static constructor */ \
49 std::shared_ptr<T> shared_from_this() \
50 { \
51  return std::static_pointer_cast<T>( \
52  teca_algorithm::shared_from_this()); \
53 } \
54  \
55 /** Enables the static constructor */ \
56 std::shared_ptr<T const> shared_from_this() const \
57 { \
58  return std::static_pointer_cast<T const>( \
59  teca_algorithm::shared_from_this()); \
60 }
61 
62 #define TECA_ALGORITHM_CLASS_NAME(T) \
63 /** returns the name of the class */ \
64 const char *get_class_name() const override \
65 { \
66  return #T; \
67 }
68 
69 /** this convenience macro removes copy and assignment operators
70  * which generally should not be defined for reference counted types
71  */
72 #define TECA_ALGORITHM_DELETE_COPY_ASSIGN(T) \
73  \
74  T(const T &src) = delete; \
75  T(T &&src) = delete; \
76  \
77  T &operator=(const T &src) = delete; \
78  T &operator=(T &&src) = delete;
79 
80 /** convenience macro to declare standard set_NAME/get_NAME methods
81  * where NAME is the name of a class member. will manage the
82  * algorithm's modified state for the user.
83  */
84 #define TECA_ALGORITHM_PROPERTY(T, NAME) \
85  \
86 /** Set the value of the NAME algorithm property */ \
87 void set_##NAME(const T &v) \
88 { \
89  if (this->NAME != v) \
90  { \
91  this->NAME = v; \
92  this->set_modified(); \
93  } \
94 } \
95  \
96 /** Get the value of the NAME algorithm property */ \
97 const T &get_##NAME() const \
98 { \
99  return this->NAME; \
100 }
101 
102 /** similar to TECA_ALGORITHM_PROPERTY but prior to setting NAME
103  * will call the member function int valididate_NAME(T v). If
104  * the value v is valid the fucntion should return 0. If the value
105  * is not zero the function should invoke TECA_ERROR with a
106  * descriptive message and return non-zero.
107  */
108 #define TECA_ALGORITHM_PROPERTY_V(T, NAME) \
109  \
110 /** Set the value of the NAME algorithm property */ \
111 void set_##NAME(const T &v) \
112 { \
113  if (this->validate_ ## NAME (v)) \
114  return; \
115  \
116  if (this->NAME != v) \
117  { \
118  this->NAME = v; \
119  this->set_modified(); \
120  } \
121 } \
122  \
123 /** Get the value of the NAME algorithm property */ \
124 const T &get_##NAME() const \
125 { \
126  return this->NAME; \
127 }
128 
129 /** convenience macro to declare standard set_NAME/get_NAME methods
130  * where NAME is the name of a class member. will manage the
131  * algorithm's modified state for the user.
132  */
133 #define TECA_ALGORITHM_VECTOR_PROPERTY(T, NAME) \
134  \
135 /** get the size of the NAME algorithm vector property */ \
136 size_t get_number_of_##NAME##s () \
137 { \
138  return this->NAME##s.size(); \
139 } \
140  \
141 /** append to the NAME algorithm vector property */ \
142 void append_##NAME(const T &v) \
143 { \
144  this->NAME##s.push_back(v); \
145  this->set_modified(); \
146 } \
147  \
148 /** set the i-th element of the NAME algorithm vector property */ \
149 void set_##NAME(size_t i, const T &v) \
150 { \
151  if (this->NAME##s[i] != v) \
152  { \
153  this->NAME##s[i] = v; \
154  this->set_modified(); \
155  } \
156 } \
157  \
158 /** set the NAME algorithm vector property */ \
159 void set_##NAME##s(const std::vector<T> &v) \
160 { \
161  if (this->NAME##s != v) \
162  { \
163  this->NAME##s = v; \
164  this->set_modified(); \
165  } \
166 } \
167  \
168 /** set the NAME algorithm vector property */ \
169 void set_##NAME##s(const std::initializer_list<T> &&l) \
170 { \
171  std::vector<T> v(l); \
172  if (this->NAME##s != v) \
173  { \
174  this->NAME##s = v; \
175  this->set_modified(); \
176  } \
177 } \
178  \
179 /** get the i-th element of the NAME algorithm vector property */ \
180 const T &get_##NAME(size_t i) const \
181 { \
182  return this->NAME##s[i]; \
183 } \
184  \
185 /** get the NAME algorithm vector property */ \
186 const std::vector<T> &get_##NAME##s() const \
187 { \
188  return this->NAME##s; \
189 } \
190  \
191 /** clear the NAME algorithm vector property */ \
192 void clear_##NAME##s() \
193 { \
194  this->NAME##s.clear(); \
195 }
196 
197 /// helper that allows us to use std::function as a TECA_ALGORITHM_PROPERTY
198 template<typename T>
199 bool operator!=(const std::function<T> &lhs, const std::function<T> &rhs)
200 {
201  return &rhs != &lhs;
202 }
203 
204 /** This is a work around for older versions of Apple clang
205  * Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)
206  * Target: x86_64-apple-darwin12.6.0
207  */
208 #define TECA_ALGORITHM_CALLBACK_PROPERTY(T, NAME) \
209  \
210 /** Set the NAME algorithm property */ \
211 void set_##NAME(const T &v) \
212 { \
213  /*if (this->NAME != v)*/ \
214  /*{*/ \
215  this->NAME = v; \
216  this->set_modified(); \
217  /*}*/ \
218 } \
219  \
220 /** Get the NAME algorithm property */ \
221 const T &get_##NAME() const \
222 { \
223  return this->NAME; \
224 } \
225  \
226 /** Get the NAME algorithm property */ \
227 T &get_##NAME() \
228 { \
229  return this->NAME; \
230 }
231 
232 
233 /// The interface to TECA pipeline architecture.
234 /**
235  * All sources/readers filters, sinks/writers will implement this interface.
236  */
237 class TECA_EXPORT teca_algorithm : public std::enable_shared_from_this<teca_algorithm>
238 {
239 public:
240  // construct/destruct
241  virtual ~teca_algorithm() noexcept;
242 
243  TECA_ALGORITHM_DELETE_COPY_ASSIGN(teca_algorithm)
244 
245  /// return the name of the class.
246  virtual const char *get_class_name() const = 0;
247 
248  /** set the communicator to use at this stage of the pipeline this has
249  * no influence on other stages. We duplicate the passed in communicator
250  * providing an isolated communication space for subsequent operations. By
251  * default the communicator is initialized to MPI_COMM_WORLD, here it is not
252  * duplicated. Thus to put an algorithm into a unique communication space
253  * one should explicitly set a communicator. When an algorithm should not
254  * use MPI, for instance when it is in a nested pipeline, one may set the
255  * communicator to MPI_COMM_SELF.
256  */
257  void set_communicator(MPI_Comm comm);
258 
259  /// get the active communicator
260  MPI_Comm get_communicator();
261 
262 #if defined(TECA_HAS_BOOST)
263  /** initialize the given options description with algorithm's properties
264  * implementors should call the base implementation when overriding.
265  * this should be called after the override adds its options.
266  */
267  virtual void get_properties_description(const std::string &prefix,
268  options_description &opts);
269 
270  /** initialize the algorithm from the given options variable map.
271  * implementors should call the base implementation when overriding.
272  * this should be called before the override sets its properties.
273  */
274  virtual void set_properties(const std::string &prefix,
275  variables_map &opts);
276 #endif
277 
278  /** @name verbose
279  * if set to a non-zero value, rank 0 will send status information to the
280  * terminal. The default setting of zero results in no output.
281  */
282  ///@{
283  TECA_ALGORITHM_PROPERTY(int, verbose)
284  ///@}
285 
286  /** get an output port from the algorithm. to be used during pipeline
287  * building
288  */
289  virtual
290  teca_algorithm_output_port get_output_port(unsigned int port = 0);
291 
292  /// set an input to this algorithm
293  void set_input_connection(const teca_algorithm_output_port &port)
294  { this->set_input_connection(0, port); }
295 
296  /// set an input to this algorithm
297  virtual
298  void set_input_connection(unsigned int id,
299  const teca_algorithm_output_port &port);
300 
301  /// remove input connections
302  virtual
303  void remove_input_connection(unsigned int id);
304 
305  /// remove all input connections
306  void clear_input_connections();
307 
308  /** access the cached data produced by this algorithm. when no request is
309  * specified the dataset on the top(most recent) of the cache is returned.
310  * When a request is specified it may optionally be filtered by the
311  * implementations cache key filter. see also get_cache_key (threadsafe)
312  */
313  const_p_teca_dataset get_output_data(unsigned int port = 0);
314 
315  /** remove a dataset from the top/bottom of the cache. the top of the cache
316  * has the most recently created dataset. top or bottom is selected via
317  * the boolean argument. (threadsafe)
318  */
319  void pop_cache(unsigned int port = 0, int top = 0);
320 
321  /// set the cache size. the default is 1. (threadsafe)
322  void set_cache_size(unsigned int n);
323 
324  /// execute the pipeline from this instance up.
325  virtual int update();
326 
327  /// execute the pipeline from this instance up.
328  virtual int update(unsigned int port);
329 
330  /// get meta data considering this instance up.
331  virtual teca_metadata update_metadata(unsigned int port = 0);
332 
333  /// set the executive
334  void set_executive(p_teca_algorithm_executive exe);
335 
336  /// get the executive
337  p_teca_algorithm_executive get_executive();
338 
339  /** serialize the configuration to a stream. this should store the public
340  * user modifiable properties so that runtime configuration may be saved
341  * and restored.
342  */
343  virtual void to_stream(std::ostream &s) const;
344 
345  /// deserialize from the stream.
346  virtual void from_stream(std::istream &s);
347 
348 protected:
349  teca_algorithm();
350 
351  /** Set the number of input connections. implementations should call this
352  * from their constructors to setup the internal caches and data structures
353  * required for execution.
354  */
355  void set_number_of_input_connections(unsigned int n);
356 
357  /** Set the number of output ports. implementations should call this from
358  * their constructors to setup the internal caches and data structures
359  * required for execution.
360  */
361  void set_number_of_output_ports(unsigned int n);
362 
363  /** set the modified flag on the given output port's cache. should be
364  * called when user modifies properties on the object that require the
365  * output to be regenerated.
366  */
367  virtual void set_modified();
368 
369  /// an overload to set_modified by port
370  void set_modified(unsigned int port);
371 
372 protected:
373 // this section contains methods that developers
374 // typically need to override when implementing
375 // teca_algorithm's such as reader, filters, and
376 // writers.
377 
378  /** implementations must override this method to provide information to
379  * downstream consumers about what data will be produced on each output
380  * port. The port to provide information about is named in the first
381  * argument the second argument contains a list of the metadata describing
382  * data on all of the inputs.
383  */
384  virtual
385  teca_metadata get_output_metadata(unsigned int port,
386  const std::vector<teca_metadata> &input_md);
387 
388  /** implementations must override this method and generate a set of
389  * requests describing the data required on the inputs to produce data for
390  * the named output port, given the upstream meta data and request. If no
391  * data is needed on an input then the list should contain a null request.
392  */
393  virtual
394  std::vector<teca_metadata> get_upstream_request(
395  unsigned int port, const std::vector<teca_metadata> &input_md,
396  const teca_metadata &request);
397 
398  /** implementations must override this method and produce the output dataset
399  * for the port named in the first argument. The second argument is a list
400  * of all of the input datasets. See also get_request. The third argument
401  * contains a request from the consumer which can specify information such
402  * as arrays, subset region, timestep etc. The implementation is free to
403  * handle the request as it sees fit.
404  */
405  virtual
406  const_p_teca_dataset execute(unsigned int port,
407  const std::vector<const_p_teca_dataset> &input_data,
408  const teca_metadata &request);
409 
410  /** implementations may choose to override this method to gain control of
411  * keys used in the cache. By default the passed in request is used as the
412  * key. This override gives implementor the chance to filter the passed in
413  * request.
414  */
415  virtual
416  teca_metadata get_cache_key(unsigned int port,
417  const teca_metadata &request) const;
418 
419 protected:
420 // this section contains methods that control the
421 // pipeline's behavior. these would typically only
422 // need to be overridden when designing a new class
423 // of algorithms.
424 
425  /** driver function that manage meta data reporting phase of pipeline
426  * execution.
427  */
428  virtual
429  teca_metadata get_output_metadata(
430  teca_algorithm_output_port &current);
431 
432  /* driver function that manages execution of the given request on the named
433  * port
434  */
435  virtual
436  const_p_teca_dataset request_data(
437  teca_algorithm_output_port &port,
438  const teca_metadata &request);
439 
440  /** driver function that clears the output data cache where modified flag
441  * has been set from the current port upstream.
442  */
443  virtual
444  int validate_cache(teca_algorithm_output_port &current);
445 
446  /** driver function that clears the modified flag on the named port and all
447  * of it's upstream connections.
448  */
449  virtual
450  void clear_modified(teca_algorithm_output_port current);
451 
452 protected:
453 // api exposing internals for use in driver methods
454 
455  /** search the given port's cache for the dataset associated
456  * with the given request. see also get_cache_key. (threadsafe)
457  */
458  const_p_teca_dataset get_output_data(unsigned int port,
459  const teca_metadata &request);
460 
461  /** add or update the given request , dataset pair in the cache. see also
462  * get_cache_key. (threadsafe)
463  */
464  int cache_output_data(unsigned int port,
465  const teca_metadata &request, const_p_teca_dataset &data);
466 
467  /// clear the cache on the given output port
468  void clear_cache(unsigned int port);
469 
470  /// get the number of input connections
471  unsigned int get_number_of_input_connections();
472 
473  /** get the output port associated with this algorithm's i'th input
474  * connection.
475  */
476  teca_algorithm_output_port &get_input_connection(unsigned int i);
477 
478  /// clear the modified flag on the i'th output
479  void clear_modified(unsigned int port);
480 
481  /// return the output port's modified flag value
482  int get_modified(unsigned int port) const;
483 
484 protected:
485  int verbose;
486 
487 private:
488  teca_algorithm_internals *internals;
489 
490  friend class teca_threaded_algorithm;
491  friend class teca_data_request;
492 };
493 
494 #endif
teca_metadata
A generic container for meta data in the form of name=value pairs.
Definition: teca_metadata.h:21
teca_program_options.h
get_port
unsigned int & get_port(teca_algorithm_output_port &op)
get port number from the output port
Definition: teca_algorithm_output_port.h:17
teca_shared_object.h
teca_algorithm::set_input_connection
void set_input_connection(const teca_algorithm_output_port &port)
set an input to this algorithm
Definition: teca_algorithm.h:293
get_algorithm
p_teca_algorithm & get_algorithm(teca_algorithm_output_port &op)
get the algorithm from the output port
Definition: teca_algorithm_output_port.h:12
teca_error::TECA_EXPORT
p_teca_error_handler error_handler TECA_EXPORT
The global error handler instance.
teca_threaded_algorithm
This is the base class defining a threaded algorithm.
Definition: teca_threaded_algorithm.h:60
teca_algorithm
The interface to TECA pipeline architecture.
Definition: teca_algorithm.h:237