solar_system.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /* Boost libs/numeric/odeint/examples/solar_system.cpp
  2. Copyright 2010-2012 Karsten Ahnert
  3. Copyright 2011 Mario Mulansky
  4. Solar system example for Hamiltonian stepper
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE_1_0.txt or
  7. copy at http://www.boost.org/LICENSE_1_0.txt)
  8. */
  9. #include <iostream>
  10. #include <boost/array.hpp>
  11. #include <boost/numeric/odeint.hpp>
  12. #include "point_type.hpp"
  13. //[ container_type_definition
  14. // we simulate 5 planets and the sun
  15. const size_t n = 6;
  16. typedef point< double , 3 > point_type;
  17. typedef boost::array< point_type , n > container_type;
  18. typedef boost::array< double , n > mass_type;
  19. //]
  20. //[ coordinate_function
  21. const double gravitational_constant = 2.95912208286e-4;
  22. struct solar_system_coor
  23. {
  24. const mass_type &m_masses;
  25. solar_system_coor( const mass_type &masses ) : m_masses( masses ) { }
  26. void operator()( const container_type &p , container_type &dqdt ) const
  27. {
  28. for( size_t i=0 ; i<n ; ++i )
  29. dqdt[i] = p[i] / m_masses[i];
  30. }
  31. };
  32. //]
  33. //[ momentum_function
  34. struct solar_system_momentum
  35. {
  36. const mass_type &m_masses;
  37. solar_system_momentum( const mass_type &masses ) : m_masses( masses ) { }
  38. void operator()( const container_type &q , container_type &dpdt ) const
  39. {
  40. const size_t n = q.size();
  41. for( size_t i=0 ; i<n ; ++i )
  42. {
  43. dpdt[i] = 0.0;
  44. for( size_t j=0 ; j<i ; ++j )
  45. {
  46. point_type diff = q[j] - q[i];
  47. double d = abs( diff );
  48. diff *= ( gravitational_constant * m_masses[i] * m_masses[j] / d / d / d );
  49. dpdt[i] += diff;
  50. dpdt[j] -= diff;
  51. }
  52. }
  53. }
  54. };
  55. //]
  56. //[ some_helpers
  57. point_type center_of_mass( const container_type &x , const mass_type &m )
  58. {
  59. double overall_mass = 0.0;
  60. point_type mean( 0.0 );
  61. for( size_t i=0 ; i<x.size() ; ++i )
  62. {
  63. overall_mass += m[i];
  64. mean += m[i] * x[i];
  65. }
  66. if( !x.empty() ) mean /= overall_mass;
  67. return mean;
  68. }
  69. double energy( const container_type &q , const container_type &p , const mass_type &masses )
  70. {
  71. const size_t n = q.size();
  72. double en = 0.0;
  73. for( size_t i=0 ; i<n ; ++i )
  74. {
  75. en += 0.5 * norm( p[i] ) / masses[i];
  76. for( size_t j=0 ; j<i ; ++j )
  77. {
  78. double diff = abs( q[i] - q[j] );
  79. en -= gravitational_constant * masses[j] * masses[i] / diff;
  80. }
  81. }
  82. return en;
  83. }
  84. //]
  85. //[ streaming_observer
  86. struct streaming_observer
  87. {
  88. std::ostream& m_out;
  89. streaming_observer( std::ostream &out ) : m_out( out ) { }
  90. template< class State >
  91. void operator()( const State &x , double t ) const
  92. {
  93. container_type &q = x.first;
  94. m_out << t;
  95. for( size_t i=0 ; i<q.size() ; ++i ) m_out << "\t" << q[i];
  96. m_out << "\n";
  97. }
  98. };
  99. //]
  100. int main( int argc , char **argv )
  101. {
  102. using namespace std;
  103. using namespace boost::numeric::odeint;
  104. mass_type masses = {{
  105. 1.00000597682 , // sun
  106. 0.000954786104043 , // jupiter
  107. 0.000285583733151 , // saturn
  108. 0.0000437273164546 , // uranus
  109. 0.0000517759138449 , // neptune
  110. 1.0 / ( 1.3e8 ) // pluto
  111. }};
  112. container_type q = {{
  113. point_type( 0.0 , 0.0 , 0.0 ) , // sun
  114. point_type( -3.5023653 , -3.8169847 , -1.5507963 ) , // jupiter
  115. point_type( 9.0755314 , -3.0458353 , -1.6483708 ) , // saturn
  116. point_type( 8.3101420 , -16.2901086 , -7.2521278 ) , // uranus
  117. point_type( 11.4707666 , -25.7294829 , -10.8169456 ) , // neptune
  118. point_type( -15.5387357 , -25.2225594 , -3.1902382 ) // pluto
  119. }};
  120. container_type p = {{
  121. point_type( 0.0 , 0.0 , 0.0 ) , // sun
  122. point_type( 0.00565429 , -0.00412490 , -0.00190589 ) , // jupiter
  123. point_type( 0.00168318 , 0.00483525 , 0.00192462 ) , // saturn
  124. point_type( 0.00354178 , 0.00137102 , 0.00055029 ) , // uranus
  125. point_type( 0.00288930 , 0.00114527 , 0.00039677 ) , // neptune
  126. point_type( 0.00276725 , -0.00170702 , -0.00136504 ) // pluto
  127. }};
  128. point_type qmean = center_of_mass( q , masses );
  129. point_type pmean = center_of_mass( p , masses );
  130. for( size_t i=0 ; i<n ; ++i )
  131. {
  132. q[i] -= qmean ;
  133. p[i] -= pmean;
  134. }
  135. for( size_t i=0 ; i<n ; ++i ) p[i] *= masses[i];
  136. //[ integration_solar_system
  137. typedef symplectic_rkn_sb3a_mclachlan< container_type > stepper_type;
  138. const double dt = 100.0;
  139. integrate_const(
  140. stepper_type() ,
  141. make_pair( solar_system_coor( masses ) , solar_system_momentum( masses ) ) ,
  142. make_pair( boost::ref( q ) , boost::ref( p ) ) ,
  143. 0.0 , 200000.0 , dt , streaming_observer( cout ) );
  144. //]
  145. return 0;
  146. }
  147. /*
  148. Plot with gnuplot:
  149. p "solar_system.dat" u 2:4 w l,"solar_system.dat" u 5:7 w l,"solar_system.dat" u 8:10 w l,"solar_system.dat" u 11:13 w l,"solar_system.dat" u 14:16 w l,"solar_system.dat" u 17:19 w l
  150. */