Reference documentation for deal.II version 9.0.0
cuda_tensor_product_kernels.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2017 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #ifndef dealii_cuda_tensor_product_kernels_h
18 #define dealii_cuda_tensor_product_kernels_h
19 
20 #include <deal.II/base/config.h>
21 
22 
23 DEAL_II_NAMESPACE_OPEN
24 
25 
26 namespace CUDAWrappers
27 {
28  namespace internal
29  {
36  // TODO: for now only the general variant is implemented
38  {
39  evaluate_general,
40  evaluate_symmetric,
41  evaluate_evenodd
42  };
43 
44 
45 
51  template <EvaluatorVariant variant, int dim, int fe_degree, int n_q_points_1d, typename Number>
53  {};
54 
55 
56 
63  template <int dim, int fe_degree, int n_q_points_1d, typename Number>
64  struct EvaluatorTensorProduct<evaluate_general, dim, fe_degree,
65  n_q_points_1d, Number>
66  {
67  static constexpr unsigned int dofs_per_cell = Utilities::pow(fe_degree + 1, dim);
68  static constexpr unsigned int n_q_points = Utilities::pow(n_q_points_1d, dim);
69 
70  __device__ EvaluatorTensorProduct();
71 
76  template <int direction, bool dof_to_quad, bool add, bool in_place>
77  __device__ void values(const Number *in, Number *out) const;
78 
83  template <int direction, bool dof_to_quad, bool add, bool in_place>
84  __device__ void gradients(const Number *in, Number *out) const;
85 
89  template <int direction, bool dof_to_quad, bool add, bool in_place>
90  __device__ void apply(Number shape_data[],
91  const Number *in,
92  Number *out) const;
93 
97  __device__ void value_at_quad_pts(Number *u);
98 
102  __device__ void integrate_value(Number *u);
103 
108  __device__ void gradient_at_quad_pts(const Number *const u,
109  Number *grad_u[dim]);
110 
115  template <bool add>
116  __device__ void integrate_gradient(Number *u,
117  Number *grad_u[dim]);
118  };
119 
120 
121 
122  template <int dim, int fe_degree, int n_q_points_1d, typename Number>
123  __device__ EvaluatorTensorProduct<evaluate_general, dim, fe_degree,
124  n_q_points_1d, Number>::EvaluatorTensorProduct()
125  {}
126 
127 
128 
129  template <int dim, int fe_degree, int n_q_points_1d, typename Number>
130  template <int direction, bool dof_to_quad, bool add, bool in_place>
131  __device__ void EvaluatorTensorProduct<evaluate_general, dim, fe_degree,
132  n_q_points_1d, Number>::values(const Number *in,
133  Number *out) const
134  {
135  apply<direction, dof_to_quad, add, in_place>(global_shape_values, in, out);
136  }
137 
138 
139 
140  template <int dim, int fe_degree, int n_q_points_1d, typename Number>
141  template <int direction, bool dof_to_quad, bool add, bool in_place>
142  __device__ void EvaluatorTensorProduct<evaluate_general, dim, fe_degree,
143  n_q_points_1d, Number>::gradients(const Number *in,
144  Number *out) const
145  {
146  apply<direction, dof_to_quad, add, in_place>(global_shape_gradients, in, out);
147  }
148 
149 
150 
151  template <int dim, int fe_degree, int n_q_points_1d, typename Number>
152  template <int direction, bool dof_to_quad, bool add, bool in_place>
153  __device__ void EvaluatorTensorProduct<evaluate_general, dim, fe_degree,
154  n_q_points_1d, Number>::apply(Number shape_data[],
155  const Number *in,
156  Number *out) const
157  {
158  const unsigned int i = (dim == 1) ? 0 : threadIdx.x%n_q_points_1d;
159  const unsigned int j = (dim == 3) ? threadIdx.y : 0;
160  const unsigned int q =
161  (dim == 1) ? (threadIdx.x%n_q_points_1d) :
162  (dim == 2) ? threadIdx.y :
163  threadIdx.z;
164 
165  // This loop simply multiply the shape function at the quadrature point by
166  // the value finite element coefficient.
167  Number t = 0;
168  for (int k=0; k<n_q_points_1d; ++k)
169  {
170  const unsigned int shape_idx = dof_to_quad ? (q+k*n_q_points_1d) :
171  (k+q*n_q_points_1d);
172  const unsigned int source_idx =
173  (direction == 0) ? (k + n_q_points_1d*(i + n_q_points_1d*j)) :
174  (direction == 1) ? (i + n_q_points_1d*(k + n_q_points_1d*j)) :
175  (i + n_q_points_1d*(j + n_q_points_1d*k));
176  t += shape_data[shape_idx] * (in_place ? out[source_idx] : in[source_idx]);
177  }
178 
179  if (in_place)
180  __syncthreads();
181 
182  const unsigned int destination_idx =
183  (direction == 0) ? (q + n_q_points_1d*(i + n_q_points_1d*j)) :
184  (direction == 1) ? (i + n_q_points_1d*(q + n_q_points_1d*j)) :
185  (i + n_q_points_1d*(j + n_q_points_1d*q));
186 
187  if (add)
188  out[destination_idx] += t;
189  else
190  out[destination_idx] = t;
191  }
192 
193 
194 
195  template <int dim, int fe_degree, int n_q_points_1d, typename Number>
196  inline
197  __device__ void EvaluatorTensorProduct<evaluate_general, dim, fe_degree,
198  n_q_points_1d, Number>::value_at_quad_pts(Number *u)
199  {
200  switch (dim)
201  {
202  case 1:
203  {
204  values<0, true, false, true>(u, u);
205 
206  break;
207  }
208  case 2:
209  {
210  values<0, true, false, true>(u, u);
211  __syncthreads();
212  values<1, true, false, true>(u, u);
213 
214  break;
215  }
216  case 3:
217  {
218  values<0, true, false, true>(u, u);
219  __syncthreads();
220  values<1, true, false, true>(u, u);
221  __syncthreads();
222  values<2, true, false, true>(u, u);
223 
224  break;
225  }
226  default:
227  {
228  // Do nothing. We should throw but we can't from a __device__ function.
229  }
230  }
231  }
232 
233 
234 
235  template <int dim, int fe_degree, int n_q_points_1d, typename Number>
236  inline
237  __device__ void EvaluatorTensorProduct<evaluate_general, dim, fe_degree,
238  n_q_points_1d, Number>::integrate_value(Number *u)
239  {
240  switch (dim)
241  {
242  case 1:
243  {
244  values<0, false, false, true> (u,u);
245 
246  break;
247  }
248  case 2:
249  {
250  values<0, false, false, true> (u,u);
251  __syncthreads();
252  values<1, false, false, true> (u,u);
253 
254  break;
255  }
256  case 3:
257  {
258  values<0, false, false, true> (u,u);
259  __syncthreads();
260  values<1, false, false, true> (u,u);
261  __syncthreads();
262  values<2, false, false, true> (u,u);
263 
264  break;
265  }
266  default:
267  {
268  // Do nothing. We should throw but we can't from a __device__ function.
269  }
270  }
271  }
272 
273 
274 
275  template <int dim, int fe_degree, int n_q_points_1d, typename Number>
276  inline
277  __device__ void EvaluatorTensorProduct<evaluate_general, dim, fe_degree,
278  n_q_points_1d, Number>::gradient_at_quad_pts(
279  const Number *const u,
280  Number *grad_u[dim])
281  {
282  switch (dim)
283  {
284  case 1:
285  {
286  gradients<0, true, false, false>(u, grad_u[0]);
287 
288  break;
289  }
290  case 2:
291  {
292  gradients<0, true, false, false>(u, grad_u[0]);
293  values<0, true, false, false>(u, grad_u[1]);
294 
295  __syncthreads();
296 
297  values<1, true, false, true>(grad_u[0], grad_u[0]);
298  gradients<1, true, false, true>(grad_u[1], grad_u[1]);
299 
300  break;
301  }
302  case 3:
303  {
304  gradients<0, true, false, false>(u, grad_u[0]);
305  values<0, true, false, false>(u, grad_u[1]);
306  values<0, true, false, false>(u, grad_u[2]);
307 
308  __syncthreads();
309 
310  values<1, true, false, true>(grad_u[0], grad_u[0]);
311  gradients<1, true, false, true>(grad_u[1], grad_u[1]);
312  values<1, true, false, true>(grad_u[2], grad_u[2]);
313 
314  __syncthreads();
315 
316  values<2, true, false, true>(grad_u[0], grad_u[0]);
317  values<2, true, false, true>(grad_u[1], grad_u[1]);
318  gradients<2, true, false, true>(grad_u[2], grad_u[2]);
319 
320  break;
321  }
322  default:
323  {
324  // Do nothing. We should throw but we can't from a __device__ function.
325  }
326  }
327  }
328 
329 
330 
331  template <int dim, int fe_degree, int n_q_points_1d, typename Number>
332  template <bool add>
333  inline
334  __device__ void EvaluatorTensorProduct<evaluate_general, dim, fe_degree,
335  n_q_points_1d, Number>::integrate_gradient(
336  Number *u,
337  Number *grad_u[dim])
338  {
339  switch (dim)
340  {
341  case 1:
342  {
343  gradients<0, false, add, false> (grad_u[dim], u);
344 
345  break;
346  }
347  case 2:
348  {
349  gradients<0, false, false, true> (grad_u[0], grad_u[0]);
350  values<0, false, false, true> (grad_u[1], grad_u[1]);
351 
352  __syncthreads();
353 
354  values<1, false, add, false> (grad_u[0], u);
355  __syncthreads();
356  gradients<1, false, true, false> (grad_u[1], u);
357 
358  break;
359  }
360  case 3:
361  {
362  gradients<0, false, false, true> (grad_u[0], grad_u[0]);
363  values<0, false, false, true> (grad_u[1], grad_u[1]);
364  values<0, false, false, true> (grad_u[2], grad_u[2]);
365 
366  __syncthreads();
367 
368  values<1, false, false, true> (grad_u[0], grad_u[0]);
369  gradients<1, false, false, true> (grad_u[1], grad_u[1]);
370  values<1, false, false, true> (grad_u[2], grad_u[2]);
371 
372  __syncthreads();
373 
374  values<2, false, add, false> (grad_u[0], u);
375  __syncthreads();
376  values<2, false, true, false> (grad_u[1], u);
377  __syncthreads();
378  gradients<2, false, true, false> (grad_u[2], u);
379 
380  break;
381  }
382  default:
383  {
384  // Do nothing. We should throw but we can't from a __device__ function.
385  }
386  }
387  }
388  }
389 }
390 
391 DEAL_II_NAMESPACE_CLOSE
392 
393 #endif
constexpr unsigned int pow(const unsigned int base, const unsigned int iexp)
Definition: utilities.h:354