Panzer Version of the Day
Loading...
Searching...
No Matches
Panzer_ScatterResidual_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_RESIDUAL_BLOCKEDEPETRA_IMPL_HPP
12#define PANZER_SCATTER_RESIDUAL_BLOCKEDEPETRA_IMPL_HPP
13
14#include "Teuchos_RCP.hpp"
15#include "Teuchos_Assert.hpp"
16
17#include "Phalanx_DataLayout.hpp"
18
21#include "Panzer_PureBasis.hpp"
24#include "Panzer_HashUtils.hpp"
27
28#include "Thyra_ProductVectorBase.hpp"
29#include "Thyra_BlockedLinearOpBase.hpp"
30#include "Thyra_TpetraVector.hpp"
31#include "Thyra_TpetraLinearOp.hpp"
32#include "Tpetra_CrsMatrix.hpp"
33#include "KokkosSparse_CrsMatrix.hpp"
34
35#include "Phalanx_DataLayout_MDALayout.hpp"
36
37#include "Teuchos_FancyOStream.hpp"
38
39template <typename EvalT,typename TRAITS,typename LO,typename GO,typename NodeT>
41ScatterResidual_BlockedTpetra(const Teuchos::RCP<const BlockedDOFManager> & /* indexer */,
42 const Teuchos::ParameterList& p)
43{
44 std::string scatterName = p.get<std::string>("Scatter Name");
45 Teuchos::RCP<PHX::FieldTag> scatterHolder =
46 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
47
48 // get names to be evaluated
49 const std::vector<std::string>& names =
50 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
51
52 Teuchos::RCP<PHX::DataLayout> dl =
53 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
54
55 // build the vector of fields that this is dependent on
56 for (std::size_t eq = 0; eq < names.size(); ++eq) {
57 PHX::MDField<const ScalarT,Cell,NODE> field = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
58
59 // tell the field manager that we depend on this field
60 this->addDependentField(field.fieldTag());
61 }
62
63 // this is what this evaluator provides
64 this->addEvaluatedField(*scatterHolder);
65
66 this->setName(scatterName+" Scatter Residual");
67}
68
69// **********************************************************************
70// Specialization: Residual
71// **********************************************************************
72
73template <typename TRAITS,typename LO,typename GO,typename NodeT>
75ScatterResidual_BlockedTpetra(const Teuchos::RCP<const BlockedDOFManager> & indexer,
76 const Teuchos::ParameterList& p)
77 : globalIndexer_(indexer)
78 , globalDataKey_("Residual Scatter Container")
79{
80 std::string scatterName = p.get<std::string>("Scatter Name");
81 scatterHolder_ =
82 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
83
84 // get names to be evaluated
85 const std::vector<std::string>& names =
86 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
87
88 // grab map from evaluated names to field names
89 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
90
91 Teuchos::RCP<PHX::DataLayout> dl =
92 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
93
94 // build the vector of fields that this is dependent on
95 scatterFields_.resize(names.size());
96 for (std::size_t eq = 0; eq < names.size(); ++eq) {
97 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
98
99 // tell the field manager that we depend on this field
100 this->addDependentField(scatterFields_[eq]);
101 }
102
103 // this is what this evaluator provides
104 this->addEvaluatedField(*scatterHolder_);
105
106 if (p.isType<std::string>("Global Data Key"))
107 globalDataKey_ = p.get<std::string>("Global Data Key");
108
109 this->setName(scatterName+" Scatter Residual");
110}
111
112// **********************************************************************
113template <typename TRAITS,typename LO,typename GO,typename NodeT>
115postRegistrationSetup(typename TRAITS::SetupData d,
117{
118 const Workset & workset_0 = (*d.worksets_)[0];
119 const std::string blockId = this->wda(workset_0).block_id;
120
121 fieldIds_.resize(scatterFields_.size());
122 fieldOffsets_.resize(scatterFields_.size());
123 fieldGlobalIndexers_.resize(scatterFields_.size());
124 productVectorBlockIndex_.resize(scatterFields_.size());
125 int maxElementBlockGIDCount = -1;
126 for(std::size_t fd=0; fd < scatterFields_.size(); ++fd) {
127 const std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
128 const int globalFieldNum = globalIndexer_->getFieldNum(fieldName); // Field number in the aggregate BlockDOFManager
129 productVectorBlockIndex_[fd] = globalIndexer_->getFieldBlock(globalFieldNum);
130 fieldGlobalIndexers_[fd] = globalIndexer_->getFieldDOFManagers()[productVectorBlockIndex_[fd]];
131 fieldIds_[fd] = fieldGlobalIndexers_[fd]->getFieldNum(fieldName); // Field number in the sub-global-indexer
132
133 const std::vector<int>& offsets = fieldGlobalIndexers_[fd]->getGIDFieldOffsets(blockId,fieldIds_[fd]);
134 fieldOffsets_[fd] = PHX::View<int*>("ScatterResidual_BlockedTpetra(Residual):fieldOffsets",offsets.size());
135 auto hostOffsets = Kokkos::create_mirror_view(fieldOffsets_[fd]);
136 for (std::size_t i=0; i < offsets.size(); ++i)
137 hostOffsets(i) = offsets[i];
138 Kokkos::deep_copy(fieldOffsets_[fd], hostOffsets);
139
140 maxElementBlockGIDCount = std::max(fieldGlobalIndexers_[fd]->getElementBlockGIDCount(blockId),maxElementBlockGIDCount);
141 }
142
143 // We will use one workset lid view for all fields, but has to be
144 // sized big enough to hold the largest elementBlockGIDCount in the
145 // ProductVector.
146 worksetLIDs_ = PHX::View<LO**>("ScatterResidual_BlockedTpetra(Residual):worksetLIDs",
147 scatterFields_[0].extent(0),
148 maxElementBlockGIDCount);
149}
150
151// **********************************************************************
152template <typename TRAITS,typename LO,typename GO,typename NodeT>
154preEvaluate(typename TRAITS::PreEvalData d)
155{
156 using Teuchos::RCP;
157 using Teuchos::rcp_dynamic_cast;
158
159 // extract linear object container
160 blockedContainer_ = rcp_dynamic_cast<const ContainerType>(d.gedc->getDataObject(globalDataKey_));
161
162 if(blockedContainer_==Teuchos::null) {
163 RCP<const LOCPair_GlobalEvaluationData> gdata = rcp_dynamic_cast<const LOCPair_GlobalEvaluationData>(d.gedc->getDataObject(globalDataKey_),true);
164 blockedContainer_ = rcp_dynamic_cast<const ContainerType>(gdata->getGhostedLOC());
165 }
166}
167
168// **********************************************************************
169template <typename TRAITS,typename LO,typename GO,typename NodeT>
171evaluateFields(typename TRAITS::EvalData workset)
172{
173 using Teuchos::RCP;
174 using Teuchos::rcp_dynamic_cast;
175 using Thyra::VectorBase;
177
178 const auto& localCellIds = this->wda(workset).cell_local_ids_k;
179 const RCP<ProductVectorBase<double>> thyraBlockResidual = rcp_dynamic_cast<ProductVectorBase<double> >(blockedContainer_->get_f(),true);
180
181 // Loop over scattered fields
182 int currentWorksetLIDSubBlock = -1;
183 for (std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
184 // workset LIDs only change for different sub blocks
185 if (productVectorBlockIndex_[fieldIndex] != currentWorksetLIDSubBlock) {
186 fieldGlobalIndexers_[fieldIndex]->getElementLIDs(localCellIds,worksetLIDs_);
187 currentWorksetLIDSubBlock = productVectorBlockIndex_[fieldIndex];
188 }
189
190 auto& tpetraResidual = *((rcp_dynamic_cast<Thyra::TpetraVector<RealType,LO,GO,NodeT>>(thyraBlockResidual->getNonconstVectorBlock(productVectorBlockIndex_[fieldIndex]),true))->getTpetraVector());
191 const auto& kokkosResidual = tpetraResidual.getLocalViewDevice(Tpetra::Access::ReadWrite);
192
193 // Class data fields for lambda capture
194 const auto& fieldOffsets = fieldOffsets_[fieldIndex];
195 const auto& worksetLIDs = worksetLIDs_;
196 const auto& fieldValues = scatterFields_[fieldIndex].get_static_view();
197
198 Kokkos::parallel_for(Kokkos::RangePolicy<PHX::Device>(0,workset.num_cells), KOKKOS_LAMBDA (const int& cell) {
199 for(int basis=0; basis < static_cast<int>(fieldOffsets.size()); ++basis) {
200 const int lid = worksetLIDs(cell,fieldOffsets(basis));
201 Kokkos::atomic_add(&kokkosResidual(lid,0), fieldValues(cell,basis));
202 }
203 });
204 }
205}
206
207// **********************************************************************
208// Specialization: Jacobian
209// **********************************************************************
210
211template <typename TRAITS,typename LO,typename GO,typename NodeT>
213ScatterResidual_BlockedTpetra(const Teuchos::RCP<const BlockedDOFManager> & indexer,
214 const Teuchos::ParameterList& p)
215 : globalIndexer_(indexer)
216 , globalDataKey_("Residual Scatter Container")
217{
218 std::string scatterName = p.get<std::string>("Scatter Name");
219 scatterHolder_ =
220 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
221
222 // get names to be evaluated
223 const std::vector<std::string>& names =
224 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
225
226 // grab map from evaluated names to field names
227 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
228
229 Teuchos::RCP<PHX::DataLayout> dl =
230 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
231
232 // build the vector of fields that this is dependent on
233 scatterFields_.resize(names.size());
234 for (std::size_t eq = 0; eq < names.size(); ++eq) {
235 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
236
237 // tell the field manager that we depend on this field
238 this->addDependentField(scatterFields_[eq]);
239 }
240
241 // this is what this evaluator provides
242 this->addEvaluatedField(*scatterHolder_);
243
244 if (p.isType<std::string>("Global Data Key"))
245 globalDataKey_ = p.get<std::string>("Global Data Key");
246
247 this->setName(scatterName+" Scatter Residual (Jacobian)");
248}
249
250// **********************************************************************
251template <typename TRAITS,typename LO,typename GO,typename NodeT>
253postRegistrationSetup(typename TRAITS::SetupData d,
255{
256 const Workset & workset_0 = (*d.worksets_)[0];
257 const std::string blockId = this->wda(workset_0).block_id;
258
259 fieldIds_.resize(scatterFields_.size());
260 fieldOffsets_.resize(scatterFields_.size());
261 productVectorBlockIndex_.resize(scatterFields_.size());
262 for (std::size_t fd=0; fd < scatterFields_.size(); ++fd) {
263 const std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
264 const int globalFieldNum = globalIndexer_->getFieldNum(fieldName); // Field number in the aggregate BlockDOFManager
265 productVectorBlockIndex_[fd] = globalIndexer_->getFieldBlock(globalFieldNum);
266 const auto& fieldGlobalIndexer = globalIndexer_->getFieldDOFManagers()[productVectorBlockIndex_[fd]];
267 fieldIds_[fd] = fieldGlobalIndexer->getFieldNum(fieldName); // Field number in the sub-global-indexer
268
269 const std::vector<int>& offsets = globalIndexer_->getGIDFieldOffsets(blockId,globalFieldNum);
270 fieldOffsets_[fd] = PHX::View<int*>("ScatterResidual_BlockedTpetra(Jacobian):fieldOffsets",offsets.size());
271 auto hostOffsets = Kokkos::create_mirror_view(fieldOffsets_[fd]);
272 for (std::size_t i=0; i < offsets.size(); ++i)
273 hostOffsets(i) = offsets[i];
274 Kokkos::deep_copy(fieldOffsets_[fd], hostOffsets);
275 }
276
277 // This is sized differently than the Residual implementation since
278 // we need the LIDs for all sub-blocks, not just the single
279 // sub-block for the field residual scatter.
280 int elementBlockGIDCount = 0;
281 for (const auto& blockDOFMgr : globalIndexer_->getFieldDOFManagers())
282 elementBlockGIDCount += blockDOFMgr->getElementBlockGIDCount(blockId);
283
284 worksetLIDs_ = Kokkos::View<LO**, Kokkos::LayoutRight, PHX::Device>(
285 "ScatterResidual_BlockedTpetra(Jacobian):worksetLIDs_",
286 scatterFields_[0].extent(0), elementBlockGIDCount );
287
288 // Compute the block offsets
289 const auto& blockGlobalIndexers = globalIndexer_->getFieldDOFManagers();
290 const int numBlocks = static_cast<int>(globalIndexer_->getFieldDOFManagers().size());
291 blockOffsets_ = PHX::View<LO*>("ScatterResidual_BlockedTpetra(Jacobian):blockOffsets_",
292 numBlocks+1); // Number of fields, plus a sentinel
293 const auto hostBlockOffsets = Kokkos::create_mirror_view(blockOffsets_);
294 for (int blk=0;blk<numBlocks;blk++) {
295 int blockOffset = globalIndexer_->getBlockGIDOffset(blockId,blk);
296 hostBlockOffsets(blk) = blockOffset;
297 }
298 hostBlockOffsets(numBlocks) = hostBlockOffsets(numBlocks-1) + blockGlobalIndexers[blockGlobalIndexers.size()-1]->getElementBlockGIDCount(blockId);
299 Kokkos::deep_copy(blockOffsets_,hostBlockOffsets);
300
301 // Make sure the that derivative dimension in the evaluate call is large
302 // enough to hold all derivatives for each sub block load
303 int max_blockDerivativeSize = 0;
304 for (int blk=0;blk<numBlocks;blk++) {
305 const int blockDerivativeSize = hostBlockOffsets(blk+1) - hostBlockOffsets(blk);
306 if ( blockDerivativeSize > max_blockDerivativeSize )
307 max_blockDerivativeSize = blockDerivativeSize;
308 }
309 workset_vals_ = Kokkos::View<typename Sacado::ScalarType<ScalarT>::type**, Kokkos::LayoutRight, PHX::Device>(
310 "ScatterResidual_BlockedTpetra(Jacobian):workset_vals_",
311 scatterFields_[0].extent(0), max_blockDerivativeSize );
312}
313
314// **********************************************************************
315template <typename TRAITS,typename LO,typename GO,typename NodeT>
317preEvaluate(typename TRAITS::PreEvalData d)
318{
319 using Teuchos::RCP;
320 using Teuchos::rcp_dynamic_cast;
321
322 // extract linear object container
323 blockedContainer_ = rcp_dynamic_cast<const ContainerType>(d.gedc->getDataObject(globalDataKey_));
324
325 if(blockedContainer_==Teuchos::null) {
326 RCP<const LOCPair_GlobalEvaluationData> gdata = rcp_dynamic_cast<const LOCPair_GlobalEvaluationData>(d.gedc->getDataObject(globalDataKey_),true);
327 blockedContainer_ = rcp_dynamic_cast<const ContainerType>(gdata->getGhostedLOC());
328 }
329}
330
331// **********************************************************************
332template <typename TRAITS,typename LO,typename GO,typename NodeT>
334evaluateFields(typename TRAITS::EvalData workset)
335{
336 using Teuchos::RCP;
337 using Teuchos::rcp_dynamic_cast;
338 using Thyra::VectorBase;
341
342 const auto& localCellIds = this->wda(workset).cell_local_ids_k;
343
344 const int numFieldBlocks = globalIndexer_->getNumFieldBlocks();
345 const RCP<const ContainerType> blockedContainer = blockedContainer_;
346 const RCP<ProductVectorBase<double>> thyraBlockResidual = rcp_dynamic_cast<ProductVectorBase<double> >(blockedContainer_->get_f());
347 const bool haveResidual = Teuchos::nonnull(thyraBlockResidual);
348 const RCP<BlockedLinearOpBase<double>> Jac = rcp_dynamic_cast<BlockedLinearOpBase<double> >(blockedContainer_->get_A(),true);
349
350 // Get the local data for the sub-block crs matrices. First allocate
351 // on host and then deep_copy to device. The sub-blocks are
352 // unmanaged since they are allocated and ref counted separately on
353 // host.
354 using LocalMatrixType = KokkosSparse::CrsMatrix<double,LO,PHX::Device,Kokkos::MemoryTraits<Kokkos::Unmanaged>, size_t>;
355 typename PHX::View<LocalMatrixType**>::host_mirror_type
356 hostJacTpetraBlocks("panzer::ScatterResidual_BlockTpetra<Jacobian>::hostJacTpetraBlocks", numFieldBlocks,numFieldBlocks);
357
358 PHX::View<int**> blockExistsInJac = PHX::View<int**>("blockExistsInJac_",numFieldBlocks,numFieldBlocks);
359 auto hostBlockExistsInJac = Kokkos::create_mirror_view(blockExistsInJac);
360
361 for (int row=0; row < numFieldBlocks; ++row) {
362 for (int col=0; col < numFieldBlocks; ++col) {
363 const auto thyraTpetraOperator = rcp_dynamic_cast<Thyra::TpetraLinearOp<double,LO,GO,NodeT>>(Jac->getNonconstBlock(row,col),false);
364 if (nonnull(thyraTpetraOperator)) {
365
366 // HACK to enforce views in the CrsGraph to be
367 // Unmanaged. Passing in the MemoryTrait<Unmanaged> doesn't
368 // work as the CrsGraph in the CrsMatrix ignores the
369 // MemoryTrait. Need to use the runtime constructor by passing
370 // in points to ensure Unmanaged. See:
371 // https://github.com/kokkos/kokkos/issues/1581
372
373 // These two lines are the original code we can revert to when #1581 is fixed.
374 // const auto crsMatrix = rcp_dynamic_cast<Tpetra::CrsMatrix<double,LO,GO,NodeT>>(thyraTpetraOperator->getTpetraOperator(),true);
375 // new (&hostJacTpetraBlocks(row,col)) KokkosSparse::CrsMatrix<double,LO,PHX::Device,Kokkos::MemoryTraits<Kokkos::Unmanaged>> (crsMatrix->getLocalMatrix());
376
377 // Instead do this
378 {
379 // Grab the local managed matrix and graph
380 const auto tpetraCrsMatrix = rcp_dynamic_cast<Tpetra::CrsMatrix<double,LO,GO,NodeT>>(thyraTpetraOperator->getTpetraOperator(),true);
381 const auto managedMatrix = tpetraCrsMatrix->getLocalMatrixDevice();
382 const auto managedGraph = managedMatrix.graph;
383
384 // Create runtime unmanaged versions
385 using StaticCrsGraphType = typename LocalMatrixType::StaticCrsGraphType;
386 StaticCrsGraphType unmanagedGraph;
387 unmanagedGraph.entries = typename StaticCrsGraphType::entries_type(managedGraph.entries.data(),managedGraph.entries.extent(0));
388 unmanagedGraph.row_map = typename StaticCrsGraphType::row_map_type(managedGraph.row_map.data(),managedGraph.row_map.extent(0));
389 unmanagedGraph.row_block_offsets = typename StaticCrsGraphType::row_block_type(managedGraph.row_block_offsets.data(),managedGraph.row_block_offsets.extent(0));
390
391 typename LocalMatrixType::values_type unmanagedValues(managedMatrix.values.data(),managedMatrix.values.extent(0));
392 LocalMatrixType unmanagedMatrix(managedMatrix.values.label(), managedMatrix.numCols(), unmanagedValues, unmanagedGraph);
393 new (&hostJacTpetraBlocks(row,col)) LocalMatrixType(unmanagedMatrix);
394 }
395
396 hostBlockExistsInJac(row,col) = 1;
397 }
398 else {
399 hostBlockExistsInJac(row,col) = 0;
400 }
401 }
402 }
403 typename PHX::View<LocalMatrixType**>
404 jacTpetraBlocks("panzer::ScatterResidual_BlockedTpetra<Jacobian>::jacTpetraBlocks",numFieldBlocks,numFieldBlocks);
405 Kokkos::deep_copy(jacTpetraBlocks,hostJacTpetraBlocks);
406 Kokkos::deep_copy(blockExistsInJac,hostBlockExistsInJac);
407
408 // worksetLIDs is larger for Jacobian than Residual fill. Need the
409 // entire set of field offsets for derivative indexing no matter
410 // which block row you are scattering. The residual only needs the
411 // lids for the sub-block that it is scattering to. The subviews
412 // below are to offset the LID blocks correctly.
413 const auto& globalIndexers = globalIndexer_->getFieldDOFManagers();
414 auto blockOffsets_h = Kokkos::create_mirror_view(blockOffsets_);
415 Kokkos::deep_copy(blockOffsets_h, blockOffsets_);
416 for (size_t block=0; block < globalIndexers.size(); ++block) {
417 const auto subviewOfBlockLIDs = Kokkos::subview(worksetLIDs_,Kokkos::ALL(), std::make_pair(blockOffsets_h(block),blockOffsets_h(block+1)));
418 globalIndexers[block]->getElementLIDs(localCellIds,subviewOfBlockLIDs);
419 }
420
421 // Loop over scattered fields
422 for (std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
423
424 const int blockRowIndex = productVectorBlockIndex_[fieldIndex];
425 typename Tpetra::Vector<double,LO,GO,PHX::Device>::dual_view_type::t_dev kokkosResidual;
426 if (haveResidual) {
427 auto& tpetraResidual = *((rcp_dynamic_cast<Thyra::TpetraVector<RealType,LO,GO,NodeT>>(thyraBlockResidual->getNonconstVectorBlock(blockRowIndex),true))->getTpetraVector());
428 kokkosResidual = tpetraResidual.getLocalViewDevice(Tpetra::Access::ReadWrite);
429 }
430
431 // Class data fields for lambda capture
432 const PHX::View<const int*> fieldOffsets = fieldOffsets_[fieldIndex];
433 const PHX::View<const ScalarT**> fieldValues = scatterFields_[fieldIndex].get_static_view();
434 const PHX::View<const LO*> blockOffsets = blockOffsets_;
435
436 const Kokkos::View<const LO**, Kokkos::LayoutRight, PHX::Device> worksetLIDs = worksetLIDs_;
437 Kokkos::View<typename Sacado::ScalarType<ScalarT>::type**, Kokkos::LayoutRight, PHX::Device> workset_vals = workset_vals_;
438
439 Kokkos::parallel_for(Kokkos::RangePolicy<PHX::Device>(0,workset.num_cells), KOKKOS_LAMBDA (const int& cell) {
440 for(int basis=0; basis < static_cast<int>(fieldOffsets.size()); ++basis) {
441 typedef PHX::MDField<const ScalarT,Cell,NODE> FieldType;
442 typename FieldType::array_type::reference_type tmpFieldVal = fieldValues(cell,basis);
443 const int rowLID = worksetLIDs(cell,fieldOffsets(basis));
444
445 if (haveResidual)
446 Kokkos::atomic_add(&kokkosResidual(rowLID,0), tmpFieldVal.val());
447
448 for (int blockColIndex=0; blockColIndex < numFieldBlocks; ++blockColIndex) {
449 if (blockExistsInJac(blockRowIndex,blockColIndex)) {
450 const int start = blockOffsets(blockColIndex);
451 const int stop = blockOffsets(blockColIndex+1);
452 const int sensSize = stop-start;
453
454 for (int i=0; i < sensSize; ++i)
455 workset_vals(cell,i) = tmpFieldVal.fastAccessDx(start+i);
456
457 jacTpetraBlocks(blockRowIndex,blockColIndex).sumIntoValues(rowLID, &worksetLIDs(cell,start), sensSize, &workset_vals(cell,0), true,true);
458 }
459 }
460 }
461 });
462
463 }
464
465 // Placement delete on view of matrices
466 for (int row=0; row < numFieldBlocks; ++row) {
467 for (int col=0; col < numFieldBlocks; ++col) {
468 if (hostBlockExistsInJac(row,col)) {
469 hostJacTpetraBlocks(row,col).~CrsMatrix();
470 }
471 }
472 }
473
474}
475
476// **********************************************************************
477// Specialization: Tangent
478// **********************************************************************
479
480template <typename TRAITS,typename LO,typename GO,typename NodeT>
482ScatterResidual_BlockedTpetra(const Teuchos::RCP<const BlockedDOFManager> & indexer,
483 const Teuchos::ParameterList& p)
484 : globalIndexer_(indexer)
485 , globalDataKey_("Residual Scatter Container")
486{
487 std::string scatterName = p.get<std::string>("Scatter Name");
488 scatterHolder_ =
489 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
490
491 // get names to be evaluated
492 const std::vector<std::string>& names =
493 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
494
495 // grab map from evaluated names to field names
496 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
497
498 Teuchos::RCP<PHX::DataLayout> dl =
499 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
500
501 // build the vector of fields that this is dependent on
502 scatterFields_.resize(names.size());
503 for (std::size_t eq = 0; eq < names.size(); ++eq) {
504 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
505
506 // tell the field manager that we depend on this field
507 this->addDependentField(scatterFields_[eq]);
508 }
509
510 // this is what this evaluator provides
511 this->addEvaluatedField(*scatterHolder_);
512
513 if (p.isType<std::string>("Global Data Key"))
514 globalDataKey_ = p.get<std::string>("Global Data Key");
515
516 this->setName(scatterName+" Scatter Residual (Tangent)");
517}
518
519// **********************************************************************
520template <typename TRAITS,typename LO,typename GO,typename NodeT>
522postRegistrationSetup(typename TRAITS::SetupData d,
524{
525 const Workset & workset_0 = (*d.worksets_)[0];
526 const std::string blockId = this->wda(workset_0).block_id;
527
528 fieldIds_.resize(scatterFields_.size());
529 fieldOffsets_.resize(scatterFields_.size());
530 fieldGlobalIndexers_.resize(scatterFields_.size());
531 productVectorBlockIndex_.resize(scatterFields_.size());
532 int maxElementBlockGIDCount = -1;
533 for(std::size_t fd=0; fd < scatterFields_.size(); ++fd) {
534 const std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
535 const int globalFieldNum = globalIndexer_->getFieldNum(fieldName); // Field number in the aggregate BlockDOFManager
536 productVectorBlockIndex_[fd] = globalIndexer_->getFieldBlock(globalFieldNum);
537 fieldGlobalIndexers_[fd] = globalIndexer_->getFieldDOFManagers()[productVectorBlockIndex_[fd]];
538 fieldIds_[fd] = fieldGlobalIndexers_[fd]->getFieldNum(fieldName); // Field number in the sub-global-indexer
539
540 const std::vector<int>& offsets = fieldGlobalIndexers_[fd]->getGIDFieldOffsets(blockId,fieldIds_[fd]);
541 fieldOffsets_[fd] = PHX::View<int*>("ScatterResidual_BlockedTpetra(Tangent):fieldOffsets",offsets.size());
542 auto hostOffsets = Kokkos::create_mirror_view(fieldOffsets_[fd]);
543 for (std::size_t i=0; i < offsets.size(); ++i)
544 hostOffsets(i) = offsets[i];
545 Kokkos::deep_copy(fieldOffsets_[fd], hostOffsets);
546
547 maxElementBlockGIDCount = std::max(fieldGlobalIndexers_[fd]->getElementBlockGIDCount(blockId),maxElementBlockGIDCount);
548 }
549
550 // We will use one workset lid view for all fields, but has to be
551 // sized big enough to hold the largest elementBlockGIDCount in the
552 // ProductVector.
553 worksetLIDs_ = PHX::View<LO**>("ScatterResidual_BlockedTpetra(Tangent):worksetLIDs",
554 scatterFields_[0].extent(0),
555 maxElementBlockGIDCount);
556}
557
558// **********************************************************************
559template <typename TRAITS,typename LO,typename GO,typename NodeT>
561preEvaluate(typename TRAITS::PreEvalData d)
562{
563 using Teuchos::RCP;
564 using Teuchos::rcp_dynamic_cast;
566
567 // this is the list of parameters and their names that this scatter has to account for
568 std::vector<std::string> activeParameters =
569 rcp_dynamic_cast<ParameterList_GlobalEvaluationData>(d.gedc->getDataObject("PARAMETER_NAMES"))->getActiveParameters();
570
571 const int numBlocks = static_cast<int>(globalIndexer_->getFieldDOFManagers().size());
572
573 dfdpFieldsVoV_.initialize("ScatterResidual_Tpetra<Tangent>::dfdpFieldsVoV_",activeParameters.size(),numBlocks);
574
575 for(std::size_t i=0;i<activeParameters.size();i++) {
576 RCP<ContainerType> paramBlockedContainer = rcp_dynamic_cast<ContainerType>(d.gedc->getDataObject(activeParameters[i]),true);
577 RCP<ProductVectorBase<double>> productVector =
578 rcp_dynamic_cast<ProductVectorBase<double>>(paramBlockedContainer->get_f(),true);
579 for(int j=0;j<numBlocks;j++) {
580 auto& tpetraBlock = *((rcp_dynamic_cast<Thyra::TpetraVector<RealType,LO,GO,NodeT>>(productVector->getNonconstVectorBlock(j),true))->getTpetraVector());
581 const auto& dfdp_view = tpetraBlock.getLocalViewDevice(Tpetra::Access::ReadWrite);
582 dfdpFieldsVoV_.addView(dfdp_view,i,j);
583 }
584 }
585
586 dfdpFieldsVoV_.syncHostToDevice();
587
588 // extract linear object container
589 blockedContainer_ = rcp_dynamic_cast<const ContainerType>(d.gedc->getDataObject(globalDataKey_));
590
591 if(blockedContainer_==Teuchos::null) {
592 RCP<const LOCPair_GlobalEvaluationData> gdata = rcp_dynamic_cast<const LOCPair_GlobalEvaluationData>(d.gedc->getDataObject(globalDataKey_),true);
593 blockedContainer_ = rcp_dynamic_cast<const ContainerType>(gdata->getGhostedLOC());
594 }
595}
596
597// **********************************************************************
598template <typename TRAITS,typename LO,typename GO,typename NodeT>
600evaluateFields(typename TRAITS::EvalData workset)
601{
602 using Teuchos::RCP;
603 using Teuchos::rcp_dynamic_cast;
604 using Thyra::VectorBase;
606
607 const auto& localCellIds = this->wda(workset).cell_local_ids_k;
608 const RCP<ProductVectorBase<double>> thyraBlockResidual = rcp_dynamic_cast<ProductVectorBase<double> >(blockedContainer_->get_f(),true);
609
610 // Loop over scattered fields
611 int currentWorksetLIDSubBlock = -1;
612 for (std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
613 // workset LIDs only change for different sub blocks
614 if (productVectorBlockIndex_[fieldIndex] != currentWorksetLIDSubBlock) {
615 fieldGlobalIndexers_[fieldIndex]->getElementLIDs(localCellIds,worksetLIDs_);
616 currentWorksetLIDSubBlock = productVectorBlockIndex_[fieldIndex];
617 }
618
619 auto& tpetraResidual = *((rcp_dynamic_cast<Thyra::TpetraVector<RealType,LO,GO,NodeT>>(thyraBlockResidual->getNonconstVectorBlock(productVectorBlockIndex_[fieldIndex]),true))->getTpetraVector());
620 const auto& kokkosResidual = tpetraResidual.getLocalViewDevice(Tpetra::Access::ReadWrite);
621
622 // Class data fields for lambda capture
623 const auto& fieldOffsets = fieldOffsets_[fieldIndex];
624 const auto& worksetLIDs = worksetLIDs_;
625 const auto& fieldValues = scatterFields_[fieldIndex].get_static_view();
626 const auto& tangentFieldsDevice = dfdpFieldsVoV_.getViewDevice();
627 const auto& kokkosTangents = Kokkos::subview(tangentFieldsDevice,Kokkos::ALL(),productVectorBlockIndex_[fieldIndex]);
628 const double num_params = Kokkos::dimension_scalar(fieldValues)-1;
629
630 Kokkos::parallel_for(Kokkos::RangePolicy<PHX::Device>(0,workset.num_cells), KOKKOS_LAMBDA (const int& cell) {
631 for(int basis=0; basis < static_cast<int>(fieldOffsets.size()); ++basis) {
632 const int lid = worksetLIDs(cell,fieldOffsets(basis));
633 Kokkos::atomic_add(&kokkosResidual(lid,0), fieldValues(cell,basis).val());
634 for(int i_param=0; i_param<num_params; i_param++)
635 kokkosTangents(i_param)(lid,0) += fieldValues(cell,basis).fastAccessDx(i_param);
636 }
637 });
638 }
639}
640
641// **********************************************************************
642
643#endif
PHX::View< const int * > offsets
PHX::MDField< ScalarT, panzer::Cell, panzer::BASIS > field
A field to which we'll contribute, or in which we'll store, the result of computing this integral.
Pushes residual values into the residual vector for a Newton-based solve.
void postRegistrationSetup(typename TRAITS::SetupData, PHX::FieldManager< TRAITS > &)
ScatterResidual_BlockedTpetra(const Teuchos::RCP< const BlockedDOFManager > &)
std::string block_id
DEPRECATED - use: getElementBlock()
FieldType
The type of discretization to use for a field pattern.