std::vector<std::complex<double> > PolyBase::calcRoots(const double epsilon) /** Calculate all the roots of the polynominal. Uses the GSL which uses a Hessian reduction of the characteristic compainion matrix. \f[ A= \left( -a_{m-1}/a_m -a_{m-2}/a_m ... -a_0/a_m \right) \f] where the matrix component below A is the Indenty. However, GSL requires that the input coefficient is a_m == 1, hence the call to this->compress(). @param epsilon :: tolerance factor (-ve to use default) @return roots (not sorted/uniqued) */ { compress(epsilon); std::vector<std::complex<double> > Out(iDegree); // Zero State: if (iDegree==0) return Out; // x+a_0 =0 if (iDegree==1) { Out[0]=std::complex<double>(-afCoeff[0]); return Out; } // x^2+a_1 x+c = 0 if (iDegree==2) { solveQuadratic(Out[0],Out[1]); return Out; } // x^3+a_2 x^2+ a_1 x+c=0 if (iDegree==2) { solveCubic(Out[0],Out[1],Out[2]); return Out; } // THERE IS A QUARTIC / QUINTIC Solution availiable but... // WS contains the the hessian matrix if required (eigenvalues/vectors) // gsl_poly_complex_workspace* WS (gsl_poly_complex_workspace_alloc(iDegree+1)); double* RZ=new double[2*(iDegree+1)]; gsl_poly_complex_solve(&afCoeff.front(),iDegree+1, WS, RZ); for(int i=0;i<iDegree;i++) Out[i]=std::complex<double>(RZ[2*i],RZ[2*i+1]); gsl_poly_complex_workspace_free (WS); delete [] RZ; return Out; }
void redlichKwong( const CriticalParameters& inCP, double inT, // Temperature (K) double inP, // Pressure (bar) double* outZ, // Compressibility Factor //double* outState, double* outVol, // Molar volume (m^3/mol) double* outPhi, // Fugacity coefficient double* outHdep, // Enthalpy departure function double* outSdep) // Entropy departure function { // Calculate a and b parameters (depend only on critical parameters)… double a = 0.42748 * kR * kR * std::pow(inCP.mTc, 2.5) / (inCP.mPc * 1.0e5); double b = 0.08664 * kR * inCP.mTc / (inCP.mPc * 1.0e5); double kappa = 0.0; // Calculate coefficients in the cubic equation of state… // // coeffs: (C0,C1,C2,A,B); double A = a * inP * 1.0e5/ (std::sqrt(inT) * std::pow(kR * inT, 2)); double B = b * inP * 1e5 / (kR * inT); double C2 = -1.0; double C1 = A - B - B * B; double C0 = -A * B; // Solve the cubic equation for Z0 - Z2, D… double Z0; double Z1; double Z2; double D; solveCubic(C0, C1, C2, &Z0, &Z1, &Z2, &D); // Determine the fugacity coefficient of first root and departure functions… // // calcdepfns(coeffs[3], coeffs[4], paramsab[0], Z[0]); // calcdepfns(A, B, kappa, Z) calcDepartureFunctions(inT, A, B, kappa, Z0, outPhi, outHdep, outSdep); }
tuple solveCubicWrapper( double a, double b, double c, double d ) { double x[3]; int s = solveCubic( a, b, c, d, x ); switch( s ) { case 0 : return tuple(); case 1 : return make_tuple( x[0] ); case 2 : return make_tuple( x[0], x[1] ); case 3 : return make_tuple( x[0], x[1], x[2] ); default : PyErr_SetString( PyExc_ArithmeticError, "Infinite solutions." ); throw_error_already_set(); return tuple(); // should never get here } }
bool CubicSpline::intersects(const CubicSpline &rt, VectorF ignoreAxis) const { #if 1 vector<VectorF> path1 = getSplinePoints(*this); vector<VectorF> path2 = getSplinePoints(rt); for(size_t i = 1; i < path1.size(); i++) { for(size_t j = 1; j < path2.size(); j++) { if(linesIntersect(path1[i - 1], path1[i], path2[j - 1], path2[j], 0)) return true; } } return false; #else const int splitCount = 50; // number of line segments to split spline into ignoreAxis = normalize(ignoreAxis); for(int segmentNumber = 0; segmentNumber < splitCount; segmentNumber++) { float startT = (float)(segmentNumber) / splitCount; float endT = (float)(segmentNumber + 1) / splitCount; VectorF startP = rt.evaluate(startT); startP -= ignoreAxis * dot(ignoreAxis, startP); // move to plane normal to ignoreAxis VectorF endP = rt.evaluate(endT); endP -= ignoreAxis * dot(ignoreAxis, endP); // move to plane normal to ignoreAxis VectorF delta = endP - startP; if(absSquared(delta) < eps * eps) // if delta is too small { continue; } // solve dot(evaluate(t), cross(ignoreAxis, delta)) == 0 and it intersects if dot(evaluate(t) - startP, delta) / dot(delta, delta) is in [0, 1] and t is in [0, 1] VectorF normal = cross(ignoreAxis, delta); float cubic = dot(getCubic(), normal); float quadratic = dot(getQuadratic(), normal); float linear = dot(getLinear(), normal); float constant = dot(getConstant(), normal); float intersections[3]; int intersectionCount = solveCubic(constant, linear, quadratic, cubic, intersections); for(int i = 0; i < intersectionCount; i++) { float t = intersections[i]; if(t < 0 || t > 1) { continue; } float v = dot(evaluate(t) - startP, delta) / dot(delta, delta); if(v < 0 || v > 1) { continue; } return true; } } return false; #endif }
int PolynomialSolver::solveQuartic(float c[5], float s[4]) { float coeffs[4], z, u, v, sub, A, B, C, D, sq_A, p, q, r; int i, num; // normalize the equation:x ^ 4 + Ax ^ 3 + Bx ^ 2 + Cx + D = 0 A = c[3] / c[4]; B = c[2] / c[4]; C = c[1] / c[4]; D = c[0] / c[4]; // subsitute x = y - A / 4 to eliminate the cubic term: x^4 + px^2 + qx + r = 0 sq_A = A * A; p = -3.0f / 8.0f * sq_A + B; q = 1.0f / 8.0f * sq_A * A - 1.0f / 2.0f * A * B + C; r = -3.0f / 256.0f * sq_A * sq_A + 1.0f / 16.0f * sq_A * B - 1.0f / 4.0f * A * C + D; if(isZero(r)) { // no absolute term:y(y ^ 3 + py + q) = 0 coeffs[0] = q; coeffs[1] = p; coeffs[2] = 0.0; coeffs[3] = 1.0; num = solveCubic(coeffs, s); s[num++] = 0; } else { // solve the resolvent cubic... coeffs[0] = 1.0f / 2.0f * r * p - 1.0f / 8.0f * q * q; coeffs[1] = -r; coeffs[2] = -1.0f / 2.0f * p; coeffs[3] = 1.0f; (void) solveCubic(coeffs, s); // ...and take the one real solution... z = s[0]; // ...to build two quadratic equations u = z * z - r; v = 2.0f * z - p; if(isZero(u)) u = 0.0; else if(u > 0.0f) u = std::sqrt(u); else return 0; if(isZero(v)) v = 0; else if(v > 0.0f) v = std::sqrt(v); else return 0; coeffs[0] = z - u; coeffs[1] = q < 0 ? -v : v; coeffs[2] = 1.0f; num = solveQuadric(coeffs, s); coeffs[0] = z + u; coeffs[1] = q < 0 ? v : -v; coeffs[2] = 1.0f; num += solveQuadric(coeffs, s + num); } // resubstitute sub = 1.0f / 4 * A; for(i = 0; i < num; i++) s[i] -= sub; return num; }
int solveQuartic(float c[5], float s[4]) { float coeffs[4]; float z, u, v, sub; float A, B, C, D; float sq_A, p, q, r; int i, num; /* normal form: x^4 + Ax^3 + Bx^2 + Cx + D = 0 */ A = c[ 3 ] / c[ 4 ]; B = c[ 2 ] / c[ 4 ]; C = c[ 1 ] / c[ 4 ]; D = c[ 0 ] / c[ 4 ]; /* substitute x = y - A/4 to eliminate cubic term: x^4 + px^2 + qx + r = 0 */ sq_A = A * A; p = - 3.0/8 * sq_A + B; q = 1.0/8 * sq_A * A - 1.0/2 * A * B + C; r = - 3.0/256*sq_A*sq_A + 1.0/16*sq_A*B - 1.0/4*A*C + D; if (IS_ZERO(r)) { /* no absolute term: y(y^3 + py + q) = 0 */ coeffs[ 0 ] = q; coeffs[ 1 ] = p; coeffs[ 2 ] = 0; coeffs[ 3 ] = 1; num = solveCubic(coeffs, s); s[ num++ ] = 0; } else { /* solve the resolvent cubic ... */ coeffs[ 0 ] = 1.0/2 * r * p - 1.0/8 * q * q; coeffs[ 1 ] = - r; coeffs[ 2 ] = - 1.0/2 * p; coeffs[ 3 ] = 1; (void) solveCubic(coeffs, s); /* ... and take the one real solution ... */ z = s[ 0 ]; /* ... to build two quadric equations */ u = z * z - r; v = 2 * z - p; if (IS_ZERO(u)) u = 0; else if (u > 0) u = sqrt(u); else return 0; if (IS_ZERO(v)) v = 0; else if (v > 0) v = sqrt(v); else return 0; coeffs[ 0 ] = z - u; coeffs[ 1 ] = q < 0 ? -v : v; coeffs[ 2 ] = 1; num = solveQuadric(coeffs, s); coeffs[ 0 ]= z + u; coeffs[ 1 ] = q < 0 ? v : -v; coeffs[ 2 ] = 1; num += solveQuadric(coeffs, s + num); } /* resubstitute */ sub = 1.0/4 * A; for (i = 0; i < num; ++i) s[ i ] -= sub; return num; }