VertexCFD  0.0-dev
VertexCFD_Integrator_BoundaryGradBasisDotVector_impl.hpp
1 #ifndef VERTEXCFD_INTEGRATOR_BOUNDARYGRADBASISDOTVECTOR_IMPL_HPP
2 #define VERTEXCFD_INTEGRATOR_BOUNDARYGRADBASISDOTVECTOR_IMPL_HPP
3 
4 #include <Panzer_BasisIRLayout.hpp>
5 #include <Panzer_HierarchicParallelism.hpp>
6 #include <Panzer_IntegrationRule.hpp>
7 #include <Panzer_Workset_Utilities.hpp>
8 
9 namespace VertexCFD
10 {
11 namespace Integrator
12 {
13 //---------------------------------------------------------------------------//
14 template<typename EvalType, typename Traits>
15 BoundaryGradBasisDotVector<EvalType, Traits>::BoundaryGradBasisDotVector(
16  const panzer::EvaluatorStyle& eval_style,
17  const std::string& res_name,
18  const std::string& flux_name,
19  const panzer::BasisIRLayout& basis,
20  const panzer::IntegrationRule& ir,
21  const double& multiplier,
22  const std::vector<std::string>& fm_names)
23  : _eval_style(eval_style)
24  , _multiplier(multiplier)
25  , _basis_name(basis.name())
26  , _field(res_name, basis.functional)
27  , _boundary_grad_basis("boundary_grad_basis", basis.basis_grad)
28  , _vector(flux_name, ir.dl_vector)
29  , _normals("Side Normal", ir.dl_vector)
30 {
31  if (res_name == "")
32  {
33  throw std::invalid_argument(
34  "Error: BoundaryGradBasisDotVector called with an empty residual "
35  "name.");
36  }
37  if (flux_name == "")
38  {
39  throw std::invalid_argument(
40  "Error: BoundaryGradBasisDotVector called with an empty flux "
41  "name.");
42  }
43 
44  if (!basis.getBasis()->supportsGrad())
45  {
46  const std::string msg
47  = "Error: BoundaryGradBasisDotVector: Basis of type "
48  + basis.getBasis()->name()
49  + " does not support the gradient operator.";
50  throw std::logic_error(msg);
51  }
52 
53  if (_eval_style == panzer::EvaluatorStyle::CONTRIBUTES)
54  {
55  this->addContributedField(_field);
56  }
57  else
58  {
59  this->addEvaluatedField(_field);
60  }
61 
62  this->addEvaluatedField(_boundary_grad_basis);
63 
64  this->addDependentField(_vector);
65  this->addDependentField(_normals);
66 
67  // Add the dependent field multipliers and expand them into kokkos views
68  // so we can have an arbitrary number of them on device.
69  const int num_name = fm_names.size();
70  _field_mults.resize(num_name);
71  _kokkos_field_mults
72  = Kokkos::View<Kokkos::View<const ScalarT**,
73  typename PHX::DevLayout<ScalarT>::type,
74  PHX::Device>*>(
75  "GradBasisDotVector::KokkosFieldMultipliers", num_name);
76  for (int i = 0; i < num_name; ++i)
77  {
78  _field_mults[i]
79  = PHX::MDField<const ScalarT, panzer::Cell, panzer::Point>(
80  fm_names[i], ir.dl_scalar);
81  this->addDependentField(_field_mults[i]);
82  }
83 
84  std::string n("BoundaryGradBasisDotVector (");
85  if (_eval_style == panzer::EvaluatorStyle::CONTRIBUTES)
86  {
87  n += "CONTRIBUTES";
88  }
89  else
90  {
91  n += "EVALUATES";
92  }
93  n += "): " + _field.fieldTag().name();
94  this->setName(n);
95 }
96 
97 //---------------------------------------------------------------------------//
98 template<typename EvalType, typename Traits>
99 void BoundaryGradBasisDotVector<EvalType, Traits>::postRegistrationSetup(
100  typename Traits::SetupData sd, PHX::FieldManager<Traits>& /* fm */)
101 {
102  for (std::size_t i = 0; i < _field_mults.size(); ++i)
103  {
104  _kokkos_field_mults(i) = _field_mults[i].get_static_view();
105  }
106  PHX::Device().fence();
107 
108  _basis_index
109  = panzer::getBasisIndex(_basis_name, (*sd.worksets_)[0], this->wda);
110 }
111 
112 //---------------------------------------------------------------------------//
113 template<typename EvalType, typename Traits>
114 template<int NUM_FIELD_MULT>
115 KOKKOS_INLINE_FUNCTION void
116 BoundaryGradBasisDotVector<EvalType, Traits>::operator()(
117  const FieldMultTag<NUM_FIELD_MULT>& /* tag */,
118  const Kokkos::TeamPolicy<PHX::exec_space>::member_type& team) const
119 {
120  const int cell = team.league_rank();
121 
122  // Create the boundary gradients.
123  const int num_qp(_vector.extent(1));
124  const int num_dim(_vector.extent(2));
125  const int num_bases(_grad_basis.extent(1));
126  ScalarT n_dot_grad;
127  for (int qp = 0; qp < num_qp; ++qp)
128  {
129  for (int basis = 0; basis < num_bases; ++basis)
130  {
131  n_dot_grad = 0.0;
132  for (int dim = 0; dim < num_dim; ++dim)
133  {
134  n_dot_grad += _normals(cell, qp, dim)
135  * _grad_basis(cell, basis, qp, dim);
136  }
137  for (int dim = 0; dim < num_dim; ++dim)
138  {
139  _boundary_grad_basis(cell, basis, qp, dim)
140  = _grad_basis(cell, basis, qp, dim)
141  - _normals(cell, qp, dim) * n_dot_grad;
142  }
143  }
144  }
145 
146  // Initialize the evaluated field.
147  if (_eval_style == panzer::EvaluatorStyle::EVALUATES)
148  {
149  Kokkos::parallel_for(
150  Kokkos::TeamThreadRange(team, 0, num_bases),
151  [&](const int& basis) { _field(cell, basis) = 0.0; });
152  }
153 
154  // Perform integration with the given number of field multipliers.
155  ScalarT tmp;
156  if (NUM_FIELD_MULT == 0)
157  {
158  for (int qp = 0; qp < num_qp; ++qp)
159  {
160  for (int dim = 0; dim < num_dim; ++dim)
161  {
162  tmp = _multiplier * _vector(cell, qp, dim);
163  Kokkos::parallel_for(
164  Kokkos::TeamThreadRange(team, 0, num_bases),
165  [&](const int& basis) {
166  _field(cell, basis)
167  += _boundary_grad_basis(cell, basis, qp, dim) * tmp;
168  });
169  }
170  }
171  }
172  else if (NUM_FIELD_MULT == 1)
173  {
174  for (int qp = 0; qp < num_qp; ++qp)
175  {
176  for (int dim = 0; dim < num_dim; ++dim)
177  {
178  tmp = _multiplier * _vector(cell, qp, dim)
179  * _kokkos_field_mults(0)(cell, qp);
180  Kokkos::parallel_for(
181  Kokkos::TeamThreadRange(team, 0, num_bases),
182  [&](const int& basis) {
183  _field(cell, basis)
184  += _boundary_grad_basis(cell, basis, qp, dim) * tmp;
185  });
186  }
187  }
188  }
189  else
190  {
191  const int num_field_mults(_kokkos_field_mults.extent(0));
192  for (int qp = 0; qp < num_qp; ++qp)
193  {
194  ScalarT field_mults_total(1);
195  for (int fm = 0; fm < num_field_mults; ++fm)
196  field_mults_total *= _kokkos_field_mults(fm)(cell, qp);
197  for (int dim = 0; dim < num_dim; ++dim)
198  {
199  tmp = _multiplier * _vector(cell, qp, dim) * field_mults_total;
200  Kokkos::parallel_for(
201  Kokkos::TeamThreadRange(team, 0, num_bases),
202  [&](const int& basis) {
203  _field(cell, basis)
204  += _boundary_grad_basis(cell, basis, qp, dim) * tmp;
205  });
206  }
207  }
208  }
209 }
210 
211 //---------------------------------------------------------------------------//
212 template<typename EvalType, typename Traits>
213 template<int NUM_FIELD_MULT>
214 KOKKOS_INLINE_FUNCTION void
215 BoundaryGradBasisDotVector<EvalType, Traits>::operator()(
216  const SharedFieldMultTag<NUM_FIELD_MULT>& /* tag */,
217  const Kokkos::TeamPolicy<PHX::exec_space>::member_type& team) const
218 {
219  const int cell = team.league_rank();
220  const int num_qp = _vector.extent(1);
221  const int num_dim = _vector.extent(2);
222  const int num_bases = _grad_basis.extent(1);
223  const int fad_size = Kokkos::dimension_scalar(_field.get_view());
224 
225  scratch_view tmp;
226  scratch_view tmp_field;
227  if (Sacado::IsADType<ScalarT>::value)
228  {
229  tmp = scratch_view(team.team_shmem(), 1, fad_size);
230  tmp_field = scratch_view(team.team_shmem(), num_bases, fad_size);
231  }
232  else
233  {
234  tmp = scratch_view(team.team_shmem(), 1);
235  tmp_field = scratch_view(team.team_shmem(), num_bases);
236  }
237 
238  // Create the boundary gradients.
239  ScalarT n_dot_grad;
240  for (int qp = 0; qp < num_qp; ++qp)
241  {
242  for (int basis = 0; basis < num_bases; ++basis)
243  {
244  n_dot_grad = 0.0;
245  for (int dim = 0; dim < num_dim; ++dim)
246  {
247  n_dot_grad += _normals(cell, qp, dim)
248  * _grad_basis(cell, basis, qp, dim);
249  }
250  for (int dim = 0; dim < num_dim; ++dim)
251  {
252  _boundary_grad_basis(cell, basis, qp, dim)
253  = _grad_basis(cell, basis, qp, dim)
254  - _normals(cell, qp, dim) * n_dot_grad;
255  }
256  }
257  }
258 
259  // Initialize the evaluated field.
260  Kokkos::parallel_for(Kokkos::TeamThreadRange(team, 0, num_bases),
261  [&](const int& basis) { tmp_field(basis) = 0.0; });
262 
263  // Perform integration with the given number of fields.
264  if (NUM_FIELD_MULT == 0)
265  {
266  for (int qp = 0; qp < num_qp; ++qp)
267  {
268  for (int dim = 0; dim < num_dim; ++dim)
269  {
270  team.team_barrier();
271  tmp(0) = _multiplier * _vector(cell, qp, dim);
272  Kokkos::parallel_for(
273  Kokkos::TeamThreadRange(team, 0, num_bases),
274  [&](const int& basis) {
275  tmp_field(basis)
276  += _boundary_grad_basis(cell, basis, qp, dim)
277  * tmp(0);
278  });
279  }
280  }
281  }
282  else if (NUM_FIELD_MULT == 1)
283  {
284  for (int qp = 0; qp < num_qp; ++qp)
285  {
286  for (int dim = 0; dim < num_dim; ++dim)
287  {
288  team.team_barrier();
289  tmp(0) = _multiplier * _vector(cell, qp, dim)
290  * _kokkos_field_mults(0)(cell, qp);
291  Kokkos::parallel_for(
292  Kokkos::TeamThreadRange(team, 0, num_bases),
293  [&](const int& basis) {
294  tmp_field(basis)
295  += _boundary_grad_basis(cell, basis, qp, dim)
296  * tmp(0);
297  });
298  }
299  }
300  }
301  else
302  {
303  const int num_field_mults(_kokkos_field_mults.extent(0));
304  for (int qp = 0; qp < num_qp; ++qp)
305  {
306  ScalarT field_mults_total(1); // need shared mem here
307  for (int fm = 0; fm < num_field_mults; ++fm)
308  field_mults_total *= _kokkos_field_mults(fm)(cell, qp);
309  for (int dim = 0; dim < num_dim; ++dim)
310  {
311  team.team_barrier();
312  tmp(0) = _multiplier * _vector(cell, qp, dim)
313  * field_mults_total;
314  Kokkos::parallel_for(
315  Kokkos::TeamThreadRange(team, 0, num_bases),
316  [&](const int& basis) {
317  tmp_field(basis)
318  += _boundary_grad_basis(cell, basis, qp, dim)
319  * tmp(0);
320  });
321  }
322  }
323  }
324 
325  // Put values into target field
326  if (_eval_style == panzer::EvaluatorStyle::EVALUATES)
327  {
328  Kokkos::parallel_for(
329  Kokkos::TeamThreadRange(team, 0, num_bases),
330  [&](const int& basis) { _field(cell, basis) = tmp_field(basis); });
331  }
332  else if (_eval_style == panzer::EvaluatorStyle::CONTRIBUTES)
333  {
334  Kokkos::parallel_for(Kokkos::TeamThreadRange(team, 0, num_bases),
335  [&](const int& basis) {
336  _field(cell, basis) += tmp_field(basis);
337  });
338  }
339 }
340 
341 //---------------------------------------------------------------------------//
342 template<typename EvalType, typename Traits>
343 void BoundaryGradBasisDotVector<EvalType, Traits>::evaluateFields(
344  typename Traits::EvalData workset)
345 {
346  _grad_basis = this->wda(workset).bases[_basis_index]->weighted_grad_basis;
347 
348  const bool use_shared_memory
349  = panzer::HP::inst().useSharedMemory<ScalarT>();
350  if (use_shared_memory)
351  {
352  int bytes;
353  if (Sacado::IsADType<ScalarT>::value)
354  {
355  const int fad_size = Kokkos::dimension_scalar(_field.get_view());
356  bytes = scratch_view::shmem_size(1, fad_size)
357  + scratch_view::shmem_size(_grad_basis.extent(1), fad_size);
358  }
359  else
360  bytes = scratch_view::shmem_size(1)
361  + scratch_view::shmem_size(_grad_basis.extent(1));
362 
363  // The following if-block is for the sake of optimization depending on
364  // the number of field multipliers. The parallel_fors will loop over
365  // the cells in the Workset and execute operator()() above.
366  if (_field_mults.size() == 0)
367  {
368  auto policy
369  = panzer::HP::inst()
370  .teamPolicy<ScalarT, SharedFieldMultTag<0>, PHX::Device>(
371  workset.num_cells)
372  .set_scratch_size(0, Kokkos::PerTeam(bytes));
373  Kokkos::parallel_for(this->getName(), policy, *this);
374  }
375  else if (_field_mults.size() == 1)
376  {
377  auto policy
378  = panzer::HP::inst()
379  .teamPolicy<ScalarT, SharedFieldMultTag<1>, PHX::Device>(
380  workset.num_cells)
381  .set_scratch_size(0, Kokkos::PerTeam(bytes));
382  Kokkos::parallel_for(this->getName(), policy, *this);
383  }
384  else
385  {
386  auto policy
387  = panzer::HP::inst()
388  .teamPolicy<ScalarT, SharedFieldMultTag<-1>, PHX::Device>(
389  workset.num_cells)
390  .set_scratch_size(0, Kokkos::PerTeam(bytes));
391  Kokkos::parallel_for(this->getName(), policy, *this);
392  }
393  }
394  else
395  {
396  // The following if-block is for the sake of optimization depending on
397  // the number of field multipliers. The Kokkos::parallel_fors will
398  // loop over the cells in the Workset and execute operator()() above.
399  if (_field_mults.size() == 0)
400  {
401  auto policy
402  = panzer::HP::inst()
403  .teamPolicy<ScalarT, FieldMultTag<0>, PHX::Device>(
404  workset.num_cells);
405  Kokkos::parallel_for(this->getName(), policy, *this);
406  }
407  else if (_field_mults.size() == 1)
408  {
409  auto policy
410  = panzer::HP::inst()
411  .teamPolicy<ScalarT, FieldMultTag<1>, PHX::Device>(
412  workset.num_cells);
413  Kokkos::parallel_for(this->getName(), policy, *this);
414  }
415  else
416  {
417  auto policy
418  = panzer::HP::inst()
419  .teamPolicy<ScalarT, FieldMultTag<-1>, PHX::Device>(
420  workset.num_cells);
421  Kokkos::parallel_for(this->getName(), policy, *this);
422  }
423  }
424 }
425 
426 //---------------------------------------------------------------------------//
427 
428 } // end namespace Integrator
429 } // end namespace VertexCFD
430 
431 #endif // VERTEXCFD_INTEGRATOR_BOUNDARYGRADBASISDOTVECTOR_IMPL_HPP
VertexCFD
Definition: tstMethodManufacturedSolutionBC.cpp:23