VTK-m  2.0
CellOddyMetric.h
Go to the documentation of this file.
1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 // This software is distributed WITHOUT ANY WARRANTY; without even
6 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
7 // PURPOSE. See the above copyright notice for more information.
8 //
9 // Copyright 2018 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
10 // Copyright 2018 UT-Battelle, LLC.
11 // Copyright 2018 Los Alamos National Security.
12 //
13 // Under the terms of Contract DE-NA0003525 with NTESS,
14 // the U.S. Government retains certain rights in this software.
15 //
16 // Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
17 // Laboratory (LANL), the U.S. Government retains certain rights in
18 // this software.
19 //============================================================================
20 #ifndef vtk_m_worklet_cellmetrics_Oddy_h
21 #define vtk_m_worklet_cellmetrics_Oddy_h
22 
23 /*
24 * Mesh quality metric functions that compute the Oddy of mesh cells.
25 ** These metric computations are adapted from the VTK implementation of the Verdict library,
26 * which provides a set of mesh/cell metrics for evaluating the geometric qualities of regions
27 * of mesh spaces.
28 ** See: The Verdict Library Reference Manual (for per-cell-type metric formulae)
29 * See: vtk/ThirdParty/verdict/vtkverdict (for VTK code implementation of this metric)
30 */
31 
32 #include "TypeOfCellHexahedral.h"
34 #include "TypeOfCellTetrahedral.h"
35 #include "TypeOfCellTriangle.h"
36 #include <vtkm/CellShape.h>
37 #include <vtkm/CellTraits.h>
38 #include <vtkm/ErrorCode.h>
39 #include <vtkm/VecTraits.h>
40 #include <vtkm/VectorAnalysis.h>
41 
42 #define UNUSED(expr) (void)(expr);
43 
44 namespace vtkm
45 {
46 namespace worklet
47 {
48 namespace cellmetrics
49 {
50 // ========================= Unsupported cells ==================================
51 
52 // By default, cells have zero shape unless the shape type template is specialized below.
53 template <typename OutType, typename PointCoordVecType, typename CellShapeType>
55  const PointCoordVecType& pts,
56  CellShapeType shape,
58 {
59  UNUSED(numPts);
60  UNUSED(pts);
61  UNUSED(shape);
62  return OutType(-1.0);
63 }
64 
65 // ========================= 2D cells ==================================
66 // Compute the Oddy of a quadrilateral.
67 // Formula: for i 0 to 3: max{[(||Li||^2 - ||Li+1||^2)^2 + 4((Li * Li+1)^2)] / (2||Ni+1||^2)}
68 // - L4 = L0
69 // - '*' symbolizes the dot product of two vectors
70 // - Ni is the normal vector associated with each point
71 // Equals 0 for a unit square
72 // Acceptable range: [0,0.5]
73 // Normal range: [0,FLOAT_MAX]
74 // Full range: [0,FLOAT_MAX]
75 // Note, for loop avoided because L4 = L0
76 template <typename Scalar, typename Vector>
77 VTKM_EXEC Scalar GetQuadOddyQi(const Vector& Li, const Vector& LiPlus1, const Vector& NiPlus1)
78 {
79  const Scalar two(2.0);
80  const Scalar four(4.0);
81  const Scalar liMagnitudeSquared = static_cast<Scalar>(vtkm::MagnitudeSquared(Li));
82  const Scalar liPlus1MagnitudeSquared = static_cast<Scalar>(vtkm::MagnitudeSquared(LiPlus1));
83  const Scalar niPlus1MagnitudeSquared = static_cast<Scalar>(vtkm::MagnitudeSquared(NiPlus1));
84  const Scalar q = (((liMagnitudeSquared - liPlus1MagnitudeSquared) *
85  (liMagnitudeSquared - liPlus1MagnitudeSquared)) +
86  (four * static_cast<Scalar>(vtkm::Dot(Li, LiPlus1) * vtkm::Dot(Li, LiPlus1)))) /
87  (two * niPlus1MagnitudeSquared);
88 
89  return q;
90 }
91 template <typename OutType, typename PointCoordVecType>
93  const PointCoordVecType& pts,
94  vtkm::CellShapeTagQuad,
95  vtkm::ErrorCode& ec)
96 {
97  if (numPts != 4)
98  {
100  return OutType(0.0);
101  }
102 
103  using Scalar = OutType;
104  using CollectionOfPoints = PointCoordVecType;
105  using Vector = typename PointCoordVecType::ComponentType;
106 
107  const Vector L0 = GetQuadL0<Scalar, Vector, CollectionOfPoints>(pts);
108  const Vector L1 = GetQuadL1<Scalar, Vector, CollectionOfPoints>(pts);
109  const Vector L2 = GetQuadL2<Scalar, Vector, CollectionOfPoints>(pts);
110  const Vector L3 = GetQuadL3<Scalar, Vector, CollectionOfPoints>(pts);
111  const Vector N0 = GetQuadN0<Scalar, Vector, CollectionOfPoints>(pts);
112  const Vector N1 = GetQuadN1<Scalar, Vector, CollectionOfPoints>(pts);
113  const Vector N2 = GetQuadN2<Scalar, Vector, CollectionOfPoints>(pts);
114  const Vector N3 = GetQuadN3<Scalar, Vector, CollectionOfPoints>(pts);
115 
116  if (vtkm::MagnitudeSquared(N0) <= Scalar(0.0) || vtkm::MagnitudeSquared(N1) <= Scalar(0.0) ||
117  vtkm::MagnitudeSquared(N2) <= Scalar(0.0) || vtkm::MagnitudeSquared(N3) <= Scalar(0.0))
118  {
119  return vtkm::Infinity<Scalar>();
120  }
121 
122  const Scalar q0 = GetQuadOddyQi<Scalar, Vector>(L0, L1, N1);
123  const Scalar q1 = GetQuadOddyQi<Scalar, Vector>(L1, L2, N2);
124  const Scalar q2 = GetQuadOddyQi<Scalar, Vector>(L2, L3, N3);
125  const Scalar q3 = GetQuadOddyQi<Scalar, Vector>(L3, L0, N0);
126 
127  const Scalar q = vtkm::Max(q0, vtkm::Max(q1, vtkm::Max(q2, q3)));
128  return q;
129 }
130 
131 // ============================= 3D Volume cells ==================================
132 // Compute the Oddy of a hexahedron.
133 // Formula:
134 // Equals 0 for a unit cube
135 // Acceptable Range: [0, 0.5]
136 // Normal range: [0,FLOAT_MAX]
137 // Full range: [0,FLOAT_MAX]
138 template <typename OutType, typename PointCoordVecType>
140  const PointCoordVecType& pts,
141  vtkm::CellShapeTagHexahedron,
142  vtkm::ErrorCode& ec)
143 {
144  if (numPts != 8)
145  {
147  return OutType(0.0);
148  }
149 
150  //The 12 points of a hexahedron
151  using Edge = typename PointCoordVecType::ComponentType;
152  const Edge HexEdges[12] = {
153  pts[1] - pts[0], // 0
154  pts[2] - pts[1], pts[3] - pts[2],
155  pts[3] - pts[0], // 3
156  pts[4] - pts[0], pts[5] - pts[1],
157  pts[6] - pts[2], // 6
158  pts[7] - pts[3], pts[5] - pts[4],
159  pts[6] - pts[5], // 9
160  pts[7] - pts[6],
161  pts[7] - pts[4] // 11
162  };
163 
164  Edge principleXAxis = HexEdges[0] + (pts[2] - pts[3]) + HexEdges[8] + (pts[6] - pts[7]);
165  Edge principleYAxis = (pts[3] - pts[0]) + HexEdges[1] + (pts[7] - pts[4]) + HexEdges[9];
166  Edge principleZAxis = HexEdges[4] + HexEdges[5] + HexEdges[6] + HexEdges[7];
167  Edge hexJacobianMatrices[9][3] = {
168  { HexEdges[0], HexEdges[3], HexEdges[4] },
169  { HexEdges[1], (-1 * HexEdges[0]), HexEdges[5] },
170  { HexEdges[2], (-1 * HexEdges[1]), HexEdges[6] },
171  { (-1 * HexEdges[3]), (-1 * HexEdges[2]), HexEdges[7] },
172  { HexEdges[11], HexEdges[8], (-1 * HexEdges[4]) },
173  { (-1 * HexEdges[8]), HexEdges[9], (-1 * HexEdges[5]) },
174  { (-1 * HexEdges[9]), HexEdges[10], (-1 * HexEdges[6]) },
175  { (-1 * HexEdges[10]), (-1 * HexEdges[11]), (-1 * HexEdges[7]) },
176  { principleXAxis, principleYAxis, principleZAxis }
177  };
178 
179  OutType third = (OutType)(1.0 / 3.0);
180  OutType negativeInfinity = vtkm::NegativeInfinity<OutType>();
181  OutType tempMatrix1_1, tempMatrix1_2, tempMatrix1_3, tempMatrix2_2, tempMatrix2_3, tempMatrix3_3,
182  determinant;
183  OutType firstPartOfNumerator, secondPartOfNumerator, currentOddy, maxOddy = negativeInfinity;
184  for (vtkm::IdComponent matrixNumber = 0; matrixNumber < 9; matrixNumber++)
185  {
186  /*
187  // these computations equal the value at X_Y for the matrix B,
188  // where B = matrix A multiplied by its transpose.
189  // the values at X_X are also used for the matrix multiplication AA.
190  // Note that the values 1_2 = 2_1, 1_3 = 3_1, and 2_3 = 3_2.
191  // This fact is used to optimize the computation
192  */
193  tempMatrix1_1 = static_cast<OutType>(
194  vtkm::Dot(hexJacobianMatrices[matrixNumber][0], hexJacobianMatrices[matrixNumber][0]));
195  tempMatrix1_2 = static_cast<OutType>(
196  vtkm::Dot(hexJacobianMatrices[matrixNumber][0], hexJacobianMatrices[matrixNumber][1]));
197  tempMatrix1_3 = static_cast<OutType>(
198  vtkm::Dot(hexJacobianMatrices[matrixNumber][0], hexJacobianMatrices[matrixNumber][2]));
199  tempMatrix2_2 = static_cast<OutType>(
200  vtkm::Dot(hexJacobianMatrices[matrixNumber][1], hexJacobianMatrices[matrixNumber][1]));
201  tempMatrix2_3 = static_cast<OutType>(
202  vtkm::Dot(hexJacobianMatrices[matrixNumber][1], hexJacobianMatrices[matrixNumber][2]));
203  tempMatrix3_3 = static_cast<OutType>(
204  vtkm::Dot(hexJacobianMatrices[matrixNumber][2], hexJacobianMatrices[matrixNumber][2]));
205  determinant = static_cast<OutType>(vtkm::Dot(
206  hexJacobianMatrices[matrixNumber][0],
207  vtkm::Cross(hexJacobianMatrices[matrixNumber][1], hexJacobianMatrices[matrixNumber][2])));
208  if (determinant <= OutType(0.0))
209  {
210  return vtkm::Infinity<OutType>();
211  }
212  else
213  {
214  firstPartOfNumerator = (tempMatrix1_1 * tempMatrix1_1) + 2 * (tempMatrix1_2 * tempMatrix1_2) +
215  2 * (tempMatrix1_3 * tempMatrix1_3) + (tempMatrix2_2 * tempMatrix2_2) +
216  2 * (tempMatrix2_3 * tempMatrix2_3) + (tempMatrix3_3 * tempMatrix3_3);
217  secondPartOfNumerator = tempMatrix1_1 + tempMatrix2_2 + tempMatrix3_3;
218  secondPartOfNumerator *= secondPartOfNumerator;
219  secondPartOfNumerator *= third;
220  currentOddy = (firstPartOfNumerator - secondPartOfNumerator) /
221  (vtkm::Pow(determinant, OutType(4.0 * third)));
222  maxOddy = currentOddy > maxOddy ? currentOddy : maxOddy;
223  }
224  }
225  if (maxOddy > 0)
226  {
227  return vtkm::Min(maxOddy, vtkm::Infinity<OutType>()); //normal case
228  }
229 
230  return vtkm::Max(maxOddy, negativeInfinity);
231 }
232 } // namespace cellmetrics
233 } // namespace worklet
234 } // namespace vtkm
235 #endif // vtk_m_worklet_cellmetrics_Oddy_h
vtkm::ErrorCode
ErrorCode
Definition: ErrorCode.h:19
vtkm::MagnitudeSquared
VTKM_EXEC_CONT detail::FloatingPointReturnType< T >::Type MagnitudeSquared(const T &x)
Returns the square of the magnitude of a vector.
Definition: VectorAnalysis.h:64
VTKM_EXEC
#define VTKM_EXEC
Definition: ExportMacros.h:51
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
vtkm::IdComponent
vtkm::Int32 IdComponent
Represents a component ID (index of component in a vector).
Definition: Types.h:168
CellShape.h
ErrorCode.h
VectorAnalysis.h
UNUSED
#define UNUSED(expr)
Definition: CellOddyMetric.h:42
vtkm::worklet::cellmetrics::CellOddyMetric
VTKM_EXEC OutType CellOddyMetric(const vtkm::IdComponent &numPts, const PointCoordVecType &pts, CellShapeType shape, vtkm::ErrorCode &)
Definition: CellOddyMetric.h:54
vtkm::Cross
VTKM_EXEC_CONT vtkm::Vec< typename detail::FloatingPointReturnType< T >::Type, 3 > Cross(const vtkm::Vec< T, 3 > &x, const vtkm::Vec< T, 3 > &y)
Find the cross product of two vectors.
Definition: VectorAnalysis.h:177
TypeOfCellTetrahedral.h
TypeOfCellTriangle.h
TypeOfCellHexahedral.h
TypeOfCellQuadrilateral.h
vtkm::worklet::cellmetrics::GetQuadOddyQi
VTKM_EXEC Scalar GetQuadOddyQi(const Vector &Li, const Vector &LiPlus1, const Vector &NiPlus1)
Definition: CellOddyMetric.h:77
CellTraits.h
VecTraits.h
vtkm::ErrorCode::InvalidNumberOfPoints
@ InvalidNumberOfPoints