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