Intrepid2
Intrepid2_CellToolsDefControlVolume.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Intrepid2 Package
4 //
5 // Copyright 2007 NTESS and the Intrepid2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 
16 #ifndef __INTREPID2_CELLTOOLS_DEF_CONTROL_VOLUME_HPP__
17 #define __INTREPID2_CELLTOOLS_DEF_CONTROL_VOLUME_HPP__
18 
19 // disable clang warnings
20 #if defined (__clang__) && !defined (__INTEL_COMPILER)
21 #pragma clang system_header
22 #endif
23 
24 namespace Intrepid2 {
25 
26  //============================================================================================//
27  // //
28  // Control Volume Coordinates //
29  // //
30  //============================================================================================//
31 
32  namespace FunctorCellTools {
33 
38  template<typename centerViewType, typename vertViewType>
39  KOKKOS_INLINE_FUNCTION
40  void getBarycenterPolygon2D( centerViewType center,
41  const vertViewType verts) {
42  // the enumeration already assumes the ordering of vertices (circling around the polygon)
43  const ordinal_type nvert = verts.extent(0);
44 
45  center(0) = 0;
46  center(1) = 0;
47  typename centerViewType::value_type area = 0;
48  for (ordinal_type i=0;i<nvert;++i) {
49  const ordinal_type j = (i + 1)%nvert;
50  const auto scale = verts(i,0)*verts(j,1) - verts(j,0)*verts(i,1);
51  center(0) += (verts(i,0) + verts(j,0))*scale;
52  center(1) += (verts(i,1) + verts(j,1))*scale;
53  area += 0.5*scale;
54  }
55  center(0) /= (6.0*area);
56  center(1) /= (6.0*area);
57  }
58 
59  template<typename midPointViewType, typename nodeMapViewType, typename vertViewType>
60  KOKKOS_INLINE_FUNCTION
61  void getMidPoints( midPointViewType midpts,
62  const nodeMapViewType map,
63  const vertViewType verts) {
64  const ordinal_type npts = map.extent(0);
65  const ordinal_type dim = verts.extent(1);
66 
67  for (ordinal_type i=0;i<npts;++i) {
68  // first entry is the number of subcell vertices
69  const ordinal_type nvert_per_subcell = map(i, 0);
70  for (ordinal_type j=0;j<dim;++j) {
71  midpts(i,j) = 0;
72  for (ordinal_type k=1;k<=nvert_per_subcell;++k)
73  midpts(i,j) += verts(map(i,k),j);
74  midpts(i,j) /= nvert_per_subcell;
75  }
76  }
77  }
78 
79  template<typename subcvCoordViewType,
80  typename cellCoordViewType,
81  typename mapViewType>
86  subcvCoordViewType _subcvCoords;
87  const cellCoordViewType _cellCoords;
88  const mapViewType _edgeMap;
89 
90  KOKKOS_INLINE_FUNCTION
91  F_getSubcvCoords_Polygon2D( subcvCoordViewType subcvCoords_,
92  cellCoordViewType cellCoords_,
93  mapViewType edgeMap_ )
94  : _subcvCoords(subcvCoords_), _cellCoords(cellCoords_), _edgeMap(edgeMap_) {}
95 
96  KOKKOS_INLINE_FUNCTION
97  void operator()(const ordinal_type cell) const {
98  // vertices of cell (P,D)
99  const auto verts = Kokkos::subdynrankview( _cellCoords, cell,
100  Kokkos::ALL(), Kokkos::ALL() );
101  const ordinal_type nvert = verts.extent(0);
102  const ordinal_type dim = verts.extent(1);
103 
104  // control volume coords (N,P,D), here N corresponds to cell vertices
105  auto cvCoords = Kokkos::subdynrankview( _subcvCoords, cell,
106  Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL() );
107 
108  // work space for barycenter and midpoints on edges
109  typedef typename subcvCoordViewType::value_type value_type;
110  value_type buf_center[2], buf_midpts[4*2];
111  Kokkos::View<value_type*,Kokkos::AnonymousSpace> center(buf_center, 2);
112  Kokkos::View<value_type**,Kokkos::AnonymousSpace> midpts(buf_midpts, 4, 2);
113 
114  getBarycenterPolygon2D(center, verts);
115  getMidPoints(midpts, _edgeMap, verts);
116 
117  for (ordinal_type i=0;i<nvert;++i) {
118  for (ordinal_type j=0;j<dim;++j) {
119  // control volume is always quad
120  cvCoords(i, 0, j) = verts(i, j);
121  cvCoords(i, 1, j) = midpts(i, j);
122  cvCoords(i, 2, j) = center(j);
123  cvCoords(i, 3, j) = midpts((i+nvert-1)%nvert, j);
124  }
125  }
126  }
127  };
128 
129  template<typename subcvCoordViewType,
130  typename cellCoordViewType,
131  typename mapViewType>
136  subcvCoordViewType _subcvCoords;
137  const cellCoordViewType _cellCoords;
138  const mapViewType _edgeMap, _faceMap;
139 
140  KOKKOS_INLINE_FUNCTION
141  F_getSubcvCoords_Hexahedron( subcvCoordViewType subcvCoords_,
142  cellCoordViewType cellCoords_,
143  mapViewType edgeMap_,
144  mapViewType faceMap_ )
145  : _subcvCoords(subcvCoords_), _cellCoords(cellCoords_), _edgeMap(edgeMap_), _faceMap(faceMap_) {}
146 
147  KOKKOS_INLINE_FUNCTION
148  void operator()(const ordinal_type cell) const {
149  // vertices of cell (P,D)
150  const auto verts = Kokkos::subdynrankview( _cellCoords, cell,
151  Kokkos::ALL(), Kokkos::ALL() );
152  const ordinal_type nvert = verts.extent(0);
153  const ordinal_type dim = verts.extent(1);
154 
155  // control volume coords (N,P,D), here N corresponds to cell vertices
156  auto cvCoords = Kokkos::subdynrankview( _subcvCoords, cell,
157  Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL() );
158 
159  // work space for barycenter and midpoints on edges
160  typedef typename subcvCoordViewType::value_type value_type;
161  value_type buf_center[3], buf_edge_midpts[12*3], buf_face_midpts[6*3];
162  Kokkos::View<value_type*,Kokkos::AnonymousSpace> center(buf_center, 3);
163  Kokkos::View<value_type**,Kokkos::AnonymousSpace> edge_midpts(buf_edge_midpts, 12, 3);
164  Kokkos::View<value_type**,Kokkos::AnonymousSpace> face_midpts(buf_face_midpts, 6, 3);
165 
166  // find barycenter
167  //Warning! I think this assumes the Hexa is affinely mapped from the reference Hexa
168  for (ordinal_type j=0;j<3;++j) {
169  center(j) = 0;
170  for (ordinal_type i=0;i<nvert;++i)
171  center(j) += verts(i,j);
172  center(j) /= nvert;
173  }
174 
175  getMidPoints(edge_midpts, _edgeMap, verts);
176  getMidPoints(face_midpts, _faceMap, verts);
177 
178  for (ordinal_type i=0;i<4;++i) {
179  const ordinal_type ii = (i+4-1)%4;
180  for (ordinal_type j=0;j<dim;++j) {
181 
182  // set first node of bottom hex to primary cell node
183  // and fifth node of upper hex
184  cvCoords(i, 0,j) = verts(i, j);
185  cvCoords(i+4,4,j) = verts(i+4,j);
186 
187  // set second node of bottom hex to adjacent edge midpoint
188  // and sixth node of upper hex
189  cvCoords(i, 1,j) = edge_midpts(i, j);
190  cvCoords(i+4,5,j) = edge_midpts(i+4,j);
191 
192  // set third node of bottom hex to bottom face midpoint (number 4)
193  // and seventh node of upper hex to top face midpoint
194  cvCoords(i, 2,j) = face_midpts(4,j);
195  cvCoords(i+4,6,j) = face_midpts(5,j);
196 
197  // set fourth node of bottom hex to other adjacent edge midpoint
198  // and eight node of upper hex to other adjacent edge midpoint
199  cvCoords(i, 3,j) = edge_midpts(ii, j);
200  cvCoords(i+4,7,j) = edge_midpts(ii+4,j);
201 
202  // set fifth node to vertical edge
203  // same as first node of upper hex
204  cvCoords(i, 4,j) = edge_midpts(i+8,j);
205  cvCoords(i+4,0,j) = edge_midpts(i+8,j);
206 
207  // set sixth node to adjacent face midpoint
208  // same as second node of upper hex
209  cvCoords(i, 5,j) = face_midpts(i,j);
210  cvCoords(i+4,1,j) = face_midpts(i,j);
211 
212  // set seventh node to barycenter
213  // same as third node of upper hex
214  cvCoords(i, 6,j) = center(j);
215  cvCoords(i+4,2,j) = center(j);
216 
217  // set eighth node to other adjacent face midpoint
218  // same as fourth node of upper hex
219  cvCoords(i, 7,j) = face_midpts(ii,j);
220  cvCoords(i+4,3,j) = face_midpts(ii,j);
221  }
222  }
223  }
224  };
225 
226 
227  template<typename subcvCoordViewType,
228  typename cellCoordViewType,
229  typename mapViewType>
234  subcvCoordViewType _subcvCoords;
235  const cellCoordViewType _cellCoords;
236  const mapViewType _edgeMap, _faceMap;
237 
238  KOKKOS_INLINE_FUNCTION
239  F_getSubcvCoords_Tetrahedron( subcvCoordViewType subcvCoords_,
240  cellCoordViewType cellCoords_,
241  mapViewType edgeMap_,
242  mapViewType faceMap_ )
243  : _subcvCoords(subcvCoords_), _cellCoords(cellCoords_), _edgeMap(edgeMap_), _faceMap(faceMap_) {}
244 
245  KOKKOS_INLINE_FUNCTION
246  void operator()(const ordinal_type cell) const {
247  // ** vertices of cell (P,D)
248  const auto verts = Kokkos::subdynrankview( _cellCoords, cell,
249  Kokkos::ALL(), Kokkos::ALL() );
250  const ordinal_type nvert = verts.extent(0);
251  const ordinal_type dim = verts.extent(1);
252 
253  // control volume coords (N,P,D), here N corresponds to cell vertices
254  auto cvCoords = Kokkos::subdynrankview( _subcvCoords, cell,
255  Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL() );
256 
257  // work space for barycenter and midpoints on edges
258  typedef typename subcvCoordViewType::value_type value_type;
259  value_type buf_center[3], buf_edge_midpts[6*3], buf_face_midpts[4*3];
260  Kokkos::View<value_type*,Kokkos::AnonymousSpace> center(buf_center, 3);
261  Kokkos::View<value_type**,Kokkos::AnonymousSpace> edge_midpts(buf_edge_midpts, 6, 3);
262  Kokkos::View<value_type**,Kokkos::AnonymousSpace> face_midpts(buf_face_midpts, 4, 3);
263 
264  // find barycenter
265  for (ordinal_type j=0;j<3;++j) {
266  center(j) = 0;
267  for (ordinal_type i=0;i<nvert;++i)
268  center(j) += verts(i,j);
269  center(j) /= nvert;
270  }
271 
272  getMidPoints(edge_midpts, _edgeMap, verts);
273  getMidPoints(face_midpts, _faceMap, verts);
274 
275  for (ordinal_type i=0;i<3;++i) {
276  const ordinal_type ii = (i+3-1)%3;
277  for (ordinal_type j=0;j<dim;++j) {
278  // set first node of bottom hex to primary cell node
279  cvCoords(i,0,j) = verts(i,j);
280 
281  // set second node of bottom hex to adjacent edge midpoint
282  cvCoords(i,1,j) = edge_midpts(i,j);
283 
284  // set third node of bottom hex to bottom face midpoint (number 3)
285  cvCoords(i,2,j) = face_midpts(3,j);
286 
287  // set fourth node of bottom hex to other adjacent edge midpoint
288  cvCoords(i,3,j) = edge_midpts(ii,j);
289 
290  // set fifth node to vertical edge
291  cvCoords(i,4,j) = edge_midpts(i+3,j);
292 
293  // set sixth node to adjacent face midpoint
294  cvCoords(i,5,j) = face_midpts(i,j);
295 
296  // set seventh node to barycenter
297  cvCoords(i,6,j) = center(j);
298 
299  // set eighth node to other adjacent face midpoint
300  cvCoords(i,7,j) = face_midpts(ii,j);
301  }
302  }
303 
304  for (ordinal_type j=0;j<dim;++j) {
305  // Control volume attached to fourth node
306  // set first node of bottom hex to primary cell node
307  cvCoords(3,0,j) = verts(3,j);
308 
309  // set second node of bottom hex to adjacent edge midpoint
310  cvCoords(3,1,j) = edge_midpts(3,j);
311 
312  // set third node of bottom hex to bottom face midpoint (number 3)
313  cvCoords(3,2,j) = face_midpts(2,j);
314 
315  // set fourth node of bottom hex to other adjacent edge midpoint
316  cvCoords(3,3,j) = edge_midpts(5,j);
317 
318  // set fifth node to vertical edge
319  cvCoords(3,4,j) = edge_midpts(4,j);
320 
321  // set sixth node to adjacent face midpoint
322  cvCoords(3,5,j) = face_midpts(0,j);
323 
324  // set seventh node to barycenter
325  cvCoords(3,6,j) = center(j);
326 
327  // set eighth node to other adjacent face midpoint
328  cvCoords(3,7,j) = face_midpts(1,j);
329  }
330  }
331  };
332 
333  }
334 
335  template<typename DeviceType>
336  template<typename subcvCoordValueType, class ...subcvCoordProperties,
337  typename cellCoordValueType, class ...cellCoordProperties>
338  void
340  getSubcvCoords( Kokkos::DynRankView<subcvCoordValueType,subcvCoordProperties...> subcvCoords,
341  const Kokkos::DynRankView<cellCoordValueType,cellCoordProperties...> cellCoords,
342  const shards::CellTopology primaryCell ) {
343 #ifdef HAVE_INTREPID2_DEBUG
344  INTREPID2_TEST_FOR_EXCEPTION( !hasReferenceCell(primaryCell), std::invalid_argument,
345  ">>> ERROR (Intrepid2::CellTools::getSubcvCoords): the primary cell must have a reference cell." );
346 
347  INTREPID2_TEST_FOR_EXCEPTION( cellCoords.extent(1) != primaryCell.getVertexCount(), std::invalid_argument,
348  ">>> ERROR (Intrepid2::CellTools::getSubcvCoords): cell coords dimension(1) does not match to # of vertices of the cell." );
349 
350  INTREPID2_TEST_FOR_EXCEPTION( cellCoords.extent(2) != primaryCell.getDimension(), std::invalid_argument,
351  ">>> ERROR (Intrepid2::CellTools::getSubcvCoords): cell coords dimension(2) does not match to the dimension of the cell." );
352 #endif
353  constexpr bool are_accessible =
354  Kokkos::Impl::MemorySpaceAccess<MemSpaceType,
355  typename decltype(subcvCoords)::memory_space>::accessible &&
356  Kokkos::Impl::MemorySpaceAccess<MemSpaceType,
357  typename decltype(cellCoords)::memory_space>::accessible;
358  static_assert(are_accessible, "CellTools<DeviceType>::getSubcvCoords(..): input/output views' memory spaces are not compatible with DeviceType");
359 
360 
361  // get array dimensions
362  const ordinal_type numCells = cellCoords.extent(0);
363  //const ordinal_type numVerts = cellCoords.extent(1);
364  const ordinal_type spaceDim = cellCoords.extent(2);
365 
366  // construct edge and face map for the cell type
367  const ordinal_type numEdge = primaryCell.getSubcellCount(1);
368  Kokkos::View<ordinal_type**,DeviceType> edgeMap("CellTools::getSubcvCoords::edgeMap", numEdge, 3);
369  auto edgeMapHost = Kokkos::create_mirror_view(edgeMap);
370  for (ordinal_type i=0;i<numEdge;++i) {
371  edgeMapHost(i,0) = primaryCell.getNodeCount(1, i);
372  for (ordinal_type j=0;j<edgeMapHost(i,0);++j)
373  edgeMapHost(i,j+1) = primaryCell.getNodeMap(1, i, j);
374  }
375 
376  const ordinal_type numFace = (spaceDim > 2 ? primaryCell.getSubcellCount(2) : 0);
377  Kokkos::View<ordinal_type**,DeviceType> faceMap("CellTools::getSubcvCoords::faceMap", numFace, 5);
378  auto faceMapHost = Kokkos::create_mirror_view(faceMap);
379  for (ordinal_type i=0;i<numFace;++i) {
380  faceMapHost(i,0) = primaryCell.getNodeCount(2, i);
381  for (ordinal_type j=0;j<faceMapHost(i,0);++j)
382  faceMapHost(i,j+1) = primaryCell.getNodeMap(2, i, j);
383  }
384 
385  Kokkos::deep_copy(edgeMap, edgeMapHost);
386  Kokkos::deep_copy(faceMap, faceMapHost);
387 
388  // parallel run
389  using subcvCoordViewType = decltype(subcvCoords);
390  using cellCoordViewType = decltype(cellCoords);
391  using mapViewType = decltype(edgeMap);
392 
393  const auto loopSize = numCells;
394  Kokkos::RangePolicy<ExecSpaceType, Kokkos::Schedule<Kokkos::Static> > policy(0, loopSize);
395 
396  switch (primaryCell.getKey()) {
397  case shards::Triangle<3>::key:
398  case shards::Quadrilateral<4>::key: {
399  // 2D polygon
401  Kokkos::parallel_for( policy, FunctorType(subcvCoords, cellCoords, edgeMap) );
402  break;
403  }
404  case shards::Hexahedron<8>::key: {
406  Kokkos::parallel_for( policy, FunctorType(subcvCoords, cellCoords, edgeMap, faceMap) );
407  break;
408  }
409  case shards::Tetrahedron<4>::key: {
411  Kokkos::parallel_for( policy, FunctorType(subcvCoords, cellCoords, edgeMap, faceMap) );
412  break;
413  }
414  default: {
415  INTREPID2_TEST_FOR_EXCEPTION( true, std::invalid_argument,
416  ">>> ERROR (Intrepid2::CellTools::getSubcvCoords: the give cell topology is not supported.");
417  }
418  }
419  }
420 }
421 
422 #endif
Functor for calculation of sub-control volume coordinates on hexahedra see Intrepid2::CellTools for m...
Functor for calculation of sub-control volume coordinates on polygons see Intrepid2::CellTools for mo...
Functor for calculation of sub-control volume coordinates on tetrahedra see Intrepid2::CellTools for ...
static void getSubcvCoords(Kokkos::DynRankView< subcvCoordValueType, subcvCoordProperties...> subcvCoords, const Kokkos::DynRankView< cellCoordValueType, cellCoordProperties...> cellCoords, const shards::CellTopology primaryCell)
Computes coordinates of sub-control volumes in each primary cell.