Planetary Orbital Evolution due to Tides
Orbital evolution of two objects experiencing tides
EccentricityExpansionCoefficients.cpp
1 #define BUILDING_LIBRARY
3 
4 namespace Evolve {
5 
6  std::vector<double> EccentricityExpansionCoefficients::load_coefficient(
7  sqlite3* db,
8  int m,
9  int s
10  )
11  {
12  bool error_flag = false;
13  int ms_index = local_index(m, s);
14 
15  std::vector<double> pms;
16 
17  sqlite3_stmt *statement;
18  std::string stmnt = "SELECT y_value, step_number";
19  stmnt.append(" FROM interpolation_data WHERE p_id = ");
20  stmnt.append(std::to_string(__db_pms_id[ms_index]));
21  stmnt.append(" ORDER BY step_number DESC");
22  const char *sql = stmnt.c_str();
23  if(sqlite3_prepare_v2(db, sql, -1, &statement, NULL) == SQLITE_OK) {
24  int rc = sqlite3_step(statement);
25  int i_b = sqlite3_column_int(statement, 1);
26  assert (i_b == __num_steps[ms_index] - 1);
27  pms.resize(i_b + 1);
28  while(rc == SQLITE_ROW) {
29  pms[i_b] = sqlite3_column_double(statement, 0);
30  --i_b;
31  rc = sqlite3_step(statement);
32  }
33 
34  if (rc != SQLITE_DONE)
35  error_flag=true;
36  }
37  else
38  error_flag = true;
39  sqlite3_finalize(statement);
40 
41  if(error_flag)
42  throw Core::Error::IO(
43  "Unable to retrieve expansion id "
44  +
45  std::to_string(__db_pms_id[ms_index])
46  +
47  " in eccentricity expansion file during load_coefficient!"
48  );
49 
50  return pms;
51  }
52 
55  {
56  sqlite3_stmt *statement;
57  std::string stmnt="SELECT MAX(s) FROM interpolations";
58  const char *sql = stmnt.c_str();
59  int result_s = 0;
60  bool error_flag = false;
61 
62  int codeOne=sqlite3_prepare_v2(db,sql,-1,&statement,NULL);
63  if(codeOne==SQLITE_OK) {
64  int rc = sqlite3_step(statement);
65  while(rc==SQLITE_ROW) {
66  result_s = sqlite3_column_double(statement,0);
67  rc=sqlite3_step(statement);
68  }
69  if (rc!=SQLITE_DONE) error_flag=true;
70  }
71  else error_flag=true;
72  sqlite3_finalize(statement);
73 
74  if(error_flag==true)
75  {
76  std::string msg ="Eccentricity expansion file could not be read in";
77  msg.append(" EccentricityExpansionCoefficients::set_max_s()!");
78  throw Core::Error::IO(msg);
79  }
80 
81  __max_s = result_s;
82  }
83 
85  {
86  sqlite3_stmt *statement;
87  std::string stmnt = "SELECT id, m, s, min_interp_e, number_of_steps,";
88  stmnt.append("max_checked_e, interp_accuracy FROM interpolations");
89  const char *sql = stmnt.c_str();
90  int error_flag = 0;
91 
92  __db_pms_id.resize(3 * (__max_s + 1), -1);
93  __min_e.resize(3 * (__max_s + 1), Core::NaN);
94  __num_steps.resize(3 * (__max_s + 1));
95  __max_e.resize(3 * (__max_s + 1), Core::NaN);
96  __interp_precision.resize(3 * (__max_s + 1), Core::NaN);
97 
98  if(sqlite3_prepare_v2(db, sql, -1, &statement, NULL) == SQLITE_OK)
99  {
100  int rc = sqlite3_step(statement);
101  while(rc == SQLITE_ROW)
102  {
103  int m = sqlite3_column_int(statement, 1);
104  int s = sqlite3_column_int(statement, 2);
105  int ms_index = local_index(m, s);
106  __db_pms_id[ms_index] = sqlite3_column_int(statement, 0);
107  __min_e[ms_index] = sqlite3_column_double(statement, 3);
108  __num_steps[ms_index] = sqlite3_column_int(statement, 4);
109  __max_e[ms_index] = sqlite3_column_double(statement, 5);
110  __interp_precision[ms_index] = sqlite3_column_double(
111  statement,
112  6
113  );
114  rc = sqlite3_step(statement);
115  }
116  if (rc != SQLITE_DONE)
117  error_flag = -1;
118  } else
119  error_flag = -1;
120  sqlite3_finalize(statement);
121 
122  if(error_flag == -1)
123  throw Core::Error::IO(
124  "Eccentricity expansion file could not be read in "
125  "EccentricityExpansionCoefficients::load_metadata()!"
126  );
127  }
128 
130  sqlite3* db,
131  double precision
132  )
133  {
134  __max_ignore_eccentricity.resize(3 * (__max_s + 1), Core::NaN);
135 
136  for(int m=2; m >= -2; m -= 2)
137  {
138  for(int s=0; s <= __max_s; ++s)
139  {
140  int destination_i = local_index(m, s);
141  if(s<=2) {
142  __max_ignore_eccentricity[destination_i] = -Core::Inf;
143  } else {
144  sqlite3_stmt *statement;
145  std::ostringstream stmnt;
146  stmnt.setf(std::ios_base::scientific);
147  stmnt.precision(16);
148  stmnt << (
149  "SELECT MIN(b.step_number) FROM interpolations a "
150  "LEFT JOIN interpolation_data b ON a.id = b.p_id "
151  "WHERE "
152  )
153  << "a.m = " << m
154  << " AND a.s = " << s
155  << " AND ABS(b.y_value) >= " << precision/double(s);
156  int error_flag = 0;
157 
158  if(
159  sqlite3_prepare_v2(db,
160  stmnt.str().c_str(),
161  -1,
162  &statement,
163  NULL)
164  ==
165  SQLITE_OK
166  ) {
167  if(sqlite3_step(statement) != SQLITE_ROW)
168  error_flag=-1;
169  else {
170  int max_ignore_step = (
171  sqlite3_column_int(statement, 0)
172  -
173  1
174  );
175  __max_ignore_eccentricity[destination_i] = (
176  max_ignore_step >= 0
177  ? step_to_e(m, s, max_ignore_step)
178  : -Core::Inf
179  );
180  if(sqlite3_step(statement) != SQLITE_DONE)
181  error_flag=-1;
182  }
183  } else
184  error_flag = -1;
185  sqlite3_finalize(statement);
186 
187  if(error_flag == -1)
188  throw Core::Error::IO(
189  "Eccentricity expansion file could not be read in "
190  "EccentricityExpansionCoefficients::"
191  "load_max_ignore_eccentricity()!"
192  );
193  }
194  }
195  }
196  }
197 
198  double EccentricityExpansionCoefficients::load_specific_e(
199  int m,
200  int s,
201  int e_step
202  ) const
203  {
204  assert(__useable);
205 
206  bool error_flag = false;
207  double result;
208  int ms_index = local_index(m, s);
209  sqlite3 *db;
210 
211  int rc = sqlite3_open(__file_name.c_str(),&db);
212  if(rc!=SQLITE_OK) {
213  sqlite3_close(db);
214  throw Core::Error::IO(
215  "Unable to open eccentricity expansion file: "
216  +
218  +
219  "!"
220  );
221  }
222  try {
223  sqlite3_stmt *statement;
224  std::string stmnt="SELECT y_value FROM interpolation_data";
225  stmnt.append(" WHERE p_id = ");
226  stmnt.append(std::to_string(__db_pms_id[ms_index]));
227  stmnt.append(" AND step_number=");
228  stmnt.append(std::to_string(e_step));
229  const char *sql = stmnt.c_str();
230  int theCode=sqlite3_prepare_v2(db,sql,-1,&statement,NULL);
231  if(theCode==SQLITE_OK)
232  {
233  int rc = sqlite3_step(statement);
234  while(rc==SQLITE_ROW)
235  {
236  result=( sqlite3_column_double(statement,0) );
237  rc=sqlite3_step(statement);
238  }
239 
240  if (rc!=SQLITE_DONE)
241  {
242  error_flag=true;
243  std::cout<<"Loop finished without being done.\n";
244  }
245  }
246  else
247  {
248  error_flag=true;
249  std::cout<<"prepare was not ok. error code " << std::to_string(theCode) << "\n";
250  std::cout<<sqlite3_errmsg(db);
251  }
252  sqlite3_finalize(statement);
253 
254  if(error_flag)
255  throw Core::Error::IO(
256  "Unable to retrieve expansion id "
257  +
258  std::to_string(__db_pms_id[ms_index])
259  +
260  " in eccentricity expansion file during load_specific_e!"
261  );
262  } catch(...) {
263  sqlite3_close(db);
264  throw;
265  }
266  sqlite3_close(db);
267  return result;
268  }
269 
271  {
272  __pms_interp_data.resize(3*(__max_s+1));
273  for(int s=0; s <= __max_s; s++)
274  for(int m=-2; m<=2; m+=2)
275  __pms_interp_data[local_index(m, s)] = load_coefficient(db,
276  m,
277  s);
278  }
279 
281  int m,
282  int s,
283  int e_step
284  ) const
285  {
286  return (
287  __load_all
288  ? __pms_interp_data[local_index(m, s)][e_step]
289  : load_specific_e(m, s, e_step)
290  );
291  }
292 
293  std::vector<double> EccentricityExpansionCoefficients::find_pms_boundary_values(
294  int m,
295  int s,
296  double e
297  ) const
298  {
299  std::vector<double> results (4);
300  int lo_i = e_to_nearest_step(m,s,e,true);
301  int hi_i = lo_i+1;
302 
303  results[0] = step_to_e(m, s, lo_i);
304  results[1] = step_to_e(m, s, hi_i);
305  results[2] = get_specific_e(m, s, lo_i);
306  results[3] = get_specific_e(m, s, hi_i);
307  return results;
308  }
309 
310  double EccentricityExpansionCoefficients::return_known_e(
311  int m,
312  int s,
313  double e
314  ) const
315  {
316  if(
317  ( (s==0 || e==1.0) && m==0 )
318  ||
319  ( m==2 && s==2 && e==0.0 )
320  )
321  return 1.0;
322 
323  if(
324  ( s==0 && std::abs(m)==2 )
325  ||
326  e==1.0
327  ||
328  e==0.0
329  )
330  return 0.0;
331 
332  if( e < __min_e[local_index(m,s)] )
333  return 0.0;
334 
335  assert(false);
336  }
337 
338  bool EccentricityExpansionCoefficients::check_known_e(
339  int m,
340  int s,
341  double e
342  ) const
343  {
344  if(
345  s==0
346  ||
347  e==1.0
348  ||
349  e==0.0
350  ||
351  e<__min_e[local_index(m,s)]
352  )
353  return true;
354  return false;
355  }
356 
357  inline int EccentricityExpansionCoefficients::e_to_nearest_step(
358  int m,
359  int s,
360  double e,
361  bool flr
362  ) const
363  {
364  int li = local_index(m,s);
365  double square_step;
366  square_step = ( e-double(__min_e[li]) )
367  *
368  (double(__num_steps[li]) - 1)
369  /
370  ( 1-double(__min_e[li]) );
371  if(flr) return int( floor(square_step) );
372  else return int( ceil(square_step) );
373  }
374 
375  inline double EccentricityExpansionCoefficients::step_to_e(
376  int m,
377  int s,
378  int step
379  ) const
380  {
381  int li = local_index(m,s);
382  double result = ( double(step) / (double(__num_steps[li]) - 1) )
383  *
384  ( 1-double(__min_e[li]) )
385  +
386  double(__min_e[li]);
387  return result;
388  }
389 
390  inline int EccentricityExpansionCoefficients::local_index(int m,
391  int s) const
392  {
393  return s * 3 + (m + 2) / 2;
394  }
395 
397  const std::string &tabulated_pms_fname,
398  double precision,
399  bool pre_load,
400  bool disable_precision_fail
401  )
402  {
403  __expansion_precision = precision;
404  sqlite3 *db;
405  int rc;
406 
407  __load_all = pre_load;
408  __allow_precision_fail = !disable_precision_fail;
409 
410  rc = sqlite3_open(tabulated_pms_fname.c_str(), &db);
411  if(rc!=SQLITE_OK) {
412  sqlite3_close(db);
413  throw Core::Error::IO(
414  "Unable to open eccentricity expansion file: "
415  +
416  tabulated_pms_fname
417  +
418  "!"
419  );
420  }
421  try {
422  set_max_s(db);
423  load_metadata(db);
424  load_max_ignore_eccentricity(db, precision);
425  if(__load_all)
426  {
427  get_interp_data(db);
428  }
429  else
430  {
431  __file_name=tabulated_pms_fname;
432  }
433  } catch(...) {
434  sqlite3_close(db);
435  throw;
436  }
437  sqlite3_close(db);
438  __useable = true;
439  }
440 
442  {
443  if(!__useable)
444  throw Core::Error::Runtime(
445  "Asking for EccentricityExpansionCoefficients::"
446  "interp_precision() before reading interpolation data"
447  );
448  if(m != 0l && std::abs(m) != 2)
450  "Asking EccentricityExpansionCoefficients::interp_precision() "
451  "for p_{m,s} with m other than +-2 and 0"
452  );
453  return __interp_precision[local_index(m, s)];
454  }
455 
457  double e,
458  int m
459  ) const
460  {
461  if(!__useable)
462  throw Core::Error::Runtime(
463  "Asking EccentricityExpansionCoefficients::"
464  "required_expansion_order() before reading interpolation data"
465  );
466  int s = __max_s;
467  while(__max_ignore_eccentricity[local_index(m, s)] >= e)
468  --s;
469  if(s == __max_s && __allow_precision_fail) {
470  std::ostringstream message;
471  message << "Tabulated eccentricity interpolation is unsufficient "
472  << "to achieve the specified precision in tidal potential "
473  << "expansion for e = "
474  << e
475  << ", m = "
476  << m;
477  throw Core::Error::Runtime(message.str());
478  }
479  return s;
480  }
481 
482  std::pair<double,double>
484  int m,
485  int max_s
486  ) const
487  {
488  if(!__useable)
489  throw Core::Error::Runtime(
490  "Asking EccentricityExpansionCoefficients::"
491  "get_expansion_range() before reading interpolation data"
492  );
493 #ifdef VERBOSE_DEBUG
494  std::cerr << "Max ignore e(m="
495  << m
496  << ", m'="
497  << max_s
498  << ") = "
499  << __max_ignore_eccentricity[local_index(m, max_s)]
500  << "Max ignore e(m="
501  << m
502  << ", m'="
503  << max_s + 1
504  << ") = "
505  << __max_ignore_eccentricity[local_index(m, max_s + 1)]
506  << std::endl;
507 #endif
508 
509  return std::make_pair(
510  __max_ignore_eccentricity[local_index(m, max_s)],
511  __max_ignore_eccentricity[local_index(m, max_s + 1)]
512  );
513  }
514 
516  int m,
517  int s,
518  double e,
519  bool deriv
520  ) const
521  {
522  if(s<0)
523  return operator()(-m, -s, e, deriv);
524  if(!__useable)
525  throw Core::Error::Runtime(
526  "Attempting to evaluate p_ms before reading interpolation data"
527  );
528 
529  if(m != 0 && std::abs(m) != 2)
531  "Asking for p_{m,s} with m other than +-2 and 0"
532  );
533  if(s > __max_s)
535  "Attempting to evaluate larger s than is available!"
536  );
537  if(e > __max_e[local_index(m, s)])
539  "Attempting to evaluate larger e than is accounted for!"
540  );
541 
542  if(check_known_e(m, s, e)) {
543  //TODO: handle deriv properly
544  return (deriv ? Core::NaN : return_known_e(m, s, e));
545  }
546 
547  std::vector<double> e_and_y_values(4);
548  e_and_y_values = find_pms_boundary_values(m, s, e);
549 
550  double slope = (
551  (e_and_y_values[3] - e_and_y_values[2])
552  /
553  (e_and_y_values[1] - e_and_y_values[0])
554  );
555 
556  if(deriv)
557  return slope;
558  return slope * (e - e_and_y_values[0]) + e_and_y_values[2];
559  }
560 
561 } //End Evolve namespace.
std::vector< double > __max_e
The maximum eccentricity at which each coefficient can be reliably interpolated. ...
double operator()(int m, int s, double e, bool deriv) const
Approximate the value of .
Function arguments do not satisfy some requirement.
Definition: Error.h:73
std::vector< double > __max_ignore_eccentricity
The maximum eccentricity at which a given can be ignored.
Declares a class which provides the [ coefficients]{InclinationEccentricity_pms1}.
std::vector< int > __num_steps
The number of e values at which each coefficient is tabulated.
double __expansion_precision
The currently defined expansion precision (see prepare())
Any runtime error.
Definition: Error.h:61
Orientations of zones of bodies in a binary system.
void load_metadata(sqlite3 *db)
Read the metadata for the available coefficients from the databate.
std::vector< std::vector< double > > __pms_interp_data
The expansion coefficients for all .
std::vector< int > __db_pms_id
The identifiers of particular coefficients in the database.
void load_max_ignore_eccentricity(sqlite3 *db, double precision)
Fill the __max_ignore_eccentricity member per the database.
std::string __file_name
The name of the file contanining the interpolatiod sqlite database.
bool __allow_precision_fail
See do_not_fail argument to prepare().
double get_specific_e(int m, int s, int e_step) const
Return a single tabulated value of .
Input/Output exception.
Definition: Error.h:118
void prepare(const std::string &tabulated_pms_fname, double precision, bool pre_load, bool disable_precision_fail=false)
Reads in tabulated expansion coefficients, making this object useable.
double interp_precision(int m, int s) const
The guaranteed interpolation precision for a given .
void get_interp_data(sqlite3 *db)
The callback SQL function that updates the above values (__pms_interp_data)
std::vector< double > __interp_precision
The guaranteed interpolation precision for each u coefficient.
void set_max_s(sqlite3 *db)
TODO: use smallest max s over m=+-2 and m=0.
bool __load_all
Whether we load the whole database at the start (true) or part of it as needed (false) ...
int required_expansion_order(double e, int m) const
Return the smallest s value such that all for.
int __max_s
The largest s (second) index at which all three coefficients are tabulated.
std::pair< double, double > get_expansion_range(int m, int max_s) const
Return the range of eccentricities (min, max) over which an expansion going up to given max s is vali...