TECA
The Toolkit for Extreme Climate Analysis
teca_coordinate_util.h
Go to the documentation of this file.
1 #ifndef teca_cartesian_mesh_util_h
2 #define teca_cartesian_mesh_util_h
3 
4 /// @file
5 
6 #include "teca_config.h"
7 #include "teca_cartesian_mesh.h"
8 #include "teca_variant_array.h"
11 #include "teca_metadata.h"
12 #include "teca_array_attributes.h"
13 
14 #include <vector>
15 #include <cmath>
16 #include <type_traits>
17 #include <typeinfo>
18 #include <iomanip>
19 #include <deque>
20 #include <vector>
21 
22 using namespace teca_variant_array_util;
23 using allocator = teca_variant_array::allocator;
24 
25 #if defined(TECA_HAS_CUDA)
26 #define TECA_TARGET __host__ __device__
27 #else
28 #define TECA_TARGET
29 #endif
30 
31 /// For printing data as ASCII with the maximum supported numerical precision
32 #define max_prec(T) \
33  std::setprecision(std::numeric_limits<T>::digits10 + 1)
34 
35 /// Codes dealing with operations on coordinate systems
37 {
38 /** @brief
39  * traits classes used to get default tolerances for comparing numbers
40  * of a given precision.
41  *
42  * @details
43  * A relative tolerance is used for comparing large
44  * numbers and an absolute tolerance is used for comparing small numbers.
45  * these defaults are not universal and will not work well in all situations.
46  *
47  * see also:
48  * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
49  */
50 template <typename n_t>
51 struct equal_tt {};
52 
53 #define declare_equal_tt(cpp_t, atol, rtol) \
54 /** Specialization for cpp_t with default absTol and relTol */ \
55 template <> \
56 struct equal_tt<cpp_t> \
57 { \
58  TECA_TARGET static cpp_t absTol() { return atol; } \
59  TECA_TARGET static cpp_t relTol() { return rtol; } \
60 };
61 
62 declare_equal_tt(float, 10.0f*std::numeric_limits<float>::epsilon(),
63  std::numeric_limits<float>::epsilon())
64 
65 declare_equal_tt(double, 10.0*std::numeric_limits<double>::epsilon(),
66  std::numeric_limits<float>::epsilon())
67 
68 declare_equal_tt(long double, std::numeric_limits<double>::epsilon(),
69  std::numeric_limits<double>::epsilon())
70 
71 /** Compare two floating point numbers. absTol handles comparing numbers very
72  * close to zero. relTol handles comparing larger values.
73  */
74 template <typename T>
75 TECA_TARGET
76 bool equal(T a, T b,
77  T relTol = equal_tt<T>::relTol(), T absTol = equal_tt<T>::absTol(),
78  typename std::enable_if<std::is_floating_point<T>::value>::type* = 0)
79 {
80  // for numbers close to zero
81  T diff = std::abs(a - b);
82  if (diff <= absTol)
83  return true;
84  // realtive difference for larger values
85  a = std::abs(a);
86  b = std::abs(b);
87  b = (b > a) ? b : a;
88  b *= relTol;
89  if (diff <= b)
90  return true;
91  return false;
92 }
93 
94 /// Compare two integral numbers.
95 template <typename T>
96 TECA_TARGET
97 bool equal(T a, T b, T relTol = 0, T absTol = 0,
98  typename std::enable_if<std::is_integral<T>::value>::type* = 0)
99 {
100  (void)relTol;
101  (void)absTol;
102  return a == b;
103 }
104 
105 /** Compare two floating point numbers. This overload may be used in regression
106  * tests or other contexts where a diagnostic error message should be reported
107  * if the numbers are not equal.
108  */
109 template <typename T>
110 bool equal(T a, T b, std::string &diagnostic,
111  T relTol = equal_tt<T>::relTol(), T absTol = equal_tt<T>::absTol(),
112  typename std::enable_if<std::is_floating_point<T>::value>::type* = 0)
113 {
114  // for numbers close to zero
115  T diff = std::abs(a - b);
116  if (diff <= absTol)
117  return true;
118  // realtive difference for larger values
119  T aa = std::abs(a);
120  T bb = std::abs(b);
121  bb = (bb > aa) ? bb : aa;
122  T cc = bb*relTol;
123  if (diff <= cc)
124  return true;
125  // a and b are not equal format the diagnostic
126  T eps = std::numeric_limits<T>::epsilon();
127  std::ostringstream os;
128  os << max_prec(T) << a << " != " << max_prec(T) << b
129  << " relTol=" << max_prec(T) << relTol
130  << " absTol=" << max_prec(T) << absTol
131  << " |a-b|=" << max_prec(T) << diff
132  << " |a-b|/eps=" << max_prec(T) << diff/eps
133  << " max(|a|,|b|)*relTol=" << max_prec(T) << cc
134  << " |a-b|/max(|a|,|b|)=" << max_prec(T) << diff/bb
135  << " eps(" << typeid(a).name() << sizeof(T) << ")="
136  << max_prec(T) << eps;
137  diagnostic = os.str();
138  return false;
139 }
140 
141 /** Compare two integral numbers. This overload may be used in regression
142  * tests or other contexts where a diagnostic error message should be reported
143  * if the numbers are not equal.
144  */
145 template <typename T>
146 bool equal(T a, T b, std::string &diagnostic, T relTol = 0, T absTol = 0,
147  typename std::enable_if<std::is_integral<T>::value>::type* = 0)
148 {
149  (void)relTol;
150  (void)absTol;
151  if (a == b)
152  return true;
153  // a and b are not equal format the diagnostic
154  std::ostringstream os;
155  os << typeid(a).name() << sizeof(T) << " " << a << " != " << b;
156  diagnostic = os.str();
157  return false;
158 }
159 
160 /** Error codes returned by bool equal(const const_p_teca_variant_array &array1,
161  const const_p_teca_variant_array &array2,
162  double absTol, double relTol, int errorNo,
163  std::string &errorStr);
164  * | Code | Meaning |
165  * |------------------|---------|
166  * | no_error | no error |
167  * | length_missmatch | length missmatch |
168  * | type_missmatch | type missmatch |
169  * | invalid_value | invalid value detected (NaN, inf) |
170  * | value_missmatch | a value failed to compare within the tolerance |
171  */
173 {
174  enum {no_error = 0,
175  invalid_value = 1,
176  length_missmatch = 2,
177  type_missmatch = 3,
178  value_missmatch = 4,
179  unsupported_type = 5
180  };
181 };
182 
183 /** Compare two variant arrays elementwise for equality. If the arrays fail to
184  * compare within the specified tolerance errorNo will contain one of the
185  * equal_error enumerations and errorStr will conatin a diagnostic message
186  * describing the failure.
187  */
190  const const_p_teca_variant_array &array2,
191  double absTol, double relTol, int &errorNo,
192  std::string &errorStr);
193 
194 /// Less than or equal to predicate
195 template<typename data_t>
197 { static bool eval(const data_t &l, const data_t &r) { return l <= r; } };
198 
199 /// Greater than or equal to predicate
200 template<typename data_t>
202 { static bool eval(const data_t &l, const data_t &r) { return l >= r; } };
203 
204 /// Less than predicate
205 template<typename data_t>
207 { static bool eval(const data_t &l, const data_t &r) { return l < r; } };
208 
209 /// Greater than predicate
210 template<typename data_t>
212 { static bool eval(const data_t &l, const data_t &r) { return l > r; } };
213 
214 /// comparator implementing bracket for ascending input arrays
215 template<typename data_t>
217 {
218  // m_0 is an index into the data, m_1 = m_0 + 1
219  // comparitors defining the bracket orientation. for data in
220  // ascending order: val >= data[m_0] && val <= data[m_1]
221  using comp0_t = geq<data_t>;
222  using comp1_t = leq<data_t>;
223 
224  // m_0 is an index into the data, m_1 = m_0 + 1
225  // get the id of the smaller value (lower == true)
226  // or the larger value (lower == false)
227  static unsigned long get_id(bool lower,
228  unsigned long m_0, unsigned long m_1)
229  {
230  if (lower)
231  return m_0;
232  return m_1;
233  }
234 };
235 
236 /// comparator implementing bracket for descending input arrays
237 template<typename data_t>
239 {
240  // m_0 is an index into the data, m_1 = m_0 + 1
241  // comparitors defining the bracket orientation. for data in
242  // descending order: val <= data[m_0] && val >= data[m_1]
243  using comp0_t = leq<data_t>;
244  using comp1_t = geq<data_t>;
245 
246  // m_0 is an index into the data, m_1 = m_0 + 1
247  // get the id of the smaller value (lower == true)
248  // or the larger value (lower == false)
249  static unsigned long get_id(bool lower,
250  unsigned long m_0, unsigned long m_1)
251  {
252  if (lower)
253  return m_1;
254  return m_0;
255  }
256 };
257 
258 /** binary search that will locate index bounding the value above or below
259  * such that data[i] <= val or val <= data[i+1] depending on the value of
260  * lower. return 0 if the value is found. the comp0 and comp1 template
261  * parameters let us operate on both ascending and descending input. defaults
262  * are set for ascending inputs.
263  */
264 template <typename data_t, typename bracket_t = ascend_bracket<data_t>>
266 int index_of(const data_t *data, unsigned long l, unsigned long r,
267  data_t val, bool lower, unsigned long &id)
268 {
269  unsigned long m_0 = (r + l)/2;
270  unsigned long m_1 = m_0 + 1;
271 
272  if (m_0 == r)
273  {
274  if (equal(val, data[m_0]))
275  {
276  id = m_0;
277  return 0;
278  }
279  // not found
280  return -1;
281  }
282  else
283  if (bracket_t::comp0_t::eval(val, data[m_0]) &&
284  bracket_t::comp1_t::eval(val, data[m_1]))
285  {
286  // found a bracket around the value
287  if (equal(val, data[m_0]))
288  id = m_0;
289  else
290  if (equal(val, data[m_1]))
291  id = m_1;
292  else
293  id = bracket_t::get_id(lower, m_0, m_1);
294  return 0;
295  }
296  else
297  if (bracket_t::comp1_t::eval(val, data[m_0]))
298  {
299  // split range to the left
300  return teca_coordinate_util::index_of<data_t, bracket_t>(
301  data, l, m_0, val, lower, id);
302  }
303  else
304  {
305  // split the range to the right
306  return teca_coordinate_util::index_of<data_t, bracket_t>(
307  data, m_1, r, val, lower, id);
308  }
309 
310  // not found
311  return -1;
312 }
313 
314 /** binary search that will locate index of the given value. return 0 if the
315  * value is found.
316  */
317 template <typename T>
319 int index_of(const T *data, size_t l, size_t r, T val, unsigned long &id)
320 {
321  unsigned long m_0 = (r + l)/2;
322  unsigned long m_1 = m_0 + 1;
323 
324  if (m_0 == r)
325  {
326  // need this test when len of data is 1
327  if (equal(val, data[m_0], T(8)*std::numeric_limits<T>::epsilon()))
328  {
329  id = m_0;
330  return 0;
331  }
332  // not found
333  return -1;
334  }
335  else
336  if (equal(val, data[m_0], T(8)*std::numeric_limits<T>::epsilon()))
337  {
338  id = m_0;
339  return 0;
340  }
341  else
342  if (equal(val, data[m_1], T(8)*std::numeric_limits<T>::epsilon()))
343  {
344  id = m_1;
345  return 0;
346  }
347  else
348  if (val < data[m_0])
349  {
350  // split range to the left
351  return teca_coordinate_util::index_of(data, l, m_0, val, id);
352  }
353  else
354  {
355  // split the range to the right
356  return teca_coordinate_util::index_of(data, m_1, r, val, id);
357  }
358 
359  // not found
360  return -1;
361 }
362 
363 /** Convert bounds to extents in three dimensions.
364  *
365  * @param[in] bounds the 3D spatial bounding box [x0, x1, y0, y1, z0, z1]
366  * @param[in] x the x-coordinate array
367  * @param[in] y the y-coordinate array
368  * @param[in] z the z-coordinate array
369  * @param[out] extent the resulting 3D extent [i0, i1, j0, j1, k0, k1]
370  *
371  * @returns non-zero if the requested bounds are not in the given coordinate
372  * arrays.
373  *
374  * @note the x,y and z coordinate arrays must not be empty.
375  */
377 int bounds_to_extent(const double *bounds,
379  const const_p_teca_variant_array &z, unsigned long *extent);
380 
381 /** Convert bounds to extents in one dimension.
382  *
383  * @param[in] bounds the 1D spatial bounding box [x0, x1]
384  * @param[in] x the x-coordinate array
385  * @param[out] extent the resulting 1Dextent [i0, i1]
386  *
387  * @returns non-zero if the requested bounds are not in the given coordinate
388  * arrays.
389  *
390  * @note the coordinate array must not be empty.
391  */
393 int bounds_to_extent(const double *bounds,
394  const const_p_teca_variant_array &x, unsigned long *extent);
395 
396 /** Convert bounds to extents in three dimensions.
397  *
398  * @param[in] bounds the 3D spatial bounding box [x0, x1, y0, y1, z0, z1]
399  * @param[in] md a metadata object containing coordinate information as defined
400  * by the teca_cf_reader
401  * @param[out] extent the resulting 3D extent [i0, i1, j0, j1, k0, k1]
402  *
403  * @returns non-zero if the requested bounds are not in the given coordinate
404  * arrays.
405  *
406  * @note the x,y and z coordinate arrays must not be empty.
407  */
409 int bounds_to_extent(const double *bounds, const teca_metadata &md,
410  unsigned long *extent);
411 
412 
413 /** Convert bounds to extents in one dimension.
414  *
415  * @param[in] bounds the 1D spatial bounding box [x0, x1]
416  * @param[in] px pointer to the coordinate array
417  * @param[in] nx the size of the coordinate array
418  * @param[out] extent the resulting 1D extent [i0, i1]
419  *
420  * @returns non-zero if the requested bounds are not in the given coordinate
421  * arrays.
422  */
423 template <typename coord_t>
425 int bounds_to_extent(const double *bounds,
426  const coord_t *px, unsigned long nx, unsigned long *extent)
427 {
428  // in the following, for each side (low, high) of the bounds in
429  // each cooridnate direction we are searching for the index that
430  // is either just below, just above, or exactly at the given value.
431  // special cases include:
432  // * x,y,z in descending order. we check for that and
433  // invert the compare functions that define the bracket
434  // * bounds describing a plane. we test for this and
435  // so that both high and low extent return the same value.
436  // * x,y,z are length 1. we can skip the search in that
437  // case.
438 
439  const coord_t eps8 = coord_t(8)*std::numeric_limits<coord_t>::epsilon();
440 
441  unsigned long high_i = nx - 1;
442  extent[0] = 0;
443  extent[1] = high_i;
444  coord_t low_x = static_cast<coord_t>(bounds[0]);
445  coord_t high_x = static_cast<coord_t>(bounds[1]);
446  bool slice_x = equal(low_x, high_x, eps8);
447 
448  if (((nx > 1) && (((px[high_i] > px[0]) &&
449  (teca_coordinate_util::index_of(px, 0, high_i, low_x, true, extent[0])
450  || teca_coordinate_util::index_of(px, 0, high_i, high_x, slice_x, extent[1]))) ||
451  ((px[high_i] < px[0]) &&
452  (teca_coordinate_util::index_of<coord_t,descend_bracket<coord_t>>(px, 0, high_i, low_x, false, extent[0])
453  || teca_coordinate_util::index_of<coord_t,descend_bracket<coord_t>>(px, 0, high_i, high_x, !slice_x, extent[1]))))))
454  {
455  TECA_ERROR(<< "requested subset [" << bounds[0] << ", " << bounds[1] << ", "
456  << "] is not contained in the current dataset bounds [" << px[0] << ", "
457  << px[high_i] << "]")
458  return -1;
459  }
460 
461  return 0;
462 }
463 
464 /** Get the i,j,k cell index of point x,y,z in the given mesh. return 0 if
465  * successful.
466  */
467 template<typename T>
469 int index_of(const const_p_teca_cartesian_mesh &mesh, T x, T y, T z,
470  unsigned long &i, unsigned long &j, unsigned long &k)
471 {
472  const_p_teca_variant_array xc = mesh->get_x_coordinates();
473  const_p_teca_variant_array yc = mesh->get_y_coordinates();
474  const_p_teca_variant_array zc = mesh->get_z_coordinates();
475 
476  VARIANT_ARRAY_DISPATCH_FP(xc.get(),
477 
478  assert_type<TT>(yc, zc);
479 
480  auto [sp_xc, p_xc,
481  sp_yc, p_yc,
482  sp_zc, p_zc] = get_host_accessible<CTT>(xc, yc, zc);
483 
484  sync_host_access_any(xc, yc, zc);
485 
486  unsigned long nx = xc->size();
487  unsigned long ny = yc->size();
488  unsigned long nz = zc->size();
489 
490  if (teca_coordinate_util::index_of(p_xc, 0, nx-1, x, true, i)
491  || teca_coordinate_util::index_of(p_yc, 0, ny-1, y, true, j)
492  || teca_coordinate_util::index_of(p_zc, 0, nz-1, z, true, k))
493  {
494  // out of bounds
495  return -1;
496  }
497 
498  // success
499  return 0;
500  )
501 
502  // coords are not a floating point type
503  return -1;
504 }
505 
506 /** given a human readable date string in YYYY-MM-DD hh:mm:ss format and a
507  * list of floating point offset times in the specified calendar and units find
508  * the closest time step. return 0 if successful see index_of for a description
509  * of lower, if clamp is true then when the date falls outside of the time
510  * values either the first or last time step is returned.
511  */
514  bool lower, bool clamp, const std::string &calendar,
515  const std::string &units, const std::string &date,
516  unsigned long &step);
517 
518 /** given a time value (val), associated time units (units), and calendar
519  * (calendar), return a human-readable rendering of the date (date) in a
520  * strftime-format (format). return 0 if successful.
521  */
523 int time_to_string(double val, const std::string &calendar,
524  const std::string &units, const std::string &format, std::string &date);
525 
526 /** build random access data structures for an indexed table. the index column
527  * gives each entity a unique id. the index is used to identify rows that
528  * belong in the entity. it is assumed that an entity occupies consecutive rows.
529  * the returns are: n_entities, the number of entities found; counts, the
530  * number of rows used by each entity; offsets, the starting row of each
531  * entity; ids, a new set of ids for the entities starting from 0
532  */
533 template <typename int_t>
535 void get_table_offsets(const int_t *index, unsigned long n_rows,
536  unsigned long &n_entities, std::vector<unsigned long> &counts,
537  std::vector<unsigned long> &offsets, std::vector<unsigned long> &ids)
538 {
539  // count unique number of steps and compute an array index
540  // from each time step.
541  n_entities = 1;
542  ids.resize(n_rows);
543  unsigned long n_m1 = n_rows - 1;
544  for (unsigned long i = 0; i < n_m1; ++i)
545  {
546  ids[i] = n_entities - 1;
547  if (index[i] != index[i+1])
548  ++n_entities;
549  }
550  ids[n_m1] = n_entities - 1;
551 
552  // compute num storms in each step
553  counts.resize(n_entities);
554  unsigned long q = 0;
555  for (unsigned long i = 0; i < n_entities; ++i)
556  {
557  counts[i] = 1;
558  while ((q < n_m1) && (index[q] == index[q+1]))
559  {
560  ++counts[i];
561  ++q;
562  }
563  ++q;
564  }
565 
566  // compute the offset to the first storm in each step
567  offsets.resize(n_entities);
568  offsets[0] = 0;
569  for (unsigned long i = 1; i < n_entities; ++i)
570  offsets[i] = offsets[i-1] + counts[i-1];
571 }
572 
573 /** 0th order (nearest neighbor) interpolation for nodal data on a stretched
574  * Cartesian mesh. This overload implements the general 3D case.
575  * cx, cy, cz is the location to interpolate to
576  * p_x, p_y, p_z array arrays containing the source coordinates with extents
577  * [0, ihi, 0, jhi, 0, khi]
578  * p_data is the field to interpolate from
579  * val is the result
580  * returns 0 if successful, an error occurs if cx, cy, cz is outside of the
581  * source coordinate system
582  */
583 template<typename CT, typename DT>
585 int interpolate_nearest(CT cx, CT cy, CT cz,
586  const CT *p_x, const CT *p_y, const CT *p_z,
587  const DT *p_data, unsigned long ihi, unsigned long jhi,
588  unsigned long khi, unsigned long nx, unsigned long nxy,
589  DT &val)
590 {
591  // get i,j of node less than cx,cy
592  unsigned long i = 0;
593  unsigned long j = 0;
594  unsigned long k = 0;
595 
596  if ((ihi && teca_coordinate_util::index_of(p_x, 0, ihi, cx, true, i))
597  || (jhi && teca_coordinate_util::index_of(p_y, 0, jhi, cy, true, j))
598  || (khi && teca_coordinate_util::index_of(p_z, 0, khi, cz, true, k)))
599  {
600  // cx,cy,cz is outside the coordinate axes
601  return -1;
602  }
603 
604  // get i,j of node greater than cx,cy
605  unsigned long ii = std::min(i + 1, ihi);
606  unsigned long jj = std::min(j + 1, jhi);
607  unsigned long kk = std::min(k + 1, khi);
608 
609  // get index of nearest node
610  unsigned long p = (cx - p_x[i]) <= (p_x[ii] - cx) ? i : ii;
611  unsigned long q = (cy - p_y[j]) <= (p_y[jj] - cy) ? j : jj;
612  unsigned long r = (cz - p_z[k]) <= (p_z[kk] - cz) ? k : kk;
613 
614  // assign value from nearest node
615  val = p_data[p + nx*q + nxy*r];
616  return 0;
617 }
618 
619 /** 0th order (nearest neighbor) interpolation for nodal data on a stretched
620  * Cartesian mesh. This overload implements the special case where both source
621  * and target mesh data are in a 2D x-y plane using fewer operations than the
622  * general 3D implementation.
623  * cx, cy, cz is the location to interpolate to
624  * p_x, p_y, p_z array arrays containing the source coordinates with extents
625  * [0, ihi, 0, jhi, 0, khi]
626  * p_data is the field to interpolate from
627  * val is the result
628  * returns 0 if successful, an error occurs if cx, cy, cz is outside of the
629  * source coordinate system
630  */
631 template<typename coord_t, typename data_t>
633 int interpolate_nearest(coord_t cx, coord_t cy, const coord_t *p_x,
634  const coord_t *p_y, const data_t *p_data, unsigned long ihi,
635  unsigned long jhi, unsigned long nx, data_t &val)
636 {
637  // get i,j of node less than cx,cy
638  unsigned long i = 0;
639  unsigned long j = 0;
640 
641  if ((ihi && teca_coordinate_util::index_of(p_x, 0, ihi, cx, true, i))
642  || (jhi && teca_coordinate_util::index_of(p_y, 0, jhi, cy, true, j)))
643  {
644  // cx,cy is outside the coordinate axes
645  return -1;
646  }
647 
648  // get i,j of node greater than cx,cy
649  unsigned long ii = std::min(i + 1, ihi);
650  unsigned long jj = std::min(j + 1, jhi);
651 
652  // get index of nearest node
653  unsigned long p = (cx - p_x[i]) <= (p_x[ii] - cx) ? i : ii;
654  unsigned long q = (cy - p_y[j]) <= (p_y[jj] - cy) ? j : jj;
655 
656  // assign value from nearest node
657  val = p_data[p + nx*q];
658 
659  return 0;
660 }
661 
662 /** 1st order (linear) interpolation for nodal data on stretched Cartesian
663  * mesh. This overload implements the general 3D case.
664  * cx, cy, cz is the location to interpolate to
665  * p_x, p_y, p_z array arrays containing the source coordinates with extents
666  * [0, ihi, 0, jhi, 0, khi]
667  * p_data is the field to interpolate from
668  * val is the result
669  * returns 0 if successful, an error occurs if cx, cy, cz is outside of the
670  * source coordinate system
671  */
672 template<typename CT, typename DT>
674 int interpolate_linear(CT cx, CT cy, CT cz,
675  const CT *p_x, const CT *p_y, const CT *p_z,
676  const DT *p_data, unsigned long ihi, unsigned long jhi,
677  unsigned long khi, unsigned long nx, unsigned long nxy,
678  DT &val)
679 {
680  // get i,j of node less than cx,cy
681  unsigned long i = 0;
682  unsigned long j = 0;
683  unsigned long k = 0;
684 
685  if ((ihi && teca_coordinate_util::index_of(p_x, 0, ihi, cx, true, i))
686  || (jhi && teca_coordinate_util::index_of(p_y, 0, jhi, cy, true, j))
687  || (khi && teca_coordinate_util::index_of(p_z, 0, khi, cz, true, k)))
688  {
689  // cx,cy,cz is outside the coordinate axes
690  return -1;
691  }
692 
693  // get i,j of node greater than cx,cy,cz
694  unsigned long ii = std::min(i + 1, ihi);
695  unsigned long jj = std::min(j + 1, jhi);
696  unsigned long kk = std::min(k + 1, khi);
697 
698  // compute weights
699  CT wx = ii == i ? 0 : (cx - p_x[i])/(p_x[ii] - p_x[i]);
700  CT wy = jj == j ? 0 : (cy - p_y[j])/(p_y[jj] - p_y[j]);
701  CT wz = kk == k ? 0 : (cz - p_z[k])/(p_z[kk] - p_z[k]);
702 
703  CT vx = CT(1) - wx;
704  CT vy = CT(1) - wy;
705  CT vz = CT(1) - wz;
706 
707  // interpolate
708  val = vx*vy*vz*p_data[ i + j*nx + k*nxy]
709  + wx*vy*vz*p_data[ii + j*nx + k*nxy]
710  + wx*wy*vz*p_data[ii + jj*nx + k*nxy]
711  + vx*wy*vz*p_data[ i + jj*nx + k*nxy]
712  + vx*vy*wz*p_data[ i + j*nx + kk*nxy]
713  + wx*vy*wz*p_data[ii + j*nx + kk*nxy]
714  + wx*wy*wz*p_data[ii + jj*nx + kk*nxy]
715  + vx*wy*wz*p_data[ i + jj*nx + kk*nxy];
716 
717  return 0;
718 }
719 
720 /** 1st order (linear) interpolation for nodal data on stretched Cartesian mesh.
721  * This overload implements the special case where both source and target data
722  * are in a 2D x-y plane using fewer operations than the general 3D
723  * implementation.
724  * cx, cy, cz is the location to interpolate to
725  * p_x, p_y, p_z array arrays containing the source coordinates with extents
726  * [0, ihi, 0, jhi, 0, khi]
727  * p_data is the field to interpolate from
728  * val is the result
729  * returns 0 if successful, an error occurs if cx, cy, cz is outside of the
730  * source coordinate system
731  */
732 template<typename CT, typename DT>
734 int interpolate_linear(CT cx, CT cy, const CT *p_x, const CT *p_y,
735  const DT *p_data, unsigned long ihi, unsigned long jhi,
736  unsigned long nx, DT &val)
737 {
738  // get i,j of node less than cx,cy
739  unsigned long i = 0;
740  unsigned long j = 0;
741 
742  if ((ihi && teca_coordinate_util::index_of(p_x, 0, ihi, cx, true, i))
743  || (jhi && teca_coordinate_util::index_of(p_y, 0, jhi, cy, true, j)))
744  {
745  // cx,cy is outside the coordinate axes
746  return -1;
747  }
748 
749  // get i,j of node greater than cx,cy
750  unsigned long ii = std::min(i + 1, ihi);
751  unsigned long jj = std::min(j + 1, jhi);
752 
753  // compute weights
754  CT wx = ii == i ? 0 : (cx - p_x[i])/(p_x[ii] - p_x[i]);
755  CT wy = jj == j ? 0 : (cy - p_y[j])/(p_y[jj] - p_y[j]);
756 
757  CT vx = CT(1) - wx;
758  CT vy = CT(1) - wy;
759 
760  // interpolate
761  val = vx*vy*p_data[ i + j*nx]
762  + wx*vy*p_data[ii + j*nx]
763  + wx*wy*p_data[ii + jj*nx]
764  + vx*wy*p_data[ i + jj*nx];
765 
766  return 0;
767 }
768 
769 /// A functor templated on order of accuracy for above Cartesian mesh interpolants
770 template<int> struct TECA_EXPORT interpolate_t;
771 
772 /// Zero'th order interpolant specialization
773 template<> struct interpolate_t<0>
774 {
775  // 3D
776  template<typename CT, typename DT>
777  int operator()(CT tx, CT ty, CT tz, const CT *sx, const CT *sy,
778  const CT *sz, const DT *sa, unsigned long ihi, unsigned long jhi,
779  unsigned long khi, unsigned long nx, unsigned long nxy, DT &ta)
780  {
782  sx,sy,sz,sa, ihi,jhi,khi, nx,nxy, ta);
783  }
784 
785  // 2D x-y plane
786  template<typename CT, typename DT>
787  int operator()(CT tx, CT ty, const CT *sx, const CT *sy,
788  const DT *sa, unsigned long ihi, unsigned long jhi,
789  unsigned long nx, DT &ta)
790  {
792  sx,sy,sa, ihi,jhi, nx, ta);
793  }
794 };
795 
796 /// First order interpolant specialization
797 template<> struct interpolate_t<1>
798 {
799  // 3D
800  template<typename CT, typename DT>
801  int operator()(CT tx, CT ty, CT tz, const CT *sx, const CT *sy,
802  const CT *sz, const DT *sa, unsigned long ihi, unsigned long jhi,
803  unsigned long khi, unsigned long nx,unsigned long nxy, DT &ta)
804  {
806  sx,sy,sz,sa, ihi,jhi,khi, nx,nxy, ta);
807  }
808 
809  // 2D x-y plane
810  template<typename CT, typename DT>
811  int operator()(CT tx, CT ty, const CT *sx, const CT *sy,
812  const DT *sa, unsigned long ihi, unsigned long jhi,
813  unsigned long nx, DT &ta)
814  {
816  sx,sy,sa, ihi,jhi, nx, ta);
817  }
818 };
819 
820 /// return 0 if the centering is one of the values defined in teca_array_attributes
822 int validate_centering(int centering);
823 
824 /// convert from a cell extent to a face, edge or point centered extent
825 template <typename num_t>
827 int convert_cell_extent(num_t *extent, int centering)
828 {
829  switch (centering)
830  {
831  case teca_array_attributes::invalid_value:
832  TECA_ERROR("detected invalid_value in centering")
833  return -1;
834  break;
835  case teca_array_attributes::cell_centering:
836  break;
837  case teca_array_attributes::x_face_centering:
838  extent[1] += 1;
839  break;
840  case teca_array_attributes::y_face_centering:
841  extent[3] += 1;
842  break;
843  case teca_array_attributes::z_face_centering:
844  extent[5] += 1;
845  break;
846  case teca_array_attributes::x_edge_centering:
847  extent[3] += 1;
848  extent[5] += 1;
849  break;
850  case teca_array_attributes::y_edge_centering:
851  extent[1] += 1;
852  extent[5] += 1;
853  break;
854  case teca_array_attributes::z_edge_centering:
855  extent[1] += 1;
856  extent[3] += 1;
857  break;
858  case teca_array_attributes::point_centering:
859  extent[1] += 1;
860  extent[3] += 1;
861  extent[5] += 1;
862  break;
863  case teca_array_attributes::no_centering:
864  break;
865  default:
866  TECA_ERROR("this centering is undefined " << centering)
867  return -1;
868  }
869  return 0;
870 }
871 
872 /** Given Cartesian mesh metadata extract whole_extent and bounds
873  * if bounds metadata is not already present then it is initialized
874  * from coordinate arrays. It's an error if whole_extent or coordinate
875  * arrays are not present. return zero if successful.
876  */
879  unsigned long *whole_extent, double *bounds);
880 
881 /// get the mesh's bounds from the coordinate axis arrays
885  double *bounds);
886 
887 /** Check that one Cartesian region covers the other coordinates must be in
888  * ascending order. assumes that both regions are specified in ascending order.
889  */
890 template <typename num_t>
892 int covers_ascending(const num_t *whole, const num_t *part)
893 {
894  if ((part[0] >= whole[0]) && (part[0] <= whole[1]) &&
895  (part[1] >= whole[0]) && (part[1] <= whole[1]) &&
896  (part[2] >= whole[2]) && (part[2] <= whole[3]) &&
897  (part[3] >= whole[2]) && (part[3] <= whole[3]) &&
898  (part[4] >= whole[4]) && (part[4] <= whole[5]) &&
899  (part[5] >= whole[4]) && (part[5] <= whole[5]))
900  return 1;
901  return 0;
902 }
903 
904 /** Check that one Cartesian region covers the other, taking into account the
905  * order of the coordinates. assumes that the regions are specified in the same
906  * orientation.
907  */
908 template <typename num_t>
910 int covers(const num_t *whole, const num_t *part)
911 {
912  bool x_ascend = whole[0] <= whole[1];
913  bool y_ascend = whole[2] <= whole[3];
914  bool z_ascend = whole[4] <= whole[5];
915  if (((x_ascend &&
916  (part[0] >= whole[0]) && (part[0] <= whole[1]) &&
917  (part[1] >= whole[0]) && (part[1] <= whole[1])) ||
918  (!x_ascend &&
919  (part[0] <= whole[0]) && (part[0] >= whole[1]) &&
920  (part[1] <= whole[0]) && (part[1] >= whole[1]))) &&
921  ((y_ascend &&
922  (part[2] >= whole[2]) && (part[2] <= whole[3]) &&
923  (part[3] >= whole[2]) && (part[3] <= whole[3])) ||
924  (!y_ascend &&
925  (part[2] <= whole[2]) && (part[2] >= whole[3]) &&
926  (part[3] <= whole[2]) && (part[3] >= whole[3]))) &&
927  ((z_ascend &&
928  (part[4] >= whole[4]) && (part[4] <= whole[5]) &&
929  (part[5] >= whole[4]) && (part[5] <= whole[5])) ||
930  (!z_ascend &&
931  (part[4] <= whole[4]) && (part[4] >= whole[5]) &&
932  (part[5] <= whole[4]) && (part[5] >= whole[5]))))
933  return 1;
934  return 0;
935 }
936 
937 /** check that two Cartesian regions have the same orientation ie they are
938  * either both specified in ascending or descending order.
939  */
940 template <typename num_t>
942 int same_orientation(const num_t *whole, const num_t *part)
943 {
944  if ((((whole[0] <= whole[1]) && (part[0] <= part[1])) ||
945  ((whole[0] >= whole[1]) && (part[0] >= part[1]))) &&
946  (((whole[2] <= whole[3]) && (part[2] <= part[3])) ||
947  ((whole[2] >= whole[3]) && (part[2] >= part[3]))) &&
948  (((whole[4] <= whole[5]) && (part[4] <= part[5])) ||
949  ((whole[4] >= whole[5]) && (part[4] >= part[5]))))
950  return 1;
951  return 0;
952 }
953 
954 /** where array dimensions specified by nx_max, ny_max, and nz_max are 1, and
955  * the extent would be out of bounds, set the extent to [0, 0]. If verbose is
956  * set, a warning is reported when the extent was clamped in one or more
957  * directions. The return is non zero if any direction was clamped and 0
958  * otherwise.
959  */
961 int clamp_dimensions_of_one(unsigned long nx_max, unsigned long ny_max,
962  unsigned long nz_max, unsigned long *extent, bool verbose);
963 
964 /** Return 0 if the passed extent does not exceed array dimensions specified in
965  * nx_max, ny_max, and nz_max. If verbose is set, an error is reported via
966  * TECA_ERROR when the extent would be out of bounds.
967  */
969 int validate_extent(unsigned long nx_max, unsigned long ny_max,
970  unsigned long nz_max, unsigned long *extent, bool verbose);
971 
972 
973 /// compares a set of arrays against a reference array
975 {
976 public:
977  /// set the array to which others will be compared to
978  void set_reference_array(const std::string &a_source,
979  const std::string &a_name, const std::string a_units,
980  const const_p_teca_variant_array &a_array);
981 
982  /// add an array to check against the reference
983  void append_array(const std::string &a_source,
984  const std::string &a_name, const std::string &a_units,
985  const const_p_teca_variant_array &a_array);
986 
987  /// error codes potentially returned from ::validate
988  enum {no_error = 0,
989  invalid_value = 1,
990  length_missmatch = 2,
991  type_missmatch = 3,
992  value_missmatch = 4,
993  unsupported_type = 5,
994  units_missmatch = 6
995  };
996 
997  /** Compare all the arrays in the collection against the reference returns
998  * 0 if all arrays in the collection are equal to the reference. When an
999  * array does not compare equal to the reference array a descritpion
1000  * explaining why is returned in errorStr.
1001  */
1002  int validate(const std::string &a_descriptor,
1003  double a_abs_tol, double a_rel_tol,
1004  std::string &errorStr);
1005 
1006 private:
1007  const_p_teca_variant_array m_reference;
1008  std::string m_reference_source;
1009  std::string m_reference_name;
1010  std::string m_reference_units;
1011 
1012  std::vector<const_p_teca_variant_array> m_arrays;
1013  std::vector<std::string> m_array_sources;
1014  std::vector<std::string> m_array_names;
1015  std::vector<std::string> m_array_units;
1016 };
1017 
1018 /// Check that cooridnate arrays from different sources match a refrence array
1019 /** Compares names, units, and values of coordinate axis arrays.
1020  */
1022 {
1023 public:
1025  m_absolute_tolerance(equal_tt<float>::absTol()),
1026  m_relative_tolerance(equal_tt<float>::relTol())
1027  {}
1028 
1029  /** Adds a time axis to validate. if provides_time is true then the axis
1030  * becomes the reference to which all others are compared. returns 0 if
1031  * necessary metadata was present and non zero if the necessary information
1032  * was not present.
1033  */
1034  int add_time_axis(const std::string &source,
1035  const teca_metadata &coords, const teca_metadata &atts,
1036  bool provides_time);
1037 
1038  /** Adds anx-coordinate axis to validate. if provides_geometry is true then
1039  * the axis becomes the reference to which all others are compared. returns
1040  * 0 if necessary metadata was present and non zero if the necessary
1041  * information was not present.
1042  */
1043  int add_x_coordinate_axis(const std::string &source,
1044  const teca_metadata &coords, const teca_metadata &atts,
1045  bool provides_geometry);
1046 
1047  /** Adds anx-coordinate axis to validate. if provides_geometry is true then
1048  * the axis becomes the reference to which all others are compared. returns
1049  * 0 if necessary metadata was present and non zero if the necessary
1050  * information was not present.
1051  */
1052  int add_y_coordinate_axis(const std::string &source,
1053  const teca_metadata &coords, const teca_metadata &atts,
1054  bool provides_geometry);
1055 
1056  /** Adds anx-coordinate axis to validate. if provides_geometry is true then
1057  * the axis becomes the reference to which all others are compared. returns
1058  * 0 if necessary metadata was present and non zero if the necessary
1059  * information was not present.
1060  */
1061  int add_z_coordinate_axis(const std::string &source,
1062  const teca_metadata &coords, const teca_metadata &atts,
1063  bool provides_geometry);
1064 
1065  /** runs the validation. returns 0 if all of the stored coordinate axes are
1066  * equal to the reference axes. When an array does not compare equal to the
1067  * reference array a descritpion explaining why is returned in errorStr.
1068  */
1069  int validate_spatial_coordinate_axes(std::string &errorStr);
1070 
1071  /** runs the validation. returns 0 if all of the stored time axes are
1072  * equal to the reference axis. When an array does not compare equal to the
1073  * reference array a descritpion explaining why is returned in errorStr.
1074  */
1075  int validate_time_axis(std::string &errorStr);
1076 
1077 private:
1078  double m_absolute_tolerance;
1079  double m_relative_tolerance;
1084 };
1085 
1086 /** a copy-assignable type for 3D Cartesian index space extents of the form:
1087  * [i0, i1, j0, j1, k0, k1]
1088  */
1089 using spatial_extent_t = std::array<unsigned long, 6>;
1090 
1091 /** a copy-assignable type for temporal index space extents of the form:
1092  * [t0, t1]
1093  */
1094 using temporal_extent_t = std::array<unsigned long, 2>;
1095 
1096 /// converts a std::array to a std:vector
1097 template <typename T, size_t N>
1098 std::vector<T> as_vector(const std::array<T,N> &arr)
1099 {
1100  return std::vector<T>(arr.begin(), arr.end());
1101 }
1102 
1103 /// converts a std::vector to a std::array
1104 template <typename T, size_t N>
1105 std::array<T,N> as_array(const std::vector<T> &vec)
1106 {
1107  std::array<T,N> arr;
1108  size_t m = vec.size();
1109  for (size_t i = 0; i < N && i < m; ++i)
1110  arr[i] = vec[i];
1111  return arr;
1112 }
1113 
1114 /** converts a vector holding a Cartesian index space extent of the form
1115  * [i0, i1, j0, j1, k0, k1] to a spatial_extent_t
1116  */
1117 template <typename T>
1118 spatial_extent_t as_spatial_extent(const std::vector<T> &vec)
1119 {
1120  return as_array<T,6>(vec);
1121 }
1122 
1123 /** converts a vector holding a time extent of the form
1124  * [t0, t1] to a temporal_extent_t
1125  */
1126 template <typename T>
1127 spatial_extent_t as_temporal_extent(const std::vector<T> &vec)
1128 {
1129  return as_array<T,2>(vec);
1130 }
1131 
1132 /** converts an array holding a Cartesian index space extent of the form
1133  * [i0, i1, j0, j1, k0, k1] to a spatial_extent_t
1134  */
1135 template <typename T>
1137 {
1138  return {arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]};
1139 }
1140 
1141 
1142 /** split block 1 into 2 blocks in the d direction. block1 is modified in place
1143  * and the new block is returned in block 2. return 1 if the split succeeded
1144  * and 0 if it failed.
1145  */
1147 int split(spatial_extent_t &block_1, spatial_extent_t &block_2,
1148  int split_dir, unsigned long min_size);
1149 
1150 /** given an input extent, partition it in into a set of n disjoint blocks of
1151  * approximately the same size covering the input extent.
1152  *
1153  * @param[in] extent the Cartesian iondex space extent top partition
1154  * @param[in] n_blocks the desired numberof partitions
1155  * @param[in] split_x if zero skip splitting in the x-direction
1156  * @param[in] split_y if zero skip splitting in the y-direction
1157  * @param[in] split_z if zero skip splitting in the z-direction
1158  * @param[in] min_size_x sets the minimum block size in the x-direction
1159  * @param[in] min_size_y sets the minimum block size in the y-direction
1160  * @param[in] min_size_z sets the minimum block size in the z-direction
1161  * @param[out] blocks the set of n blocks covering the input extent
1162  *
1163  * @returns 0 if the input extent could be partitioned into the requested
1164  * number of blocks.
1165  */
1167 int partition(const spatial_extent_t &extent, unsigned int n_blocks,
1168  int split_x, int split_y, int split_z, unsigned long min_size_x,
1169  unsigned long min_size_y, unsigned long min_size_z,
1170  std::deque<spatial_extent_t> &blocks);
1171 
1172 /** Given an inclusive range of time steps [step_0 step_1] partition it into a
1173  * set of disjoint blocks covering the input range. The partitioning algorithm
1174  * is controled by either specifying the number of blocks or the block size.
1175  * Set one of these parameters to the desired value and the other parameter to
1176  * 0.
1177  *
1178  * @param[in] temporal_extent the temporal extent to partition
1179  * @param[in] n_temporal_blocks the desired number of blocks or 0 if specifying
1180  * the block size. Note: the block size that was
1181  * used is returned by the block_size argument.
1182  * @param[in] temporal_block_size the desired size of the blocks or 0 if
1183  * specifying the number of blocks.
1184  * @param[out] temporal_blocks the partitioning
1185  *
1186  * @retruns 0 if the partitioning was successful.
1187  */
1189 int partition(const temporal_extent_t &temporal_extent,
1190  long n_temporal_blocks, long temporal_block_size,
1191  std::vector<temporal_extent_t> &temporal_blocks);
1192 
1193 /** Given a time step and a vector of step extents find the index of the extent
1194  * that contains the step.
1195  *
1196  * @param[in] step the step to find
1197  * @param[in] step_extents an ordered list of time step extents [t0, t1]
1198  * @param[out] index the index into the vector pointing to the extent that
1199  * contains the step.
1200 
1201  * @returns non-zero if the step was not contained by any of the extents
1202  */
1205  const std::vector<std::pair<long, long>> &step_extents,
1206  long &index);
1207 
1208 /** Computes the intersection of two 2D Cartesian tiles. If the intersection is
1209  * empty the low coordinate is above the high coordinate. The tiles are specified
1210  * in the form [i0, i1, j0, j1].
1211  *
1212  * @param[out] int_tile the intersection
1213  * @param[in] left_tile the first of the tiles to intersect
1214  * @param[in] right_tile the second of the tiles to intersect
1215  *
1216  * @returns a reference to the intersection
1217  */
1218 template <typename coord_t>
1220 coord_t &intersect_tiles(coord_t &int_tile,
1221  const coord_t &left_tile, const coord_t &right_tile)
1222 {
1223  int_tile[0] = std::max(left_tile[0], right_tile[0]);
1224  int_tile[1] = std::min(left_tile[1], right_tile[1]);
1225  int_tile[2] = std::max(left_tile[2], right_tile[2]);
1226  int_tile[3] = std::min(left_tile[3], right_tile[3]);
1227  return int_tile;
1228 }
1229 
1230 /** returns true if the 2D Cartesian tile is empty. An empty tile has for any
1231  * dimension the low coordinate larger than the high coordinate
1232  */
1233 template <typename coord_t>
1235 bool empty_tile(const coord_t &tile)
1236 {
1237  return (tile[0] > tile[1]) || (tile[2] > tile[3]);
1238 }
1239 
1240 }
1241 #endif
Check that cooridnate arrays from different sources match a refrence array.
Definition: teca_coordinate_util.h:1022
int add_x_coordinate_axis(const std::string &source, const teca_metadata &coords, const teca_metadata &atts, bool provides_geometry)
int add_y_coordinate_axis(const std::string &source, const teca_metadata &coords, const teca_metadata &atts, bool provides_geometry)
int add_time_axis(const std::string &source, const teca_metadata &coords, const teca_metadata &atts, bool provides_time)
int validate_spatial_coordinate_axes(std::string &errorStr)
int add_z_coordinate_axis(const std::string &source, const teca_metadata &coords, const teca_metadata &atts, bool provides_geometry)
compares a set of arrays against a reference array
Definition: teca_coordinate_util.h:975
void append_array(const std::string &a_source, const std::string &a_name, const std::string &a_units, const const_p_teca_variant_array &a_array)
add an array to check against the reference
void set_reference_array(const std::string &a_source, const std::string &a_name, const std::string a_units, const const_p_teca_variant_array &a_array)
set the array to which others will be compared to
int validate(const std::string &a_descriptor, double a_abs_tol, double a_rel_tol, std::string &errorStr)
A generic container for meta data in the form of name=value pairs.
Definition: teca_metadata.h:22
hamr::buffer_allocator allocator
allocator types
Definition: teca_variant_array.h:46
TECA_EXPORT int date(double val, int *year, int *month, int *day, int *hour, int *minute, double *second, const char *dataunits, const char *calendar_name)
Codes dealing with operations on coordinate systems.
Definition: teca_coordinate_util.h:37
TECA_EXPORT bool equal(const const_p_teca_variant_array &array1, const const_p_teca_variant_array &array2, double absTol, double relTol, int &errorNo, std::string &errorStr)
TECA_EXPORT int interpolate_linear(CT cx, CT cy, const CT *p_x, const CT *p_y, const DT *p_data, unsigned long ihi, unsigned long jhi, unsigned long nx, DT &val)
Definition: teca_coordinate_util.h:734
TECA_EXPORT int validate_centering(int centering)
return 0 if the centering is one of the values defined in teca_array_attributes
std::array< unsigned long, 2 > temporal_extent_t
Definition: teca_coordinate_util.h:1094
TECA_EXPORT int split(spatial_extent_t &block_1, spatial_extent_t &block_2, int split_dir, unsigned long min_size)
TECA_EXPORT void get_table_offsets(const int_t *index, unsigned long n_rows, unsigned long &n_entities, std::vector< unsigned long > &counts, std::vector< unsigned long > &offsets, std::vector< unsigned long > &ids)
Definition: teca_coordinate_util.h:535
TECA_EXPORT int partition(const temporal_extent_t &temporal_extent, long n_temporal_blocks, long temporal_block_size, std::vector< temporal_extent_t > &temporal_blocks)
TECA_EXPORT int convert_cell_extent(num_t *extent, int centering)
convert from a cell extent to a face, edge or point centered extent
Definition: teca_coordinate_util.h:827
TECA_EXPORT int get_cartesian_mesh_bounds(const const_p_teca_variant_array x, const const_p_teca_variant_array y, const const_p_teca_variant_array z, double *bounds)
get the mesh's bounds from the coordinate axis arrays
TECA_EXPORT int interpolate_nearest(CT cx, CT cy, CT cz, const CT *p_x, const CT *p_y, const CT *p_z, const DT *p_data, unsigned long ihi, unsigned long jhi, unsigned long khi, unsigned long nx, unsigned long nxy, DT &val)
Definition: teca_coordinate_util.h:585
TECA_EXPORT int bounds_to_extent(const double *bounds, const coord_t *px, unsigned long nx, unsigned long *extent)
Definition: teca_coordinate_util.h:425
TECA_EXPORT int index_of(const const_p_teca_cartesian_mesh &mesh, T x, T y, T z, unsigned long &i, unsigned long &j, unsigned long &k)
Definition: teca_coordinate_util.h:469
TECA_EXPORT int time_step_of(const const_p_teca_variant_array &time, bool lower, bool clamp, const std::string &calendar, const std::string &units, const std::string &date, unsigned long &step)
spatial_extent_t as_spatial_extent(const T arr[6])
Definition: teca_coordinate_util.h:1136
std::vector< T > as_vector(const std::array< T, N > &arr)
converts a std::array to a std:vector
Definition: teca_coordinate_util.h:1098
TECA_EXPORT int same_orientation(const num_t *whole, const num_t *part)
Definition: teca_coordinate_util.h:942
TECA_EXPORT bool empty_tile(const coord_t &tile)
Definition: teca_coordinate_util.h:1235
TECA_EXPORT int clamp_dimensions_of_one(unsigned long nx_max, unsigned long ny_max, unsigned long nz_max, unsigned long *extent, bool verbose)
spatial_extent_t as_temporal_extent(const std::vector< T > &vec)
Definition: teca_coordinate_util.h:1127
std::array< T, N > as_array(const std::vector< T > &vec)
converts a std::vector to a std::array
Definition: teca_coordinate_util.h:1105
TECA_EXPORT int interpolate_nearest(coord_t cx, coord_t cy, const coord_t *p_x, const coord_t *p_y, const data_t *p_data, unsigned long ihi, unsigned long jhi, unsigned long nx, data_t &val)
Definition: teca_coordinate_util.h:633
TECA_EXPORT int get_cartesian_mesh_extent(const teca_metadata &md, unsigned long *whole_extent, double *bounds)
TECA_EXPORT int index_of(const data_t *data, unsigned long l, unsigned long r, data_t val, bool lower, unsigned long &id)
Definition: teca_coordinate_util.h:266
TECA_EXPORT int find_extent_containing_step(long step, const std::vector< std::pair< long, long >> &step_extents, long &index)
TECA_EXPORT int covers(const num_t *whole, const num_t *part)
Definition: teca_coordinate_util.h:910
TECA_EXPORT int covers_ascending(const num_t *whole, const num_t *part)
Definition: teca_coordinate_util.h:892
struct TECA_EXPORT interpolate_t
A functor templated on order of accuracy for above Cartesian mesh interpolants.
Definition: teca_coordinate_util.h:770
TECA_EXPORT int interpolate_linear(CT cx, CT cy, CT cz, const CT *p_x, const CT *p_y, const CT *p_z, const DT *p_data, unsigned long ihi, unsigned long jhi, unsigned long khi, unsigned long nx, unsigned long nxy, DT &val)
Definition: teca_coordinate_util.h:674
TECA_EXPORT int validate_extent(unsigned long nx_max, unsigned long ny_max, unsigned long nz_max, unsigned long *extent, bool verbose)
TECA_EXPORT coord_t & intersect_tiles(coord_t &int_tile, const coord_t &left_tile, const coord_t &right_tile)
Definition: teca_coordinate_util.h:1220
TECA_EXPORT int time_to_string(double val, const std::string &calendar, const std::string &units, const std::string &format, std::string &date)
std::array< unsigned long, 6 > spatial_extent_t
Definition: teca_coordinate_util.h:1089
p_teca_error_handler error_handler TECA_EXPORT
The global error handler instance.
some functions helping us manipulate teca_variant_array
Definition: teca_variant_array_util.h:14
auto data(V &&... args)
Definition: teca_variant_array_util.h:255
void sync_host_access_any(const array_t &... arrays)
Definition: teca_variant_array_util.h:29
comparator implementing bracket for ascending input arrays
Definition: teca_coordinate_util.h:217
comparator implementing bracket for descending input arrays
Definition: teca_coordinate_util.h:239
Definition: teca_coordinate_util.h:173
traits classes used to get default tolerances for comparing numbers of a given precision.
Definition: teca_coordinate_util.h:51
Greater than or equal to predicate.
Definition: teca_coordinate_util.h:202
Greater than predicate.
Definition: teca_coordinate_util.h:212
Less than or equal to predicate.
Definition: teca_coordinate_util.h:197
Less than predicate.
Definition: teca_coordinate_util.h:207
#define TECA_ERROR(_msg)
Constructs an error message and sends it to the stderr stream.
Definition: teca_common.h:161
#define max_prec(T)
For printing data as ASCII with the maximum supported numerical precision.
Definition: teca_coordinate_util.h:32
std::shared_ptr< const teca_variant_array > const_p_teca_variant_array
Definition: teca_variant_array.h:27