ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_EBPolygon.H
Go to the documentation of this file.
1 /**
2  * \file ERF_EBPolygon.H
3  * \brief Defines polygon geometry utilities for EB cut-cell reconstruction.
4  */
5 #ifndef ERF_EB_POLYGON_H_
6 #define ERF_EB_POLYGON_H_
7 
8 #include <AMReX_REAL.H>
9 #include <AMReX_RealVect.H>
10 
11 #include <cmath>
12 #include "ERF_NumericalConstants.H"
13 
14 /**
15  * \brief Polygon helper used to accumulate cut-cell face geometry.
16  *
17  * The polygon stores up to six vertices, sorts them in a local plane, and
18  * computes area, centroid, distance, and normal data used by eb_cut_cell_.
19  */
20 class polygon_ {
21 
22  public:
23 
24  /**
25  * \brief Construct a cell-face polygon clipped by an EB plane.
26  * \param a_point Point on the EB plane.
27  * \param a_normal Unit normal for the EB plane.
28  */
29  AMREX_GPU_HOST_DEVICE
30  polygon_ ( amrex::RealVect a_point,
31  amrex::RealVect a_normal )
32  : m_cell_face(1)
33  , m_eb_point(a_point)
34  , m_eb_normal(a_normal)
35  , m_defined(0)
36  , m_num_vertices(0)
37  , m_area(zero)
38  , m_sorted(0)
39  , m_vertices({amrex::RealVect(zero), amrex::RealVect(zero), amrex::RealVect(zero),
40  amrex::RealVect(zero), amrex::RealVect(zero), amrex::RealVect(zero)})
41  , m_zdir(zero)
42  {}
43 
44  //! Construct an empty EB-boundary polygon.
45  AMREX_GPU_HOST_DEVICE
47  : m_cell_face(0)
48  , m_eb_point(zero)
49  , m_eb_normal(zero)
50  , m_defined(0)
51  , m_num_vertices(0)
52  , m_area(zero)
53  , m_sorted(0)
54  , m_vertices({amrex::RealVect(zero), amrex::RealVect(zero), amrex::RealVect(zero),
55  amrex::RealVect(zero), amrex::RealVect(zero), amrex::RealVect(zero)})
56  , m_zdir(zero)
57  {}
58 
59  /**
60  * \brief Add a unique vertex to the polygon.
61  * \param a_v Vertex coordinates.
62  */
63  AMREX_GPU_HOST_DEVICE
64  void add_vertex ( amrex::RealVect const& a_v ) {
65  for ( int i(0); i<m_num_vertices; ++i) {
66  if ( amrex::almostEqual(m_vertices[i][0],a_v[0]) &&
67  amrex::almostEqual(m_vertices[i][1],a_v[1]) &&
68  amrex::almostEqual(m_vertices[i][2],a_v[2]) ) {
69  return;
70  }
71  }
72  AMREX_ASSERT( m_num_vertices < m_max_vertices );
75  }
76 
77  //! Return the number of stored vertices.
78  AMREX_GPU_HOST_DEVICE
79  int get_num_vertices ( ) {
80  return m_num_vertices;
81  }
82 
83  /**
84  * \brief Set the polygon area directly.
85  * \param a_area Area value assigned to the polygon.
86  */
87  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
88  void set_area ( amrex::Real const& a_area ) { m_area = a_area; }
89 
90  /**
91  * \brief Finalize polygon ordering and compute its area.
92  *
93  * Vertices are sorted counter-clockwise in the polygon plane before area is
94  * computed by a triangle fan.
95  */
96  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
97  void define () {
98 
99  AMREX_ALWAYS_ASSERT( m_defined == 0 ); // TODO ---------------------------- remove ALWAYS
100 
101  m_defined = 1;
102 
103  // We need at least 3 vertices.
104  if (m_num_vertices < 3) { return; }
105 
106  // Check to see if the vertices of the face are inside or outside of the plane.
107  // If they are outside, this face doesn't belong to the volume.
108  if ( m_cell_face ) {
109  for ( int i(0); i<m_num_vertices; ++i) {
110  if ((m_eb_normal.dotProduct(m_vertices[i] - m_eb_point)) >= zero) {
111  } else {
112  }
113  }
114  }
115 
116  // Calculate the centroid of the polygon.
117  amrex::RealVect centroid = get_centroid();
118 
119  // Shift the vertices relative to the centroid
120  amrex::Array<amrex::RealVect,m_max_vertices> vertex_cent;
121  for ( int i(0); i<m_num_vertices; ++i) {
122  vertex_cent[i] = m_vertices[i] - centroid;
123  }
124 
125  // Compute the normal vector m_zdir by cross product of two vectors in vertex_cent.
126  // Choose the vectors with the largest cross-product magnitude.
127  amrex::RealVect v_normal;
128  amrex::Real max_norm2 = -one;
129  const amrex::RealVect& vertex_cent_0 = vertex_cent[0];
130 
131  for (int i = 1; i < m_num_vertices; ++i)
132  {
133  amrex::RealVect vi = vertex_cent[i];
134  amrex::RealVect v_cross = vertex_cent_0.crossProduct(vi);
135  amrex::Real n2 = v_cross.radSquared();
136  if (n2 > max_norm2)
137  {
138  max_norm2 = n2;
139  v_normal = v_cross;
140  }
141  }
142  if (!amrex::almostEqual(max_norm2, zero))
143  {
144  v_normal /= std::sqrt(max_norm2);
145  }
146  m_zdir = v_normal;
147 
148  //
149 
150  m_theta[0] = zero;
151  for ( int i(1); i<m_num_vertices; ++i) {
152 
153  m_theta[i] = std::atan2(m_zdir.dotProduct( vertex_cent[0].crossProduct(vertex_cent[i]) ),
154  vertex_cent[0].dotProduct(vertex_cent[i]));
155 
156  m_theta[i] += ((m_theta[i] >= zero) ? zero : two*PI);
157  }
158 
159  // Sort counter clockwise based on theta.
160  for (int i(0); i<m_num_vertices; ++i) {
161  for (int j(0); j < m_num_vertices-i-1; ++j) {
162  if ( m_theta[j] > m_theta[j+1] ) {
163  amrex::Swap(m_theta[j], m_theta[j+1]);
164  amrex::Swap(m_vertices[j], m_vertices[j+1]);
165  amrex::Swap(vertex_cent[j], vertex_cent[j+1]);
166  }
167  } // j-loop
168  } // i-loop
169  m_sorted = 1;
170 
171  // Compute areas of triangles
172 
173  for (int i(0); i<m_num_vertices; ++i) {
174  int const j( (i+1 == m_num_vertices) ? 0 : i+1 );
175  amrex::RealVect vi_cross_vj = vertex_cent[i].crossProduct(vertex_cent[j]);
176  m_area += myhalf*vi_cross_vj.vectorLength();
177  }
178  AMREX_ALWAYS_ASSERT( m_area > zero ); // <------------------------------- TODO remove ALWAYS
179  } // void define
180 
181  //! Return whether the polygon has been defined with a valid area state.
182  [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
183  int ok ( ) const noexcept
184  { return ((m_area > zero || (m_area == zero && m_defined == 1)) ? 1 : 0); }
185 
186  //! Return the polygon area.
187  [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
188  amrex::Real area ( ) const noexcept {
189  AMREX_ALWAYS_ASSERT( ok() ); // <-------------------------------------- TODO remove ALWAYS
190  return m_area;
191  }
192 
193  /**
194  * \brief Return the perpendicular distance from this polygon to a point.
195  * \param a_point Point used in the distance calculation.
196  */
197  [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
198  amrex::Real distance ( amrex::RealVect const& a_point ) const noexcept {
199  AMREX_ALWAYS_ASSERT( m_defined == 1 ); // <--------------------------- TODO remove ALWAYS
200  amrex::RealVect x0 = a_point - m_vertices[0];
201  return amrex::Math::abs(x0.dotProduct(m_zdir));
202  }
203 
204  //! Return the polygon centroid from its sub-triangulation.
205  [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
206  amrex::RealVect get_centroid ( ) const noexcept {
207  amrex::RealVect cent(zero);
208  if (m_num_vertices==3) {
209  cent = (m_vertices[0] + m_vertices[1] + m_vertices[2]) / three;
210  } else {
211  // Loop over sub-triangles
213  for ( int i(0); i<m_num_vertices-2; ++i) {
214  amrex::RealVect const v0 (m_vertices[i+1] - m_vertices[0]);
215  amrex::RealVect const v1 (m_vertices[i+2] - m_vertices[0]);
216  amrex::RealVect v0_cross_v1 = v0.crossProduct(v1);
217  amrex::Real area_tri = myhalf * v0_cross_v1.vectorLength();
218  amrex::RealVect cent_tri = (m_vertices[0] + m_vertices[i+1] + m_vertices[i+2]) / three;
219  area += area_tri;
220  cent += area_tri * cent_tri;
221  }
222  cent = cent / area;
223  }
224  return cent;
225  }
226 
227  //! Return the unit normal vector of the polygon plane.
228  [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
229  amrex::RealVect normal () const noexcept {
230  return m_zdir;
231  }
232 
233  /**
234  * \brief Print a diagnostic report for the polygon on CPU builds.
235  * \param a_id Face identifier used in the diagnostic output.
236  * \param a_v0 Reference point used to compute the reported distance.
237  */
238 #ifndef AMREX_USE_GPU
239  void report ( int const a_id, amrex::RealVect a_v0 )
240 #else
241  void report ( int const /*a_id*/, amrex::RealVect /*a_v0*/ )
242 #endif
243  {
244 
245 #ifndef AMREX_USE_GPU
246  amrex::RealVect centroid = get_centroid();
247  amrex::Print() << "Face " << a_id
248  << " -------------------------------------------\n"
249  << "\nok? " << (ok() ? "yes" : "no") << "\n\n";
250  for (int i(0); i<m_num_vertices; ++i) {
251  amrex::Print() << "v" << i << ": " << m_vertices[i] << '\n';
252  }
253  amrex::Print() << "\nvc: " << " " << centroid << "\n";
254 
255  amrex::Real const dist = distance( a_v0 );
256  // amrex::Real const vol = ok() ? m_area * dist : zero;
257 
258  amrex::Print() << "\narea: " << m_area
259  << "\ndistance: " << dist
260  << "\nvolume: " << dist*m_area
261  << "\n==================================================\n\n";
262 #endif
263  }
264 
265  /**
266  * \brief Print polygon vertices with a face identifier.
267  * \param a_id Face identifier used in the diagnostic output.
268  */
269  void debug( int const a_id ) {
270  amrex::Print() << "EBPolygon: id = " << a_id << ", m_num_vertices = " << m_num_vertices << '\n';
271  for (int i(0); i<m_num_vertices; ++i) {
272  amrex::Print() << "EBPolygon: v" << i << ": " << m_vertices[i] << '\n';
273  }
274  }
275  //! Print polygon vertices without a face identifier.
276  void debug() {
277  debug(-1);
278  }
279 
280  private:
281 
282  static int constexpr m_max_vertices = 6;
283 
284  int const m_cell_face;
285 
286  amrex::RealVect const m_eb_point;
287  amrex::RealVect const m_eb_normal;
288 
290 
292 
294 
295  int m_sorted;
296 
297  amrex::Array<amrex::RealVect,m_max_vertices> m_vertices;
298 
299  amrex::GpuArray<amrex::Real,m_max_vertices> m_theta;
300 
301  amrex::RealVect m_zdir; // normal to polygon
302 };
303 
304 
305 #endif
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
Dimensionless numeric literals and pure mathematical constants.
constexpr amrex::Real three
Definition: ERF_NumericalConstants.H:32
constexpr amrex::Real two
Definition: ERF_NumericalConstants.H:31
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:30
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:29
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:34
constexpr amrex::Real PI
Definition: ERF_NumericalConstants.H:39
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Polygon helper used to accumulate cut-cell face geometry.
Definition: ERF_EBPolygon.H:20
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::RealVect get_centroid() const noexcept
Return the polygon centroid from its sub-triangulation.
Definition: ERF_EBPolygon.H:206
int m_defined
Definition: ERF_EBPolygon.H:289
AMREX_GPU_HOST_DEVICE int get_num_vertices()
Return the number of stored vertices.
Definition: ERF_EBPolygon.H:79
amrex::Real m_area
Definition: ERF_EBPolygon.H:293
amrex::Array< amrex::RealVect, m_max_vertices > m_vertices
Definition: ERF_EBPolygon.H:297
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int ok() const noexcept
Return whether the polygon has been defined with a valid area state.
Definition: ERF_EBPolygon.H:183
amrex::GpuArray< amrex::Real, m_max_vertices > m_theta
Definition: ERF_EBPolygon.H:299
AMREX_GPU_HOST_DEVICE void add_vertex(amrex::RealVect const &a_v)
Add a unique vertex to the polygon.
Definition: ERF_EBPolygon.H:64
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real distance(amrex::RealVect const &a_point) const noexcept
Return the perpendicular distance from this polygon to a point.
Definition: ERF_EBPolygon.H:198
void debug(int const a_id)
Print polygon vertices with a face identifier.
Definition: ERF_EBPolygon.H:269
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real area() const noexcept
Return the polygon area.
Definition: ERF_EBPolygon.H:188
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void set_area(amrex::Real const &a_area)
Set the polygon area directly.
Definition: ERF_EBPolygon.H:88
void debug()
Print polygon vertices without a face identifier.
Definition: ERF_EBPolygon.H:276
int const m_cell_face
Definition: ERF_EBPolygon.H:284
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::RealVect normal() const noexcept
Return the unit normal vector of the polygon plane.
Definition: ERF_EBPolygon.H:229
int m_sorted
Definition: ERF_EBPolygon.H:295
amrex::RealVect const m_eb_normal
Definition: ERF_EBPolygon.H:287
static constexpr int m_max_vertices
Definition: ERF_EBPolygon.H:282
void report(int const a_id, amrex::RealVect a_v0)
Print a diagnostic report for the polygon on CPU builds.
Definition: ERF_EBPolygon.H:239
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void define()
Finalize polygon ordering and compute its area.
Definition: ERF_EBPolygon.H:97
int m_num_vertices
Definition: ERF_EBPolygon.H:291
AMREX_GPU_HOST_DEVICE polygon_()
Construct an empty EB-boundary polygon.
Definition: ERF_EBPolygon.H:46
AMREX_GPU_HOST_DEVICE polygon_(amrex::RealVect a_point, amrex::RealVect a_normal)
Construct a cell-face polygon clipped by an EB plane.
Definition: ERF_EBPolygon.H:30
amrex::RealVect const m_eb_point
Definition: ERF_EBPolygon.H:286
amrex::RealVect m_zdir
Definition: ERF_EBPolygon.H:301
real(c_double), private vi
Definition: ERF_module_mp_morr_two_moment.F90:219