DamBreak++ Wave Simulator 0.3
DamBreak++ Simulation Framework
Loading...
Searching...
No Matches
Sfx_MathFunctions.hpp
Go to the documentation of this file.
1#pragma once
2
3// C++ includes
4#include <cassert>
5#include <type_traits>
6#include <ranges> // C++20
7// numeric includes
8#include <numeric>
9#include <valarray>
10// SfxBase19 includes
11#include "include/Sfx_Utility.h"
12#include "include/BaseMacros.h"
13#include "include/Sfx_UniversalConstants.h"
14// App include
16
17namespace Sfx
18{
24 std::valarray<float64> cell_face_average(std::ranges::view auto aRng)
25 {
26 // C++20 function declaration
27 //auto viewBeg = std::ranges::cbegin(aRng);
28 //auto viewSiz = std::ranges::size(aRng);
29 assert( Sfx::EMCNEILNbSections::value == std::ranges::size(aRng));
30
31 std::valarray<double> w_valArray(Sfx::DIM::value); // initialize to 0
32 // Based on Nujic paper (1995)
33 for( auto i = 0; i < Sfx::DIM::value; ++i)
34 {
35 if (i == 0) // boundaary point
36 {
37 w_valArray[i] = (0.5 *(aRng[i + 1] + aRng[i]));
38 }
39 else
40 {
41 w_valArray[i] = (0.5 * (aRng[i + 1] + aRng[i - 1]));
42 }
43 }
44 return w_valArray;
45 }
46
47 // Alias template
48 // not valid
49 //template<typename Range1, typename Range2>
50 //using EnableIfIsameRngType = std::is_same_t<Range1, Range2>;
51
52 /*template<typename Range1, typename Range2>
53 using EnableIfIsameRngSiz = std::is_same_v<std::size(Range1), std::size(Range2)>;*/
54
55 // DESIGN NOTE
56// can be done with the STL Adjacent_difference algorithm.
57// I have an implementation in the VS15 project, should it.
58// Delta function for the positive part computed by the
59// ENO stencil which is a three point stencil [j-1,j,j+1]
60
71 template<typename Range1, typename Range2>
72 std::common_type_t<Range1, Range2> computeLimitedGradient( const Range1& aRng1, const Range2& aRng2)
73 {
74 // some basic check before proceeding (sanity check)
75 static_assert( dbpp::isHomogeneous(aRng1,aRng2));
76 static_assert( std::is_same_v<decltype(aRng1), const std::valarray<double>&>, "Not using numeric valarray");
77 static_assert( std::is_same_v<decltype(aRng2), const std::valarray<double>&>, "Not using numeric valarray");
78
79 if constexpr (std::ranges::size(aRng1) != std::ranges::size(aRng2))
80 {
81 return { Range1 {}, Range2 {} };
82 }
83 else if constexpr (std::ranges::empty(aRng1) && std::ranges::empty(aRng2))
84 {
85 return { Range1 {}, Range2 {} };
86 }
87 else
88 {
89 // gradient according to limiter function
90 Range1 w_df1p{ aRng1.size() };
91 Range2 w_df2p{ aRng2.size() };
92
93 // boundary node i=0
94 w_df1p[0] = Sfx::minmod(aRng1[1] - aRng1[0], 0.);
95 w_df2p[0] = Sfx::minmod(aRng2[1] - aRng2[0], 0.);
96
97 // interior node (exclude i=0 and i=100 global node index)
98 for (uint32 i2 = 1; i2 < aRng1.size() - 1; ++i2)
99 {
100 w_df1p[i2] = Sfx::minmod(aRng1[i2 + 1] - aRng1[i2], aRng1[i2] - aRng1[i2 - 1]);
101 w_df2p[i2] = Sfx::minmod(aRng2[i2 + 1] - aRng2[i2], aRng2[i2] - aRng2[i2 - 1]);
102 }
103
104 // boundary cnd i=100 ghost node (avoid index out of range)
105 w_df1p[aRng1.size() - 1] = Sfx::minmod(0., aRng1[aRng1.size() - 1] - aRng1[aRng1.size() - 2]);
106 w_df2p[aRng2.size() - 1] = Sfx::minmod(0., aRng2[aRng2.size() - 1] - aRng2[aRng2.size() - 2]);
107
108 return { w_df1p, w_df2p };
109 }
110 }
111
117 template<typename Range, typename FuncLimiter> // let compiler deduce type (moved to "Dsn_MathUtils.hpp")
118 requires std::same_as<Range, std::vector<float64>>
119 auto computeDU(Range aRng, FuncLimiter&& aFuncLimiter) // deduced return type according to values categories C++17
120 {
121 // NOTE range must be constant to call distance
122 if constexpr (std::ranges::range<decltype(aRng)>)
123 assert(std::ranges::distance(aRng) == Sfx::EMCNEILNbSections::value);
124
125 // gradient over each cell
126 std::vector<double> w_deltaU(std::ranges::size(aRng));
127
128 // compute the gradient of dU (U_i+1-U_i) over each cell (1st order)
129 std::adjacent_difference(std::ranges::begin(aRng), std::ranges::end(aRng), w_deltaU.begin());
130
131 // Overwriting first value not part of computation according to
132 // numerical algo "adjacent_difference" and set to 0. for slope limiter
133 if (w_deltaU[0] != 0.) // boundary node (right)
134 {
135 w_deltaU[0] = 0.; // force to zero
136 }
137
138 // last node i=100 (ghost node) compare with 0, need to add
139 w_deltaU.push_back(0.); // fwd stencil [i+1-i]
140
141 // Apply slope limiter function gradient 1st order (Total Variation Diminishing)
142 std::adjacent_difference(w_deltaU.begin(), w_deltaU.end(), // range
143 w_deltaU.begin(), // result
144 aFuncLimiter); //function
145
146 return std::move(w_deltaU) | std::views::drop(1);
147 }
148
153 // let compiler deduce type (auto always decay)
154 template<typename Range, typename FuncLimiter>
155 decltype(auto) computeDU( Range& aRng, FuncLimiter&& aFuncLimiter)
156 {
157#if _DEBUG
158 // static_assert( std::size(aRng) == 101,"Range not correct size");
159 assert(Sfx::EMCNEILNbSections::value == std::distance(std::begin(aRng), std::end(aRng)));
160#endif
161 std::vector<float64> w_deltaU(std::ranges::cbegin(aRng), std::ranges::cend(aRng));
162
163 // compute the gradient of U (U_i+1-U_i) over each cell
164 std::adjacent_difference(std::ranges::cbegin(aRng), std::ranges::cend(aRng), w_deltaU.begin());
165
166 if (w_deltaU[0] != 0.) // boundary node (right)
167 {
168 w_deltaU[0] = 0.; // force to zero
169 }
170
171 // last node i=100 (ghost node) compare with 0, need to add
172 w_deltaU.push_back(0.); //[i+1-i]
173
174 std::adjacent_difference(w_deltaU.begin(), w_deltaU.end(), w_deltaU.begin(),
175 std::forward<FuncLimiter>(aFuncLimiter));
176
177 //auto w_rngDiff = make_iterator_range( w_deltaU.begin(), w_deltaU.end()).advance_begin(1);
178
179 // subrange of computational range (without )
180 // return iterator_range(w_deltaU.begin(), w_deltaU.end()).advance_begin(1);
181 // return std::move(w_deltaU) | std::views::drop(w_deltaU,1);
182 return std::vector<double>(std::next(w_deltaU.begin()), w_deltaU.end());
183 }
184
193 auto computeDU_v( std::ranges::view auto aView)
194 {
195 // sanity check (concept)
196 if constexpr (std::ranges::view<decltype(aView)>)
197 static_assert( std::ranges::distance(aView) == Sfx::EMCNEILNbSections::value);
198
199 auto view_type = std::ranges::range_value_t<decltype(aView)>;
200 std::vector<view_type> w_dU;
201 w_dU.reserve(std::ranges::size(aView));
202
203 // Compute the gradient of dU (U_i+1-U_i) over each cell (1st order)
204 std::adjacent_difference(std::ranges::begin(aView), std::ranges::end(aView),
205 w_dU.begin());
206
207 w_dU.push_back(0.); // comparison purpose
208
209 // Apply slope limiter function gradient 1st order (Total Variation Diminishing)
210 std::adjacent_difference(w_dU.begin(), w_dU.end(), // range
211 w_dU.begin(), // result
212 dbpp::MinMod19{}); // limiter function
213
214 return std::valarray<view_type>( std::next(w_dU.begin()), w_dU.size()-1); // temp fix for debugging
215 }
216
217 // compute the average over the cell
218 template<typename Range>
219 auto cell_face_average( const Range& aRng) // consider to pass it b value
220 { // std::views such as span is cheap to copy
221 // Design Note
222 // call in SweRhsAlgorithm::calculate() "auto w_Avrg = Sfx::cell_face_average(w_A);"
223 // but w_A not constant.
224#if _DEBUG
225 // Since we are in the prototyping phase using
226 // E. McNeil dambreak data, particularly nbSections=101
227 //static_assert( std::size(aRng) == EMCNEILNbSections::value, "Range not valid size"); error msg "expr did not evaluate to constant"???
228 assert( std::ranges::size(aRng) == EMCNEILNbSections::value);
229#endif
230
231 // concept of a range C++20
232 // NOTE
233 // not sure about this one. If we pass valarray I think it would not work.
234 // valrray doesn't provide a begin and end operations
235 if constexpr( std::ranges::range<decltype(aRng)>)
236 {
237 //auto w_rngSiz = std::size(aRng);
238 // create array of given size
239 std::valarray<float64> w_valArray(std::ranges::size(aRng) - 1);
240 // Based on Nujic paper (1995)
241 for (auto i = 0; i < std::ranges::size(aRng) - 1; ++i)
242 {
243 if (i == 0)
244 {
245 w_valArray[i] = (0.5 * Sfx::cGravity<float64> *(aRng[i + 1] + aRng[i]));
246 }
247 else
248 {
249 w_valArray[i] = (0.5 * Sfx::cGravity<float64> *(aRng[i + 1] + aRng[i - 1]));
250 }
251 }
252 return w_valArray;
253 }//if
254 else
255 {
256 throw "Not a range"; // not sure yet, but at least it must do something
257 return std::valarray<double>{};
258 }
259 }
260
261 // ===============================================================
262 //
263 // Math Utilities
264 //
265 // ===============================================================
266
272 inline float64 wrapPi(float64 aTheta)
273 {
274 aTheta += cPi<float64>;
275 aTheta -= static_cast<float>(floor(aTheta * c1Over2Pi<float64>) * c2Pi<float64>);
276 aTheta -= cPi<float64>;
277
278 return aTheta;
279 }
280
290 inline float64 safeAcos(float64 x)
291 {
292 // Check limit conditions
293 if (x <= -1.) {
294 return cPi<float64>;
295 }
296 if (x >= 1.) {
297 return 0.;
298 }
299
300 // Value is in the domain - use standard C function
301 return static_cast<float>(acos(x));
302 }
303
309 constexpr float64 degToRad( float64 aDeg) { return aDeg * cPiOver180<float64>; }
310 constexpr float64 radToDeg( float64 aRad) { return aRad * c180OverPi<float64>; }
311
320 inline void sinCos( float* aReturnSin, float* aReturnCos, float aTheta)
321 {
322 // For simplicity, we'll just use the normal trig functions.
323 // Note that on some platforms we may be able to do better
324 *aReturnSin = static_cast<float>(sin(aTheta));
325 *aReturnCos = static_cast<float>(cos(aTheta));
326 }
327
328 // shall return std::optional<double>
329 template<typename Range>
330 auto StVenant1D_Incomplete_Flux(Range& aU1, Range& aU2)
331 {
332 static_assert(0 != std::size(aU1));
333 static_assert(std::is_same_v<std::size(aU1), std::size(aU2)>);
334
335 if constexpr (!std::is_same_v<std::size(aU1), std::size(aU2)>)
336 {
337 return -1.;
338 }
339 else
340 {
341 return (aU2 * aU2) / aU1;
342 }
343
344 //static_assert(std::extent_v<decltype(aU1[0],0)> == 10.);
345 //static_assert(std::extent_v<decltype(aU1[99],0)> == 1.);
346 //static_assert( std::size(aU1) == std::size(decltype(aU2)), "Incomplete Flux range empty");
347 //static_assert( !std::size(aU1) && !std::size(aU2) , "Incomplete Flux range empty");
348
349 //return (aU2 * aU2) / aU1;
350
351 // Fonction de calcul de F2 incomplet (excluant le terme de pression hydrostatique)
352
353 // float64 F2;
354
355 // F2 = U2 * U2 / U1;
356
357 // return (F2);
358 }
359} // End of namespace
Minmod limiter function for slope limiting gradient evaluation.
Definition dbpp_SimulationUtilities.hpp:89
Definition HydUtils.h:15
float64 wrapPi(float64 aTheta)
"Wrap" an angle in range -pi...pi by adding the correct multiple of 2 pi
Definition Sfx_MathFunctions.hpp:272
constexpr float64 radToDeg(float64 aRad)
Definition Sfx_MathFunctions.hpp:310
auto computeDU(Range aRng, FuncLimiter &&aFuncLimiter)
Compute gradient over cell by applying a slope limiter function. Range aRng Range of values (computat...
Definition Sfx_MathFunctions.hpp:119
float64 safeAcos(float64 x)
"Safe" inverse trig functions
Definition Sfx_MathFunctions.hpp:290
void sinCos(float *aReturnSin, float *aReturnCos, float aTheta)
Compute the sin and cosine of an angle. On some platforms, if we know that we need both values,...
Definition Sfx_MathFunctions.hpp:320
std::common_type_t< Range1, Range2 > computeLimitedGradient(const Range1 &aRng1, const Range2 &aRng2)
Compute gradient by using a limiter function.
Definition Sfx_MathFunctions.hpp:72
auto computeDU_v(std::ranges::view auto aView)
state variables gradient over each cell (1st order)
Definition Sfx_MathFunctions.hpp:193
std::valarray< float64 > cell_face_average(std::ranges::view auto aRng)
Compute average of a variable at cell face.
Definition Sfx_MathFunctions.hpp:24
constexpr float64 degToRad(float64 aDeg)
Convert between degrees and radians.
Definition Sfx_MathFunctions.hpp:309
auto StVenant1D_Incomplete_Flux(Range &aU1, Range &aU2)
Definition Sfx_MathFunctions.hpp:330
Check if types are identical using fold expression.
Definition dbpp_SimulationUtilities.hpp:41