Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_Workset_Builder_impl.hpp
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 
43 #ifndef __Panzer_Workset_Builder_impl_hpp__
44 #define __Panzer_Workset_Builder_impl_hpp__
45 
46 #include <iostream>
47 #include <vector>
48 #include <map>
49 #include <algorithm>
50 #include "Panzer_Workset.hpp"
51 #include "Panzer_CellData.hpp"
52 #include "Panzer_BC.hpp"
55 
56 #include "Phalanx_DataLayout_MDALayout.hpp"
57 
58 // Intrepid2
59 #include "Shards_CellTopology.hpp"
60 #include "Intrepid2_DefaultCubatureFactory.hpp"
61 #include "Intrepid2_CellTools.hpp"
62 #include "Intrepid2_FunctionSpaceTools.hpp"
63 #include "Intrepid2_Basis.hpp"
64 
65 template<typename ArrayT>
67 panzer::buildWorksets(const WorksetNeeds & needs,
68  const std::string & elementBlock,
69  const std::vector<std::size_t>& local_cell_ids,
70  const ArrayT& node_coordinates)
71 {
72  using std::vector;
73  using std::string;
74  using Teuchos::RCP;
75  using Teuchos::rcp;
76 
77  panzer::MDFieldArrayFactory mdArrayFactory("",true);
78 
79  std::size_t total_num_cells = local_cell_ids.size();
80 
81  std::size_t workset_size = needs.cellData.numCells();
82 
84  Teuchos::rcp(new std::vector<panzer::Workset>);
85  std::vector<panzer::Workset>& worksets = *worksets_ptr;
86 
87  // special case for 0 elements!
88  if(total_num_cells==0) {
89 
90  // Setup integration rules and basis
91  RCP<vector<int> > ir_degrees = rcp(new vector<int>(0));
92  RCP<vector<string> > basis_names = rcp(new vector<string>(0));
93 
94  worksets.resize(1);
95  std::vector<panzer::Workset>::iterator i = worksets.begin();
96  i->setNumberOfCells(0,0,0);
97  i->block_id = elementBlock;
98  i->ir_degrees = ir_degrees;
99  i->basis_names = basis_names;
100 
101  for (std::size_t j=0;j<needs.int_rules.size();j++) {
102 
103  RCP<panzer::IntegrationValues2<double> > iv2 =
105  iv2->setupArrays(needs.int_rules[j]);
106 
107  ir_degrees->push_back(needs.int_rules[j]->cubature_degree);
108  i->int_rules.push_back(iv2);
109  }
110 
111  // Need to create all combinations of basis/ir pairings
112  for (std::size_t j=0;j<needs.int_rules.size();j++) {
113  for (std::size_t b=0;b<needs.bases.size();b++) {
114  RCP<panzer::BasisIRLayout> b_layout
115  = rcp(new panzer::BasisIRLayout(needs.bases[b],*needs.int_rules[j]));
116 
117  RCP<panzer::BasisValues2<double> > bv2
118  = rcp(new panzer::BasisValues2<double>("",true,true));
119  bv2->setupArrays(b_layout);
120  i->bases.push_back(bv2);
121 
122  basis_names->push_back(b_layout->name());
123  }
124 
125  }
126 
127  return worksets_ptr;
128  } // end special case
129 
130  {
131  std::size_t num_worksets = total_num_cells / workset_size;
132  bool last_set_is_full = true;
133  std::size_t last_workset_size = total_num_cells % workset_size;
134  if (last_workset_size != 0) {
135  num_worksets += 1;
136  last_set_is_full = false;
137  }
138 
139  worksets.resize(num_worksets);
140  std::vector<panzer::Workset>::iterator i;
141  for (i = worksets.begin(); i != worksets.end(); ++i)
142  i->setNumberOfCells(workset_size,0,0);
143 
144  if (!last_set_is_full) {
145  worksets.back().setNumberOfCells(last_workset_size,0,0);
146  }
147  }
148 
149  // assign workset cell local ids
150  std::vector<std::size_t>::const_iterator local_begin = local_cell_ids.begin();
151  for (std::vector<panzer::Workset>::iterator wkst = worksets.begin(); wkst != worksets.end(); ++wkst) {
152  std::vector<std::size_t>::const_iterator begin_iter = local_begin;
153  std::vector<std::size_t>::const_iterator end_iter = begin_iter + wkst->num_cells;
154  local_begin = end_iter;
155  wkst->cell_local_ids.assign(begin_iter,end_iter);
156 
157  PHX::View<int*> cell_local_ids_k = PHX::View<int*>("Workset:cell_local_ids",wkst->cell_local_ids.size());
158  auto cell_local_ids_k_h = Kokkos::create_mirror_view(cell_local_ids_k);
159  for(std::size_t i=0;i<wkst->cell_local_ids.size();i++)
160  cell_local_ids_k_h(i) = wkst->cell_local_ids[i];
161  Kokkos::deep_copy(cell_local_ids_k, cell_local_ids_k_h);
162  wkst->cell_local_ids_k = cell_local_ids_k;
163 
164  wkst->cell_node_coordinates = mdArrayFactory.buildStaticArray<double,Cell,NODE,Dim>("cnc",workset_size,
165  node_coordinates.extent(1),
166  node_coordinates.extent(2));
167  wkst->block_id = elementBlock;
168  wkst->subcell_dim = needs.cellData.baseCellDimension();
169  wkst->subcell_index = 0;
170  }
171 
172  TEUCHOS_ASSERT(local_begin == local_cell_ids.end());
173 
174  // Copy cell node coordinates into local workset arrays
175  std::size_t offset = 0;
176  for (std::vector<panzer::Workset>::iterator wkst = worksets.begin(); wkst != worksets.end(); ++wkst) {
177  auto cell_node_coordinates = wkst->cell_node_coordinates.get_static_view();
178  Kokkos::parallel_for(wkst->num_cells, KOKKOS_LAMBDA (int cell) {
179  for (std::size_t node = 0; node < node_coordinates.extent(1); ++ node)
180  for (std::size_t dim = 0; dim < node_coordinates.extent(2); ++ dim) {
181  cell_node_coordinates(cell,node,dim) = node_coordinates(cell + offset,node,dim);
182  }
183  });
184  Kokkos::fence();
185  offset += wkst->num_cells;
186  }
187 
188  TEUCHOS_ASSERT(offset == Teuchos::as<std::size_t>(node_coordinates.extent(0)));
189 
190  // Set ir and basis arrayskset
191  RCP<vector<int> > ir_degrees = rcp(new vector<int>(0));
192  RCP<vector<string> > basis_names = rcp(new vector<string>(0));
193  for (std::vector<panzer::Workset>::iterator wkst = worksets.begin(); wkst != worksets.end(); ++wkst) {
194  wkst->ir_degrees = ir_degrees;
195  wkst->basis_names = basis_names;
196  }
197 
198  // setup the integration rules and bases
199  for(std::vector<panzer::Workset>::iterator wkst = worksets.begin(); wkst != worksets.end(); ++wkst)
200  populateValueArrays(wkst->num_cells,false,needs,*wkst);
201 
202  return worksets_ptr;
203 }
204 
205 // ****************************************************************
206 // ****************************************************************
207 
208 template<typename ArrayT>
210 panzer::buildBCWorkset(const WorksetNeeds & needs,
211  const std::string & elementBlock,
212  const std::vector<std::size_t>& local_cell_ids,
213  const std::vector<std::size_t>& local_side_ids,
214  const ArrayT& node_coordinates,
215  const bool populate_value_arrays)
216 {
217  using Teuchos::RCP;
218  using Teuchos::rcp;
219 
220  panzer::MDFieldArrayFactory mdArrayFactory("",true);
221 
222  // key is local face index, value is workset with all elements
223  // for that local face
224  auto worksets_ptr = Teuchos::rcp(new std::map<unsigned,panzer::Workset>);
225 
226  // All elements of boundary condition should go into one workset.
227  // However due to design of Intrepid2 (requires same basis for all
228  // cells), we have to separate the workset based on the local side
229  // index. Each workset for a boundary condition is associated with
230  // a local side for the element
231 
232  TEUCHOS_ASSERT(local_side_ids.size() == local_cell_ids.size());
233  TEUCHOS_ASSERT(local_side_ids.size() == static_cast<std::size_t>(node_coordinates.extent(0)));
234 
235  // key is local face index, value is a pair of cell index and vector of element local ids
236  std::map< unsigned, std::vector< std::pair< std::size_t, std::size_t>>> element_list;
237  for (std::size_t cell = 0; cell < local_cell_ids.size(); ++cell)
238  element_list[local_side_ids[cell]].push_back(std::make_pair(cell, local_cell_ids[cell]));
239 
240  auto& worksets = *worksets_ptr;
241 
242  // create worksets
243  for (const auto& side : element_list) {
244 
245  auto& cell_local_ids = worksets[side.first].cell_local_ids;
246 
247  worksets[side.first].cell_node_coordinates = mdArrayFactory.buildStaticArray<double,Cell,NODE,Dim>("cnc",
248  side.second.size(),
249  node_coordinates.extent(1),
250  node_coordinates.extent(2));
251  auto coords_view = worksets[side.first].cell_node_coordinates.get_view();
252  auto coords_h = Kokkos::create_mirror_view(coords_view);
253 
254  auto node_coordinates_h = Kokkos::create_mirror_view(PHX::as_view(node_coordinates));
255  Kokkos::deep_copy(node_coordinates_h, PHX::as_view(node_coordinates));
256 
257  for (std::size_t cell = 0; cell < side.second.size(); ++cell) {
258  cell_local_ids.push_back(side.second[cell].second);
259  const auto dim0 = side.second[cell].first;
260 
261  for(std::size_t node = 0; node < node_coordinates.extent(1); ++node)
262  {
263  const auto extent = Teuchos::as<std::size_t>(node_coordinates.extent(2));
264 
265  for (std::size_t dim = 0; dim < extent; ++dim)
266  coords_h(cell, node, dim) = node_coordinates_h(dim0, node, dim);
267  }
268  }
269 
270  Kokkos::deep_copy(coords_view, coords_h);
271 
272  const auto cell_local_ids_size = worksets[side.first].cell_local_ids.size();
273  auto cell_local_ids_k = PHX::View<int*>("Workset:cell_local_ids", cell_local_ids_size);
274  auto cell_local_ids_k_h = Kokkos::create_mirror_view(cell_local_ids_k);
275 
276  for(std::size_t i = 0; i < cell_local_ids_size; ++i){
277  cell_local_ids_k_h(i) = worksets.at(side.first).cell_local_ids[i];
278  }
279 
280  Kokkos::deep_copy(cell_local_ids_k, cell_local_ids_k_h);
281 
282  worksets[side.first].cell_local_ids_k = cell_local_ids_k;
283  worksets[side.first].num_cells = worksets[side.first].cell_local_ids.size();
284  worksets[side.first].block_id = elementBlock;
285  worksets[side.first].subcell_dim = needs.cellData.baseCellDimension() - 1;
286  worksets[side.first].subcell_index = side.first;
287  }
288 
289  if (populate_value_arrays) {
290  // setup the integration rules and bases
291  for (std::map<unsigned,panzer::Workset>::iterator wkst = worksets.begin();
292  wkst != worksets.end(); ++wkst) {
293 
294  populateValueArrays(wkst->second.num_cells,true,needs,wkst->second); // populate "side" values
295  }
296  }
297 
298  return worksets_ptr;
299 }
300 
301 // ****************************************************************
302 // ****************************************************************
303 
304 namespace panzer {
305 namespace impl {
306 
307 /* Associate two sets of local side IDs into lists. Each list L has the property
308  * that every local side id in that list is the same, and this holds for each
309  * local side ID set. The smallest set of lists is found. The motivation for
310  * this procedure is to find a 1-1 workset pairing in advance. See the comment
311  * re: Intrepid2 in buildBCWorkset for more.
312  * The return value is an RCP to a map. Only the map's values are of interest
313  * in practice. Each value is a list L. The map's key is a pair (side ID a, side
314  * ID b) that gives rise to the list. We return a pointer to a map so that the
315  * caller does not have to deal with the map type; auto suffices.
316  */
318 associateCellsBySideIds(const std::vector<std::size_t>& sia /* local_side_ids_a */,
319  const std::vector<std::size_t>& sib /* local_side_ids_b */)
320 {
321  TEUCHOS_ASSERT(sia.size() == sib.size());
322 
323  auto sip2i_p = Teuchos::rcp(new std::map< std::pair<std::size_t, std::size_t>, std::vector<std::size_t> >);
324  auto& sip2i = *sip2i_p;
325 
326  for (std::size_t i = 0; i < sia.size(); ++i)
327  sip2i[std::make_pair(sia[i], sib[i])].push_back(i);
328 
329  return sip2i_p;
330 }
331 
332 // Set s = a(idxs). No error checking.
333 template <typename T>
334 void subset(const std::vector<T>& a, const std::vector<std::size_t>& idxs, std::vector<T>& s)
335 {
336  s.resize(idxs.size());
337  for (std::size_t i = 0; i < idxs.size(); ++i)
338  s[i] = a[idxs[i]];
339 }
340 
341 template<typename ArrayT>
344  const std::string & blockid_a,
345  const std::vector<std::size_t>& local_cell_ids_a,
346  const std::vector<std::size_t>& local_side_ids_a,
347  const ArrayT& node_coordinates_a,
348  const panzer::WorksetNeeds & needs_b,
349  const std::string & blockid_b,
350  const std::vector<std::size_t>& local_cell_ids_b,
351  const std::vector<std::size_t>& local_side_ids_b,
352  const ArrayT& node_coordinates_b,
353  const WorksetNeeds& needs_b2)
354 {
355  TEUCHOS_ASSERT(local_cell_ids_a.size() == local_cell_ids_b.size());
356  // Get a and b workset maps separately, but don't populate b's arrays.
358  mwa = buildBCWorkset(needs_a,blockid_a, local_cell_ids_a, local_side_ids_a, node_coordinates_a),
359  mwb = buildBCWorkset(needs_b2, blockid_b, local_cell_ids_b, local_side_ids_b,
360  node_coordinates_b, false /* populate_value_arrays */);
361  TEUCHOS_ASSERT(mwa->size() == 1 && mwb->size() == 1);
362  for (std::map<unsigned,panzer::Workset>::iterator ait = mwa->begin(), bit = mwb->begin();
363  ait != mwa->end(); ++ait, ++bit) {
364  TEUCHOS_ASSERT(Teuchos::as<std::size_t>(ait->second.num_cells) == local_cell_ids_a.size() &&
365  Teuchos::as<std::size_t>(bit->second.num_cells) == local_cell_ids_b.size());
366  panzer::Workset& wa = ait->second;
367  // Copy b's details(0) to a's details(1).
368  wa.other = Teuchos::rcp(new panzer::WorksetDetails(bit->second.details(0)));
369  // Populate details(1) arrays so that IP are in order corresponding to details(0).
370  populateValueArrays(wa.num_cells, true, needs_b, wa.details(1), Teuchos::rcpFromRef(wa.details(0)));
371  }
372  // Now mwa has everything we need.
373  return mwa;
374 }
375 
376 } // namespace impl
377 } // namespace panzer
378 
379 // ****************************************************************
380 // ****************************************************************
381 
382 template<typename ArrayT>
385  const std::string & blockid_a,
386  const std::vector<std::size_t>& local_cell_ids_a,
387  const std::vector<std::size_t>& local_side_ids_a,
388  const ArrayT& node_coordinates_a,
389  const panzer::WorksetNeeds & needs_b,
390  const std::string & blockid_b,
391  const std::vector<std::size_t>& local_cell_ids_b,
392  const std::vector<std::size_t>& local_side_ids_b,
393  const ArrayT& node_coordinates_b)
394 {
395  // Since Intrepid2 requires all side IDs in a workset to be the same (see
396  // Intrepid2 comment above), we break the element list into pieces such that
397  // each piece contains elements on each side of the interface L_a and L_b and
398  // all elemnets L_a have the same side ID, and the same for L_b.
399  auto side_id_associations = impl::associateCellsBySideIds(local_side_ids_a, local_side_ids_b);
400  if (side_id_associations->size() == 1) {
401  // Common case of one workset on each side; optimize for it.
402  return impl::buildBCWorksetForUniqueSideId(needs_a, blockid_a, local_cell_ids_a, local_side_ids_a, node_coordinates_a,
403  needs_b, blockid_b, local_cell_ids_b, local_side_ids_b, node_coordinates_b,
404  needs_b);
405  } else {
406  // The interface has elements having a mix of side IDs, so deal with each
407  // pair in turn.
408  Teuchos::RCP<std::map<unsigned,panzer::Workset> > mwa = Teuchos::rcp(new std::map<unsigned,panzer::Workset>);
409  std::vector<std::size_t> lci_a, lci_b, lsi_a, lsi_b;
410  panzer::MDFieldArrayFactory mdArrayFactory("", true);
411  const int d1 = Teuchos::as<std::size_t>(node_coordinates_a.extent(1)),
412  d2 = Teuchos::as<std::size_t>(node_coordinates_a.extent(2));
413  for (auto it : *side_id_associations) {
414  const auto& idxs = it.second;
415  impl::subset(local_cell_ids_a, idxs, lci_a);
416  impl::subset(local_side_ids_a, idxs, lsi_a);
417  impl::subset(local_cell_ids_b, idxs, lci_b);
418  impl::subset(local_side_ids_b, idxs, lsi_b);
419  auto nc_a = mdArrayFactory.buildStaticArray<double,Cell,NODE,Dim>("nc_a", idxs.size(), d1, d2);
420  auto nc_b = mdArrayFactory.buildStaticArray<double,Cell,NODE,Dim>("nc_b", idxs.size(), d1, d2);
421  auto nc_a_h = Kokkos::create_mirror_view(nc_a.get_static_view());
422  auto nc_b_h = Kokkos::create_mirror_view(nc_b.get_static_view());
423  auto node_coordinates_a_h = Kokkos::create_mirror_view(PHX::as_view(node_coordinates_a));
424  auto node_coordinates_b_h = Kokkos::create_mirror_view(PHX::as_view(node_coordinates_b));
425  Kokkos::deep_copy(node_coordinates_a_h, PHX::as_view(node_coordinates_a));
426  Kokkos::deep_copy(node_coordinates_b_h, PHX::as_view(node_coordinates_b));
427  for (std::size_t i = 0; i < idxs.size(); ++i) {
428  const auto ii = idxs[i];
429  for (int j = 0; j < d1; ++j)
430  for (int k = 0; k < d2; ++k) {
431  nc_a_h(i, j, k) = node_coordinates_a_h(ii, j, k);
432  nc_b_h(i, j, k) = node_coordinates_b_h(ii, j, k);
433  }
434  }
435  Kokkos::deep_copy(nc_a.get_static_view(), nc_a_h);
436  Kokkos::deep_copy(nc_b.get_static_view(), nc_b_h);
437  auto mwa_it = impl::buildBCWorksetForUniqueSideId(needs_a,blockid_a, lci_a, lsi_a, nc_a,
438  needs_b,blockid_b, lci_b, lsi_b, nc_b,
439  needs_b);
440  TEUCHOS_ASSERT(mwa_it->size() == 1);
441  // Form a unique key that encodes the pair (side ID a, side ID b). We
442  // abuse the key here in the sense that it is everywhere else understood
443  // to correspond to the side ID of the elements in the workset.
444  // 1000 is a number substantially larger than is needed for any element.
445  const std::size_t key = lsi_a[0] * 1000 + lsi_b[0];
446  (*mwa)[key] = mwa_it->begin()->second;
447  }
448  return mwa;
449  }
450 }
451 
452 // ****************************************************************
453 // ****************************************************************
454 
455 template<typename ArrayT>
457 panzer::buildEdgeWorksets(const WorksetNeeds & needs_a,
458  const std::string & eblock_a,
459  const std::vector<std::size_t>& local_cell_ids_a,
460  const std::vector<std::size_t>& local_side_ids_a,
461  const ArrayT& node_coordinates_a,
462  const WorksetNeeds & needs_b,
463  const std::string & eblock_b,
464  const std::vector<std::size_t>& local_cell_ids_b,
465  const std::vector<std::size_t>& local_side_ids_b,
466  const ArrayT& node_coordinates_b)
467 {
468  using Teuchos::RCP;
469  using Teuchos::rcp;
470 
471  panzer::MDFieldArrayFactory mdArrayFactory("",true);
472 
473  std::size_t total_num_cells_a = local_cell_ids_a.size();
474  std::size_t total_num_cells_b = local_cell_ids_b.size();
475 
476  TEUCHOS_ASSERT(total_num_cells_a==total_num_cells_b);
477  TEUCHOS_ASSERT(local_side_ids_a.size() == local_cell_ids_a.size());
478  TEUCHOS_ASSERT(local_side_ids_a.size() == static_cast<std::size_t>(node_coordinates_a.extent(0)));
479  TEUCHOS_ASSERT(local_side_ids_b.size() == local_cell_ids_b.size());
480  TEUCHOS_ASSERT(local_side_ids_b.size() == static_cast<std::size_t>(node_coordinates_b.extent(0)));
481 
482  std::size_t total_num_cells = total_num_cells_a;
483 
484  std::size_t workset_size = needs_a.cellData.numCells();
485 
487  Teuchos::rcp(new std::vector<panzer::Workset>);
488  std::vector<panzer::Workset>& worksets = *worksets_ptr;
489 
490  // special case for 0 elements!
491  if(total_num_cells==0) {
492 
493  // Setup integration rules and basis
494  RCP<std::vector<int> > ir_degrees = rcp(new std::vector<int>(0));
495  RCP<std::vector<std::string> > basis_names = rcp(new std::vector<std::string>(0));
496 
497  worksets.resize(1);
498  std::vector<panzer::Workset>::iterator i = worksets.begin();
499 
500  i->details(0).block_id = eblock_a;
501  i->other = Teuchos::rcp(new panzer::WorksetDetails);
502  i->details(1).block_id = eblock_b;
503 
504  i->num_cells = 0;
505  i->ir_degrees = ir_degrees;
506  i->basis_names = basis_names;
507 
508  for(std::size_t j=0;j<needs_a.int_rules.size();j++) {
509 
510  RCP<panzer::IntegrationValues2<double> > iv2 =
512  iv2->setupArrays(needs_a.int_rules[j]);
513 
514  ir_degrees->push_back(needs_a.int_rules[j]->cubature_degree);
515  i->int_rules.push_back(iv2);
516  }
517 
518  // Need to create all combinations of basis/ir pairings
519  for(std::size_t j=0;j<needs_a.int_rules.size();j++) {
520 
521  for(std::size_t b=0;b<needs_a.bases.size();b++) {
522 
523  RCP<panzer::BasisIRLayout> b_layout = rcp(new panzer::BasisIRLayout(needs_a.bases[b],*needs_a.int_rules[j]));
524 
525  RCP<panzer::BasisValues2<double> > bv2 =
526  rcp(new panzer::BasisValues2<double>("",true,true));
527  bv2->setupArrays(b_layout);
528  i->bases.push_back(bv2);
529 
530  basis_names->push_back(b_layout->name());
531  }
532 
533  }
534 
535  return worksets_ptr;
536  } // end special case
537 
538  // This collects all the elements that share the same sub cell pairs, this makes it easier to
539  // build the required worksets
540  // key is the pair of local face indices, value is a vector of cell indices that satisfy this pair
541  std::map<std::pair<unsigned,unsigned>,std::vector<std::size_t> > element_list;
542  for (std::size_t cell=0; cell < local_cell_ids_a.size(); ++cell)
543  element_list[std::make_pair(local_side_ids_a[cell],local_side_ids_b[cell])].push_back(cell);
544 
545  // figure out how many worksets will be needed, resize workset vector accordingly
546  std::size_t num_worksets = 0;
547  for(const auto& edge : element_list) {
548  std::size_t num_worksets_for_edge = edge.second.size() / workset_size;
549  std::size_t last_workset_size = edge.second.size() % workset_size;
550  if(last_workset_size!=0)
551  num_worksets_for_edge += 1;
552 
553  num_worksets += num_worksets_for_edge;
554  }
555  worksets.resize(num_worksets);
556 
557  // fill the worksets
558  std::vector<Workset>::iterator current_workset = worksets.begin();
559  for(const auto& edge : element_list) {
560  // loop over each workset
561  const std::vector<std::size_t> & cell_indices = edge.second;
562 
563  current_workset = buildEdgeWorksets(cell_indices,
564  needs_a,eblock_a,local_cell_ids_a,local_side_ids_a,node_coordinates_a,
565  needs_b,eblock_b,local_cell_ids_b,local_side_ids_b,node_coordinates_b,
566  current_workset);
567  }
568 
569  // sanity check
570  TEUCHOS_ASSERT(current_workset==worksets.end());
571 
572  return worksets_ptr;
573 }
574 
575 template<typename ArrayT>
576 std::vector<panzer::Workset>::iterator
577 panzer::buildEdgeWorksets(const std::vector<std::size_t> & cell_indices,
578  const WorksetNeeds & needs_a,
579  const std::string & eblock_a,
580  const std::vector<std::size_t>& local_cell_ids_a,
581  const std::vector<std::size_t>& local_side_ids_a,
582  const ArrayT& node_coordinates_a,
583  const WorksetNeeds & needs_b,
584  const std::string & eblock_b,
585  const std::vector<std::size_t>& local_cell_ids_b,
586  const std::vector<std::size_t>& local_side_ids_b,
587  const ArrayT& node_coordinates_b,
588  std::vector<Workset>::iterator beg)
589 {
590  panzer::MDFieldArrayFactory mdArrayFactory("",true);
591 
592  std::vector<Workset>::iterator wkst = beg;
593 
594  std::size_t current_cell_index = 0;
595  while (current_cell_index<cell_indices.size()) {
596  std::size_t workset_size = needs_a.cellData.numCells();
597 
598  // allocate workset details (details(0) is already associated with the
599  // workset object itself)
600  wkst->other = Teuchos::rcp(new panzer::WorksetDetails);
601 
602  wkst->subcell_dim = needs_a.cellData.baseCellDimension()-1;
603 
604  wkst->details(0).subcell_index = local_side_ids_a[cell_indices[current_cell_index]];
605  wkst->details(0).block_id = eblock_a;
606  wkst->details(0).cell_node_coordinates = mdArrayFactory.buildStaticArray<double,Cell,NODE,Dim>("cnc",workset_size,
607  node_coordinates_a.extent(1),
608  node_coordinates_a.extent(2));
609 
610  wkst->details(1).subcell_index = local_side_ids_b[cell_indices[current_cell_index]];
611  wkst->details(1).block_id = eblock_b;
612  wkst->details(1).cell_node_coordinates = mdArrayFactory.buildStaticArray<double,Cell,NODE,Dim>("cnc",workset_size,
613  node_coordinates_a.extent(1),
614  node_coordinates_a.extent(2));
615 
616  std::size_t remaining_cells = cell_indices.size()-current_cell_index;
617  if(remaining_cells<workset_size)
618  workset_size = remaining_cells;
619 
620  // this is the true number of cells in this workset
621  wkst->setNumberOfCells(workset_size,0,0);
622  wkst->details(0).cell_local_ids.resize(workset_size);
623  wkst->details(1).cell_local_ids.resize(workset_size);
624 
625  auto dim0_cell_node_coordinates_view = wkst->details(0).cell_node_coordinates.get_static_view();
626  auto dim0_cell_node_coordinates_h = Kokkos::create_mirror_view(dim0_cell_node_coordinates_view);
627  Kokkos::deep_copy(dim0_cell_node_coordinates_h, dim0_cell_node_coordinates_view);
628 
629  auto dim1_cell_node_coordinates_view = wkst->details(1).cell_node_coordinates.get_static_view();
630  auto dim1_cell_node_coordinates_h = Kokkos::create_mirror_view(dim1_cell_node_coordinates_view);
631  Kokkos::deep_copy(dim1_cell_node_coordinates_h, dim1_cell_node_coordinates_view);
632 
633  auto node_coordinates_a_h = Kokkos::create_mirror_view(node_coordinates_a);
634  Kokkos::deep_copy(node_coordinates_a_h, node_coordinates_a);
635 
636  auto node_coordinates_b_h = Kokkos::create_mirror_view(node_coordinates_b);
637  Kokkos::deep_copy(node_coordinates_b_h, node_coordinates_b);
638 
639  for(std::size_t cell=0;cell<workset_size; cell++,current_cell_index++) {
640 
641  wkst->details(0).cell_local_ids[cell] = local_cell_ids_a[cell_indices[current_cell_index]];
642  wkst->details(1).cell_local_ids[cell] = local_cell_ids_b[cell_indices[current_cell_index]];
643 
644  for (std::size_t node = 0; node < Teuchos::as<std::size_t>(node_coordinates_a.extent(1)); ++ node) {
645  for (std::size_t dim = 0; dim < Teuchos::as<std::size_t>(node_coordinates_a.extent(2)); ++ dim) {
646  dim0_cell_node_coordinates_h(cell,node,dim) = node_coordinates_a_h(cell_indices[current_cell_index],node,dim);
647  dim1_cell_node_coordinates_h(cell,node,dim) = node_coordinates_b_h(cell_indices[current_cell_index],node,dim);
648  }
649  }
650  }
651 
652  Kokkos::deep_copy(dim0_cell_node_coordinates_view, dim0_cell_node_coordinates_h);
653  Kokkos::deep_copy(dim1_cell_node_coordinates_view, dim1_cell_node_coordinates_h);
654 
655  auto cell_local_ids_k_0 = PHX::View<int*>("Workset:cell_local_ids",wkst->details(0).cell_local_ids.size());
656  auto cell_local_ids_k_0_h = Kokkos::create_mirror_view(cell_local_ids_k_0);
657 
658  auto cell_local_ids_k_1 = PHX::View<int*>("Workset:cell_local_ids",wkst->details(1).cell_local_ids.size());
659  auto cell_local_ids_k_1_h = Kokkos::create_mirror_view(cell_local_ids_k_1);
660 
661  for(std::size_t i=0;i<wkst->details(0).cell_local_ids.size();i++)
662  cell_local_ids_k_0_h(i) = wkst->details(0).cell_local_ids[i];
663  for(std::size_t i=0;i<wkst->details(1).cell_local_ids.size();i++)
664  cell_local_ids_k_1_h(i) = wkst->details(1).cell_local_ids[i];
665 
666  Kokkos::deep_copy(cell_local_ids_k_0, cell_local_ids_k_0_h);
667  Kokkos::deep_copy(cell_local_ids_k_1, cell_local_ids_k_1_h);
668 
669  wkst->details(0).cell_local_ids_k = cell_local_ids_k_0;
670  wkst->details(1).cell_local_ids_k = cell_local_ids_k_1;
671 
672  // fill the BasisValues and IntegrationValues arrays
673  std::size_t max_workset_size = needs_a.cellData.numCells();
674  populateValueArrays(max_workset_size,true,needs_a,wkst->details(0)); // populate "side" values
675  populateValueArrays(max_workset_size,true,needs_b,wkst->details(1),Teuchos::rcpFromRef(wkst->details(0)));
676 
677  wkst++;
678  }
679 
680  return wkst;
681 }
682 
683 #endif
Teuchos::RCP< std::map< unsigned, panzer::Workset > > buildBCWorksetForUniqueSideId(const panzer::WorksetNeeds &needs_a, const std::string &blockid_a, const std::vector< std::size_t > &local_cell_ids_a, const std::vector< std::size_t > &local_side_ids_a, const ArrayT &node_coordinates_a, const panzer::WorksetNeeds &needs_b, const std::string &blockid_b, const std::vector< std::size_t > &local_cell_ids_b, const std::vector< std::size_t > &local_side_ids_b, const ArrayT &node_coordinates_b, const WorksetNeeds &needs_b2)
Teuchos::RCP< std::vector< Workset > > buildWorksets(const WorksetNeeds &needs, const std::string &elementBlock, const std::vector< std::size_t > &local_cell_ids, const ArrayT &node_coordinates)
PHX::MDField< Scalar, T0 > buildStaticArray(const std::string &str, int d0) const
Teuchos::RCP< std::vector< Workset > > buildEdgeWorksets(const WorksetNeeds &needs_a, const std::string &eblock_a, const std::vector< std::size_t > &local_cell_ids_a, const std::vector< std::size_t > &local_side_ids_a, const ArrayT &node_coordinates_a, const WorksetNeeds &needs_b, const std::string &eblock_b, const std::vector< std::size_t > &local_cell_ids_b, const std::vector< std::size_t > &local_side_ids_b, const ArrayT &node_coordinates_b)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Teuchos::RCP< std::map< std::pair< std::size_t, std::size_t >, std::vector< std::size_t > > > associateCellsBySideIds(const std::vector< std::size_t > &sia, const std::vector< std::size_t > &sib)
Teuchos::RCP< WorksetDetails > other
Teuchos::RCP< std::map< unsigned, Workset > > buildBCWorkset(const WorksetNeeds &needs, const std::string &elementBlock, const std::vector< std::size_t > &local_cell_ids, const std::vector< std::size_t > &local_side_ids, const ArrayT &node_coordinates, const bool populate_value_arrays=true)
void subset(const std::vector< T > &a, const std::vector< std::size_t > &idxs, std::vector< T > &s)
#define TEUCHOS_ASSERT(assertion_test)
void populateValueArrays(std::size_t num_cells, bool isSide, const WorksetNeeds &needs, WorksetDetails &details, const Teuchos::RCP< WorksetDetails > other_details)