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 //
4 // Panzer: A partial differential equation assembly
5 // engine for strongly coupled complex multiphysics systems
6 // Copyright (2011) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Roger P. Pawlowski (rppawlo@sandia.gov) and
39 // Eric C. Cyr (eccyr@sandia.gov)
40 // ***********************************************************************
41 // @HEADER
42 
44 
46 
50 #include "Panzer_Dimension.hpp"
51 
52 namespace panzer {
53 
56  : worksetSize_(1)
57 {}
59  const std::map<std::string,WorksetNeeds> & needs)
60  : wkstFactory_(factory), worksetSize_(0)
61 {
62  // thats all!
63  ebToNeeds_ = needs;
64 }
65 
70  : wkstFactory_(wc.wkstFactory_)
71  , worksetSize_(wc.worksetSize_)
72 {
73 }
74 
79 {
80  this->clearVolumeWorksets();
81  this->clearSideWorksets();
82 }
83 
85 {
86  worksets_.clear();
87 }
88 
90 {
91  sideWorksets_.clear();
92 }
93 
95 setNeeds(const std::string & eBlock,const WorksetNeeds & needs)
96 {
97  clear(); // clear out old worksets
98  ebToNeeds_[eBlock] = needs;
99 }
100 
102 const WorksetNeeds & WorksetContainer::lookupNeeds(const std::string & eBlock) const
103 {
104  std::map<std::string,WorksetNeeds>::const_iterator itr = ebToNeeds_.find(eBlock);
105 
106  TEUCHOS_TEST_FOR_EXCEPTION(itr==ebToNeeds_.end(),std::logic_error,
107  "WorksetContainer::lookupNeeds no WorksetNeeds object is associated "
108  "with the element block \""+eBlock+"\".");
109 
110  return itr->second;
111 }
112 
115 {
116  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::WorksetContainer::getWorksets()",pwkst_con_get_worksets);
117 
118  Teuchos::RCP<std::vector<Workset> > worksetVector;
119  WorksetMap::iterator itr = worksets_.find(wd);
120  if(itr==worksets_.end()) {
121  // couldn't find workset, build it!
122  WorksetNeeds needs;
123  if(hasNeeds())
124  needs = lookupNeeds(wd.getElementBlock());
125  worksetVector = wkstFactory_->getWorksets(wd,needs);
126 
127  // apply orientations to the just constructed worksets
128  if(worksetVector!=Teuchos::null && wd.applyOrientations()) {
129  applyOrientations(wd.getElementBlock(),*worksetVector);
130  }
131 
132  if(worksetVector!=Teuchos::null)
133  setIdentifiers(wd,*worksetVector);
134 
135  // store vector for reuse in the future
136  worksets_[wd] = worksetVector;
137  }
138  else
139  worksetVector = itr->second;
140 
141  return worksetVector;
142 }
143 
147 {
148  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::WorksetContainer::getSideWorksets()",pwkst_con_get_side_worksets);
149 
151 
152  // this is the key for the workset map
153  SideMap::iterator itr = sideWorksets_.find(desc);
154 
155  if(itr==sideWorksets_.end()) {
156  // couldn't find workset, build it!
157  if (desc.connectsElementBlocks()) {
158  worksetMap = wkstFactory_->getSideWorksets(desc, lookupNeeds(desc.getElementBlock(0)),
159  lookupNeeds(desc.getElementBlock(1)));
160  }
161  else {
162  worksetMap = wkstFactory_->getSideWorksets(desc,lookupNeeds(desc.getElementBlock(0)));
163  }
164 
165  // apply orientations to the worksets for this side
166  if(worksetMap!=Teuchos::null)
167  applyOrientations(desc,*worksetMap);
168 
169  if(worksetMap!=Teuchos::null)
170  setIdentifiers(desc,*worksetMap);
171 
172  // store map for reuse in the future
173  sideWorksets_[desc] = worksetMap;
174  }
175  else {
176  worksetMap = itr->second;
177  }
178 
179  return worksetMap;
180 }
181 
182 
185 {
186  // apply the orientations for stored worksets
187  applyOrientations(ugi);
188 }
189 
191 addBasis(const std::string & type,int order,const std::string & rep_field)
192 {
193  using Teuchos::RCP;
194  using Teuchos::rcp;
195 
196  for(auto itr=ebToNeeds_.begin();itr!=ebToNeeds_.end();++itr) {
197  WorksetNeeds & needs = itr->second;
198  RCP<PureBasis> basis = rcp(new PureBasis(type,order,needs.cellData));
199 
200  // add in the new basis
201  needs.bases.push_back(basis);
202  needs.rep_field_name.push_back(rep_field);
203  }
204 
205  // clear all arrays, lazy evaluation means it will be rebuilt
206  clear();
207 }
208 
211 {
212  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::WorksetContainer::applyOrientations(ugi)",pwkst_con_apply_orts);
213 
214  // this gurantees orientations won't accidently be applied twice.
215  TEUCHOS_ASSERT(globalIndexer_==Teuchos::null);
216 
217  globalIndexer_ = ugi;
218 
219  // this should be created once and stored in an appropriate place
220  TEUCHOS_TEST_FOR_EXCEPTION(globalIndexer_ == Teuchos::null, std::logic_error,
221  "global indexer is not set yet");
223 
224  // loop over volume worksets, apply orientations to each
225  for(WorksetMap::iterator itr=worksets_.begin();
226  itr!=worksets_.end();++itr) {
227  std::string eBlock = itr->first.getElementBlock();
228 
229  applyOrientations(eBlock,*itr->second);
230  }
231 
232  // loop over side worksets, apply orientations to each
233  for(SideMap::iterator itr=sideWorksets_.begin();
234  itr!=sideWorksets_.end();itr++) {
235 
236  applyOrientations(itr->first,*itr->second);
237  }
238 }
239 
241 setIdentifiers(const WorksetDescriptor & wd,std::vector<Workset> & worksets)
242 {
243  std::size_t hash = std::hash<WorksetDescriptor>()(wd); // this is really ugly, is this really a C++ standard?
244  for(std::size_t i=0;i<worksets.size();i++)
245  worksets[i].setIdentifier(hash+i);
246 }
247 
249 setIdentifiers(const WorksetDescriptor & wd,std::map<unsigned,Workset> & workset_map)
250 {
251  std::size_t hash = std::hash<WorksetDescriptor>()(wd); // this is really ugly, is this really a C++ standard?
252  std::size_t offset = 0;
253  for(auto itr : workset_map) {
254  // itr.second.setIdentifier(hash+offset);
255  workset_map[itr.first].setIdentifier(hash+offset);
256 
257  offset++;
258  }
259 }
260 
262 applyOrientations(const std::string & eBlock, std::vector<Workset> & worksets) const
263 {
264  using Teuchos::RCP;
265 
266  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::WorksetContainer::applyOrientations(eBlock,worksets)",pwkst_con_apply_orts_eb_w);
267 
269  // this is for volume worksets //
271 
272  // short circuit if no global indexer exists
273  if((globalIndexer_==Teuchos::null) and (wkstFactory_->getOrientationsInterface() == Teuchos::null)) {
274  Teuchos::FancyOStream fout(Teuchos::rcpFromRef(std::cout));
275  fout.setOutputToRootOnly(0);
276 
277  fout << "Panzer Warning: No global indexer assigned to a workset container or factory. "
278  << "Orientation of the basis for edge basis functions cannot be applied, "
279  << "if those basis functions are used, there will be problems!" << std::endl;
280  return;
281  }
282 
283  // this should be matched to global indexer size (not sure how to retrive it)
284  if(globalIndexer_!=Teuchos::null){
285  TEUCHOS_TEST_FOR_EXCEPTION(orientations_ == Teuchos::null, std::logic_error,
286  "intrepid2 orientation is not constructed");
287  }
288 
289  // loop over each basis requiring orientations, then apply them
291 
292  // Note: It may be faster to loop over the basis pairs on the inside (not really sure)
293 
294  WorksetNeeds needs;
295  if(hasNeeds())
296  needs = lookupNeeds(eBlock);
297 
298  if(needs.bases.size()>0) {
299  // sanity check that we aren't missing something (the old and new "needs" should not be used together)
300  TEUCHOS_ASSERT(needs.getBases().size()==0);
301 
302  for(std::size_t w=0;w<needs.bases.size();w++) {
303  const PureBasis & basis = *needs.bases[w];
304 
305  // no need for this if orientations are not required!
306  if(!basis.requiresOrientations())
307  continue;
308 
309  // build accessors for orientation fields
310  std::vector<Intrepid2::Orientation> ortsPerBlock;
311 
312  // loop over worksets compute and apply orientations
313  for(std::size_t i=0;i<worksets.size();i++) {
314  // break out of the workset loop
315  if(worksets[i].num_cells<=0) continue;
316 
317  for(std::size_t j=0;j<worksets[i].numDetails();j++) {
318  WorksetDetails & details = worksets[i](j);
319 
320  ortsPerBlock.clear();
321  for (int k=0;k<worksets[i].num_cells;++k) {
322  ortsPerBlock.push_back((*orientations_)[details.cell_local_ids[k]]);
323  }
324 
325  for(std::size_t basis_index=0;basis_index<details.bases.size();basis_index++) {
326  Teuchos::RCP<const BasisIRLayout> layout = details.bases[basis_index]->basis_layout;
327 
328  // only apply orientations if its relevant to the current needs
329  if(layout->getBasis()->name()!=basis.name())
330  continue;
331 
332  TEUCHOS_ASSERT(layout!=Teuchos::null);
333  TEUCHOS_ASSERT(layout->getBasis()!=Teuchos::null);
334  if(layout->getBasis()->requiresOrientations()) {
335  // apply orientations for this basis
336  auto & bv = *details.bases[basis_index];
337  if(not bv.orientationsApplied())
338  bv.applyOrientations(ortsPerBlock,(int) worksets[i].num_cells);
339  }
340  }
341  }
342  }
343  } // end for w
344  }
345  else if(needs.getBases().size()>0) {
346  // sanity check that we aren't missing something (the old and new "needs" should not be used together)
347  TEUCHOS_ASSERT(needs.bases.size()==0);
348 
349  // This is for forwards compatibility, the needs now use "getBasis" calls as opposed
350  // to director accessors.
351  for(const auto & bd : needs.getBases()) {
352 
353  // build accessors for orientation fields
354  std::vector<Intrepid2::Orientation> ortsPerBlock;
355 
356  // loop over worksets compute and apply orientations
357  for(std::size_t i=0;i<worksets.size();i++) {
358  // break out of the workset loop
359  if(worksets[i].num_cells<=0) continue;
360 
361  for(std::size_t j=0;j<worksets[i].numDetails();j++) {
362  WorksetDetails & details = worksets[i](j);
363 
364  ortsPerBlock.clear();
365  // for (int k=0;k<worksets[i].num_cells;++k) {
366  for (int k=0;k<details.numOwnedCells();++k) {
367  ortsPerBlock.push_back((*orientations_)[details.cell_local_ids[k]]);
368  }
369 
370  for(const auto & id : needs.getIntegrators()) {
371  // apply orientations for this basis
372  auto & bv = details.getBasisValues(bd,id);
373  if(not bv.orientationsApplied())
374  bv.applyOrientations(ortsPerBlock,(int) worksets[i].num_cells);
375  }
376  }
377  }
378  } // end for w
379  }
380 }
381 
382 
384 applyOrientations(const WorksetDescriptor & desc,std::map<unsigned,Workset> & worksets) const
385 {
386  using Teuchos::RCP;
387 
388  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::WorksetContainer::applyOrientations(wd,worksets)",pwkst_con_apply_orts_wd_wksts);
389 
391  // this is for side worksets //
393 
394  // short circuit if no global indexer exists
395  if((globalIndexer_==Teuchos::null) and (wkstFactory_->getOrientationsInterface() == Teuchos::null)) {
396  Teuchos::FancyOStream fout(Teuchos::rcpFromRef(std::cout));
397  fout.setOutputToRootOnly(0);
398 
399  fout << "Panzer Warning: No global indexer assigned to a workset container or factory. "
400  << "Orientation of the basis for edge basis functions cannot be applied, "
401  << "if those basis functions are used, there will be problems!";
402  return;
403  }
404 
405  // loop over each basis requiring orientations, then apply them
407 
408  // Note: It may be faster to loop over the basis pairs on the inside (not really sure)
409  WorksetNeeds needs;
410  if(hasNeeds())
411  needs = lookupNeeds(desc.getElementBlock());
412 
413  if(needs.bases.size()>0) {
414  // sanity check that we aren't missing something (the old and new "needs" should not be used together)
415  TEUCHOS_ASSERT(needs.getBases().size()==0);
416  for(std::size_t i=0;i<needs.bases.size();i++) {
417  const PureBasis & basis = *needs.bases[i];
418 
419  // no need for this if orientations are not required!
420  if(!basis.requiresOrientations()) continue;
421 
422  // build accessors for orientation fields
423  std::vector<Intrepid2::Orientation> ortsPerBlock;
424 
425  // loop over worksets compute and apply orientations
426  for(std::map<unsigned,Workset>::iterator itr=worksets.begin();
427  itr!=worksets.end();++itr) {
428 
429  // break out of the workset loop
430  if(itr->second.num_cells<=0) continue;
431 
432  for(std::size_t j=0;j<itr->second.numDetails();j++) {
433  WorksetDetails & details = itr->second(j);
434 
435  ortsPerBlock.clear();
436  for (int k=0;k<itr->second.num_cells;++k) {
437  ortsPerBlock.push_back((*orientations_)[details.cell_local_ids[k]]);
438  }
439 
440  for(std::size_t basis_index=0;basis_index<details.bases.size();basis_index++) {
441  Teuchos::RCP<const BasisIRLayout> layout = details.bases[basis_index]->basis_layout;
442 
443  // only apply orientations if its relevant to the current needs
444  if(layout->getBasis()->name()!=basis.name())
445  continue;
446 
447  TEUCHOS_ASSERT(layout!=Teuchos::null);
448  TEUCHOS_ASSERT(layout->getBasis()!=Teuchos::null);
449  if(layout->getBasis()->requiresOrientations()) {
450  // apply orientations for this basis
451  auto & bv = *details.bases[basis_index];
452  if(not bv.orientationsApplied())
453  bv.applyOrientations(ortsPerBlock,(int) itr->second.num_cells);
454  }
455  }
456  }
457  }
458  } // end for i
459  }
460  else if(needs.getBases().size()>0) {
461  // sanity check that we aren't missing something (the old and new "needs" should not be used together)
462  TEUCHOS_ASSERT(needs.bases.size()==0);
463 
464  // This is for forwards compatibility, the needs now use "getBasis" calls as opposed
465  // to director accessors.
466  for(const auto & bd : needs.getBases()) {
467 
468  // build accessors for orientation fields
469  std::vector<Intrepid2::Orientation> ortsPerBlock;
470 
471  // loop over worksets compute and apply orientations
472  for(std::map<unsigned,Workset>::iterator itr=worksets.begin();
473  itr!=worksets.end();++itr) {
474 
475  // break out of the workset loop
476  if(itr->second.num_cells<=0) continue;
477 
478  for(std::size_t j=0;j<itr->second.numDetails();j++) {
479  WorksetDetails & details = itr->second(j);
480 
481  ortsPerBlock.clear();
482  for (int k=0;k<itr->second.num_cells;++k) {
483  ortsPerBlock.push_back((*orientations_)[details.cell_local_ids[k]]);
484  }
485 
486  for(const auto & id : needs.getIntegrators()) {
487  // apply orientations for this basis
488  auto & bv = details.getBasisValues(bd,id);
489  if(not bv.orientationsApplied())
490  bv.applyOrientations(ortsPerBlock,(int) itr->second.num_cells);
491  }
492  }
493  }
494  } // end for w
495  }
496 }
497 
499  const std::vector<std::string> & elementBlockNames,
500  std::map<std::string,Teuchos::RCP<std::vector<Workset> > > & volumeWksts)
501 {
502  for(std::size_t i=0;i<elementBlockNames.size();i++) {
503  WorksetDescriptor wd = blockDescriptor(elementBlockNames[i]);
504  volumeWksts[elementBlockNames[i]] = wc.getWorksets(wd);
505  }
506 }
507 
509  const std::vector<BC> & bcs,
510  std::map<BC,Teuchos::RCP<std::map<unsigned,Workset> >,LessBC> & sideWksts)
511 {
512  for(std::size_t i=0;i<bcs.size();i++) {
513  WorksetDescriptor wd(bcs[i].elementBlockID(),bcs[i].sidesetID());
515  if(wksts!=Teuchos::null)
516  sideWksts[bcs[i]] = wksts;
517  }
518 }
519 
520 }
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:81
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)