Panzer Version of the Day
Loading...
Searching...
No Matches
Panzer_ScatterDirichletResidual_BlockedTpetra_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_DIRICHLET_RESIDUAL_BLOCEDTPETRA_IMPL_HPP
12#define PANZER_SCATTER_DIRICHLET_RESIDUAL_BLOCEDTPETRA_IMPL_HPP
13
14#include "Teuchos_RCP.hpp"
15#include "Teuchos_Assert.hpp"
16
17#include "Phalanx_DataLayout.hpp"
18#include "Panzer_NodeType.hpp"
19
20// #include "Epetra_Map.h"
21// #include "Epetra_Vector.h"
22// #include "Epetra_CrsMatrix.h"
23
26#include "Panzer_PureBasis.hpp"
30
31#include "Phalanx_DataLayout_MDALayout.hpp"
32
33#include "Thyra_SpmdVectorBase.hpp"
34#include "Thyra_ProductVectorBase.hpp"
35#include "Thyra_BlockedLinearOpBase.hpp"
36// #include "Thyra_get_Epetra_Operator.hpp"
37
38#include "Teuchos_FancyOStream.hpp"
39
40#include <unordered_map>
41
42template <typename EvalT,typename TRAITS,typename LO,typename GO,typename NodeT>
44ScatterDirichletResidual_BlockedTpetra(const Teuchos::RCP<const BlockedDOFManager> & /* indexer */,
45 const Teuchos::ParameterList& p)
46{
47 std::string scatterName = p.get<std::string>("Scatter Name");
48 Teuchos::RCP<PHX::FieldTag> scatterHolder =
49 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
50
51 // get names to be evaluated
52 const std::vector<std::string>& names =
53 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
54
55 Teuchos::RCP<PHX::DataLayout> dl =
56 p.get< Teuchos::RCP<panzer::PureBasis> >("Basis")->functional;
57
58 // build the vector of fields that this is dependent on
59 for (std::size_t eq = 0; eq < names.size(); ++eq) {
60 PHX::MDField<const ScalarT,Cell,NODE> scatterField = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
61
62 // tell the field manager that we depend on this field
63 this->addDependentField(scatterField.fieldTag());
64 }
65
66 // this is what this evaluator provides
67 this->addEvaluatedField(*scatterHolder);
68
69 this->setName(scatterName+" Scatter Residual");
70}
71
72// **********************************************************************
73// Specialization: Residual
74// **********************************************************************
75
76
77template <typename TRAITS,typename LO,typename GO,typename NodeT>
79ScatterDirichletResidual_BlockedTpetra(const Teuchos::RCP<const BlockedDOFManager> & indexer,
80 const Teuchos::ParameterList& p)
81 : globalIndexer_(indexer)
82 , globalDataKey_("Residual Scatter Container")
83{
84 std::string scatterName = p.get<std::string>("Scatter Name");
86 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
87
88 // get names to be evaluated
89 const std::vector<std::string>& names =
90 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
91
92 // grab map from evaluated names to field names
93 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
94
95 // determine if we are scattering an initial condition
96 scatterIC_ = p.isParameter("Scatter Initial Condition") ? p.get<bool>("Scatter Initial Condition") : false;
97
98 Teuchos::RCP<PHX::DataLayout> dl = (!scatterIC_) ?
99 p.get< Teuchos::RCP<panzer::PureBasis> >("Basis")->functional :
100 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
101 if (!scatterIC_) {
102 side_subcell_dim_ = p.get<int>("Side Subcell Dimension");
103 local_side_id_ = p.get<int>("Local Side ID");
104 }
105
106 // build the vector of fields that this is dependent on
107 scatterFields_.resize(names.size());
108 for (std::size_t eq = 0; eq < names.size(); ++eq) {
109 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
110
111 // tell the field manager that we depend on this field
112 this->addDependentField(scatterFields_[eq]);
113 }
114
115 checkApplyBC_ = p.isParameter("Check Apply BC") ? p.get<bool>("Check Apply BC") : false;
116 applyBC_.resize(names.size()); // must allocate (even if not used) to support lambda capture
117 if (checkApplyBC_) {
118 for (std::size_t eq = 0; eq < names.size(); ++eq) {
119 applyBC_[eq] = PHX::MDField<const bool,Cell,NODE>(std::string("APPLY_BC_")+fieldMap_->find(names[eq])->second,dl);
120 this->addDependentField(applyBC_[eq]);
121 }
122 }
123
124 // this is what this evaluator provides
125 this->addEvaluatedField(*scatterHolder_);
126
127 if (p.isType<std::string>("Global Data Key"))
128 globalDataKey_ = p.get<std::string>("Global Data Key");
129
130 this->setName(scatterName+" Scatter Dirichlet Residual");
131}
132
133// **********************************************************************
134template <typename TRAITS,typename LO,typename GO,typename NodeT>
136postRegistrationSetup(typename TRAITS::SetupData d,
138{
139 const Workset & workset_0 = (*d.worksets_)[0];
140 const std::string blockId = this->wda(workset_0).block_id;
141
142 fieldIds_.resize(scatterFields_.size());
143 fieldOffsets_.resize(scatterFields_.size());
147 int maxElementBlockGIDCount = -1;
148 for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
149 // get field ID from DOF manager
150 std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
151
152 const int globalFieldNum = globalIndexer_->getFieldNum(fieldName); // Field number in the aggregate BlockDOFManager
153 productVectorBlockIndex_[fd] = globalIndexer_->getFieldBlock(globalFieldNum);
154 fieldGlobalIndexers_[fd] = globalIndexer_->getFieldDOFManagers()[productVectorBlockIndex_[fd]];
155 fieldIds_[fd] = fieldGlobalIndexers_[fd]->getFieldNum(fieldName); // Field number in the sub-global-indexer
156
157 // Offsets and basisIndex depend on whether scattering IC or Dirichlet BC
158 if (!scatterIC_) {
159 const auto& offsetPair = fieldGlobalIndexers_[fd]->getGIDFieldOffsets_closure(blockId,fieldIds_[fd],side_subcell_dim_,local_side_id_);
160 {
161 const auto& offsets = offsetPair.first;
162 fieldOffsets_[fd] = PHX::View<int*>("ScatterDirichletResidual_BlockedTpetra(Residual):fieldOffsets",offsets.size());
163 auto hostOffsets = Kokkos::create_mirror_view(fieldOffsets_[fd]);
164 for (std::size_t i=0; i < offsets.size(); ++i)
165 hostOffsets(i) = offsets[i];
166 Kokkos::deep_copy(fieldOffsets_[fd], hostOffsets);
167 }
168 {
169 const auto& basisIndex = offsetPair.second;
170 basisIndexForMDFieldOffsets_[fd] = PHX::View<int*>("ScatterDirichletResidual_BlockedTpetra(Residual):basisIndexForMDFieldOffsets",basisIndex.size());
171 auto hostBasisIndex = Kokkos::create_mirror_view(basisIndexForMDFieldOffsets_[fd]);
172 for (std::size_t i=0; i < basisIndex.size(); ++i)
173 hostBasisIndex(i) = basisIndex[i];
174 Kokkos::deep_copy(basisIndexForMDFieldOffsets_[fd], hostBasisIndex);
175 }
176 }
177 else {
178 // For ICs, only need offsets, not basisIndex
179 const std::vector<int>& offsets = fieldGlobalIndexers_[fd]->getGIDFieldOffsets(blockId,fieldIds_[fd]);
180 fieldOffsets_[fd] = PHX::View<int*>("ScatterDirichletResidual_BlockedTpetra(Residual):fieldOffsets",offsets.size());
181 auto hostOffsets = Kokkos::create_mirror_view(fieldOffsets_[fd]);
182 for (std::size_t i=0; i < offsets.size(); ++i)
183 hostOffsets(i) = offsets[i];
184 Kokkos::deep_copy(fieldOffsets_[fd], hostOffsets);
185 }
186
187 maxElementBlockGIDCount = std::max(fieldGlobalIndexers_[fd]->getElementBlockGIDCount(blockId),maxElementBlockGIDCount);
188 }
189
190 // We will use one workset lid view for all fields, but has to be
191 // sized big enough to hold the largest elementBlockGIDCount in the
192 // ProductVector.
193 worksetLIDs_ = PHX::View<LO**>("ScatterResidual_BlockedTpetra(Residual):worksetLIDs",
194 scatterFields_[0].extent(0),
195 maxElementBlockGIDCount);
196}
197
198// **********************************************************************
199template <typename TRAITS,typename LO,typename GO,typename NodeT>
201preEvaluate(typename TRAITS::PreEvalData d)
202{
203 // extract dirichlet counter from container
204 Teuchos::RCP<const ContainerType> blockContainer
205 = Teuchos::rcp_dynamic_cast<ContainerType>(d.gedc->getDataObject("Dirichlet Counter"),true);
206
207 dirichletCounter_ = Teuchos::rcp_dynamic_cast<Thyra::ProductVectorBase<double> >(blockContainer->get_f(),true);
208 TEUCHOS_ASSERT(!Teuchos::is_null(dirichletCounter_));
209
210 // extract linear object container
211 blockedContainer_ = Teuchos::rcp_dynamic_cast<const ContainerType>(d.gedc->getDataObject(globalDataKey_),true);
212 TEUCHOS_ASSERT(!Teuchos::is_null(blockedContainer_));
213}
214
215// **********************************************************************
216template <typename TRAITS,typename LO,typename GO,typename NodeT>
218evaluateFields(typename TRAITS::EvalData workset)
219{
220 using Teuchos::RCP;
221 using Teuchos::rcp_dynamic_cast;
222 using Thyra::VectorBase;
224
225 const auto& localCellIds = this->wda(workset).cell_local_ids_k;
226
227 RCP<ProductVectorBase<double> > thyraScatterTarget = (!scatterIC_) ?
228 rcp_dynamic_cast<ProductVectorBase<double> >(blockedContainer_->get_f(),true) :
229 rcp_dynamic_cast<ProductVectorBase<double> >(blockedContainer_->get_x(),true);
230
231 // Loop over scattered fields
232 int currentWorksetLIDSubBlock = -1;
233 for (std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
234 // workset LIDs only change for different sub blocks
235 if (productVectorBlockIndex_[fieldIndex] != currentWorksetLIDSubBlock) {
236 fieldGlobalIndexers_[fieldIndex]->getElementLIDs(localCellIds,worksetLIDs_);
237 currentWorksetLIDSubBlock = productVectorBlockIndex_[fieldIndex];
238 }
239
240 // Get Scatter target block
241 auto& tpetraScatterTarget = *((rcp_dynamic_cast<Thyra::TpetraVector<RealType,LO,GO,NodeT>>(thyraScatterTarget->getNonconstVectorBlock(productVectorBlockIndex_[fieldIndex]),true))->getTpetraVector());
242 const auto& kokkosScatterTarget = tpetraScatterTarget.getLocalViewDevice(Tpetra::Access::ReadWrite);
243
244 // Get dirichlet counter block
245 auto& tpetraDirichletCounter = *((rcp_dynamic_cast<Thyra::TpetraVector<RealType,LO,GO,NodeT>>(dirichletCounter_->getNonconstVectorBlock(productVectorBlockIndex_[fieldIndex]),true))->getTpetraVector());
246 const auto& kokkosDirichletCounter = tpetraDirichletCounter.getLocalViewDevice(Tpetra::Access::ReadWrite);
247
248 // Class data fields for lambda capture
249 const auto fieldOffsets = fieldOffsets_[fieldIndex];
250 const auto basisIndices = basisIndexForMDFieldOffsets_[fieldIndex];
251 const auto worksetLIDs = worksetLIDs_;
252 const auto fieldValues = scatterFields_[fieldIndex].get_static_view();
253 const auto applyBC = applyBC_[fieldIndex].get_static_view();
254 const bool checkApplyBC = checkApplyBC_;
255
256 if (!scatterIC_) {
257
258 Kokkos::parallel_for(Kokkos::RangePolicy<PHX::ExecutionSpace>(0,workset.num_cells), KOKKOS_LAMBDA (const int& cell) {
259 for (int basis=0; basis < static_cast<int>(fieldOffsets.size()); ++basis) {
260 const int lid = worksetLIDs(cell,fieldOffsets(basis));
261 if (lid < 0) // not on this processor!
262 continue;
263 const int basisIndex = basisIndices(basis);
264
265 // Possible warp divergence for hierarchic
266 if (checkApplyBC)
267 if (!applyBC(cell,basisIndex))
268 continue;
269
270 kokkosScatterTarget(lid,0) = fieldValues(cell,basisIndex);
271 kokkosDirichletCounter(lid,0) = 1.0;
272 }
273 });
274
275 } else {
276
277 Kokkos::parallel_for(Kokkos::RangePolicy<PHX::ExecutionSpace>(0,workset.num_cells), KOKKOS_LAMBDA (const int& cell) {
278 for (int basis=0; basis < static_cast<int>(fieldOffsets.size()); ++basis) {
279 const int lid = worksetLIDs(cell,fieldOffsets(basis));
280 if (lid < 0) // not on this processor!
281 continue;
282 kokkosScatterTarget(lid,0) = fieldValues(cell,basis);
283 kokkosDirichletCounter(lid,0) = 1.0;
284 }
285 });
286
287 }
288 }
289
290}
291
292// **********************************************************************
293// Specialization: Jacobian
294// **********************************************************************
295
296template <typename TRAITS,typename LO,typename GO,typename NodeT>
298ScatterDirichletResidual_BlockedTpetra(const Teuchos::RCP<const BlockedDOFManager> & indexer,
299 const Teuchos::ParameterList& p)
300 : ScatterDirichletResidual_BlockedTpetra(indexer,std::vector<Teuchos::RCP<const panzer::GlobalIndexer> >(),p)
301{ }
302
303template <typename TRAITS,typename LO,typename GO,typename NodeT>
305ScatterDirichletResidual_BlockedTpetra(const Teuchos::RCP<const BlockedDOFManager> & indexer,
306 const std::vector<Teuchos::RCP<const panzer::GlobalIndexer> > & colIndexers,
307 const Teuchos::ParameterList& p)
308 : globalIndexer_(indexer)
309 , globalDataKey_("Residual Scatter Container")
310 , colGlobalIndexers_(colIndexers)
311 , hasColIndexers_(!colIndexers.empty())
312{
313 // When the columns are not indexed separately they are the rows, so resolve
314 // that here and let everything below read colGlobalIndexers_ unconditionally.
315 if(!hasColIndexers_) {
316 const auto & rowManagers = globalIndexer_->getFieldDOFManagers();
317 colGlobalIndexers_.assign(rowManagers.begin(),rowManagers.end());
318 }
319
320 std::string scatterName = p.get<std::string>("Scatter Name");
322 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
323
324 // get names to be evaluated
325 const std::vector<std::string>& names =
326 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
327
328 // grab map from evaluated names to field names
329 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
330
331 Teuchos::RCP<PHX::DataLayout> dl =
332 p.get< Teuchos::RCP<panzer::PureBasis> >("Basis")->functional;
333
334 side_subcell_dim_ = p.get<int>("Side Subcell Dimension");
335 local_side_id_ = p.get<int>("Local Side ID");
336
337 // build the vector of fields that this is dependent on
338 scatterFields_.resize(names.size());
339 for (std::size_t eq = 0; eq < names.size(); ++eq) {
340 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
341
342 // tell the field manager that we depend on this field
343 this->addDependentField(scatterFields_[eq]);
344 }
345
346 checkApplyBC_ = p.get<bool>("Check Apply BC");
347 applyBC_.resize(names.size()); // must allocate (even if not used) to support lambda capture
348 if (checkApplyBC_) {
349 for (std::size_t eq = 0; eq < names.size(); ++eq) {
350 applyBC_[eq] = PHX::MDField<const bool,Cell,NODE>(std::string("APPLY_BC_")+fieldMap_->find(names[eq])->second,dl);
351 this->addDependentField(applyBC_[eq]);
352 }
353 }
354
355 // this is what this evaluator provides
356 this->addEvaluatedField(*scatterHolder_);
357
358 if (p.isType<std::string>("Global Data Key"))
359 globalDataKey_ = p.get<std::string>("Global Data Key");
360
361 this->setName(scatterName+" Scatter Dirichlet Residual (Jacobian)");
362}
363
364// **********************************************************************
365template <typename TRAITS,typename LO,typename GO,typename NodeT>
367postRegistrationSetup(typename TRAITS::SetupData d,
369{
370 const Workset & workset_0 = (*d.worksets_)[0];
371 const std::string blockId = this->wda(workset_0).block_id;
372
373 fieldIds_.resize(scatterFields_.size());
374 fieldOffsets_.resize(scatterFields_.size());
377 for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
378
379 std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
380 const int globalFieldNum = globalIndexer_->getFieldNum(fieldName); // Field number in the aggregate BlockDOFManager
381 productVectorBlockIndex_[fd] = globalIndexer_->getFieldBlock(globalFieldNum);
382 const auto& fieldGlobalIndexer = globalIndexer_->getFieldDOFManagers()[productVectorBlockIndex_[fd]];
383 fieldIds_[fd] = fieldGlobalIndexer->getFieldNum(fieldName); // Field number in the sub-global-indexer
384
385 const auto& offsetPair = fieldGlobalIndexer->getGIDFieldOffsets_closure(blockId,fieldIds_[fd],side_subcell_dim_,local_side_id_);
386 {
387 const auto& offsets = offsetPair.first;
388 fieldOffsets_[fd] = PHX::View<int*>("ScatterDirichletResidual_BlockedTpetra(Jacobian):fieldOffsets",offsets.size());
389 auto hostOffsets = Kokkos::create_mirror_view(fieldOffsets_[fd]);
390 for (std::size_t i=0; i < offsets.size(); ++i)
391 hostOffsets(i) = offsets[i];
392 Kokkos::deep_copy(fieldOffsets_[fd], hostOffsets);
393 }
394 {
395 const auto& basisIndex = offsetPair.second;
396 basisIndexForMDFieldOffsets_[fd] = PHX::View<int*>("ScatterDirichletResidual_BlockedTpetra(Jacobian):basisIndexForMDFieldOffsets",basisIndex.size());
397 auto hostBasisIndex = Kokkos::create_mirror_view(basisIndexForMDFieldOffsets_[fd]);
398 for (std::size_t i=0; i < basisIndex.size(); ++i)
399 hostBasisIndex(i) = basisIndex[i];
400 Kokkos::deep_copy(basisIndexForMDFieldOffsets_[fd], hostBasisIndex);
401 }
402 }
403
404 // This is sized differently than the Residual implementation since
405 // we need the LIDs for all sub-blocks, not just the single
406 // sub-block for the field residual scatter.
407 int elementBlockGIDCount = 0;
408 for (const auto& blockDOFMgr : globalIndexer_->getFieldDOFManagers())
409 elementBlockGIDCount += blockDOFMgr->getElementBlockGIDCount(blockId);
410
411 worksetLIDs_ = PHX::View<LO**>("ScatterDirichletResidual_BlockedTpetra(Jacobian):worksetLIDs",
412 scatterFields_[0].extent(0),
413 elementBlockGIDCount);
414
415 // Compute the block offsets
416 const auto& blockGlobalIndexers = globalIndexer_->getFieldDOFManagers();
417 const int numBlocks = static_cast<int>(globalIndexer_->getFieldDOFManagers().size());
418 blockOffsets_ = PHX::View<LO*>("ScatterDirichletResidual_BlockedTpetra(Jacobian):blockOffsets_",
419 numBlocks+1); // Number of fields, plus a sentinel
420 const auto hostBlockOffsets = Kokkos::create_mirror_view(blockOffsets_);
421 for (int blk=0;blk<numBlocks;blk++) {
422 int blockOffset = globalIndexer_->getBlockGIDOffset(blockId,blk);
423 hostBlockOffsets(blk) = blockOffset;
424 }
425 hostBlockOffsets(numBlocks) = hostBlockOffsets(numBlocks-1) + blockGlobalIndexers[blockGlobalIndexers.size()-1]->getElementBlockGIDCount(blockId);
426 Kokkos::deep_copy(blockOffsets_,hostBlockOffsets);
427
428 // The columns carry the derivative components, so when they are indexed
429 // separately from the rows they need their own offsets and LIDs.
430 if (!hasColIndexers_) {
433 }
434 else {
435 const int numColBlocks = static_cast<int>(colGlobalIndexers_.size());
436 colBlockOffsets_ = PHX::View<LO*>("ScatterDirichletResidual_BlockedTpetra(Jacobian):colBlockOffsets_",
437 numColBlocks+1);
438 auto hostColOffsets = Kokkos::create_mirror_view(colBlockOffsets_);
439 hostColOffsets(0) = 0;
440 for (int blk=0;blk<numColBlocks;blk++)
441 hostColOffsets(blk+1) = hostColOffsets(blk) + colGlobalIndexers_[blk]->getElementBlockGIDCount(blockId);
442 Kokkos::deep_copy(colBlockOffsets_,hostColOffsets);
443
444 colWorksetLIDs_ = PHX::View<LO**>("ScatterDirichletResidual_BlockedTpetra(Jacobian):colWorksetLIDs",
445 scatterFields_[0].extent(0), hostColOffsets(numColBlocks));
446 }
447
448 // The offsets never change after this point, so copy them to the host once
449 // here rather than rebuilding a mirror on every evaluateFields() call.
450 blockOffsets_h_ = Kokkos::create_mirror_view(blockOffsets_);
451 Kokkos::deep_copy(blockOffsets_h_, blockOffsets_);
452 colBlockOffsets_h_ = Kokkos::create_mirror_view(colBlockOffsets_);
453 Kokkos::deep_copy(colBlockOffsets_h_, colBlockOffsets_);
454
455 // Size the scatter scratch once. The contents are rebuilt per call, but the
456 // extents only depend on the block structure.
457 {
458 // Size with the same expression evaluateFields() indexes with.
459 const int numRowBlocks = globalIndexer_->getNumFieldBlocks();
460 const int numColBlocks = static_cast<int>(colGlobalIndexers_.size());
461 hostJacTpetraBlocks_ = typename PHX::View<LocalMatrixType**>::host_mirror_type(
462 "ScatterDirichletResidual_BlockedTpetra(Jacobian):hostJacTpetraBlocks", numRowBlocks, numColBlocks);
463 jacTpetraBlocks_ = PHX::View<LocalMatrixType**>(
464 "ScatterDirichletResidual_BlockedTpetra(Jacobian):jacTpetraBlocks", numRowBlocks, numColBlocks);
465 blockExistsInJac_ = PHX::View<int**>("ScatterDirichletResidual_BlockedTpetra(Jacobian):blockExistsInJac", numRowBlocks, numColBlocks);
466 hostBlockExistsInJac_ = Kokkos::create_mirror_view(blockExistsInJac_);
467 }
468
469 // Make sure the that hard coded derivative dimension in the
470 // evaluate call is large enough to hold all derivatives for each
471 // sub block load
472 for (int blk=0;blk<numBlocks;blk++) {
473 const int blockDerivativeSize = hostBlockOffsets(blk+1) - hostBlockOffsets(blk);
474 TEUCHOS_TEST_FOR_EXCEPTION(blockDerivativeSize > maxDerivativeArraySize_, std::runtime_error,
475 "ERROR: the derivative dimension for sub block "
476 << blk << "with a value of " << blockDerivativeSize
477 << "is larger than the size allocated for cLIDs and vals "
478 << "in the evaluate call! You must manually increase the "
479 << "size and recompile!");
480 }
481}
482
483// **********************************************************************
484template <typename TRAITS,typename LO,typename GO,typename NodeT>
486preEvaluate(typename TRAITS::PreEvalData d)
487{
488 // extract dirichlet counter from container
489 Teuchos::RCP<const ContainerType> blockContainer
490 = Teuchos::rcp_dynamic_cast<const ContainerType>(d.gedc->getDataObject("Dirichlet Counter"),true);
491
492 dirichletCounter_ = Teuchos::rcp_dynamic_cast<Thyra::ProductVectorBase<double> >(blockContainer->get_f(),true);
493 TEUCHOS_ASSERT(!Teuchos::is_null(dirichletCounter_));
494
495 // extract linear object container
496 blockedContainer_ = Teuchos::rcp_dynamic_cast<const ContainerType>(d.gedc->getDataObject(globalDataKey_),true);
497 TEUCHOS_ASSERT(!Teuchos::is_null(blockedContainer_));
498}
499
500// **********************************************************************
501template <typename TRAITS,typename LO,typename GO,typename NodeT>
503evaluateFields(typename TRAITS::EvalData workset)
504{
505 using Teuchos::RCP;
506 using Teuchos::rcp_dynamic_cast;
507 using Thyra::VectorBase;
510
511 const auto& localCellIds = this->wda(workset).cell_local_ids_k;
512
513 const int numFieldBlocks = globalIndexer_->getNumFieldBlocks();
514 const int numColFieldBlocks = static_cast<int>(colGlobalIndexers_.size());
515 const RCP<const ContainerType> blockedContainer = blockedContainer_;
516 const RCP<ProductVectorBase<double>> thyraBlockResidual = rcp_dynamic_cast<ProductVectorBase<double>>(blockedContainer_->get_f());
517 const bool haveResidual = Teuchos::nonnull(thyraBlockResidual);
518 const RCP<BlockedLinearOpBase<double>> Jac = rcp_dynamic_cast<BlockedLinearOpBase<double>>(blockedContainer_->get_A(),true);
519
520 // Get the local data for the sub-block crs matrices. First allocate
521 // on host and then deep_copy to device. The sub-blocks are
522 // unmanaged since they are allocated and ref counted separately on
523 // host.
524 // Scratch sized in postRegistrationSetup(); only the contents are rebuilt here.
525 TEUCHOS_ASSERT(static_cast<int>(jacTpetraBlocks_.extent(0))==numFieldBlocks &&
526 static_cast<int>(jacTpetraBlocks_.extent(1))==numColFieldBlocks);
527 auto& hostJacTpetraBlocks = hostJacTpetraBlocks_;
528 auto& blockExistsInJac = blockExistsInJac_;
529 auto& hostBlockExistsInJac = hostBlockExistsInJac_;
530
531 for (int row=0; row < numFieldBlocks; ++row) {
532 for (int col=0; col < numColFieldBlocks; ++col) {
533 const auto thyraTpetraOperator = rcp_dynamic_cast<Thyra::TpetraLinearOp<double,LO,GO,NodeT>>(Jac->getNonconstBlock(row,col),false);
534 if (nonnull(thyraTpetraOperator)) {
535
536 // HACK to enforce views in the CrsGraph to be
537 // Unmanaged. Passing in the MemoryTrait<Unmanaged> doesn't
538 // work as the CrsGraph in the CrsMatrix ignores the
539 // MemoryTrait. Need to use the runtime constructor by passing
540 // in points to ensure Unmanaged. See:
541 // https://github.com/kokkos/kokkos/issues/1581
542
543 // These two lines are the original code we can revert to when #1581 is fixed.
544 // const auto crsMatrix = rcp_dynamic_cast<Tpetra::CrsMatrix<double,LO,GO,NodeT>>(thyraTpetraOperator->getTpetraOperator(),true);
545 // new (&hostJacTpetraBlocks(row,col)) KokkosSparse::CrsMatrix<double,LO,PHX::Device,Kokkos::MemoryTraits<Kokkos::Unmanaged>> (crsMatrix->getLocalMatrix());
546
547 // Instead do this
548 {
549 // Grab the local managed matrix and graph
550 const auto tpetraCrsMatrix = rcp_dynamic_cast<Tpetra::CrsMatrix<double,LO,GO,NodeT>>(thyraTpetraOperator->getTpetraOperator(),true);
551 const auto managedMatrix = tpetraCrsMatrix->getLocalMatrixDevice();
552 const auto managedGraph = managedMatrix.graph;
553
554 // Create runtime unmanaged versions
555 using StaticCrsGraphType = typename LocalMatrixType::StaticCrsGraphType;
556 StaticCrsGraphType unmanagedGraph;
557 unmanagedGraph.entries = typename StaticCrsGraphType::entries_type(managedGraph.entries.data(),managedGraph.entries.extent(0));
558 unmanagedGraph.row_map = typename StaticCrsGraphType::row_map_type(managedGraph.row_map.data(),managedGraph.row_map.extent(0));
559 unmanagedGraph.row_block_offsets = typename StaticCrsGraphType::row_block_type(managedGraph.row_block_offsets.data(),managedGraph.row_block_offsets.extent(0));
560
561 typename LocalMatrixType::values_type unmanagedValues(managedMatrix.values.data(),managedMatrix.values.extent(0));
562 LocalMatrixType unmanagedMatrix(managedMatrix.values.label(), managedMatrix.numCols(), unmanagedValues, unmanagedGraph);
563 new (&hostJacTpetraBlocks(row,col)) LocalMatrixType(unmanagedMatrix);
564 }
565
566 hostBlockExistsInJac(row,col) = 1;
567 }
568 else {
569 hostBlockExistsInJac(row,col) = 0;
570 }
571 }
572 }
573 auto& jacTpetraBlocks = jacTpetraBlocks_;
574 Kokkos::deep_copy(jacTpetraBlocks,hostJacTpetraBlocks);
575 Kokkos::deep_copy(blockExistsInJac,hostBlockExistsInJac);
576
577 // worksetLIDs is larger for Jacobian than Residual fill. Need the
578 // entire set of field offsets for derivative indexing no matter
579 // which block row you are scattering. The residual only needs the
580 // lids for the sub-block that it is scattering to. The subviews
581 // below are to offset the LID blocks correctly.
582 const auto& globalIndexers = globalIndexer_->getFieldDOFManagers();
583 const auto& blockOffsets_h = blockOffsets_h_;
584 for (size_t block=0; block < globalIndexers.size(); ++block) {
585 const auto subviewOfBlockLIDs = Kokkos::subview(worksetLIDs_,Kokkos::ALL(), std::make_pair(blockOffsets_h(block),blockOffsets_h(block+1)));
586 globalIndexers[block]->getElementLIDs(localCellIds,subviewOfBlockLIDs);
587 }
588
589 const auto& colBlockOffsets_h = colBlockOffsets_h_;
590 if (hasColIndexers_) {
591 for (size_t block=0; block < colGlobalIndexers_.size(); ++block) {
592 const auto subviewOfBlockLIDs = Kokkos::subview(colWorksetLIDs_,Kokkos::ALL(), std::make_pair(colBlockOffsets_h(block),colBlockOffsets_h(block+1)));
593 colGlobalIndexers_[block]->getElementLIDs(localCellIds,subviewOfBlockLIDs);
594 }
595 }
596
597 // Loop over scattered fields
598 for (std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
599
600 const int blockRowIndex = productVectorBlockIndex_[fieldIndex];
601 typename Tpetra::Vector<double,LO,GO,panzer::TpetraNodeType>::dual_view_type::t_dev kokkosResidual;
602 if (haveResidual) {
603 auto& tpetraResidual = *((rcp_dynamic_cast<Thyra::TpetraVector<RealType,LO,GO,NodeT>>(thyraBlockResidual->getNonconstVectorBlock(blockRowIndex),true))->getTpetraVector());
604 kokkosResidual = tpetraResidual.getLocalViewDevice(Tpetra::Access::ReadWrite);
605 }
606
607 // Get dirichlet counter block
608 auto& tpetraDirichletCounter = *((rcp_dynamic_cast<Thyra::TpetraVector<RealType,LO,GO,NodeT>>(dirichletCounter_->getNonconstVectorBlock(blockRowIndex),true))->getTpetraVector());
609 const auto& kokkosDirichletCounter = tpetraDirichletCounter.getLocalViewDevice(Tpetra::Access::ReadWrite);
610
611 // Class data fields for lambda capture
612 const PHX::View<const int*> fieldOffsets = fieldOffsets_[fieldIndex];
613 const auto& basisIndices = basisIndexForMDFieldOffsets_[fieldIndex];
614 const PHX::View<const LO**> worksetLIDs = worksetLIDs_;
615 const PHX::View<const ScalarT**> fieldValues = scatterFields_[fieldIndex].get_static_view();
616 const PHX::View<const LO*> blockOffsets = blockOffsets_;
617 const PHX::View<const LO*> colBlockOffsets = colBlockOffsets_;
618 const PHX::View<const LO**> colWorksetLIDs = colWorksetLIDs_;
619 const auto& applyBC = applyBC_[fieldIndex].get_static_view();
620 const bool checkApplyBC = checkApplyBC_;
621
622 Kokkos::parallel_for(Kokkos::RangePolicy<PHX::ExecutionSpace>(0,workset.num_cells), KOKKOS_LAMBDA (const int& cell) {
623 LO cLIDs[maxDerivativeArraySize_];
624 typename Sacado::ScalarType<ScalarT>::type vals[maxDerivativeArraySize_];
625
626 for(int basis=0; basis < static_cast<int>(fieldOffsets.size()); ++basis) {
627 const int block_row_offset = blockOffsets(blockRowIndex);
628 const int rowLID = worksetLIDs(cell,block_row_offset+fieldOffsets(basis));
629
630 if (rowLID < 0) // not on this processor!
631 continue;
632
633 const int basisIndex = basisIndices(basis);
634
635 // Possible warp divergence for hierarchic
636 if (checkApplyBC)
637 if (!applyBC(cell,basisIndex))
638 continue;
639
640 typedef PHX::MDField<const ScalarT,Cell,NODE> FieldType;
641 typename FieldType::array_type::reference_type tmpFieldVal = fieldValues(cell,basisIndex);
642
643 if (haveResidual)
644 kokkosResidual(rowLID,0) = tmpFieldVal.val();
645
646 kokkosDirichletCounter(rowLID,0) = 1.0;
647
648 // Zero out entire matrix row
649 for (int blockColIndex=0; blockColIndex < numColFieldBlocks; ++blockColIndex) {
650 if (blockExistsInJac(blockRowIndex,blockColIndex)) {
651 const auto& rowEntries = jacTpetraBlocks(blockRowIndex,blockColIndex).row(rowLID);
652 for (int i=0; i < rowEntries.length; ++i)
653 rowEntries.value(i) = Traits::RealType(0.0);
654 }
655 }
656
657 // Set values
658 for (int blockColIndex=0; blockColIndex < numColFieldBlocks; ++blockColIndex) {
659 if (blockExistsInJac(blockRowIndex,blockColIndex)) {
660 const int start = colBlockOffsets(blockColIndex);
661 const int stop = colBlockOffsets(blockColIndex+1);
662 const int sensSize = stop-start;
663 // Views may be padded. Use contiguous arrays here
664 for (int i=0; i < sensSize; ++i) {
665 cLIDs[i] = colWorksetLIDs(cell,start+i);
666 vals[i] = tmpFieldVal.fastAccessDx(start+i);
667 }
668 jacTpetraBlocks(blockRowIndex,blockColIndex).replaceValues(rowLID,cLIDs,sensSize,vals,true,true);
669 }
670 }
671 }
672 });
673
674 }
675
676 // Placement delete on view of matrices
677 for (int row=0; row < numFieldBlocks; ++row) {
678 for (int col=0; col < numColFieldBlocks; ++col) {
679 if (hostBlockExistsInJac(row,col)) {
680 hostJacTpetraBlocks(row,col).~CrsMatrix();
681 }
682 }
683 }
684
685}
686
687// **********************************************************************
688
689// **********************************************************************
690// Specialization: Tangent
691// **********************************************************************
692
693
694template <typename TRAITS,typename LO,typename GO,typename NodeT>
696ScatterDirichletResidual_BlockedTpetra(const Teuchos::RCP<const BlockedDOFManager> & indexer,
697 const Teuchos::ParameterList& p)
698 : globalIndexer_(indexer)
699 , globalDataKey_("Residual Scatter Container")
700{
701 std::string scatterName = p.get<std::string>("Scatter Name");
703 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
704
705 // get names to be evaluated
706 const std::vector<std::string>& names =
707 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
708
709 // grab map from evaluated names to field names
710 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
711
712 // determine if we are scattering an initial condition
713 scatterIC_ = p.isParameter("Scatter Initial Condition") ? p.get<bool>("Scatter Initial Condition") : false;
714
715 Teuchos::RCP<PHX::DataLayout> dl = (!scatterIC_) ?
716 p.get< Teuchos::RCP<panzer::PureBasis> >("Basis")->functional :
717 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
718 if (!scatterIC_) {
719 side_subcell_dim_ = p.get<int>("Side Subcell Dimension");
720 local_side_id_ = p.get<int>("Local Side ID");
721 }
722
723 // build the vector of fields that this is dependent on
724 scatterFields_.resize(names.size());
725 for (std::size_t eq = 0; eq < names.size(); ++eq) {
726 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
727
728 // tell the field manager that we depend on this field
729 this->addDependentField(scatterFields_[eq]);
730 }
731
732 checkApplyBC_ = p.isParameter("Check Apply BC") ? p.get<bool>("Check Apply BC") : false;
733 applyBC_.resize(names.size()); // must allocate (even if not used) to support lambda capture
734 if (checkApplyBC_) {
735 for (std::size_t eq = 0; eq < names.size(); ++eq) {
736 applyBC_[eq] = PHX::MDField<const bool,Cell,NODE>(std::string("APPLY_BC_")+fieldMap_->find(names[eq])->second,dl);
737 this->addDependentField(applyBC_[eq]);
738 }
739 }
740
741 // this is what this evaluator provides
742 this->addEvaluatedField(*scatterHolder_);
743
744 if (p.isType<std::string>("Global Data Key"))
745 globalDataKey_ = p.get<std::string>("Global Data Key");
746
747 this->setName(scatterName+" Scatter Dirichlet Residual");
748}
749
750// **********************************************************************
751template <typename TRAITS,typename LO,typename GO,typename NodeT>
753postRegistrationSetup(typename TRAITS::SetupData d,
755{
756 const Workset & workset_0 = (*d.worksets_)[0];
757 const std::string blockId = this->wda(workset_0).block_id;
758
759 fieldIds_.resize(scatterFields_.size());
760 fieldOffsets_.resize(scatterFields_.size());
764 int maxElementBlockGIDCount = -1;
765 for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
766 // get field ID from DOF manager
767 std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
768
769 const int globalFieldNum = globalIndexer_->getFieldNum(fieldName); // Field number in the aggregate BlockDOFManager
770 productVectorBlockIndex_[fd] = globalIndexer_->getFieldBlock(globalFieldNum);
771 fieldGlobalIndexers_[fd] = globalIndexer_->getFieldDOFManagers()[productVectorBlockIndex_[fd]];
772 fieldIds_[fd] = fieldGlobalIndexers_[fd]->getFieldNum(fieldName); // Field number in the sub-global-indexer
773
774 // Offsets and basisIndex depend on whether scattering IC or Dirichlet BC
775 if (!scatterIC_) {
776 const auto& offsetPair = fieldGlobalIndexers_[fd]->getGIDFieldOffsets_closure(blockId,fieldIds_[fd],side_subcell_dim_,local_side_id_);
777 {
778 const auto& offsets = offsetPair.first;
779 fieldOffsets_[fd] = PHX::View<int*>("ScatterDirichletResidual_BlockedTpetra(Tangent):fieldOffsets",offsets.size());
780 auto hostOffsets = Kokkos::create_mirror_view(fieldOffsets_[fd]);
781 for (std::size_t i=0; i < offsets.size(); ++i)
782 hostOffsets(i) = offsets[i];
783 Kokkos::deep_copy(fieldOffsets_[fd], hostOffsets);
784 }
785 {
786 const auto& basisIndex = offsetPair.second;
787 basisIndexForMDFieldOffsets_[fd] = PHX::View<int*>("ScatterDirichletResidual_BlockedTpetra(Tangent):basisIndexForMDFieldOffsets",basisIndex.size());
788 auto hostBasisIndex = Kokkos::create_mirror_view(basisIndexForMDFieldOffsets_[fd]);
789 for (std::size_t i=0; i < basisIndex.size(); ++i)
790 hostBasisIndex(i) = basisIndex[i];
791 Kokkos::deep_copy(basisIndexForMDFieldOffsets_[fd], hostBasisIndex);
792 }
793 }
794 else {
795 // For ICs, only need offsets, not basisIndex
796 const std::vector<int>& offsets = fieldGlobalIndexers_[fd]->getGIDFieldOffsets(blockId,fieldIds_[fd]);
797 fieldOffsets_[fd] = PHX::View<int*>("ScatterDirichletResidual_BlockedTpetra(Tangent):fieldOffsets",offsets.size());
798 auto hostOffsets = Kokkos::create_mirror_view(fieldOffsets_[fd]);
799 for (std::size_t i=0; i < offsets.size(); ++i)
800 hostOffsets(i) = offsets[i];
801 Kokkos::deep_copy(fieldOffsets_[fd], hostOffsets);
802 }
803
804 maxElementBlockGIDCount = std::max(fieldGlobalIndexers_[fd]->getElementBlockGIDCount(blockId),maxElementBlockGIDCount);
805 }
806
807 // We will use one workset lid view for all fields, but has to be
808 // sized big enough to hold the largest elementBlockGIDCount in the
809 // ProductVector.
810 worksetLIDs_ = PHX::View<LO**>("ScatterResidual_BlockedTpetra(Tangent):worksetLIDs",
811 scatterFields_[0].extent(0),
812 maxElementBlockGIDCount);
813}
814
815// **********************************************************************
816template <typename TRAITS,typename LO,typename GO,typename NodeT>
818preEvaluate(typename TRAITS::PreEvalData d)
819{
820
821 // this is the list of parameters and their names that this scatter has to account for
822 std::vector<std::string> activeParameters =
823 Teuchos::rcp_dynamic_cast<ParameterList_GlobalEvaluationData>(d.gedc->getDataObject("PARAMETER_NAMES"))->getActiveParameters();
824
825 const int numBlocks = static_cast<int>(globalIndexer_->getFieldDOFManagers().size());
826
827 // Only the outer view is allocated here. The device views of the df/dp
828 // sub-blocks are acquired and released in evaluateFields().
829 dfdpFieldsVoV_.initialize("ScatterResidual_Tpetra<Tangent>::dfdpFieldsVoV_",activeParameters.size(),numBlocks);
830
831 dfdpVectors_.resize(activeParameters.size());
832 for(std::size_t i=0;i<activeParameters.size();i++) {
833 Teuchos::RCP<ContainerType> paramBlockedContainer = Teuchos::rcp_dynamic_cast<ContainerType>(d.gedc->getDataObject(activeParameters[i]),true);
834 Teuchos::RCP<Thyra::ProductVectorBase<double>> productVector =
835 Teuchos::rcp_dynamic_cast<Thyra::ProductVectorBase<double>>(paramBlockedContainer->get_f(),true);
836 dfdpVectors_[i].resize(numBlocks);
837 for(int j=0;j<numBlocks;j++)
838 dfdpVectors_[i][j] = Teuchos::rcp_dynamic_cast<Thyra::TpetraVector<RealType,LO,GO,NodeT>>(productVector->getNonconstVectorBlock(j),true)->getTpetraVector();
839 }
840
841 // extract dirichlet counter from container
842 Teuchos::RCP<const ContainerType> blockContainer
843 = Teuchos::rcp_dynamic_cast<ContainerType>(d.gedc->getDataObject("Dirichlet Counter"),true);
844
845 dirichletCounter_ = Teuchos::rcp_dynamic_cast<Thyra::ProductVectorBase<double> >(blockContainer->get_f(),true);
846 TEUCHOS_ASSERT(!Teuchos::is_null(dirichletCounter_));
847
848 // extract linear object container
849 blockedContainer_ = Teuchos::rcp_dynamic_cast<const ContainerType>(d.gedc->getDataObject(globalDataKey_),true);
850 TEUCHOS_ASSERT(!Teuchos::is_null(blockedContainer_));
851}
852
853// **********************************************************************
854template <typename TRAITS,typename LO,typename GO,typename NodeT>
856evaluateFields(typename TRAITS::EvalData workset)
857{
858 using Teuchos::RCP;
859 using Teuchos::rcp_dynamic_cast;
860 using Thyra::VectorBase;
862
863 const auto& localCellIds = this->wda(workset).cell_local_ids_k;
864
865 RCP<ProductVectorBase<double> > thyraScatterTarget = (!scatterIC_) ?
866 rcp_dynamic_cast<ProductVectorBase<double> >(blockedContainer_->get_f(),true) :
867 rcp_dynamic_cast<ProductVectorBase<double> >(blockedContainer_->get_x(),true);
868
869 // Acquire the df/dp device views for the duration of this method only. See
870 // the release loop at the end of this method.
871 for(std::size_t i=0;i<dfdpVectors_.size();i++)
872 for(std::size_t j=0;j<dfdpVectors_[i].size();j++)
873 dfdpFieldsVoV_.addView(dfdpVectors_[i][j]->getLocalViewDevice(Tpetra::Access::ReadWrite),i,j);
874 dfdpFieldsVoV_.syncHostToDevice();
875
876 // Loop over scattered fields
877 int currentWorksetLIDSubBlock = -1;
878 for (std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
879 // workset LIDs only change for different sub blocks
880 if (productVectorBlockIndex_[fieldIndex] != currentWorksetLIDSubBlock) {
881 fieldGlobalIndexers_[fieldIndex]->getElementLIDs(localCellIds,worksetLIDs_);
882 currentWorksetLIDSubBlock = productVectorBlockIndex_[fieldIndex];
883 }
884
885 // Get Scatter target block
886 auto& tpetraScatterTarget = *((rcp_dynamic_cast<Thyra::TpetraVector<RealType,LO,GO,NodeT>>(thyraScatterTarget->getNonconstVectorBlock(productVectorBlockIndex_[fieldIndex]),true))->getTpetraVector());
887 const auto& kokkosScatterTarget = tpetraScatterTarget.getLocalViewDevice(Tpetra::Access::ReadWrite);
888
889 // Get dirichlet counter block
890 auto& tpetraDirichletCounter = *((rcp_dynamic_cast<Thyra::TpetraVector<RealType,LO,GO,NodeT>>(dirichletCounter_->getNonconstVectorBlock(productVectorBlockIndex_[fieldIndex]),true))->getTpetraVector());
891 const auto& kokkosDirichletCounter = tpetraDirichletCounter.getLocalViewDevice(Tpetra::Access::ReadWrite);
892
893 // Class data fields for lambda capture
894 const auto fieldOffsets = fieldOffsets_[fieldIndex];
895 const auto basisIndices = basisIndexForMDFieldOffsets_[fieldIndex];
896 const auto worksetLIDs = worksetLIDs_;
897 const auto fieldValues = scatterFields_[fieldIndex].get_static_view();
898 const auto applyBC = applyBC_[fieldIndex].get_static_view();
899 const bool checkApplyBC = checkApplyBC_;
900 const auto& tangentFieldsDevice = dfdpFieldsVoV_.getViewDevice();
901 const auto& kokkosTangents = Kokkos::subview(tangentFieldsDevice,Kokkos::ALL(),productVectorBlockIndex_[fieldIndex]);
902 const std::size_t num_params = Sacado::dimension_scalar(fieldValues)-1;
903
904 if (!scatterIC_) {
905
906 Kokkos::parallel_for(Kokkos::RangePolicy<PHX::ExecutionSpace>(0,workset.num_cells), KOKKOS_LAMBDA (const int& cell) {
907 for (int basis=0; basis < static_cast<int>(fieldOffsets.size()); ++basis) {
908 const int lid = worksetLIDs(cell,fieldOffsets(basis));
909 if (lid < 0) // not on this processor!
910 continue;
911 const int basisIndex = basisIndices(basis);
912
913 // Possible warp divergence for hierarchic
914 if (checkApplyBC)
915 if (!applyBC(cell,basisIndex))
916 continue;
917
918 kokkosScatterTarget(lid,0) = fieldValues(cell,basisIndex).val();
919 for(std::size_t i_param=0; i_param<num_params; i_param++)
920 kokkosTangents(i_param)(lid,0) = fieldValues(cell,basisIndex).fastAccessDx(i_param);
921
922 kokkosDirichletCounter(lid,0) = 1.0;
923 }
924 });
925
926 } else {
927
928 Kokkos::parallel_for(Kokkos::RangePolicy<PHX::ExecutionSpace>(0,workset.num_cells), KOKKOS_LAMBDA (const int& cell) {
929 for (int basis=0; basis < static_cast<int>(fieldOffsets.size()); ++basis) {
930 const int lid = worksetLIDs(cell,fieldOffsets(basis));
931 if (lid < 0) // not on this processor!
932 continue;
933 kokkosScatterTarget(lid,0) = fieldValues(cell,basis).val();
934 for(std::size_t i_param=0; i_param<num_params; i_param++)
935 kokkosTangents(i_param)(lid,0) = fieldValues(cell,basis).fastAccessDx(i_param);
936 kokkosDirichletCounter(lid,0) = 1.0;
937 }
938 });
939
940 }
941 }
942
943 // Release the df/dp device views. Holding a device view past the return of
944 // this method makes any subsequent host access to the same vector throw, e.g.
945 // AssemblyEngine::evaluateDirichletBCs() -> adjustForDirichletConditions().
946 for(std::size_t i=0;i<dfdpVectors_.size();i++)
947 for(std::size_t j=0;j<dfdpVectors_[i].size();j++)
948 dfdpFieldsVoV_.addView(Kokkos::View<RealType**,Kokkos::LayoutLeft,PHX::Device>(),i,j);
949}
950#endif
PHX::View< LO ** > colWorksetLIDs_
Column LIDs and derivative offsets. Aliases of the row members when square.
PHX::View< LO * > blockOffsets_
The offset values of the blocked DOFs per element. Size of number of blocks in the product vector + 1...
std::vector< PHX::View< int * > > fieldOffsets_
Offset into the cell lids for each field. Size of number of fields to scatter.
PHX::View< LO * >::host_mirror_type blockOffsets_h_
Host copies of the offsets, filled once since the offsets never change.
KokkosSparse::CrsMatrix< double, LO, PHX::Device, Kokkos::MemoryTraits< Kokkos::Unmanaged >, size_t > LocalMatrixType
Sub-block matrix type handed to the scatter kernel.
Pushes residual values into the residual vector for a Newton-based solve.
ScatterDirichletResidual_BlockedTpetra(const Teuchos::RCP< const BlockedDOFManager > &)
void postRegistrationSetup(typename TRAITS::SetupData, PHX::FieldManager< TRAITS > &)
FieldType
The type of discretization to use for a field pattern.
double RealType
Scalar type used for the Residual evaluation type (plain double).