PRISMS-PF Manual
Loading...
Searching...
No Matches
utilities.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: © 2025 PRISMS Center at the University of Michigan
2// SPDX-License-Identifier: GNU Lesser General Public Version 2.1
3
4#pragma once
5
6#include <deal.II/base/config.h>
7#include <deal.II/base/exceptions.h>
8#include <deal.II/base/logstream.h>
9#include <deal.II/base/mpi.h>
10#include <deal.II/base/point.h>
11#include <deal.II/base/tensor.h>
12#include <deal.II/base/types.h>
13#include <deal.II/base/utilities.h>
14#include <deal.II/base/vectorization.h>
15#include <deal.II/matrix_free/evaluation_flags.h>
16
17#include <boost/range/algorithm.hpp>
18#include <boost/range/algorithm_ext.hpp>
19
21
22#include <prismspf/config.h>
23
24#include <string>
25#include <string_view>
26#include <unordered_map>
27
28#ifdef PRISMS_PF_WITH_CALIPER
29# include <caliper/cali-manager.h>
30# include <caliper/cali.h>
31#endif
32
34
40class MPIInitFinalize : public dealii::Utilities::MPI::MPI_InitFinalize
41{
42public:
43 MPIInitFinalize(int &argc, char **&argv, unsigned int _max_n_threads = 0);
44
46
47private:
53#ifdef PRISMS_PF_THREADS
54 static constexpr unsigned int max_n_threads = dealii::numbers::invalid_unsigned_int;
55#else
56 static constexpr unsigned int max_n_threads = 1;
57#endif
58
62#ifdef PRISMS_PF_WITH_CALIPER
63 cali::ConfigManager mgr;
64#endif
65};
66
67template <typename dealii_vector>
68void
69set_zero_entries_to_one(dealii_vector &vec)
70{
71 for (const auto index : vec.locally_owned_elements())
72 {
73 if (vec[index] == 0.0)
74 {
75 vec[index] = 1.0;
76 }
77 }
78}
79
83template <typename Type>
84Type
85string_to_type(const std::string &string,
86 const std::unordered_map<std::string, Type> &table)
87{
88 auto iterator = table.find(string);
89 AssertThrow(iterator != table.end(),
90 dealii::ExcMessage("Unknown table entry: " + string));
91 return iterator->second;
92}
93
111template <typename Type, typename OtherType>
112std::pair<OtherType, Type>
114 const std::string &string,
115 const std::unordered_map<std::string, Type> &table,
116 const std::unordered_map<std::string, OtherType> &other_table,
117 const std::pair<char, char> &delimiters = {'(', ')'})
118{
119 // Check to see if the string has any delimiters
120 const auto opening_delimiter_position = string.find(delimiters.first);
121 const auto closing_delimiter_position = string.find(delimiters.second);
122
123 bool has_opening_delimiter = opening_delimiter_position != std::string_view::npos;
124 bool has_closing_delimiter = closing_delimiter_position != std::string_view::npos;
125
126 // Some checks for malformed input
127 AssertThrow(closing_delimiter_position >= opening_delimiter_position,
128 dealii::ExcMessage(
129 "Opening delimiter must precede the closing delimiter. You had " +
130 string));
131 AssertThrow(has_closing_delimiter == has_opening_delimiter,
132 dealii::ExcMessage("You must either have a delimiter pair or not. You seem "
133 "to only have one delimiter. You had " +
134 string));
135
136 // Case 2 - no delimiters
137 if (!has_closing_delimiter && !has_opening_delimiter)
138 {
139 const auto second_type = string_to_type("", table);
140 const auto first_type = string_to_type(string, other_table);
141 return {first_type, second_type};
142 }
143
144 // More checks for malformed input
145 AssertThrow(closing_delimiter_position == string.size() - 1,
146 dealii::ExcMessage(
147 "Closing delimiter must be at the end of the string. You had " + string));
148
149 // Case 1 - delimiters
150 std::string_view input_view {string};
151 std::string_view outer_string = input_view.substr(0, opening_delimiter_position);
152 std::string_view inner_string =
153 input_view.substr(opening_delimiter_position + 1,
154 closing_delimiter_position - opening_delimiter_position - 1);
155
156 AssertThrow(!outer_string.empty() && !inner_string.empty(),
157 dealii::ExcMessage(
158 "Inner and outer map entries must not be empty. You had " + string));
159 // NOTE: This will allocate the string views to strings on the heap. Hopefully this
160 // isn't so bad in performance, but I didn't wanna support heterogeneous lookup tables.
161 // I can't imagine this becoming a performance problem right now since we only deal with
162 // strings in the initialization of simulations; however, if it does, it shouldn't be
163 // two hard to support heterogeneous lookup or a table that uses std::string_view.
164 const auto second_type = string_to_type(std::string(outer_string), table);
165 const auto first_type = string_to_type(std::string(inner_string), other_table);
166 return {first_type, second_type};
167}
168
173template <typename Number>
174inline DEAL_II_ALWAYS_INLINE Number
175pmod(const Number &value, const Number &modulus)
176{
177 return std::fmod(std::fmod(value, modulus) + modulus, modulus);
178}
179
187template <unsigned int dim, unsigned int degree, typename T>
188inline DEAL_II_ALWAYS_INLINE T
189stabilization_parameter(const T &timestep,
190 const T &element_volume,
191 const dealii::Tensor<1, dim, T> &velocity,
192 const T &kinematic_viscosity)
193{
194 using dealii::Utilities::fixed_power;
195 using std::cbrt;
196 using std::sqrt;
197
198 constexpr auto degree_modifier = T(1) / T(degree);
199 constexpr auto inv_pi = T(1) / T(M_PI);
200 const auto velocity_l2_norm = velocity.norm_square() + T(1e-12);
201
202 auto element_size = T(0);
203 if constexpr (dim == 1)
204 {
205 element_size = element_volume;
206 }
207 else if constexpr (dim == 2)
208 {
209 element_size = T(2) * sqrt(element_volume * inv_pi);
210 }
211 else if constexpr (dim == 3)
212 {
213 element_size = cbrt(T(6) * element_volume * inv_pi);
214 }
215 else
216 {
217 Assert(false, dealii::ExcMessage("Invalid dimension for the stabilization term."));
218 }
219 element_size *= degree_modifier;
220 const auto element_size_2 = element_size * element_size;
221 const auto element_size_2_inv = T(1) / element_size_2;
222 const auto element_size_4_inv = element_size_2_inv * element_size_2_inv;
223
224 const T term_time = fixed_power<2>(T(2) / timestep);
225 const T term_adv = T(4) * velocity_l2_norm * element_size_2_inv;
226 const T term_diff = T(144) * fixed_power<2>(kinematic_viscosity) * element_size_4_inv;
227
228 return T(1) / sqrt(term_time + term_adv + term_diff);
229}
230
240template <unsigned int dim, unsigned int degree, typename T>
241inline DEAL_II_ALWAYS_INLINE T
242stabilization_parameter(const T &element_volume,
243 const dealii::Tensor<1, dim, T> &velocity,
244 const T &kinematic_viscosity)
245{
246 using dealii::Utilities::fixed_power;
247 using std::cbrt;
248 using std::sqrt;
249
250 constexpr auto degree_modifier = T(1) / T(degree);
251 constexpr auto inv_pi = T(1) / T(M_PI);
252 const auto velocity_l2_norm = velocity.norm_square() + T(1e-12);
253
254 auto element_size = T(0);
255 if constexpr (dim == 1)
256 {
257 element_size = element_volume;
258 }
259 else if constexpr (dim == 2)
260 {
261 element_size = T(2) * sqrt(element_volume * inv_pi);
262 }
263 else if constexpr (dim == 3)
264 {
265 element_size = cbrt(T(6) * element_volume * inv_pi);
266 }
267 else
268 {
269 Assert(false, dealii::ExcMessage("Invalid dimension for the stabilization term."));
270 }
271 element_size *= degree_modifier;
272 const auto element_size_2 = element_size * element_size;
273 const auto element_size_2_inv = T(1) / element_size_2;
274 const auto element_size_4_inv = element_size_2_inv * element_size_2_inv;
275
276 const T term_adv = T(4) * velocity_l2_norm * element_size_2_inv;
277 const T term_diff = T(144) * fixed_power<2>(kinematic_viscosity) * element_size_4_inv;
278
279 return T(1) / sqrt(term_adv + term_diff);
280}
281
291template <unsigned int dim, unsigned int degree, typename T>
292inline DEAL_II_ALWAYS_INLINE T
293stabilization_parameter(const T &timestep,
294 const T &element_volume,
295 const dealii::Tensor<1, dim, T> &velocity)
296{
297 using dealii::Utilities::fixed_power;
298 using std::cbrt;
299 using std::sqrt;
300
301 constexpr auto degree_modifier = T(1) / T(degree);
302 constexpr auto inv_pi = T(1) / T(M_PI);
303 const auto velocity_l2_norm = velocity.norm_square() + T(1e-12);
304
305 auto element_size = T(0);
306 if constexpr (dim == 1)
307 {
308 element_size = element_volume;
309 }
310 else if constexpr (dim == 2)
311 {
312 element_size = T(2) * sqrt(element_volume * inv_pi);
313 }
314 else if constexpr (dim == 3)
315 {
316 element_size = cbrt(T(6) * element_volume * inv_pi);
317 }
318 else
319 {
320 Assert(false, dealii::ExcMessage("Invalid dimension for the stabilization term."));
321 }
322 element_size *= degree_modifier;
323 const auto element_size_2 = element_size * element_size;
324 const auto element_size_2_inv = T(1) / element_size_2;
325 const auto element_size_4_inv = element_size_2_inv * element_size_2_inv;
326
327 const T term_time = fixed_power<2>(T(2) / timestep);
328 const T term_adv = T(4) * velocity_l2_norm * element_size_2_inv;
329
330 return T(1) / sqrt(term_time + term_adv);
331}
332
342template <unsigned int dim, unsigned int degree, typename T>
343inline DEAL_II_ALWAYS_INLINE T
344stabilization_parameter(const T &element_volume,
345 const dealii::Tensor<1, dim, T> &velocity)
346{
347 using dealii::Utilities::fixed_power;
348 using std::cbrt;
349 using std::sqrt;
350
351 constexpr auto degree_modifier = T(1) / T(degree);
352 constexpr auto inv_pi = T(1) / T(M_PI);
353 const auto velocity_l2_norm = velocity.norm_square() + T(1e-12);
354
355 auto element_size = T(0);
356 if constexpr (dim == 1)
357 {
358 element_size = element_volume;
359 }
360 else if constexpr (dim == 2)
361 {
362 element_size = T(2) * sqrt(element_volume * inv_pi);
363 }
364 else if constexpr (dim == 3)
365 {
366 element_size = cbrt(T(6) * element_volume * inv_pi);
367 }
368 else
369 {
370 Assert(false, dealii::ExcMessage("Invalid dimension for the stabilization term."));
371 }
372 element_size *= degree_modifier;
373 const auto element_size_2 = element_size * element_size;
374 const auto element_size_2_inv = T(1) / element_size_2;
375 const auto element_size_4_inv = element_size_2_inv * element_size_2_inv;
376
377 const T term_adv = T(4) * velocity_l2_norm * element_size_2_inv;
378 // NOTE: I could simplify the math here, but I won't bother for now since I imagine the
379 // use case is pretty limited.
380
381 return T(1) / sqrt(term_adv);
382}
383
387inline std::string
388strip_whitespace(const std::string &_text)
389{
390 std::string text = _text;
391 boost::range::remove_erase_if(text, ::isspace);
392 return text;
393}
394
398inline const char *
399bool_to_string(bool boolean)
400{
401 return boolean ? "true" : "false";
402}
403
407inline std::string
408eval_flags_to_string(dealii::EvaluationFlags::EvaluationFlags flag)
409{
410 std::string result;
411
412 if ((flag & dealii::EvaluationFlags::EvaluationFlags::values) != 0U)
413 {
414 result += "values";
415 }
416 if ((flag & dealii::EvaluationFlags::EvaluationFlags::gradients) != 0U)
417 {
418 if (!result.empty())
419 {
420 result += " | ";
421 }
422 result += "gradients";
423 }
424 if ((flag & dealii::EvaluationFlags::EvaluationFlags::hessians) != 0U)
425 {
426 if (!result.empty())
427 {
428 result += " | ";
429 }
430 result += "hessians";
431 }
432
433 if (result.empty())
434 {
435 return "nothing";
436 }
437
438 return result;
439}
440
441template <unsigned int dim, typename number>
442inline DEAL_II_ALWAYS_INLINE std::vector<number>
443dealii_point_to_vector(const dealii::Point<dim, number> &point)
444{
445 static_assert(dim < 4, "We only allow 3 space dimensions");
446
447 std::vector<number> vec(3, 0.0);
448
449 // NOLINTBEGIN(cppcoreguidelines-pro-bounds-constant-array-index)
450
451 for (unsigned int i = 0; i < dim; ++i)
452 {
453 vec[i] = point[i];
454 }
455
456 // NOLINTEND(cppcoreguidelines-pro-bounds-constant-array-index)
457
458 return vec;
459}
460
461PRISMS_PF_END_NAMESPACE
462
static constexpr unsigned int max_n_threads
Number of threads to try and use.
Definition utilities.h:56
~MPIInitFinalize()
Definition utilities.cc:44
MPIInitFinalize(int &argc, char **&argv, unsigned int _max_n_threads=0)
Definition utilities.cc:16
Definition conditional_ostreams.cc:20
inline ::dealii::VectorizedArray< Number, width > fmod(const ::dealii::VectorizedArray< Number, width > &numer, const Number denom)
Definition vectorized_operations.h:54
Type
Factory function to create appropriate reader based on input file type not a member of ReadFieldBase ...
Definition read_field_factory.h:30
void set_zero_entries_to_one(dealii_vector &vec)
Definition utilities.h:69
std::string strip_whitespace(const std::string &_text)
Remove whitespace from strings.
Definition utilities.h:388
DEAL_II_ALWAYS_INLINE T stabilization_parameter(const T &timestep, const T &element_volume, const dealii::Tensor< 1, dim, T > &velocity, const T &kinematic_viscosity)
Stabilization term as defined by Tezduyar
Definition utilities.h:189
std::pair< OtherType, Type > string_to_type_pair_with_delimiters(const std::string &string, const std::unordered_map< std::string, Type > &table, const std::unordered_map< std::string, OtherType > &other_table, const std::pair< char, char > &delimiters={'(', ')'})
Helper function that converts a string to some type pair, given two mappings and a set of delimiters.
Definition utilities.h:113
Type string_to_type(const std::string &string, const std::unordered_map< std::string, Type > &table)
Helper function that converts a string to some type, given a mapping.
Definition utilities.h:85
std::string eval_flags_to_string(dealii::EvaluationFlags::EvaluationFlags flag)
Convert evaluation flags to string.
Definition utilities.h:408
DEAL_II_ALWAYS_INLINE std::vector< number > dealii_point_to_vector(const dealii::Point< dim, number > &point)
Definition utilities.h:443
DEAL_II_ALWAYS_INLINE Number pmod(const Number &value, const Number &modulus)
Positive moldulo (remainder) returns the normal remainder. (c++ fmod is defined abnormally for negati...
Definition utilities.h:175
const char * bool_to_string(bool boolean)
Convert bool to string.
Definition utilities.h:399