Compadre  1.5.9
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Compadre_ScalarTaylorPolynomial.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Compadre: COMpatible PArticle Discretization and REmap Toolkit
4 //
5 // Copyright 2018 NTESS and the Compadre contributors.
6 // SPDX-License-Identifier: BSD-2-Clause
7 // *****************************************************************************
8 // @HEADER
9 #ifndef _COMPADRE_SCALAR_TAYLORPOLYNOMIAL_BASIS_HPP_
10 #define _COMPADRE_SCALAR_TAYLORPOLYNOMIAL_BASIS_HPP_
11 
12 #include "Compadre_GMLS.hpp"
13 
14 namespace Compadre {
15 /*! \brief Definition of scalar Taylor polynomial basis
16 
17  For order P, the sum of the basis is defined by:
18  \li in 1D) \f[\sum_{n=0}^{n=P} \frac{(x/h)^n}{n!}\f]
19  \li in 2D) \f[\sum_{n=0}^{n=P} \sum_{k=0}^{k=n} \frac{(x/h)^{n-k}*(y/h)^k}{(n-k)!k!}\f]
20  \li in 3D) \f[\sum_{p=0}^{p=P} \sum_{k_1+k_2+k_3=n} \frac{(x/h)^{k_1}*(y/h)^{k_2}*(z/h)^{k_3}}{k_1!k_2!k_3!}\f]
21 */
22 namespace ScalarTaylorPolynomialBasis {
23 
24  /*! \brief Returns size of basis
25  \param degree [in] - highest degree of polynomial
26  \param dimension [in] - spatial dimension to evaluate
27  */
28  KOKKOS_INLINE_FUNCTION
29  int getSize(const int degree, const int dimension) {
30  if (dimension == 3) return (degree+1)*(degree+2)*(degree+3)/6;
31  else if (dimension == 2) return (degree+1)*(degree+2)/2;
32  else return degree+1;
33  }
34 
35  /*! \brief Evaluates the scalar Taylor polynomial basis
36  * delta[j] = weight_of_original_value * delta[j] + weight_of_new_value * (calculation of this function)
37  \param delta [in/out] - scratch space that is allocated so that each thread has its own copy. Must be at least as large as the _basis_multipler*the dimension of the polynomial basis.
38  \param workspace [in/out] - scratch space that is allocated so that each thread has its own copy. Must be at least as large as the _poly_order*the spatial dimension of the polynomial basis.
39  \param dimension [in] - spatial dimension to evaluate
40  \param max_degree [in] - highest degree of polynomial
41  \param h [in] - epsilon/window size
42  \param x [in] - x coordinate (already shifted by target)
43  \param y [in] - y coordinate (already shifted by target)
44  \param z [in] - z coordinate (already shifted by target)
45  \param starting_order [in] - polynomial order to start with (default=0)
46  \param weight_of_original_value [in] - weighting to assign to original value in delta (default=0, replace, 1-increment current value)
47  \param weight_of_new_value [in] - weighting to assign to new contribution (default=1, add to/replace)
48  */
49  KOKKOS_INLINE_FUNCTION
50  void evaluate(const member_type& teamMember, double* delta, double* workspace, const int dimension, const int max_degree, const double h, const double x, const double y, const double z, const int starting_order = 0, const double weight_of_original_value = 0.0, const double weight_of_new_value = 1.0) {
51  Kokkos::single(Kokkos::PerThread(teamMember), [&] () {
52  const double factorial[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200};
53  if (dimension==3) {
54  scratch_vector_type x_over_h_to_i(workspace, max_degree+1);
55  scratch_vector_type y_over_h_to_i(workspace+1*(max_degree+1), max_degree+1);
56  scratch_vector_type z_over_h_to_i(workspace+2*(max_degree+1), max_degree+1);
57  x_over_h_to_i[0] = 1;
58  y_over_h_to_i[0] = 1;
59  z_over_h_to_i[0] = 1;
60  for (int i=1; i<=max_degree; ++i) {
61  x_over_h_to_i[i] = x_over_h_to_i[i-1]*(x/h);
62  y_over_h_to_i[i] = y_over_h_to_i[i-1]*(y/h);
63  z_over_h_to_i[i] = z_over_h_to_i[i-1]*(z/h);
64  }
65  // (in 3D) \sum_{p=0}^{p=P} \sum_{k1+k2+k3=n} (x/h)^k1*(y/h)^k2*(z/h)^k3 / (k1!k2!k3!)
66  int alphax, alphay, alphaz;
67  double alphaf;
68  int i=0, s=0;
69  for (int n = starting_order; n <= max_degree; n++){
70  for (alphaz = 0; alphaz <= n; alphaz++){
71  s = n - alphaz;
72  for (alphay = 0; alphay <= s; alphay++){
73  alphax = s - alphay;
74  alphaf = factorial[alphax]*factorial[alphay]*factorial[alphaz];
75  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * x_over_h_to_i[alphax]*y_over_h_to_i[alphay]*z_over_h_to_i[alphaz]/alphaf;
76  i++;
77  }
78  }
79  }
80  } else if (dimension==2) {
81  scratch_vector_type x_over_h_to_i(workspace, max_degree+1);
82  scratch_vector_type y_over_h_to_i(workspace+1*(max_degree+1), max_degree+1);
83  x_over_h_to_i[0] = 1;
84  y_over_h_to_i[0] = 1;
85  for (int i=1; i<=max_degree; ++i) {
86  x_over_h_to_i[i] = x_over_h_to_i[i-1]*(x/h);
87  y_over_h_to_i[i] = y_over_h_to_i[i-1]*(y/h);
88  }
89  // (in 2D) \sum_{n=0}^{n=P} \sum_{k=0}^{k=n} (x/h)^(n-k)*(y/h)^k / ((n-k)!k!)
90  int alphax, alphay;
91  double alphaf;
92  int i = 0;
93  for (int n = starting_order; n <= max_degree; n++){
94  for (alphay = 0; alphay <= n; alphay++){
95  alphax = n - alphay;
96  alphaf = factorial[alphax]*factorial[alphay];
97  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * x_over_h_to_i[alphax]*y_over_h_to_i[alphay]/alphaf;
98  i++;
99  }
100  }
101  } else {
102  scratch_vector_type x_over_h_to_i(workspace, max_degree+1);
103  x_over_h_to_i[0] = 1;
104  for (int i=1; i<=max_degree; ++i) {
105  x_over_h_to_i[i] = x_over_h_to_i[i-1]*(x/h);
106  }
107  // (in 1D) \sum_{n=0}^{n=P} (x/h)^n / n!
108  for (int i=starting_order; i<=max_degree; ++i) {
109  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * x_over_h_to_i[i]/factorial[i];
110  }
111  }
112  });
113  }
114 
115  /*! \brief Evaluates the first partial derivatives of scalar Taylor polynomial basis
116  * delta[j] = weight_of_original_value * delta[j] + weight_of_new_value * (calculation of this function)
117  \param delta [in/out] - scratch space that is allocated so that each thread has its own copy. Must be at least as large as the _basis_multipler*the dimension of the polynomial basis.
118  \param workspace [in/out] - scratch space that is allocated so that each thread has its own copy. Must be at least as large as the _poly_order*the spatial dimension of the polynomial basis.
119  \param dimension [in] - spatial dimension to evaluate
120  \param max_degree [in] - highest degree of polynomial
121  \param partial_direction [in] - direction in which to take partial derivative
122  \param h [in] - epsilon/window size
123  \param x [in] - x coordinate (already shifted by target)
124  \param y [in] - y coordinate (already shifted by target)
125  \param z [in] - z coordinate (already shifted by target)
126  \param starting_order [in] - polynomial order to start with (default=0)
127  \param weight_of_original_value [in] - weighting to assign to original value in delta (default=0, replace, 1-increment current value)
128  \param weight_of_new_value [in] - weighting to assign to new contribution (default=1, add to/replace)
129  */
130  KOKKOS_INLINE_FUNCTION
131  void evaluatePartialDerivative(const member_type& teamMember, double* delta, double* workspace, const int dimension, const int max_degree, const int partial_direction, const double h, const double x, const double y, const double z, const int starting_order = 0, const double weight_of_original_value = 0.0, const double weight_of_new_value = 1.0) {
132  Kokkos::single(Kokkos::PerThread(teamMember), [&] () {
133  const double factorial[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200};
134  if (dimension==3) {
135  scratch_vector_type x_over_h_to_i(workspace, max_degree+1);
136  scratch_vector_type y_over_h_to_i(workspace+1*(max_degree+1), max_degree+1);
137  scratch_vector_type z_over_h_to_i(workspace+2*(max_degree+1), max_degree+1);
138  x_over_h_to_i[0] = 1;
139  y_over_h_to_i[0] = 1;
140  z_over_h_to_i[0] = 1;
141  for (int i=1; i<=max_degree; ++i) {
142  x_over_h_to_i[i] = x_over_h_to_i[i-1]*(x/h);
143  y_over_h_to_i[i] = y_over_h_to_i[i-1]*(y/h);
144  z_over_h_to_i[i] = z_over_h_to_i[i-1]*(z/h);
145  }
146  // (in 3D) \sum_{p=0}^{p=P} \sum_{k1+k2+k3=n} (x/h)^k1*(y/h)^k2*(z/h)^k3 / (k1!k2!k3!)
147  int alphax, alphay, alphaz;
148  double alphaf;
149  int i=0, s=0;
150  for (int n = starting_order; n <= max_degree; n++){
151  for (alphaz = 0; alphaz <= n; alphaz++){
152  s = n - alphaz;
153  for (alphay = 0; alphay <= s; alphay++){
154  alphax = s - alphay;
155 
156  int var_pow[3] = {alphax, alphay, alphaz};
157  var_pow[partial_direction]--;
158 
159  if (var_pow[0]<0 || var_pow[1]<0 || var_pow[2]<0) {
160  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 0.0;
161  } else {
162  alphaf = factorial[var_pow[0]]*factorial[var_pow[1]]*factorial[var_pow[2]];
163  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 1./h * x_over_h_to_i[var_pow[0]]*y_over_h_to_i[var_pow[1]]*z_over_h_to_i[var_pow[2]]/alphaf;
164  }
165  i++;
166  }
167  }
168  }
169  } else if (dimension==2) {
170  scratch_vector_type x_over_h_to_i(workspace, max_degree+1);
171  scratch_vector_type y_over_h_to_i(workspace+1*(max_degree+1), max_degree+1);
172  x_over_h_to_i[0] = 1;
173  y_over_h_to_i[0] = 1;
174  for (int i=1; i<=max_degree; ++i) {
175  x_over_h_to_i[i] = x_over_h_to_i[i-1]*(x/h);
176  y_over_h_to_i[i] = y_over_h_to_i[i-1]*(y/h);
177  }
178  // (in 3D) \sum_{p=0}^{p=P} \sum_{k1+k2+k3=n} (x/h)^k1*(y/h)^k2*(z/h)^k3 / (k1!k2!k3!)
179  int alphax, alphay;
180  double alphaf;
181  int i=0;
182  for (int n = starting_order; n <= max_degree; n++){
183  for (alphay = 0; alphay <= n; alphay++){
184  alphax = n - alphay;
185 
186  int var_pow[2] = {alphax, alphay};
187  var_pow[partial_direction]--;
188 
189  if (var_pow[0]<0 || var_pow[1]<0) {
190  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 0.0;
191  } else {
192  alphaf = factorial[var_pow[0]]*factorial[var_pow[1]];
193  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 1./h * x_over_h_to_i[var_pow[0]]*y_over_h_to_i[var_pow[1]]/alphaf;
194  }
195  i++;
196  }
197  }
198  } else {
199  scratch_vector_type x_over_h_to_i(workspace, max_degree+1);
200  x_over_h_to_i[0] = 1;
201  for (int i=1; i<=max_degree; ++i) {
202  x_over_h_to_i[i] = x_over_h_to_i[i-1]*(x/h);
203  }
204  int alphax;
205  double alphaf;
206  int i=0;
207  for (int n = starting_order; n <= max_degree; n++){
208  alphax = n;
209 
210  int var_pow[1] = {alphax};
211  var_pow[partial_direction]--;
212 
213  if (var_pow[0]<0) {
214  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 0.0;
215  } else {
216  alphaf = factorial[var_pow[0]];
217  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 1./h * x_over_h_to_i[var_pow[0]]/alphaf;
218  }
219  i++;
220  }
221  }
222  });
223  }
224 
225  /*! \brief Evaluates the second partial derivatives of scalar Taylor polynomial basis
226  * delta[j] = weight_of_original_value * delta[j] + weight_of_new_value * (calculation of this function)
227  \param delta [in/out] - scratch space that is allocated so that each thread has its own copy. Must be at least as large as the _basis_multipler*the dimension of the polynomial basis.
228  \param workspace [in/out] - scratch space that is allocated so that each thread has its own copy. Must be at least as large as the _poly_order*the spatial dimension of the polynomial basis.
229  \param dimension [in] - spatial dimension to evaluate
230  \param max_degree [in] - highest degree of polynomial
231  \param partial_direction_1 [in] - direction in which to take first partial derivative
232  \param partial_direction_2 [in] - direction in which to take second partial derivative
233  \param h [in] - epsilon/window size
234  \param x [in] - x coordinate (already shifted by target)
235  \param y [in] - y coordinate (already shifted by target)
236  \param z [in] - z coordinate (already shifted by target)
237  \param starting_order [in] - polynomial order to start with (default=0)
238  \param weight_of_original_value [in] - weighting to assign to original value in delta (default=0, replace, 1-increment current value)
239  \param weight_of_new_value [in] - weighting to assign to new contribution (default=1, add to/replace)
240  */
241  KOKKOS_INLINE_FUNCTION
242  void evaluateSecondPartialDerivative(const member_type& teamMember, double* delta, double* workspace, const int dimension, const int max_degree, const int partial_direction_1, const int partial_direction_2, const double h, const double x, const double y, const double z, const int starting_order = 0, const double weight_of_original_value = 0.0, const double weight_of_new_value = 1.0) {
243  Kokkos::single(Kokkos::PerThread(teamMember), [&] () {
244  const double factorial[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200};
245  if (dimension==3) {
246  scratch_vector_type x_over_h_to_i(workspace, max_degree+1);
247  scratch_vector_type y_over_h_to_i(workspace+1*(max_degree+1), max_degree+1);
248  scratch_vector_type z_over_h_to_i(workspace+2*(max_degree+1), max_degree+1);
249  x_over_h_to_i[0] = 1;
250  y_over_h_to_i[0] = 1;
251  z_over_h_to_i[0] = 1;
252  for (int i=1; i<=max_degree; ++i) {
253  x_over_h_to_i[i] = x_over_h_to_i[i-1]*(x/h);
254  y_over_h_to_i[i] = y_over_h_to_i[i-1]*(y/h);
255  z_over_h_to_i[i] = z_over_h_to_i[i-1]*(z/h);
256  }
257  // (in 3D) \sum_{p=0}^{p=P} \sum_{k1+k2+k3=n} (x/h)^k1*(y/h)^k2*(z/h)^k3 / (k1!k2!k3!)
258  int alphax, alphay, alphaz;
259  double alphaf;
260  int i=0, s=0;
261  for (int n = starting_order; n <= max_degree; n++){
262  for (alphaz = 0; alphaz <= n; alphaz++){
263  s = n - alphaz;
264  for (alphay = 0; alphay <= s; alphay++){
265  alphax = s - alphay;
266 
267  int var_pow[3] = {alphax, alphay, alphaz};
268  var_pow[partial_direction_1]--;
269  var_pow[partial_direction_2]--;
270 
271  if (var_pow[0]<0 || var_pow[1]<0 || var_pow[2]<0) {
272  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 0.0;
273  } else {
274  alphaf = factorial[var_pow[0]]*factorial[var_pow[1]]*factorial[var_pow[2]];
275  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 1./h * x_over_h_to_i[var_pow[0]]*y_over_h_to_i[var_pow[1]]*z_over_h_to_i[var_pow[2]]/alphaf;
276  }
277  i++;
278  }
279  }
280  }
281  } else if (dimension==2) {
282  scratch_vector_type x_over_h_to_i(workspace, max_degree+1);
283  scratch_vector_type y_over_h_to_i(workspace+1*(max_degree+1), max_degree+1);
284  x_over_h_to_i[0] = 1;
285  y_over_h_to_i[0] = 1;
286  for (int i=1; i<=max_degree; ++i) {
287  x_over_h_to_i[i] = x_over_h_to_i[i-1]*(x/h);
288  y_over_h_to_i[i] = y_over_h_to_i[i-1]*(y/h);
289  }
290  // (in 3D) \sum_{p=0}^{p=P} \sum_{k1+k2+k3=n} (x/h)^k1*(y/h)^k2*(z/h)^k3 / (k1!k2!k3!)
291  int alphax, alphay;
292  double alphaf;
293  int i=0;
294  for (int n = starting_order; n <= max_degree; n++){
295  for (alphay = 0; alphay <= n; alphay++){
296  alphax = n - alphay;
297 
298  int var_pow[2] = {alphax, alphay};
299  var_pow[partial_direction_1]--;
300  var_pow[partial_direction_2]--;
301 
302  if (var_pow[0]<0 || var_pow[1]<0) {
303  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 0.0;
304  } else {
305  alphaf = factorial[var_pow[0]]*factorial[var_pow[1]];
306  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 1./h * x_over_h_to_i[var_pow[0]]*y_over_h_to_i[var_pow[1]]/alphaf;
307  }
308  i++;
309  }
310  }
311  } else {
312  scratch_vector_type x_over_h_to_i(workspace, max_degree+1);
313  x_over_h_to_i[0] = 1;
314  for (int i=1; i<=max_degree; ++i) {
315  x_over_h_to_i[i] = x_over_h_to_i[i-1]*(x/h);
316  }
317  int alphax;
318  double alphaf;
319  int i=0;
320  for (int n = starting_order; n <= max_degree; n++){
321  alphax = n;
322 
323  int var_pow[1] = {alphax};
324  var_pow[partial_direction_1]--;
325  var_pow[partial_direction_2]--;
326 
327  if (var_pow[0]<0) {
328  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 0.0;
329  } else {
330  alphaf = factorial[var_pow[0]];
331  *(delta+i) = weight_of_original_value * *(delta+i) + weight_of_new_value * 1./h * x_over_h_to_i[var_pow[0]]/alphaf;
332  }
333  i++;
334  }
335  }
336  });
337  }
338 
339 } // ScalarTaylorPolynomialBasis
340 
341 } // Compadre
342 
343 #endif
KOKKOS_INLINE_FUNCTION int getSize(const int degree, const int dimension)
Returns size of basis.
KOKKOS_INLINE_FUNCTION void evaluatePartialDerivative(const member_type &teamMember, double *delta, double *workspace, const int dimension, const int max_degree, const int partial_direction, const double h, const double x, const double y, const double z, const int starting_order=0, const double weight_of_original_value=0.0, const double weight_of_new_value=1.0)
Evaluates the first partial derivatives of scalar Taylor polynomial basis delta[j] = weight_of_origin...
team_policy::member_type member_type
KOKKOS_INLINE_FUNCTION void evaluate(const member_type &teamMember, double *delta, double *workspace, const int dimension, const int max_degree, const double h, const double x, const double y, const double z, const int starting_order=0, const double weight_of_original_value=0.0, const double weight_of_new_value=1.0)
Evaluates the scalar Taylor polynomial basis delta[j] = weight_of_original_value * delta[j] + weight_...
KOKKOS_INLINE_FUNCTION void evaluateSecondPartialDerivative(const member_type &teamMember, double *delta, double *workspace, const int dimension, const int max_degree, const int partial_direction_1, const int partial_direction_2, const double h, const double x, const double y, const double z, const int starting_order=0, const double weight_of_original_value=0.0, const double weight_of_new_value=1.0)
Evaluates the second partial derivatives of scalar Taylor polynomial basis delta[j] = weight_of_origi...
Kokkos::View< double *, Kokkos::MemoryTraits< Kokkos::Unmanaged > > scratch_vector_type