Panzer Version of the Day
Loading...
Searching...
No Matches
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
26
27#include "Teuchos_TimeMonitor.hpp"
28
29#include <vector>
30#include <set>
31#include <string>
32
33namespace panzer
34{
35
36template <typename LocalOrdinal,typename GlobalOrdinal>
41
42#ifndef PANZER_HIDE_DEPRECATED_CODE
47template <typename LocalOrdinal,typename GlobalOrdinal>
53#endif
54
55template <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
68template <typename LocalOrdinal,typename GlobalOrdinal>
69void
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
78template <typename LocalOrdinal,typename GlobalOrdinal>
79void
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;
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));
155 Teuchos::RCP<GOMultiVector> face2elem_mv = Teuchos::RCP<GOMultiVector>(new GOMultiVector(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__ */
Pure virtual base class for supplying mesh connectivity information to the DOF Manager.
virtual const std::vector< LocalOrdinal > & getElementBlock(const std::string &blockID) const =0
virtual void buildConnectivity(const FieldPattern &fp)=0
virtual const GlobalOrdinal * getConnectivity(LocalOrdinal localElmtId) const =0
virtual void getElementBlockIds(std::vector< std::string > &elementBlockIds) const =0
virtual void getElementBlockTopologies(std::vector< shards::CellTopology > &elementBlockTopologies) const =0
virtual LocalOrdinal getConnectivitySize(LocalOrdinal localElmtId) const =0
Tpetra::MultiVector< GlobalOrdinal, LocalOrdinal, GlobalOrdinal, NodeType > GOMultiVector
Tpetra::Export< LocalOrdinal, GlobalOrdinal, NodeType > Export
void initialize(panzer::ConnManager &conn)
Tpetra::Map< LocalOrdinal, GlobalOrdinal, NodeType > Map
Tpetra::Import< LocalOrdinal, GlobalOrdinal, NodeType > Import