CoolProp 8.0.0
An open-source fluid property and humid air property database
CPnumerics.cpp
Go to the documentation of this file.
3#include <cmath>
4#include <unsupported/Eigen/Polynomials>
5
6double root_sum_square(const std::vector<double>& x) {
7 double sum = 0;
8 for (double i : x) {
9 sum += pow(i, 2);
10 }
11 return sqrt(sum);
12}
13double interp1d(const std::vector<double>* x, const std::vector<double>* y, double x0) {
14 std::size_t i = 0, L = 0, R = 0, M = 0;
15 L = 0;
16 R = (*x).size() - 1;
17 M = (L + R) / 2;
18 // Use interval halving to find the indices which bracket the density of interest
19 while (R - L > 1) {
20 if (x0 >= (*x)[M]) {
21 L = M;
22 M = (L + R) / 2;
23 continue;
24 }
25 if (x0 < (*x)[M]) {
26 R = M;
27 M = (L + R) / 2;
28 continue;
29 }
30 }
31 i = L;
32 if (i < (*x).size() - 2) {
33 // Go "forwards" with the interpolation range
34 return QuadInterp((*x)[i], (*x)[i + 1], (*x)[i + 2], (*y)[i], (*y)[i + 1], (*y)[i + 2], x0);
35 } else {
36 // Go "backwards" with the interpolation range
37 return QuadInterp((*x)[i], (*x)[i - 1], (*x)[i - 2], (*y)[i], (*y)[i - 1], (*y)[i - 2], x0);
38 }
39}
40double powInt(double x, int y) {
41 // Raise a double to an integer power
42 // Overload not provided in math.h
43 int i = 0;
44 double product = 1.0;
45 double x_in = NAN;
46 int y_in = 0;
47
48 if (y == 0) {
49 return 1.0;
50 }
51
52 if (y < 0) {
53 x_in = 1 / x;
54 y_in = -y;
55 } else {
56 x_in = x;
57 y_in = y;
58 }
59
60 if (y_in == 1) {
61 return x_in;
62 }
63
64 product = x_in;
65 for (i = 1; i < y_in; i++) {
66 product = product * x_in;
67 }
68 return product;
69}
70
71void MatInv_2(double A[2][2], double B[2][2]) {
72 double Det = NAN;
73 //Using Cramer's Rule to solve
74
75 Det = A[0][0] * A[1][1] - A[1][0] * A[0][1];
76 B[0][0] = 1.0 / Det * A[1][1];
77 B[1][1] = 1.0 / Det * A[0][0];
78 B[1][0] = -1.0 / Det * A[1][0];
79 B[0][1] = -1.0 / Det * A[0][1];
80}
81
82void solve_cubic(double a, double b, double c, double d, int& N, double& x0, double& x1, double& x2) {
83 // 0 = ax^3 + b*x^2 + c*x + d
84
85 // First check if the "cubic" is actually a second order or first order curve
86 if (std::abs(a) < 10 * DBL_EPSILON) {
87 if (std::abs(b) < 10 * DBL_EPSILON) {
88 // Linear solution if a = 0 and b = 0
89 x0 = -d / c;
90 N = 1;
91 return;
92 } else {
93 // Quadratic solution(s) if a = 0 and b != 0
94 x0 = (-c + sqrt(c * c - 4 * b * d)) / (2 * b);
95 x1 = (-c - sqrt(c * c - 4 * b * d)) / (2 * b);
96 N = 2;
97 return;
98 }
99 }
100
101 // Ok, it is really a cubic
102
103 // Discriminant
104 double DELTA = 18 * a * b * c * d - 4 * b * b * b * d + b * b * c * c - 4 * a * c * c * c - 27 * a * a * d * d;
105 // Coefficients for the depressed cubic t^3+p*t+q = 0
106 double p = (3 * a * c - b * b) / (3 * a * a);
107 double q = (2 * b * b * b - 9 * a * b * c + 27 * a * a * d) / (27 * a * a * a);
108
109 if (DELTA < 0) {
110 // One real root
111 double t0 = NAN;
112 if (4 * p * p * p + 27 * q * q > 0 && p < 0) {
113 t0 = -2.0 * std::abs(q) / q * sqrt(-p / 3.0) * cosh(1.0 / 3.0 * acosh(-3.0 * std::abs(q) / (2.0 * p) * sqrt(-3.0 / p)));
114 } else {
115 t0 = -2.0 * sqrt(p / 3.0) * sinh(1.0 / 3.0 * asinh(3.0 * q / (2.0 * p) * sqrt(3.0 / p)));
116 }
117 N = 1;
118 x0 = t0 - b / (3 * a);
119 x1 = t0 - b / (3 * a);
120 x2 = t0 - b / (3 * a);
121 } else //(DELTA>0)
122 {
123 // Three real roots
124 double t0 = 2.0 * sqrt(-p / 3.0) * cos(1.0 / 3.0 * acos(3.0 * q / (2.0 * p) * sqrt(-3.0 / p)) - 0 * 2.0 * M_PI / 3.0);
125 double t1 = 2.0 * sqrt(-p / 3.0) * cos(1.0 / 3.0 * acos(3.0 * q / (2.0 * p) * sqrt(-3.0 / p)) - 1 * 2.0 * M_PI / 3.0);
126 double t2 = 2.0 * sqrt(-p / 3.0) * cos(1.0 / 3.0 * acos(3.0 * q / (2.0 * p) * sqrt(-3.0 / p)) - 2 * 2.0 * M_PI / 3.0);
127
128 N = 3;
129 x0 = t0 - b / (3 * a);
130 x1 = t1 - b / (3 * a);
131 x2 = t2 - b / (3 * a);
132 }
133}
134void solve_quartic(double a, double b, double c, double d, double e, int& N, double& x0, double& x1, double& x2, double& x3) {
135
136 // 0 = ax^4 + b*x^3 + c*x^2 + d*x + e
137
138 Eigen::PolynomialSolver<double, Eigen::Dynamic> solver;
139 Eigen::VectorXd coeff(5);
140 coeff << e, d, c, b, a;
141 solver.compute(coeff);
142
143 std::vector<double> realRoots;
144 solver.realRoots(realRoots);
145 N = static_cast<int>(realRoots.size());
146
147 if (N > 0) {
148 x0 = realRoots[0];
149 }
150 if (N > 1) {
151 x1 = realRoots[1];
152 }
153 if (N > 2) {
154 x2 = realRoots[2];
155 }
156 if (N > 3) {
157 x3 = realRoots[3];
158 }
159}
160
162 if (Nconstraints == 4) {
163 std::vector<double> abcd = CoolProp::linsolve(A, B);
164 a = abcd[0];
165 b = abcd[1];
166 c = abcd[2];
167 d = abcd[3];
168 return true;
169 } else {
170 throw CoolProp::ValueError(format("Number of constraints[%d] is not equal to 4", Nconstraints));
171 }
172}
173bool SplineClass::add_value_constraint(double x, double y) {
174 int i = Nconstraints;
175 if (i == 4) return false;
176 A[i][0] = x * x * x;
177 A[i][1] = x * x;
178 A[i][2] = x;
179 A[i][3] = 1;
180 B[i] = y;
181 Nconstraints++;
182 return true;
183}
184void SplineClass::add_4value_constraints(double x1, double x2, double x3, double x4, double y1, double y2, double y3, double y4) {
185 add_value_constraint(x1, y1);
186 add_value_constraint(x2, y2);
187 add_value_constraint(x3, y3);
188 add_value_constraint(x4, y4);
189}
190bool SplineClass::add_derivative_constraint(double x, double dydx) {
191 int i = Nconstraints;
192 if (i == 4) return false;
193 A[i][0] = 3 * x * x;
194 A[i][1] = 2 * x;
195 A[i][2] = 1;
196 A[i][3] = 0;
197 B[i] = dydx;
198 Nconstraints++;
199 return true;
200}
201double SplineClass::evaluate(double x) {
202 return a * x * x * x + b * x * x + c * x + d;
203}