NEMoSys  0.63.0
A modular, extensible resource with robust automated mesh generation, mesh quality analysis, adaptive mesh refinement, and data transfer between arbitrary meshes.
AuxiliaryFunctions.H
Go to the documentation of this file.
1 /*******************************************************************************
2 * Promesh *
3 * Copyright (C) 2022, IllinoisRocstar LLC. All rights reserved. *
4 * *
5 * Promesh is the property of IllinoisRocstar LLC. *
6 * *
7 * IllinoisRocstar LLC *
8 * Champaign, IL *
9 * www.illinoisrocstar.com *
10 * promesh@illinoisrocstar.com *
11 *******************************************************************************/
12 /*******************************************************************************
13 * This file is part of Promesh *
14 * *
15 * This version of Promesh is free software: you can redistribute it and/or *
16 * modify it under the terms of the GNU Lesser General Public License as *
17 * published by the Free Software Foundation, either version 3 of the License, *
18 * or (at your option) any later version. *
19 * *
20 * Promesh is distributed in the hope that it will be useful, but WITHOUT ANY *
21 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more *
23 * details. *
24 * *
25 * You should have received a copy of the GNU Lesser General Public License *
26 * along with this program. If not, see <https://www.gnu.org/licenses/>. *
27 * *
28 *******************************************************************************/
29 #ifndef NEMOSYS_AUXILIARYFUNCTIONS_H_
30 #define NEMOSYS_AUXILIARYFUNCTIONS_H_
31 
32 #include <algorithm>
33 #include <chrono>
34 #include <cmath>
35 #include <ctime>
36 #include <cstring>
37 #include <fstream>
38 #include <iomanip>
39 #include <iostream>
40 #include <iterator>
41 #include <map>
42 #include <memory>
43 #include <random>
44 #include <sstream>
45 #include <string>
46 #include <utility>
47 #include <vector>
48 
49 //--------------------------Start nemAux namespace----------------------------//
50 namespace nemAux {
51 
52 //----------------------------Auxiliary Classes-------------------------------//
53 
54 // class wrapping around std::chrono for timing methods
55 class Timer {
56  private:
57  using time_t = std::chrono::time_point<std::chrono::system_clock>;
58 
59  public:
60  Timer() : startTime(), stopTime() {}
61 
62  time_t start() { return startTime = std::chrono::system_clock::now(); }
63 
64  time_t stop() { return stopTime = std::chrono::system_clock::now(); }
65 
66  double elapsed() {
67  return std::chrono::duration_cast<std::chrono::milliseconds>(stopTime -
68  startTime)
69  .count();
70  }
71 
72  private:
74 };
75 
76 //----------------------------------------------------------------------------//
77 
78 //----------------------Auxiliary Function Declarations-----------------------//
79 
80 /*
81 Reasons for inline functions:
82 
83  Per C++11 Standard, every program (after linking) shall contain exactly one
84  definition of every non-inline function or variable that is odr-used
85  (one-definition-rule-used) in the program. An inline function shall be defined
86  in every translation unit in which it is odr-used.
87 
88  So, if functions are non-inline and defined in a header that is included in
89  multiple translation units (separate source files), the linker will see the
90  same symbol is used more than once when merging object code. This violates the
91  odr.
92 
93  If functions are inline and defined in a header, an exception is made to the
94  odr rule, and it is defined in every translation unit in which it's used.
95  Although inlining is a non-binding request, the inline keyword succeeds at
96  telling the linker to tolerate multiple symbol definitions.
97 */
98 
99 // flattens vector of vectors
100 template <typename T>
101 std::vector<T> flatten(const std::vector<std::vector<T>> &v);
102 
103 // folds vector into vector of vectors
104 template <typename T>
105 std::vector<std::vector<T>> fold(const std::vector<T> &v, int dim);
106 
107 // adds two vectors
108 template <typename T>
109 std::vector<T> operator+(const std::vector<T> &x, const std::vector<T> &y);
110 // sub two vectors
111 template <typename T>
112 std::vector<T> operator-(const std::vector<T> &x, const std::vector<T> &y);
113 
114 // multiplies vector by scalar
115 template <typename T>
116 std::vector<T> operator*(T a, const std::vector<T> &x);
117 
118 // Hadamard product of vectors
119 template <typename T>
120 std::vector<T> hadamard(const std::vector<T> &x, const std::vector<T> &y);
121 
122 // compute 2 norm of vec
123 template <typename T>
124 T l2_Norm(const std::vector<T> &x);
125 // computes reciprocal of argument
126 template <typename T>
127 T reciprocal(T x);
128 // IN PLACE, computes reciprocal of vector elements
129 template <typename T>
130 void reciprocal_vec(std::vector<T> &x);
131 // checks if vector has zeros
132 template <typename T>
133 bool hasZero(const std::vector<T> &x);
134 // find minmax of vector, excluding inf
135 template <typename T>
136 std::vector<T> getMinMax(const std::vector<T> &x);
137 // scales x from range [xmin, xmax] to within range [ymin, ymax]
138 // if x is inf, the scaled value will be ymax
139 template <typename T>
140 T scale_to_range(T x, const std::vector<T> &xminmax,
141  const std::vector<T> &yminmax);
142 // IN PLACE, scales each number in vector in range [xmin, xmax] to [ymin, ymax]
143 template <typename T>
144 void scale_vec_to_range(std::vector<T> &x, const std::vector<T> &xminmax,
145  const std::vector<T> &yminmax);
146 // get average and stdev of values
147 template <typename T>
148 std::vector<T> getMeanStdev(const std::vector<T> &x);
149 // generates boolean array with 1 if value >= tol, 0 otherwise
150 template <typename T>
151 std::vector<bool> cellsToRefine(const std::vector<T> &values, T tol);
152 // generates boolean array with 1 if value >= mean+/-dev, 0 otherwise
153 template <typename T>
154 std::vector<bool> cellsToRefineStdev(const std::vector<T> &values, T mean,
155  T dev);
156 // return selects cells if their value is above some threshold of the maximum
157 template <typename T>
158 std::vector<bool> cellsToRefineMaxdev(const std::vector<T> &values, T dev);
159 // string trimming for consistent file names
160 inline std::string trim_fname(const std::string &name, const std::string &ext);
161 // find file extension
162 inline std::string find_ext(const std::string &fname);
163 // IN PLACE, to lower
164 inline void toLower(std::string &str);
165 // IN PLACE, to upper
166 inline void toUpper(std::string &str);
167 // return from beginning to the location of str
168 inline std::string findToStr(const std::string &str, const std::string &ptrn);
169 // return from the location of str
170 inline std::string findFromStr(const std::string &str, const std::string &ptrn);
171 // returns current time as string
172 inline std::string getTimeStr();
173 // find file extension
174 inline std::string find_name(const std::string &fname);
175 // print a vector
176 template <typename T>
177 void printVec(const std::vector<T> &v);
178 // find if in vector
179 template <typename T>
180 bool valInVec(const std::vector<T> &v, T val);
181 // flip a pair
182 template <typename A, typename B>
183 std::pair<B, A> flip_pair(const std::pair<A, B> &p);
184 // flip a map into a multimap
185 template <typename A, typename B>
186 std::multimap<B, A> flip_map(const std::map<A, B> &src);
187 // check if coordinate is inside a bounding box
188 template <typename T>
189 bool isInBBox(const std::vector<T> &crd, const std::vector<T> &bb);
190 // get a vector of the keys from a map (which are sorted)
191 template <typename A, typename B>
192 std::vector<A> getSortedKeys(const std::map<A, B> &mapObj);
193 // generate a random string of given length
194 inline std::string getRandomString(int length);
195 // converts string to character
196 inline std::shared_ptr<char> strToChar(const std::string &strng);
197 // decomposes string into tokens using single delimiter
198 inline std::vector<std::string> Tokenize(const std::string &lineIn,
199  const char &delim);
200 inline std::vector<std::string> Tokenize(const std::string &lineIn,
201  const std::string &delim);
202 // get the least positive integer that is not in the map and at least min
203 template <typename A, typename B>
204 A leastUnusedKey(const std::map<A, B> &map, A min = 1);
205 //----------------------------------------------------------------------------//
206 
207 //-------------------Auxiliary Function Implementations-----------------------//
208 
209 // flattens vector of vectors
210 template <typename T>
211 std::vector<T> flatten(const std::vector<std::vector<T>> &v) {
212  std::size_t size = 0;
213  for (const auto &sub : v) size += sub.size();
214 
215  std::vector<T> result;
216  result.reserve(size);
217  for (const auto &sub : v) result.insert(result.end(), sub.begin(), sub.end());
218  return result;
219 }
220 
221 // folds vector into vector of vectors, each of length dim
222 template <typename T>
223 std::vector<std::vector<T>> fold(const std::vector<T> &v, int dim) {
224  if (v.size() % dim != 0) {
225  std::cerr << "Size must be divisible by dim for folding" << std::endl;
226  exit(1);
227  }
228 
229  std::vector<std::vector<T>> result(v.size() / dim);
230  for (std::size_t i = 0; i < result.size(); ++i) {
231  result[i].resize(dim);
232  for (std::size_t j = 0; j < dim; ++j) result[i][j] = v[i * dim + j];
233  }
234  return result;
235 }
236 
237 // compute 2 norm of vec
238 template <typename T>
239 T l2_Norm(const std::vector<T> &x) {
240  T result = 0.0;
241  for (const auto &i : x) result += i * i;
242 
243  return std::sqrt(result);
244 }
245 
246 // adds two vectors
247 template <typename T>
248 std::vector<T> operator+(const std::vector<T> &x, const std::vector<T> &y) {
249  if (x.size() != y.size()) {
250  std::cerr << "Vectors must be same length for addition" << std::endl;
251  exit(1);
252  }
253 
254  std::vector<T> result(x.size());
255  for (std::size_t i = 0; i < x.size(); ++i) result[i] = x[i] + y[i];
256  return result;
257 }
258 
259 // sub two vectors
260 template <typename T>
261 std::vector<T> operator-(const std::vector<T> &x, const std::vector<T> &y) {
262  if (x.size() != y.size()) {
263  std::cerr << "Vectors must be same length for subtraction" << std::endl;
264  exit(1);
265  }
266 
267  std::vector<T> result(x.size());
268  for (std::size_t i = 0; i < x.size(); ++i) result[i] = x[i] - y[i];
269  return result;
270 }
271 
272 // multiplies vector by scalar
273 template <typename T>
274 std::vector<T> operator*(T a, const std::vector<T> &x) {
275  std::vector<T> result(x.size());
276  for (std::size_t i = 0; i < x.size(); ++i) result[i] = a * x[i];
277  return result;
278 }
279 
280 template <typename T>
281 std::vector<T> hadamard(const std::vector<T> &x, const std::vector<T> &y) {
282  if (x.size() != y.size()) {
283  std::cerr << "Vectors must be same length for Hadamard product"
284  << std::endl;
285  exit(1);
286  }
287 
288  std::vector<T> result(x.size());
289  for (std::size_t i = 0; i < x.size(); ++i) result[i] = x[i] * y[i];
290  return result;
291 }
292 
293 // computes reciprocal of argument
294 template <typename T>
295 T reciprocal(T x) {
296  return 1 / x;
297 }
298 
299 // converts string to character for std::atof function
300 std::shared_ptr<char> strToChar(const std::string &strng) {
301  std::shared_ptr<char> tab(new char[strng.length() + 1],
302  std::default_delete<char[]>());
303  std::strcpy(tab.get(), strng.c_str());
304  return tab;
305 }
306 
307 // decomposes a string into tokens using single delimiter
308 std::vector<std::string> Tokenize(const std::string &lineIn,
309  const char &delim) {
310  std::vector<std::string> rtrnTokens;
311 
312  std::string intermediate;
313  std::stringstream checkStr(lineIn);
314 
315  // Tokenizing
316  while (std::getline(checkStr, intermediate, delim)) {
317  rtrnTokens.push_back(intermediate);
318  }
319  return rtrnTokens;
320 }
321 
322 // decomposes a string into tokens using string of delimiters
323 std::vector<std::string> Tokenize(const std::string &lineIn,
324  const std::string &delim) {
325  std::vector<std::string> rtrnTokens;
326  std::vector<char> delimStr;
327  delimStr.reserve(delim.size());
328 
329  for (int i = 0; i < delim.size(); i++) delimStr.push_back(delim[i]);
330 
331  std::string intermediate;
332  std::stringstream checkStr(lineIn);
333 
334  // Tokenizing
335  int iter = 0;
336  while (std::getline(checkStr, intermediate, delimStr[iter])) {
337  rtrnTokens.push_back(intermediate);
338  iter++;
339  }
340  return rtrnTokens;
341 }
342 
343 // IN PLACE, computes reciprocal of vector elements
344 template <typename T>
345 void reciprocal_vec(std::vector<T> &x) {
346  std::transform(x.begin(), x.end(), x.begin(), reciprocal<T>);
347 }
348 
349 template <typename T>
350 bool hasZero(const std::vector<T> &x) {
351  for (const auto &i : x)
352  if (i == 0) return true;
353  return false;
354 }
355 
356 // find minmax of vector, excluding inf
357 template <typename T>
358 std::vector<T> getMinMax(const std::vector<T> &x) {
359  std::vector<T> tmp;
360  for (std::size_t i = 0; i < x.size(); ++i)
361  if (!std::isinf(x[i])) // exclude inf
362  tmp.push_back(x[i]);
363 
364  auto minmax = std::minmax_element(tmp.begin(), tmp.end());
365 
366  return {*minmax.first, *minmax.second};
367 }
368 
369 // scales x from range [xmin, xmax] to within range [ymin, ymax]
370 // if x is inf, the scaled value will be ymax
371 template <typename T>
372 T scale_to_range(T x, const std::vector<T> &xminmax,
373  const std::vector<T> &yminmax) {
374  if (std::isinf(x)) return yminmax[1];
375  return yminmax[0] + (yminmax[1] - yminmax[0]) * (x - xminmax[0]) /
376  (xminmax[1] - xminmax[0]);
377 }
378 
379 // IN PLACE, scales each number in vector in range [xmin, xmax] to [ymin,ymax]
380 template <typename T>
381 void scale_vec_to_range(std::vector<T> &x, const std::vector<T> &xminmax,
382  const std::vector<T> &yminmax) {
383  for (auto &&i : x) i = scale_to_range(i, xminmax, yminmax);
384 }
385 
386 // get average and stdev of values
387 template <typename T>
388 std::vector<T> getMeanStdev(const std::vector<T> &x) {
389  T ave = 0;
390  for (const auto &i : x) ave += i;
391  ave /= x.size();
392 
393  T stdev = 0;
394  for (const auto &i : x) stdev += (i - ave) * (i - ave);
395  stdev = std::sqrt(stdev / x.size());
396 
397  return {ave, stdev};
398 }
399 
400 // generates boolean array with 1 if value >= tol, 0 otherwise
401 template <typename T>
402 std::vector<bool> cellsToRefine(const std::vector<T> &values, T tol) {
403  std::vector<bool> result(values.size(), false);
404  for (std::size_t i = 0; i < values.size(); ++i)
405  if (values[i] > tol) result[i] = true;
406  return result;
407 }
408 
409 // generates boolean array with true if value >= mean+/-dev, false otherwise
410 template <typename T>
411 std::vector<bool> cellsToRefineStdev(const std::vector<T> &values, T mean,
412  T dev) {
413  if (std::abs(dev / mean) >= 1.0) dev = 0.99 * mean;
414 
415  T th = mean + dev;
416  T tl = mean - dev;
417 
418  std::vector<bool> result(values.size(), false);
419  for (std::size_t i = 0; i < values.size(); ++i)
420  if (values[i] > th || values[i] < tl) result[i] = true;
421  return result;
422 }
423 
424 // generates boolean array with 1 if value >= mean+/-dev, 0 otherwise
425 template <typename T>
426 std::vector<bool> cellsToRefineMaxdev(const std::vector<T> &values, T dev) {
427  dev = std::abs(dev);
428  if (dev > 1) dev = 1;
429 
430  T max = *std::max_element(values.begin(), values.end());
431  T hl = (1 - dev) * max;
432 
433  std::vector<bool> result(values.size(), false);
434  for (std::size_t i = 0; i < values.size(); ++i)
435  if (values[i] > hl) result[i] = true;
436  return result;
437 }
438 
439 // string trimming for consistent file names
440 std::string trim_fname(const std::string &fname, const std::string &ext) {
441  std::string::size_type end = fname.find_last_of('.');
442  if (end != std::string::npos) {
443  return fname.substr(0, end).append(ext);
444  } else {
445  std::cerr << "Error finding file extension for " << fname << std::endl;
446  exit(1);
447  }
448 }
449 
450 // find file extension
451 std::string find_ext(const std::string &fname) {
452  std::string::size_type last = fname.find_last_of('.');
453  if (last != std::string::npos) {
454  return fname.substr(last);
455  } else {
456  std::cerr << "Error finding file extension for " << fname << std::endl;
457  exit(1);
458  }
459 }
460 
461 // IN PLACE, to lower
462 void toLower(std::string &str) {
463  std::transform(str.begin(), str.end(), str.begin(), ::tolower);
464 }
465 
466 // IN PLACE, to upper
467 void toUpper(std::string &str) {
468  std::transform(str.begin(), str.end(), str.begin(), ::toupper);
469 }
470 
471 // return from beginning to the location of str
472 std::string findToStr(const std::string &str, const std::string &ptrn) {
473  return str.substr(0, str.find_first_of(ptrn));
474 }
475 
476 // return from the location of str
477 std::string findFromStr(const std::string &str, const std::string &ptrn) {
478  return str.substr(str.find_first_of(ptrn) + 1, std::string::npos);
479 }
480 
481 // returns current time as string
482 std::string getTimeStr() {
483  time_t rawTime;
484  struct tm *timeInfo;
485  char buffer[80];
486 
487  time(&rawTime);
488  timeInfo = localtime(&rawTime);
489 
490  strftime(buffer, sizeof(buffer), "%d-%m-%Y %I:%M:%S %p", timeInfo);
491  std::string str(buffer);
492 
493  return str;
494 }
495 
496 // find file name
497 std::string find_name(const std::string &fname) {
498  std::string::size_type first = fname.find_last_of('/');
499  std::string::size_type last = fname.find_last_of('.');
500  if (first != std::string::npos && last != std::string::npos) {
501  return fname.substr(first + 1, last);
502  } else {
503  std::cerr << "error finding file extension for " << fname << std::endl;
504  exit(1);
505  }
506 }
507 
508 // print vector
509 template <typename T>
510 void printVec(const std::vector<T> &v) {
511  for (const auto &i : v) std::cout << std::setprecision(15) << i << " ";
512  std::cout << std::endl;
513 }
514 
515 // find is val is in vector
516 template <typename T>
517 bool valInVec(const std::vector<T> &v, T val) {
518  for (const auto &i : v)
519  if (i == val) return true;
520  return false;
521 }
522 
523 template <typename A, typename B>
524 std::pair<B, A> flip_pair(const std::pair<A, B> &p) {
525  return std::pair<B, A>(p.second, p.first);
526 }
527 
528 template <typename A, typename B>
529 std::multimap<B, A> flip_map(const std::map<A, B> &src) {
530  std::multimap<B, A> dst;
531  std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()),
532  flip_pair<A, B>);
533  return dst;
534 }
535 
536 template <typename T>
537 bool isInBBox(const std::vector<T> &crd, const std::vector<T> &bb) {
538  for (std::size_t i = 0; i < crd.size(); ++i)
539  if (crd[i] < bb[2 * i] || crd[i] > bb[2 * i + 1]) return false;
540  return true;
541 }
542 
543 template <typename A, typename B>
544 std::vector<A> getSortedKeys(const std::map<A, B> &mapObj) {
545  if (!mapObj.empty()) {
546  std::vector<A> sortedKeys(mapObj.size());
547  for (const auto &i : mapObj) sortedKeys.emplace_back(i.first);
548  return sortedKeys;
549  } else {
550  std::cerr << "Map is empty! No sorted keys to return." << std::endl;
551  exit(1);
552  }
553 }
554 
555 // generate a random string of given length
556 std::string getRandomString(int length) {
557  const char *alp = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
558  std::random_device rd;
559  std::default_random_engine dre(rd());
560  std::uniform_int_distribution<int> uid(0, strlen(alp) - 1);
561 
562  std::string out;
563  for (int i = 0; i < length; ++i) out += alp[uid(dre)];
564 
565  return out;
566 }
567 
568 template <typename A, typename B>
569 A leastUnusedKey(const std::map<A, B> &map, A min) {
570  A i = min;
571  auto it = map.begin();
572  if (min > 1) {
573  auto ub = map.upper_bound(min);
574  if (ub != it) {
575  it = --ub;
576  }
577  }
578  for (; it != map.end(); ++it) {
579  if (it->first == i) {
580  ++i;
581  } else {
582  return i;
583  }
584  }
585  return i;
586 }
587 
588 //---------------------------End nemAux namespace-----------------------------//
589 } // namespace nemAux
590 
591 #endif // NEMOSYS_AUXILIARYFUNCTIONS_H_
void scale_vec_to_range(std::vector< T > &x, const std::vector< T > &xminmax, const std::vector< T > &yminmax)
std::multimap< B, A > flip_map(const std::map< A, B > &src)
std::string getTimeStr()
std::vector< T > getMinMax(const std::vector< T > &x)
A leastUnusedKey(const std::map< A, B > &map, A min=1)
T reciprocal(T x)
std::vector< T > getMeanStdev(const std::vector< T > &x)
std::vector< bool > cellsToRefineMaxdev(const std::vector< T > &values, T dev)
void reciprocal_vec(std::vector< T > &x)
std::vector< std::string > Tokenize(const std::string &lineIn, const char &delim)
std::string find_ext(const std::string &fname)
std::shared_ptr< char > strToChar(const std::string &strng)
std::chrono::time_point< std::chrono::system_clock > time_t
std::vector< T > operator+(const std::vector< T > &x, const std::vector< T > &y)
std::string findToStr(const std::string &str, const std::string &ptrn)
std::pair< B, A > flip_pair(const std::pair< A, B > &p)
void toUpper(std::string &str)
std::string findFromStr(const std::string &str, const std::string &ptrn)
std::string trim_fname(const std::string &name, const std::string &ext)
std::string getRandomString(int length)
void toLower(std::string &str)
T scale_to_range(T x, const std::vector< T > &xminmax, const std::vector< T > &yminmax)
std::string find_name(const std::string &fname)
std::vector< T > hadamard(const std::vector< T > &x, const std::vector< T > &y)
bool valInVec(const std::vector< T > &v, T val)
std::vector< T > operator*(T a, const std::vector< T > &x)
void printVec(const std::vector< T > &v)
std::vector< bool > cellsToRefineStdev(const std::vector< T > &values, T mean, T dev)
bool isInBBox(const std::vector< T > &crd, const std::vector< T > &bb)
std::vector< T > operator-(const std::vector< T > &x, const std::vector< T > &y)
bool hasZero(const std::vector< T > &x)
std::vector< std::vector< T > > fold(const std::vector< T > &v, int dim)
std::vector< A > getSortedKeys(const std::map< A, B > &mapObj)
std::vector< bool > cellsToRefine(const std::vector< T > &values, T tol)
std::vector< T > flatten(const std::vector< std::vector< T >> &v)
T l2_Norm(const std::vector< T > &x)