Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
21 namespace panzer {
22 
23 // **************************************************************
24 // Hessian Specialization
25 // **************************************************************
26 template<typename TRAITS,typename LO,typename GO>
28 ScatterResidual_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_ =
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 
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 
78 template<typename TRAITS,typename LO,typename GO>
79 void
81 postRegistrationSetup(typename TRAITS::SetupData /* d */,
82  PHX::FieldManager<TRAITS>& /* fm */)
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 
97 template<typename TRAITS,typename LO,typename GO>
98 void
100 preEvaluate(typename TRAITS::PreEvalData d)
101 {
102  using Teuchos::RCP;
103  using Teuchos::rcp_dynamic_cast;
104 
105  typedef BlockedEpetraLinearObjContainer BLOC;
106  typedef BlockedEpetraLinearObjContainer ELOC;
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 
125 template<typename TRAITS,typename LO,typename GO>
126 void
128 evaluateFields(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
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 computeBlockOffsets(const std::string &blockId, const std::vector< Teuchos::RCP< GlobalIndexer >> &ugis, std::vector< int > &blockOffsets)
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)
int SumIntoMyValues(int MyRow, int NumEntries, const double *Values, const int *Indices)
virtual void preEvaluate(typename Traits::PreEvalData d)=0
void postRegistrationSetup(typename TRAITS::SetupData d, PHX::FieldManager< TRAITS > &vm)
bool isType(const std::string &name) const
#define TEUCHOS_ASSERT(assertion_test)
TransListIter end