Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_WorksetContainer.cpp
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 
12 
14 
18 #include "Panzer_Dimension.hpp"
19 
20 namespace panzer {
21 
24  : worksetSize_(1)
25 {}
27  const std::map<std::string,WorksetNeeds> & needs)
28  : wkstFactory_(factory), worksetSize_(0)
29 {
30  // thats all!
31  ebToNeeds_ = needs;
32 }
33 
38  : wkstFactory_(wc.wkstFactory_)
39  , worksetSize_(wc.worksetSize_)
40 {
41 }
42 
47 {
48  this->clearVolumeWorksets();
49  this->clearSideWorksets();
50 }
51 
53 {
54  worksets_.clear();
55 }
56 
58 {
59  sideWorksets_.clear();
60 }
61 
63 setNeeds(const std::string & eBlock,const WorksetNeeds & needs)
64 {
65  clear(); // clear out old worksets
66  ebToNeeds_[eBlock] = needs;
67 }
68 
70 const WorksetNeeds & WorksetContainer::lookupNeeds(const std::string & eBlock) const
71 {
72  std::map<std::string,WorksetNeeds>::const_iterator itr = ebToNeeds_.find(eBlock);
73 
74  TEUCHOS_TEST_FOR_EXCEPTION(itr==ebToNeeds_.end(),std::logic_error,
75  "WorksetContainer::lookupNeeds no WorksetNeeds object is associated "
76  "with the element block \""+eBlock+"\".");
77 
78  return itr->second;
79 }
80 
83 {
84  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::WorksetContainer::getWorksets()",pwkst_con_get_worksets);
85 
86  Teuchos::RCP<std::vector<Workset> > worksetVector;
87  WorksetMap::iterator itr = worksets_.find(wd);
88  if(itr==worksets_.end()) {
89  // couldn't find workset, build it!
90  WorksetNeeds needs;
91  if(hasNeeds())
92  needs = lookupNeeds(wd.getElementBlock());
93  worksetVector = wkstFactory_->getWorksets(wd,needs);
94 
95  // apply orientations to the just constructed worksets
96  if(worksetVector!=Teuchos::null && wd.applyOrientations()) {
97  applyOrientations(wd.getElementBlock(),*worksetVector);
98  }
99 
100  if(worksetVector!=Teuchos::null)
101  setIdentifiers(wd,*worksetVector);
102 
103  // store vector for reuse in the future
104  worksets_[wd] = worksetVector;
105  }
106  else
107  worksetVector = itr->second;
108 
109  return worksetVector;
110 }
111 
115 {
116  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::WorksetContainer::getSideWorksets()",pwkst_con_get_side_worksets);
117 
119 
120  // this is the key for the workset map
121  SideMap::iterator itr = sideWorksets_.find(desc);
122 
123  if(itr==sideWorksets_.end()) {
124  // couldn't find workset, build it!
125  if (desc.connectsElementBlocks()) {
126  worksetMap = wkstFactory_->getSideWorksets(desc, lookupNeeds(desc.getElementBlock(0)),
127  lookupNeeds(desc.getElementBlock(1)));
128  }
129  else {
130  worksetMap = wkstFactory_->getSideWorksets(desc,lookupNeeds(desc.getElementBlock(0)));
131  }
132 
133  // apply orientations to the worksets for this side
134  if(worksetMap!=Teuchos::null)
135  applyOrientations(desc,*worksetMap);
136 
137  if(worksetMap!=Teuchos::null)
138  setIdentifiers(desc,*worksetMap);
139 
140  // store map for reuse in the future
141  sideWorksets_[desc] = worksetMap;
142  }
143  else {
144  worksetMap = itr->second;
145  }
146 
147  return worksetMap;
148 }
149 
150 
153 {
154  // apply the orientations for stored worksets
155  applyOrientations(ugi);
156 }
157 
159 addBasis(const std::string & type,int order,const std::string & rep_field)
160 {
161  using Teuchos::RCP;
162  using Teuchos::rcp;
163 
164  for(auto itr=ebToNeeds_.begin();itr!=ebToNeeds_.end();++itr) {
165  WorksetNeeds & needs = itr->second;
166  RCP<PureBasis> basis = rcp(new PureBasis(type,order,needs.cellData));
167 
168  // add in the new basis
169  needs.bases.push_back(basis);
170  needs.rep_field_name.push_back(rep_field);
171  }
172 
173  // clear all arrays, lazy evaluation means it will be rebuilt
174  clear();
175 }
176 
179 {
180  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::WorksetContainer::applyOrientations(ugi)",pwkst_con_apply_orts);
181 
182  // this gurantees orientations won't accidently be applied twice.
183  TEUCHOS_ASSERT(globalIndexer_==Teuchos::null);
184 
185  globalIndexer_ = ugi;
186 
187  // this should be created once and stored in an appropriate place
188  TEUCHOS_TEST_FOR_EXCEPTION(globalIndexer_ == Teuchos::null, std::logic_error,
189  "global indexer is not set yet");
191 
192  // loop over volume worksets, apply orientations to each
193  for(WorksetMap::iterator itr=worksets_.begin();
194  itr!=worksets_.end();++itr) {
195  std::string eBlock = itr->first.getElementBlock();
196 
197  applyOrientations(eBlock,*itr->second);
198  }
199 
200  // loop over side worksets, apply orientations to each
201  for(SideMap::iterator itr=sideWorksets_.begin();
202  itr!=sideWorksets_.end();itr++) {
203 
204  applyOrientations(itr->first,*itr->second);
205  }
206 }
207 
209 setIdentifiers(const WorksetDescriptor & wd,std::vector<Workset> & worksets)
210 {
211  std::size_t hash = std::hash<WorksetDescriptor>()(wd); // this is really ugly, is this really a C++ standard?
212  for(std::size_t i=0;i<worksets.size();i++)
213  worksets[i].setIdentifier(hash+i);
214 }
215 
217 setIdentifiers(const WorksetDescriptor & wd,std::map<unsigned,Workset> & workset_map)
218 {
219  std::size_t hash = std::hash<WorksetDescriptor>()(wd); // this is really ugly, is this really a C++ standard?
220  std::size_t offset = 0;
221  for(auto itr : workset_map) {
222  // itr.second.setIdentifier(hash+offset);
223  workset_map[itr.first].setIdentifier(hash+offset);
224 
225  offset++;
226  }
227 }
228 
230 applyOrientations(const std::string & eBlock, std::vector<Workset> & worksets) const
231 {
232  using Teuchos::RCP;
233 
234  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::WorksetContainer::applyOrientations(eBlock,worksets)",pwkst_con_apply_orts_eb_w);
235 
237  // this is for volume worksets //
239 
240  // short circuit if no global indexer exists
241  if((globalIndexer_==Teuchos::null) and (wkstFactory_->getOrientationsInterface() == Teuchos::null)) {
242  Teuchos::FancyOStream fout(Teuchos::rcpFromRef(std::cout));
243  fout.setOutputToRootOnly(0);
244 
245  fout << "Panzer Warning: No global indexer assigned to a workset container or factory. "
246  << "Orientation of the basis for edge basis functions cannot be applied, "
247  << "if those basis functions are used, there will be problems!" << std::endl;
248  return;
249  }
250 
251  // this should be matched to global indexer size (not sure how to retrive it)
252  if(globalIndexer_!=Teuchos::null){
253  TEUCHOS_TEST_FOR_EXCEPTION(orientations_ == Teuchos::null, std::logic_error,
254  "intrepid2 orientation is not constructed");
255  }
256 
257  // loop over each basis requiring orientations, then apply them
259 
260  // Note: It may be faster to loop over the basis pairs on the inside (not really sure)
261 
262  WorksetNeeds needs;
263  if(hasNeeds())
264  needs = lookupNeeds(eBlock);
265 
266  if(needs.bases.size()>0) {
267  // sanity check that we aren't missing something (the old and new "needs" should not be used together)
268  TEUCHOS_ASSERT(needs.getBases().size()==0);
269 
270  for(std::size_t w=0;w<needs.bases.size();w++) {
271  const PureBasis & basis = *needs.bases[w];
272 
273  // no need for this if orientations are not required!
274  if(!basis.requiresOrientations())
275  continue;
276 
277  // build accessors for orientation fields
278  std::vector<Intrepid2::Orientation> ortsPerBlock;
279 
280  // loop over worksets compute and apply orientations
281  for(std::size_t i=0;i<worksets.size();i++) {
282  // break out of the workset loop
283  if(worksets[i].num_cells<=0) continue;
284 
285  for(std::size_t j=0;j<worksets[i].numDetails();j++) {
286  WorksetDetails & details = worksets[i](j);
287 
288  ortsPerBlock.clear();
289  for (int k=0;k<worksets[i].num_cells;++k) {
290  ortsPerBlock.push_back((*orientations_)[details.cell_local_ids[k]]);
291  }
292 
293  for(std::size_t basis_index=0;basis_index<details.bases.size();basis_index++) {
294  Teuchos::RCP<const BasisIRLayout> layout = details.bases[basis_index]->basis_layout;
295 
296  // only apply orientations if its relevant to the current needs
297  if(layout->getBasis()->name()!=basis.name())
298  continue;
299 
300  TEUCHOS_ASSERT(layout!=Teuchos::null);
301  TEUCHOS_ASSERT(layout->getBasis()!=Teuchos::null);
302  if(layout->getBasis()->requiresOrientations()) {
303  // apply orientations for this basis
304  auto & bv = *details.bases[basis_index];
305  if(not bv.orientationsApplied())
306  bv.applyOrientations(ortsPerBlock,(int) worksets[i].num_cells);
307  }
308  }
309  }
310  }
311  } // end for w
312  }
313  else if(needs.getBases().size()>0) {
314  // sanity check that we aren't missing something (the old and new "needs" should not be used together)
315  TEUCHOS_ASSERT(needs.bases.size()==0);
316 
317  // This is for forwards compatibility, the needs now use "getBasis" calls as opposed
318  // to director accessors.
319  for(const auto & bd : needs.getBases()) {
320 
321  // build accessors for orientation fields
322  std::vector<Intrepid2::Orientation> ortsPerBlock;
323 
324  // loop over worksets compute and apply orientations
325  for(std::size_t i=0;i<worksets.size();i++) {
326  // break out of the workset loop
327  if(worksets[i].num_cells<=0) continue;
328 
329  for(std::size_t j=0;j<worksets[i].numDetails();j++) {
330  WorksetDetails & details = worksets[i](j);
331 
332  ortsPerBlock.clear();
333  // for (int k=0;k<worksets[i].num_cells;++k) {
334  for (int k=0;k<details.numOwnedCells();++k) {
335  ortsPerBlock.push_back((*orientations_)[details.cell_local_ids[k]]);
336  }
337 
338  for(const auto & id : needs.getIntegrators()) {
339  // apply orientations for this basis
340  auto & bv = details.getBasisValues(bd,id);
341  if(not bv.orientationsApplied())
342  bv.applyOrientations(ortsPerBlock,(int) worksets[i].num_cells);
343  }
344  }
345  }
346  } // end for w
347  }
348 }
349 
350 
352 applyOrientations(const WorksetDescriptor & desc,std::map<unsigned,Workset> & worksets) const
353 {
354  using Teuchos::RCP;
355 
356  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::WorksetContainer::applyOrientations(wd,worksets)",pwkst_con_apply_orts_wd_wksts);
357 
359  // this is for side worksets //
361 
362  // short circuit if no global indexer exists
363  if((globalIndexer_==Teuchos::null) and (wkstFactory_->getOrientationsInterface() == Teuchos::null)) {
364  Teuchos::FancyOStream fout(Teuchos::rcpFromRef(std::cout));
365  fout.setOutputToRootOnly(0);
366 
367  fout << "Panzer Warning: No global indexer assigned to a workset container or factory. "
368  << "Orientation of the basis for edge basis functions cannot be applied, "
369  << "if those basis functions are used, there will be problems!";
370  return;
371  }
372 
373  // loop over each basis requiring orientations, then apply them
375 
376  // Note: It may be faster to loop over the basis pairs on the inside (not really sure)
377  WorksetNeeds needs;
378  if(hasNeeds())
379  needs = lookupNeeds(desc.getElementBlock());
380 
381  if(needs.bases.size()>0) {
382  // sanity check that we aren't missing something (the old and new "needs" should not be used together)
383  TEUCHOS_ASSERT(needs.getBases().size()==0);
384  for(std::size_t i=0;i<needs.bases.size();i++) {
385  const PureBasis & basis = *needs.bases[i];
386 
387  // no need for this if orientations are not required!
388  if(!basis.requiresOrientations()) continue;
389 
390  // build accessors for orientation fields
391  std::vector<Intrepid2::Orientation> ortsPerBlock;
392 
393  // loop over worksets compute and apply orientations
394  for(std::map<unsigned,Workset>::iterator itr=worksets.begin();
395  itr!=worksets.end();++itr) {
396 
397  // break out of the workset loop
398  if(itr->second.num_cells<=0) continue;
399 
400  for(std::size_t j=0;j<itr->second.numDetails();j++) {
401  WorksetDetails & details = itr->second(j);
402 
403  ortsPerBlock.clear();
404  for (int k=0;k<itr->second.num_cells;++k) {
405  ortsPerBlock.push_back((*orientations_)[details.cell_local_ids[k]]);
406  }
407 
408  for(std::size_t basis_index=0;basis_index<details.bases.size();basis_index++) {
409  Teuchos::RCP<const BasisIRLayout> layout = details.bases[basis_index]->basis_layout;
410 
411  // only apply orientations if its relevant to the current needs
412  if(layout->getBasis()->name()!=basis.name())
413  continue;
414 
415  TEUCHOS_ASSERT(layout!=Teuchos::null);
416  TEUCHOS_ASSERT(layout->getBasis()!=Teuchos::null);
417  if(layout->getBasis()->requiresOrientations()) {
418  // apply orientations for this basis
419  auto & bv = *details.bases[basis_index];
420  if(not bv.orientationsApplied())
421  bv.applyOrientations(ortsPerBlock,(int) itr->second.num_cells);
422  }
423  }
424  }
425  }
426  } // end for i
427  }
428  else if(needs.getBases().size()>0) {
429  // sanity check that we aren't missing something (the old and new "needs" should not be used together)
430  TEUCHOS_ASSERT(needs.bases.size()==0);
431 
432  // This is for forwards compatibility, the needs now use "getBasis" calls as opposed
433  // to director accessors.
434  for(const auto & bd : needs.getBases()) {
435 
436  // build accessors for orientation fields
437  std::vector<Intrepid2::Orientation> ortsPerBlock;
438 
439  // loop over worksets compute and apply orientations
440  for(std::map<unsigned,Workset>::iterator itr=worksets.begin();
441  itr!=worksets.end();++itr) {
442 
443  // break out of the workset loop
444  if(itr->second.num_cells<=0) continue;
445 
446  for(std::size_t j=0;j<itr->second.numDetails();j++) {
447  WorksetDetails & details = itr->second(j);
448 
449  ortsPerBlock.clear();
450  for (int k=0;k<itr->second.num_cells;++k) {
451  ortsPerBlock.push_back((*orientations_)[details.cell_local_ids[k]]);
452  }
453 
454  for(const auto & id : needs.getIntegrators()) {
455  // apply orientations for this basis
456  auto & bv = details.getBasisValues(bd,id);
457  if(not bv.orientationsApplied())
458  bv.applyOrientations(ortsPerBlock,(int) itr->second.num_cells);
459  }
460  }
461  }
462  } // end for w
463  }
464 }
465 
467  const std::vector<std::string> & elementBlockNames,
468  std::map<std::string,Teuchos::RCP<std::vector<Workset> > > & volumeWksts)
469 {
470  for(std::size_t i=0;i<elementBlockNames.size();i++) {
471  WorksetDescriptor wd = blockDescriptor(elementBlockNames[i]);
472  volumeWksts[elementBlockNames[i]] = wc.getWorksets(wd);
473  }
474 }
475 
477  const std::vector<BC> & bcs,
478  std::map<BC,Teuchos::RCP<std::map<unsigned,Workset> >,LessBC> & sideWksts)
479 {
480  for(std::size_t i=0;i<bcs.size();i++) {
481  WorksetDescriptor wd(bcs[i].elementBlockID(),bcs[i].sidesetID());
483  if(wksts!=Teuchos::null)
484  sideWksts[bcs[i]] = wksts;
485  }
486 }
487 
488 }
std::string name() const
A unique key that is the combination of the basis type and basis order.
std::vector< Teuchos::RCP< const PureBasis > > bases
void setGlobalIndexer(const Teuchos::RCP< const panzer::GlobalIndexer > &ugi)
Teuchos::RCP< std::vector< Intrepid2::Orientation > > orientations_
bool connectsElementBlocks() const
Identifies this workset as an interface between two element blocks.
WorksetContainer()
Default contructor, starts with no workset factory objects.
std::vector< size_t > cell_local_ids
Teuchos::RCP< const panzer::GlobalIndexer > globalIndexer_
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
std::vector< Teuchos::RCP< panzer::BasisValues2< double > > > bases
Static basis function data, key is basis name, value is index in the static_bases vector...
Teuchos::RCP< const WorksetFactoryBase > wkstFactory_
const std::string & getElementBlock(const int block=0) const
Get element block name.
int numOwnedCells() const
Number of cells owned by this workset.
std::vector< std::string > rep_field_name
void buildIntrepidOrientation(std::vector< Intrepid2::Orientation > &orientation, panzer::ConnManager &connMgr)
Builds the element orientations for all element blocks.
Class that provides access to worksets on each element block and side set.
bool requiresOrientations() const
WorksetMap worksets_
Maps element blocks to input physics block objects.
Teuchos::RCP< std::map< unsigned, Workset > > getSideWorksets(const WorksetDescriptor &desc)
Access, and construction of side worksets.
const std::vector< panzer::BasisDescriptor > & getBases() const
Get a list of bases being requested.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Teuchos::RCP< std::vector< Workset > > getWorksets(const WorksetDescriptor &wd)
Access to volume worksets.
basic_FancyOStream & setOutputToRootOnly(const int rootRank)
void setIdentifiers(const WorksetDescriptor &wd, std::vector< Workset > &worksets)
const std::vector< panzer::IntegrationDescriptor > & getIntegrators() const
Get a list of integrators being requested.
void applyOrientations(const Teuchos::RCP< const panzer::GlobalIndexer > &ugi)
const WorksetNeeds & lookupNeeds(const std::string &eBlock) const
Look up an input physics block, throws an exception if it can not be found.
void addBasis(const std::string &type, int order, const std::string &rep_field)
WorksetDescriptor blockDescriptor(const std::string &eBlock)
void getSideWorksetsFromContainer(WorksetContainer &wc, const std::vector< BC > &bcs, std::map< BC, Teuchos::RCP< std::map< unsigned, Workset > >, LessBC > &sideWksts)
Stores input information for a boundary condition.
Definition: Panzer_BC.hpp:48
Description and data layouts associated with a particular basis.
#define TEUCHOS_ASSERT(assertion_test)
void setNeeds(const std::string &eBlock, const WorksetNeeds &needs)
const panzer::BasisValues2< double > & getBasisValues(const panzer::BasisDescriptor &basis_description, const bool lazy_version=false) const
std::map< std::string, WorksetNeeds > ebToNeeds_
How to construct worksets.
void getVolumeWorksetsFromContainer(WorksetContainer &wc, const std::vector< std::string > &elementBlockNames, std::map< std::string, Teuchos::RCP< std::vector< Workset > > > &volumeWksts)