Panzer Version of the Day
Loading...
Searching...
No Matches
Panzer_ScatterResidual_BlockedEpetra_Hessian_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//
12#ifndef __Panzer_ScatterResidual_BlockedEpetra_Hessian_impl_hpp__
13#define __Panzer_ScatterResidual_BlockedEpetra_Hessian_impl_hpp__
14
15// only do this if required by the user
16#ifdef Panzer_BUILD_HESSIAN_SUPPORT
17
18// the includes for this file come in as a result of the includes in the main
19// Epetra scatter residual file
20
21namespace panzer {
22
23// **************************************************************
24// Hessian Specialization
25// **************************************************************
26template<typename TRAITS,typename LO,typename GO>
28ScatterResidual_BlockedEpetra(const std::vector<Teuchos::RCP<const GlobalIndexer<LO,int> > > & rIndexers,
29 const std::vector<Teuchos::RCP<const GlobalIndexer<LO,int> > > & cIndexers,
30 const Teuchos::ParameterList& p,
31 bool useDiscreteAdjoint)
32 : rowIndexers_(rIndexers)
33 , colIndexers_(cIndexers)
34 , globalDataKey_("Residual Scatter Container")
35 , useDiscreteAdjoint_(useDiscreteAdjoint)
36{
37 std::string scatterName = p.get<std::string>("Scatter Name");
38 scatterHolder_ =
39 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
40
41 // get names to be evaluated
42 const std::vector<std::string>& names =
43 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
44
45 // grab map from evaluated names to field names
46 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
47
48 Teuchos::RCP<PHX::DataLayout> dl =
49 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional;
50
51 // build the vector of fields that this is dependent on
52 scatterFields_.resize(names.size());
53 for (std::size_t eq = 0; eq < names.size(); ++eq) {
54 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
55
56 // tell the field manager that we depend on this field
57 this->addDependentField(scatterFields_[eq]);
58 }
59
60 // this is what this evaluator provides
61 this->addEvaluatedField(*scatterHolder_);
62
63 if (p.isType<std::string>("Global Data Key"))
64 globalDataKey_ = p.get<std::string>("Global Data Key");
65 if (p.isType<bool>("Use Discrete Adjoint"))
66 useDiscreteAdjoint = p.get<bool>("Use Discrete Adjoint");
67
68 // discrete adjoint does not work with non-square matrices
69 if(useDiscreteAdjoint)
70 { TEUCHOS_ASSERT(colIndexers_.size()==0); }
71
72 if(colIndexers_.size()==0)
73 colIndexers_ = rowIndexers_;
74
75 this->setName(scatterName+" Scatter Residual BlockedEpetra (Hessian)");
76}
77
78template<typename TRAITS,typename LO,typename GO>
79void
81postRegistrationSetup(typename TRAITS::SetupData /* d */,
83{
84 indexerIds_.resize(scatterFields_.size());
85 subFieldIds_.resize(scatterFields_.size());
86
87 // load required field numbers for fast use
88 for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
89 // get field ID from DOF manager
90 std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
91
92 indexerIds_[fd] = getFieldBlock(fieldName,rowIndexers_);
93 subFieldIds_[fd] = rowIndexers_[indexerIds_[fd]]->getFieldNum(fieldName);
94 }
95}
96
97template<typename TRAITS,typename LO,typename GO>
98void
100preEvaluate(typename TRAITS::PreEvalData d)
101{
102 using Teuchos::RCP;
103 using Teuchos::rcp_dynamic_cast;
104
107
108 // extract linear object container
109 RCP<const BLOC> blockedContainer = rcp_dynamic_cast<const BLOC>(d.gedc->getDataObject(globalDataKey_));
110 RCP<const ELOC> epetraContainer = rcp_dynamic_cast<const ELOC>(d.gedc->getDataObject(globalDataKey_));
111
112 // if its blocked do this
113 if(blockedContainer!=Teuchos::null) {
114 Jac_ = rcp_dynamic_cast<Thyra::BlockedLinearOpBase<double> >(blockedContainer->get_A());
115 }
116 else if(epetraContainer!=Teuchos::null) {
117 // convert it into a blocked operator
118 RCP<Thyra::LinearOpBase<double> > J = blockedContainer->get_A_th();
119 Jac_ = rcp_dynamic_cast<Thyra::BlockedLinearOpBase<double> >(Thyra::nonconstBlock1x1(J));
120 }
121
122 TEUCHOS_ASSERT(Jac_!=Teuchos::null);
123}
124
125template<typename TRAITS,typename LO,typename GO>
126void
128evaluateFields(typename TRAITS::EvalData workset)
129{
130 using Teuchos::RCP;
131 using Teuchos::ArrayRCP;
132 using Teuchos::ptrFromRef;
133 using Teuchos::rcp_dynamic_cast;
134
135 using Thyra::VectorBase;
136 using Thyra::SpmdVectorBase;
139
140 std::vector<double> jacRow;
141
142 // for convenience pull out some objects from workset
143 std::string blockId = this->wda(workset).block_id;
144 const std::vector<std::size_t> & localCellIds = this->wda(workset).cell_local_ids;
145
146 int numFieldBlocks = Teuchos::as<int>(colIndexers_.size());
147
148 std::vector<int> blockOffsets;
149 computeBlockOffsets(blockId,colIndexers_,blockOffsets);
150
151 std::unordered_map<std::pair<int,int>,Teuchos::RCP<Epetra_CrsMatrix>,panzer::pair_hash> jacEpetraBlocks;
152
153 // loop over each field to be scattered
154 for(std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
155 int rowIndexer = indexerIds_[fieldIndex];
156 int subFieldNum = subFieldIds_[fieldIndex];
157
158 auto subRowIndexer = rowIndexers_[rowIndexer];
159 const std::vector<int> & elmtOffset = subRowIndexer->getGIDFieldOffsets(blockId,subFieldNum);
160
161 // scatter operation for each cell in workset
162 for(std::size_t worksetCellIndex=0;worksetCellIndex<localCellIds.size();++worksetCellIndex) {
163 std::size_t cellLocalId = localCellIds[worksetCellIndex];
164
165 auto rLIDs = subRowIndexer->getElementLIDs(cellLocalId);
166
167 // loop over the basis functions (currently they are nodes)
168 for(std::size_t rowBasisNum = 0; rowBasisNum < elmtOffset.size(); rowBasisNum++) {
169 const ScalarT scatterField = (scatterFields_[fieldIndex])(worksetCellIndex,rowBasisNum);
170 int rowOffset = elmtOffset[rowBasisNum];
171 int r_lid = rLIDs[rowOffset];
172
173 // loop over the sensitivity indices: all DOFs on a cell
174 jacRow.resize(scatterField.size());
175
176 // For Neumann conditions with no dependence on degrees of freedom, there should be no Jacobian contribution
177 if(scatterField.size() == 0)
178 continue;
179
180 for(int sensIndex=0;sensIndex<scatterField.size();++sensIndex)
181 jacRow[sensIndex] = scatterField.fastAccessDx(sensIndex).fastAccessDx(0);
182
183 // scatter the row to each block
184 for(int colIndexer=0;colIndexer<numFieldBlocks;colIndexer++) {
185 int start = blockOffsets[colIndexer];
186 int end = blockOffsets[colIndexer+1];
187
188 if(end-start<=0)
189 continue;
190
191 auto subColIndexer = colIndexers_[colIndexer];
192 auto cLIDs = subColIndexer->getElementLIDs(cellLocalId);
193
194 TEUCHOS_ASSERT(end-start==Teuchos::as<int>(cLIDs.size()));
195
196 // check hash table for jacobian sub block
197 std::pair<int,int> blockIndex = std::make_pair(rowIndexer,colIndexer);
198 Teuchos::RCP<Epetra_CrsMatrix> subJac = jacEpetraBlocks[blockIndex];
199
200 // if you didn't find one before, add it to the hash table
201 if(subJac==Teuchos::null) {
202 Teuchos::RCP<Thyra::LinearOpBase<double> > tOp = Jac_->getNonconstBlock(blockIndex.first,blockIndex.second);
203
204 // block operator is null, don't do anything (it is excluded)
205 if(Teuchos::is_null(tOp))
206 continue;
207
208 Teuchos::RCP<Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*tOp);
209 subJac = rcp_dynamic_cast<Epetra_CrsMatrix>(eOp,true);
210 jacEpetraBlocks[blockIndex] = subJac;
211 }
212
213 // Sum Jacobian
214 {
215 int err = subJac->SumIntoMyValues(r_lid, end-start, &jacRow[start],&cLIDs[0]);
216 if(err!=0) {
217
218 std::stringstream ss;
219 ss << "Failed inserting row: " << "LID = " << r_lid << ": ";
220 for(int i=0;i<end-start;i++)
221 ss << cLIDs[i] << " ";
222 ss << std::endl;
223 ss << "Into block " << rowIndexer << ", " << colIndexer << std::endl;
224
225 ss << "scatter field = ";
226 scatterFields_[fieldIndex].print(ss);
227 ss << std::endl;
228
229 ss << "values = ";
230 for(int i=start;i<end;i++)
231 ss << jacRow[i] << " ";
232 ss << std::endl;
233
234 std::cout << ss.str() << std::endl;
235
236 TEUCHOS_TEST_FOR_EXCEPTION(err!=0,std::runtime_error,ss.str());
237 }
238 }
239 }
240 } // end rowBasisNum
241 } // end fieldIndex
242 }
243}
244
245}
246
247// **************************************************************
248#endif
249
250#endif
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)