TransFlow  0.1.0
A transient pipeline flow simulation library
utilities.hpp
1 #pragma once
2 
3 #include <string>
4 #include <cmath>
5 #include <exception>
6 #include <armadillo>
7 
12 namespace utils
13 {
14  inline double pow2(const double a);
15  inline arma::vec pow2(const arma::vec& a);
16  inline double pow3(const double a);
17  inline double pow4(const double a);
18  inline double pow5(const double a);
19  inline double pow6(const double a);
20 
21  inline arma::vec cubeRoot(const arma::vec& input);
22 
23  inline arma::vec centerDifference(const arma::vec& input);
24 
25  inline arma::vec centerDifference(const arma::subview_col<arma::mat::elem_type>& input);
26 
27  inline arma::vec centerSum(const arma::vec& input);
28 
29  inline arma::vec centerSum(const arma::subview_col<arma::mat::elem_type>& input);
30 
31  inline arma::vec centerAverage(const arma::vec& input);
32 
33  inline arma::vec centerAverage(const arma::subview_col<arma::mat::elem_type>& input);
34 
35  inline arma::vec weightedAverage(const arma::vec& weightA, const arma::vec& weightB, const arma::vec& A, const arma::vec& B);
36 
37  inline double weightedAverage(const double weightA, const double weightB, const double A, const double B);
38 
39  inline bool isRelativeDifferenceWithinTolerance(
40  const double oldValue,
41  const double newValue,
42  const double tolerance);
43 
44  inline bool areRelativeDifferencesWithinTolerance(
45  const arma::vec& oldValues,
46  const arma::vec& newValues,
47  const double tolerance);
48 
49  inline double convertBurialToStandardDefinition(
50  const double burial,
51  const double innerDiameter,
52  const arma::rowvec& width);
53 
54  inline double convertBurialToStandardDefinition(
55  const double burial,
56  const double innerDiameter,
57  const arma::subview_row<arma::mat::elem_type>& width);
58 
59  inline arma::vec convertBurialToStandardDefinition(
60  const arma::vec& burial,
61  const arma::vec& innerDiameter,
62  const arma::colvec& width);
63 
64  inline arma::vec convertBurialToStandardDefinition(
65  const arma::vec& burial,
66  const arma::vec& innerDiameter,
67  const arma::mat& width);
68 
69  inline arma::vec smooth(const arma::vec& x, const double smoothness);
70 
71  inline arma::vec smoothTransition(const arma::vec& firstPart, const arma::vec& lastPart, double smoothness = 1.0, const double timeStep = 60);
72 
73  inline arma::vec createSmoothTransient(
74  const double initialValue,
75  const double finalValue,
76  const arma::uword n,
77  const double smoothness,
78  const arma::uword dt);
79 
80  inline arma::vec findLogSpacedConcentricShellWidths(
81  const double innerRadius,
82  const double outerRadius,
83  const arma::uword nShells);
84 
85  inline arma::cube loadCubeFromFile(const std::string& filename, const arma::file_type& fileType = arma::csv_ascii);
86  inline arma::mat loadMatFromFile(const std::string& filename, const arma::file_type& fileType = arma::csv_ascii);
87  inline arma::vec loadVecFromFile(const std::string& filename, const arma::file_type& fileType = arma::csv_ascii);
88 }
89 
90 inline double utils::pow2(const double a)
91 {
92  return a*a;
93 }
94 
95 inline arma::vec utils::pow2(const arma::vec& a)
96 {
97  return a%a;
98 }
99 
100 inline double utils::pow3(const double a)
101 {
102  return a*a*a;
103 }
104 
105 inline double utils::pow4(const double a)
106 {
107  return a*a*a*a;
108 }
109 
110 inline double utils::pow5(const double a)
111 {
112  return a*a*a*a*a;
113 }
114 
115 inline double utils::pow6(const double a)
116 {
117  return a*a*a*a*a*a;
118 }
119 
120 inline arma::vec utils::cubeRoot(const arma::vec& input)
121 {
122  arma::vec cubed = arma::zeros<arma::vec>(input.n_elem);
123  for (arma::uword i = 0; i < input.n_elem; i++)
124  {
125  cubed(i) = std::cbrt(input(i));
126  }
127  return cubed;
128 }
129 
130 arma::vec utils::centerDifference(const arma::vec& input)
131 {
132  return input(arma::span(1, input.n_elem - 1)) - input(arma::span(0, input.n_elem - 2));
133 }
134 
135 arma::vec utils::centerDifference(const arma::subview_col<arma::mat::elem_type>& input)
136 {
137  return input.rows(1, input.n_elem - 1) - input.rows(0, input.n_elem - 2);
138 }
139 
140 arma::vec utils::centerSum(const arma::vec& input)
141 {
142  return input(arma::span(1, input.n_elem - 1)) + input(arma::span(0, input.n_elem - 2));
143 }
144 
145 arma::vec utils::centerSum(const arma::subview_col<arma::mat::elem_type>& input)
146 {
147  return input.rows(1, input.n_elem - 1) + input.rows(0, input.n_elem - 2);
148 }
149 
150 arma::vec utils::centerAverage(const arma::vec& input)
151 {
152  return centerSum(input)/2.0;
153 }
154 
155 arma::vec utils::centerAverage(const arma::subview_col<arma::mat::elem_type>& input)
156 {
157  return centerSum(input)/2.0;
158 }
159 
160 double utils::weightedAverage(const double weightA, const double weightB, const double A, const double B)
161 {
162  if (std::round(weightA + weightB) == 0)
163  {
164  throw std::invalid_argument("utils::weightedAverage(): both weights are zero");
165  }
166 
167  return (A*weightA + B*weightB)/(weightA + weightB);
168 }
169 
170 arma::vec utils::weightedAverage(const arma::vec& weightA, const arma::vec& weightB, const arma::vec& A, const arma::vec& B)
171 {
172  if (!arma::all((weightA + weightB) != 0))
173  {
174  throw std::invalid_argument("utils::weightedAverage(): both weights are zero");
175  }
176 
177  return (A % weightA + B % weightB)/(weightA + weightB);
178 }
179 
180 bool utils::isRelativeDifferenceWithinTolerance(
181  const double oldValue,
182  const double newValue,
183  const double tolerance)
184 {
185  double relativeDifference;
186  if (oldValue != 0)
187  {
188  relativeDifference = std::abs(newValue - oldValue)/std::abs(oldValue);
189  }
190  else if (newValue != 0)
191  {
192  relativeDifference = std::abs(newValue - oldValue)/std::abs(newValue);
193  }
194  else
195  {
196  // both values zero, difference also zero
197  return true;
198  }
199  return relativeDifference < tolerance;
200 }
201 
202 bool utils::areRelativeDifferencesWithinTolerance(
203  const arma::vec& oldValues,
204  const arma::vec& newValues,
205  const double tolerance)
206 {
207  for (arma::uword i = 0; i < oldValues.n_elem; i++)
208  {
209  double relativeDifference;
210  if (oldValues(i) != 0)
211  {
212  relativeDifference = std::abs(newValues(i) - oldValues(i))/std::abs(oldValues(i));
213  }
214  else if (newValues(i) != 0)
215  {
216  relativeDifference = std::abs(newValues(i) - oldValues(i))/std::abs(newValues(i));
217  }
218  else
219  {
220  // both values zero, difference also zero
221  continue;
222  }
223 
224  if (relativeDifference > tolerance)
225  {
226  return false;
227  }
228  }
229 
230  return true;
231 }
232 
233 double utils::convertBurialToStandardDefinition(
234  const double burial,
235  const double innerDiameter,
236  const arma::rowvec& width)
237 {
238  return burial + innerDiameter/2.0 + arma::sum(width);
239 }
240 
241 double utils::convertBurialToStandardDefinition(
242  const double burial,
243  const double innerDiameter,
244  const arma::subview_row<arma::mat::elem_type>& width)
245 {
246  return burial + innerDiameter/2.0 + arma::sum(width);
247 }
248 
249 arma::vec utils::convertBurialToStandardDefinition(
250  const arma::vec& burial,
251  const arma::vec& innerDiameter,
252  const arma::colvec& width)
253 {
254  return burial + innerDiameter/2.0 + arma::sum(width);
255 }
256 
257 arma::vec utils::convertBurialToStandardDefinition(
258  const arma::vec& burial,
259  const arma::vec& innerDiameter,
260  const arma::mat& width)
261 {
262  // burial depth is defined as "from top of soil to center of pipe" in our code,
263  // but given as distance from top of pipe to top of soil in thesis and in SIM
264  // this means that we have to add half a diameter + the width of all layers to convert
265  arma::vec convertedBurial = arma::zeros<arma::vec>(burial.n_elem);
266  for (arma::uword i = 0; i < burial.n_elem; i++)
267  {
268  convertedBurial(i) = convertBurialToStandardDefinition(burial(i), innerDiameter(i), width.row(i));
269  }
270 
271  return convertedBurial;
272 }
273 
274 arma::vec utils::smooth(const arma::vec& x, const double smoothness)
275 {
276  return 0.5 + 0.5*tanh((x - 0.5)/smoothness); // use x - 0.5 to get transition point to be between x = 0 and x = 1.0
277 }
278 
279 arma::vec utils::smoothTransition(
280  const arma::vec& firstPart,
281  const arma::vec& lastPart,
282  double smoothness,
283  const double timeStep)
284 {
285  // smooths transition from firstPart to lastPart by using a tanh function
286  // idea from here: http://www.j-raedler.de/2010/10/smooth-transition-between-functions-with-tanh/
287 
288  // the smoothing is time-independent (or time-depending, depending on how you look at it),
289  // meaning that changing the time step but using the same smoothness should result in the same smoothed curve,
290  // if you also scale the x-axis correctly (meaning: use time on the x-axis, not number of time steps)
291 
292  // a smoothness of 1.0 will give a transition that uses approx. 10 minutes
293  // a smoothness of 5.0 will use around 30 minutes
294 
295  arma::uword m = firstPart.n_elem;
296  arma::uword n = lastPart.n_elem;
297 
298  // non-dimensionalizing smoothness
299  // default time step of 60 gives no scaling
300  smoothness *= 60.0/timeStep; // 60 is standard timestep
301 
302  arma::vec f = arma::join_cols(
303  firstPart,
304  arma::zeros<arma::vec>(n) + firstPart(m-1) // repeat last element of firstPart
305  );
306  arma::vec g = arma::join_cols(
307  arma::zeros<arma::vec>(m) + lastPart(0), // repeat first element of lastPart
308  lastPart
309  );
310 
311  arma::vec x = arma::linspace(-int(m)+1, n, m+n); // !!! cast to int before subtracting, since m is unsigned int!!!
312  arma::vec s = smooth(x, smoothness);
313 
314  arma::vec h = (1-s) % f + s % g;
315 
316  return h;
317 }
318 
319 arma::vec utils::createSmoothTransient(
320  const double initialValue,
321  const double finalValue,
322  const arma::uword n,
323  const double smoothness,
324  const arma::uword dt)
325 {
326  // transient will be centered in interval [0, n]
327  if (n % 2 != 0)
328  {
329  std::cout << "n (" << n << ") should be divisible by 2!" << std::endl;
330  }
331  arma::vec a = arma::zeros<arma::vec>(n/2) + initialValue;
332  arma::vec b = arma::zeros<arma::vec>(n/2) + finalValue;
333  return smoothTransition(a, b, smoothness, dt);
334 }
335 
336 arma::vec utils::findLogSpacedConcentricShellWidths(
337  const double innerRadius,
338  const double outerRadius,
339  const arma::uword nShells)
340 {
341  arma::vec logSpacedLayerRadii = arma::logspace(log10(innerRadius), log10(outerRadius), nShells+1);
342  arma::vec logSpacedLayerWidths = arma::zeros<arma::vec>(nShells);
343  for (arma::uword i = 0; i < nShells; i++)
344  {
345  logSpacedLayerWidths(i) = logSpacedLayerRadii(i+1) - logSpacedLayerRadii(i);
346  }
347 
348  return logSpacedLayerWidths;
349 }
350 
351 arma::cube utils::loadCubeFromFile(const std::string& filename, const arma::file_type& fileType)
352 {
353  arma::cube c;
354  if (!c.load(filename, fileType))
355  {
356  throw std::runtime_error("Couldn't load file \"" + filename + "\"");
357  }
358 
359  return c;
360 }
361 
362 arma::mat utils::loadMatFromFile(const std::string& filename, const arma::file_type& fileType)
363 {
364  arma::mat m;
365  if (!m.load(filename, fileType))
366  {
367  throw std::runtime_error("Couldn't load file \"" + filename + "\"");
368  }
369 
370  return m;
371 }
372 
373 arma::vec utils::loadVecFromFile(const std::string& filename, const arma::file_type& fileType)
374 {
375  arma::vec v;
376  if (!v.load(filename, fileType))
377  {
378  throw std::runtime_error("Couldn't load file \"" + filename + "\"");
379  }
380 
381  return v;
382 }
utils
Definition: utils.hpp:10