Panzer Version of the Day
Loading...
Searching...
No Matches
Panzer_Integrator_DivBasisTimesScalar_impl.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Panzer: A partial differential equation assembly
4// engine for strongly coupled complex multiphysics systems
5//
6// Copyright 2011 NTESS and the Panzer contributors.
7// SPDX-License-Identifier: BSD-3-Clause
8// *****************************************************************************
9// @HEADER
10
11#ifndef __Panzer_Integrator_DivBasisTimesScalar_impl_hpp__
12#define __Panzer_Integrator_DivBasisTimesScalar_impl_hpp__
13
15//
16// Include Files
17//
19
20// Intrepid2
21#include "Intrepid2_FunctionSpaceTools.hpp"
22
23// Kokkos
24#include "Sacado_Fad_Kokkos_ViewFactory.hpp"
25
26// Panzer
31
32namespace panzer
33{
35 //
36 // Main Constructor
37 //
39 template<typename EvalT, typename Traits>
42 const panzer::EvaluatorStyle& evalStyle,
43 const std::string& resName,
44 const std::string& valName,
45 const panzer::BasisIRLayout& basis,
47 const double& multiplier, /* = 1 */
48 const std::vector<std::string>& fmNames /* =
49 std::vector<std::string>() */)
50 :
51 evalStyle_(evalStyle),
52 multiplier_(multiplier),
53 basisName_(basis.name())
54 {
55 using PHX::View;
56 using panzer::BASIS;
57 using panzer::Cell;
59 using panzer::IP;
61 using PHX::MDField;
62 using std::invalid_argument;
63 using std::logic_error;
64 using std::string;
65 using Teuchos::RCP;
66
67 // Ensure the input makes sense.
68 TEUCHOS_TEST_FOR_EXCEPTION(resName == "", invalid_argument, "Error: " \
69 "Integrator_DivBasisTimesScalar called with an empty residual name.")
70 TEUCHOS_TEST_FOR_EXCEPTION(valName == "", invalid_argument, "Error: " \
71 "Integrator_DivBasisTimesScalar called with an empty value name.")
72 RCP<const PureBasis> tmpBasis = basis.getBasis();
73 TEUCHOS_TEST_FOR_EXCEPTION(not tmpBasis->supportsDiv(), logic_error,
74 "Error: Integrator_DivBasisTimesScalar: Basis of type \""
75 << tmpBasis->name() << "\" does not support DIV.")
76 TEUCHOS_TEST_FOR_EXCEPTION(not tmpBasis->requiresOrientations(), logic_error,
77 "Error: Integration_DivBasisTimesScalar: Basis of type \""
78 << tmpBasis->name() << "\" should require orientations.")
79
80 // Create the field for the scalar quantity we're integrating.
81 scalar_ = MDField<const ScalarT, Cell, IP>(valName, ir.dl_scalar);
82 this->addDependentField(scalar_);
83
84 // Create the field that we're either contributing to or evaluating
85 // (storing).
86 field_ = MDField<ScalarT, Cell, BASIS>(resName, basis.functional);
88 this->addContributedField(field_);
89 else // if (evalStyle_ == EvaluatorStyle::EVALUATES)
90 this->addEvaluatedField(field_);
91
92 // Add the dependent field multipliers, if there are any.
93 int i(0);
94 fieldMults_.resize(fmNames.size());
96 View<PHX::UnmanagedView<const ScalarT**>*>("DivBasisTimesScalar::KokkosFieldMultipliers",
97 fmNames.size());
98 for (const auto& name : fmNames)
99 {
100 fieldMults_[i++] = MDField<const ScalarT, Cell, IP>(name, ir.dl_scalar);
101 this->addDependentField(fieldMults_[i - 1]);
102 } // end loop over the field multipliers
103
104 // Set the name of this object.
105 string n("Integrator_DivBasisTimesScalar (");
107 n += "CONTRIBUTES";
108 else // if (evalStyle_ == EvaluatorStyle::EVALUATES)
109 n += "EVALUATES";
110 n += "): " + field_.fieldTag().name();
111 this->setName(n);
112 } // end of Main Constructor
113
115 //
116 // ParameterList Constructor
117 //
119 template<typename EvalT, typename Traits>
122 const Teuchos::ParameterList& p)
123 :
126 p.get<std::string>("Residual Name"),
127 p.get<std::string>("Value Name"),
128 (*p.get<Teuchos::RCP<panzer::BasisIRLayout>>("Basis")),
129 (*p.get<Teuchos::RCP<panzer::IntegrationRule>>("IR")),
130 p.get<double>("Multiplier"),
131 p.isType<Teuchos::RCP<const std::vector<std::string>>>
132 ("Field Multipliers") ?
133 (*p.get<Teuchos::RCP<const std::vector<std::string>>>
134 ("Field Multipliers")) : std::vector<std::string>())
135 {
136 using Teuchos::ParameterList;
137 using Teuchos::RCP;
138
139 // Ensure that the input ParameterList didn't contain any bogus entries.
140 RCP<ParameterList> validParams = this->getValidParameters();
141 p.validateParameters(*validParams);
142 } // end of ParameterList Constructor
143
145 //
146 // postRegistrationSetup()
147 //
149 template<typename EvalT, typename Traits>
150 void
153 typename Traits::SetupData sd,
155 {
156 using Sacado::createDynRankView;
158
159 auto kokkosFieldMults_h = Kokkos::create_mirror_view(kokkosFieldMults_);
160
161 // Get the PHX::Views of the field multipliers.
162 for (size_t i(0); i < fieldMults_.size(); ++i)
163 kokkosFieldMults_h(i) = fieldMults_[i].get_static_view();
164
165 Kokkos::deep_copy(kokkosFieldMults_, kokkosFieldMults_h);
166
167 // Allocate temporary if not using shared memory
168 bool use_shared_memory = panzer::HP::inst().useSharedMemory<ScalarT>();
169 if (!use_shared_memory) {
170 if (Sacado::IsADType<ScalarT>::value) {
171 const auto fadSize = Sacado::dimension_scalar(field_.get_view());
172 tmp_ = PHX::View<ScalarT*>("panzer::Integrator::DivBasisTimesScalar::tmp_",field_.extent(0),fadSize);
173 } else {
174 tmp_ = PHX::View<ScalarT*>("panzer::Integrator::DivBasisTimesScalar::tmp_",field_.extent(0));
175 }
176 }
177
178 // Determine the index in the Workset bases for our particular basis name.
179 basisIndex_ = getBasisIndex(basisName_, (*sd.worksets_)[0], this->wda);
180 } // end of postRegistrationSetup()
181
183 //
184 // No shared memory operator()()
185 //
187 template<typename EvalT, typename Traits>
188 template<int NUM_FIELD_MULT>
189 KOKKOS_INLINE_FUNCTION
190 void
193 const FieldMultTag<NUM_FIELD_MULT>& /* tag */,
194 const Kokkos::TeamPolicy<PHX::ExecutionSpace>::member_type& team) const
195 {
197 const int cell = team.league_rank();
198
199 // Initialize the evaluated field.
200 const int numQP(scalar_.extent(1)), numBases(basis_.extent(1));
202 Kokkos::parallel_for(Kokkos::TeamThreadRange(team,0,numBases), [&] (const int basis) {
203 field_(cell, basis) = 0.0;
204 });
205 }
206
207 // The following if-block is for the sake of optimization depending on the
208 // number of field multipliers.
209 if constexpr (NUM_FIELD_MULT == 0)
210 {
211 // Loop over the quadrature points, scale the integrand by the
212 // multiplier, and then perform the actual integration, looping over the
213 // bases.
214 for (int qp(0); qp < numQP; ++qp)
215 {
216 Kokkos::parallel_for(Kokkos::TeamThreadRange(team,0,numBases), [&] (const int basis) {
217 field_(cell, basis) += basis_(cell, basis, qp) * multiplier_ * scalar_(cell, qp);
218 });
219 } // end loop over the quadrature points
220 }
221 else if constexpr (NUM_FIELD_MULT == 1)
222 {
223 // Loop over the quadrature points, scale the integrand by the multiplier
224 // and the single field multiplier, and then perform the actual
225 // integration, looping over the bases.
226 for (int qp(0); qp < numQP; ++qp)
227 {
228 Kokkos::parallel_for(Kokkos::TeamThreadRange(team,0,numBases), [&] (const int basis) {
229 field_(cell, basis) += basis_(cell, basis, qp) * multiplier_ * scalar_(cell, qp) * kokkosFieldMults_(0)(cell, qp);
230 });
231 } // end loop over the quadrature points
232 }
233 else
234 {
235 // Loop over the quadrature points and pre-multiply all the field
236 // multipliers together, scale the integrand by the multiplier and the
237 // combination of field multipliers, and then perform the actual
238 // integration, looping over the bases.
239 const int numFieldMults(kokkosFieldMults_.extent(0));
240 for (int qp(0); qp < numQP; ++qp)
241 {
242 // tmp_(cell) is shared by the team, so a single team thread (all of
243 // its vector lanes, to keep hierarchic Fad partitions intact) computes
244 // the product, and barriers fence it from the reads.
245 team.team_barrier();
246 if (team.team_rank() == 0) {
247 tmp_(cell) = 1.0;
248 for (int fm(0); fm < numFieldMults; ++fm)
249 tmp_(cell) *= kokkosFieldMults_(fm)(cell, qp);
250 }
251 team.team_barrier();
252 Kokkos::parallel_for(Kokkos::TeamThreadRange(team,0,numBases),[&] (const int& basis) {
253 field_(cell, basis) += basis_(cell, basis, qp) * multiplier_ * scalar_(cell, qp) * tmp_(cell);
254 });
255 } // end loop over the quadrature points
256 } // end if (NUM_FIELD_MULT == something)
257 } // end of operator()
258
260 //
261 // Shared memory operator()()
262 //
264 template<typename EvalT, typename Traits>
265 template<int NUM_FIELD_MULT>
266 KOKKOS_INLINE_FUNCTION
267 void
270 const SharedFieldMultTag<NUM_FIELD_MULT>& /* tag */,
271 const Kokkos::TeamPolicy<PHX::ExecutionSpace>::member_type& team) const
272 {
274 const int cell = team.league_rank();
275 const int numQP = scalar_.extent(1);
276 const int numBases = basis_.extent(1);
277 const int fadSize = Sacado::dimension_scalar(field_.get_view());
278
279 scratch_view tmp;
280 scratch_view tmp_field;
281 if (Sacado::IsADType<ScalarT>::value) {
282 tmp = scratch_view(team.team_shmem(),1,fadSize);
283 tmp_field = scratch_view(team.team_shmem(),numBases,fadSize);
284 }
285 else {
286 tmp = scratch_view(team.team_shmem(),1);
287 tmp_field = scratch_view(team.team_shmem(),numBases);
288 }
289
290 // Initialize the evaluated field.
291 Kokkos::parallel_for(Kokkos::TeamThreadRange(team,0,numBases),[&] (const int& basis) {
292 tmp_field(basis) = 0.0;
293 });
294
295 // The following if-block is for the sake of optimization depending on the
296 // number of field multipliers.
297 if constexpr (NUM_FIELD_MULT == 0)
298 {
299 // Loop over the quadrature points, scale the integrand by the
300 // multiplier, and then perform the actual integration, looping over the
301 // bases.
302 for (int qp(0); qp < numQP; ++qp)
303 {
304 Kokkos::parallel_for(Kokkos::TeamThreadRange(team,0,numBases),[&] (const int& basis) {
305 tmp_field(basis) += basis_(cell, basis, qp) * multiplier_ * scalar_(cell, qp);
306 });
307 } // end loop over the quadrature points
308 }
309 else if constexpr (NUM_FIELD_MULT == 1)
310 {
311 // Loop over the quadrature points, scale the integrand by the multiplier
312 // and the single field multiplier, and then perform the actual
313 // integration, looping over the bases.
314 for (int qp(0); qp < numQP; ++qp)
315 {
316 Kokkos::parallel_for(Kokkos::TeamThreadRange(team,0,numBases),[&] (const int& basis) {
317 tmp_field(basis) += basis_(cell, basis, qp) * multiplier_ * scalar_(cell, qp) * kokkosFieldMults_(0)(cell, qp);
318 });
319 } // end loop over the quadrature points
320 }
321 else
322 {
323 // Loop over the quadrature points and pre-multiply all the field
324 // multipliers together, scale the integrand by the multiplier and the
325 // combination of field multipliers, and then perform the actual
326 // integration, looping over the bases.
327 const int numFieldMults = kokkosFieldMults_.extent(0);
328 for (int qp(0); qp < numQP; ++qp)
329 {
330 // tmp(0) is shared by the team, so a single team thread (all of its
331 // vector lanes, to keep hierarchic Fad partitions intact) computes it,
332 // and barriers fence it from the reads.
333 team.team_barrier();
334 if (team.team_rank() == 0) {
335 tmp(0) = multiplier_ * scalar_(cell, qp);
336 for (int fm(0); fm < numFieldMults; ++fm)
337 tmp(0) *= kokkosFieldMults_(fm)(cell, qp);
338 }
339 team.team_barrier();
340 Kokkos::parallel_for(Kokkos::TeamThreadRange(team,0,numBases),[&] (const int& basis) {
341 tmp_field(basis) += basis_(cell, basis, qp) * tmp(0);
342 });
343 } // end loop over the quadrature points
344 } // end if (NUM_FIELD_MULT == something)
345
346 // Put final values into target field
348 Kokkos::parallel_for(Kokkos::TeamThreadRange(team,0,numBases),[&] (const int& basis) {
349 field_(cell,basis) = tmp_field(basis);
350 });
351 }
352 else { // Contributed
353 Kokkos::parallel_for(Kokkos::TeamThreadRange(team,0,numBases),[&] (const int& basis) {
354 field_(cell,basis) += tmp_field(basis);
355 });
356 }
357
358 } // end of operator()
359
361 //
362 // evaluateFields()
363 //
365 template<typename EvalT, typename Traits>
366 void
369 typename Traits::EvalData workset)
370 {
371 using Kokkos::parallel_for;
372 using Kokkos::TeamPolicy;
373
374 // Grab the basis information.
375 basis_ = this->wda(workset).bases[basisIndex_]->weighted_div_basis;
376
377 bool use_shared_memory = panzer::HP::inst().useSharedMemory<ScalarT>();
378
379 if (use_shared_memory) {
380 int bytes;
381 if (Sacado::IsADType<ScalarT>::value) {
382 const int fadSize = Sacado::dimension_scalar(field_.get_view());
383 bytes = scratch_view::shmem_size(1,fadSize) + scratch_view::shmem_size(basis_.extent(1),fadSize);
384 }
385 else
386 bytes = scratch_view::shmem_size(1) + scratch_view::shmem_size(basis_.extent(1));
387
388 // The following if-block is for the sake of optimization depending on the
389 // number of field multipliers. The parallel_fors will loop over the cells
390 // in the Workset and execute operator()() above.
391 if (fieldMults_.size() == 0) {
392 auto policy = panzer::HP::inst().teamPolicy<ScalarT,SharedFieldMultTag<0>,PHX::ExecutionSpace>(workset.num_cells).set_scratch_size(0,Kokkos::PerTeam(bytes));
393 parallel_for(this->getName(), policy, *this);
394 } else if (fieldMults_.size() == 1) {
395 auto policy = panzer::HP::inst().teamPolicy<ScalarT,SharedFieldMultTag<1>,PHX::ExecutionSpace>(workset.num_cells).set_scratch_size(0,Kokkos::PerTeam(bytes));
396 parallel_for(this->getName(), policy, *this);
397 } else {
398 auto policy = panzer::HP::inst().teamPolicy<ScalarT,SharedFieldMultTag<-1>,PHX::ExecutionSpace>(workset.num_cells).set_scratch_size(0,Kokkos::PerTeam(bytes));
399 parallel_for(this->getName(), policy, *this);
400 }
401 }
402 else {
403 // The following if-block is for the sake of optimization depending on the
404 // number of field multipliers. The parallel_fors will loop over the cells
405 // in the Workset and execute operator()() above.
406 if (fieldMults_.size() == 0) {
407 auto policy = panzer::HP::inst().teamPolicy<ScalarT,FieldMultTag<0>,PHX::ExecutionSpace>(workset.num_cells);
408 parallel_for(this->getName(), policy, *this);
409 } else if (fieldMults_.size() == 1) {
410 auto policy = panzer::HP::inst().teamPolicy<ScalarT,FieldMultTag<1>,PHX::ExecutionSpace>(workset.num_cells);
411 parallel_for(this->getName(), policy, *this);
412 } else {
413 auto policy = panzer::HP::inst().teamPolicy<ScalarT,FieldMultTag<-1>,PHX::ExecutionSpace>(workset.num_cells);
414 parallel_for(this->getName(), policy, *this);
415 }
416 }
417 } // end of evaluateFields()
418
420 //
421 // getValidParameters()
422 //
424 template<typename EvalT, typename TRAITS>
425 Teuchos::RCP<Teuchos::ParameterList>
427 {
430 using std::string;
431 using std::vector;
432 using Teuchos::ParameterList;
433 using Teuchos::RCP;
434 using Teuchos::rcp;
435
436 // Create a ParameterList with all the valid keys we support.
437 RCP<ParameterList> p = rcp(new ParameterList);
438 p->set<string>("Residual Name", "?");
439 p->set<string>("Value Name", "?");
440 p->set<string>("Test Field Name", "?");
441 RCP<BasisIRLayout> basis;
442 p->set("Basis", basis);
443 RCP<IntegrationRule> ir;
444 p->set("IR", ir);
445 p->set<double>("Multiplier", 1.0);
446 RCP<const vector<string>> fms;
447 p->set("Field Multipliers", fms);
448 return p;
449 } // end of getValidParameters()
450
451} // end of namespace panzer
452
453#endif // __Panzer_Integrator_DivBasisTimesScalar_impl_hpp__
Teuchos::RCP< PHX::DataLayout > functional
<Cell,Basis>
Teuchos::RCP< const PureBasis > getBasis() const
static HP & inst()
Private ctor.
Kokkos::TeamPolicy< TeamPolicyProperties... > teamPolicy(const int &league_size)
Returns a TeamPolicy for hierarchic parallelism.
PHX::MDField< const ScalarT, Cell, IP > scalar_
A field representing the scalar function we're integrating ( ).
Teuchos::RCP< Teuchos::ParameterList > getValidParameters() const
Get Valid Parameters.
PHX::MDField< double, panzer::Cell, panzer::BASIS, panzer::IP > basis_
The scalar basis information necessary for integration.
Integrator_DivBasisTimesScalar(const panzer::EvaluatorStyle &evalStyle, const std::string &resName, const std::string &valName, const panzer::BasisIRLayout &basis, const panzer::IntegrationRule &ir, const double &multiplier=1, const std::vector< std::string > &fmNames=std::vector< std::string >())
Main Constructor.
void postRegistrationSetup(typename Traits::SetupData d, PHX::FieldManager< Traits > &fm)
Post-Registration Setup.
std::string basisName_
The name of the basis we're using.
void evaluateFields(typename Traits::EvalData d)
Evaluate Fields.
PHX::View< ScalarT * > tmp_
Temporary for non-shared calculations.
KOKKOS_INLINE_FUNCTION void operator()(const FieldMultTag< NUM_FIELD_MULT > &tag, const Kokkos::TeamPolicy< PHX::ExecutionSpace >::member_type &team) const
Perform the integration. Main memory version.
const panzer::EvaluatorStyle evalStyle_
An enum determining the behavior of this Evaluator.
Kokkos::View< ScalarT *,typename PHX::DevLayout< ScalarT >::type, typename PHX::ExecutionSpace::scratch_memory_space, Kokkos::MemoryUnmanaged > scratch_view
Type for shared memory.
double multiplier_
The scalar multiplier out in front of the integral ( ).
std::size_t basisIndex_
The index in the Workset bases for our particular BasisIRLayout name.
PHX::MDField< ScalarT, Cell, BASIS > field_
A field to which we'll contribute, or in which we'll store, the result of computing this integral.
PHX::View< PHX::UnmanagedView< const ScalarT ** > * > kokkosFieldMults_
The PHX::View representation of the (possibly empty) list of fields that are multipliers out in front...
std::vector< PHX::MDField< const ScalarT, Cell, IP > > fieldMults_
The (possibly empty) list of fields that are multipliers out in front of the integral ( ,...
Teuchos::RCP< PHX::DataLayout > dl_scalar
Data layout for scalar fields.
Description and data layouts associated with a particular basis.
int num_cells
DEPRECATED - use: numCells().
std::vector< std::string >::size_type getBasisIndex(std::string basis_name, const panzer::Workset &workset, WorksetDetailsAccessor &wda)
Returns the index in the workset bases for a particular BasisIRLayout name.
EvaluatorStyle
An indication of how an Evaluator will behave.
This empty struct allows us to optimize operator()() depending on the number of field multipliers.
This empty struct allows us to optimize operator()() depending on the number of field multipliers.
Teuchos::RCP< const std::vector< panzer::Workset > > worksets_
All worksets that will be evaluated over the lifetime of this evaluator.
const panzer::Workset & EvalData
Data type passed to PHX::Evaluator::evaluateFields(): a single workset holding the cell data for one ...
const SD & SetupData
Data type passed to PHX::Evaluator::postRegistrationSetup().