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
24namespace 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
KOKKOS_INLINE_FUNCTION void getBarycenterPolygon2D(centerViewType center, const vertViewType verts)
Computes barycenter of polygonal cells.
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.
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 ...