Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
21 namespace panzer {
22 
23 // **************************************************************
24 // Hessian Specialization
25 // **************************************************************
26 template<typename TRAITS,typename LO,typename GO>
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_ =
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 
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 
83 template<typename TRAITS,typename LO,typename GO>
84 void
86 postRegistrationSetup(typename TRAITS::SetupData /* d */,
87  PHX::FieldManager<TRAITS>& /* fm */)
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 
106 template<typename TRAITS,typename LO,typename GO>
107 void
109 preEvaluate(typename TRAITS::PreEvalData d)
110 {
111  typedef BlockedEpetraLinearObjContainer BLOC;
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 
129 template<typename TRAITS,typename LO,typename GO>
130 void
132 evaluateFields(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
T & get(const std::string &name, T def_value)
bool is_null(const std::shared_ptr< T > &p)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
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 ExtractMyRowView(int MyRow, int &NumEntries, double *&Values, int *&Indices) const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
int getFieldBlock(const std::string &fieldName, const std::vector< Teuchos::RCP< const GlobalIndexer >> &ugis)
virtual void preEvaluate(typename Traits::PreEvalData d)=0
bool isType(const std::string &name) const
#define TEUCHOS_ASSERT(assertion_test)
int ReplaceMyValues(int MyRow, int NumEntries, const double *Values, const int *Indices)
TransListIter end