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