PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/share/functions.cxx

https://gitlab.com/ineris/amc
C++ | 570 lines | 396 code | 108 blank | 66 comment | 84 complexity | 2011047747ca3434140b72312d66e57b MD5 | raw file
Possible License(s): GPL-3.0
  1. // Copyright (C) 2013-2015 INERIS
  2. // Author(s) : Edouard Debry
  3. //
  4. // This file is part of AMC.
  5. //
  6. // AMC is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // AMC is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with AMC. If not, see <http://www.gnu.org/licenses/>.
  18. #ifndef AMC_FILE_FUNCTIONS_CXX
  19. #include "functions.hxx"
  20. namespace AMC
  21. {
  22. // Compute cubic root.
  23. inline float pow3(float x)
  24. {
  25. // Save constant befor modifying it.
  26. float a = x * 0.3333333333333333333;
  27. // First approximation.
  28. const int ebits = 8;
  29. const int fbits = 23;
  30. const int n = 3;
  31. int32_t& i = (int32_t&) x;
  32. const int32_t bias = (1 << (ebits - 1)) - 1;
  33. i = (i - (bias << fbits)) / n + (bias << fbits);
  34. x = 0.6666666666666666666 * x + a / (x * x);
  35. x = 0.6666666666666666666 * x + a / (x * x);
  36. x = 0.6666666666666666666 * x + a / (x * x);
  37. x = 0.6666666666666666666 * x + a / (x * x);
  38. return x;
  39. }
  40. inline double pow3(double x)
  41. {
  42. // Save constant befor modifying it.
  43. double a = x * 0.3333333333333333333;
  44. // First approximation.
  45. const int ebits = 11;
  46. const int fbits = 52;
  47. const int n = 3;
  48. int64_t& i = (int64_t&) x;
  49. const int64_t bias = (1 << (ebits - 1)) - 1;
  50. i = (i - (bias << fbits)) / n + (bias << fbits);
  51. x = 0.6666666666666666666 * x + a / (x * x);
  52. x = 0.6666666666666666666 * x + a / (x * x);
  53. x = 0.6666666666666666666 * x + a / (x * x);
  54. x = 0.6666666666666666666 * x + a / (x * x);
  55. return x;
  56. }
  57. // Get the number of power of p out of n.
  58. inline int get_power_out_of(const int &n, const int p)
  59. {
  60. int i(0), j(n);
  61. while (j / p > 0)
  62. {
  63. j /= p;
  64. i++;
  65. }
  66. return i;
  67. }
  68. // Check index.
  69. inline void check_index(const int &index_min, const int &index_max, const int &index)
  70. {
  71. if (index < index_min || index >= index_max)
  72. throw string("Out of range index, should be within ["
  73. + to_str(index_min) + ", " + to_str(index_max)
  74. + "[, got " + to_str(index) + ".");
  75. }
  76. // Get combinations of p values within n.
  77. bool get_combination(const int &p, const int &n, vector<int> &index_reference, vector<int> &index)
  78. {
  79. int i, j, k;
  80. if (int(index_reference.size()) == 0)
  81. for (i = 0; i < p; i++)
  82. index_reference.push_back(i);
  83. if (index_reference == index)
  84. return false;
  85. index = index_reference;
  86. for (i = 0; i < p; i++)
  87. {
  88. j = p - i - 1;
  89. if (index_reference[j] < n - 1 - i)
  90. {
  91. index_reference[j]++;
  92. for (k = j + 1; k < p; k++)
  93. index_reference[k] = index_reference[k - 1] + 1;
  94. break;
  95. }
  96. }
  97. return true;
  98. }
  99. // Find convex hull of a polygon.
  100. template<class T>
  101. void find_polygon_convex_hull(const int &p, const int &n, const vector<T> &point, vector<int> &edge)
  102. {
  103. // n is the number of points.
  104. // p is the points dimension.
  105. // Then, point should be of dimension n * p.
  106. if (int(point.size()) != (n * p))
  107. throw string("Size of point vector is " + to_str(point.size()) + ", expected " + to_str(n * p) + ".");
  108. int q = p + 1;
  109. vector<int> index_reference, index;
  110. // When number of points is just below the dimension all points are edges.
  111. if (n == q)
  112. while(get_combination(p, n, index_reference, index))
  113. for (int i = 0; i < p; i++)
  114. edge.push_back(index[i]);
  115. else
  116. {
  117. int p2 = p * p;
  118. int q2 = q * q;
  119. while(get_combination(p, n, index_reference, index))
  120. {
  121. // Compute supplementary index.
  122. vector<int> index_supplementary;
  123. for (int i = 0; i < n; i++)
  124. {
  125. bool is_included(false);
  126. for (int j = 0; j < p; j++)
  127. if (i == index[j])
  128. {
  129. is_included = true;
  130. break;
  131. }
  132. if (! is_included)
  133. index_supplementary.push_back(i);
  134. }
  135. int np = int(index_supplementary.size());
  136. if (np != (n - p))
  137. throw string("Wrong number of supplementary points, got " + to_str(np) + ", expected " + to_str(n - p) + ".");
  138. // Compute intermediate determinants.
  139. vector<T> mat(q2, T(1));
  140. int i(q);
  141. for (int j = 0; j < p; j++)
  142. {
  143. int l = p * index[j];
  144. for (int k = 0; k < p; k++)
  145. mat[i++] = point[l + k];
  146. i++;
  147. }
  148. vector<T> det(np);
  149. for (i = 0; i < np; i++)
  150. {
  151. int l = p * index_supplementary[i];
  152. for (int j = 0; j < p; j++)
  153. mat[j] = point[l + j];
  154. det[i] = compute_matrix_determinant<T>(mat, q);
  155. }
  156. for (i = 0; i < np; i++)
  157. if (det[i] == T(0))
  158. throw string("Got coplanar points.");
  159. bool same_sign(true);
  160. for (i = 1; i < np; i++)
  161. if (det[0] * det[i] < T(0))
  162. {
  163. same_sign = false;
  164. break;
  165. }
  166. // All determinants are of same sign,
  167. // this means all supplementary points are on
  168. // the same side of given surface, provided
  169. // the polygon is convex, this entails the surface
  170. // to be an edge.
  171. if (same_sign)
  172. for (i = 0; i < p; i++)
  173. edge.push_back(index[i]);
  174. }
  175. }
  176. }
  177. // Search index in a vector.
  178. template<typename T>
  179. inline int search_index(const vector<T> &v, const T &x, int imin, int imax)
  180. {
  181. imax = imax < 0 ? int(v.size()) + imax : imax;
  182. // Search algorithm
  183. if (x < v[imin])
  184. return imin;
  185. else if (x >= v[imax])
  186. return imax;
  187. else
  188. {
  189. int imid = (imin + imax) / 2;
  190. while (imax >= imin)
  191. {
  192. if (x > v[imid])
  193. imin = imid + 1;
  194. else if (x < v[imid])
  195. imax = imid - 1;
  196. else
  197. return imid;
  198. imid = (imin + imax) / 2;
  199. }
  200. return imid;
  201. }
  202. }
  203. template<typename T>
  204. inline int search_index_ascending(const vector<T> &v, const T x, int imin)
  205. {
  206. int imax = int(v.size()) - 1;
  207. for (int i = ++imin; i < imax; ++i)
  208. if (x < v[i])
  209. return --i;
  210. return --imax;
  211. }
  212. template<typename T>
  213. inline int search_index_descending(const vector<T> &v, const T x, int imax)
  214. {
  215. imax = imax < 0 ? int(v.size()) - 2 : imax;
  216. for (int i = imax; i > 0; --i)
  217. if (x >= v[i])
  218. return i;
  219. return 0;
  220. }
  221. // Test is one vector (v) is included into another one (w).
  222. template<typename T>
  223. bool is_included(const vector<T> &v, const vector<T> &w)
  224. {
  225. if (v.size() > w.size())
  226. throw string("Vector v has a greater size as vector w, hence cannot be included in this one.");
  227. size_t count(0);
  228. for (int i = 0; i < int(v.size()); i++)
  229. for (int j = 0; j < int(w.size()); j++)
  230. if (v[i] == w[j])
  231. {
  232. count++;
  233. break;
  234. }
  235. return count == v.size();
  236. }
  237. // Compute sum of vector or part of vector.
  238. template<typename T>
  239. inline T compute_vector_sum(const vector<T> &v, int n)
  240. {
  241. if (n <= 0)
  242. n += v.size();
  243. T sum(T(0));
  244. for (int i = 0; i < n; i++)
  245. sum += v[i];
  246. return sum;
  247. }
  248. // Compute the determinant of a matrix, stored in row major order (C-style).
  249. template<typename T>
  250. T compute_matrix_determinant(const vector<T> &matrix, int n)
  251. {
  252. if (n == 0)
  253. return 0;
  254. else if (n == 1)
  255. return matrix[0];
  256. else if (n == 2)
  257. return matrix[0] * matrix[3] - matrix[1] * matrix[2];
  258. else
  259. {
  260. T determinant(T(0));
  261. for (int i = 0; i < n; i++)
  262. {
  263. int n2 = n - 1;
  264. vector<T> matrix2(n2 * n2);
  265. int l(0), m(n);
  266. for (int j = 1; j < n; j++)
  267. {
  268. for (int k = 0; k < i; k++)
  269. matrix2[l++] = matrix[m++];
  270. m++;
  271. for (int k = i + 1; k < n; k++)
  272. matrix2[l++] = matrix[m++];
  273. }
  274. determinant += matrix[i]
  275. * ((i % 2 == 0) ? T(1) : T(-1))
  276. * compute_matrix_determinant(matrix2, n2);
  277. }
  278. return determinant;
  279. }
  280. }
  281. // Generate pseudo-random vector with law uniform.
  282. template<typename T>
  283. inline void generate_random_vector(const int &n, vector<T> &random, const T sum)
  284. {
  285. random.assign(n, sum);
  286. for (int i = 0; i < n - 1; i++)
  287. random[i] = sum * T(drand48());
  288. sort(random.begin(), random.end());
  289. for (int i = n - 1; i > 0; --i)
  290. random[i] -= random[i - 1];
  291. }
  292. // Set the random generator seed in C++.
  293. void set_random_generator(const int &seed)
  294. {
  295. srand48(seed);
  296. }
  297. // Generate one random vector.
  298. template<typename T>
  299. vector<T> generate_random_vector(const int &n, const T sum)
  300. {
  301. vector<T> random;
  302. generate_random_vector(n, random, sum);
  303. return random;
  304. }
  305. // Split one 2D domain into most equally possible subdomains.
  306. void split_domain(const int n, int &p, int &q)
  307. {
  308. vector<int> vp, vq, rank;
  309. const int Np(p), Nq(q);
  310. p = 0;
  311. q = 0;
  312. while (p < n)
  313. {
  314. p++;
  315. if (n % p == 0)
  316. {
  317. vp.push_back(p);
  318. q = n / p;
  319. vq.push_back(q);
  320. rank.push_back(abs(Nq * p - Np * q));
  321. }
  322. }
  323. // Which couple is the best ?
  324. int i(0);
  325. for (int j = 1; j < int(rank.size()); ++j)
  326. if (rank[j] < rank[i]) i = j;
  327. p = vp[i];
  328. q = vq[i];
  329. }
  330. // Compute the Gauss-Legendre quadrature zeros and weights, from Numerical Recipes in C.
  331. template<typename T>
  332. void compute_gauss_legendre_zero_weight(const int &n, T *x, T *w,
  333. const T x1, const T x2,
  334. const T eps)
  335. {
  336. // High precision is a good idea for this routine.
  337. int m, j, i;
  338. double z1, z, xm, xl, pp, p3, p2, p1;
  339. // The roots are symmetric in the interval, so we only have to find half of them.
  340. m = (n + 1) / 2;
  341. xm = 0.5 * (x2 + x1);
  342. xl = 0.5 * (x2 - x1);
  343. // Loop over the desired roots.
  344. for (i = 1; i <= m; i++)
  345. {
  346. z = cos(3.14159265358979323846 * (i - 0.25) / (n + 0.5));
  347. // Starting with the above approximation to the ith root,
  348. // we enter the main loop of refinement by Newton’s method.
  349. do
  350. {
  351. p1 = 1.0;
  352. p2 = 0.0;
  353. // Loop up the recurrence relation to get the Legendre polynomial evaluated at z.
  354. for (j = 1; j <= n; j++)
  355. {
  356. p3 = p2;
  357. p2 = p1;
  358. p1 = ((2.0 * j - 1.0) * z * p2 - (j - 1.0) * p3) / j;
  359. }
  360. // p1 is now the desired Legendre polynomial. We next compute pp, its derivative,
  361. // by a standard relation involving also p2, the polynomial of one lower order.
  362. pp = n * (z * p1 - p2) / (z * z - 1.0);
  363. z1 = z;
  364. z = z1 - p1 / pp;
  365. // Newton’s method.
  366. }
  367. while (fabs(z - z1) > eps);
  368. // Scale the root to the desired interval.
  369. x[i] = xm - xl * z;
  370. x[n+1-i] = xm + xl * z;
  371. w[i] = 2.0 * xl / ((1.0 - z * z) * pp * pp);
  372. // Compute the weight and its symmetric counterpart.
  373. w[n + 1 - i] = w[i];
  374. }
  375. }
  376. // Comute cubic splines.
  377. template<typename T>
  378. void compute_cubic_spline(const int n, const T *x, const T *y, T *y2, const T *yp1, const T *ypn)
  379. {
  380. vector<T> u(n - 1, T(0));
  381. if (yp1 == NULL)
  382. {
  383. y2[0] = T(0);
  384. u[0] = T(0);
  385. }
  386. else
  387. {
  388. y2[0] = -T(0.5);
  389. u[0] = (T(3) / (x[1] - x[0])) * ((y[1] - y[0]) / (x[1] - x[0]) - *yp1);
  390. }
  391. for (int i = 1; i < n - 1; ++i)
  392. {
  393. const T sig=(x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]);
  394. const T p = sig * y2[i - 1] + T(2);
  395. y2[i] = (sig - T(1)) / p;
  396. u[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]);
  397. u[i]=(T(6) * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p;
  398. }
  399. T qn(T(0)), un(T(0));
  400. if (ypn != NULL)
  401. {
  402. qn = T(0.5);
  403. un = (T(3) / (x[n - 1] - x[n - 2])) * (*ypn - (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2]));
  404. }
  405. y2[n - 1] = (un - qn * u[n - 2]) / (qn * y2[n - 2] + T(1));
  406. for (int k = n - 2; k >= 0; --k)
  407. y2[k] = y2[k] * y2[k + 1] + u[k];
  408. }
  409. template<typename T>
  410. T apply_cubic_spline(const int n, const T *xa, const T *ya, const T *y2a, const T &x)
  411. {
  412. int klo(0), khi(n - 1);
  413. while (khi - klo > 1)
  414. {
  415. const int k = (khi + klo) >> 1;
  416. if (xa[k] > x)
  417. khi = k;
  418. else
  419. klo = k;
  420. }
  421. const T h = xa[khi] - xa[klo];
  422. const T a = (xa[khi] - x) / h;
  423. const T b = (x - xa[klo]) / h;
  424. return a * ya[klo] + b * ya[khi] + (a * (a * a - T(1)) * y2a[klo] + b * (b * b - T(1)) * y2a[khi]) * (h * h) / T(6);
  425. }
  426. // Convert ppm to molecule per cm3.
  427. template<typename T>
  428. T convert_ppm_to_molecule_per_cm3(const T &pressure,
  429. const T &temperature,
  430. const T concentration)
  431. {
  432. // Na / R / 1.e-6 = 1.e6 / kb.
  433. return T(7.24297156525251e10) * concentration * pressure / temperature;
  434. }
  435. // Convert ppt to molecule per cm3.
  436. template<typename T>
  437. T convert_ppt_to_molecule_per_cm3(const T &pressure,
  438. const T &temperature,
  439. const T concentration)
  440. {
  441. // Na / R / 1.e-9 = 1.e9 / kb.
  442. return T(7.24297156525251e7) * concentration * pressure / temperature;
  443. }
  444. // Convert molecule per cm3 to ppm.
  445. template<typename T>
  446. T convert_molecule_per_cm3_to_ppm(const T &pressure,
  447. const T &temperature,
  448. const T concentration)
  449. {
  450. return T(1.3806488e-11) * concentration * temperature / pressure;
  451. }
  452. // Convert molecule per cm3 to ppt.
  453. template<typename T>
  454. T convert_molecule_per_cm3_to_ppt(const T &pressure,
  455. const T &temperature,
  456. const T concentration)
  457. {
  458. return T(1.3806488e-8) * concentration * temperature / pressure;
  459. }
  460. }
  461. #define AMC_FILE_FUNCTIONS_CXX
  462. #endif