Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_ScatterResidual_Tpetra_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_SCATTER_RESIDUAL_TPETRA_IMPL_HPP
12 #define PANZER_SCATTER_RESIDUAL_TPETRA_IMPL_HPP
13 
14 #include "Teuchos_RCP.hpp"
15 #include "Teuchos_Assert.hpp"
16 
17 #include "Phalanx_DataLayout.hpp"
18 
19 #include "Panzer_GlobalIndexer.hpp"
20 #include "Panzer_PureBasis.hpp"
25 
26 #include "Phalanx_DataLayout_MDALayout.hpp"
27 
28 #include "Teuchos_FancyOStream.hpp"
29 
30 #include "Tpetra_Vector.hpp"
31 #include "Tpetra_Map.hpp"
32 #include "Tpetra_CrsMatrix.hpp"
33 
34 // **********************************************************************
35 // Specialization: Residual
36 // **********************************************************************
37 
38 template<typename TRAITS,typename LO,typename GO,typename NodeT>
41  const Teuchos::ParameterList& p)
42  : globalIndexer_(indexer)
43  , globalDataKey_("Residual Scatter Container")
44 {
45  std::string scatterName = p.get<std::string>("Scatter Name");
46  scatterHolder_ =
48 
49  // get names to be evaluated
50  const std::vector<std::string>& names =
51  *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
52 
53  // grab map from evaluated names to field names
54  fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
55 
57  p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
58 
59  // build the vector of fields that this is dependent on
60  scatterFields_.resize(names.size());
61  scratch_offsets_.resize(names.size());
62  for (std::size_t eq = 0; eq < names.size(); ++eq) {
63  scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
64 
65  // tell the field manager that we depend on this field
66  this->addDependentField(scatterFields_[eq]);
67  }
68 
69  // this is what this evaluator provides
70  this->addEvaluatedField(*scatterHolder_);
71 
72  if (p.isType<std::string>("Global Data Key"))
73  globalDataKey_ = p.get<std::string>("Global Data Key");
74 
75  this->setName(scatterName+" Scatter Residual");
76 }
77 
78 // **********************************************************************
79 template<typename TRAITS,typename LO,typename GO,typename NodeT>
81 postRegistrationSetup(typename TRAITS::SetupData d,
82  PHX::FieldManager<TRAITS>& /* fm */)
83 {
84  fieldIds_.resize(scatterFields_.size());
85  const Workset & workset_0 = (*d.worksets_)[0];
86  std::string blockId = this->wda(workset_0).block_id;
87 
88 
89  // load required field numbers for fast use
90  for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
91  // get field ID from DOF manager
92  std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
93  fieldIds_[fd] = globalIndexer_->getFieldNum(fieldName);
94 
95  const std::vector<int> & offsets = globalIndexer_->getGIDFieldOffsets(blockId,fieldIds_[fd]);
96  scratch_offsets_[fd] = PHX::View<int*>("offsets",offsets.size());
97  Kokkos::deep_copy(scratch_offsets_[fd], Kokkos::View<const int*, Kokkos::HostSpace, Kokkos::MemoryUnmanaged>(offsets.data(), offsets.size()));
98  }
99  scratch_lids_ = PHX::View<LO**>("lids",scatterFields_[0].extent(0),
100  globalIndexer_->getElementBlockGIDCount(blockId));
101 
102 }
103 
104 // **********************************************************************
105 template<typename TRAITS,typename LO,typename GO,typename NodeT>
107 preEvaluate(typename TRAITS::PreEvalData d)
108 {
110 
111  // extract linear object container
112  tpetraContainer_ = Teuchos::rcp_dynamic_cast<LOC>(d.gedc->getDataObject(globalDataKey_));
113 
114  if(tpetraContainer_==Teuchos::null) {
115  // extract linear object container
116  Teuchos::RCP<LinearObjContainer> loc = Teuchos::rcp_dynamic_cast<LOCPair_GlobalEvaluationData>(d.gedc->getDataObject(globalDataKey_),true)->getGhostedLOC();
117  tpetraContainer_ = Teuchos::rcp_dynamic_cast<LOC>(loc);
118  }
119 }
120 
121 
122 // **********************************************************************
123 // Specialization: Tangent
124 // **********************************************************************
125 
126 template<typename TRAITS,typename LO,typename GO,typename NodeT>
129  const Teuchos::ParameterList& p)
130  : globalIndexer_(indexer)
131  , globalDataKey_("Residual Scatter Container")
132 {
133  std::string scatterName = p.get<std::string>("Scatter Name");
134  scatterHolder_ =
136 
137  // get names to be evaluated
138  const std::vector<std::string>& names =
139  *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
140 
141  // grab map from evaluated names to field names
142  fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
143 
145  p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
146 
147  // build the vector of fields that this is dependent on
148  scatterFields_.resize(names.size());
149  for (std::size_t eq = 0; eq < names.size(); ++eq) {
150  scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
151 
152  // tell the field manager that we depend on this field
153  this->addDependentField(scatterFields_[eq]);
154  }
155 
156  // this is what this evaluator provides
157  this->addEvaluatedField(*scatterHolder_);
158 
159  if (p.isType<std::string>("Global Data Key"))
160  globalDataKey_ = p.get<std::string>("Global Data Key");
161 
162  this->setName(scatterName+" Scatter Tangent");
163 }
164 
165 // **********************************************************************
166 template<typename TRAITS,typename LO,typename GO,typename NodeT>
168 postRegistrationSetup(typename TRAITS::SetupData /* d */,
169  PHX::FieldManager<TRAITS>& /* fm */)
170 {
171  fieldIds_.resize(scatterFields_.size());
172  // load required field numbers for fast use
173  for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
174  // get field ID from DOF manager
175  std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
176  fieldIds_[fd] = globalIndexer_->getFieldNum(fieldName);
177  }
178 }
179 
180 // **********************************************************************
181 template<typename TRAITS,typename LO,typename GO,typename NodeT>
183 preEvaluate(typename TRAITS::PreEvalData d)
184 {
185  using Teuchos::RCP;
186  using Teuchos::rcp_dynamic_cast;
187 
189 
190  // this is the list of parameters and their names that this scatter has to account for
191  std::vector<std::string> activeParameters =
192  rcp_dynamic_cast<ParameterList_GlobalEvaluationData>(d.gedc->getDataObject("PARAMETER_NAMES"))->getActiveParameters();
193 
194  dfdp_vectors_.clear();
195  for(std::size_t i=0;i<activeParameters.size();i++) {
197  rcp_dynamic_cast<LOC>(d.gedc->getDataObject(activeParameters[i]),true)->get_f();
198  Teuchos::ArrayRCP<double> vec_array = vec->get1dViewNonConst();
199  dfdp_vectors_.push_back(vec_array);
200  }
201 }
202 
203 // **********************************************************************
204 template<typename TRAITS,typename LO,typename GO,typename NodeT>
206 evaluateFields(typename TRAITS::EvalData workset)
207 {
208  // for convenience pull out some objects from workset
209  std::string blockId = this->wda(workset).block_id;
210  const std::vector<std::size_t> & localCellIds = this->wda(workset).cell_local_ids;
211 
212  // NOTE: A reordering of these loops will likely improve performance
213  // The "getGIDFieldOffsets may be expensive. However the
214  // "getElementGIDs" can be cheaper. However the lookup for LIDs
215  // may be more expensive!
216 
217  // scatter operation for each cell in workset
218  for(std::size_t worksetCellIndex=0;worksetCellIndex<localCellIds.size();++worksetCellIndex) {
219  std::size_t cellLocalId = localCellIds[worksetCellIndex];
220 
221  auto LIDs = globalIndexer_->getElementLIDs(cellLocalId);
222 
223  // loop over each field to be scattered
224  for (std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
225  int fieldNum = fieldIds_[fieldIndex];
226  const std::vector<int> & elmtOffset = globalIndexer_->getGIDFieldOffsets(blockId,fieldNum);
227 
228  // loop over basis functions
229  for(std::size_t basis=0;basis<elmtOffset.size();basis++) {
230  int offset = elmtOffset[basis];
231  LO lid = LIDs[offset];
232  ScalarT value = (scatterFields_[fieldIndex])(worksetCellIndex,basis);
233  for(int d=0;d<value.size();d++)
234  dfdp_vectors_[d][lid] += value.fastAccessDx(d);
235  }
236  }
237  }
238 }
239 
240 // **********************************************************************
241 // Specialization: Jacobian
242 // **********************************************************************
243 
244 template<typename TRAITS,typename LO,typename GO,typename NodeT>
247  const Teuchos::ParameterList& p)
248  : globalIndexer_(indexer)
249  , globalDataKey_("Residual Scatter Container")
250  , my_derivative_size_(0)
251  , other_derivative_size_(0)
252 {
253  std::string scatterName = p.get<std::string>("Scatter Name");
254  scatterHolder_ =
256 
257  // get names to be evaluated
258  const std::vector<std::string>& names =
259  *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
260 
261  // grab map from evaluated names to field names
262  fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
263 
265  p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
266 
267  // build the vector of fields that this is dependent on
268  scatterFields_.resize(names.size());
269  scratch_offsets_.resize(names.size());
270  for (std::size_t eq = 0; eq < names.size(); ++eq) {
271  scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
272 
273  // tell the field manager that we depend on this field
274  this->addDependentField(scatterFields_[eq]);
275  }
276 
277  // this is what this evaluator provides
278  this->addEvaluatedField(*scatterHolder_);
279 
280  if (p.isType<std::string>("Global Data Key"))
281  globalDataKey_ = p.get<std::string>("Global Data Key");
282 
283  this->setName(scatterName+" Scatter Residual (Jacobian)");
284 }
285 
286 // **********************************************************************
287 template<typename TRAITS,typename LO,typename GO,typename NodeT>
289 postRegistrationSetup(typename TRAITS::SetupData d,
290  PHX::FieldManager<TRAITS>& /* fm */)
291 {
292  fieldIds_.resize(scatterFields_.size());
293 
294  const Workset & workset_0 = (*d.worksets_)[0];
295  std::string blockId = this->wda(workset_0).block_id;
296 
297  // load required field numbers for fast use
298  for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
299  // get field ID from DOF manager
300  std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
301  fieldIds_[fd] = globalIndexer_->getFieldNum(fieldName);
302 
303  int fieldNum = fieldIds_[fd];
304  const std::vector<int> & offsets = globalIndexer_->getGIDFieldOffsets(blockId,fieldNum);
305  scratch_offsets_[fd] = PHX::View<int*>("offsets",offsets.size());
306  Kokkos::deep_copy(scratch_offsets_[fd], Kokkos::View<const int*, Kokkos::HostSpace, Kokkos::MemoryUnmanaged>(offsets.data(), offsets.size()));
307  }
308 
309  my_derivative_size_ = globalIndexer_->getElementBlockGIDCount(blockId);
310  if (Teuchos::nonnull(workset_0.other)) {
311  auto otherBlockId = workset_0.other->block_id;
312  other_derivative_size_ = globalIndexer_->getElementBlockGIDCount(otherBlockId);
313  }
315  "lids", scatterFields_[0].extent(0), my_derivative_size_ + other_derivative_size_ );
316  scratch_vals_ = Kokkos::View<typename Sacado::ScalarType<ScalarT>::type**, Kokkos::LayoutRight, PHX::Device>(
317  "vals", scatterFields_[0].extent(0), my_derivative_size_ + other_derivative_size_ );
318 }
319 
320 // **********************************************************************
321 template<typename TRAITS,typename LO,typename GO,typename NodeT>
323 preEvaluate(typename TRAITS::PreEvalData d)
324 {
326 
327  // extract linear object container
328  tpetraContainer_ = Teuchos::rcp_dynamic_cast<LOC>(d.gedc->getDataObject(globalDataKey_));
329 
330  if(tpetraContainer_==Teuchos::null) {
331  // extract linear object container
332  Teuchos::RCP<LinearObjContainer> loc = Teuchos::rcp_dynamic_cast<LOCPair_GlobalEvaluationData>(d.gedc->getDataObject(globalDataKey_),true)->getGhostedLOC();
333  tpetraContainer_ = Teuchos::rcp_dynamic_cast<LOC>(loc);
334  }
335 }
336 
337 
338 // **********************************************************************
339 namespace panzer {
340 namespace {
341 
342 template <typename ScalarT,typename LO,typename GO,typename NodeT,typename LocalMatrixT>
343 class ScatterResidual_Jacobian_Functor {
344 public:
345  typedef typename PHX::Device execution_space;
347 
350  LocalMatrixT jac; // Kokkos jacobian type
351 
353  Kokkos::View<typename Sacado::ScalarType<ScalarT>::type**, Kokkos::LayoutRight, PHX::Device> vals;
354  PHX::View<const int*> offsets; // how to get a particular field
356 
357 
358  KOKKOS_INLINE_FUNCTION
359  void operator()(const unsigned int cell) const
360  {
361  int numIds = lids.extent(1);
362 
363  // loop over the basis functions (currently they are nodes)
364  for(std::size_t basis=0; basis < offsets.extent(0); basis++) {
365  typename FieldType::array_type::reference_type scatterField = field(cell,basis);
366  int offset = offsets(basis);
367  LO lid = lids(cell,offset);
368 
369  // Sum residual
370  if(fillResidual)
371  Kokkos::atomic_add(&r_data(lid,0), scatterField.val());
372 
373  // loop over the sensitivity indices: all DOFs on a cell
374  for(int sensIndex=0;sensIndex<numIds;++sensIndex)
375  vals(cell,sensIndex) = scatterField.fastAccessDx(sensIndex);
376 
377  // Sum Jacobian
378  jac.sumIntoValues(lid, &lids(cell,0), numIds, &vals(cell,0), true, true);
379  } // end basis
380  }
381 };
382 
383 template <typename ScalarT,typename LO,typename GO,typename NodeT>
384 class ScatterResidual_Residual_Functor {
385 public:
386  typedef typename PHX::Device execution_space;
388 
390 
391  PHX::View<const LO**> lids; // local indices for unknowns
392  PHX::View<const int*> offsets; // how to get a particular field
394 
395 
396  KOKKOS_INLINE_FUNCTION
397  void operator()(const unsigned int cell) const
398  {
399 
400  // loop over the basis functions (currently they are nodes)
401  for(std::size_t basis=0; basis < offsets.extent(0); basis++) {
402  int offset = offsets(basis);
403  LO lid = lids(cell,offset);
404  Kokkos::atomic_add(&r_data(lid,0), field(cell,basis));
405 
406  } // end basis
407  }
408 };
409 
410 }
411 }
412 
413 // **********************************************************************
414 template<typename TRAITS,typename LO,typename GO,typename NodeT>
416 evaluateFields(typename TRAITS::EvalData workset)
417 {
419 
420  // for convenience pull out some objects from workset
421  std::string blockId = this->wda(workset).block_id;
422 
423  Teuchos::RCP<typename LOC::VectorType> r = tpetraContainer_->get_f();
424 
425  globalIndexer_->getElementLIDs(this->wda(workset).cell_local_ids_k,scratch_lids_);
426 
427  ScatterResidual_Residual_Functor<ScalarT,LO,GO,NodeT> functor;
428  functor.r_data = r->getLocalViewDevice(Tpetra::Access::ReadWrite);
429  functor.lids = scratch_lids_;
430 
431  // for each field, do a parallel for loop
432  for(std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
433  functor.offsets = scratch_offsets_[fieldIndex];
434  functor.field = scatterFields_[fieldIndex];
435 
436  Kokkos::parallel_for(workset.num_cells,functor);
437  }
438 }
439 
440 // **********************************************************************
441 template<typename TRAITS,typename LO,typename GO,typename NodeT>
443 evaluateFields(typename TRAITS::EvalData workset)
444 {
446 
447  typedef typename LOC::CrsMatrixType::local_matrix_device_type LocalMatrixT;
448 
449  // for convenience pull out some objects from workset
450  std::string blockId = this->wda(workset).block_id;
451 
452  Teuchos::RCP<typename LOC::VectorType> r = tpetraContainer_->get_f();
453  Teuchos::RCP<typename LOC::CrsMatrixType> Jac = tpetraContainer_->get_A();
454 
455  // Cache scratch lids. For interface bc problems the derivative
456  // dimension extent spans two cells. Use subviews to get the self
457  // lids and the other lids.
458  if (Teuchos::nonnull(workset.other)) {
459  auto my_scratch_lids = Kokkos::subview(scratch_lids_,Kokkos::ALL,std::make_pair(0,my_derivative_size_));
460  globalIndexer_->getElementLIDs(this->wda(workset).cell_local_ids_k,my_scratch_lids);
461  auto other_scratch_lids = Kokkos::subview(scratch_lids_,Kokkos::ALL,std::make_pair(my_derivative_size_,my_derivative_size_ + other_derivative_size_));
462  globalIndexer_->getElementLIDs(workset.other->cell_local_ids_k,other_scratch_lids);
463  }
464  else {
465  globalIndexer_->getElementLIDs(this->wda(workset).cell_local_ids_k,scratch_lids_);
466  }
467 
468  ScatterResidual_Jacobian_Functor<ScalarT,LO,GO,NodeT,LocalMatrixT> functor;
469  functor.fillResidual = (r!=Teuchos::null);
470  if(functor.fillResidual)
471  functor.r_data = r->getLocalViewDevice(Tpetra::Access::ReadWrite);
472  functor.jac = Jac->getLocalMatrixDevice();
473  functor.lids = scratch_lids_;
474  functor.vals = scratch_vals_;
475 
476  // for each field, do a parallel for loop
477  for(std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
478  functor.offsets = scratch_offsets_[fieldIndex];
479  functor.field = scatterFields_[fieldIndex];
480 
481  Kokkos::parallel_for(workset.num_cells,functor);
482  }
483 
484 }
485 
486 // **********************************************************************
487 
488 #endif
T & get(const std::string &name, T def_value)
bool nonnull(const std::shared_ptr< T > &p)
FieldType
The type of discretization to use for a field pattern.
PHX::View< const int * > offsets
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Teuchos::RCP< WorksetDetails > other
Kokkos::View< typename Sacado::ScalarType< ScalarT >::type **, Kokkos::LayoutRight, PHX::Device > vals
Kokkos::View< double **, Kokkos::LayoutLeft, PHX::Device > r_data
std::string block_id
DEPRECATED - use: getElementBlock()
Pushes residual values into the residual vector for a Newton-based solve.
PHX::MDField< ScalarT, panzer::Cell, panzer::BASIS > field
A field to which we&#39;ll contribute, or in which we&#39;ll store, the result of computing this integral...
bool isType(const std::string &name) const
Kokkos::View< const LO **, Kokkos::LayoutRight, PHX::Device > lids