Compadre  1.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
GMLS_Manifold.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <string>
3 #include <vector>
4 #include <map>
5 #include <stdlib.h>
6 #include <cstdio>
7 #include <random>
8 
9 #include <Compadre_Config.h>
10 #include <Compadre_GMLS.hpp>
11 #include <Compadre_Evaluator.hpp>
13 
14 #include "GMLS_Manifold.hpp"
15 
16 #ifdef COMPADRE_USE_MPI
17 #include <mpi.h>
18 #endif
19 
20 #include <Kokkos_Timer.hpp>
21 #include <Kokkos_Core.hpp>
22 
23 using namespace Compadre;
24 
25 //! [Parse Command Line Arguments]
26 
27 // called from command line
28 int main (int argc, char* args[]) {
29 
30 // initializes MPI (if available) with command line arguments given
31 #ifdef COMPADRE_USE_MPI
32 MPI_Init(&argc, &args);
33 #endif
34 
35 // initializes Kokkos with command line arguments given
36 Kokkos::initialize(argc, args);
37 
38 // code block to reduce scope for all Kokkos View allocations
39 // otherwise, Views may be deallocating when we call Kokkos::finalize() later
40 {
41  // check if 8 arguments are given from the command line, the first being the program name
42  // constraint_type used in solving each GMLS problem:
43  // 0 - No constraints used in solving each GMLS problem
44  // 1 - Neumann Gradient Scalar used in solving each GMLS problem
45  int constraint_type = 0; // No constraints by default
46  if (argc >= 8) {
47  int arg8toi = atoi(args[7]);
48  if (arg8toi > 0) {
49  constraint_type = arg8toi;
50  }
51  }
52 
53  // check if 7 arguments are given from the command line, the first being the program name
54  // problem_type used in solving each GMLS problem:
55  // 0 - Standard GMLS problem
56  // 1 - Manifold GMLS problem
57  int problem_type = 1; // Manifold for this example
58  if (argc >= 7) {
59  int arg7toi = atoi(args[6]);
60  if (arg7toi > 0) {
61  problem_type = arg7toi;
62  }
63  }
64 
65  // check if 6 arguments are given from the command line, the first being the program name
66  // solver_type used for factorization in solving each GMLS problem:
67  // 0 - SVD used for factorization in solving each GMLS problem
68  // 1 - QR used for factorization in solving each GMLS problem
69  // 2 - LU used for factorization in solving each GMLS problem
70  int solver_type = 1; // QR by default
71  if (argc >= 6) {
72  int arg6toi = atoi(args[5]);
73  if (arg6toi >= 0) {
74  solver_type = arg6toi;
75  }
76  }
77 
78  // check if 5 arguments are given from the command line, the first being the program name
79  // N_pts_on_sphere used to determine spatial resolution
80  int N_pts_on_sphere = 1000; // 1000 points by default
81  if (argc >= 5) {
82  int arg5toi = atoi(args[4]);
83  if (arg5toi > 0) {
84  N_pts_on_sphere = arg5toi;
85  }
86  }
87 
88  // check if 4 arguments are given from the command line
89  // dimension for the coordinates and the solution
90  int dimension = 3; // dimension 3 by default
91  if (argc >= 4) {
92  int arg4toi = atoi(args[3]);
93  if (arg4toi > 0) {
94  dimension = arg4toi;
95  }
96  }
97 
98  // check if 3 arguments are given from the command line
99  // set the number of target sites where we will reconstruct the target functionals at
100  int number_target_coords = 200; // 200 target sites by default
101  if (argc >= 3) {
102  int arg3toi = atoi(args[2]);
103  if (arg3toi > 0) {
104  number_target_coords = arg3toi;
105  }
106  }
107 
108  // check if 2 arguments are given from the command line
109  // set the number of target sites where we will reconstruct the target functionals at
110  int order = 3; // 3rd degree polynomial basis by default
111  if (argc >= 2) {
112  int arg2toi = atoi(args[1]);
113  if (arg2toi > 0) {
114  order = arg2toi;
115  }
116  }
117 
118  // minimum neighbors for unisolvency is the same as the size of the polynomial basis
119  // dimension has one subtracted because it is a D-1 manifold represented in D dimensions
120  const int min_neighbors = Compadre::GMLS::getNP(order, dimension-1);
121 
122  //! [Parse Command Line Arguments]
123  Kokkos::Timer timer;
124  Kokkos::Profiling::pushRegion("Setup Point Data");
125  //! [Setting Up The Point Cloud]
126 
127 
128  // coordinates of source sites, bigger than needed then resized later
129  Kokkos::View<double**, Kokkos::DefaultExecutionSpace> source_coords_device("source coordinates",
130  1.25*N_pts_on_sphere, 3);
131  Kokkos::View<double**>::HostMirror source_coords = Kokkos::create_mirror_view(source_coords_device);
132 
133  double r = 1.0;
134 
135  // set number of source coordinates from what was calculated
136  int number_source_coords;
137 
138  {
139  // fill source coordinates from surface of a sphere with quasiuniform points
140  // algorithm described at https://www.cmu.edu/biolphys/deserno/pdf/sphere_equi.pdf
141  int N_count = 0;
142  double a = 4*PI*r*r/N_pts_on_sphere;
143  double d = std::sqrt(a);
144  int M_theta = std::round(PI/d);
145  double d_theta = PI/M_theta;
146  double d_phi = a/d_theta;
147  for (int i=0; i<M_theta; ++i) {
148  double theta = PI*(i + 0.5)/M_theta;
149  int M_phi = std::round(2*PI*std::sin(theta)/d_phi);
150  for (int j=0; j<M_phi; ++j) {
151  double phi = 2*PI*j/M_phi;
152  source_coords(N_count, 0) = theta;
153  source_coords(N_count, 1) = phi;
154  N_count++;
155  }
156  }
157 
158  for (int i=0; i<N_count; ++i) {
159  double theta = source_coords(i,0);
160  double phi = source_coords(i,1);
161  source_coords(i,0) = r*std::sin(theta)*std::cos(phi);
162  source_coords(i,1) = r*std::sin(theta)*std::sin(phi);
163  source_coords(i,2) = r*cos(theta);
164  //printf("%f %f %f\n", source_coords(i,0), source_coords(i,1), source_coords(i,2));
165  }
166  number_source_coords = N_count;
167  }
168 
169  // resize source_coords to the size actually needed
170  Kokkos::resize(source_coords, number_source_coords, 3);
171  Kokkos::resize(source_coords_device, number_source_coords, 3);
172 
173  // coordinates of target sites
174  Kokkos::View<double**, Kokkos::DefaultExecutionSpace> target_coords_device ("target coordinates",
175  number_target_coords, 3);
176  Kokkos::View<double**>::HostMirror target_coords = Kokkos::create_mirror_view(target_coords_device);
177 
178  {
179  bool enough_pts_found = false;
180  // fill target coordinates from surface of a sphere with quasiuniform points
181  // stop when enough points are found
182  int N_count = 0;
183  double a = 4.0*PI*r*r/((double)(5.0*number_target_coords)); // 5.0 is in case number_target_coords is set to something very small (like 1)
184  double d = std::sqrt(a);
185  int M_theta = std::round(PI/d);
186  double d_theta = PI/((double)M_theta);
187  double d_phi = a/d_theta;
188  for (int i=0; i<M_theta; ++i) {
189  double theta = PI*(i + 0.5)/M_theta;
190  int M_phi = std::round(2*PI*std::sin(theta)/d_phi);
191  for (int j=0; j<M_phi; ++j) {
192  double phi = 2*PI*j/M_phi;
193  target_coords(N_count, 0) = theta;
194  target_coords(N_count, 1) = phi;
195  N_count++;
196  if (N_count == number_target_coords) {
197  enough_pts_found = true;
198  break;
199  }
200  }
201  if (enough_pts_found) break;
202  }
203 
204  for (int i=0; i<N_count; ++i) {
205  double theta = target_coords(i,0);
206  double phi = target_coords(i,1);
207  target_coords(i,0) = r*std::sin(theta)*std::cos(phi);
208  target_coords(i,1) = r*std::sin(theta)*std::sin(phi);
209  target_coords(i,2) = r*cos(theta);
210  //printf("%f %f %f\n", target_coords(i,0), target_coords(i,1), target_coords(i,2));
211  }
212  }
213 
214 
215  //! [Setting Up The Point Cloud]
216 
217  Kokkos::Profiling::popRegion();
218  Kokkos::fence();
219  Kokkos::Profiling::pushRegion("Creating Data");
220 
221  //! [Creating The Data]
222 
223 
224  // source coordinates need copied to device before using to construct sampling data
225  Kokkos::deep_copy(source_coords_device, source_coords);
226 
227  // target coordinates copied next, because it is a convenient time to send them to device
228  Kokkos::deep_copy(target_coords_device, target_coords);
229 
230  // ensure that source coordinates are sent to device before evaluating sampling data based on them
231  Kokkos::fence();
232 
233 
234  // need Kokkos View storing true solution (for samples)
235  Kokkos::View<double*, Kokkos::DefaultExecutionSpace> sampling_data_device("samples of true solution",
236  source_coords_device.extent(0));
237 
238  Kokkos::View<double*, Kokkos::DefaultExecutionSpace> ones_data_device("samples of ones",
239  source_coords_device.extent(0));
240  Kokkos::deep_copy(ones_data_device, 1.0);
241 
242  // need Kokkos View storing true vector solution (for samples)
243  Kokkos::View<double**, Kokkos::DefaultExecutionSpace> sampling_vector_data_device("samples of vector true solution",
244  source_coords_device.extent(0), 3);
245 
246  Kokkos::parallel_for("Sampling Manufactured Solutions", Kokkos::RangePolicy<Kokkos::DefaultExecutionSpace>
247  (0,source_coords.extent(0)), KOKKOS_LAMBDA(const int i) {
248 
249  // coordinates of source site i
250  double xval = source_coords_device(i,0);
251  double yval = (dimension>1) ? source_coords_device(i,1) : 0;
252  double zval = (dimension>2) ? source_coords_device(i,2) : 0;
253 
254  // data for targets with scalar input
255  sampling_data_device(i) = sphere_harmonic54(xval, yval, zval);
256 
257  for (int j=0; j<3; ++j) {
258  double gradient[3] = {0,0,0};
259  gradient_sphereHarmonic54_ambient(gradient, xval, yval, zval);
260  sampling_vector_data_device(i,j) = gradient[j];
261  }
262  });
263 
264 
265  //! [Creating The Data]
266 
267  Kokkos::Profiling::popRegion();
268  Kokkos::Profiling::pushRegion("Neighbor Search");
269 
270  //! [Performing Neighbor Search]
271 
272 
273  // Point cloud construction for neighbor search
274  // CreatePointCloudSearch constructs an object of type PointCloudSearch, but deduces the templates for you
275  auto point_cloud_search(CreatePointCloudSearch(source_coords, dimension));
276 
277  // each row is a neighbor list for a target site, with the first column of each row containing
278  // the number of neighbors for that rows corresponding target site
279  double epsilon_multiplier = 1.9;
280  int estimated_upper_bound_number_neighbors =
281  point_cloud_search.getEstimatedNumberNeighborsUpperBound(min_neighbors, dimension, epsilon_multiplier);
282 
283  Kokkos::View<int**, Kokkos::DefaultExecutionSpace> neighbor_lists_device("neighbor lists",
284  number_target_coords, estimated_upper_bound_number_neighbors); // first column is # of neighbors
285  Kokkos::View<int**>::HostMirror neighbor_lists = Kokkos::create_mirror_view(neighbor_lists_device);
286 
287  // each target site has a window size
288  Kokkos::View<double*, Kokkos::DefaultExecutionSpace> epsilon_device("h supports", number_target_coords);
289  Kokkos::View<double*>::HostMirror epsilon = Kokkos::create_mirror_view(epsilon_device);
290 
291  // query the point cloud to generate the neighbor lists using a kdtree to produce the n nearest neighbor
292  // to each target site, adding (epsilon_multiplier-1)*100% to whatever the distance away the further neighbor used is from
293  // each target to the view for epsilon
294  point_cloud_search.generate2DNeighborListsFromKNNSearch(false /*not dry run*/, target_coords, neighbor_lists,
295  epsilon, min_neighbors, epsilon_multiplier);
296 
297  //! [Performing Neighbor Search]
298 
299  Kokkos::Profiling::popRegion();
300  Kokkos::fence(); // let call to build neighbor lists complete before copying back to device
301  timer.reset();
302 
303  //! [Setting Up The GMLS Object]
304 
305 
306  // Copy data back to device (they were filled on the host)
307  // We could have filled Kokkos Views with memory space on the host
308  // and used these instead, and then the copying of data to the device
309  // would be performed in the GMLS class
310  Kokkos::deep_copy(neighbor_lists_device, neighbor_lists);
311  Kokkos::deep_copy(epsilon_device, epsilon);
312 
313  // solver name for passing into the GMLS class
314  std::string solver_name;
315  if (solver_type == 0) { // SVD
316  solver_name = "SVD";
317  } else if (solver_type == 1) { // QR
318  solver_name = "QR";
319  } else if (solver_type == 2) { // LU
320  solver_name = "LU";
321  }
322 
323  // problem name for passing into the GMLS class
324  std::string problem_name;
325  if (problem_type == 0) { // Standard
326  problem_name = "STANDARD";
327  } else if (problem_type == 1) { // Manifold
328  problem_name = "MANIFOLD";
329  }
330 
331  // boundary name for passing into the GMLS class
332  std::string constraint_name;
333  if (constraint_type == 0) { // No constraints
334  constraint_name = "NO_CONSTRAINT";
335  } else if (constraint_type == 1) { // Neumann Gradient Scalar
336  constraint_name = "NEUMANN_GRAD_SCALAR";
337  }
338 
339  // initialize an instance of the GMLS class for problems with a scalar basis and
340  // traditional point sampling as the sampling functional
341  GMLS my_GMLS_scalar(order, dimension,
342  solver_name.c_str(), problem_name.c_str(), constraint_name.c_str(),
343  order /*manifold order*/);
344 
345  // pass in neighbor lists, source coordinates, target coordinates, and window sizes
346  //
347  // neighbor lists have the format:
348  // dimensions: (# number of target sites) X (# maximum number of neighbors for any given target + 1)
349  // the first column contains the number of neighbors for that rows corresponding target index
350  //
351  // source coordinates have the format:
352  // dimensions: (# number of source sites) X (dimension)
353  // entries in the neighbor lists (integers) correspond to rows of this 2D array
354  //
355  // target coordinates have the format:
356  // dimensions: (# number of target sites) X (dimension)
357  // # of target sites is same as # of rows of neighbor lists
358  //
359  my_GMLS_scalar.setProblemData(neighbor_lists_device, source_coords_device, target_coords_device, epsilon_device);
360 
361  // set a reference outward normal direction, causing a surface orientation after
362  // the GMLS instance computes an approximate tangent bundle
363  // on a sphere, the ambient coordinates are the outward normal direction
364  my_GMLS_scalar.setReferenceOutwardNormalDirection(target_coords_device, true /* use to orient surface */);
365 
366  // create a vector of target operations
367  std::vector<TargetOperation> lro_scalar(4);
368  lro_scalar[0] = ScalarPointEvaluation;
369  lro_scalar[1] = LaplacianOfScalarPointEvaluation;
370  lro_scalar[2] = GradientOfScalarPointEvaluation;
371  lro_scalar[3] = GaussianCurvaturePointEvaluation;
372 
373  // and then pass them to the GMLS class
374  my_GMLS_scalar.addTargets(lro_scalar);
375 
376  // sets the weighting kernel function from WeightingFunctionType for curvature
377  my_GMLS_scalar.setCurvatureWeightingType(WeightingFunctionType::Power);
378 
379  // power to use in the weighting kernel function for curvature coefficients
380  my_GMLS_scalar.setCurvatureWeightingPower(2);
381 
382  // sets the weighting kernel function from WeightingFunctionType
383  my_GMLS_scalar.setWeightingType(WeightingFunctionType::Power);
384 
385  // power to use in that weighting kernel function
386  my_GMLS_scalar.setWeightingPower(2);
387 
388  // generate the alphas that to be combined with data for each target operation requested in lro
389  my_GMLS_scalar.generateAlphas();
390 
391  Kokkos::Profiling::pushRegion("Full Polynomial Basis GMLS Solution");
392  // initialize another instance of the GMLS class for problems with a vector basis on a manifold and point
393  // evaluation of that vector as the sampling functional
394  // VectorTaylorPolynomial indicates that the basis will be a polynomial with as many components as the
395  // dimension of the manifold. This differs from another possibility, which follows this class.
397  order, dimension,
398  solver_name.c_str(), problem_name.c_str(), constraint_name.c_str(),
399  order /*manifold order*/);
400 
401  my_GMLS_vector.setProblemData(neighbor_lists_device, source_coords_device, target_coords_device, epsilon_device);
402  std::vector<TargetOperation> lro_vector(2);
403  lro_vector[0] = VectorPointEvaluation;
404  lro_vector[1] = DivergenceOfVectorPointEvaluation;
405  my_GMLS_vector.addTargets(lro_vector);
406  my_GMLS_vector.setCurvatureWeightingType(WeightingFunctionType::Power);
407  my_GMLS_vector.setCurvatureWeightingPower(2);
408  my_GMLS_vector.setWeightingType(WeightingFunctionType::Power);
409  my_GMLS_vector.setWeightingPower(2);
410  my_GMLS_vector.generateAlphas();
411  Kokkos::Profiling::popRegion();
412 
413  Kokkos::Profiling::pushRegion("Scalar Polynomial Basis Repeated to Form a Vector GMLS Solution");
414  // initialize another instance of the GMLS class for problems with a vector basis on a manifold and point
415  // evaluation of that vector as the sampling functional
416  // VectorOfScalarClonesTaylorPolynomial indicates a scalar polynomial will be solved for, since
417  // each component of the reconstructed vector are independent. This results in solving a smaller system
418  // for each GMLS problem, and is the suggested way to do vector reconstructions when sampling functionals
419  // acting on the basis would not create non-zero offdiagonal blocks.
420  //
421  // As an example, consider a 2D manifold in 3D ambient space. The GMLS problem is posed in the local chart,
422  // meaning that the problem being solved looks like
423  //
424  // [P_0 0 | where P_0 has dimension #number of neighbors for a target X #dimension of a scalar basis
425  // | 0 P_1]
426  //
427  // P_1 is similarly shaped, and for sampling functional that is a point evaluation, P_0 and P_1 are
428  // identical and their degrees of freedom in this system are disjoint, allowing us to solve for the
429  // degrees of freedom for either block independently. Additionally, the will produce the exact
430  // same polynomial coefficients for the point sampling functional, therefore it makes sense to use
431  // VectorOfScalarClonesTaylorPolynomial.
432  //
433  // In the print-out for this program, we include the timings and errors on this and VectorTaylorPolynomial
434  // in order to demonstrate that they produce exactly the same answer, but that one is much more efficient.
435  //
437  order, dimension,
438  solver_name.c_str(), problem_name.c_str(), constraint_name.c_str(),
439  order /*manifold order*/);
440 
441  my_GMLS_vector_of_scalar_clones.setProblemData(neighbor_lists_device, source_coords_device, target_coords_device, epsilon_device);
442  std::vector<TargetOperation> lro_vector_of_scalar_clones(2);
443  lro_vector_of_scalar_clones[0] = VectorPointEvaluation;
444  lro_vector_of_scalar_clones[1] = DivergenceOfVectorPointEvaluation;
445  my_GMLS_vector_of_scalar_clones.addTargets(lro_vector_of_scalar_clones);
446  my_GMLS_vector_of_scalar_clones.setCurvatureWeightingType(WeightingFunctionType::Power);
447  my_GMLS_vector_of_scalar_clones.setCurvatureWeightingPower(2);
448  my_GMLS_vector_of_scalar_clones.setWeightingType(WeightingFunctionType::Power);
449  my_GMLS_vector_of_scalar_clones.setWeightingPower(2);
450  my_GMLS_vector_of_scalar_clones.generateAlphas();
451  Kokkos::Profiling::popRegion();
452 
453 
454  //! [Setting Up The GMLS Object]
455 
456  double instantiation_time = timer.seconds();
457  std::cout << "Took " << instantiation_time << "s to complete alphas generation." << std::endl;
458  Kokkos::fence(); // let generateAlphas finish up before using alphas
459  Kokkos::Profiling::pushRegion("Apply Alphas to Data");
460 
461  //! [Apply GMLS Alphas To Data]
462 
463 
464  // it is important to note that if you expect to use the data as a 1D view, then you should use double*
465  // however, if you know that the target operation will result in a 2D view (vector or matrix output),
466  // then you should template with double** as this is something that can not be infered from the input data
467  // or the target operator at compile time. Additionally, a template argument is required indicating either
468  // Kokkos::HostSpace or Kokkos::DefaultExecutionSpace::memory_space()
469 
470  // The Evaluator class takes care of handling input data views as well as the output data views.
471  // It uses information from the GMLS class to determine how many components are in the input
472  // as well as output for any choice of target functionals and then performs the contactions
473  // on the data using the alpha coefficients generated by the GMLS class, all on the device.
474  Evaluator scalar_gmls_evaluator(&my_GMLS_scalar);
475  Evaluator vector_gmls_evaluator(&my_GMLS_vector);
476  Evaluator vector_gmls_evaluator_of_scalar_clones(&my_GMLS_vector_of_scalar_clones);
477 
478  auto output_value = scalar_gmls_evaluator.applyAlphasToDataAllComponentsAllTargetSites<double*, Kokkos::HostSpace>
479  (sampling_data_device, ScalarPointEvaluation);
480 
481  auto output_laplacian = scalar_gmls_evaluator.applyAlphasToDataAllComponentsAllTargetSites<double*, Kokkos::HostSpace>
482  (sampling_data_device, LaplacianOfScalarPointEvaluation);
483 
484  auto output_gradient = scalar_gmls_evaluator.applyAlphasToDataAllComponentsAllTargetSites<double**, Kokkos::HostSpace>
485  (sampling_data_device, GradientOfScalarPointEvaluation);
486 
487  auto output_gc = scalar_gmls_evaluator.applyAlphasToDataAllComponentsAllTargetSites<double*, Kokkos::HostSpace>
488  (ones_data_device, GaussianCurvaturePointEvaluation);
489 
490  auto output_vector = vector_gmls_evaluator.applyAlphasToDataAllComponentsAllTargetSites<double**, Kokkos::HostSpace>
491  (sampling_vector_data_device, VectorPointEvaluation, ManifoldVectorPointSample);
492 
493  auto output_divergence = vector_gmls_evaluator.applyAlphasToDataAllComponentsAllTargetSites<double*, Kokkos::HostSpace>
494  (sampling_vector_data_device, DivergenceOfVectorPointEvaluation, ManifoldVectorPointSample);
495 
496  auto output_vector_of_scalar_clones =
497  vector_gmls_evaluator_of_scalar_clones.applyAlphasToDataAllComponentsAllTargetSites<double**,
498  Kokkos::HostSpace>(sampling_vector_data_device, VectorPointEvaluation, ManifoldVectorPointSample);
499 
500  auto output_divergence_of_scalar_clones =
501  vector_gmls_evaluator_of_scalar_clones.applyAlphasToDataAllComponentsAllTargetSites<double*,
502  Kokkos::HostSpace>(sampling_vector_data_device, DivergenceOfVectorPointEvaluation, ManifoldVectorPointSample);
503 
504 
505  // Kokkos::fence(); // let application of alphas to data finish before using results
506  //
507  //// move gradient data to device so that it can be transformed into velocity
508  //auto output_gradient_device_mirror = Kokkos::create_mirror(Kokkos::DefaultExecutionSpace::memory_space(), output_gradient);
509  //Kokkos::deep_copy(output_gradient_device_mirror, output_gradient);
510  //Kokkos::parallel_for("Create Velocity From Surface Gradient", Kokkos::RangePolicy<Kokkos::DefaultExecutionSpace>
511  // (0,target_coords.extent(0)), KOKKOS_LAMBDA(const int i) {
512  //
513  // // coordinates of target site i
514  // double xval = target_coords_device(i,0);
515  // double yval = (dimension>1) ? target_coords_device(i,1) : 0;
516  // double zval = (dimension>2) ? target_coords_device(i,2) : 0;
517 
518  // double gradx = output_gradient_device_mirror(i,0);
519  // double grady = output_gradient_device_mirror(i,1);
520  // double gradz = output_gradient_device_mirror(i,2);
521  //
522  // // overwrites gradient with velocity
523  // output_gradient_device_mirror(i,0) = (grady*zval - yval*gradz);
524  // output_gradient_device_mirror(i,1) = (-(gradx*zval - xval*gradz));
525  // output_gradient_device_mirror(i,2) = (gradx*yval - xval*grady);
526  //
527  //});
528  //Kokkos::deep_copy(output_gradient, output_gradient_device_mirror);
529 
530 
531  //! [Apply GMLS Alphas To Data]
532 
533  Kokkos::fence(); // let application of alphas to data finish before using results
534  Kokkos::Profiling::popRegion();
535  // times the Comparison in Kokkos
536  Kokkos::Profiling::pushRegion("Comparison");
537 
538  //! [Check That Solutions Are Correct]
539 
540  double tangent_bundle_error = 0;
541  double tangent_bundle_norm = 0;
542  double values_error = 0;
543  double values_norm = 0;
544  double laplacian_error = 0;
545  double laplacian_norm = 0;
546  double gradient_ambient_error = 0;
547  double gradient_ambient_norm = 0;
548  double gc_error = 0;
549  double gc_norm = 0;
550  double vector_ambient_error = 0;
551  double vector_ambient_norm = 0;
552  double divergence_ambient_error = 0;
553  double divergence_ambient_norm = 0;
554  double vector_of_scalar_clones_ambient_error = 0;
555  double vector_of_scalar_clones_ambient_norm = 0;
556  double divergence_of_scalar_clones_ambient_error = 0;
557  double divergence_of_scalar_clones_ambient_norm = 0;
558 
559  // loop through the target sites
560  for (int i=0; i<number_target_coords; i++) {
561 
562  // load value from output
563  double GMLS_value = output_value(i);
564  double GMLS_gc = output_gc(i);
565 
566  // load laplacian from output
567  double GMLS_Laplacian = output_laplacian(i);
568 
569  // target site i's coordinate
570  double xval = target_coords(i,0);
571  double yval = (dimension>1) ? target_coords(i,1) : 0;
572  double zval = (dimension>2) ? target_coords(i,2) : 0;
573  double coord[3] = {xval, yval, zval};
574 
575  // get tangent vector and see if orthgonal to coordinate (it should be on a sphere)
576  for (int j=0; j<dimension-1; ++j) {
577  double tangent_inner_prod = 0;
578  for (int k=0; k<dimension; ++k) {
579  tangent_inner_prod += coord[k] * my_GMLS_scalar.getTangentBundle(i, j, k);
580  }
581  tangent_bundle_error += tangent_inner_prod * tangent_inner_prod;
582  }
583  double normal_inner_prod = 0;
584  for (int k=0; k<dimension; ++k) {
585  normal_inner_prod += coord[k] * my_GMLS_scalar.getTangentBundle(i, dimension-1, k);
586  }
587  // inner product could be plus or minus 1 (depends on tangent direction ordering)
588  double normal_error_to_sum = (normal_inner_prod > 0) ? normal_inner_prod - 1 : normal_inner_prod + 1;
589  tangent_bundle_error += normal_error_to_sum * normal_error_to_sum;
590  tangent_bundle_norm += 1;
591 
592  // evaluation of various exact solutions
593  double actual_value = sphere_harmonic54(xval, yval, zval);
594  double actual_Laplacian = laplace_beltrami_sphere_harmonic54(xval, yval, zval);
595  double actual_Gradient_ambient[3] = {0,0,0}; // initialized for 3, but only filled up to dimension
596  gradient_sphereHarmonic54_ambient(actual_Gradient_ambient, xval, yval, zval);
597  //velocity_sphereHarmonic54_ambient(actual_Gradient_ambient, xval, yval, zval);
598 
599  values_error += (GMLS_value - actual_value)*(GMLS_value - actual_value);
600  values_norm += actual_value*actual_value;
601 
602  laplacian_error += (GMLS_Laplacian - actual_Laplacian)*(GMLS_Laplacian - actual_Laplacian);
603  laplacian_norm += actual_Laplacian*actual_Laplacian;
604 
605  double actual_gc = 1.0;
606  gc_error += (GMLS_gc - actual_gc)*(GMLS_gc - actual_gc);
607  gc_norm += actual_gc*actual_gc;
608 
609  for (int j=0; j<dimension; ++j) {
610  gradient_ambient_error += (output_gradient(i,j) - actual_Gradient_ambient[j])*(output_gradient(i,j) - actual_Gradient_ambient[j]);
611  gradient_ambient_norm += actual_Gradient_ambient[j]*actual_Gradient_ambient[j];
612  }
613 
614  for (int j=0; j<dimension; ++j) {
615  vector_ambient_error += (output_vector(i,j) - actual_Gradient_ambient[j])*(output_vector(i,j) - actual_Gradient_ambient[j]);
616  vector_ambient_norm += actual_Gradient_ambient[j]*actual_Gradient_ambient[j];
617  }
618 
619  divergence_ambient_error += (output_divergence(i) - actual_Laplacian)*(output_divergence(i) - actual_Laplacian);
620  divergence_ambient_norm += actual_Laplacian*actual_Laplacian;
621 
622  for (int j=0; j<dimension; ++j) {
623  vector_of_scalar_clones_ambient_error += (output_vector_of_scalar_clones(i,j) - actual_Gradient_ambient[j])*(output_vector_of_scalar_clones(i,j) - actual_Gradient_ambient[j]);
624  vector_of_scalar_clones_ambient_norm += actual_Gradient_ambient[j]*actual_Gradient_ambient[j];
625  }
626 
627  divergence_of_scalar_clones_ambient_error += (output_divergence_of_scalar_clones(i) - actual_Laplacian)*(output_divergence_of_scalar_clones(i) - actual_Laplacian);
628  divergence_of_scalar_clones_ambient_norm += actual_Laplacian*actual_Laplacian;
629 
630  }
631 
632  tangent_bundle_error /= number_target_coords;
633  tangent_bundle_error = std::sqrt(tangent_bundle_error);
634  tangent_bundle_norm /= number_target_coords;
635  tangent_bundle_norm = std::sqrt(tangent_bundle_norm);
636 
637  values_error /= number_target_coords;
638  values_error = std::sqrt(values_error);
639  values_norm /= number_target_coords;
640  values_norm = std::sqrt(values_norm);
641 
642  laplacian_error /= number_target_coords;
643  laplacian_error = std::sqrt(laplacian_error);
644  laplacian_norm /= number_target_coords;
645  laplacian_norm = std::sqrt(laplacian_norm);
646 
647  gradient_ambient_error /= number_target_coords;
648  gradient_ambient_error = std::sqrt(gradient_ambient_error);
649  gradient_ambient_norm /= number_target_coords;
650  gradient_ambient_norm = std::sqrt(gradient_ambient_norm);
651 
652  gc_error /= number_target_coords;
653  gc_error = std::sqrt(gc_error);
654  gc_norm /= number_target_coords;
655  gc_norm = std::sqrt(gc_norm);
656 
657  vector_ambient_error /= number_target_coords;
658  vector_ambient_error = std::sqrt(vector_ambient_error);
659  vector_ambient_norm /= number_target_coords;
660  vector_ambient_norm = std::sqrt(vector_ambient_norm);
661 
662  divergence_ambient_error /= number_target_coords;
663  divergence_ambient_error = std::sqrt(divergence_ambient_error);
664  divergence_ambient_norm /= number_target_coords;
665  divergence_ambient_norm = std::sqrt(divergence_ambient_norm);
666 
667  vector_of_scalar_clones_ambient_error /= number_target_coords;
668  vector_of_scalar_clones_ambient_error = std::sqrt(vector_of_scalar_clones_ambient_error);
669  vector_of_scalar_clones_ambient_norm /= number_target_coords;
670  vector_of_scalar_clones_ambient_norm = std::sqrt(vector_of_scalar_clones_ambient_norm);
671 
672  divergence_of_scalar_clones_ambient_error /= number_target_coords;
673  divergence_of_scalar_clones_ambient_error = std::sqrt(divergence_of_scalar_clones_ambient_error);
674  divergence_of_scalar_clones_ambient_norm /= number_target_coords;
675  divergence_of_scalar_clones_ambient_norm = std::sqrt(divergence_of_scalar_clones_ambient_norm);
676 
677  printf("Tangent Bundle Error: %g\n", tangent_bundle_error / tangent_bundle_norm);
678  printf("Point Value Error: %g\n", values_error / values_norm);
679  printf("Laplace-Beltrami Error: %g\n", laplacian_error / laplacian_norm);
680  printf("Gaussian Curvature Error: %g\n", gc_error / gc_norm);
681  printf("Surface Gradient (Ambient) Error: %g\n", gradient_ambient_error / gradient_ambient_norm);
682  printf("Surface Vector (VectorBasis) Error: %g\n", vector_ambient_error / vector_ambient_norm);
683  printf("Surface Divergence (VectorBasis) Error: %g\n", divergence_ambient_error / divergence_ambient_norm);
684  printf("Surface Vector (ScalarClones) Error: %g\n",
685  vector_of_scalar_clones_ambient_error / vector_of_scalar_clones_ambient_norm);
686  printf("Surface Divergence (ScalarClones) Error: %g\n",
687  divergence_of_scalar_clones_ambient_error / divergence_of_scalar_clones_ambient_norm);
688  //! [Check That Solutions Are Correct]
689  // popRegion hidden from tutorial
690  // stop timing comparison loop
691  Kokkos::Profiling::popRegion();
692  //! [Finalize Program]
693 
694 
695 } // end of code block to reduce scope, causing Kokkos View de-allocations
696 // otherwise, Views may be deallocating when we call Kokkos::finalize() later
697 
698 // finalize Kokkos and MPI (if available)
699 Kokkos::finalize();
700 #ifdef COMPADRE_USE_MPI
701 MPI_Finalize();
702 #endif
703 
704 return 0;
705 
706 } // main
707 
708 
709 //! [Finalize Program]
KOKKOS_INLINE_FUNCTION double sphere_harmonic54(double x, double y, double z)
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...
Point evaluation of a vector (reconstructs entire vector at once, requiring a ReconstructionSpace hav...
PointCloudSearch< view_type > CreatePointCloudSearch(view_type src_view, const local_index_type dimensions=-1, const local_index_type max_leaf=-1)
CreatePointCloudSearch allows for the construction of an object of type PointCloudSearch with templat...
#define PI
Point evaluation of Gaussian curvature.
int main(int argc, char *args[])
[Parse Command Line Arguments]
Definition: GMLS_Device.cpp:29
Point evaluation of a scalar.
static KOKKOS_INLINE_FUNCTION int getNP(const int m, const int dimension=3, const ReconstructionSpace r_space=ReconstructionSpace::ScalarTaylorPolynomial)
Returns size of the basis for a given polynomial order and dimension General to dimension 1...
Scalar basis reused as many times as there are components in the vector resulting in a much cheaper p...
Point evaluation of the laplacian of a scalar (could be on a manifold or not)
Point evaluation of the divergence of a vector (results in a scalar)
KOKKOS_INLINE_FUNCTION void gradient_sphereHarmonic54_ambient(double *gradient, double x, double y, double z)
Point evaluation of the gradient of a scalar.
Generalized Moving Least Squares (GMLS)
import subprocess import os import re import math import sys import argparse d d d(20 *num_target_sites *pow(4, grid_num))
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.
void setProblemData(view_type_1 neighbor_lists, view_type_2 source_coordinates, view_type_3 target_coordinates, view_type_4 epsilons)
Sets basic problem data (neighbor lists, source coordinates, and target coordinates) ...
KOKKOS_INLINE_FUNCTION double laplace_beltrami_sphere_harmonic54(double x, double y, double z)
Vector polynomial basis having # of components _dimensions, or (_dimensions-1) in the case of manifol...