Squashed 'third_party/boostorg/odeint/' content from commit 6ff2719

Change-Id: If4892e29c1a5e6cf3a7aa51486a2725c251b0c7d
git-subtree-dir: third_party/boostorg/odeint
git-subtree-split: 6ff2719b6907b86596c3d43e88c1bcfdf29df560
diff --git a/examples/2d_lattice/Jamfile.v2 b/examples/2d_lattice/Jamfile.v2
new file mode 100644
index 0000000..c995ec1
--- /dev/null
+++ b/examples/2d_lattice/Jamfile.v2
@@ -0,0 +1,13 @@
+# Copyright 2011 Mario Mulansky
+# Copyright 2012 Karsten Ahnert
+# Distributed under the Boost Software License, Version 1.0. (See
+# accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+project
+    : requirements 
+      <include>../../../../..
+      <define>BOOST_ALL_NO_LIB=1
+    ;
+    
+exe spreading : spreading.cpp ;
\ No newline at end of file
diff --git a/examples/2d_lattice/lattice2d.hpp b/examples/2d_lattice/lattice2d.hpp
new file mode 100644
index 0000000..4fd9c98
--- /dev/null
+++ b/examples/2d_lattice/lattice2d.hpp
@@ -0,0 +1,165 @@
+/*
+ Copyright 2011 Mario Mulansky
+ Copyright 2012-2013 Karsten Ahnert
+
+ Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or
+ copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+
+/* strongly nonlinear hamiltonian lattice in 2d */
+
+#ifndef LATTICE2D_HPP
+#define LATTICE2D_HPP
+
+#include <vector>
+
+#include <boost/math/special_functions/pow.hpp>
+
+using boost::math::pow;
+
+template< int Kappa , int Lambda >
+struct lattice2d {
+
+    const double m_beta;
+    std::vector< std::vector< double > > m_omega;
+
+    lattice2d( const double beta )
+        : m_beta( beta )
+    { }
+
+    template< class StateIn , class StateOut >
+    void operator()( const StateIn &q , StateOut &dpdt )
+    {
+        // q and dpdt are 2d
+        const int N = q.size();
+
+        int i;
+        for( i = 0 ; i < N ; ++i )
+        {
+            const int i_l = (i-1+N) % N;
+            const int i_r = (i+1) % N;
+            for( int j = 0 ; j < N ; ++j )
+            {
+            const int j_l = (j-1+N) % N;
+            const int j_r = (j+1) % N;
+            dpdt[i][j] = - m_omega[i][j] * pow<Kappa-1>( q[i][j] )
+                - m_beta * pow<Lambda-1>( q[i][j] - q[i][j_l] )
+                - m_beta * pow<Lambda-1>( q[i][j] - q[i][j_r] )
+                - m_beta * pow<Lambda-1>( q[i][j] - q[i_l][j] )
+                - m_beta * pow<Lambda-1>( q[i][j] - q[i_r][j] );
+            }
+        }
+    }
+
+    template< class StateIn >
+    double energy( const StateIn &q , const StateIn &p )
+    {
+        // q and dpdt are 2d
+        const int N = q.size();
+        double energy = 0.0;
+        int i;
+        for( i = 0 ; i < N ; ++i )
+        {
+            const int i_l = (i-1+N) % N;
+            const int i_r = (i+1) % N;
+            for( int j = 0 ; j < N ; ++j )
+            {
+            const int j_l = (j-1+N) % N;
+            const int j_r = (j+1) % N;
+            energy += p[i][j]*p[i][j] / 2.0
+                        + m_omega[i][j] * pow<Kappa>( q[i][j] ) / Kappa
+                + m_beta * pow<Lambda>( q[i][j] - q[i][j_l] ) / Lambda / 2
+                + m_beta * pow<Lambda>( q[i][j] - q[i][j_r] ) / Lambda / 2
+                + m_beta * pow<Lambda>( q[i][j] - q[i_l][j] ) / Lambda / 2
+                + m_beta * pow<Lambda>( q[i][j] - q[i_r][j] ) / Lambda / 2;
+            }
+        }
+        return energy;
+    }
+
+
+    template< class StateIn , class StateOut >
+    double local_energy( const StateIn &q , const StateIn &p , StateOut &energy )
+    {
+        // q and dpdt are 2d
+        const int N = q.size();
+        double e = 0.0;
+        int i;
+        for( i = 0 ; i < N ; ++i )
+        {
+            const int i_l = (i-1+N) % N;
+            const int i_r = (i+1) % N;
+            for( int j = 0 ; j < N ; ++j )
+            {
+                const int j_l = (j-1+N) % N;
+                const int j_r = (j+1) % N;
+                energy[i][j] = p[i][j]*p[i][j] / 2.0
+                    + m_omega[i][j] * pow<Kappa>( q[i][j] ) / Kappa
+                    + m_beta * pow<Lambda>( q[i][j] - q[i][j_l] ) / Lambda / 2
+                    + m_beta * pow<Lambda>( q[i][j] - q[i][j_r] ) / Lambda / 2
+                    + m_beta * pow<Lambda>( q[i][j] - q[i_l][j] ) / Lambda / 2
+                    + m_beta * pow<Lambda>( q[i][j] - q[i_r][j] ) / Lambda / 2;
+                e += energy[i][j];
+            }
+        }
+        //rescale
+        e = 1.0/e;
+        for( i = 0 ; i < N ; ++i )
+            for( int j = 0 ; j < N ; ++j )
+                energy[i][j] *= e;
+        return 1.0/e;
+    }
+
+    void load_pot( const char* filename , const double W , const double gap , 
+                   const size_t dim )
+    {
+        std::ifstream in( filename , std::ios::in | std::ios::binary );
+        if( !in.is_open() ) {
+            std::cerr << "pot file not found: " << filename << std::endl;
+            exit(0);
+        } else {
+            std::cout << "using pot file: " << filename << std::endl;
+        }
+
+        m_omega.resize( dim );
+        for( int i = 0 ; i < dim ; ++i )
+        {
+            m_omega[i].resize( dim );
+            for( size_t j = 0 ; j < dim ; ++j )
+            {
+                if( !in.good() )
+                {
+                    std::cerr << "I/O Error: " << filename << std::endl;
+                    exit(0);
+                }
+                double d;
+                in.read( (char*) &d , sizeof(d) );
+                if( (d < 0) || (d > 1.0) )
+                {
+                    std::cerr << "ERROR: " << d << std::endl;
+                    exit(0);
+                }
+                m_omega[i][j] = W*d + gap;
+            }
+        }
+
+    }
+
+    void generate_pot( const double W , const double gap , const size_t dim )
+    {
+        m_omega.resize( dim );
+        for( size_t i = 0 ; i < dim ; ++i )
+        {
+            m_omega[i].resize( dim );
+            for( size_t j = 0 ; j < dim ; ++j )
+            {
+                m_omega[i][j] = W*static_cast<double>(rand())/RAND_MAX + gap;
+            }
+        }
+    }
+
+};
+
+#endif
diff --git a/examples/2d_lattice/nested_range_algebra.hpp b/examples/2d_lattice/nested_range_algebra.hpp
new file mode 100644
index 0000000..0afa367
--- /dev/null
+++ b/examples/2d_lattice/nested_range_algebra.hpp
@@ -0,0 +1,46 @@
+/*
+ Copyright 2011 Mario Mulansky
+ Copyright 2012 Karsten Ahnert
+
+ Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or
+ copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+
+/* nested range algebra */
+
+#ifndef NESTED_RANGE_ALGEBRA
+#define NESTED_RANGE_ALGEBRA
+
+namespace detail {
+
+    template< class Iterator1 , class Iterator2 , class Iterator3 , class Operation , class Algebra >
+    void for_each3( Iterator1 first1 , Iterator1 last1 , Iterator2 first2 , Iterator3 first3, Operation op , Algebra &algebra )
+{
+    for( ; first1 != last1 ; )
+        algebra.for_each3( *first1++ , *first2++ , *first3++ , op );
+}
+}
+
+
+template< class InnerAlgebra >
+struct nested_range_algebra
+{
+    
+    nested_range_algebra() 
+        : m_inner_algebra()
+    { }
+
+    template< class S1 , class S2 , class S3 , class Op >
+    void for_each3( S1 &s1 , S2 &s2 , S3 &s3 , Op op )
+    {
+        detail::for_each3( boost::begin( s1 ) , boost::end( s1 ) , boost::begin( s2 ) , boost::begin( s3 ) , op , m_inner_algebra );
+    }
+
+
+private:
+    InnerAlgebra m_inner_algebra;
+};
+
+#endif
diff --git a/examples/2d_lattice/spreading.cpp b/examples/2d_lattice/spreading.cpp
new file mode 100644
index 0000000..88c60bf
--- /dev/null
+++ b/examples/2d_lattice/spreading.cpp
@@ -0,0 +1,122 @@
+/*
+ Copyright 2011 Mario Mulansky
+ Copyright 2012 Karsten Ahnert
+
+ Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or
+ copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+
+/*
+ * Example of a 2D simulation of nonlinearly coupled oscillators.
+ * Program just prints final energy which should be close to the initial energy (1.0).
+ * No parallelization is employed here.
+ * Run time on a 2.3GHz Intel Core-i5: about 10 seconds for 100 steps.
+ * Compile simply via bjam or directly:
+ * g++ -O3 -I${BOOST_ROOT} -I../../../../.. spreading.cpp
+ */
+
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <cstdlib>
+#include <sys/time.h>
+
+#include <boost/ref.hpp>
+#include <boost/numeric/odeint/stepper/symplectic_rkn_sb3a_mclachlan.hpp>
+
+// we use a vector< vector< double > > as state type,
+// for that some functionality has to be added for odeint to work
+#include "nested_range_algebra.hpp"
+#include "vector_vector_resize.hpp"
+
+// defines the rhs of our dynamical equation
+#include "lattice2d.hpp"
+/* dynamical equations (Hamiltonian structure):
+dqdt_{i,j} = p_{i,j}
+dpdt_{i,j} = - omega_{i,j}*q_{i,j} - \beta*[ (q_{i,j} - q_{i,j-1})^3
+                                            +(q_{i,j} - q_{i,j+1})^3
+                                            +(q_{i,j} - q_{i-1,j})^3
+                                            +(q_{i,j} - q_{i+1,j})^3 ]
+*/
+
+
+using namespace std;
+
+static const int MAX_N = 1024;//2048;
+
+static const size_t KAPPA = 2;
+static const size_t LAMBDA = 4;
+static const double W = 1.0;
+static const double gap = 0.0;
+static const size_t steps = 100;
+static const double dt = 0.1;
+
+double initial_e = 1.0;
+double beta = 1.0;
+int realization_index = 0;
+
+//the state type
+typedef vector< vector< double > > state_type;
+
+//the stepper, choose a symplectic one to account for hamiltonian structure
+//use nested_range_algebra for calculations on vector< vector< ... > >
+typedef boost::numeric::odeint::symplectic_rkn_sb3a_mclachlan< 
+    state_type , state_type , double , state_type , state_type , double , 
+    nested_range_algebra< boost::numeric::odeint::range_algebra > ,
+    boost::numeric::odeint::default_operations > stepper_type;
+
+double time_diff_in_ms( timeval &t1 , timeval &t2 )
+{ return (t2.tv_sec - t1.tv_sec)*1000.0 + (t2.tv_usec - t1.tv_usec)/1000.0 + 0.5; }
+
+
+int main( int argc, const char* argv[] ) {
+
+    srand( time(NULL) );
+
+    lattice2d< KAPPA , LAMBDA > lattice( beta );
+
+
+    lattice.generate_pot( W , gap , MAX_N );
+
+    state_type q( MAX_N , vector< double >( MAX_N , 0.0 ) );
+
+    state_type p( q );
+
+    state_type energy( q );
+
+    p[MAX_N/2][MAX_N/2] = sqrt( 0.5*initial_e );
+    p[MAX_N/2+1][MAX_N/2] = sqrt( 0.5*initial_e );
+    p[MAX_N/2][MAX_N/2+1] = sqrt( 0.5*initial_e );
+    p[MAX_N/2+1][MAX_N/2+1] = sqrt( 0.5*initial_e );
+
+    cout.precision(10);
+
+    lattice.local_energy( q , p , energy );
+    double e=0.0;
+    for( size_t i=0 ; i<energy.size() ; ++i )
+        for( size_t j=0 ; j<energy[i].size() ; ++j )
+        {
+            e += energy[i][j];
+        }
+
+    cout << "initial energy: " << lattice.energy( q , p ) << endl;
+
+    timeval elapsed_time_start , elapsed_time_end;
+    gettimeofday(&elapsed_time_start , NULL);
+
+    stepper_type stepper;
+
+    for( size_t step=0 ; step<=steps ; ++step )
+    {
+        stepper.do_step( boost::ref( lattice ) , 
+                         make_pair( boost::ref( q ) , boost::ref( p ) ) , 
+                         0.0 , 0.1 );
+    }
+
+    gettimeofday(&elapsed_time_end , NULL);
+    double elapsed_time = time_diff_in_ms( elapsed_time_start , elapsed_time_end );
+    cout << steps << " steps in " << elapsed_time/1000 << " s (energy: " << lattice.energy( q , p ) << ")" << endl;
+}
diff --git a/examples/2d_lattice/vector_vector_resize.hpp b/examples/2d_lattice/vector_vector_resize.hpp
new file mode 100644
index 0000000..7132aa5
--- /dev/null
+++ b/examples/2d_lattice/vector_vector_resize.hpp
@@ -0,0 +1,105 @@
+/*
+ Copyright 2011 Mario Mulansky
+ Copyright 2012 Karsten Ahnert
+
+ Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or
+ copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+
+/* reserved vector */
+
+#ifndef VECTOR_VECTOR_RESIZE_HPP
+#define VECTOR_VECTOR_RESIZE_HPP
+
+#include <vector>
+
+#include <boost/range.hpp>
+
+namespace boost { namespace numeric { namespace odeint {
+
+template<>
+struct is_resizeable< std::vector< std::vector< double > > >
+{
+    typedef boost::true_type type;
+    const static bool value = type::value;
+};
+
+template<>
+struct same_size_impl< std::vector< std::vector< double > > , std::vector< std::vector< double > > >
+{
+    typedef std::vector< std::vector< double > > state_type;
+
+    static bool same_size( const state_type &x1 ,
+                           const state_type &x2 )
+    {
+        bool same = ( boost::size( x1 ) == boost::size( x2 ) );
+        if( !same )
+            return false;
+        typename state_type::const_iterator begin1 = boost::begin( x1 );
+        typename state_type::const_iterator begin2 = boost::begin( x2 );
+        while( begin1 != boost::end( x1 ) )
+            same &= ( boost::size( *begin1++ ) == boost::size( *begin2++ ) );
+        return same;
+    }
+};
+
+template<>
+struct resize_impl< std::vector< std::vector< double > > , std::vector< std::vector< double > > >
+{
+    typedef std::vector< std::vector< double > > state_type;
+
+    static void resize( state_type &x1 , const state_type &x2 )
+    {
+        x1.resize( boost::size( x2 ) );
+        typename state_type::iterator begin1 = boost::begin( x1 );
+        typename state_type::const_iterator begin2 = boost::begin( x2 );
+        while( begin1 != boost::end( x1 ) )
+            (*begin1++).resize( boost::size( *begin2++ ) );
+    }
+};
+
+template<>
+struct state_wrapper< std::vector< std::vector< double > > >
+{
+    typedef std::vector< std::vector< double > > state_type;
+    typedef state_wrapper< state_type > state_wrapper_type;
+    typedef boost::true_type is_resizeable;
+
+    state_type m_v;
+
+    template< class State >
+    bool same_size( const State &x )
+    {
+        bool same = ( boost::size( m_v ) == boost::size( x ) );
+        if( !same )
+            return false;
+        typename state_type::iterator begin1 = boost::begin( m_v );
+        typename State::const_iterator begin2 = boost::begin( x );
+        while( begin1 != boost::end( m_v ) )
+            same &= ( boost::size( *begin1++ ) == boost::size( *begin2++ ) );
+        return same;
+    }
+
+    template< class State >
+    bool resize( const State &x )
+    {
+        if( !same_size( x ) )
+        {
+            m_v.resize( boost::size( x ) );
+            typename state_type::iterator begin1 = boost::begin( m_v );
+            typename State::const_iterator begin2 = boost::begin( x );
+            while( begin1 != boost::end( m_v ) )
+                (*begin1++).resize( boost::size( *begin2++ ) );
+
+            return true;
+        } else
+            return false;
+    }
+ 
+};
+
+} } }
+
+#endif