fpu.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * fpu.cpp
  3. *
  4. * This example demonstrates how one can use odeint to solve the Fermi-Pasta-Ulam system.
  5. * Created on: July 13, 2011
  6. *
  7. * Copyright 2011-2012 Karsten Ahnert
  8. * Copyright 2011 Mario Mulansky
  9. * Distributed under the Boost Software License, Version 1.0. (See
  10. * accompanying file LICENSE_1_0.txt or copy at
  11. * http://www.boost.org/LICENSE_1_0.txt)
  12. */
  13. #include <iostream>
  14. #include <numeric>
  15. #include <cmath>
  16. #include <vector>
  17. #include <boost/numeric/odeint.hpp>
  18. #ifndef M_PI //not there on windows
  19. #define M_PI 3.1415927 //...
  20. #endif
  21. using namespace std;
  22. using namespace boost::numeric::odeint;
  23. //[ fpu_system_function
  24. typedef vector< double > container_type;
  25. struct fpu
  26. {
  27. const double m_beta;
  28. fpu( const double beta = 1.0 ) : m_beta( beta ) { }
  29. // system function defining the ODE
  30. void operator()( const container_type &q , container_type &dpdt ) const
  31. {
  32. size_t n = q.size();
  33. double tmp = q[0] - 0.0;
  34. double tmp2 = tmp + m_beta * tmp * tmp * tmp;
  35. dpdt[0] = -tmp2;
  36. for( size_t i=0 ; i<n-1 ; ++i )
  37. {
  38. tmp = q[i+1] - q[i];
  39. tmp2 = tmp + m_beta * tmp * tmp * tmp;
  40. dpdt[i] += tmp2;
  41. dpdt[i+1] = -tmp2;
  42. }
  43. tmp = - q[n-1];
  44. tmp2 = tmp + m_beta * tmp * tmp * tmp;
  45. dpdt[n-1] += tmp2;
  46. }
  47. // calculates the energy of the system
  48. double energy( const container_type &q , const container_type &p ) const
  49. {
  50. // ...
  51. //<-
  52. double energy = 0.0;
  53. size_t n = q.size();
  54. double tmp = q[0];
  55. energy += 0.5 * tmp * tmp + 0.25 * m_beta * tmp * tmp * tmp * tmp;
  56. for( size_t i=0 ; i<n-1 ; ++i )
  57. {
  58. tmp = q[i+1] - q[i];
  59. energy += 0.5 * ( p[i] * p[i] + tmp * tmp ) + 0.25 * m_beta * tmp * tmp * tmp * tmp;
  60. }
  61. energy += 0.5 * p[n-1] * p[n-1];
  62. tmp = q[n-1];
  63. energy += 0.5 * tmp * tmp + 0.25 * m_beta * tmp * tmp * tmp * tmp;
  64. return energy;
  65. //->
  66. }
  67. // calculates the local energy of the system
  68. void local_energy( const container_type &q , const container_type &p , container_type &e ) const
  69. {
  70. // ...
  71. //<-
  72. size_t n = q.size();
  73. double tmp = q[0];
  74. double tmp2 = 0.5 * tmp * tmp + 0.25 * m_beta * tmp * tmp * tmp * tmp;
  75. e[0] = tmp2;
  76. for( size_t i=0 ; i<n-1 ; ++i )
  77. {
  78. tmp = q[i+1] - q[i];
  79. tmp2 = 0.25 * tmp * tmp + 0.125 * m_beta * tmp * tmp * tmp * tmp;
  80. e[i] += 0.5 * p[i] * p[i] + tmp2 ;
  81. e[i+1] = tmp2;
  82. }
  83. tmp = q[n-1];
  84. tmp2 = 0.5 * tmp * tmp + 0.25 * m_beta * tmp * tmp * tmp * tmp;
  85. e[n-1] += 0.5 * p[n-1] * p[n-1] + tmp2;
  86. //->
  87. }
  88. };
  89. //]
  90. //[ fpu_observer
  91. struct streaming_observer
  92. {
  93. std::ostream& m_out;
  94. const fpu &m_fpu;
  95. size_t m_write_every;
  96. size_t m_count;
  97. streaming_observer( std::ostream &out , const fpu &f , size_t write_every = 100 )
  98. : m_out( out ) , m_fpu( f ) , m_write_every( write_every ) , m_count( 0 ) { }
  99. template< class State >
  100. void operator()( const State &x , double t )
  101. {
  102. if( ( m_count % m_write_every ) == 0 )
  103. {
  104. container_type &q = x.first;
  105. container_type &p = x.second;
  106. container_type energy( q.size() );
  107. m_fpu.local_energy( q , p , energy );
  108. for( size_t i=0 ; i<q.size() ; ++i )
  109. {
  110. m_out << t << "\t" << i << "\t" << q[i] << "\t" << p[i] << "\t" << energy[i] << "\n";
  111. }
  112. m_out << "\n";
  113. clog << t << "\t" << accumulate( energy.begin() , energy.end() , 0.0 ) << "\n";
  114. }
  115. ++m_count;
  116. }
  117. };
  118. //]
  119. int main( int argc , char **argv )
  120. {
  121. //[ fpu_integration
  122. const size_t n = 64;
  123. container_type q( n , 0.0 ) , p( n , 0.0 );
  124. for( size_t i=0 ; i<n ; ++i )
  125. {
  126. p[i] = 0.0;
  127. q[i] = 32.0 * sin( double( i + 1 ) / double( n + 1 ) * M_PI );
  128. }
  129. const double dt = 0.1;
  130. typedef symplectic_rkn_sb3a_mclachlan< container_type > stepper_type;
  131. fpu fpu_instance( 8.0 );
  132. integrate_const( stepper_type() , fpu_instance ,
  133. make_pair( boost::ref( q ) , boost::ref( p ) ) ,
  134. 0.0 , 1000.0 , dt , streaming_observer( cout , fpu_instance , 10 ) );
  135. //]
  136. return 0;
  137. }