12 const std::valarray<double> &arr)
14 for(
size_t i=0; i<arr.size(); i++) {
21 std::ostream &operator<<(std::ostream &os, const std::list<double> &l)
24 std::list<double>::const_iterator i=l.begin();
35 std::ostream &operator<<(std::ostream &os,
39 case BINARY: os <<
"BINARY";
break;
40 case SINGLE: os <<
"SINGLE";
break;
47 const double NUMERIC_SAFETY=100.0*std::numeric_limits<double>::epsilon();
56 n = gsl_poly_solve_quadratic(c2, c1, c0, &x[0], &x[1]);
58 n = gsl_poly_solve_cubic(c2/c3,
64 std::valarray<double> result(x, n);
70 double dy0,
double dy1)
72 double dx=x1-x0, dy=y1-y0, slope_inv=dx/dy;
73 double linear_solution=x0 - y0*slope_inv;
74 if(linear_solution<x0 || linear_solution>x1)
75 linear_solution=x1 - y1*slope_inv;
76 if(std::isnan(dy0) || std::isnan(dy1)) {
84 return linear_solution;
86 double x1_2=std::pow(x1, 2), x0_2=std::pow(x0, 2),
87 a=(dx*(dy1+dy0) - 2.0*dy)/std::pow(dx, 3),
88 b=(dy1-dy0 - 3.0*a*(x1_2-x0_2))/(2.0*dx),
89 c=dy0 - 3.0*a*x0_2 - 2.0*b*x0,
90 d=y0 - a*x0*x0_2 - b*x0_2 - c*x0;
91 std::valarray<double> solutions=
solve_cubic(d, c, b, a);
100 for(
size_t i=0; i<solutions.size(); i++)
101 if(solutions[i]>=x0 && solutions[i]<=x1) {
114 return linear_solution;
116 std::ostringstream msg;
118 msg <<
"No solution to " 129 <<
" found in the given range in estimate zerocrossing. " 130 "Solutions(" << solutions.size() <<
"): ";
131 if(solutions.size()>0) msg << solutions[0];
132 for(
size_t i=1; i<solutions.size(); i++)
133 msg <<
", " << solutions[i];
139 double x1,
double y1,
140 double x2,
double y2,
141 double require_range_low,
142 double require_range_high)
144 double d12=(y1-y2)/(x1-x2), d02=(y0-y2)/(x0-x2), dx10=(x1-x0),
145 a=d12/(x1-x0) - d02/dx10,
146 b=d12 + d02*(x1+x2)/dx10 - d12*(x1+x2)/dx10,
147 c=y2 + d12*x1*x2/dx10 - d12*x2 - d02*x1*x2/dx10,
148 xpre, ypre, xpost, ypost;
149 if(y0*y1<0) {xpre=x0; xpost=x1; ypre=y0; ypost=y1;}
150 else if(y1*y2<0) {xpre=x1; xpost=x2; ypre=y1; ypost=y2;}
152 std::ostringstream msg;
154 msg <<
"No sign change found in quadratic_zerocrossing(x0=" 155 << x0 <<
", y0=" << y0 <<
", x1=" << x1 <<
", y1=" << y1
156 <<
", x2=" << x2 <<
", y2=" << y2 <<
")";
159 std::valarray<double> solutions=
solve_cubic(c, b, a, 0);
160 if(std::isnan(require_range_low)) {
161 assert(std::isnan(require_range_high));
162 require_range_low=x0;
163 require_range_high=x2;
174 for(
size_t i=0; i<solutions.size(); i++)
175 if(solutions[i]>=require_range_low &&
176 solutions[i]<=require_range_high) {
190 double x1,
double y1,
191 double x2,
double y2,
192 double x3,
double y3,
193 double require_range_low,
194 double require_range_high)
196 double xpre, ypre, xpost, ypost;
197 if(y0*y1<=0) {xpre=x0; xpost=x1; ypre=y0; ypost=y1;}
198 else if(y1*y2<=0) {xpre=x1; xpost=x2; ypre=y1; ypost=y2;}
199 else if(y2*y3<=0) {xpre=x2; xpost=x3; ypre=y2; ypost=y3;}
201 std::ostringstream msg;
203 msg <<
"No sign change found in cubic_zerocrossing(x0=" 204 << x0 <<
", y0=" << y0 <<
", x1=" << x1 <<
", y1=" << y1
205 <<
", x2=" << x2 <<
", y2=" << y2
206 <<
", x3=" << x3 <<
", y3=" << y3 <<
")";
214 gsl_vector_get(cubic_coef, 0),
215 gsl_vector_get(cubic_coef, 1),
216 gsl_vector_get(cubic_coef, 2),
217 gsl_vector_get(cubic_coef, 3));
218 if(std::isnan(require_range_low)) {
219 assert(std::isnan(require_range_high));
220 require_range_low=x0;
221 require_range_high=x3;
235 gsl_vector_free(cubic_coef);
236 for(
size_t i=0; i<solutions.size(); i++)
237 if(solutions[i]>=require_range_low &&
238 solutions[i]<=require_range_high) {
252 double x1,
double y1,
253 double dy0,
double dy1,
258 double x1_2=std::pow(x1, 2), x0_2=std::pow(x0, 2),
259 a=(dx*(dy1+dy0) - 2.0*(y1-y0))/std::pow(dx, 3),
260 b=(dy1-dy0 - 3.0*a*(x1_2-x0_2))/(2.0*dx),
261 c=dy0 - 3.0*a*x0_2 - 2.0*b*x0,
262 d=y0 - a*x0*x0_2 - b*x0_2 - c*x0,
263 linear_extremum_x=x0 - dy0*dx/(dy1-dy0),
264 linear_extremum_y=(linear_extremum_x-x0<x1-linear_extremum_x ?
265 y0+dy0*(linear_extremum_x-x0) :
266 y1-dy1*(x1-linear_extremum_x));
267 std::valarray<double> solutions=
solve_cubic(c, 2.0*b, 3.0*a, 0);
283 for(
size_t i=0; i<solutions.size(); i++) {
284 if(solutions[i]>x0 && solutions[i]<x1) {
285 double x=solutions[i];
286 if(extremum_y!=NULL) {
287 double ax3=a*x*x*x, bx2=b*x*x, cx=c*x;
288 *extremum_y=ax3 + bx2 + cx + d;
289 if(std::abs(*extremum_y)/std::max(
290 std::max(std::abs(ax3), std::abs(bx2)),
291 std::max(std::abs(cx), std::abs(d)))<1e-10)
292 *extremum_y=linear_extremum_y;
302 if(extremum_y!=NULL) *extremum_y=linear_extremum_y;
308 return linear_extremum_x;
314 return (std::abs(x1-x0)/std::max(std::abs(x1), std::abs(x0))
317 std::abs(y1-y0)/std::max(std::abs(y1), std::abs(y0))
322 double y1,
double x2,
double y2,
double *extremum_y)
325 assert((y1-y0)*(y2-y1)<=0);
333 if(extremum_y) *extremum_y=y1;
336 double s02=(y0-y2)/(x0-x2), s12=(y1-y2)/(x1-x2), a=(s02 - s12)/(x0-x1),
337 extremum_x=0.5*(x0 + x2 - s02/a);
339 *extremum_y=y0 - s02*s02/(2.0*a) + s02*x2
340 - a*(x0*x0 + x2*x2)/2.0;
355 double y1,
double x2,
double y2,
double x3,
double y3,
356 double *extremum_y,
double require_range_low,
357 double require_range_high)
360 assert((y1-y0)*(y2-y1)<=0 || (y2-y1)*(y3-y2)<=0);
368 if((y2-y1)*(y3-y2)<=0)
372 if(extremum_y) *extremum_y=y1;
379 double xmid=0.5*(x1+x2), ymid=0.5*(y1+y2);
380 if((ymid-y0)*(y3-ymid)<=0)
383 else if((y1-y0)*(y2-y1)<=0) {
385 if(extremum_y) *extremum_y=y1;
388 if(extremum_y) *extremum_y=y2;
395 if((y1-y0)*(y2-y1)<=0)
399 if(extremum_y) *extremum_y=y2;
402 gsl_vector *cubic_coef=
404 double a=3.0*gsl_vector_get(cubic_coef, 3),
405 b=2.0*gsl_vector_get(cubic_coef, 2),
406 c=gsl_vector_get(cubic_coef, 1), sqrtD=std::sqrt(b*b-4.0*a*c);
411 if(std::isnan(require_range_low)) {
412 assert(std::isnan(require_range_high));
413 require_range_low=x0;
414 require_range_high=x3;
435 if(a<0) {a*=-1; b*=-1; c*=-1;}
436 extremum_x=(-b-sqrtD)/(2.0*a);
437 if(extremum_x<require_range_low || extremum_x>require_range_high)
438 extremum_x=(-b+sqrtD)/(2.0*a);
442 for(
size_t i=0; i<4; i++) {
443 *extremum_y+=xpow*gsl_vector_get(cubic_coef, i);
447 gsl_vector_free(cubic_coef);
449 if(extremum_x<require_range_low || extremum_x>require_range_high) {
453 if((y1-y0)*(y2-y1)<=0)
460 extremum_x<require_range_low
462 extremum_x>require_range_high
465 (y2 - y1) * (y3 - y2) <= 0
471 if(extremum_x<require_range_low || extremum_x>require_range_high) {
472 std::ostringstream msg;
474 msg.setf(std::ios_base::scientific);
475 msg <<
"No extremum found in the range (" 477 <<
", " << require_range_high <<
") from points (" 478 << x0 <<
", " << y0 <<
"), (" 479 << x1 <<
", " << y1 <<
"), (" 480 << x2 <<
", " << y2 <<
") and (" 481 << x3 <<
", " << y3 <<
")!";
494 double x1,
double y1,
495 double x2,
double y2,
496 double x3,
double y3)
498 std::list<double> xs, ys;
499 xs.push_back(x0); ys.push_back(y0);
500 xs.push_back(x1); ys.push_back(y1);
501 xs.push_back(x2); ys.push_back(y2);
502 xs.push_back(x3); ys.push_back(y3);
Function arguments do not satisfy some requirement.
gsl_vector * cubic_coefficients(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3)
Returns the polynomial coefficients of the cubic going through four points.
double estimate_zerocrossing(double x0, double y0, double x1, double y1, double dy0, double dy1)
Finds a zero of a smooth curve defined by the given points and derivatives.
std::valarray< double > solve_cubic(double c0, double c1, double c2, double c3)
Solves the cubic equation .
double cubic_zerocrossing(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, double require_range_low, double require_range_high)
Finds the abscissa of a zero of a cubic defined by four points.
std::ostream & operator<<(std::ostream &os, const std::valarray< double > &arr)
Outputs a valarray as a sequence of ', ' separated values.
bool indistinguishable(double x0, double y0, double x1, double y1)
Are the two points indistinguishable (up to NUMERIC_SAFETY).
double estimate_extremum(double x0, double y0, double x1, double y1, double dy0, double dy1, double *extremum_y)
Finds an extremum of a cubic defined by two points and derivatives.
The surface rotation of one of the bodies is locked to a prescribed value.
gsl_vector * polynomial_coefficients(ITERATOR x_i, ITERATOR y_i, size_t num_points)
Finds the polynomial that goes through the points iterated over by x_i and y_i.
There is only one body in the system (only its rotation evolves).
double quadratic_extremum(double x0, double y0, double x1, double y1, double x2, double y2, double *extremum_y)
Finds the abscissa of the extremum of the quadratic function passing through three points...
double cubic_extremum(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, double *extremum_y, double require_range_low, double require_range_high)
Finds the abscissa of an extremum of the cubic function passing through four points.
Declaration of some general purpose utilities.
EvolModeType
The various evolution modes.
Two bodies orbiting each other.
double quadratic_zerocrossing(double x0, double y0, double x1, double y1, double x2, double y2, double require_range_low, double require_range_high)
Finds the abscissa of a zero of a quadratic defined by three points.