Panzer Version of the Day
Loading...
Searching...
No Matches
Panzer_ScatterDirichletResidual_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#ifndef __Panzer_ScatterDirichletResidual_BlockedEpetra_Hessian_impl_hpp__
12#define __Panzer_ScatterDirichletResidual_BlockedEpetra_Hessian_impl_hpp__
13
14// only do this if required by the user
15#ifdef Panzer_BUILD_HESSIAN_SUPPORT
16
17// the includes for this file come in as a result of the includes in the main
18// blocked Epetra scatter dirichlet residual file
19
20
21namespace panzer {
22
23// **************************************************************
24// Hessian Specialization
25// **************************************************************
26template<typename TRAITS,typename LO,typename GO>
28ScatterDirichletResidual_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{
36 std::string scatterName = p.get<std::string>("Scatter Name");
37 scatterHolder_ =
38 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
39
40 // get names to be evaluated
41 const std::vector<std::string>& names =
42 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
43
44 // grab map from evaluated names to field names
45 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
46
47 Teuchos::RCP<PHX::DataLayout> dl =
48 p.get< Teuchos::RCP<panzer::PureBasis> >("Basis")->functional;
49
50 side_subcell_dim_ = p.get<int>("Side Subcell Dimension");
51 local_side_id_ = p.get<int>("Local Side ID");
52
53 // build the vector of fields that this is dependent on
54 scatterFields_.resize(names.size());
55 for (std::size_t eq = 0; eq < names.size(); ++eq) {
56 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
57
58 // tell the field manager that we depend on this field
59 this->addDependentField(scatterFields_[eq]);
60 }
61
62 checkApplyBC_ = p.get<bool>("Check Apply BC");
63 if (checkApplyBC_) {
64 applyBC_.resize(names.size());
65 for (std::size_t eq = 0; eq < names.size(); ++eq) {
66 applyBC_[eq] = PHX::MDField<const bool,Cell,NODE>(std::string("APPLY_BC_")+fieldMap_->find(names[eq])->second,dl);
67 this->addDependentField(applyBC_[eq]);
68 }
69 }
70
71 // this is what this evaluator provides
72 this->addEvaluatedField(*scatterHolder_);
73
74 if (p.isType<std::string>("Global Data Key"))
75 globalDataKey_ = p.get<std::string>("Global Data Key");
76
77 if(colIndexers_.size()==0)
78 colIndexers_ = rowIndexers_;
79
80 this->setName(scatterName+" Scatter Dirichlet Residual : BlockedEpetra (Hessian)");
81}
82
83template<typename TRAITS,typename LO,typename GO>
84void
86postRegistrationSetup(typename TRAITS::SetupData /* d */,
88{
89 indexerIds_.resize(scatterFields_.size());
90 subFieldIds_.resize(scatterFields_.size());
91
92 // load required field numbers for fast use
93 for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
94 // get field ID from DOF manager
95 std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
96
97 indexerIds_[fd] = getFieldBlock(fieldName,rowIndexers_);
98 subFieldIds_[fd] = rowIndexers_[indexerIds_[fd]]->getFieldNum(fieldName);
99 }
100
101 // get the number of nodes (Should be renamed basis)
102 num_nodes = scatterFields_[0].extent(1);
103 num_eq = scatterFields_.size();
104}
105
106template<typename TRAITS,typename LO,typename GO>
107void
109preEvaluate(typename TRAITS::PreEvalData d)
110{
112
113 using Teuchos::rcp_dynamic_cast;
114
115 // extract dirichlet counter from container
116 Teuchos::RCP<const BLOC> blockContainer
117 = rcp_dynamic_cast<const BLOC>(d.gedc->getDataObject("Dirichlet Counter"),true);
118
119 dirichletCounter_ = rcp_dynamic_cast<Thyra::ProductVectorBase<double> >(blockContainer->get_f(),true);
120 TEUCHOS_ASSERT(!Teuchos::is_null(dirichletCounter_));
121
122 // extract linear object container
123 blockContainer = rcp_dynamic_cast<const BLOC>(d.gedc->getDataObject(globalDataKey_),true);
124 TEUCHOS_ASSERT(!Teuchos::is_null(blockContainer));
125
126 Jac_ = rcp_dynamic_cast<Thyra::BlockedLinearOpBase<double> >(blockContainer->get_A());
127}
128
129template<typename TRAITS,typename LO,typename GO>
130void
132evaluateFields(typename TRAITS::EvalData workset)
133{
134 using Teuchos::RCP;
135 using Teuchos::ArrayRCP;
136 using Teuchos::ptrFromRef;
137 using Teuchos::rcp_dynamic_cast;
138
139 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 int numFieldBlocks = Teuchos::as<int>(colIndexers_.size());
146
147 std::vector<int> blockOffsets;
148 computeBlockOffsets(blockId,colIndexers_,blockOffsets);
149
150 std::unordered_map<std::pair<int,int>,Teuchos::RCP<Epetra_CrsMatrix>,panzer::pair_hash> jacEpetraBlocks;
151
152 // NOTE: A reordering of these loops will likely improve performance
153 // The "getGIDFieldOffsets may be expensive. However the
154 // "getElementGIDs" can be cheaper. However the lookup for LIDs
155 // may be more expensive!
156
157 for(std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
158 int rowIndexer = indexerIds_[fieldIndex];
159 int subFieldNum = subFieldIds_[fieldIndex];
160
161 // loop over each field to be scattered
162 Teuchos::ArrayRCP<double> local_dc;
163 rcp_dynamic_cast<SpmdVectorBase<double> >(dirichletCounter_->getNonconstVectorBlock(rowIndexer))
164 ->getNonconstLocalData(ptrFromRef(local_dc));
165
166 auto subRowIndexer = rowIndexers_[rowIndexer];
167 auto subIndicePair = subRowIndexer->getGIDFieldOffsets_closure(blockId,subFieldNum, side_subcell_dim_, local_side_id_);
168 const std::vector<int> & subElmtOffset = subIndicePair.first;
169 const std::vector<int> & subBasisIdMap = subIndicePair.second;
170
171 // scatter operation for each cell in workset
172 for(std::size_t worksetCellIndex=0;worksetCellIndex<localCellIds.size();++worksetCellIndex) {
173 std::size_t cellLocalId = localCellIds[worksetCellIndex];
174
175 auto rLIDs = subRowIndexer->getElementLIDs(cellLocalId);
176
177 // loop over basis functions
178 for(std::size_t basis=0;basis<subElmtOffset.size();basis++) {
179 int offset = subElmtOffset[basis];
180 int lid = rLIDs[offset];
181 if(lid<0) // not on this processor
182 continue;
183
184 int basisId = subBasisIdMap[basis];
185
186 if (checkApplyBC_)
187 if (!applyBC_[fieldIndex](worksetCellIndex,basisId))
188 continue;
189
190 // zero out matrix row
191 for(int colIndexer=0;colIndexer<numFieldBlocks;colIndexer++) {
192 int start = blockOffsets[colIndexer];
193 int end = blockOffsets[colIndexer+1];
194
195 if(end-start<=0)
196 continue;
197
198 // check hash table for jacobian sub block
199 std::pair<int,int> blockIndex = std::make_pair(rowIndexer,colIndexer);
200 Teuchos::RCP<Epetra_CrsMatrix> subJac = jacEpetraBlocks[blockIndex];
201 // if you didn't find one before, add it to the hash table
202 if(subJac==Teuchos::null) {
203 Teuchos::RCP<Thyra::LinearOpBase<double> > tOp = Jac_->getNonconstBlock(blockIndex.first,blockIndex.second);
204
205 // block operator is null, don't do anything (it is excluded)
206 if(Teuchos::is_null(tOp))
207 continue;
208
209 Teuchos::RCP<Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*tOp);
210 subJac = rcp_dynamic_cast<Epetra_CrsMatrix>(eOp,true);
211 jacEpetraBlocks[blockIndex] = subJac;
212 }
213
214 int numEntries = 0;
215 int * rowIndices = 0;
216 double * rowValues = 0;
217
218 subJac->ExtractMyRowView(lid,numEntries,rowValues,rowIndices);
219
220 for(int i=0;i<numEntries;i++)
221 rowValues[i] = 0.0;
222 }
223
224 const ScalarT scatterField = (scatterFields_[fieldIndex])(worksetCellIndex,basisId);
225
226 local_dc[lid] = 1.0; // mark row as dirichlet
227
228 // loop over the sensitivity indices: all DOFs on a cell
229 std::vector<double> jacRow(scatterField.size(),0.0);
230
231 for(int sensIndex=0;sensIndex<scatterField.size();++sensIndex)
232 jacRow[sensIndex] = scatterField.fastAccessDx(sensIndex).fastAccessDx(0);
233
234 for(int colIndexer=0;colIndexer<numFieldBlocks;colIndexer++) {
235 int start = blockOffsets[colIndexer];
236 int end = blockOffsets[colIndexer+1];
237
238 if(end-start<=0)
239 continue;
240
241 auto subColIndexer = colIndexers_[colIndexer];
242 auto cLIDs = subColIndexer->getElementLIDs(cellLocalId);
243
244 TEUCHOS_ASSERT(end-start==Teuchos::as<int>(cLIDs.size()));
245
246 // check hash table for jacobian sub block
247 std::pair<int,int> blockIndex = std::make_pair(rowIndexer,colIndexer);
248 Teuchos::RCP<Epetra_CrsMatrix> subJac = jacEpetraBlocks[blockIndex];
249
250 // if you didn't find one before, add it to the hash table
251 if(subJac==Teuchos::null) {
252 Teuchos::RCP<Thyra::LinearOpBase<double> > tOp = Jac_->getNonconstBlock(blockIndex.first,blockIndex.second);
253
254 // block operator is null, don't do anything (it is excluded)
255 if(Teuchos::is_null(tOp))
256 continue;
257
258 Teuchos::RCP<Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*tOp);
259 subJac = rcp_dynamic_cast<Epetra_CrsMatrix>(eOp,true);
260 jacEpetraBlocks[blockIndex] = subJac;
261 }
262
263 // Sum Jacobian
264 int err = subJac->ReplaceMyValues(lid, end-start, &jacRow[start],&cLIDs[0]);
265 if(err!=0) {
266 std::stringstream ss;
267 ss << "Failed inserting row: " << " (" << lid << "): ";
268 for(int i=0;i<end-start;i++)
269 ss << cLIDs[i] << " ";
270 ss << std::endl;
271 ss << "Into block " << rowIndexer << ", " << colIndexer << std::endl;
272
273 ss << "scatter field = ";
274 scatterFields_[fieldIndex].print(ss);
275 ss << std::endl;
276
277 TEUCHOS_TEST_FOR_EXCEPTION(err!=0,std::runtime_error,ss.str());
278 }
279
280 }
281 }
282 }
283 }
284}
285
286}
287
288// **************************************************************
289#endif
290
291#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)