OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GeoRasterTableFunctions.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #ifndef __CUDACC__
20 
21 #include <cmath>
22 #include <vector>
23 
24 #include <tbb/parallel_for.h>
25 #include <tbb/task_arena.h>
26 
28 #include "Shared/StringTransform.h"
30 #include "Shared/math_consts.h"
31 
32 const size_t max_inputs_per_thread = 1000000L;
33 const size_t max_temp_output_entries = 200000000L;
34 
35 // Note that GAUSS_AVG and AVG only valid in context of fill pass
37 
38 RasterAggType get_raster_agg_type(const std::string& agg_type_str,
39  const bool is_fill_agg);
40 
41 template <RasterAggType AggType>
42 struct ComputeAgg {};
43 
44 template <>
46  template <typename Z, typename Z2>
47  void operator()(const Z2& input_z, Z& output_z, const Z2 input_sentinel) const {
48  if (input_z != input_sentinel) {
49  output_z = output_z == std::numeric_limits<Z>::lowest() ? 1 : output_z + 1;
50  }
51  }
52 };
53 
54 template <>
56  template <typename Z, typename Z2>
57  void operator()(const Z2& input_z, Z& output_z, const Z2 input_sentinel) const {
58  if (input_z != input_sentinel && input_z > output_z) {
59  output_z = input_z;
60  }
61  }
62 };
63 
64 template <>
66  template <typename Z, typename Z2>
67  void operator()(const Z2& input_z, Z& output_z, const Z2 input_sentinel) const {
68  if (input_z != input_sentinel && input_z < output_z) {
69  output_z = input_z;
70  }
71  }
72 };
73 
74 template <>
76  template <typename Z, typename Z2>
77  void operator()(const Z2& input_z, Z& output_z, const Z2 input_sentinel) const {
78  if (input_z != input_sentinel) {
79  output_z =
80  output_z == std::numeric_limits<Z>::lowest() ? input_z : output_z + input_z;
81  }
82  }
83 };
84 
85 // Just instansiating so don't have to work conditionally around AVG
86 template <>
88 
89 template <typename T, typename Z>
90 struct GeoRaster {
92  const bool geographic_coords_;
93  const Z null_sentinel_;
94  const bool is_multi_z_;
95  std::vector<Z> z_;
96  std::vector<std::vector<Z>> z_cols_;
97  std::vector<Z> counts_;
98  T x_min_{0};
99  T x_max_{0};
100  T y_min_{0};
101  T y_max_{0};
106  int64_t num_x_bins_{0};
107  int64_t num_y_bins_{0};
108  int64_t num_bins_{0};
113 
114  constexpr static int64_t BIN_OUT_OF_BOUNDS{-1};
115 
116  template <typename T2, typename Z2>
117  GeoRaster(const Column<T2>& input_x,
118  const Column<T2>& input_y,
119  const Column<Z2>& input_z,
120  const RasterAggType raster_agg_type,
121  const double bin_dim_meters,
122  const bool geographic_coords,
123  const bool align_bins_to_zero_based_grid);
124 
125  template <typename T2, typename Z2>
126  GeoRaster(const Column<T2>& input_x,
127  const Column<T2>& input_y,
128  const ColumnList<Z2>& input_z_cols,
129  const std::vector<RasterAggType>& raster_agg_types,
130  const double bin_dim_meters,
131  const bool geographic_coords,
132  const bool align_bins_to_zero_based_grid);
133 
134  template <typename T2, typename Z2>
135  GeoRaster(const Column<T2>& input_x,
136  const Column<T2>& input_y,
137  const Column<Z2>& input_z,
138  const RasterAggType raster_agg_type,
139  const double bin_dim_meters,
140  const bool geographic_coords,
141  const bool align_bins_to_zero_based_grid,
142  const T x_min,
143  const T x_max,
144  const T y_min,
145  const T y_max);
146 
147  inline T get_x_bin(const T input) const {
148  return (input - x_min_) * x_scale_input_to_bin_;
149  }
150 
151  inline T get_y_bin(const T input) const {
152  return (input - y_min_) * y_scale_input_to_bin_;
153  }
154 
155  inline bool is_null(const Z value) const { return value == null_sentinel_; }
156 
157  inline bool is_bin_out_of_bounds(const int64_t x_bin, const int64_t y_bin) const {
158  return (x_bin < 0 || x_bin >= num_x_bins_ || y_bin < 0 || y_bin >= num_y_bins_);
159  }
160 
161  inline std::pair<int64_t, Z> get_bin_idx_and_z_val_for_xy_bin(
162  const int64_t x_bin,
163  const int64_t y_bin) const {
164  if (is_bin_out_of_bounds(x_bin, y_bin)) {
165  return std::make_pair(BIN_OUT_OF_BOUNDS, null_sentinel_);
166  }
167  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
168  return std::make_pair(bin_idx, z_[bin_idx]);
169  }
170 
171  inline int64_t get_bin_idx_for_xy_coords(const T x, const T y) const {
172  if (x < x_min_ || x > x_max_ || y < y_min_ || y > y_max_) {
173  return BIN_OUT_OF_BOUNDS;
174  }
176  }
177 
178  inline std::pair<T, T> get_xy_coords_for_bin_idx(const int64_t bin_idx) const {
179  const auto [x_bin, y_bin] = bin_to_x_y_bin_indexes(bin_idx, num_x_bins_);
180  const T x = x_min_ + (x_bin + 0.5) * x_scale_bin_to_input_;
181  const T y = y_min_ + (y_bin + 0.5) * y_scale_bin_to_input_;
182  return std::make_pair(x, y);
183  }
184 
185  inline Z offset_source_z_from_raster_z(const int64_t source_x_bin,
186  const int64_t source_y_bin,
187  const Z source_z_offset) const;
188 
189  inline Z offset_source_z_from_raster_z(const int64_t source_x_bin,
190  const int64_t source_y_bin,
191  const Z source_z_offset,
192  const int64_t z_col_idx) const;
194 
196 
198 
199  template <typename T2, typename Z2>
200  void compute(const Column<T2>& input_x,
201  const Column<T2>& input_y,
202  const Column<Z2>& input_z,
203  std::vector<Z>& output_z,
204  const RasterAggType raster_agg_type,
205  const size_t max_inputs_per_thread);
206 
208  const int64_t neighborhood_fill_radius,
209  const bool fill_only_nulls,
210  const RasterAggType raster_agg_type = RasterAggType::GAUSS_AVG);
211 
212  void fill_bins_from_neighbors(const int64_t neighborhood_fill_radius,
213  const bool fill_only_nulls,
214  const RasterAggType raster_agg_type,
215  std::vector<Z>& z);
216 
217  bool get_nxn_neighbors_if_not_null(const int64_t x_bin,
218  const int64_t y_bin,
219  const int64_t num_bins_radius,
220  std::vector<Z>& neighboring_bins) const;
221  inline std::pair<Z, Z> calculate_slope_and_aspect_of_cell(
222  const std::vector<Z>& neighboring_cells,
223  const bool compute_slope_in_degrees) const;
225  Column<Z>& aspect,
226  const bool compute_slope_in_degrees) const;
227 
229  Column<T>& output_x,
230  Column<T>& output_y,
231  Column<Z>& output_z,
232  const int64_t band_idx = 0) const;
233 
235  Column<Z>& output_z,
236  const int64_t band_idx) const;
237 
239  Column<T>& output_x,
240  Column<T>& output_y,
241  Column<Array<Z>>& output_z) const;
242 
244  Column<T>& output_x,
245  Column<T>& output_y,
246  Column<Z>& output_z,
247  const int64_t neighborhood_null_fill_radius) const;
248 
249  void setMetadata(TableFunctionManager& mgr) const;
250 
251  private:
252  template <RasterAggType AggType, typename T2, typename Z2>
253  void computeSerialImpl(const Column<T2>& input_x,
254  const Column<T2>& input_y,
255  const Column<Z2>& input_z,
256  std::vector<Z>& output_z);
257 
258  template <RasterAggType AggType>
259  void computeParallelReductionAggImpl(const std::vector<std::vector<Z>>& z_inputs,
260  std::vector<Z>& output_z,
261  const Z agg_sentinel);
262 
263  template <RasterAggType AggType, typename T2, typename Z2>
264  void computeParallelImpl(const Column<T2>& input_x,
265  const Column<T2>& input_y,
266  const Column<Z2>& input_z,
267  std::vector<Z>& output_z,
268  const size_t max_inputs_per_thread);
269 
270  inline Z fill_bin_from_avg_box_neighborhood(const int64_t x_centroid_bin,
271  const int64_t y_centroid_bin,
272  const int64_t bins_radius,
273  std::vector<Z>& z) const;
274 
275  template <RasterAggType AggType>
276  inline Z fill_bin_from_box_neighborhood(const int64_t x_centroid_bin,
277  const int64_t y_centroid_bin,
278  const int64_t bins_radius,
279  const ComputeAgg<AggType>& compute_agg,
280  std::vector<Z>& z) const;
281 
282  template <RasterAggType AggType>
283  void fill_bins_from_box_neighborhood(const int64_t neighborhood_fill_radius,
284  const bool fill_only_nulls,
285  std::vector<Z>& z);
286  void fill_bins_from_gaussian_neighborhood(const int64_t neighborhood_fill_radius,
287  const bool fill_only_nulls,
288  std::vector<Z>& z);
289 };
290 
291 // Allow input types to GeoRaster that are different than class types/output Z type
292 // So we can move everything to the type of T and Z (which can each be either float
293 // or double)
294 template <typename T, typename Z>
295 template <typename T2, typename Z2>
297  const Column<T2>& input_y,
298  const Column<Z2>& input_z,
299  const RasterAggType raster_agg_type,
300  const double bin_dim_meters,
301  const bool geographic_coords,
302  const bool align_bins_to_zero_based_grid)
303  : bin_dim_meters_(bin_dim_meters)
304  , geographic_coords_(geographic_coords)
305  , null_sentinel_(inline_null_value<Z>())
306  , is_multi_z_(false) {
307  auto timer = DEBUG_TIMER(__func__);
308  const int64_t input_size{input_z.size()};
309  if (input_size <= 0) {
310  num_bins_ = 0;
311  num_x_bins_ = 0;
312  num_y_bins_ = 0;
313  return;
314  }
315  const auto min_max_x = get_column_min_max(input_x);
316  const auto min_max_y = get_column_min_max(input_y);
317  x_min_ = min_max_x.first;
318  x_max_ = min_max_x.second;
319  y_min_ = min_max_y.first;
320  y_max_ = min_max_y.second;
321 
322  if (align_bins_to_zero_based_grid && !geographic_coords_) {
323  // For implicit, data-defined bounds, we treat the max of the x and y ranges as
324  // inclusive (closed interval), since if the max of the data in either x/y dimensions
325  // is at the first value of the next bin, values at that max will be discarded if we
326  // don't include the final bin. For exmaple, if the input data (perhaps already binned
327  // with a group by query) goes from 0.0 to 40.0 in both x and y directions, we should
328  // have the last x/y bins cover the range [40.0, 50.0), not [30.0, 40.0)
330  }
331 
333  compute(input_x, input_y, input_z, z_, raster_agg_type, max_inputs_per_thread);
334 }
335 
336 template <typename T, typename Z>
337 template <typename T2, typename Z2>
339  const Column<T2>& input_y,
340  const ColumnList<Z2>& input_z_cols,
341  const std::vector<RasterAggType>& raster_agg_types,
342  const double bin_dim_meters,
343  const bool geographic_coords,
344  const bool align_bins_to_zero_based_grid)
345  : bin_dim_meters_(bin_dim_meters)
346  , geographic_coords_(geographic_coords)
347  , null_sentinel_(inline_null_value<Z>())
348  , is_multi_z_(true) {
349  auto timer = DEBUG_TIMER(__func__);
350  const int64_t input_size{input_x.size()};
351  const int64_t num_z_cols = input_z_cols.numCols();
352  if (num_z_cols != static_cast<int64_t>(raster_agg_types.size())) {
353  throw std::runtime_error("Number of z cols and raster_agg_types do not match.");
354  }
355  if (input_size <= 0) {
356  num_bins_ = 0;
357  num_x_bins_ = 0;
358  num_y_bins_ = 0;
359  return;
360  }
361  z_cols_.resize(num_z_cols);
362  const auto min_max_x = get_column_min_max(input_x);
363  const auto min_max_y = get_column_min_max(input_y);
364  x_min_ = min_max_x.first;
365  x_max_ = min_max_x.second;
366  y_min_ = min_max_y.first;
367  y_max_ = min_max_y.second;
368 
369  if (align_bins_to_zero_based_grid && !geographic_coords_) {
370  // For implicit, data-defined bounds, we treat the max of the x and y ranges as
371  // inclusive (closed interval), since if the max of the data in either x/y dimensions
372  // is at the first value of the next bin, values at that max will be discarded if we
373  // don't include the final bin. For exmaple, if the input data (perhaps already binned
374  // with a group by query) goes from 0.0 to 40.0 in both x and y directions, we should
375  // have the last x/y bins cover the range [40.0, 50.0), not [30.0, 40.0)
377  }
378 
380  for (int64_t z_col_idx = 0; z_col_idx < num_z_cols; ++z_col_idx) {
381  compute(input_x,
382  input_y,
383  input_z_cols[z_col_idx],
384  z_cols_[z_col_idx],
385  raster_agg_types[z_col_idx],
387  }
388 }
389 
390 // Allow input types to GeoRaster that are different than class types/output Z type
391 // So we can move everything to the type of T and Z (which can each be either float
392 // or double)
393 template <typename T, typename Z>
394 template <typename T2, typename Z2>
396  const Column<T2>& input_y,
397  const Column<Z2>& input_z,
398  const RasterAggType raster_agg_type,
399  const double bin_dim_meters,
400  const bool geographic_coords,
401  const bool align_bins_to_zero_based_grid,
402  const T x_min,
403  const T x_max,
404  const T y_min,
405  const T y_max)
406  : bin_dim_meters_(bin_dim_meters)
407  , geographic_coords_(geographic_coords)
408  , null_sentinel_(inline_null_value<Z>())
409  , is_multi_z_(false)
410  , x_min_(x_min)
411  , x_max_(x_max)
412  , y_min_(y_min)
413  , y_max_(y_max) {
414  auto timer = DEBUG_TIMER(__func__);
415  if (align_bins_to_zero_based_grid && !geographic_coords_) {
416  // For explicit, user-defined bounds, we treat the max of the x and y ranges as
417  // exclusive (open interval), since if the user specifies the max x/y as the end of
418  // the bin, they do not intend to add the next full bin For example, if a user
419  // specifies a bin_dim_meters of 10.0 and an x and y range from 0 to 40.0, they almost
420  // assuredly intend for there to be 4 bins in each of the x and y dimensions, with the
421  // last bin of range [30.0, 40.0), not 5 with the final bin's range from [40.0, 50.0)
423  }
425  compute(input_x, input_y, input_z, z_, raster_agg_type, max_inputs_per_thread);
426 }
427 
428 template <typename T, typename Z>
429 inline Z GeoRaster<T, Z>::offset_source_z_from_raster_z(const int64_t source_x_bin,
430  const int64_t source_y_bin,
431  const Z source_z_offset) const {
432  if (is_bin_out_of_bounds(source_x_bin, source_y_bin)) {
433  return null_sentinel_;
434  }
435  const Z terrain_z = z_[x_y_bin_to_bin_index(source_x_bin, source_y_bin, num_x_bins_)];
436  if (terrain_z == null_sentinel_) {
437  return terrain_z;
438  }
439  return terrain_z + source_z_offset;
440 }
441 
442 template <typename T, typename Z>
443 inline Z GeoRaster<T, Z>::offset_source_z_from_raster_z(const int64_t source_x_bin,
444  const int64_t source_y_bin,
445  const Z source_z_offset,
446  const int64_t z_col_idx) const {
447  if (is_bin_out_of_bounds(source_x_bin, source_y_bin)) {
448  return null_sentinel_;
449  }
450  const Z terrain_z =
451  z_cols_[z_col_idx][x_y_bin_to_bin_index(source_x_bin, source_y_bin, num_x_bins_)];
452  if (terrain_z == null_sentinel_) {
453  return terrain_z;
454  }
455  return terrain_z + source_z_offset;
456 }
457 
458 template <typename T, typename Z>
460  x_min_ = std::floor(x_min_ / bin_dim_meters_) * bin_dim_meters_;
461  x_max_ = std::floor(x_max_ / bin_dim_meters_) * bin_dim_meters_ +
462  bin_dim_meters_; // Snap to end of bin
463  y_min_ = std::floor(y_min_ / bin_dim_meters_) * bin_dim_meters_;
464  y_max_ = std::floor(y_max_ / bin_dim_meters_) * bin_dim_meters_ +
465  bin_dim_meters_; // Snap to end of bin
466 }
467 
468 template <typename T, typename Z>
470  x_min_ = std::floor(x_min_ / bin_dim_meters_) * bin_dim_meters_;
471  x_max_ = std::ceil(x_max_ / bin_dim_meters_) * bin_dim_meters_;
472  y_min_ = std::floor(y_min_ / bin_dim_meters_) * bin_dim_meters_;
473  y_max_ = std::ceil(y_max_ / bin_dim_meters_) * bin_dim_meters_;
474 }
475 
476 template <typename T, typename Z>
478  CHECK_GT(bin_dim_meters_, static_cast<T>(0));
479  x_range_ = x_max_ - x_min_;
480  y_range_ = y_max_ - y_min_;
481  if (geographic_coords_) {
482  const T x_centroid = (x_min_ + x_max_) * 0.5;
483  const T y_centroid = (y_min_ + y_max_) * 0.5;
484  x_meters_per_degree_ =
485  distance_in_meters(x_min_, y_centroid, x_max_, y_centroid) / x_range_;
486 
487  y_meters_per_degree_ =
488  distance_in_meters(x_centroid, y_min_, x_centroid, y_max_) / y_range_;
489 
490  num_x_bins_ = x_range_ * x_meters_per_degree_ / bin_dim_meters_;
491  num_y_bins_ = y_range_ * y_meters_per_degree_ / bin_dim_meters_;
492 
493  if (num_x_bins_ < 1 || num_y_bins_ < 1) {
494  throw std::runtime_error("Invalid GeoRaster (" + std::to_string(num_x_bins_) + "x" +
495  std::to_string(num_y_bins_) + " bins)");
496  }
497 
498  x_scale_input_to_bin_ = x_meters_per_degree_ / bin_dim_meters_;
499  y_scale_input_to_bin_ = y_meters_per_degree_ / bin_dim_meters_;
500  x_scale_bin_to_input_ = bin_dim_meters_ / x_meters_per_degree_;
501  y_scale_bin_to_input_ = bin_dim_meters_ / y_meters_per_degree_;
502 
503  } else {
504  num_x_bins_ = x_range_ / bin_dim_meters_;
505  num_y_bins_ = y_range_ / bin_dim_meters_;
506 
507  if (num_x_bins_ < 1 || num_y_bins_ < 1) {
508  throw std::runtime_error("Invalid GeoRaster (" + std::to_string(num_x_bins_) + "x" +
509  std::to_string(num_y_bins_) + " bins)");
510  }
511 
512  x_scale_input_to_bin_ = 1.0 / bin_dim_meters_;
513  y_scale_input_to_bin_ = 1.0 / bin_dim_meters_;
514  x_scale_bin_to_input_ = bin_dim_meters_;
515  y_scale_bin_to_input_ = bin_dim_meters_;
516  }
517  num_bins_ = num_x_bins_ * num_y_bins_;
518 }
519 
520 template <typename T, typename Z>
521 template <RasterAggType AggType, typename T2, typename Z2>
523  const Column<T2>& input_y,
524  const Column<Z2>& input_z,
525  std::vector<Z>& output_z) {
526  auto timer = DEBUG_TIMER(__func__);
527  const int64_t input_size{input_z.size()};
528  const Z agg_sentinel = AggType == RasterAggType::MIN ? std::numeric_limits<Z>::max()
529  : std::numeric_limits<Z>::lowest();
530  output_z.resize(num_bins_, agg_sentinel);
531  ComputeAgg<AggType> compute_agg;
532  for (int64_t sparse_idx = 0; sparse_idx != input_size; ++sparse_idx) {
533  auto const z = input_z[sparse_idx];
534  if constexpr (std::is_same_v<Z2, float> || std::is_same_v<Z2, double>) {
535  if (std::isnan(z) || std::isinf(z)) {
536  continue;
537  }
538  }
539  const int64_t x_bin = get_x_bin(input_x[sparse_idx]);
540  const int64_t y_bin = get_y_bin(input_y[sparse_idx]);
541  if (x_bin < 0 || x_bin >= num_x_bins_ || y_bin < 0 || y_bin >= num_y_bins_) {
542  continue;
543  }
544  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
545  compute_agg(z, output_z[bin_idx], inline_null_value<Z2>());
546  }
547  for (int64_t bin_idx = 0; bin_idx != num_bins_; ++bin_idx) {
548  if (output_z[bin_idx] == agg_sentinel) {
549  output_z[bin_idx] = null_sentinel_;
550  }
551  }
552 }
553 
554 template <typename T, typename Z>
555 template <RasterAggType AggType>
557  const std::vector<std::vector<Z>>& z_inputs,
558  std::vector<Z>& output_z,
559  const Z agg_sentinel) {
560  const size_t num_inputs = z_inputs.size();
561  output_z.resize(num_bins_, agg_sentinel);
562 
563  ComputeAgg<AggType> reduction_agg;
565  tbb::blocked_range<size_t>(0, num_bins_), [&](const tbb::blocked_range<size_t>& r) {
566  const size_t start_idx = r.begin();
567  const size_t end_idx = r.end();
568  for (size_t bin_idx = start_idx; bin_idx != end_idx; ++bin_idx) {
569  for (size_t input_idx = 0; input_idx < num_inputs; ++input_idx) {
570  reduction_agg(z_inputs[input_idx][bin_idx], output_z[bin_idx], agg_sentinel);
571  }
572  }
573  });
574 
575  tbb::parallel_for(tbb::blocked_range<size_t>(0, num_bins_),
576  [&](const tbb::blocked_range<size_t>& r) {
577  const size_t start_idx = r.begin();
578  const size_t end_idx = r.end();
579  for (size_t bin_idx = start_idx; bin_idx != end_idx; ++bin_idx) {
580  if (output_z[bin_idx] == agg_sentinel) {
581  output_z[bin_idx] = null_sentinel_;
582  }
583  }
584  });
585 }
586 
587 template <typename T, typename Z>
588 template <RasterAggType AggType, typename T2, typename Z2>
590  const Column<T2>& input_y,
591  const Column<Z2>& input_z,
592  std::vector<Z>& output_z,
593  const size_t max_inputs_per_thread) {
594  const size_t input_size = input_z.size();
595  const size_t max_thread_count = std::thread::hardware_concurrency();
596  const size_t num_threads_by_input_elements =
597  std::min(max_thread_count,
598  ((input_size + max_inputs_per_thread - 1) / max_inputs_per_thread));
599  const size_t num_threads_by_output_size =
600  std::min(max_thread_count, ((max_temp_output_entries + num_bins_ - 1) / num_bins_));
601  const size_t num_threads =
602  std::min(num_threads_by_input_elements, num_threads_by_output_size);
603  if (num_threads <= 1) {
604  computeSerialImpl<AggType, T2, Z2>(input_x, input_y, input_z, output_z);
605  return;
606  }
607  auto timer = DEBUG_TIMER(__func__);
608 
609  std::vector<std::vector<Z>> per_thread_z_outputs(num_threads);
610  // Fix
611  const Z agg_sentinel = AggType == RasterAggType::MIN ? std::numeric_limits<Z>::max()
612  : std::numeric_limits<Z>::lowest();
613 
614  tbb::parallel_for(tbb::blocked_range<size_t>(0, num_threads),
615  [&](const tbb::blocked_range<size_t>& r) {
616  for (size_t t = r.begin(); t != r.end(); ++t) {
617  per_thread_z_outputs[t].resize(num_bins_, agg_sentinel);
618  }
619  });
620 
621  ComputeAgg<AggType> compute_agg;
622  tbb::task_arena limited_arena(num_threads);
623  limited_arena.execute([&] {
625  tbb::blocked_range<int64_t>(0, input_size),
626  [&](const tbb::blocked_range<int64_t>& r) {
627  const int64_t start_idx = r.begin();
628  const int64_t end_idx = r.end();
629  size_t thread_idx = tbb::this_task_arena::current_thread_index();
630  std::vector<Z>& this_thread_z_output = per_thread_z_outputs[thread_idx];
631 
632  for (int64_t sparse_idx = start_idx; sparse_idx != end_idx; ++sparse_idx) {
633  auto const z = input_z[sparse_idx];
634  if constexpr (std::is_same_v<Z2, float> || std::is_same_v<Z2, double>) {
635  if (std::isnan(z) || std::isinf(z)) {
636  continue;
637  }
638  }
639  const int64_t x_bin = get_x_bin(input_x[sparse_idx]);
640  const int64_t y_bin = get_y_bin(input_y[sparse_idx]);
641  if (x_bin < 0 || x_bin >= num_x_bins_ || y_bin < 0 || y_bin >= num_y_bins_) {
642  continue;
643  }
644  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
645  compute_agg(z, this_thread_z_output[bin_idx], inline_null_value<Z2>());
646  }
647  });
648  });
649 
650  // Reduce
651  if constexpr (AggType == RasterAggType::COUNT) {
652  // Counts can't be counted, they must be summed
653  computeParallelReductionAggImpl<RasterAggType::SUM>(
654  per_thread_z_outputs, output_z, agg_sentinel);
655  } else {
656  computeParallelReductionAggImpl<AggType>(
657  per_thread_z_outputs, output_z, agg_sentinel);
658  }
659 }
660 
661 template <typename T, typename Z>
662 template <typename T2, typename Z2>
664  const Column<T2>& input_y,
665  const Column<Z2>& input_z,
666  std::vector<Z>& output_z,
667  const RasterAggType raster_agg_type,
668  const size_t max_inputs_per_thread) {
669  switch (raster_agg_type) {
670  case RasterAggType::COUNT: {
671  computeParallelImpl<RasterAggType::COUNT, T2, Z2>(
672  input_x, input_y, input_z, output_z, max_inputs_per_thread);
673  break;
674  }
675  case RasterAggType::MIN: {
676  computeParallelImpl<RasterAggType::MIN, T2, Z2>(
677  input_x, input_y, input_z, output_z, max_inputs_per_thread);
678  break;
679  }
680  case RasterAggType::MAX: {
681  computeParallelImpl<RasterAggType::MAX, T2, Z2>(
682  input_x, input_y, input_z, output_z, max_inputs_per_thread);
683  break;
684  }
685  case RasterAggType::SUM: {
686  computeParallelImpl<RasterAggType::SUM, T2, Z2>(
687  input_x, input_y, input_z, output_z, max_inputs_per_thread);
688  break;
689  }
690  case RasterAggType::AVG: {
691  computeParallelImpl<RasterAggType::SUM, T2, Z2>(
692  input_x, input_y, input_z, output_z, max_inputs_per_thread);
693  computeParallelImpl<RasterAggType::COUNT, T2, Z2>(
694  input_x, input_y, input_z, counts_, max_inputs_per_thread);
695  tbb::parallel_for(tbb::blocked_range<size_t>(0, num_bins_),
696  [&](const tbb::blocked_range<size_t>& r) {
697  const size_t start_idx = r.begin();
698  const size_t end_idx = r.end();
699  for (size_t bin_idx = start_idx; bin_idx != end_idx;
700  ++bin_idx) {
701  // counts[bin_idx] > 1 will avoid division for nulls and 1
702  // counts
703  if (counts_[bin_idx] > 1) {
704  output_z[bin_idx] /= counts_[bin_idx];
705  }
706  }
707  });
708  break;
709  }
710  default: {
711  CHECK(false);
712  }
713  }
714 }
715 
716 template <typename T, typename Z>
717 inline Z GeoRaster<T, Z>::fill_bin_from_avg_box_neighborhood(const int64_t x_centroid_bin,
718  const int64_t y_centroid_bin,
719  const int64_t bins_radius,
720  std::vector<Z>& z) const {
721  Z val = 0.0;
722  int32_t count = 0;
723  for (int64_t y_bin = y_centroid_bin - bins_radius;
724  y_bin <= y_centroid_bin + bins_radius;
725  y_bin++) {
726  for (int64_t x_bin = x_centroid_bin - bins_radius;
727  x_bin <= x_centroid_bin + bins_radius;
728  x_bin++) {
729  if (x_bin >= 0 && x_bin < num_x_bins_ && y_bin >= 0 && y_bin < num_y_bins_) {
730  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
731  const Z bin_val = z[bin_idx];
732  if (bin_val != null_sentinel_) {
733  count++;
734  val += bin_val;
735  }
736  }
737  }
738  }
739  return (count == 0) ? null_sentinel_ : val / count;
740 }
741 
742 std::vector<double> generate_1d_gaussian_kernel(const int64_t fill_radius, double sigma);
743 
744 template <typename T, typename Z>
746  const int64_t neighborhood_fill_radius,
747  const bool fill_only_nulls,
748  std::vector<Z>& z) {
749  const double sigma = neighborhood_fill_radius * 2.0 / 6.0;
750  const auto gaussian_kernel =
751  generate_1d_gaussian_kernel(neighborhood_fill_radius, sigma);
752  std::vector<Z> only_nulls_source_z;
753  if (fill_only_nulls) {
754  // Copy z_
755  only_nulls_source_z.resize(z.size());
756  tbb::parallel_for(tbb::blocked_range<int64_t>(0, num_bins_),
757  [&](const tbb::blocked_range<int64_t>& r) {
758  const int64_t end_bin_idx = r.end();
759  for (int64_t bin_idx = r.begin(); bin_idx < end_bin_idx;
760  ++bin_idx) {
761  only_nulls_source_z[bin_idx] = z[bin_idx];
762  }
763  });
764  }
765  auto& source_z = fill_only_nulls ? only_nulls_source_z : z;
766 
767  std::vector<Z> new_z(num_bins_);
769  tbb::blocked_range<int64_t>(0, num_y_bins_),
770  [&](const tbb::blocked_range<int64_t>& r) {
771  const int64_t end_y_bin = r.end();
772  for (int64_t y_start_bin = r.begin(); y_start_bin != end_y_bin; ++y_start_bin) {
773  for (int64_t x_bin = 0; x_bin < num_x_bins_; ++x_bin) {
774  Z val = 0.0;
775  Z sum_weights = 0.0;
776  for (int64_t y_offset = -neighborhood_fill_radius;
777  y_offset <= neighborhood_fill_radius;
778  ++y_offset) {
779  const auto y_bin = y_start_bin + y_offset;
780  if (y_bin >= 0 && y_bin < num_y_bins_) {
781  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
782  const Z bin_val = source_z[bin_idx];
783  if (bin_val != null_sentinel_) {
784  const auto gaussian_weight =
785  gaussian_kernel[y_offset + neighborhood_fill_radius];
786  val += bin_val * gaussian_weight;
787  sum_weights += gaussian_weight;
788  }
789  }
790  }
791  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_start_bin, num_x_bins_);
792  new_z[bin_idx] = sum_weights > 0.0 ? (val / sum_weights) : null_sentinel_;
793  }
794  }
795  });
796  source_z.swap(new_z);
798  tbb::blocked_range<int64_t>(0, num_x_bins_),
799  [&](const tbb::blocked_range<int64_t>& r) {
800  const int64_t end_x_bin = r.end();
801  for (int64_t x_start_bin = r.begin(); x_start_bin != end_x_bin; ++x_start_bin) {
802  for (int64_t y_bin = 0; y_bin < num_y_bins_; ++y_bin) {
803  Z val = 0.0;
804  Z sum_weights = 0.0;
805  for (int64_t x_offset = -neighborhood_fill_radius;
806  x_offset <= neighborhood_fill_radius;
807  ++x_offset) {
808  const auto x_bin = x_start_bin + x_offset;
809  if (x_bin >= 0 && x_bin < num_x_bins_) {
810  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
811  const Z bin_val = source_z[bin_idx];
812  if (bin_val != null_sentinel_) {
813  const auto gaussian_weight =
814  gaussian_kernel[x_offset + neighborhood_fill_radius];
815  val += bin_val * gaussian_weight;
816  sum_weights += gaussian_weight;
817  }
818  }
819  }
820  const int64_t bin_idx = x_y_bin_to_bin_index(x_start_bin, y_bin, num_x_bins_);
821  new_z[bin_idx] = sum_weights > 0.0 ? (val / sum_weights) : null_sentinel_;
822  }
823  }
824  });
825  if (fill_only_nulls) {
826  // Only copy convolved results in new_z back to z for
827  // values in z that are null
828  tbb::parallel_for(tbb::blocked_range<int64_t>(0, num_bins_),
829  [&](const tbb::blocked_range<int64_t>& r) {
830  const int64_t end_bin_idx = r.end();
831  for (int64_t bin_idx = r.begin(); bin_idx < end_bin_idx;
832  ++bin_idx) {
833  if (z[bin_idx] == null_sentinel_) {
834  z[bin_idx] = new_z[bin_idx];
835  }
836  only_nulls_source_z[bin_idx] = z[bin_idx];
837  }
838  });
839  } else {
840  source_z.swap(new_z);
841  }
842 }
843 
844 template <typename T, typename Z>
845 template <RasterAggType AggType>
847  const int64_t x_centroid_bin,
848  const int64_t y_centroid_bin,
849  const int64_t bins_radius,
850  const ComputeAgg<AggType>& compute_agg,
851  std::vector<Z>& z) const {
852  const Z agg_sentinel = AggType == RasterAggType::MIN ? std::numeric_limits<Z>::max()
853  : std::numeric_limits<Z>::lowest();
854  Z val{agg_sentinel};
855  for (int64_t y_bin = y_centroid_bin - bins_radius;
856  y_bin <= y_centroid_bin + bins_radius;
857  y_bin++) {
858  for (int64_t x_bin = x_centroid_bin - bins_radius;
859  x_bin <= x_centroid_bin + bins_radius;
860  x_bin++) {
861  if (x_bin >= 0 && x_bin < num_x_bins_ && y_bin >= 0 && y_bin < num_y_bins_) {
862  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
863  compute_agg(z[bin_idx], val, null_sentinel_);
864  }
865  }
866  }
867  return val == agg_sentinel ? null_sentinel_ : val;
868 }
869 
870 template <typename T, typename Z>
871 template <RasterAggType AggType>
873  const int64_t neighborhood_fill_radius,
874  const bool fill_only_nulls,
875  std::vector<Z>& z) {
876  CHECK(AggType != RasterAggType::GAUSS_AVG); // Should have gone down Gaussian path
877  CHECK(AggType != RasterAggType::AVG); // Should be BOX_AVG for fill pass
878  CHECK(AggType != RasterAggType::INVALID);
879  std::vector<Z> new_z(num_bins_);
880  ComputeAgg<AggType> compute_agg;
881  tbb::parallel_for(tbb::blocked_range<int64_t>(0, num_y_bins_),
882  [&](const tbb::blocked_range<int64_t>& r) {
883  const int64_t end_y_bin = r.end();
884  for (int64_t y_bin = r.begin(); y_bin != end_y_bin; ++y_bin) {
885  for (int64_t x_bin = 0; x_bin < num_x_bins_; ++x_bin) {
886  const int64_t bin_idx =
887  x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
888  const Z z_val = z[bin_idx];
889  if (!fill_only_nulls || z_val == null_sentinel_) {
890  if constexpr (AggType == RasterAggType::BOX_AVG) {
891  new_z[bin_idx] = fill_bin_from_avg_box_neighborhood(
892  x_bin, y_bin, neighborhood_fill_radius, z);
893  } else {
894  new_z[bin_idx] = fill_bin_from_box_neighborhood(
895  x_bin, y_bin, neighborhood_fill_radius, compute_agg, z);
896  }
897  } else {
898  new_z[bin_idx] = z_val;
899  }
900  }
901  }
902  });
903  z.swap(new_z);
904 }
905 
906 template <typename T, typename Z>
907 void GeoRaster<T, Z>::fill_bins_from_neighbors(const int64_t neighborhood_fill_radius,
908  const bool fill_only_nulls,
909  const RasterAggType raster_fill_agg_type) {
910  fill_bins_from_neighbors(
911  neighborhood_fill_radius, fill_only_nulls, raster_fill_agg_type, z_);
912 }
913 
914 template <typename T, typename Z>
915 void GeoRaster<T, Z>::fill_bins_from_neighbors(const int64_t neighborhood_fill_radius,
916  const bool fill_only_nulls,
917  const RasterAggType raster_fill_agg_type,
918  std::vector<Z>& z) {
919  auto timer = DEBUG_TIMER(__func__);
920  // Note: only GAUSSIAN_AVG supports Gaussian 2-pass technique currently,
921  // as only an AVG aggregate makes sense for Gaussian blur. However we
922  // should be able to implement 2-pass box convolution for the other aggregates
923  // when time allows for better performance with wide kernel sizes
924  // Todo (Todd): Implement 2-pass box blur
925 
926  switch (raster_fill_agg_type) {
927  case RasterAggType::COUNT: {
928  fill_bins_from_box_neighborhood<RasterAggType::COUNT>(
929  neighborhood_fill_radius, fill_only_nulls, z);
930  break;
931  }
932  case RasterAggType::MIN: {
933  fill_bins_from_box_neighborhood<RasterAggType::MIN>(
934  neighborhood_fill_radius, fill_only_nulls, z);
935  break;
936  }
937  case RasterAggType::MAX: {
938  fill_bins_from_box_neighborhood<RasterAggType::MAX>(
939  neighborhood_fill_radius, fill_only_nulls, z);
940  break;
941  }
942  case RasterAggType::SUM: {
943  fill_bins_from_box_neighborhood<RasterAggType::SUM>(
944  neighborhood_fill_radius, fill_only_nulls, z);
945  break;
946  }
947  case RasterAggType::BOX_AVG: {
948  fill_bins_from_box_neighborhood<RasterAggType::BOX_AVG>(
949  neighborhood_fill_radius, fill_only_nulls, z);
950  break;
951  }
952  case RasterAggType::AVG:
954  fill_bins_from_gaussian_neighborhood(neighborhood_fill_radius, fill_only_nulls, z);
955  break;
956  }
957  default: {
958  UNREACHABLE();
959  }
960  }
961 }
962 
963 template <typename T, typename Z>
965  const int64_t x_bin,
966  const int64_t y_bin,
967  const int64_t num_bins_radius,
968  std::vector<Z>& neighboring_bins) const {
969  const size_t num_bins_per_dim = num_bins_radius * 2 + 1;
970  CHECK_EQ(neighboring_bins.size(), num_bins_per_dim * num_bins_per_dim);
971  const int64_t end_y_bin_idx = y_bin + num_bins_radius;
972  const int64_t end_x_bin_idx = x_bin + num_bins_radius;
973  size_t output_bin = 0;
974  for (int64_t y_bin_idx = y_bin - num_bins_radius; y_bin_idx <= end_y_bin_idx;
975  ++y_bin_idx) {
976  for (int64_t x_bin_idx = x_bin - num_bins_radius; x_bin_idx <= end_x_bin_idx;
977  ++x_bin_idx) {
978  if (x_bin_idx < 0 || x_bin_idx >= num_x_bins_ || y_bin_idx < 0 ||
979  y_bin_idx >= num_y_bins_) {
980  return false;
981  }
982  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin_idx, y_bin_idx, num_x_bins_);
983  neighboring_bins[output_bin++] = z_[bin_idx];
984  if (z_[bin_idx] == null_sentinel_) {
985  return false;
986  }
987  }
988  }
989  return true; // not_null
990 }
991 
992 template <typename T, typename Z>
994  const std::vector<Z>& neighboring_cells,
995  const bool compute_slope_in_degrees) const {
996  const Z dz_dx =
997  ((neighboring_cells[8] + 2 * neighboring_cells[5] + neighboring_cells[2]) -
998  (neighboring_cells[6] + 2 * neighboring_cells[3] + neighboring_cells[0])) /
999  (8 * bin_dim_meters_);
1000  const Z dz_dy =
1001  ((neighboring_cells[6] + 2 * neighboring_cells[7] + neighboring_cells[8]) -
1002  (neighboring_cells[0] + 2 * neighboring_cells[1] + neighboring_cells[2])) /
1003  (8 * bin_dim_meters_);
1004  const Z slope = sqrt(dz_dx * dz_dx + dz_dy * dz_dy);
1005  std::pair<Z, Z> slope_and_aspect;
1006  slope_and_aspect.first =
1007  compute_slope_in_degrees ? atan(slope) * math_consts::radians_to_degrees : slope;
1008  if (slope < 0.0001) {
1009  slope_and_aspect.second = null_sentinel_;
1010  } else {
1011  const Z aspect_degrees =
1012  math_consts::radians_to_degrees * atan2(dz_dx, dz_dy); // -180.0 to 180.0
1013  slope_and_aspect.second = aspect_degrees + 180.0;
1014  // aspect_degrees < 0.0 ? 180.0 + aspect_degrees : aspect_degrees;
1015  }
1016  return slope_and_aspect;
1017 }
1018 
1019 template <typename T, typename Z>
1021  Column<Z>& slope,
1022  Column<Z>& aspect,
1023  const bool compute_slope_in_degrees) const {
1024  auto timer = DEBUG_TIMER(__func__);
1025  CHECK_EQ(slope.size(), num_bins_);
1027  tbb::blocked_range<int64_t>(0, num_y_bins_),
1028  [&](const tbb::blocked_range<int64_t>& r) {
1029  std::vector<Z> neighboring_z_vals(9); // 3X3 calc
1030  for (int64_t y_bin = r.begin(); y_bin != r.end(); ++y_bin) {
1031  for (int64_t x_bin = 0; x_bin < num_x_bins_; ++x_bin) {
1032  const bool not_null =
1033  get_nxn_neighbors_if_not_null(x_bin, y_bin, 1, neighboring_z_vals);
1034  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
1035  if (!not_null) {
1036  slope.setNull(bin_idx);
1037  aspect.setNull(bin_idx);
1038  } else {
1039  const auto slope_and_aspect = calculate_slope_and_aspect_of_cell(
1040  neighboring_z_vals, compute_slope_in_degrees);
1041  slope[bin_idx] = slope_and_aspect.first;
1042  if (slope_and_aspect.second == null_sentinel_) {
1043  aspect.setNull(bin_idx);
1044  } else {
1045  aspect[bin_idx] = slope_and_aspect.second;
1046  }
1047  }
1048  }
1049  }
1050  });
1051 }
1052 
1053 template <typename T, typename Z>
1055  TableFunctionManager& mgr,
1056  Column<T>& output_x,
1057  Column<T>& output_y,
1058  Column<Z>& output_z,
1059  const int64_t neighborhood_null_fill_radius) const {
1060  auto timer = DEBUG_TIMER(__func__);
1061  mgr.set_output_row_size(num_bins_);
1063  tbb::blocked_range<int64_t>(0, num_y_bins_),
1064  [&](const tbb::blocked_range<int64_t>& r) {
1065  for (int64_t y_bin = r.begin(); y_bin != r.end(); ++y_bin) {
1066  for (int64_t x_bin = 0; x_bin < num_x_bins_; ++x_bin) {
1067  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
1068  output_x[bin_idx] = x_min_ + (x_bin + 0.5) * x_scale_bin_to_input_;
1069  output_y[bin_idx] = y_min_ + (y_bin + 0.5) * y_scale_bin_to_input_;
1070  const Z z_val = z_[bin_idx];
1071  if (z_val == null_sentinel_) {
1072  output_z.setNull(bin_idx);
1073  if (neighborhood_null_fill_radius) {
1074  const Z avg_neighbor_value = fill_bin_from_avg_box_neighborhood(
1075  x_bin, y_bin, neighborhood_null_fill_radius);
1076  if (avg_neighbor_value != null_sentinel_) {
1077  output_z[bin_idx] = avg_neighbor_value;
1078  }
1079  }
1080  } else {
1081  output_z[bin_idx] = z_[bin_idx];
1082  }
1083  }
1084  }
1085  });
1086  return num_bins_;
1087 }
1088 
1089 template <typename T, typename Z>
1091  Column<T>& output_x,
1092  Column<T>& output_y,
1093  Column<Z>& output_z,
1094  const int64_t band_idx) const {
1095  const std::vector<Z>& z = z_cols_.empty() ? z_ : z_cols_[band_idx];
1096 
1097  auto timer = DEBUG_TIMER(__func__);
1098  mgr.set_output_row_size(num_bins_);
1100  tbb::blocked_range<int64_t>(0, num_y_bins_),
1101  [&](const tbb::blocked_range<int64_t>& r) {
1102  for (int64_t y_bin = r.begin(); y_bin != r.end(); ++y_bin) {
1103  for (int64_t x_bin = 0; x_bin < num_x_bins_; ++x_bin) {
1104  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
1105  output_x[bin_idx] = x_min_ + (x_bin + 0.5) * x_scale_bin_to_input_;
1106  output_y[bin_idx] = y_min_ + (y_bin + 0.5) * y_scale_bin_to_input_;
1107  const Z z_val = z[bin_idx];
1108  if (z_val == null_sentinel_) {
1109  output_z.setNull(bin_idx);
1110  } else {
1111  output_z[bin_idx] = z_val;
1112  }
1113  }
1114  }
1115  });
1116  return num_bins_;
1117 }
1118 
1119 template <typename T, typename Z>
1121  Column<Z>& output_z,
1122  const int64_t band_idx) const {
1123  const std::vector<Z>& z = z_cols_.empty() ? z_ : z_cols_[band_idx];
1124 
1125  auto timer = DEBUG_TIMER(__func__);
1126  tbb::parallel_for(tbb::blocked_range<int64_t>(0, num_y_bins_),
1127  [&](const tbb::blocked_range<int64_t>& r) {
1128  for (int64_t y_bin = r.begin(); y_bin != r.end(); ++y_bin) {
1129  for (int64_t x_bin = 0; x_bin < num_x_bins_; ++x_bin) {
1130  const int64_t bin_idx =
1131  x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
1132  const Z z_val = z[bin_idx];
1133  if (z_val == null_sentinel_) {
1134  output_z.setNull(bin_idx);
1135  } else {
1136  output_z[bin_idx] = z_val;
1137  }
1138  }
1139  }
1140  });
1141  return num_bins_;
1142 }
1143 
1144 // template <typename T, typename Z>
1145 // int64_t GeoRaster<T, Z>::outputDenseColumns(TableFunctionManager& mgr,
1146 // Column<T>& output_x,
1147 // Column<T>& output_y,
1148 // std::vector<Column<Z>>& output_z_cols) const
1149 // {
1150 // auto timer = DEBUG_TIMER(__func__);
1151 // const int64_t num_z_cols = static_cast<int64_t>(z_cols_.size());
1152 // mgr.set_output_array_values_total_number(
1153 // /*output column index=*/2,
1154 // /*upper bound to the number of items in all output arrays=*/num_bins_ *
1155 // num_z_cols);
1156 // mgr.set_output_row_size(num_bins_);
1157 // for (int64_t y_bin = 0; y_bin != num_y_bins_; ++y_bin) {
1158 // for (int64_t x_bin = 0; x_bin < num_x_bins_; ++x_bin) {
1159 // const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
1160 // output_x[bin_idx] = x_min_ + (x_bin + 0.5) * x_scale_bin_to_input_;
1161 // output_y[bin_idx] = y_min_ + (y_bin + 0.5) * y_scale_bin_to_input_;
1162 // Array<Z> z_array = output_z.getItem(bin_idx, num_z_cols);
1163 // for (int64_t z_col_idx = 0; z_col_idx < num_z_cols; ++z_col_idx) {
1164 // const Z z_val = z_cols_[z_col_idx][bin_idx];
1165 // z_array[z_col_idx] = z_val;
1166 // }
1167 // }
1168 // }
1169 
1170 template <typename T, typename Z>
1172  Column<T>& output_x,
1173  Column<T>& output_y,
1174  Column<Array<Z>>& output_z) const {
1175  auto timer = DEBUG_TIMER(__func__);
1176  const int64_t num_z_cols = static_cast<int64_t>(z_cols_.size());
1178  /*output column index=*/2,
1179  /*upper bound to the number of items in all output arrays=*/num_bins_ * num_z_cols);
1180  mgr.set_output_row_size(num_bins_);
1181  for (int64_t y_bin = 0; y_bin != num_y_bins_; ++y_bin) {
1182  for (int64_t x_bin = 0; x_bin < num_x_bins_; ++x_bin) {
1183  const int64_t bin_idx = x_y_bin_to_bin_index(x_bin, y_bin, num_x_bins_);
1184  output_x[bin_idx] = x_min_ + (x_bin + 0.5) * x_scale_bin_to_input_;
1185  output_y[bin_idx] = y_min_ + (y_bin + 0.5) * y_scale_bin_to_input_;
1186  Array<Z> z_array = output_z.getItem(bin_idx, num_z_cols);
1187  for (int64_t z_col_idx = 0; z_col_idx < num_z_cols; ++z_col_idx) {
1188  const Z z_val = z_cols_[z_col_idx][bin_idx];
1189  z_array[z_col_idx] = z_val;
1190  }
1191  }
1192  }
1193  return num_bins_;
1194 }
1195 
1196 template <typename T, typename Z>
1198  mgr.set_metadata("geo_raster_num_x_bins", num_x_bins_);
1199  mgr.set_metadata("geo_raster_num_y_bins", num_y_bins_);
1200  mgr.set_metadata("geo_raster_x_min", static_cast<double>(x_min_));
1201  mgr.set_metadata("geo_raster_y_min", static_cast<double>(y_min_));
1202  mgr.set_metadata("geo_raster_x_scale_input_to_bin",
1203  static_cast<double>(x_scale_input_to_bin_));
1204  mgr.set_metadata("geo_raster_y_scale_input_to_bin",
1205  static_cast<double>(y_scale_input_to_bin_));
1206 }
1207 
1208 template <typename T, typename Z>
1210  const Column<T>& input_x,
1211  const Column<T>& input_y,
1212  const Column<Z>& input_z,
1213  const RasterAggType raster_agg_type,
1214  const RasterAggType raster_fill_agg_type,
1215  const T bin_dim_meters,
1216  const bool geographic_coords,
1217  const int64_t neighborhood_fill_radius,
1218  const bool fill_only_nulls,
1219  Column<T>& output_x,
1220  Column<T>& output_y,
1221  Column<Z>& output_z) {
1222  GeoRaster<T, Z> geo_raster(input_x,
1223  input_y,
1224  input_z,
1225  raster_agg_type,
1226  bin_dim_meters,
1227  geographic_coords,
1228  true);
1229 
1230  geo_raster.setMetadata(mgr);
1231 
1232  if (neighborhood_fill_radius > 0) {
1233  geo_raster.fill_bins_from_neighbors(
1234  neighborhood_fill_radius, fill_only_nulls, raster_fill_agg_type);
1235  }
1236 
1237  return geo_raster.outputDenseColumns(mgr, output_x, output_y, output_z);
1238 }
1239 
1240 // clang-format off
1241 /*
1242  UDTF: tf_geo_rasterize__cpu_template(TableFunctionManager,
1243  Cursor<Column<T> x, Column<T> y, Column<Z> z> raster,
1244  TextEncodingNone agg_type | default="AVG",
1245  T bin_dim_meters | require="bin_dim_meters > 0",
1246  bool geographic_coords | default=true,
1247  int64_t neighborhood_fill_radius | require="neighborhood_fill_radius >= 0" | default=0,
1248  bool fill_only_nulls | default=false) | filter_table_function_transpose=on ->
1249  Column<T> x, Column<T> y, Column<Z> z, T=[float, double], Z=[float, double]
1250  */
1251 // clang-format on
1252 
1253 template <typename T, typename Z>
1254 TEMPLATE_NOINLINE int32_t
1256  const Column<T>& input_x,
1257  const Column<T>& input_y,
1258  const Column<Z>& input_z,
1259  const TextEncodingNone& agg_type_str,
1260  const T bin_dim_meters,
1261  const bool geographic_coords,
1262  const int64_t neighborhood_fill_radius,
1263  const bool fill_only_nulls,
1264  Column<T>& output_x,
1265  Column<T>& output_y,
1266  Column<Z>& output_z) {
1267  const auto raster_agg_type = get_raster_agg_type(agg_type_str, false);
1268  if (raster_agg_type == RasterAggType::INVALID) {
1269  const std::string error_msg =
1270  "Invalid Raster Aggregate Type: " + agg_type_str.getString();
1271  return mgr.ERROR_MESSAGE(error_msg);
1272  }
1273  return geo_rasterize_impl(mgr,
1274  input_x,
1275  input_y,
1276  input_z,
1277  raster_agg_type,
1279  bin_dim_meters,
1280  geographic_coords,
1281  neighborhood_fill_radius,
1282  fill_only_nulls,
1283  output_x,
1284  output_y,
1285  output_z);
1286 }
1287 
1288 // clang-format off
1289 /*
1290  UDTF: tf_geo_rasterize__cpu_template(TableFunctionManager,
1291  Cursor<Column<T> x, Column<T> y, Column<Z> z> raster,
1292  TextEncodingNone agg_type | default = "AVG",
1293  TextEncodingNone fill_agg_type | default = "GAUSS_AVG",
1294  T bin_dim_meters | require="bin_dim_meters > 0",
1295  bool geographic_coords | default=true,
1296  int64_t neighborhood_fill_radius | require="neighborhood_fill_radius >= 0" | default=0,
1297  bool fill_only_nulls | default=false) | filter_table_function_transpose=on ->
1298  Column<T> x, Column<T> y, Column<Z> z, T=[float, double], Z=[float, double]
1299  */
1300 // clang-format on
1301 
1302 template <typename T, typename Z>
1303 TEMPLATE_NOINLINE int32_t
1305  const Column<T>& input_x,
1306  const Column<T>& input_y,
1307  const Column<Z>& input_z,
1308  const TextEncodingNone& agg_type_str,
1309  const TextEncodingNone& fill_agg_type_str,
1310  const T bin_dim_meters,
1311  const bool geographic_coords,
1312  const int64_t neighborhood_fill_radius,
1313  const bool fill_only_nulls,
1314  Column<T>& output_x,
1315  Column<T>& output_y,
1316  Column<Z>& output_z) {
1317  const auto raster_agg_type = get_raster_agg_type(agg_type_str, false);
1318  if (raster_agg_type == RasterAggType::INVALID) {
1319  const std::string error_msg =
1320  "Invalid Raster Aggregate Type: " + agg_type_str.getString();
1321  return mgr.ERROR_MESSAGE(error_msg);
1322  }
1323  const auto raster_fill_agg_type = get_raster_agg_type(fill_agg_type_str, true);
1324  if (raster_fill_agg_type == RasterAggType::INVALID) {
1325  const std::string error_msg =
1326  "Invalid Raster Fill Aggregate Type: " + fill_agg_type_str.getString();
1327  return mgr.ERROR_MESSAGE(error_msg);
1328  }
1329  return geo_rasterize_impl(mgr,
1330  input_x,
1331  input_y,
1332  input_z,
1333  raster_agg_type,
1334  raster_fill_agg_type,
1335  bin_dim_meters,
1336  geographic_coords,
1337  neighborhood_fill_radius,
1338  fill_only_nulls,
1339  output_x,
1340  output_y,
1341  output_z);
1342 }
1343 
1344 // clang-format off
1345 /*
1346  UDTF: tf_geo_rasterize__cpu_template(TableFunctionManager,
1347  Cursor<Column<T> x, Column<T> y, Column<Z> z> raster,
1348  TextEncodingNone agg_type | default="AVG",
1349  TextEncodingNone fill_agg_type | default="GAUSS_AVG",
1350  T bin_dim_meters | require="bin_dim_meters > 0",
1351  bool geographic_coords | default=true,
1352  int64_t neighborhood_fill_radius | require="neighborhood_fill_radius >= 0" | default = 0,
1353  bool fill_only_nulls | default = false,
1354  T x_min, T x_max | require="x_max > x_min", T y_min, T y_max | require="y_max > y_min") ->
1355  Column<T> x, Column<T> y, Column<Z> z, T=[float, double], Z=[float, double]
1356  */
1357 // clang-format on
1358 
1359 template <typename T, typename Z>
1360 TEMPLATE_NOINLINE int32_t
1362  const Column<T>& input_x,
1363  const Column<T>& input_y,
1364  const Column<Z>& input_z,
1365  const TextEncodingNone& agg_type_str,
1366  const TextEncodingNone& fill_agg_type_str,
1367  const T bin_dim_meters,
1368  const bool geographic_coords,
1369  const int64_t neighborhood_fill_radius,
1370  const bool fill_only_nulls,
1371  const T x_min,
1372  const T x_max,
1373  const T y_min,
1374  const T y_max,
1375  Column<T>& output_x,
1376  Column<T>& output_y,
1377  Column<Z>& output_z) {
1378  const auto raster_agg_type = get_raster_agg_type(agg_type_str, false);
1379  if (raster_agg_type == RasterAggType::INVALID) {
1380  const std::string error_msg =
1381  "Invalid Raster Aggregate Type: " + agg_type_str.getString();
1382  return mgr.ERROR_MESSAGE(error_msg);
1383  }
1384  const auto raster_fill_agg_type = get_raster_agg_type(fill_agg_type_str, true);
1385  if (raster_fill_agg_type == RasterAggType::INVALID) {
1386  const std::string error_msg =
1387  "Invalid Raster Fill Aggregate Type: " + fill_agg_type_str.getString();
1388  return mgr.ERROR_MESSAGE(error_msg);
1389  }
1390 
1391  GeoRaster<T, Z> geo_raster(input_x,
1392  input_y,
1393  input_z,
1394  raster_agg_type,
1395  bin_dim_meters,
1396  geographic_coords,
1397  true,
1398  x_min,
1399  x_max,
1400  y_min,
1401  y_max);
1402 
1403  geo_raster.setMetadata(mgr);
1404 
1405  if (neighborhood_fill_radius > 0) {
1406  geo_raster.fill_bins_from_neighbors(
1407  neighborhood_fill_radius, fill_only_nulls, raster_fill_agg_type);
1408  }
1409 
1410  return geo_raster.outputDenseColumns(mgr, output_x, output_y, output_z);
1411 }
1412 
1413 // clang-format off
1414 /*
1415  UDTF: tf_geo_multi_rasterize__cpu_template(TableFunctionManager,
1416  Cursor<Column<T> x, Column<T> y, ColumnList<Z> z> raster,
1417  TextEncodingNone agg_types,
1418  TextEncodingNone fill_agg_types,
1419  T bin_dim_meters | require="bin_dim_meters > 0",
1420  bool geographic_coords | default=true,
1421  int64_t neighborhood_fill_radius | require="neighborhood_fill_radius >= 0" | default=0,
1422  bool fill_only_nulls | default=false) | filter_table_function_transpose=on ->
1423  Column<T> x, Column<T> y, Column<Array<Z>> z, T=[float, double], Z=[float, double]
1424  */
1425 // clang-format on
1426 
1427 template <typename T, typename Z>
1428 TEMPLATE_NOINLINE int32_t
1430  const Column<T>& input_x,
1431  const Column<T>& input_y,
1432  const ColumnList<Z>& input_z_cols,
1433  const TextEncodingNone& agg_types_str,
1434  const TextEncodingNone& fill_agg_types_str,
1435  const T bin_dim_meters,
1436  const bool geographic_coords,
1437  const int64_t neighborhood_fill_radius,
1438  const bool fill_only_nulls,
1439  Column<T>& output_x,
1440  Column<T>& output_y,
1441  Column<Array<Z>>& output_z) {
1442  const int64_t num_z_cols = input_z_cols.numCols();
1443  const auto agg_types_strs = split(agg_types_str.getString(), "|");
1444  const auto fill_agg_types_strs = split(fill_agg_types_str.getString(), "|");
1445  if (num_z_cols != static_cast<int64_t>(agg_types_strs.size()) ||
1446  num_z_cols != static_cast<int64_t>(fill_agg_types_strs.size())) {
1447  const std::string error_msg =
1448  "Mismatch between number of cols and number of agg or fill agg types.";
1449  return mgr.ERROR_MESSAGE(error_msg);
1450  }
1451 
1452  auto get_agg_types = [](const std::vector<std::string>& agg_types_strs,
1453  const bool is_fill_agg) {
1454  std::vector<RasterAggType> agg_types;
1455  for (const auto& agg_type_str : agg_types_strs) {
1456  agg_types.emplace_back(get_raster_agg_type(agg_type_str, is_fill_agg));
1457  if (agg_types.back() == RasterAggType::INVALID) {
1458  throw std::runtime_error("Invalid agg type");
1459  }
1460  }
1461  return agg_types;
1462  };
1463 
1464  std::vector<RasterAggType> raster_agg_types;
1465  std::vector<RasterAggType> raster_fill_agg_types;
1466  try {
1467  raster_agg_types = get_agg_types(agg_types_strs, false);
1468  raster_fill_agg_types = get_agg_types(fill_agg_types_strs, true);
1469  } catch (std::exception& e) {
1470  return mgr.ERROR_MESSAGE(e.what());
1471  }
1472 
1473  GeoRaster<T, Z> geo_raster(input_x,
1474  input_y,
1475  input_z_cols,
1476  raster_agg_types,
1477  bin_dim_meters,
1478  geographic_coords,
1479  true);
1480  geo_raster.setMetadata(mgr);
1481 
1482  if (neighborhood_fill_radius > 0) {
1483  for (int64_t z_col_idx = 0; z_col_idx < num_z_cols; ++z_col_idx) {
1484  geo_raster.fill_bins_from_neighbors(neighborhood_fill_radius,
1485  fill_only_nulls,
1486  raster_fill_agg_types[z_col_idx],
1487  geo_raster.z_cols_[z_col_idx]);
1488  }
1489  }
1490  return geo_raster.outputDenseColumns(mgr, output_x, output_y, output_z);
1491 }
1492 
1493 // clang-format off
1494 /*
1495  UDTF: tf_geo_rasterize_slope__cpu_template(TableFunctionManager,
1496  Cursor<Column<T> x, Column<T> y, Column<Z> z> raster,
1497  TextEncodingNone agg_type | default="AVG",
1498  T bin_dim_meters | require="bin_dim_meters > 0",
1499  bool geographic_coords | default=true,
1500  int64_t neighborhood_fill_radius | require="neighborhood_fill_radius >= 0" | default=0,
1501  bool fill_only_nulls | default=false,
1502  bool compute_slope_in_degrees | default=true) | filter_table_function_transpose=on ->
1503  Column<T> x, Column<T> y, Column<Z> z, Column<Z> slope, Column<Z> aspect, T=[float, double], Z=[float, double]
1504  */
1505 // clang-format on
1506 
1507 template <typename T, typename Z>
1508 TEMPLATE_NOINLINE int32_t
1510  const Column<T>& input_x,
1511  const Column<T>& input_y,
1512  const Column<Z>& input_z,
1513  const TextEncodingNone& agg_type_str,
1514  const T bin_dim_meters,
1515  const bool geographic_coords,
1516  const int64_t neighborhood_fill_radius,
1517  const bool fill_only_nulls,
1518  const bool compute_slope_in_degrees,
1519  Column<T>& output_x,
1520  Column<T>& output_y,
1521  Column<Z>& output_z,
1522  Column<Z>& output_slope,
1523  Column<Z>& output_aspect) {
1524  const auto raster_agg_type = get_raster_agg_type(agg_type_str, false);
1525  if (raster_agg_type == RasterAggType::INVALID) {
1526  const std::string error_msg =
1527  "Invalid Raster Aggregate Type: " + agg_type_str.getString();
1528  return mgr.ERROR_MESSAGE(error_msg);
1529  }
1530 
1531  GeoRaster<T, Z> geo_raster(input_x,
1532  input_y,
1533  input_z,
1534  raster_agg_type,
1535  bin_dim_meters,
1536  geographic_coords,
1537  true);
1538  geo_raster.setMetadata(mgr);
1539 
1540  if (neighborhood_fill_radius > 0) {
1541  geo_raster.fill_bins_from_neighbors(
1542  neighborhood_fill_radius, fill_only_nulls, RasterAggType::GAUSS_AVG);
1543  }
1544 
1545  const size_t output_rows =
1546  geo_raster.outputDenseColumns(mgr, output_x, output_y, output_z);
1547  geo_raster.calculate_slope_and_aspect(
1548  output_slope, output_aspect, compute_slope_in_degrees);
1549  return output_rows;
1550 }
1551 
1552 #endif // __CUDACC__
TEMPLATE_NOINLINE int32_t tf_geo_rasterize__cpu_template(TableFunctionManager &mgr, const Column< T > &input_x, const Column< T > &input_y, const Column< Z > &input_z, const TextEncodingNone &agg_type_str, const T bin_dim_meters, const bool geographic_coords, const int64_t neighborhood_fill_radius, const bool fill_only_nulls, Column< T > &output_x, Column< T > &output_y, Column< Z > &output_z)
void set_output_row_size(int64_t num_rows)
Definition: heavydbTypes.h:373
#define CHECK_EQ(x, y)
Definition: Logger.h:301
TEMPLATE_NOINLINE int32_t tf_geo_multi_rasterize__cpu_template(TableFunctionManager &mgr, const Column< T > &input_x, const Column< T > &input_y, const ColumnList< Z > &input_z_cols, const TextEncodingNone &agg_types_str, const TextEncodingNone &fill_agg_types_str, const T bin_dim_meters, const bool geographic_coords, const int64_t neighborhood_fill_radius, const bool fill_only_nulls, Column< T > &output_x, Column< T > &output_y, Column< Array< Z >> &output_z)
constexpr double radians_to_degrees
Definition: math_consts.h:23
Z offset_source_z_from_raster_z(const int64_t source_x_bin, const int64_t source_y_bin, const Z source_z_offset) const
bool get_nxn_neighbors_if_not_null(const int64_t x_bin, const int64_t y_bin, const int64_t num_bins_radius, std::vector< Z > &neighboring_bins) const
std::vector< std::vector< Z > > z_cols_
void set_output_array_values_total_number(int32_t index, int64_t output_array_values_total_number)
Definition: heavydbTypes.h:361
TEMPLATE_NOINLINE int32_t geo_rasterize_impl(TableFunctionManager &mgr, const Column< T > &input_x, const Column< T > &input_y, const Column< Z > &input_z, const RasterAggType raster_agg_type, const RasterAggType raster_fill_agg_type, const T bin_dim_meters, const bool geographic_coords, const int64_t neighborhood_fill_radius, const bool fill_only_nulls, Column< T > &output_x, Column< T > &output_y, Column< Z > &output_z)
void operator()(const Z2 &input_z, Z &output_z, const Z2 input_sentinel) const
const size_t max_temp_output_entries
int64_t get_bin_idx_for_xy_coords(const T x, const T y) const
void setMetadata(TableFunctionManager &mgr) const
std::pair< Z, Z > calculate_slope_and_aspect_of_cell(const std::vector< Z > &neighboring_cells, const bool compute_slope_in_degrees) const
std::pair< T, T > get_xy_coords_for_bin_idx(const int64_t bin_idx) const
std::string getString() const
Definition: heavydbTypes.h:641
NEVER_INLINE HOST std::pair< T, T > get_column_min_max(const Column< T > &col)
GeoRaster(const Column< T2 > &input_x, const Column< T2 > &input_y, const Column< Z2 > &input_z, const RasterAggType raster_agg_type, const double bin_dim_meters, const bool geographic_coords, const bool align_bins_to_zero_based_grid)
DEVICE int64_t size() const
DEVICE int64_t numCols() const
#define UNREACHABLE()
Definition: Logger.h:338
void operator()(const Z2 &input_z, Z &output_z, const Z2 input_sentinel) const
void fill_bins_from_neighbors(const int64_t neighborhood_fill_radius, const bool fill_only_nulls, const RasterAggType raster_agg_type=RasterAggType::GAUSS_AVG)
void computeParallelReductionAggImpl(const std::vector< std::vector< Z >> &z_inputs, std::vector< Z > &output_z, const Z agg_sentinel)
#define CHECK_GT(x, y)
Definition: Logger.h:305
void fill_bins_from_box_neighborhood(const int64_t neighborhood_fill_radius, const bool fill_only_nulls, std::vector< Z > &z)
T get_y_bin(const T input) const
Z fill_bin_from_avg_box_neighborhood(const int64_t x_centroid_bin, const int64_t y_centroid_bin, const int64_t bins_radius, std::vector< Z > &z) const
RasterAggType get_raster_agg_type(const std::string &agg_type_str, const bool is_fill_agg)
std::string to_string(char const *&&v)
std::vector< std::string > split(std::string_view str, std::string_view delim, std::optional< size_t > maxsplit)
split apart a string into a vector of substrings
T get_x_bin(const T input) const
bool is_bin_out_of_bounds(const int64_t x_bin, const int64_t y_bin) const
TEMPLATE_NOINLINE int32_t tf_geo_rasterize_slope__cpu_template(TableFunctionManager &mgr, const Column< T > &input_x, const Column< T > &input_y, const Column< Z > &input_z, const TextEncodingNone &agg_type_str, const T bin_dim_meters, const bool geographic_coords, const int64_t neighborhood_fill_radius, const bool fill_only_nulls, const bool compute_slope_in_degrees, Column< T > &output_x, Column< T > &output_y, Column< Z > &output_z, Column< Z > &output_slope, Column< Z > &output_aspect)
const size_t max_inputs_per_thread
DEVICE TextEncodingDict inline_null_value()
Definition: heavydbTypes.h:279
static constexpr int64_t BIN_OUT_OF_BOUNDS
std::vector< double > generate_1d_gaussian_kernel(const int64_t fill_radius, double sigma)
int64_t x_y_bin_to_bin_index(const int64_t x_bin, const int64_t y_bin, const int64_t num_x_bins)
const bool geographic_coords_
void operator()(const Z2 &input_z, Z &output_z, const Z2 input_sentinel) const
void calculate_slope_and_aspect(Column< Z > &slope, Column< Z > &aspect, const bool compute_slope_in_degrees) const
bool g_enable_smem_group_by true
void computeParallelImpl(const Column< T2 > &input_x, const Column< T2 > &input_y, const Column< Z2 > &input_z, std::vector< Z > &output_z, const size_t max_inputs_per_thread)
std::pair< int64_t, Z > get_bin_idx_and_z_val_for_xy_bin(const int64_t x_bin, const int64_t y_bin) const
int64_t outputDenseColumnsAndFill(TableFunctionManager &mgr, Column< T > &output_x, Column< T > &output_y, Column< Z > &output_z, const int64_t neighborhood_null_fill_radius) const
DEVICE void setNull(int64_t index)
bool is_null(const Z value) const
Z fill_bin_from_box_neighborhood(const int64_t x_centroid_bin, const int64_t y_centroid_bin, const int64_t bins_radius, const ComputeAgg< AggType > &compute_agg, std::vector< Z > &z) const
std::pair< int64_t, int64_t > bin_to_x_y_bin_indexes(const int64_t bin, const int64_t num_x_bins)
void parallel_for(const blocked_range< Int > &range, const Body &body, const Partitioner &p=Partitioner())
EXTENSION_NOINLINE double distance_in_meters(const double fromlon, const double fromlat, const double tolon, const double tolat)
Computes the distance, in meters, between two WGS-84 positions.
std::vector< Z > counts_
bool g_enable_watchdog false
Definition: Execute.cpp:80
void set_metadata(const std::string &key, const T &value)
Definition: heavydbTypes.h:388
#define CHECK(condition)
Definition: Logger.h:291
#define DEBUG_TIMER(name)
Definition: Logger.h:412
std::vector< Z > z_
void fill_bins_from_gaussian_neighborhood(const int64_t neighborhood_fill_radius, const bool fill_only_nulls, std::vector< Z > &z)
void operator()(const Z2 &input_z, Z &output_z, const Z2 input_sentinel) const
void compute(const Column< T2 > &input_x, const Column< T2 > &input_y, const Column< Z2 > &input_z, std::vector< Z > &output_z, const RasterAggType raster_agg_type, const size_t max_inputs_per_thread)
void computeSerialImpl(const Column< T2 > &input_x, const Column< T2 > &input_y, const Column< Z2 > &input_z, std::vector< Z > &output_z)
#define TEMPLATE_NOINLINE
Definition: heavydbTypes.h:60
int64_t outputDenseColumns(TableFunctionManager &mgr, Column< T > &output_x, Column< T > &output_y, Column< Z > &output_z, const int64_t band_idx=0) const
int64_t outputDenseColumn(TableFunctionManager &mgr, Column< Z > &output_z, const int64_t band_idx) const