Compadre  1.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Compadre_Evaluator.hpp
Go to the documentation of this file.
1 #ifndef _COMPADRE_EVALUATOR_HPP_
2 #define _COMPADRE_EVALUATOR_HPP_
3 
4 #include "Compadre_Typedefs.hpp"
5 #include "Compadre_GMLS.hpp"
7 
8 namespace Compadre {
9 
10 //! Creates 1D subviews of data from a 2D view, generally constructed with CreateNDSliceOnDeviceView
11 template<typename T, typename T2, typename T3=void>
12 struct SubviewND {
13 
17 
18  SubviewND(T data_in, T2 data_original_view, bool scalar_as_vector_if_needed) {
19  _data_in = data_in;
20  _data_original_view = data_original_view;
21  _scalar_as_vector_if_needed = scalar_as_vector_if_needed;
22  }
23 
24  auto get1DView(const int column_num) -> decltype(Kokkos::subview(_data_in, Kokkos::ALL, column_num)) {
26  compadre_assert_debug(((size_t)column_num<_data_in.extent(1))
27  && "Subview asked for column > second dimension of input data.");
28  }
29  if ((size_t)column_num<_data_in.extent(1))
30  return Kokkos::subview(_data_in, Kokkos::ALL, column_num);
31  else // scalar treated as a vector (being reused for each component of the vector input that was expected)
32  return Kokkos::subview(_data_in, Kokkos::ALL, 0);
33  }
34 
35  auto get2DView(const int column_num, const int block_size) -> decltype(Kokkos::subview(_data_in, Kokkos::ALL,
36  Kokkos::make_pair(column_num*block_size, (column_num+1)*block_size))) {
38  compadre_assert_debug(((size_t)((column_num+1)*block_size-1)<_data_in.extent(1))
39  && "Subview asked for column > second dimension of input data.");
40  }
41  if ((size_t)((column_num+1)*block_size-1)<_data_in.extent(1)) {
42  return Kokkos::subview(_data_in, Kokkos::ALL, Kokkos::make_pair(column_num*block_size, (column_num+1)*block_size));
43  } else {
44  compadre_assert_debug(((size_t)(block_size-1)<_data_in.extent(1)) && "Subview asked for column > second dimension of input data.");
45  return Kokkos::subview(_data_in, Kokkos::ALL, Kokkos::make_pair(0,block_size));
46  }
47  }
48 
50  Kokkos::deep_copy(_data_original_view, _data_in);
51  Kokkos::fence();
52  return _data_original_view;
53  }
54 
55 };
56 
57 //! Creates 1D subviews of data from a 1D view, generally constructed with CreateNDSliceOnDeviceView
58 template<typename T, typename T2>
59 struct SubviewND<T, T2, enable_if_t<(T::rank<2)> >
60 {
61 
62  T _data_in;
65 
66  SubviewND(T data_in, T2 data_original_view, bool scalar_as_vector_if_needed) {
67  _data_in = data_in;
68  _data_original_view = data_original_view;
69  _scalar_as_vector_if_needed = scalar_as_vector_if_needed;
70  }
71 
72  auto get1DView(const int column_num) -> decltype(Kokkos::subview(_data_in, Kokkos::ALL)) {
73  // TODO: There is a valid use case for violating this assert, so in the future we may want
74  // to add other logic to the evaluator function calling this so that it knows to do nothing with
75  // this data.
77  compadre_assert_debug((column_num==0) && "Subview asked for column column_num!=0, but _data_in is rank 1.");
78  }
79  return Kokkos::subview(_data_in, Kokkos::ALL);
80  }
81 
82  auto get2DView(const int column_num, const int block_size) -> decltype(Kokkos::subview(_data_in, Kokkos::ALL)) {
83  compadre_assert_release((block_size==1) && "2D subview requested not compatible with one column.");
84  return Kokkos::subview(_data_in, Kokkos::ALL);
85  }
86 
88  Kokkos::deep_copy(_data_original_view, _data_in);
89  Kokkos::fence();
90  return _data_original_view;
91  }
92 
93 };
94 
95 //! Copies data_in to the device, and then allows for access to 1D columns of data on device.
96 //! Handles either 2D or 1D views as input, and they can be on the host or the device.
97 template <typename T>
98 auto CreateNDSliceOnDeviceView(T sampling_input_data_host_or_device, bool scalar_as_vector_if_needed) -> SubviewND<decltype(Kokkos::create_mirror_view(
99  device_memory_space(), sampling_input_data_host_or_device)), T> {
100 
101  // makes view on the device (does nothing if already on the device)
102  auto sampling_input_data_device = Kokkos::create_mirror_view(
103  device_memory_space(), sampling_input_data_host_or_device);
104  Kokkos::deep_copy(sampling_input_data_device, sampling_input_data_host_or_device);
105  Kokkos::fence();
106 
107  return SubviewND<decltype(sampling_input_data_device),T>(sampling_input_data_device,
108  sampling_input_data_host_or_device, scalar_as_vector_if_needed);
109 }
110 
111 //! \brief Lightweight Evaluator Helper
112 //! This class is a lightweight wrapper for extracting and applying all relevant data from a GMLS class
113 //! in order to transform data into a form that can be acted on by the GMLS operator, apply the action of
114 //! the GMLS operator, and then transform data again (only if on a manifold)
115 class Evaluator {
116 
117 private:
118 
120 
121 
122 public:
123 
124  Evaluator(GMLS *gmls) : _gmls(gmls) {
125  Kokkos::fence();
126  };
127 
129 
130  //! Dot product of alphas with sampling data, FOR A SINGLE target_index, where sampling data is in a 1D/2D Kokkos View
131  //!
132  //! This function is to be used when the alpha values have already been calculated and stored for use
133  //!
134  //! Only supports one output component / input component at a time. The user will need to loop over the output
135  //! components in order to fill a vector target or matrix target.
136  //!
137  //! Assumptions on input data:
138  //! \param sampling_input_data [in] - 1D/2D Kokkos View (no restriction on memory space)
139  //! \param column_of_input [in] - Column of sampling_input_data to use for this input component
140  //! \param lro [in] - Target operation from the TargetOperation enum
141  //! \param target_index [in] - Target # user wants to reconstruct target functional at, corresponds to row number of neighbor_lists
142  //! \param output_component_axis_1 [in] - Row for a rank 2 tensor or rank 1 tensor, 0 for a scalar output
143  //! \param output_component_axis_2 [in] - Columns for a rank 2 tensor, 0 for rank less than 2 output tensor
144  //! \param input_component_axis_1 [in] - Row for a rank 2 tensor or rank 1 tensor, 0 for a scalar input
145  //! \param input_component_axis_2 [in] - Columns for a rank 2 tensor, 0 for rank less than 2 input tensor
146  //! \param scalar_as_vector_if_needed [in] - If a 1D view is given, where a 2D view is expected (scalar values given where a vector was expected), then the scalar will be repeated for as many components as the vector has
147  template <typename view_type_data>
148  double applyAlphasToDataSingleComponentSingleTargetSite(view_type_data sampling_input_data, const int column_of_input, TargetOperation lro, const int target_index, const int evaluation_site_local_index, const int output_component_axis_1, const int output_component_axis_2, const int input_component_axis_1, const int input_component_axis_2, bool scalar_as_vector_if_needed = true) const {
149 
150  double value = 0;
151 
152  const int alpha_input_output_component_index = _gmls->getAlphaColumnOffset(lro, output_component_axis_1,
153  output_component_axis_2, input_component_axis_1, input_component_axis_2, evaluation_site_local_index);
154 
155  auto sampling_subview_maker = CreateNDSliceOnDeviceView(sampling_input_data, scalar_as_vector_if_needed);
156 
157 
158  // gather needed information for evaluation
159  auto nla = *(_gmls->getNeighborLists());
160  auto alphas = _gmls->getAlphas();
161  auto sampling_data_device = sampling_subview_maker.get1DView(column_of_input);
162 
163  auto alpha_index = _gmls->getAlphaIndexHost(target_index, alpha_input_output_component_index);
164  // loop through neighbor list for this target_index
165  // grabbing data from that entry of data
166  Kokkos::parallel_reduce("applyAlphasToData::Device",
167  Kokkos::RangePolicy<device_execution_space>(0,nla.getNumberOfNeighborsHost(target_index)),
168  KOKKOS_LAMBDA(const int i, double& t_value) {
169 
170  t_value += sampling_data_device(nla.getNeighborDevice(target_index, i))
171  *alphas(alpha_index + i);
172 
173  }, value );
174  Kokkos::fence();
175 
176  return value;
177  }
178 
179  //! Dot product of alphas with sampling data where sampling data is in a 1D/2D Kokkos View and output view is also
180  //! a 1D/2D Kokkos View, however THE SAMPLING DATA and OUTPUT VIEW MUST BE ON THE DEVICE!
181  //!
182  //! This function is to be used when the alpha values have already been calculated and stored for use.
183  //!
184  //! Only supports one output component / input component at a time. The user will need to loop over the output
185  //! components in order to fill a vector target or matrix target.
186  //!
187  //! Assumptions on input data:
188  //! \param output_data_single_column [out] - 1D Kokkos View (memory space must be device_memory_space())
189  //! \param sampling_data_single_column [in] - 1D Kokkos View (memory space must match output_data_single_column)
190  //! \param lro [in] - Target operation from the TargetOperation enum
191  //! \param sro [in] - Sampling functional from the SamplingFunctional enum
192  //! \param evaluation_site_location [in] - local column index of site from additional evaluation sites list or 0 for the target site
193  //! \param output_component_axis_1 [in] - Row for a rank 2 tensor or rank 1 tensor, 0 for a scalar output
194  //! \param output_component_axis_2 [in] - Columns for a rank 2 tensor, 0 for rank less than 2 output tensor
195  //! \param input_component_axis_1 [in] - Row for a rank 2 tensor or rank 1 tensor, 0 for a scalar input
196  //! \param input_component_axis_2 [in] - Columns for a rank 2 tensor, 0 for rank less than 2 input tensor
197  //! \param pre_transform_local_index [in] - For manifold problems, this is the local coordinate direction that sampling data may need to be transformed to before the application of GMLS
198  //! \param pre_transform_global_index [in] - For manifold problems, this is the global coordinate direction that sampling data can be represented in
199  //! \param post_transform_local_index [in] - For manifold problems, this is the local coordinate direction that vector output target functionals from GMLS will output into
200  //! \param post_transform_global_index [in] - For manifold problems, this is the global coordinate direction that the target functional output from GMLS will be transformed into
201  //! \param transform_output_ambient [in] - Whether or not a 1D output from GMLS is on the manifold and needs to be mapped to ambient space
202  //! \param vary_on_target [in] - Whether the sampling functional has a tensor to act on sampling data that varies with each target site
203  //! \param vary_on_neighbor [in] - Whether the sampling functional has a tensor to act on sampling data that varies with each neighbor site in addition to varying wit each target site
204  template <typename view_type_data_out, typename view_type_data_in>
205  void applyAlphasToDataSingleComponentAllTargetSitesWithPreAndPostTransform(view_type_data_out output_data_single_column, view_type_data_in sampling_data_single_column, TargetOperation lro, const SamplingFunctional sro, const int evaluation_site_local_index, const int output_component_axis_1, const int output_component_axis_2, const int input_component_axis_1, const int input_component_axis_2, const int pre_transform_local_index = -1, const int pre_transform_global_index = -1, const int post_transform_local_index = -1, const int post_transform_global_index = -1, bool vary_on_target = false, bool vary_on_neighbor = false) const {
206 
207  const int alpha_input_output_component_index = _gmls->getAlphaColumnOffset(lro, output_component_axis_1,
208  output_component_axis_2, input_component_axis_1, input_component_axis_2, evaluation_site_local_index);
209  const int alpha_input_output_component_index2 = alpha_input_output_component_index;
210 
211  // gather needed information for evaluation
212  auto gmls = *(_gmls);
213  auto nla = *(_gmls->getNeighborLists());
214  auto alphas = _gmls->getAlphas();
215  auto prestencil_weights = _gmls->getPrestencilWeights();
216 
217  const int num_targets = nla.getNumberOfTargets();
218 
219  // make sure input and output views have same memory space
220  compadre_assert_debug((std::is_same<typename view_type_data_out::memory_space, typename view_type_data_in::memory_space>::value) &&
221  "output_data_single_column view and input_data_single_column view have difference memory spaces.");
222 
223  bool weight_with_pre_T = (pre_transform_local_index>=0 && pre_transform_global_index>=0) ? true : false;
224  bool target_plus_neighbor_staggered_schema = sro.use_target_site_weights;
225 
226  // loops over target indices
227  Kokkos::parallel_for(team_policy(num_targets, Kokkos::AUTO),
228  KOKKOS_LAMBDA(const member_type& teamMember) {
229 
230  const int target_index = teamMember.league_rank();
231  teamMember.team_barrier();
232 
233 
234  const double previous_value = output_data_single_column(target_index);
235 
236  // loops over neighbors of target_index
237  auto alpha_index = gmls.getAlphaIndexDevice(target_index, alpha_input_output_component_index);
238  double gmls_value = 0;
239  Kokkos::parallel_reduce(Kokkos::TeamThreadRange(teamMember, nla.getNumberOfNeighborsDevice(target_index)), [=](const int i, double& t_value) {
240  const double neighbor_varying_pre_T = (weight_with_pre_T && vary_on_neighbor) ?
241  prestencil_weights(0, target_index, i, pre_transform_local_index, pre_transform_global_index)
242  : 1.0;
243 
244  t_value += neighbor_varying_pre_T * sampling_data_single_column(nla.getNeighborDevice(target_index, i))
245  *alphas(alpha_index + i);
246 
247  }, gmls_value );
248 
249  // data contract for sampling functional
250  double pre_T = 1.0;
251  if (weight_with_pre_T) {
252  if (!vary_on_neighbor && vary_on_target) {
253  pre_T = prestencil_weights(0, target_index, 0, pre_transform_local_index,
254  pre_transform_global_index);
255  } else if (!vary_on_target) { // doesn't vary on target or neighbor
256  pre_T = prestencil_weights(0, 0, 0, pre_transform_local_index,
257  pre_transform_global_index);
258  }
259  }
260 
261  double staggered_value_from_targets = 0;
262  double pre_T_staggered = 1.0;
263  auto alpha_index2 = gmls.getAlphaIndexDevice(target_index, alpha_input_output_component_index2);
264  // loops over target_index for each neighbor for staggered approaches
265  if (target_plus_neighbor_staggered_schema) {
266  Kokkos::parallel_reduce(Kokkos::TeamThreadRange(teamMember, nla.getNumberOfNeighborsDevice(target_index)), [=](const int i, double& t_value) {
267  const double neighbor_varying_pre_T_staggered = (weight_with_pre_T && vary_on_neighbor) ?
268  prestencil_weights(1, target_index, i, pre_transform_local_index, pre_transform_global_index)
269  : 1.0;
270 
271  t_value += neighbor_varying_pre_T_staggered * sampling_data_single_column(nla.getNeighborDevice(target_index, 0))
272  *alphas(alpha_index2 + i);
273 
274  }, staggered_value_from_targets );
275 
276  // for staggered approaches that transform source data for the target and neighbors
277  if (weight_with_pre_T) {
278  if (!vary_on_neighbor && vary_on_target) {
279  pre_T_staggered = prestencil_weights(1, target_index, 0, pre_transform_local_index,
280  pre_transform_global_index);
281  } else if (!vary_on_target) { // doesn't vary on target or neighbor
282  pre_T_staggered = prestencil_weights(1, 0, 0, pre_transform_local_index,
283  pre_transform_global_index);
284  }
285  }
286  }
287 
288  double added_value = pre_T*gmls_value + pre_T_staggered*staggered_value_from_targets;
289  Kokkos::single(Kokkos::PerTeam(teamMember), [=] () {
290  output_data_single_column(target_index) = previous_value + added_value;
291  });
292  });
293  Kokkos::fence();
294  }
295 
296  //! Postprocessing for manifolds. Maps local chart vector solutions to ambient space.
297  //! THE SAMPLING DATA and OUTPUT VIEW MUST BE ON THE DEVICE!
298  //!
299  //! Only supports one output component / input component at a time. The user will need to loop over the output
300  //! components in order to transform a vector target.
301  //!
302  //! Assumptions on input data:
303  //! \param output_data_single_column [out] - 1D Kokkos View (memory space must be device_memory_space())
304  //! \param sampling_data_single_column [in] - 1D Kokkos View (memory space must match output_data_single_column)
305  //! \param local_dim_index [in] - For manifold problems, this is the local coordinate direction that sampling data may need to be transformed to before the application of GMLS
306  //! \param global_dim_index [in] - For manifold problems, this is the global coordinate direction that sampling data can be represented in
307  template <typename view_type_data_out, typename view_type_data_in>
308  void applyLocalChartToAmbientSpaceTransform(view_type_data_out output_data_single_column, view_type_data_in sampling_data_single_column, const int local_dim_index, const int global_dim_index) const {
309 
310  // Does T transpose times a vector
311  auto global_dimensions = _gmls->getGlobalDimensions();
312 
313  // gather needed information for evaluation
314  auto nla = *(_gmls->getNeighborLists());
315  const int num_targets = nla.getNumberOfTargets();
316 
317  auto tangent_directions = _gmls->getTangentDirections();
318 
319  // make sure input and output views have same memory space
320  compadre_assert_debug((std::is_same<typename view_type_data_out::memory_space, typename view_type_data_in::memory_space>::value) &&
321  "output_data_single_column view and input_data_single_column view have difference memory spaces.");
322 
323  // loops over target indices
324  Kokkos::parallel_for(team_policy(num_targets, Kokkos::AUTO),
325  KOKKOS_LAMBDA(const member_type& teamMember) {
326 
327  const int target_index = teamMember.league_rank();
328 
330  (tangent_directions.data() + TO_GLOBAL(target_index)*TO_GLOBAL(global_dimensions)*TO_GLOBAL(global_dimensions),
331  global_dimensions, global_dimensions);
332  teamMember.team_barrier();
333 
334 
335  const double previous_value = output_data_single_column(target_index);
336 
337  double added_value = T(local_dim_index, global_dim_index)*sampling_data_single_column(target_index);
338  Kokkos::single(Kokkos::PerTeam(teamMember), [=] () {
339  output_data_single_column(target_index) = previous_value + added_value;
340  });
341  });
342  Kokkos::fence();
343  }
344 
345  //! Transformation of data under GMLS
346  //!
347  //! This function is the go to function to be used when the alpha values have already been calculated and stored for use. The sampling functional provided instructs how a data transformation tensor is to be used on source data before it is provided to the GMLS operator. Once the sampling functional (if applicable) and the GMLS operator have been applied, this function also handles mapping the local vector back to the ambient space if working on a manifold problem and a target functional who has rank 1 output.
348  //!
349  //! Produces a Kokkos View as output with a Kokkos memory_space provided as a template tag by the caller.
350  //! The data type (double* or double**) must also be specified as a template type if one wish to get a 1D
351  //! Kokkos View back that can be indexed into with only one ordinal.
352  //!
353  //! Assumptions on input data:
354  //! \param sampling_data [in] - 1D or 2D Kokkos View that has the layout #targets * columns of data. Memory space for data can be host or device.
355  //! \param lro [in] - Target operation from the TargetOperation enum
356  //! \param sro_in [in] - Sampling functional from the SamplingFunctional enum
357  //! \param scalar_as_vector_if_needed [in] - If a 1D view is given, where a 2D view is expected (scalar values given where a vector was expected), then the scalar will be repeated for as many components as the vector has
358  //! \param evaluation_site_local_index [in] - 0 corresponds to evaluating at the target site itself, while a number larger than 0 indicates evaluation at a site other than the target, and specified by calling setAdditionalEvaluationSitesData on the GMLS class
359  template <typename output_data_type = double**, typename output_memory_space, typename view_type_input_data, typename output_array_layout = typename view_type_input_data::array_layout>
360  Kokkos::View<output_data_type, output_array_layout, output_memory_space> // shares layout of input by default
361  applyAlphasToDataAllComponentsAllTargetSites(view_type_input_data sampling_data, TargetOperation lro, const SamplingFunctional sro_in = PointSample, bool scalar_as_vector_if_needed = true, const int evaluation_site_local_index = 0) const {
362 
363 
364  // output can be device or host
365  // input can be device or host
366  // move everything to device and calculate there, then move back to host if necessary
367 
368  typedef Kokkos::View<output_data_type, output_array_layout, output_memory_space> output_view_type;
369 
370  auto problem_type = _gmls->getProblemType();
371  auto global_dimensions = _gmls->getGlobalDimensions();
372  auto output_dimension1_of_operator = (TargetOutputTensorRank[lro]<2) ? _gmls->getOutputDimensionOfOperation(lro) : std::sqrt(_gmls->getOutputDimensionOfOperation(lro));
373  auto output_dimension2_of_operator = (TargetOutputTensorRank[lro]<2) ? 1 : std::sqrt(_gmls->getOutputDimensionOfOperation(lro));
374  auto input_dimension_of_operator = _gmls->getInputDimensionOfOperation(lro);
375 
376  // gather needed information for evaluation
377  auto nla = *(_gmls->getNeighborLists());
378 
379  // determines the number of columns needed for output after action of the target functional
380  int output_dimensions = _gmls->getOutputDimensionOfOperation(lro);
381 
382  // special case for VectorPointSample, because if it is on a manifold it includes data transform to local charts
383  auto sro = (problem_type==MANIFOLD && sro_in==VectorPointSample) ? ManifoldVectorPointSample : sro_in;
384 
385  // create view on whatever memory space the user specified with their template argument when calling this function
386  output_view_type target_output = createView<output_view_type>("output of target operation",
387  nla.getNumberOfTargets(), output_dimensions);
388 
389  // make sure input and output columns make sense under the target operation
390  compadre_assert_debug(((output_dimensions==1 && output_view_type::rank==1) || output_view_type::rank!=1) &&
391  "Output view is requested as rank 1, but the target requires a rank larger than 1. Try double** as template argument.");
392 
393  // we need to specialize a template on the rank of the output view type and the input view type
394  auto sampling_subview_maker = CreateNDSliceOnDeviceView(sampling_data, scalar_as_vector_if_needed);
395  auto output_subview_maker = CreateNDSliceOnDeviceView(target_output, false); // output will always be the correct dimension
396 
397  // figure out preprocessing and postprocessing
398  auto prestencil_weights = _gmls->getPrestencilWeights();
399 
400  // all loop logic based on transforming data under a sampling functional
401  // into something that is valid input for GMLS
402  bool vary_on_target = false, vary_on_neighbor = false;
403  auto sro_style = sro.transform_type;
404  bool loop_global_dimensions = sro.input_rank>0 && sro_style!=Identity;
405 
407  && "SamplingFunctional requested for Evaluator does not match GMLS data sampling functional or is not of type 'Identity'.");
408 
409  if (sro.transform_type == Identity || sro.transform_type == SameForAll) {
410  vary_on_target = false;
411  vary_on_neighbor = false;
412  } else if (sro.transform_type == DifferentEachTarget) {
413  vary_on_target = true;
414  vary_on_neighbor = false;
415  } else if (sro.transform_type == DifferentEachNeighbor) {
416  vary_on_target = true;
417  vary_on_neighbor = true;
418  }
419 
420 
421  // only written for up to rank 1 to rank 2 (in / out)
422  // loop over components of output of the target operation
423  for (int axes1=0; axes1<output_dimension1_of_operator; ++axes1) {
424  const int output_component_axis_1 = axes1;
425  for (int axes2=0; axes2<output_dimension2_of_operator; ++axes2) {
426  const int output_component_axis_2 = axes2;
427  // loop over components of input of the target operation
428  for (int j=0; j<input_dimension_of_operator; ++j) {
429  const int input_component_axis_1 = j;
430  const int input_component_axis_2 = 0;
431 
432  if (loop_global_dimensions) {
433  for (int k=0; k<global_dimensions; ++k) { // loop for handling sampling functional
435  output_subview_maker.get1DView(axes1*output_dimension2_of_operator+axes2),
436  sampling_subview_maker.get1DView(k), lro, sro,
437  evaluation_site_local_index, output_component_axis_1, output_component_axis_2, input_component_axis_1,
438  input_component_axis_2, j, k, -1, -1,
439  vary_on_target, vary_on_neighbor);
440  }
441  } else if (sro_style != Identity) {
443  output_subview_maker.get1DView(axes1*output_dimension2_of_operator+axes2),
444  sampling_subview_maker.get1DView(j), lro, sro,
445  evaluation_site_local_index, output_component_axis_1, output_component_axis_2, input_component_axis_1,
446  input_component_axis_2, 0, 0, -1, -1,
447  vary_on_target, vary_on_neighbor);
448  } else { // standard
450  output_subview_maker.get1DView(axes1*output_dimension2_of_operator+axes2),
451  sampling_subview_maker.get1DView(j), lro, sro,
452  evaluation_site_local_index, output_component_axis_1, output_component_axis_2, input_component_axis_1,
453  input_component_axis_2);
454  }
455  }
456  }
457  }
458 
459  bool transform_gmls_output_to_ambient = (problem_type==MANIFOLD && TargetOutputTensorRank[(int)lro]==1);
460  if (transform_gmls_output_to_ambient) {
461  Kokkos::fence();
462 
463  // create view on whatever memory space the user specified with their template argument when calling this function
464  output_view_type ambient_target_output = createView<output_view_type>(
465  "output of transform to ambient space", nla.getNumberOfTargets(),
466  global_dimensions);
467  auto transformed_output_subview_maker = CreateNDSliceOnDeviceView(ambient_target_output, false);
468  // output will always be the correct dimension
469  for (int i=0; i<global_dimensions; ++i) {
470  for (int j=0; j<output_dimensions; ++j) {
472  transformed_output_subview_maker.get1DView(i), output_subview_maker.get1DView(j), j, i);
473  }
474  }
475  // copy back to whatever memory space the user requester through templating from the device
476  Kokkos::deep_copy(ambient_target_output, transformed_output_subview_maker.copyToAndReturnOriginalView());
477  return ambient_target_output;
478  }
479 
480  // copy back to whatever memory space the user requester through templating from the device
481  Kokkos::deep_copy(target_output, output_subview_maker.copyToAndReturnOriginalView());
482  return target_output;
483  }
484 
485 
486  //! Dot product of data with full polynomial coefficient basis where sampling data is in a 1D/2D Kokkos View and output view is also
487  //! a 1D/2D Kokkos View, however THE SAMPLING DATA and OUTPUT VIEW MUST BE ON THE DEVICE!
488  //!
489  //! This function is to be used when the polynomial coefficient basis has already been calculated and stored for use.
490  //!
491  //! Only supports one output component / input component at a time. The user will need to loop over the output
492  //! components in order to fill a vector target or matrix target.
493  //!
494  //! Assumptions on input data:
495  //! \param output_data_block_column [out] - 2D Kokkos View (memory space must be device_memory_space())
496  //! \param sampling_data_single_column [in] - 1D Kokkos View (memory space must match output_data_single_column)
497  //! \param sro [in] - Sampling functional from the SamplingFunctional enum
498  //! \param target_index [in] - Target # user wants to reconstruct target functional at, corresponds to row number of neighbor_lists
499  //! \param output_component_axis_1 [in] - Row for a rank 2 tensor or rank 1 tensor, 0 for a scalar output
500  //! \param output_component_axis_2 [in] - Columns for a rank 2 tensor, 0 for rank less than 2 output tensor
501  //! \param input_component_axis_1 [in] - Row for a rank 2 tensor or rank 1 tensor, 0 for a scalar input
502  //! \param input_component_axis_2 [in] - Columns for a rank 2 tensor, 0 for rank less than 2 input tensor
503  //! \param pre_transform_local_index [in] - For manifold problems, this is the local coordinate direction that sampling data may need to be transformed to before the application of GMLS
504  //! \param pre_transform_global_index [in] - For manifold problems, this is the global coordinate direction that sampling data can be represented in
505  //! \param post_transform_local_index [in] - For manifold problems, this is the local coordinate direction that vector output target functionals from GMLS will output into
506  //! \param post_transform_global_index [in] - For manifold problems, this is the global coordinate direction that the target functional output from GMLS will be transformed into
507  //! \param vary_on_target [in] - Whether the sampling functional has a tensor to act on sampling data that varies with each target site
508  //! \param vary_on_neighbor [in] - Whether the sampling functional has a tensor to act on sampling data that varies with each neighbor site in addition to varying wit each target site
509  template <typename view_type_data_out, typename view_type_data_in>
510  void applyFullPolynomialCoefficientsBasisToDataSingleComponent(view_type_data_out output_data_block_column, view_type_data_in sampling_data_single_column, const SamplingFunctional sro, const int output_component_axis_1, const int output_component_axis_2, const int input_component_axis_1, const int input_component_axis_2, const int pre_transform_local_index = -1, const int pre_transform_global_index = -1, const int post_transform_local_index = -1, const int post_transform_global_index = -1, bool vary_on_target = false, bool vary_on_neighbor = false) const {
511 
512  auto nla = *(_gmls->getNeighborLists());
513 
514  auto coefficient_matrix_dims = _gmls->getPolynomialCoefficientsDomainRangeSize();
515  auto coefficient_memory_layout_dims = _gmls->getPolynomialCoefficientsMemorySize();
516  auto coefficient_memory_layout_dims_device =
517  Kokkos::create_mirror_view_and_copy(device_memory_space(), coefficient_memory_layout_dims);
518 
519  auto global_dimensions = _gmls->getGlobalDimensions();
520 
521  // gather needed information for evaluation
522  auto coeffs = _gmls->getFullPolynomialCoefficientsBasis();
523  auto tangent_directions = _gmls->getTangentDirections();
524  auto prestencil_weights = _gmls->getPrestencilWeights();
525 
526  const int num_targets = nla.getNumberOfTargets();
527 
528  // make sure input and output views have same memory space
529  compadre_assert_debug((std::is_same<typename view_type_data_out::memory_space, typename view_type_data_in::memory_space>::value) &&
530  "output_data_block_column view and input_data_single_column view have difference memory spaces.");
531 
532  bool weight_with_pre_T = (pre_transform_local_index>=0 && pre_transform_global_index>=0) ? true : false;
533  bool target_plus_neighbor_staggered_schema = sro.use_target_site_weights;
534 
535  // loops over target indices
536  for (int j=0; j<coefficient_matrix_dims(0); ++j) {
537  Kokkos::parallel_for(team_policy(num_targets, Kokkos::AUTO),
538  KOKKOS_LAMBDA(const member_type& teamMember) {
539 
540  const int target_index = teamMember.league_rank();
541 
542  scratch_matrix_right_type T (tangent_directions.data()
543  + TO_GLOBAL(target_index)*TO_GLOBAL(global_dimensions)*TO_GLOBAL(global_dimensions),
544  global_dimensions, global_dimensions);
545 
547  Coeffs = scratch_matrix_right_type(coeffs.data()
548  + TO_GLOBAL(target_index)*TO_GLOBAL(coefficient_memory_layout_dims_device(0))
549  *TO_GLOBAL(coefficient_memory_layout_dims_device(1)),
550  coefficient_memory_layout_dims_device(0), coefficient_memory_layout_dims_device(1));
551 
552  teamMember.team_barrier();
553 
554 
555  const double previous_value = output_data_block_column(target_index, j);
556 
557  // loops over neighbors of target_index
558  double gmls_value = 0;
559  Kokkos::parallel_reduce(Kokkos::TeamThreadRange(teamMember, nla.getNumberOfNeighborsDevice(target_index)), [=](const int i, double& t_value) {
560  const double neighbor_varying_pre_T = (weight_with_pre_T && vary_on_neighbor) ?
561  prestencil_weights(0, target_index, i, pre_transform_local_index, pre_transform_global_index)
562  : 1.0;
563 
564  t_value += neighbor_varying_pre_T * sampling_data_single_column(nla.getNeighborDevice(target_index, i))
565  *Coeffs(j, i+input_component_axis_1*nla.getNumberOfNeighborsDevice(target_index));
566 
567  }, gmls_value );
568 
569  // data contract for sampling functional
570  double pre_T = 1.0;
571  if (weight_with_pre_T) {
572  if (!vary_on_neighbor && vary_on_target) {
573  pre_T = prestencil_weights(0, target_index, 0, pre_transform_local_index,
574  pre_transform_global_index);
575  } else if (!vary_on_target) { // doesn't vary on target or neighbor
576  pre_T = prestencil_weights(0, 0, 0, pre_transform_local_index,
577  pre_transform_global_index);
578  }
579  }
580 
581  double staggered_value_from_targets = 0;
582  double pre_T_staggered = 1.0;
583  // loops over target_index for each neighbor for staggered approaches
584  if (target_plus_neighbor_staggered_schema) {
585  Kokkos::parallel_reduce(Kokkos::TeamThreadRange(teamMember, nla.getNumberOfNeighborsDevice(target_index)), [=](const int i, double& t_value) {
586  const double neighbor_varying_pre_T_staggered = (weight_with_pre_T && vary_on_neighbor) ?
587  prestencil_weights(1, target_index, i, pre_transform_local_index, pre_transform_global_index)
588  : 1.0;
589 
590  t_value += neighbor_varying_pre_T_staggered * sampling_data_single_column(nla.getNeighborDevice(target_index, 0))
591  *Coeffs(j, i+input_component_axis_1*nla.getNumberOfNeighborsDevice(target_index));
592 
593  }, staggered_value_from_targets );
594 
595  // for staggered approaches that transform source data for the target and neighbors
596  if (weight_with_pre_T) {
597  if (!vary_on_neighbor && vary_on_target) {
598  pre_T_staggered = prestencil_weights(1, target_index, 0, pre_transform_local_index,
599  pre_transform_global_index);
600  } else if (!vary_on_target) { // doesn't vary on target or neighbor
601  pre_T_staggered = prestencil_weights(1, 0, 0, pre_transform_local_index,
602  pre_transform_global_index);
603  }
604  }
605  }
606 
607  double added_value = (pre_T*gmls_value + pre_T_staggered*staggered_value_from_targets);
608  Kokkos::single(Kokkos::PerTeam(teamMember), [=] () {
609  output_data_block_column(target_index, j) = previous_value + added_value;
610  });
611  });
612  Kokkos::fence();
613  }
614  }
615 
616  //! Generation of polynomial reconstruction coefficients by applying to data in GMLS
617  //!
618  //! Polynomial reconstruction coefficients exist for each target, but there are coefficients for each neighbor (a basis for all potentional input data). This function uses a particular choice of data to contract over this basis and return the polynomial reconstructions coefficients specific to this data.
619  //!
620  //! Produces a Kokkos View as output with a Kokkos memory_space provided as a template tag by the caller.
621  //! The data type (double* or double**) must also be specified as a template type if one wish to get a 1D
622  //! Kokkos View back that can be indexed into with only one ordinal.
623  //!
624  //! Assumptions on input data:
625  //! \param sampling_data [in] - 1D or 2D Kokkos View that has the layout #targets * columns of data. Memory space for data can be host or device.
626  //! \param sro [in] - Sampling functional from the SamplingFunctional enum
627  //! \param scalar_as_vector_if_needed [in] - If a 1D view is given, where a 2D view is expected (scalar values given where a vector was expected), then the scalar will be repeated for as many components as the vector has
628  template <typename output_data_type = double**, typename output_memory_space, typename view_type_input_data, typename output_array_layout = typename view_type_input_data::array_layout>
629  Kokkos::View<output_data_type, output_array_layout, output_memory_space> // shares layout of input by default
630  applyFullPolynomialCoefficientsBasisToDataAllComponents(view_type_input_data sampling_data, bool scalar_as_vector_if_needed = true) const {
631 
632  // output can be device or host
633  // input can be device or host
634  // move everything to device and calculate there, then move back to host if necessary
635 
636  typedef Kokkos::View<output_data_type, output_array_layout, output_memory_space> output_view_type;
637 
638  auto global_dimensions = _gmls->getGlobalDimensions();
639  auto output_dimension_of_reconstruction_space = _gmls->calculateBasisMultiplier(_gmls->getReconstructionSpace());
640  auto input_dimension_of_reconstruction_space = _gmls->calculateSamplingMultiplier(_gmls->getReconstructionSpace(), _gmls->getPolynomialSamplingFunctional());
641  auto coefficient_matrix_dims = _gmls->getPolynomialCoefficientsDomainRangeSize();
642 
643  // gather needed information for evaluation
644  auto nla = *(_gmls->getNeighborLists());
645 
646  // determines the number of columns needed for output
647  int output_dimensions = output_dimension_of_reconstruction_space;
648 
650 
651  // create view on whatever memory space the user specified with their template argument when calling this function
652  output_view_type coefficient_output("output coefficients", nla.getNumberOfTargets(),
653  output_dimensions*_gmls->getPolynomialCoefficientsSize() /* number of coefficients */);
654 
655  // make sure input and output columns make sense under the target operation
656  compadre_assert_debug(((output_dimension_of_reconstruction_space==1 && output_view_type::rank==1) || output_view_type::rank!=1) &&
657  "Output view is requested as rank 1, but the target requires a rank larger than 1. Try double** as template argument.");
658 
659  // we need to specialize a template on the rank of the output view type and the input view type
660  auto sampling_subview_maker = CreateNDSliceOnDeviceView(sampling_data, scalar_as_vector_if_needed);
661  auto output_subview_maker = CreateNDSliceOnDeviceView(coefficient_output, false); // output will always be the correct dimension
662 
663  // figure out preprocessing and postprocessing
664  auto prestencil_weights = _gmls->getPrestencilWeights();
665 
666  // all loop logic based on transforming data under a sampling functional
667  // into something that is valid input for GMLS
668  bool vary_on_target = false, vary_on_neighbor = false;
669  auto sro_style = sro.transform_type;
670  bool loop_global_dimensions = sro.input_rank>0 && sro_style!=Identity;
671 
672 
673  if (sro.transform_type == Identity || sro.transform_type == SameForAll) {
674  vary_on_target = false;
675  vary_on_neighbor = false;
676  } else if (sro.transform_type == DifferentEachTarget) {
677  vary_on_target = true;
678  vary_on_neighbor = false;
679  } else if (sro.transform_type == DifferentEachNeighbor) {
680  vary_on_target = true;
681  vary_on_neighbor = true;
682  }
683 
684  // written for up to rank 1 to rank 0 (in / out)
685  // loop over components of output of the target operation
686  for (int i=0; i<output_dimension_of_reconstruction_space; ++i) {
687  const int output_component_axis_1 = i;
688  const int output_component_axis_2 = 0;
689  // loop over components of input of the target operation
690  for (int j=0; j<input_dimension_of_reconstruction_space; ++j) {
691  const int input_component_axis_1 = j;
692  const int input_component_axis_2 = 0;
693 
694  if (loop_global_dimensions) {
695  for (int k=0; k<global_dimensions; ++k) { // loop for handling sampling functional
697  output_subview_maker.get2DView(i,_gmls->getPolynomialCoefficientsSize()),
698  sampling_subview_maker.get1DView(k), sro,
699  output_component_axis_1, output_component_axis_2, input_component_axis_1,
700  input_component_axis_2, j, k, -1, -1,
701  vary_on_target, vary_on_neighbor);
702  }
703  } else if (sro_style != Identity) {
705  output_subview_maker.get2DView(i,_gmls->getPolynomialCoefficientsSize()),
706  sampling_subview_maker.get1DView(j), sro,
707  output_component_axis_1, output_component_axis_2, input_component_axis_1,
708  input_component_axis_2, 0, 0, -1, -1,
709  vary_on_target, vary_on_neighbor);
710  } else { // standard
712  output_subview_maker.get2DView(i,_gmls->getPolynomialCoefficientsSize()),
713  sampling_subview_maker.get1DView(j), sro,
714  output_component_axis_1, output_component_axis_2, input_component_axis_1,
715  input_component_axis_2);
716  }
717  }
718  }
719 
720  // copy back to whatever memory space the user requester through templating from the device
721  Kokkos::deep_copy(coefficient_output, output_subview_maker.copyToAndReturnOriginalView());
722  return coefficient_output;
723  }
724 
725 }; // Evaluator
726 
727 } // Compadre
728 
729 #endif
SamplingFunctional getDataSamplingFunctional() const
Get the data sampling functional specified at instantiation (often the same as the polynomial samplin...
int calculateBasisMultiplier(const ReconstructionSpace rs) const
Calculate basis_multiplier.
ReconstructionSpace getReconstructionSpace() const
Get the reconstruction space specified at instantiation.
ProblemType getProblemType()
Get problem type.
Lightweight Evaluator Helper This class is a lightweight wrapper for extracting and applying all rele...
constexpr SamplingFunctional ManifoldVectorPointSample
Point evaluations of the entire vector source function (but on a manifold, so it includes a transform...
decltype(_prestencil_weights) getPrestencilWeights() const
Get a view (device) of all rank 2 preprocessing tensors This is a rank 5 tensor that is able to provi...
team_policy::member_type member_type
void applyAlphasToDataSingleComponentAllTargetSitesWithPreAndPostTransform(view_type_data_out output_data_single_column, view_type_data_in sampling_data_single_column, TargetOperation lro, const SamplingFunctional sro, const int evaluation_site_local_index, const int output_component_axis_1, const int output_component_axis_2, const int input_component_axis_1, const int input_component_axis_2, const int pre_transform_local_index=-1, const int pre_transform_global_index=-1, const int post_transform_local_index=-1, const int post_transform_global_index=-1, bool vary_on_target=false, bool vary_on_neighbor=false) const
Dot product of alphas with sampling data where sampling data is in a 1D/2D Kokkos View and output vie...
Each target applies a different data transform, but the same to each neighbor.
Each target applies a different transform for each neighbor.
int getInputDimensionOfOperation(TargetOperation lro) const
Dimensions ^ input rank for target operation (always in local chart if on a manifold, never ambient space)
bool use_target_site_weights
Whether or not the SamplingTensor acts on the target site as well as the neighbors.
Kokkos::View< output_data_type, output_array_layout, output_memory_space > applyFullPolynomialCoefficientsBasisToDataAllComponents(view_type_input_data sampling_data, bool scalar_as_vector_if_needed=true) const
Generation of polynomial reconstruction coefficients by applying to data in GMLS. ...
global_index_type getAlphaIndexHost(const int target_index, const int alpha_column_offset) const
Gives index into alphas given two axes, which when incremented by the neighbor number transforms acce...
Solve GMLS problem on a manifold (will use QR or SVD to solve the resultant GMLS problem dependent on...
int getAlphaColumnOffset(TargetOperation lro, const int output_component_axis_1, const int output_component_axis_2, const int input_component_axis_1, const int input_component_axis_2, const int additional_evaluation_local_index=0) const
Retrieves the offset for an operator based on input and output component, generic to row (but still m...
decltype(_T) getTangentDirections() const
Get a view (device) of all tangent direction bundles.
double applyAlphasToDataSingleComponentSingleTargetSite(view_type_data sampling_input_data, const int column_of_input, TargetOperation lro, const int target_index, const int evaluation_site_local_index, const int output_component_axis_1, const int output_component_axis_2, const int input_component_axis_1, const int input_component_axis_2, bool scalar_as_vector_if_needed=true) const
Dot product of alphas with sampling data, FOR A SINGLE target_index, where sampling data is in a 1D/2...
constexpr int TargetOutputTensorRank[]
Rank of target functional output for each TargetOperation Rank of target functional input for each Ta...
Kokkos::TeamPolicy< device_execution_space > team_policy
void applyLocalChartToAmbientSpaceTransform(view_type_data_out output_data_single_column, view_type_data_in sampling_data_single_column, const int local_dim_index, const int global_dim_index) const
Postprocessing for manifolds.
#define TO_GLOBAL(variable)
device_execution_space::memory_space device_memory_space
int input_rank
Rank of sampling functional input for each SamplingFunctional.
int getPolynomialCoefficientsSize() const
Returns size of the basis used in instance&#39;s polynomial reconstruction.
typename std::enable_if< B, T >::type enable_if_t
auto get1DView(const int column_num) -> decltype(Kokkos::subview(_data_in, Kokkos::ALL, column_num))
Kokkos::View< double **, layout_right, Kokkos::MemoryTraits< Kokkos::Unmanaged > > scratch_matrix_right_type
Each neighbor for each target all apply the same transform.
SubviewND(T data_in, T2 data_original_view, bool scalar_as_vector_if_needed)
auto CreateNDSliceOnDeviceView(T sampling_input_data_host_or_device, bool scalar_as_vector_if_needed) -> SubviewND< decltype(Kokkos::create_mirror_view(device_memory_space(), sampling_input_data_host_or_device)), T >
Copies data_in to the device, and then allows for access to 1D columns of data on device...
decltype(_alphas) getAlphas() const
Get a view (device) of all alphas.
decltype(_RHS) getFullPolynomialCoefficientsBasis() const
Get a view (device) of all polynomial coefficients basis.
int getGlobalDimensions() const
Dimension of the GMLS problem&#39;s point data (spatial description of points in ambient space)...
Generalized Moving Least Squares (GMLS)
No action performed on data before GMLS target operation.
int transform_type
Describes the SamplingFunction relationship to targets, neighbors.
Kokkos::View< output_data_type, output_array_layout, output_memory_space > applyAlphasToDataAllComponentsAllTargetSites(view_type_input_data sampling_data, TargetOperation lro, const SamplingFunctional sro_in=PointSample, bool scalar_as_vector_if_needed=true, const int evaluation_site_local_index=0) const
Transformation of data under GMLS.
auto get2DView(const int column_num, const int block_size) -> decltype(Kokkos::subview(_data_in, Kokkos::ALL, Kokkos::make_pair(column_num *block_size,(column_num+1)*block_size)))
constexpr SamplingFunctional PointSample
Available sampling functionals.
int calculateSamplingMultiplier(const ReconstructionSpace rs, const SamplingFunctional sro) const
Calculate sampling_multiplier.
host_managed_local_index_type getPolynomialCoefficientsDomainRangeSize() const
Returns (size of the basis used in instance&#39;s polynomial reconstruction) x (data input dimension) ...
decltype(_neighbor_lists)* getNeighborLists()
Get neighbor list accessor.
struct SubviewND< T, T2, enable_if_t<(T::rank< 2)> >{T _data_in;T2 _data_original_view;bool _scalar_as_vector_if_needed;SubviewND(T data_in, T2 data_original_view, bool scalar_as_vector_if_needed){_data_in=data_in;_data_original_view=data_original_view;_scalar_as_vector_if_needed=scalar_as_vector_if_needed;}auto get1DView(const int column_num) -> decltype(Kokkos::subview(_data_in, Kokkos::ALL))
Creates 1D subviews of data from a 1D view, generally constructed with CreateNDSliceOnDeviceView.
#define compadre_assert_debug(condition)
compadre_assert_debug is used for assertions that are checked in loops, as these significantly impact...
void applyFullPolynomialCoefficientsBasisToDataSingleComponent(view_type_data_out output_data_block_column, view_type_data_in sampling_data_single_column, const SamplingFunctional sro, const int output_component_axis_1, const int output_component_axis_2, const int input_component_axis_1, const int input_component_axis_2, const int pre_transform_local_index=-1, const int pre_transform_global_index=-1, const int post_transform_local_index=-1, const int post_transform_global_index=-1, bool vary_on_target=false, bool vary_on_neighbor=false) const
Dot product of data with full polynomial coefficient basis where sampling data is in a 1D/2D Kokkos V...
SamplingFunctional getPolynomialSamplingFunctional() const
Get the polynomial sampling functional specified at instantiation.
int getOutputDimensionOfOperation(TargetOperation lro, bool ambient=false) const
Dimensions ^ output rank for target operation.
#define compadre_assert_release(condition)
compadre_assert_release is used for assertions that should always be checked, but generally are not e...
Creates 1D subviews of data from a 2D view, generally constructed with CreateNDSliceOnDeviceView.
host_managed_local_index_type getPolynomialCoefficientsMemorySize() const
Returns 2D array size in memory on which coefficients are stored.
constexpr SamplingFunctional VectorPointSample
Point evaluations of the entire vector source function.
TargetOperation
Available target functionals.