Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_FaceToElement_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  * FaceToElement.cpp
13  *
14  * Created on: Nov 15, 2016
15  * Author: mbetten
16  */
17 
18 #ifndef PANZER_FACE_TO_ELEMENT_IMPL_HPP
19 #define PANZER_FACE_TO_ELEMENT_IMPL_HPP
20 
21 #include "Panzer_FaceToElement.hpp"
26 
27 #include <vector>
28 #include <set>
29 #include <string>
30 
31 namespace panzer
32 {
33 
34 template <typename LocalOrdinal,typename GlobalOrdinal>
37 {
38 }
39 
40 #ifndef PANZER_HIDE_DEPRECATED_CODE
41 
45 template <typename LocalOrdinal,typename GlobalOrdinal>
48 {
49  initialize(conn);
50 }
51 #endif
52 
53 template <typename LocalOrdinal,typename GlobalOrdinal>
56  const Teuchos::RCP<const Teuchos::Comm<int>> comm)
57 {
58  initialize(conn, comm);
59 }
60 
61 #ifndef PANZER_HIDE_DEPRECATED_CODE
62 
66 template <typename LocalOrdinal,typename GlobalOrdinal>
67 void
70 {
71  Teuchos::RCP<const Teuchos::Comm<int>> comm_world(new Teuchos::MpiComm< int>(MPI_COMM_WORLD)); // CHECK: ALLOW MPI_COMM_WORLD
72  initialize(conn, comm_world);
73 }
74 #endif
75 
76 template <typename LocalOrdinal,typename GlobalOrdinal>
77 void
80  const Teuchos::RCP<const Teuchos::Comm<int>> comm)
81 {
82  // Create a map of elems
83  std::vector<std::string> block_ids;
84  conn.getElementBlockIds(block_ids);
85 
86  const int shift = 1;
87 
88  int dimension;
89  std::vector<shards::CellTopology> ebt;
90  conn.getElementBlockTopologies(ebt);
91  dimension = ebt[0].getDimension();
92 
93  int my_rank = comm->getRank();
94 #ifndef NDEBUG
95  int nprocs = comm->getSize();
96 #endif
97 
98  std::vector<GlobalOrdinal> element_GIDS;
99  for (size_t iblk = 0 ; iblk < block_ids.size(); ++iblk) {
100  // The connectivity takes in a shards class, therefore, it has to be build block by block?
101  // This seems odd, but o.k, moving forward.
102  if ( dimension == 1 ) {
103  panzer::EdgeFieldPattern edge_pattern(ebt[iblk]);
104  conn.buildConnectivity(edge_pattern);
105  } else if ( dimension == 2 ){
106  panzer::FaceFieldPattern face_pattern(ebt[iblk]);
107  conn.buildConnectivity(face_pattern);
108  } else {
109  panzer::ElemFieldPattern elem_pattern(ebt[iblk]);
110  conn.buildConnectivity(elem_pattern);
111  }
112  //const std::vector<GlobalOrdinal> &block_elems = conn.getElementBlock(block_ids[iblk]);
113  const std::vector<LocalOrdinal> &block_elems = conn.getElementBlock(block_ids[iblk]);
114  for (size_t i=0; i<block_elems.size(); ++i) {
115  const auto * connectivity = conn.getConnectivity(block_elems[i]);
116  element_GIDS.push_back(*connectivity);
117  }
118  }
119  Teuchos::RCP<const Map> elem_map =
120  Teuchos::RCP<Map>( new Map(Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(), &element_GIDS[0], element_GIDS.size(), 0, comm ));
121 
122  // Now we need to create the face owned and owned/shared maps.
123  Teuchos::RCP<const Map> face_map,owned_face_map;
124  {
125  std::vector<GlobalOrdinal> face_GIDS;
126  std::set<GlobalOrdinal> set_of_face_GIDS;
127  for (size_t iblk = 0 ; iblk < block_ids.size(); ++iblk) {
128  // The connectivity takes in a shards class, therefore, it has to be build block by block?
129  // This seems odd, but o.k, moving forward.
130  if ( dimension == 1 ) {
131  panzer::NodalFieldPattern edge_pattern(ebt[iblk]);
132  conn.buildConnectivity(edge_pattern);
133  } else if ( dimension == 2 ){
134  panzer::EdgeFieldPattern face_pattern(ebt[iblk]);
135  conn.buildConnectivity(face_pattern);
136  } else {
137  panzer::FaceFieldPattern elem_pattern(ebt[iblk]);
138  conn.buildConnectivity(elem_pattern);
139  }
140  //const std::vector<GlobalOrdinal> &block_elems = conn.getElementBlock(block_ids[iblk]);
141  const std::vector<LocalOrdinal> &block_elems = conn.getElementBlock(block_ids[iblk]);
142  for (size_t i=0; i<block_elems.size(); ++i) {
143  int n_conn = conn.getConnectivitySize(block_elems[i]);
144  const panzer::GlobalOrdinal * connectivity = conn.getConnectivity(block_elems[i]);
145  for (int iface=0; iface<n_conn; ++iface)
146  set_of_face_GIDS.insert(connectivity[iface]);
147  }
148  }
149  face_GIDS.insert(face_GIDS.begin(), set_of_face_GIDS.begin(), set_of_face_GIDS.end());
150 
151  face_map = Teuchos::RCP<Map>( new Map(Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(), &face_GIDS[0], face_GIDS.size(), 0, comm ));
152  owned_face_map = Tpetra::createOneToOne(face_map);
153  }
154 
155  // OK, now we have a map of faces, and owned faces
156  // We are going to do create a multi vector of size 8, block/elem/proc/lidx, block/elem/proc/lidx
157  // (note lidx is the local index associted with a face on each cell)
158  Teuchos::RCP<GOMultiVector> owned_face2elem_mv = Teuchos::RCP<GOMultiVector>(new GOMultiVector(owned_face_map, 8));
160  // set a flag of -1-shift to identify unmodified data
161  face2elem_mv->putScalar(-1-shift);
162  {
163  auto f2e = face2elem_mv->getLocalViewHost(Tpetra::Access::ReadWrite);
164  auto b1 = Kokkos::subview(f2e,Kokkos::ALL(),0);
165  auto e1 = Kokkos::subview(f2e,Kokkos::ALL(),1);
166  auto p1 = Kokkos::subview(f2e,Kokkos::ALL(),2);
167  auto l1 = Kokkos::subview(f2e,Kokkos::ALL(),3);
168  auto b2 = Kokkos::subview(f2e,Kokkos::ALL(),4);
169  auto e2 = Kokkos::subview(f2e,Kokkos::ALL(),5);
170  auto p2 = Kokkos::subview(f2e,Kokkos::ALL(),6);
171  auto l2 = Kokkos::subview(f2e,Kokkos::ALL(),7);
172  // Now loop once again over the blocks
173  GlobalOrdinal my_elem = 0;
174  for (size_t iblk = 0 ; iblk < block_ids.size(); ++iblk) {
175  // The connectivity takes in a shards class, therefore, it has to be build block by block?
176  // This seems odd, but o.k, moving forward.
177  if ( dimension == 1 ) {
178  panzer::NodalFieldPattern edge_pattern(ebt[iblk]);
179  conn.buildConnectivity(edge_pattern);
180  } else if ( dimension == 2 ){
181  panzer::EdgeFieldPattern face_pattern(ebt[iblk]);
182  conn.buildConnectivity(face_pattern);
183  } else {
184  panzer::FaceFieldPattern elem_pattern(ebt[iblk]);
185  conn.buildConnectivity(elem_pattern);
186  }
187  //const std::vector<GlobalOrdinal> &block_elems = conn.getElementBlock(block_ids[iblk]);
188  const std::vector<LocalOrdinal> &block_elems = conn.getElementBlock(block_ids[iblk]);
189  for (size_t i=0; i<block_elems.size(); ++i) {
190  int n_conn = conn.getConnectivitySize(block_elems[i]);
191  const panzer::GlobalOrdinal * connectivity = conn.getConnectivity(block_elems[i]);
192  for (int iface=0; iface<n_conn; ++iface) {
193  LocalOrdinal f = face_map->getLocalElement(connectivity[iface]);
194 
195  // Fun fact: this method breaks if we have cell 0 found in block 0 on process 0 for local index 0
196  // Fix = add 'shift' to everything
197  if (b1[f] < 0 ) {
198  b1[f] = iblk+shift;
199  e1[f] = elem_map->getGlobalElement(my_elem)+shift;
200  p1[f] = my_rank+shift;
201  l1[f] = iface+shift;
202  } else if (b2[f] < 0){
203  b2[f] = iblk+shift;
204  e2[f] = elem_map->getGlobalElement(my_elem)+shift;
205  p2[f] = my_rank+shift;
206  l2[f] = iface+shift;
207  } else
208  assert(false);
209  }
210  ++my_elem;
211  }
212  }
213  }
214 
215  // So, now we can export our owned things to our owned one.
216  Import imp(owned_face_map, face_map);
217  Export exp(face_map, owned_face_map);
218  owned_face2elem_mv->doExport(*face2elem_mv, exp, Tpetra::ADD);
219 
220  {
221  auto f2e = face2elem_mv->getLocalViewHost(Tpetra::Access::ReadWrite);
222  auto b1 = Kokkos::subview(f2e,Kokkos::ALL(),0);
223  auto e1 = Kokkos::subview(f2e,Kokkos::ALL(),1);
224  auto p1 = Kokkos::subview(f2e,Kokkos::ALL(),2);
225  auto l1 = Kokkos::subview(f2e,Kokkos::ALL(),3);
226  auto b2 = Kokkos::subview(f2e,Kokkos::ALL(),4);
227  auto e2 = Kokkos::subview(f2e,Kokkos::ALL(),5);
228  auto p2 = Kokkos::subview(f2e,Kokkos::ALL(),6);
229  auto l2 = Kokkos::subview(f2e,Kokkos::ALL(),7);
230 
231  auto of2e = owned_face2elem_mv->getLocalViewHost(Tpetra::Access::ReadWrite);
232  auto ob1 = Kokkos::subview(of2e,Kokkos::ALL(),0);
233  auto oe1 = Kokkos::subview(of2e,Kokkos::ALL(),1);
234  auto op1 = Kokkos::subview(of2e,Kokkos::ALL(),2);
235  auto ol1 = Kokkos::subview(of2e,Kokkos::ALL(),3);
236  auto ob2 = Kokkos::subview(of2e,Kokkos::ALL(),4);
237  auto oe2 = Kokkos::subview(of2e,Kokkos::ALL(),5);
238  auto op2 = Kokkos::subview(of2e,Kokkos::ALL(),6);
239  auto ol2 = Kokkos::subview(of2e,Kokkos::ALL(),7);
240 
241  // Since we added all of the arrays together, they're going to be broken
242  // We need to fix all of the broken faces
243  int num_boundary=0;
244  for (size_t i=0; i<ob1.size();++i){
245 
246  // Make sure side 1 of face was set (either by this process or by multiple processes
247  assert(b1[i] >= shift);
248 
249  LocalOrdinal shared_local_id = face_map->getLocalElement(owned_face_map->getGlobalElement(i));
250  // handle purely internal faces
251  if (ob1[i] == b1[shared_local_id] && ob2[i] == b2[shared_local_id] &&
252  oe1[i] == e1[shared_local_id] && oe2[i] == e2[shared_local_id]) {
253  if (ob2[i] < 0 )
254  num_boundary++;
255  continue;
256  }
257 
258  // Handle shared nodes on a boundary, this shouldn't happen
259  if (ob1[i] < b1[shared_local_id] || oe1[i] < e1[shared_local_id]) {
260  assert(false);
261  }
262 
263  if ( ob1[i] > b1[shared_local_id] || oe1[i] > e1[shared_local_id]) {
264  // This case both wrote to a face, we need to detangle
265  assert(ob2[i] < 0 && oe2[i] < 0);
266  ob2[i] = ob1[i] - b1[shared_local_id];
267  oe2[i] = oe1[i] - e1[shared_local_id];
268  op2[i] = op1[i] - p1[shared_local_id];
269  ol2[i] = ol1[i] - l1[shared_local_id];
270 
271  ob1[i] = b1[shared_local_id];
272  oe1[i] = e1[shared_local_id];
273  op1[i] = p1[shared_local_id];
274  ol1[i] = l1[shared_local_id];
275 
276  assert(op1[i] >=0 && op2[i] >= 0 && op1[i] < nprocs+shift && op2[i] < nprocs+shift);
277  }
278  }
279  }
280  face2elem_mv->doImport(*owned_face2elem_mv, imp, Tpetra::REPLACE);
281 
282  // std::cout << "number ext boundaries "<<num_boundary << std::endl;
283 
284  // Now cache the data
285  face_map_ = face_map;
286  LocalOrdinal nfaces = face_map_->getLocalNumElements();
287  elems_by_face_ = PHX::View<GlobalOrdinal *[2]>("FaceToElement::elems_by_face_", nfaces);
288  lidx_by_face_ = PHX::View<int *[2]>("FaceToElement::elems_by_face_", nfaces);
289  blocks_by_face_ = PHX::View<int *[2]> ("FaceToElement::blocks_by_face_", nfaces);
290  procs_by_face_ = PHX::View<int *[2]> ("FaceToElement::procs_by_face_", nfaces);
291  auto elems_by_face_h = Kokkos::create_mirror_view(elems_by_face_);
292  auto blocks_by_face_h = Kokkos::create_mirror_view(blocks_by_face_);
293  auto procs_by_face_h = Kokkos::create_mirror_view(procs_by_face_);
294  auto lidx_by_face_h = Kokkos::create_mirror_view(lidx_by_face_);
295 
296  auto f2e = face2elem_mv->getLocalViewHost(Tpetra::Access::ReadWrite);
297  auto b1 = Kokkos::subview(f2e,Kokkos::ALL(),0);
298  auto e1 = Kokkos::subview(f2e,Kokkos::ALL(),1);
299  auto p1 = Kokkos::subview(f2e,Kokkos::ALL(),2);
300  auto l1 = Kokkos::subview(f2e,Kokkos::ALL(),3);
301  auto b2 = Kokkos::subview(f2e,Kokkos::ALL(),4);
302  auto e2 = Kokkos::subview(f2e,Kokkos::ALL(),5);
303  auto p2 = Kokkos::subview(f2e,Kokkos::ALL(),6);
304  auto l2 = Kokkos::subview(f2e,Kokkos::ALL(),7);
305 
306  for (LocalOrdinal i=0; i< nfaces; ++i) {
307  elems_by_face_h (i,0) = e1[i]-shift;
308  elems_by_face_h (i,1) = e2[i]-shift;
309  blocks_by_face_h(i,0) = b1[i]-shift;
310  blocks_by_face_h(i,1) = b2[i]-shift;
311  procs_by_face_h (i,0) = p1[i]-shift;
312  procs_by_face_h (i,1) = p2[i]-shift;
313  lidx_by_face_h (i,0) = l1[i]-shift;
314  lidx_by_face_h (i,1) = l2[i]-shift;
315 
316  if(elems_by_face_h (i,0) < 0){
317  elems_by_face_h (i,0) = -1;
318  }
319  if(elems_by_face_h (i,1) < 0){
320  elems_by_face_h (i,1) = -1;
321  }
322  }
323  Kokkos::deep_copy(elems_by_face_, elems_by_face_h);
324  Kokkos::deep_copy(blocks_by_face_, blocks_by_face_h);
325  Kokkos::deep_copy(procs_by_face_, procs_by_face_h);
326  Kokkos::deep_copy(lidx_by_face_, lidx_by_face_h);
327 }
328 
329 }
330 
331 #endif /* __FaceToElementent_impl_hpp__ */
Tpetra::Import< LocalOrdinal, GlobalOrdinal, NodeType > Import
virtual LocalOrdinal getConnectivitySize(LocalOrdinal localElmtId) const =0
void initialize(panzer::ConnManager &conn)
Tpetra::Map< LocalOrdinal, GlobalOrdinal, NodeType > Map
virtual const std::vector< LocalOrdinal > & getElementBlock(const std::string &blockID) const =0
virtual void getElementBlockIds(std::vector< std::string > &elementBlockIds) const =0
Pure virtual base class for supplying mesh connectivity information to the DOF Manager.
virtual void getElementBlockTopologies(std::vector< shards::CellTopology > &elementBlockTopologies) const =0
Tpetra::Export< LocalOrdinal, GlobalOrdinal, NodeType > Export
Tpetra::MultiVector< GlobalOrdinal, LocalOrdinal, GlobalOrdinal, NodeType > GOMultiVector
virtual void buildConnectivity(const FieldPattern &fp)=0
virtual const GlobalOrdinal * getConnectivity(LocalOrdinal localElmtId) const =0