Intrepid2
Intrepid2_OrientationToolsDefModifyBasis.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 
48 #ifndef __INTREPID2_ORIENTATIONTOOLS_DEF_MODIFY_BASIS_HPP__
49 #define __INTREPID2_ORIENTATIONTOOLS_DEF_MODIFY_BASIS_HPP__
50 
51 // disable clang warnings
52 #if defined (__clang__) && !defined (__INTEL_COMPILER)
53 #pragma clang system_header
54 #endif
55 
56 namespace Intrepid2 {
57 
58  template<typename SpT>
59  template<typename ptViewType>
60  KOKKOS_INLINE_FUNCTION
62  isLeftHandedCell(const ptViewType pts) {
63 #ifdef HAVE_INTREPID2_DEBUG
64  INTREPID2_TEST_FOR_ABORT( pts.rank() != 2, // npts x ndim
65  ">>> ERROR (Intrepid::OrientationTools::isLeftHandedCell): " \
66  "Point array is supposed to have rank 2.");
67 #endif
68  typedef typename ptViewType::value_type value_type;
69 
70  const auto dim = pts.extent(1);
71  value_type det = 0.0;
72  switch (dim) {
73  case 2: {
74  // need 3 points (origin, x end point, y end point)
75  const value_type v[2][2] = { { pts(1,0) - pts(0,0), pts(1,1) - pts(0,1) },
76  { pts(2,0) - pts(0,0), pts(2,1) - pts(0,1) } };
77 
78  det = (v[0][0]*v[1][1] - v[1][0]*v[0][1]);
79  break;
80  }
81  case 3: {
82  // need 4 points (origin, x end point, y end point, z end point)
83  const value_type v[3][3] = { { pts(1,0) - pts(0,0), pts(1,1) - pts(0,1), pts(1,2) - pts(0,2) },
84  { pts(2,0) - pts(0,0), pts(2,1) - pts(0,1), pts(2,2) - pts(0,2) },
85  { pts(3,0) - pts(0,0), pts(3,1) - pts(0,1), pts(3,2) - pts(0,2) } };
86 
87  det = (v[0][0] * v[1][1] * v[2][2] +
88  v[0][1] * v[1][2] * v[2][0] +
89  v[0][2] * v[1][0] * v[2][1] -
90  v[0][2] * v[1][1] * v[2][0] -
91  v[0][0] * v[1][2] * v[2][1] -
92  v[0][1] * v[1][0] * v[2][2]);
93  break;
94  }
95  default:{
96  INTREPID2_TEST_FOR_ABORT( true,
97  ">>> ERROR (Intrepid::Orientation::isLeftHandedCell): " \
98  "Dimension of points must be 2 or 3");
99  }
100  }
101  return (det < 0.0);
102  }
103 
104  template<typename SpT>
105  template<typename elemOrtValueType, class ...elemOrtProperties,
106  typename elemNodeValueType, class ...elemNodeProperties>
107  void
109  getOrientation( Kokkos::DynRankView<elemOrtValueType,elemOrtProperties...> elemOrts,
110  const Kokkos::DynRankView<elemNodeValueType,elemNodeProperties...> elemNodes,
111  const shards::CellTopology cellTopo) {
112  // small meta data modification and it uses shards; let's do this on host
113  typedef typename Kokkos::Impl::is_space<SpT>::host_mirror_space::execution_space host_space_type;
114  auto elemOrtsHost = Kokkos::create_mirror_view(typename host_space_type::memory_space(), elemOrts);
115  auto elemNodesHost = Kokkos::create_mirror_view_and_copy(typename host_space_type::memory_space(), elemNodes);
116 
117  const ordinal_type numCells = elemNodes.extent(0);
118  for (auto cell=0;cell<numCells;++cell) {
119  const auto nodes = Kokkos::subview(elemNodesHost, cell, Kokkos::ALL());
120  elemOrtsHost(cell) = Orientation::getOrientation(cellTopo, nodes);
121  }
122 
123  Kokkos::deep_copy(elemOrts, elemOrtsHost);
124  }
125 
126  template<typename ortViewType,
127  typename OutputViewType,
128  typename inputViewType,
129  typename o2tViewType,
130  typename t2oViewType,
131  typename dataViewType>
133  ortViewType orts;
134  OutputViewType output;
135  inputViewType input;
136  o2tViewType ordinalToTag;
137  t2oViewType tagToOrdinal;
138 
139  const dataViewType matData;
140  const ordinal_type cellDim, numVerts, numEdges, numFaces, numPoints, dimBasis;
141 
142  F_modifyBasisByOrientation(ortViewType orts_,
143  OutputViewType output_,
144  inputViewType input_,
145  o2tViewType ordinalToTag_,
146  t2oViewType tagToOrdinal_,
147  const dataViewType matData_,
148  const ordinal_type cellDim_,
149  const ordinal_type numVerts_,
150  const ordinal_type numEdges_,
151  const ordinal_type numFaces_,
152  const ordinal_type numPoints_,
153  const ordinal_type dimBasis_)
154  : orts(orts_),
155  output(output_),
156  input(input_),
157  ordinalToTag(ordinalToTag_),
158  tagToOrdinal(tagToOrdinal_),
159  matData(matData_),
160  cellDim(cellDim_),
161  numVerts(numVerts_),
162  numEdges(numEdges_),
163  numFaces(numFaces_),
164  numPoints(numPoints_),
165  dimBasis(dimBasis_)
166  {}
167 
168  KOKKOS_INLINE_FUNCTION
169  void operator()(const ordinal_type cell) const {
170  typedef typename inputViewType::non_const_value_type input_value_type;
171 
172  auto out = Kokkos::subview(output, cell, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL());
173  auto in = (input.rank() == output.rank()) ?
174  Kokkos::subview(input, cell, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL())
175  : Kokkos::subview(input, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL());
176 
177  // vertex copy (no orientation)
178  for (ordinal_type vertId=0;vertId<numVerts;++vertId) {
179  const ordinal_type i = (static_cast<size_type>(vertId) < tagToOrdinal.extent(1) ? tagToOrdinal(0, vertId, 0) : -1);
180  if (i != -1) // if dof does not exist i returns with -1
181  for (ordinal_type j=0;j<numPoints;++j)
182  for (ordinal_type k=0;k<dimBasis;++k)
183  out(i, j, k) = in(i, j, k);
184  }
185 
186  // interior copy
187  {
188  const ordinal_type ordIntr = (static_cast<size_type>(cellDim) < tagToOrdinal.extent(0) ? tagToOrdinal(cellDim, 0, 0) : -1);
189  if (ordIntr != -1) {
190  const ordinal_type ndofIntr = ordinalToTag(ordIntr, 3);
191  for (ordinal_type i=0;i<ndofIntr;++i) {
192  const ordinal_type ii = tagToOrdinal(cellDim, 0, i);
193  for (ordinal_type j=0;j<numPoints;++j)
194  for (ordinal_type k=0;k<dimBasis;++k)
195  out(ii, j, k) = in(ii, j, k);
196  }
197  }
198  }
199 
200  // edge transformation
201  ordinal_type existEdgeDofs = 0;
202  if (numEdges > 0) {
203  ordinal_type ortEdges[12];
204  orts(cell).getEdgeOrientation(ortEdges, numEdges);
205 
206  // apply coeff matrix
207  for (ordinal_type edgeId=0;edgeId<numEdges;++edgeId) {
208  const ordinal_type ordEdge = (1 < tagToOrdinal.extent(0) ? (static_cast<size_type>(edgeId) < tagToOrdinal.extent(1) ? tagToOrdinal(1, edgeId, 0) : -1) : -1);
209 
210  if (ordEdge != -1) {
211  existEdgeDofs = 1;
212  const ordinal_type ndofEdge = ordinalToTag(ordEdge, 3);
213  const auto mat = Kokkos::subview(matData,
214  edgeId, ortEdges[edgeId],
215  Kokkos::ALL(), Kokkos::ALL());
216 
217  for (ordinal_type j=0;j<numPoints;++j)
218  for (ordinal_type i=0;i<ndofEdge;++i) {
219  const ordinal_type ii = tagToOrdinal(1, edgeId, i);
220 
221  for (ordinal_type k=0;k<dimBasis;++k) {
222  input_value_type temp = 0.0;
223  for (ordinal_type l=0;l<ndofEdge;++l) {
224  const ordinal_type ll = tagToOrdinal(1, edgeId, l);
225  temp += mat(i,l)*in(ll, j, k);
226  }
227  out(ii, j, k) = temp;
228  }
229  }
230  }
231  }
232  }
233 
234  // face transformation
235  if (numFaces > 0) {
236  ordinal_type ortFaces[12];
237  orts(cell).getFaceOrientation(ortFaces, numFaces);
238 
239  // apply coeff matrix
240  for (ordinal_type faceId=0;faceId<numFaces;++faceId) {
241  const ordinal_type ordFace = (2 < tagToOrdinal.extent(0) ? (static_cast<size_type>(faceId) < tagToOrdinal.extent(1) ? tagToOrdinal(2, faceId, 0) : -1) : -1);
242 
243  if (ordFace != -1) {
244  const ordinal_type ndofFace = ordinalToTag(ordFace, 3);
245  const auto mat = Kokkos::subview(matData,
246  numEdges*existEdgeDofs+faceId, ortFaces[faceId],
247  Kokkos::ALL(), Kokkos::ALL());
248 
249  for (ordinal_type j=0;j<numPoints;++j)
250  for (ordinal_type i=0;i<ndofFace;++i) {
251  const ordinal_type ii = tagToOrdinal(2, faceId, i);
252 
253  for (ordinal_type k=0;k<dimBasis;++k) {
254  input_value_type temp = 0.0;
255  for (ordinal_type l=0;l<ndofFace;++l) {
256  const ordinal_type ll = tagToOrdinal(2, faceId, l);
257  temp += mat(i,l)*in(ll, j, k);
258  }
259  out(ii, j, k) = temp;
260  }
261  }
262  }
263  }
264  }
265  }
266  };
267 
268  template<typename SpT>
269  template<typename outputValueType, class ...outputProperties,
270  typename inputValueType, class ...inputProperties,
271  typename ortValueType, class ...ortProperties,
272  typename BasisType>
273  void
275  modifyBasisByOrientation( Kokkos::DynRankView<outputValueType,outputProperties...> output,
276  const Kokkos::DynRankView<inputValueType, inputProperties...> input,
277  const Kokkos::DynRankView<ortValueType, ortProperties...> orts,
278  const BasisType* basis ) {
279 #ifdef HAVE_INTREPID2_DEBUG
280  {
281  if (input.rank() == output.rank())
282  {
283  for (size_type i=0;i<input.rank();++i)
284  INTREPID2_TEST_FOR_EXCEPTION( input.extent(i) != output.extent(i), std::invalid_argument,
285  ">>> ERROR (OrientationTools::modifyBasisByOrientation): Input and output dimension does not match.");
286  }
287  else if (input.rank() == output.rank() - 1)
288  {
289  for (size_type i=0;i<input.rank();++i)
290  INTREPID2_TEST_FOR_EXCEPTION( input.extent(i) != output.extent(i+1), std::invalid_argument,
291  ">>> ERROR (OrientationTools::modifyBasisByOrientation): Input dimensions must match output dimensions exactly, or else match all but the first dimension (in the case that input does not have a 'cell' dimension).");
292  }
293  else
294  {
295  INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument,
296  ">>> ERROR (OrientationTools::modifyBasisByOrientation): input and output ranks must either match, or input rank must be one less than that of output.")
297  }
298 
299  INTREPID2_TEST_FOR_EXCEPTION( static_cast<ordinal_type>(output.extent(1)) != basis->getCardinality(), std::invalid_argument,
300  ">>> ERROR (OrientationTools::modifyBasisByOrientation): Field dimension of input/output does not match to basis cardinality.");
301  }
302 #endif
303 
304  if (basis->requireOrientation()) {
305  auto ordinalToTag = Kokkos::create_mirror_view(typename SpT::memory_space(), basis->getAllDofTags());
306  auto tagToOrdinal = Kokkos::create_mirror_view(typename SpT::memory_space(), basis->getAllDofOrdinal());
307 
308  Kokkos::deep_copy(ordinalToTag, basis->getAllDofTags());
309  Kokkos::deep_copy(tagToOrdinal, basis->getAllDofOrdinal());
310 
311  const ordinal_type
312  numCells = output.extent(0),
313  //numBasis = output.extent(1),
314  numPoints = output.extent(2),
315  dimBasis = output.extent(3); //returns 1 when output.rank() < 4;
316 
317  const CoeffMatrixDataViewType matData = createCoeffMatrix(basis);
318  const shards::CellTopology cellTopo = basis->getBaseCellTopology();
319 
320  const ordinal_type
321  cellDim = cellTopo.getDimension(),
322  numVerts = cellTopo.getVertexCount()*ordinal_type(basis->getDofCount(0, 0) > 0),
323  numEdges = cellTopo.getEdgeCount()*ordinal_type(basis->getDofCount(1, 0) > 0),
324  numFaces = cellTopo.getFaceCount();
325 
326  const Kokkos::RangePolicy<SpT> policy(0, numCells);
328  <decltype(orts),
329  decltype(output),decltype(input),
330  decltype(ordinalToTag),decltype(tagToOrdinal),
331  decltype(matData)> FunctorType;
332  Kokkos::parallel_for(policy,
333  FunctorType(orts,
334  output, input,
335  ordinalToTag, tagToOrdinal,
336  matData,
337  cellDim, numVerts, numEdges, numFaces,
338  numPoints, dimBasis));
339  } else {
340  Kokkos::deep_copy(output, input);
341  }
342  }
343 }
344 
345 #endif
static KOKKOS_INLINE_FUNCTION bool isLeftHandedCell(const ptViewType pts)
Check if left-handed. If an element is alinged left, it is an error.
static void modifyBasisByOrientation(Kokkos::DynRankView< outputValueType, outputProperties...> output, const Kokkos::DynRankView< inputValueType, inputProperties...> input, const Kokkos::DynRankView< ortValueType, ortProperties...> orts, const BasisType *basis)
Modify basis due to orientation.
Kokkos::View< double ****, ExecSpaceType > CoeffMatrixDataViewType
subcell ordinal, orientation, matrix m x n
static void getOrientation(Kokkos::DynRankView< elemOrtValueType, elemOrtProperties...> elemOrts, const Kokkos::DynRankView< elemNodeValueType, elemNodeProperties...> elemNodes, const shards::CellTopology cellTopo)
Compute orientations of cells in a workset.