Panzer Version of the Day
Loading...
Searching...
No Matches
Panzer_ScatterResidual_BlockedEpetra_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
19#include "Epetra_Map.h"
20#include "Epetra_Vector.h"
21#include "Epetra_CrsMatrix.h"
22
25#include "Panzer_PureBasis.hpp"
28#include "Panzer_HashUtils.hpp"
30
31#include "Thyra_SpmdVectorBase.hpp"
32#include "Thyra_ProductVectorBase.hpp"
33#include "Thyra_DefaultProductVector.hpp"
34#include "Thyra_BlockedLinearOpBase.hpp"
35#include "Thyra_DefaultBlockedLinearOp.hpp"
36#include "Thyra_get_Epetra_Operator.hpp"
37
38#include "Phalanx_DataLayout_MDALayout.hpp"
39
40#include "Teuchos_FancyOStream.hpp"
41
42// **********************************************************************
43// Specialization: Residual
44// **********************************************************************
45
46template<typename TRAITS,typename LO,typename GO>
48ScatterResidual_BlockedEpetra(const std::vector<Teuchos::RCP<const GlobalIndexer> > & rIndexers,
49 const std::vector<Teuchos::RCP<const GlobalIndexer> > & cIndexers,
50 const Teuchos::ParameterList& p,
51 bool /* useDiscreteAdjoint */)
52 : rowIndexers_(rIndexers)
53 , colIndexers_(cIndexers)
54 , globalDataKey_("Residual Scatter Container")
55{
56 std::string scatterName = p.get<std::string>("Scatter Name");
57 scatterHolder_ =
58 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
59
60 // get names to be evaluated
61 const std::vector<std::string>& names =
62 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
63
64 // grab map from evaluated names to field names
65 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
66
67 Teuchos::RCP<PHX::DataLayout> dl =
68 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
69
70 // build the vector of fields that this is dependent on
71 scatterFields_.resize(names.size());
72 for (std::size_t eq = 0; eq < names.size(); ++eq) {
73 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
74
75 // tell the field manager that we depend on this field
76 this->addDependentField(scatterFields_[eq]);
77 }
78
79 // this is what this evaluator provides
80 this->addEvaluatedField(*scatterHolder_);
81
82 if (p.isType<std::string>("Global Data Key"))
83 globalDataKey_ = p.get<std::string>("Global Data Key");
84
85 this->setName(scatterName+" Scatter Residual");
86}
87
88// **********************************************************************
89template<typename TRAITS,typename LO,typename GO>
91postRegistrationSetup(typename TRAITS::SetupData /* d */,
93{
94 indexerIds_.resize(scatterFields_.size());
95 subFieldIds_.resize(scatterFields_.size());
96
97 // load required field numbers for fast use
98 for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
99 // get field ID from DOF manager
100 std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
101
102 indexerIds_[fd] = getFieldBlock(fieldName,rowIndexers_);
103 subFieldIds_[fd] = rowIndexers_[indexerIds_[fd]]->getFieldNum(fieldName);
104 }
105}
106
107// **********************************************************************
108template<typename TRAITS,typename LO,typename GO>
110preEvaluate(typename TRAITS::PreEvalData d)
111{
114
115 // extract linear object container
116 Teuchos::RCP<const BLOC> blockedContainer = Teuchos::rcp_dynamic_cast<const BLOC>(d.gedc->getDataObject(globalDataKey_));
117 Teuchos::RCP<const ELOC> epetraContainer = Teuchos::rcp_dynamic_cast<const ELOC>(d.gedc->getDataObject(globalDataKey_));
118
119 // if its blocked do this
120 if(blockedContainer!=Teuchos::null)
121 r_ = Teuchos::rcp_dynamic_cast<Thyra::ProductVectorBase<double> >(blockedContainer->get_f());
122 else if(epetraContainer!=Teuchos::null) // if its straight up epetra do this
123 r_ = Thyra::castOrCreateNonconstProductVectorBase<double>(epetraContainer->get_f_th());
124
125 TEUCHOS_ASSERT(r_!=Teuchos::null);
126}
127
128// **********************************************************************
129template<typename TRAITS,typename LO,typename GO>
131evaluateFields(typename TRAITS::EvalData workset)
132{
133 using Teuchos::RCP;
134 using Teuchos::ptrFromRef;
135 using Teuchos::rcp_dynamic_cast;
136
137 using Thyra::VectorBase;
138 using Thyra::SpmdVectorBase;
140
141 // for convenience pull out some objects from workset
142 std::string blockId = this->wda(workset).block_id;
143 const std::vector<std::size_t> & localCellIds = this->wda(workset).cell_local_ids;
144
145 // NOTE: A reordering of these loops will likely improve performance
146 // The "getGIDFieldOffsets may be expensive. However the
147 // "getElementGIDs" can be cheaper. However the lookup for LIDs
148 // may be more expensive!
149
150 // loop over each field to be scattered
151 Teuchos::ArrayRCP<double> local_r;
152 for (std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
153 int indexerId = indexerIds_[fieldIndex];
154 int subFieldNum = subFieldIds_[fieldIndex];
155
156 // grab local data for inputing
157 rcp_dynamic_cast<SpmdVectorBase<double> >(r_->getNonconstVectorBlock(indexerId))->getNonconstLocalData(ptrFromRef(local_r));
158
159 auto subRowIndexer = rowIndexers_[indexerId];
160 const std::vector<int> & elmtOffset = subRowIndexer->getGIDFieldOffsets(blockId,subFieldNum);
161
162 auto field = PHX::as_view(scatterFields_[fieldIndex]);
163 auto field_h = Kokkos::create_mirror_view(field);
164 Kokkos::deep_copy(field_h, field);
165
166 // scatter operation for each cell in workset
167 for(std::size_t worksetCellIndex=0;worksetCellIndex<localCellIds.size();++worksetCellIndex) {
168 std::size_t cellLocalId = localCellIds[worksetCellIndex];
169
170 auto LIDs = subRowIndexer->getElementLIDs(cellLocalId);
171 auto LIDs_h = Kokkos::create_mirror_view(LIDs);
172 Kokkos::deep_copy(LIDs_h, LIDs);
173
174 // loop over basis functions
175 for(std::size_t basis=0;basis<elmtOffset.size();basis++) {
176 int offset = elmtOffset[basis];
177 int lid = LIDs_h[offset];
178 local_r[lid] += field_h(worksetCellIndex,basis);
179 }
180 }
181 }
182}
183
184// **********************************************************************
185// Specialization: Tangent
186// **********************************************************************
187
188template<typename TRAITS,typename LO,typename GO>
190ScatterResidual_BlockedEpetra(const std::vector<Teuchos::RCP<const GlobalIndexer> > & rIndexers,
191 const std::vector<Teuchos::RCP<const GlobalIndexer> > & cIndexers,
192 const Teuchos::ParameterList& p,
193 bool /* useDiscreteAdjoint */)
194 : rowIndexers_(rIndexers)
195 , colIndexers_(cIndexers)
196 , globalDataKey_("Residual Scatter Container")
197{
198 std::string scatterName = p.get<std::string>("Scatter Name");
199 scatterHolder_ =
200 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
201
202 // get names to be evaluated
203 const std::vector<std::string>& names =
204 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
205
206 // grab map from evaluated names to field names
207 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
208
209 Teuchos::RCP<PHX::DataLayout> dl =
210 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
211
212 // build the vector of fields that this is dependent on
213 scatterFields_.resize(names.size());
214 for (std::size_t eq = 0; eq < names.size(); ++eq) {
215 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
216
217 // tell the field manager that we depend on this field
218 this->addDependentField(scatterFields_[eq]);
219 }
220
221 // this is what this evaluator provides
222 this->addEvaluatedField(*scatterHolder_);
223
224 if (p.isType<std::string>("Global Data Key"))
225 globalDataKey_ = p.get<std::string>("Global Data Key");
226
227 this->setName(scatterName+" Scatter Tangent");
228}
229
230// **********************************************************************
231template<typename TRAITS,typename LO,typename GO>
233postRegistrationSetup(typename TRAITS::SetupData /* d */,
235{
236 indexerIds_.resize(scatterFields_.size());
237 subFieldIds_.resize(scatterFields_.size());
238
239 // load required field numbers for fast use
240 for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
241 // get field ID from DOF manager
242 std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
243
244 indexerIds_[fd] = getFieldBlock(fieldName,rowIndexers_);
245 subFieldIds_[fd] = rowIndexers_[indexerIds_[fd]]->getFieldNum(fieldName);
246 }
247}
248
249// **********************************************************************
250template<typename TRAITS,typename LO,typename GO>
252preEvaluate(typename TRAITS::PreEvalData d)
253{
256
257 // extract linear object container
258 Teuchos::RCP<const BLOC> blockedContainer = Teuchos::rcp_dynamic_cast<const BLOC>(d.gedc->getDataObject(globalDataKey_));
259 Teuchos::RCP<const ELOC> epetraContainer = Teuchos::rcp_dynamic_cast<const ELOC>(d.gedc->getDataObject(globalDataKey_));
260
261 // if its blocked do this
262 if(blockedContainer!=Teuchos::null)
263 r_ = Teuchos::rcp_dynamic_cast<Thyra::ProductVectorBase<double> >(blockedContainer->get_f());
264 else if(epetraContainer!=Teuchos::null) // if its straight up epetra do this
265 r_ = Thyra::castOrCreateNonconstProductVectorBase<double>(epetraContainer->get_f_th());
266
267 TEUCHOS_ASSERT(r_!=Teuchos::null);
268}
269
270// **********************************************************************
271template<typename TRAITS,typename LO,typename GO>
273evaluateFields(typename TRAITS::EvalData workset)
274{
275 TEUCHOS_ASSERT(false);
276
277 using Teuchos::RCP;
278 using Teuchos::ptrFromRef;
279 using Teuchos::rcp_dynamic_cast;
280
281 using Thyra::VectorBase;
282 using Thyra::SpmdVectorBase;
284
285 // for convenience pull out some objects from workset
286 std::string blockId = this->wda(workset).block_id;
287 const std::vector<std::size_t> & localCellIds = this->wda(workset).cell_local_ids;
288
289 // NOTE: A reordering of these loops will likely improve performance
290 // The "getGIDFieldOffsets may be expensive. However the
291 // "getElementGIDs" can be cheaper. However the lookup for LIDs
292 // may be more expensive!
293
294 // loop over each field to be scattered
295 Teuchos::ArrayRCP<double> local_r;
296 for (std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
297 int indexerId = indexerIds_[fieldIndex];
298 int subFieldNum = subFieldIds_[fieldIndex];
299
300 // grab local data for inputing
301 rcp_dynamic_cast<SpmdVectorBase<double> >(r_->getNonconstVectorBlock(indexerId))->getNonconstLocalData(ptrFromRef(local_r));
302
303 auto subRowIndexer = rowIndexers_[indexerId];
304 const std::vector<int> & elmtOffset = subRowIndexer->getGIDFieldOffsets(blockId,subFieldNum);
305
306 // scatter operation for each cell in workset
307 for(std::size_t worksetCellIndex=0;worksetCellIndex<localCellIds.size();++worksetCellIndex) {
308 std::size_t cellLocalId = localCellIds[worksetCellIndex];
309
310 auto LIDs = subRowIndexer->getElementLIDs(cellLocalId);
311
312 // loop over basis functions
313 for(std::size_t basis=0;basis<elmtOffset.size();basis++) {
314 int offset = elmtOffset[basis];
315 int lid = LIDs[offset];
316 local_r[lid] += (scatterFields_[fieldIndex])(worksetCellIndex,basis).val();
317 }
318 }
319 }
320}
321
322// **********************************************************************
323// Specialization: Jacobian
324// **********************************************************************
325
326template<typename TRAITS,typename LO,typename GO>
328ScatterResidual_BlockedEpetra(const std::vector<Teuchos::RCP<const GlobalIndexer> > & rIndexers,
329 const std::vector<Teuchos::RCP<const GlobalIndexer> > & cIndexers,
330 const Teuchos::ParameterList& p,
331 bool useDiscreteAdjoint)
332 : rowIndexers_(rIndexers)
333 , colIndexers_(cIndexers)
334 , globalDataKey_("Residual Scatter Container")
335 , useDiscreteAdjoint_(useDiscreteAdjoint)
336{
337 std::string scatterName = p.get<std::string>("Scatter Name");
338 scatterHolder_ =
339 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
340
341 // get names to be evaluated
342 const std::vector<std::string>& names =
343 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
344
345 // grab map from evaluated names to field names
346 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
347
348 Teuchos::RCP<PHX::DataLayout> dl =
349 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
350
351 // build the vector of fields that this is dependent on
352 scatterFields_.resize(names.size());
353 for (std::size_t eq = 0; eq < names.size(); ++eq) {
354 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
355
356 // tell the field manager that we depend on this field
357 this->addDependentField(scatterFields_[eq]);
358 }
359
360 // this is what this evaluator provides
361 this->addEvaluatedField(*scatterHolder_);
362
363 if (p.isType<std::string>("Global Data Key"))
364 globalDataKey_ = p.get<std::string>("Global Data Key");
365 if (p.isType<bool>("Use Discrete Adjoint"))
366 useDiscreteAdjoint = p.get<bool>("Use Discrete Adjoint");
367
368 // discrete adjoint does not work with non-square matrices
369 if(useDiscreteAdjoint)
370 { TEUCHOS_ASSERT(colIndexers_.size()==0); }
371
372 if(colIndexers_.size()==0)
373 colIndexers_ = rowIndexers_;
374
375 this->setName(scatterName+" Scatter Residual BlockedEpetra (Jacobian)");
376}
377
378// **********************************************************************
379template<typename TRAITS,typename LO,typename GO>
381postRegistrationSetup(typename TRAITS::SetupData /* d */,
383{
384 indexerIds_.resize(scatterFields_.size());
385 subFieldIds_.resize(scatterFields_.size());
386
387 // load required field numbers for fast use
388 for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
389 // get field ID from DOF manager
390 std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
391
392 indexerIds_[fd] = getFieldBlock(fieldName,rowIndexers_);
393 subFieldIds_[fd] = rowIndexers_[indexerIds_[fd]]->getFieldNum(fieldName);
394 }
395}
396
397// **********************************************************************
398template<typename TRAITS,typename LO,typename GO>
400preEvaluate(typename TRAITS::PreEvalData d)
401{
402 using Teuchos::RCP;
403 using Teuchos::rcp_dynamic_cast;
404
407
408 // extract linear object container
409 RCP<const BLOC> blockedContainer = rcp_dynamic_cast<const BLOC>(d.gedc->getDataObject(globalDataKey_));
410 RCP<const ELOC> epetraContainer = rcp_dynamic_cast<const ELOC>(d.gedc->getDataObject(globalDataKey_));
411
412 // if its blocked do this
413 if(blockedContainer!=Teuchos::null) {
414 r_ = Teuchos::rcp_dynamic_cast<Thyra::ProductVectorBase<double> >(blockedContainer->get_f());
415 Jac_ = rcp_dynamic_cast<Thyra::BlockedLinearOpBase<double> >(blockedContainer->get_A());
416 }
417 else if(epetraContainer!=Teuchos::null) {
418 // if its straight up epetra do this
419 if(epetraContainer->get_f_th()!=Teuchos::null)
420 r_ = Thyra::castOrCreateNonconstProductVectorBase<double>(epetraContainer->get_f_th());
421
422 // convert it into a blocked operator
423 RCP<Thyra::LinearOpBase<double> > J = blockedContainer->get_A_th();
424 Jac_ = rcp_dynamic_cast<Thyra::BlockedLinearOpBase<double> >(Thyra::nonconstBlock1x1(J));
425 }
426
427 TEUCHOS_ASSERT(Jac_!=Teuchos::null);
428}
429
430// **********************************************************************
431template<typename TRAITS,typename LO,typename GO>
433evaluateFields(typename TRAITS::EvalData workset)
434{
435 using Teuchos::RCP;
436 using Teuchos::ArrayRCP;
437 using Teuchos::ptrFromRef;
438 using Teuchos::rcp_dynamic_cast;
439
440 using Thyra::VectorBase;
441 using Thyra::SpmdVectorBase;
444
445 std::vector<double> jacRow;
446
447 // for convenience pull out some objects from workset
448 std::string blockId = this->wda(workset).block_id;
449 const std::vector<std::size_t> & localCellIds = this->wda(workset).cell_local_ids;
450
451 int numFieldBlocks = Teuchos::as<int>(colIndexers_.size());
452
453 std::vector<int> blockOffsets;
454 computeBlockOffsets(blockId,colIndexers_,blockOffsets);
455
456 std::unordered_map<std::pair<int,int>,Teuchos::RCP<Epetra_CrsMatrix>,panzer::pair_hash> jacEpetraBlocks;
457
458 // loop over each field to be scattered
459 Teuchos::ArrayRCP<double> local_r;
460 for(std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
461 int rowIndexer = indexerIds_[fieldIndex];
462 int subFieldNum = subFieldIds_[fieldIndex];
463
464 // grab local data for inputing
465 if(r_!=Teuchos::null)
466 rcp_dynamic_cast<SpmdVectorBase<double> >(r_->getNonconstVectorBlock(rowIndexer))->getNonconstLocalData(ptrFromRef(local_r));
467
468 auto subRowIndexer = rowIndexers_[rowIndexer];
469 const std::vector<int> & elmtOffset = subRowIndexer->getGIDFieldOffsets(blockId,subFieldNum);
470
471 auto field = scatterFields_[fieldIndex].get_view();
472 auto field_h = Kokkos::create_mirror_view(field);
473 Kokkos::deep_copy(field_h, field);
474
475 auto rLIDs = subRowIndexer->getLIDs();
476 auto rLIDs_h = Kokkos::create_mirror_view(rLIDs);
477 Kokkos::deep_copy(rLIDs_h, rLIDs);
478
479 // scatter operation for each cell in workset
480 for(std::size_t worksetCellIndex=0;worksetCellIndex<localCellIds.size();++worksetCellIndex) {
481 std::size_t cellLocalId = localCellIds[worksetCellIndex];
482
483 // loop over the basis functions (currently they are nodes)
484 for(std::size_t rowBasisNum = 0; rowBasisNum < elmtOffset.size(); rowBasisNum++) {
485 const ScalarT scatterField = field_h(worksetCellIndex,rowBasisNum);
486 int rowOffset = elmtOffset[rowBasisNum];
487 int r_lid = rLIDs_h(cellLocalId, rowOffset);
488
489 // Sum residual
490 if(local_r!=Teuchos::null)
491 local_r[r_lid] += (scatterField.val());
492
493 // loop over the sensitivity indices: all DOFs on a cell
494 jacRow.resize(scatterField.size());
495
496 // For Neumann conditions with no dependence on degrees of freedom, there should be no Jacobian contribution
497 if(scatterField.size() == 0)
498 continue;
499
500 for(int sensIndex=0;sensIndex<scatterField.size();++sensIndex)
501 jacRow[sensIndex] = scatterField.fastAccessDx(sensIndex);
502
503 // scatter the row to each block
504 for(int colIndexer=0;colIndexer<numFieldBlocks;colIndexer++) {
505 int start = blockOffsets[colIndexer];
506 int end = blockOffsets[colIndexer+1];
507
508 if(end-start<=0)
509 continue;
510
511 auto subColIndexer = colIndexers_[colIndexer];
512 auto cLIDs = subColIndexer->getElementLIDs(cellLocalId);
513 auto cLIDs_h = Kokkos::create_mirror_view(cLIDs);
514 Kokkos::deep_copy(cLIDs_h, cLIDs);
515
516 TEUCHOS_ASSERT(end-start==Teuchos::as<int>(cLIDs.size()));
517
518 // check hash table for jacobian sub block
519 std::pair<int,int> blockIndex = useDiscreteAdjoint_ ? std::make_pair(colIndexer,rowIndexer)
520 : std::make_pair(rowIndexer,colIndexer);
521 Teuchos::RCP<Epetra_CrsMatrix> subJac = jacEpetraBlocks[blockIndex];
522
523 // if you didn't find one before, add it to the hash table
524 if(subJac==Teuchos::null) {
525 Teuchos::RCP<Thyra::LinearOpBase<double> > tOp = Jac_->getNonconstBlock(blockIndex.first,blockIndex.second);
526
527 // block operator is null, don't do anything (it is excluded)
528 if(Teuchos::is_null(tOp))
529 continue;
530
531 Teuchos::RCP<Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*tOp);
532 subJac = rcp_dynamic_cast<Epetra_CrsMatrix>(eOp,true);
533 jacEpetraBlocks[blockIndex] = subJac;
534 }
535
536 // Sum Jacobian
537 if(!useDiscreteAdjoint_) {
538 int err = subJac->SumIntoMyValues(r_lid, end-start, &jacRow[start],&cLIDs_h[0]);
539 if(err!=0) {
540
541 std::stringstream ss;
542 ss << "Failed inserting row: " << "LID = " << r_lid << "): ";
543 for(int i=start;i<end;i++)
544 ss << cLIDs_h[i] << " ";
545 ss << std::endl;
546 ss << "Into block " << rowIndexer << ", " << colIndexer << std::endl;
547
548 ss << "scatter field = ";
549 scatterFields_[fieldIndex].print(ss);
550 ss << std::endl;
551
552 TEUCHOS_TEST_FOR_EXCEPTION(err!=0,std::runtime_error,ss.str());
553 }
554 }
555 else {
556 for(std::size_t c=0;c<cLIDs.size();c++) {
557 int err = subJac->SumIntoMyValues(cLIDs_h[c], 1, &jacRow[start+c],&r_lid);
558 TEUCHOS_ASSERT_EQUALITY(err,0);
559 }
560 }
561 }
562 } // end rowBasisNum
563 } // end fieldIndex
564 }
565}
566
567// **********************************************************************
568
569#endif
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 d, PHX::FieldManager< TRAITS > &vm)
void computeBlockOffsets(const std::string &blockId, const std::vector< Teuchos::RCP< GlobalIndexer > > &ugis, std::vector< int > &blockOffsets)
int getFieldBlock(const std::string &fieldName, const std::vector< Teuchos::RCP< const GlobalIndexer > > &ugis)