27#ifndef OPM_POLYNOMIAL_UTILS_HH
28#define OPM_POLYNOMIAL_UTILS_HH
51template <
class Scalar,
class SolContainer>
56 if (std::abs(scalarValue(a)) < 1e-30)
79template <
class Scalar,
class SolContainer>
86 if (std::abs(scalarValue(a)) < 1e-30)
90 Scalar Delta = b*b - 4*a*c;
95 sol[0] = (- b + Delta)/(2*a);
96 sol[1] = (- b - Delta)/(2*a);
100 std::swap(sol[0], sol[1]);
105template <
class Scalar,
class SolContainer>
106void invertCubicPolynomialPostProcess_(SolContainer& sol,
115 for (
int i = 0; i < numSol; ++i) {
117 Scalar fOld = d + x*(c + x*(b + x*a));
119 Scalar fPrime = c + x*(2*b + x*3*a);
120 if (std::abs(scalarValue(fPrime)) < 1e-30)
124 Scalar fNew = d + x*(c + x*(b + x*a));
125 if (std::abs(scalarValue(fNew)) < std::abs(scalarValue(fOld)))
148template <
class Scalar,
class SolContainer>
156 if (std::abs(scalarValue(a)) < 1e-30)
166 Scalar p = c - b*b/3;
167 Scalar q = d + (2*b*b*b - 9*b*c)/27;
169 if (std::abs(scalarValue(p)) > 1e-30 && std::abs(scalarValue(q)) > 1e-30) {
200 Scalar wDisc = q*q/4 + p*p*p/27;
203 Scalar u = - q/2 + sqrt(wDisc);
204 if (u < 0) u = - pow(-u, 1.0/3);
205 else u = pow(u, 1.0/3);
209 sol[0] = u - p/(3*u) - b/3;
213 invertCubicPolynomialPostProcess_(sol, 1, a, b, c, d);
217 Scalar uCubedRe = - q/2;
218 Scalar uCubedIm = sqrt(-wDisc);
220 Scalar uAbs = pow(sqrt(uCubedRe*uCubedRe + uCubedIm*uCubedIm), 1.0/3);
221 Scalar phi = atan2(uCubedIm, uCubedRe)/3;
262 for (
int i = 0; i < 3; ++i) {
263 sol[i] = cos(phi)*(uAbs - p/(3*uAbs)) - b/3;
264 phi += 2*std::numbers::pi/3;
269 invertCubicPolynomialPostProcess_(sol, 3, a, b, c, d);
272 std::sort(sol, sol + 3);
279 else if (std::abs(scalarValue(p)) < 1e-30 && std::abs(scalarValue(q)) < 1e-30) {
281 sol[0] = sol[1] = sol[2] = 0.0 - b/3;
284 else if (std::abs(scalarValue(p)) < 1e-30 && std::abs(scalarValue(q)) > 1e-30) {
289 if (-q > 0) t = pow(-q, 1./3);
290 else t = - pow(q, 1./3);
296 assert(std::abs(scalarValue(p)) > 1e-30 && std::abs(scalarValue(q)) > 1e-30);
307 sol[0] = -sqrt(-p) - b/3;;
309 sol[2] = sqrt(-p) - b/3;
331template <
class Scalar,
class SolContainer>
339 if (std::abs(scalarValue(a)) < 1e-30)
346 Scalar p = (3.0 * a * c - b * b) / (3.0 * a * a);
347 Scalar q = (2.0 * b * b * b - 9.0 * a * b * c + 27.0 * d * a * a) / (27.0 * a * a * a);
351 Scalar discr = 4.0 * p * p * p + 27.0 * q * q;
355 Scalar theta = (1.0 / 3.0) * acos( ((3.0 * q) / (2.0 * p)) * sqrt(-3.0 / p) );
358 sol[0] = 2.0 * sqrt(-p / 3.0) * cos( theta ) - b / (3.0 * a);
359 sol[1] = 2.0 * sqrt(-p / 3.0) * cos( theta - ((2.0 * std::numbers::pi) / 3.0) ) - b / (3.0 * a);
360 sol[2] = 2.0 * sqrt(-p / 3.0) * cos( theta - ((4.0 * std::numbers::pi) / 3.0) ) - b / (3.0 * a);
363 std::sort(sol, sol + 3);
369 else if (discr > 0.0) {
376 Scalar theta = (1.0 / 3.0) * acosh( ((-3.0 * abs(q)) / (2.0 * p)) * sqrt(-3.0 / p) );
379 t = ( (-2.0 * abs(q)) / q ) * sqrt(-p / 3.0) * cosh(theta);
383 Scalar theta = (1.0 / 3.0) * asinh( ((3.0 * q) / (2.0 * p)) * sqrt(3.0 / p) );
385 t = -2.0 * sqrt(p / 3.0) * sinh(theta);
389 throw std::runtime_error(
" p = 0 in cubic root solver!");
393 sol[0] = t - b / (3.0 * a);
401 sol[0] = sol[1] = sol[2] = 0.0 - b / (3.0 * a);
405 sol[0] = (3.0 * q / p) - b / (3.0 * a);
406 sol[1] = sol[2] = (-3.0 * q) / (2.0 * p) - b / (3.0 * a);
407 std::sort(sol, sol + 3);
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition Exceptions.hpp:30
unsigned invertQuadraticPolynomial(SolContainer &sol, Scalar a, Scalar b, Scalar c)
Invert a quadratic polynomial analytically.
Definition PolynomialUtils.hpp:80
unsigned invertLinearPolynomial(SolContainer &sol, Scalar a, Scalar b)
Invert a linear polynomial analytically.
Definition PolynomialUtils.hpp:52
unsigned cubicRoots(SolContainer *sol, Scalar a, Scalar b, Scalar c, Scalar d)
Invert a cubic polynomial analytically.
Definition PolynomialUtils.hpp:332
unsigned invertCubicPolynomial(SolContainer *sol, Scalar a, Scalar b, Scalar c, Scalar d)
Invert a cubic polynomial analytically.
Definition PolynomialUtils.hpp:149