Intrepid2
Intrepid2_CellToolsDefControlVolume.hpp
Go to the documentation of this file.
1// @HEADER
2// ************************************************************************
3//
4// Intrepid2 Package
5// Copyright (2007) Sandia Corporation
6//
7// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8// license for use of this work by or on behalf of the U.S. Government.
9//
10// Redistribution and use in source and binary forms, with or without
11// modification, are permitted provided that the following conditions are
12// met:
13//
14// 1. Redistributions of source code must retain the above copyright
15// notice, this list of conditions and the following disclaimer.
16//
17// 2. Redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution.
20//
21// 3. Neither the name of the Corporation nor the names of the
22// contributors may be used to endorse or promote products derived from
23// this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36//
37// Questions? Contact Kyungjoo Kim (kyukim@sandia.gov), or
38// Mauro Perego (mperego@sandia.gov)
39//
40// ************************************************************************
41// @HEADER
42
43
49#ifndef __INTREPID2_CELLTOOLS_DEF_CONTROL_VOLUME_HPP__
50#define __INTREPID2_CELLTOOLS_DEF_CONTROL_VOLUME_HPP__
51
52// disable clang warnings
53#if defined (__clang__) && !defined (__INTEL_COMPILER)
54#pragma clang system_header
55#endif
56
57namespace Intrepid2 {
58
59 //============================================================================================//
60 // //
61 // Control Volume Coordinates //
62 // //
63 //============================================================================================//
64
65 namespace FunctorCellTools {
66
71 template<typename centerViewType, typename vertViewType>
72 KOKKOS_INLINE_FUNCTION
73 void getBaryCenter( centerViewType center,
74 const vertViewType verts) {
75 // the enumeration already assumes the ordering of vertices (circling around the polygon)
76 const ordinal_type nvert = verts.extent(0);
77 const ordinal_type dim = verts.extent(1);
78
79 switch (dim) {
80 case 2: {
81 center(0) = 0;
82 center(1) = 0;
83 typename centerViewType::value_type area = 0;
84 for (ordinal_type i=0;i<nvert;++i) {
85 const ordinal_type j = (i + 1)%nvert;
86 const auto scale = verts(i,0)*verts(j,1) - verts(j,0)*verts(i,1);
87 center(0) += (verts(i,0) + verts(j,0))*scale;
88 center(1) += (verts(i,1) + verts(j,1))*scale;
89 area += 0.5*scale;
90 }
91 center(0) /= (6.0*area);
92 center(1) /= (6.0*area);
93 break;
94 }
95 case 3: {
96 // This method works fine for simplices, but for other 3-d shapes
97 // is not precisely accurate. Could replace with approximate integration
98 // perhaps.
99 for (ordinal_type j=0;j<dim;++j) {
100 center(j) = 0;
101 for (ordinal_type i=0;i<nvert;++i)
102 center(j) += verts(i,j);
103 center(j) /= nvert;
104 }
105 break;
106 }
107 }
108 }
109
110 template<typename midPointViewType, typename nodeMapViewType, typename vertViewType>
111 KOKKOS_INLINE_FUNCTION
112 void getMidPoints( midPointViewType midpts,
113 const nodeMapViewType map,
114 const vertViewType verts) {
115 const ordinal_type npts = map.extent(0);
116 const ordinal_type dim = verts.extent(1);
117
118 for (ordinal_type i=0;i<npts;++i) {
119 // first entry is the number of subcell vertices
120 const ordinal_type nvert_per_subcell = map(i, 0);
121 for (ordinal_type j=0;j<dim;++j) {
122 midpts(i,j) = 0;
123 for (ordinal_type k=1;k<=nvert_per_subcell;++k)
124 midpts(i,j) += verts(map(i,k),j);
125 midpts(i,j) /= nvert_per_subcell;
126 }
127 }
128 }
129
130 template<typename subcvCoordViewType,
131 typename cellCoordViewType,
132 typename mapViewType>
137 subcvCoordViewType _subcvCoords;
138 const cellCoordViewType _cellCoords;
139 const mapViewType _edgeMap;
140
141 KOKKOS_INLINE_FUNCTION
142 F_getSubcvCoords_Polygon2D( subcvCoordViewType subcvCoords_,
143 cellCoordViewType cellCoords_,
144 mapViewType edgeMap_ )
145 : _subcvCoords(subcvCoords_), _cellCoords(cellCoords_), _edgeMap(edgeMap_) {}
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[2], buf_midpts[4*2];
162 Kokkos::View<value_type*,Kokkos::Impl::ActiveExecutionMemorySpace> center(buf_center, 2);
163 Kokkos::View<value_type**,Kokkos::Impl::ActiveExecutionMemorySpace> midpts(buf_midpts, 4, 2);
164
165 getBaryCenter(center, verts);
166 getMidPoints(midpts, _edgeMap, verts);
167
168 for (ordinal_type i=0;i<nvert;++i) {
169 for (ordinal_type j=0;j<dim;++j) {
170 // control volume is always quad
171 cvCoords(i, 0, j) = verts(i, j);
172 cvCoords(i, 1, j) = midpts(i, j);
173 cvCoords(i, 2, j) = center(j);
174 cvCoords(i, 3, j) = midpts((i+nvert-1)%nvert, j);
175 }
176 }
177 }
178 };
179
180 template<typename subcvCoordViewType,
181 typename cellCoordViewType,
182 typename mapViewType>
187 subcvCoordViewType _subcvCoords;
188 const cellCoordViewType _cellCoords;
189 const mapViewType _edgeMap, _faceMap;
190
191 KOKKOS_INLINE_FUNCTION
192 F_getSubcvCoords_Hexahedron( subcvCoordViewType subcvCoords_,
193 cellCoordViewType cellCoords_,
194 mapViewType edgeMap_,
195 mapViewType faceMap_ )
196 : _subcvCoords(subcvCoords_), _cellCoords(cellCoords_), _edgeMap(edgeMap_), _faceMap(faceMap_) {}
197
198 KOKKOS_INLINE_FUNCTION
199 void operator()(const ordinal_type cell) const {
200 // vertices of cell (P,D)
201 const auto verts = Kokkos::subdynrankview( _cellCoords, cell,
202 Kokkos::ALL(), Kokkos::ALL() );
203 // const ordinal_type nvert = verts.extent(0);
204 const ordinal_type dim = verts.extent(1);
205
206 // control volume coords (N,P,D), here N corresponds to cell vertices
207 auto cvCoords = Kokkos::subdynrankview( _subcvCoords, cell,
208 Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL() );
209
210 // work space for barycenter and midpoints on edges
211 typedef typename subcvCoordViewType::value_type value_type;
212 value_type buf_center[3], buf_edge_midpts[12*3], buf_face_midpts[6*3];
213 Kokkos::View<value_type*,Kokkos::Impl::ActiveExecutionMemorySpace> center(buf_center, 3);
214 Kokkos::View<value_type**,Kokkos::Impl::ActiveExecutionMemorySpace> edge_midpts(buf_edge_midpts, 12, 3);
215 Kokkos::View<value_type**,Kokkos::Impl::ActiveExecutionMemorySpace> face_midpts(buf_face_midpts, 6, 3);
216
217 getBaryCenter(center, verts);
218 getMidPoints(edge_midpts, _edgeMap, verts);
219 getMidPoints(face_midpts, _faceMap, verts);
220
221 for (ordinal_type i=0;i<4;++i) {
222 const ordinal_type ii = (i+4-1)%4;
223 for (ordinal_type j=0;j<dim;++j) {
224
225 // set first node of bottom hex to primary cell node
226 // and fifth node of upper hex
227 cvCoords(i, 0,j) = verts(i, j);
228 cvCoords(i+4,4,j) = verts(i+4,j);
229
230 // set second node of bottom hex to adjacent edge midpoint
231 // and sixth node of upper hex
232 cvCoords(i, 1,j) = edge_midpts(i, j);
233 cvCoords(i+4,5,j) = edge_midpts(i+4,j);
234
235 // set third node of bottom hex to bottom face midpoint (number 4)
236 // and seventh node of upper hex to top face midpoint
237 cvCoords(i, 2,j) = face_midpts(4,j);
238 cvCoords(i+4,6,j) = face_midpts(5,j);
239
240 // set fourth node of bottom hex to other adjacent edge midpoint
241 // and eight node of upper hex to other adjacent edge midpoint
242 cvCoords(i, 3,j) = edge_midpts(ii, j);
243 cvCoords(i+4,7,j) = edge_midpts(ii+4,j);
244
245 // set fifth node to vertical edge
246 // same as first node of upper hex
247 cvCoords(i, 4,j) = edge_midpts(i+8,j);
248 cvCoords(i+4,0,j) = edge_midpts(i+8,j);
249
250 // set sixth node to adjacent face midpoint
251 // same as second node of upper hex
252 cvCoords(i, 5,j) = face_midpts(i,j);
253 cvCoords(i+4,1,j) = face_midpts(i,j);
254
255 // set seventh node to barycenter
256 // same as third node of upper hex
257 cvCoords(i, 6,j) = center(j);
258 cvCoords(i+4,2,j) = center(j);
259
260 // set eighth node to other adjacent face midpoint
261 // same as fourth node of upper hex
262 cvCoords(i, 7,j) = face_midpts(ii,j);
263 cvCoords(i+4,3,j) = face_midpts(ii,j);
264 }
265 }
266 }
267 };
268
269
270 template<typename subcvCoordViewType,
271 typename cellCoordViewType,
272 typename mapViewType>
277 subcvCoordViewType _subcvCoords;
278 const cellCoordViewType _cellCoords;
279 const mapViewType _edgeMap, _faceMap;
280
281 KOKKOS_INLINE_FUNCTION
282 F_getSubcvCoords_Tetrahedron( subcvCoordViewType subcvCoords_,
283 cellCoordViewType cellCoords_,
284 mapViewType edgeMap_,
285 mapViewType faceMap_ )
286 : _subcvCoords(subcvCoords_), _cellCoords(cellCoords_), _edgeMap(edgeMap_), _faceMap(faceMap_) {}
287
288 KOKKOS_INLINE_FUNCTION
289 void operator()(const ordinal_type cell) const {
290 // ** vertices of cell (P,D)
291 const auto verts = Kokkos::subdynrankview( _cellCoords, cell,
292 Kokkos::ALL(), Kokkos::ALL() );
293 //const ordinal_type nvert = verts.extent(0);
294 const ordinal_type dim = verts.extent(1);
295
296 // control volume coords (N,P,D), here N corresponds to cell vertices
297 auto cvCoords = Kokkos::subdynrankview( _subcvCoords, cell,
298 Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL() );
299
300 // work space for barycenter and midpoints on edges
301 typedef typename subcvCoordViewType::value_type value_type;
302 value_type buf_center[3], buf_edge_midpts[6*3], buf_face_midpts[4*3];
303 Kokkos::View<value_type*,Kokkos::Impl::ActiveExecutionMemorySpace> center(buf_center, 3);
304 Kokkos::View<value_type**,Kokkos::Impl::ActiveExecutionMemorySpace> edge_midpts(buf_edge_midpts, 6, 3);
305 Kokkos::View<value_type**,Kokkos::Impl::ActiveExecutionMemorySpace> face_midpts(buf_face_midpts, 4, 3);
306
307 getBaryCenter(center, verts);
308 getMidPoints(edge_midpts, _edgeMap, verts);
309 getMidPoints(face_midpts, _faceMap, verts);
310
311 for (ordinal_type i=0;i<3;++i) {
312 const ordinal_type ii = (i+3-1)%3;
313 for (ordinal_type j=0;j<dim;++j) {
314 // set first node of bottom hex to primary cell node
315 cvCoords(i,0,j) = verts(i,j);
316
317 // set second node of bottom hex to adjacent edge midpoint
318 cvCoords(i,1,j) = edge_midpts(i,j);
319
320 // set third node of bottom hex to bottom face midpoint (number 3)
321 cvCoords(i,2,j) = face_midpts(3,j);
322
323 // set fourth node of bottom hex to other adjacent edge midpoint
324 cvCoords(i,3,j) = edge_midpts(ii,j);
325
326 // set fifth node to vertical edge
327 cvCoords(i,4,j) = edge_midpts(i+3,j);
328
329 // set sixth node to adjacent face midpoint
330 cvCoords(i,5,j) = face_midpts(i,j);
331
332 // set seventh node to barycenter
333 cvCoords(i,6,j) = center(j);
334
335 // set eighth node to other adjacent face midpoint
336 cvCoords(i,7,j) = face_midpts(ii,j);
337 }
338 }
339
340 for (ordinal_type j=0;j<dim;++j) {
341 // Control volume attached to fourth node
342 // set first node of bottom hex to primary cell node
343 cvCoords(3,0,j) = verts(3,j);
344
345 // set second node of bottom hex to adjacent edge midpoint
346 cvCoords(3,1,j) = edge_midpts(3,j);
347
348 // set third node of bottom hex to bottom face midpoint (number 3)
349 cvCoords(3,2,j) = face_midpts(2,j);
350
351 // set fourth node of bottom hex to other adjacent edge midpoint
352 cvCoords(3,3,j) = edge_midpts(5,j);
353
354 // set fifth node to vertical edge
355 cvCoords(3,4,j) = edge_midpts(4,j);
356
357 // set sixth node to adjacent face midpoint
358 cvCoords(3,5,j) = face_midpts(0,j);
359
360 // set seventh node to barycenter
361 cvCoords(3,6,j) = center(j);
362
363 // set eighth node to other adjacent face midpoint
364 cvCoords(3,7,j) = face_midpts(1,j);
365 }
366 }
367 };
368
369 }
370
371 template<typename DeviceType>
372 template<typename subcvCoordValueType, class ...subcvCoordProperties,
373 typename cellCoordValueType, class ...cellCoordProperties>
374 void
376 getSubcvCoords( Kokkos::DynRankView<subcvCoordValueType,subcvCoordProperties...> subcvCoords,
377 const Kokkos::DynRankView<cellCoordValueType,cellCoordProperties...> cellCoords,
378 const shards::CellTopology primaryCell ) {
379#ifdef HAVE_INTREPID2_DEBUG
380 INTREPID2_TEST_FOR_EXCEPTION( !hasReferenceCell(primaryCell), std::invalid_argument,
381 ">>> ERROR (Intrepid2::CellTools::getSubcvCoords): the primary cell must have a reference cell." );
382
383 INTREPID2_TEST_FOR_EXCEPTION( cellCoords.extent(1) != primaryCell.getVertexCount(), std::invalid_argument,
384 ">>> ERROR (Intrepid2::CellTools::getSubcvCoords): cell coords dimension(1) does not match to # of vertices of the cell." );
385
386 INTREPID2_TEST_FOR_EXCEPTION( cellCoords.extent(2) != primaryCell.getDimension(), std::invalid_argument,
387 ">>> ERROR (Intrepid2::CellTools::getSubcvCoords): cell coords dimension(2) does not match to the dimension of the cell." );
388#endif
389 constexpr bool are_accessible =
390 Kokkos::Impl::MemorySpaceAccess<MemSpaceType,
391 typename decltype(subcvCoords)::memory_space>::accessible &&
392 Kokkos::Impl::MemorySpaceAccess<MemSpaceType,
393 typename decltype(cellCoords)::memory_space>::accessible;
394 static_assert(are_accessible, "CellTools<DeviceType>::getSubcvCoords(..): input/output views' memory spaces are not compatible with DeviceType");
395
396
397 // get array dimensions
398 const ordinal_type numCells = cellCoords.extent(0);
399 //const ordinal_type numVerts = cellCoords.extent(1);
400 const ordinal_type spaceDim = cellCoords.extent(2);
401
402 // construct edge and face map for the cell type
403 const ordinal_type numEdge = primaryCell.getSubcellCount(1);
404 Kokkos::View<ordinal_type**,DeviceType> edgeMap("CellTools::getSubcvCoords::edgeMap", numEdge, 3);
405 auto edgeMapHost = Kokkos::create_mirror_view(edgeMap);
406 for (ordinal_type i=0;i<numEdge;++i) {
407 edgeMapHost(i,0) = primaryCell.getNodeCount(1, i);
408 for (ordinal_type j=0;j<edgeMapHost(i,0);++j)
409 edgeMapHost(i,j+1) = primaryCell.getNodeMap(1, i, j);
410 }
411
412 const ordinal_type numFace = (spaceDim > 2 ? primaryCell.getSubcellCount(2) : 0);
413 Kokkos::View<ordinal_type**,DeviceType> faceMap("CellTools::getSubcvCoords::faceMap", numFace, 5);
414 auto faceMapHost = Kokkos::create_mirror_view(faceMap);
415 for (ordinal_type i=0;i<numFace;++i) {
416 faceMapHost(i,0) = primaryCell.getNodeCount(2, i);
417 for (ordinal_type j=0;j<faceMapHost(i,0);++j)
418 faceMapHost(i,j+1) = primaryCell.getNodeMap(2, i, j);
419 }
420
421 Kokkos::deep_copy(edgeMap, edgeMapHost);
422 Kokkos::deep_copy(faceMap, faceMapHost);
423
424 // parallel run
425 using subcvCoordViewType = decltype(subcvCoords);
426 using cellCoordViewType = decltype(cellCoords);
427 using mapViewType = decltype(edgeMap);
428
429 const auto loopSize = numCells;
430 Kokkos::RangePolicy<ExecSpaceType, Kokkos::Schedule<Kokkos::Static> > policy(0, loopSize);
431
432 switch (primaryCell.getKey()) {
433 case shards::Triangle<3>::key:
434 case shards::Quadrilateral<4>::key: {
435 // 2D polygon
437 Kokkos::parallel_for( policy, FunctorType(subcvCoords, cellCoords, edgeMap) );
438 break;
439 }
440 case shards::Hexahedron<8>::key: {
442 Kokkos::parallel_for( policy, FunctorType(subcvCoords, cellCoords, edgeMap, faceMap) );
443 break;
444 }
445 case shards::Tetrahedron<4>::key: {
447 Kokkos::parallel_for( policy, FunctorType(subcvCoords, cellCoords, edgeMap, faceMap) );
448 break;
449 }
450 default: {
451 INTREPID2_TEST_FOR_EXCEPTION( true, std::invalid_argument,
452 ">>> ERROR (Intrepid2::CellTools::getSubcvCoords: the give cell topology is not supported.");
453 }
454 }
455 }
456}
457
458#endif
KOKKOS_INLINE_FUNCTION void getBaryCenter(centerViewType center, const vertViewType verts)
Computes cell barycenter.
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 ...