Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r57818 - in sandbox/odeint: boost/numeric boost/numeric/odeint libs/numeric/odeint/examples
From: mario.mulansky_at_[hidden]
Date: 2009-11-20 09:29:22


Author: mariomulansky
Date: 2009-11-20 09:29:20 EST (Fri, 20 Nov 2009)
New Revision: 57818
URL: http://svn.boost.org/trac/boost/changeset/57818

Log:
changed stepsize_controller to controlled stepper
Added:
   sandbox/odeint/boost/numeric/odeint/controlled_stepper_standard.hpp
      - copied, changed from r57806, /sandbox/odeint/boost/numeric/odeint/stepsize_controller_standard.hpp
Removed:
   sandbox/odeint/boost/numeric/odeint/stepsize_controller_standard.hpp
Text files modified:
   sandbox/odeint/boost/numeric/odeint.hpp | 2
   sandbox/odeint/boost/numeric/odeint/controlled_stepper_standard.hpp | 103 +++++++++++++++++++++++----------------
   sandbox/odeint/boost/numeric/odeint/integrator_adaptive_stepsize.hpp | 91 ++++++++++++++++------------------
   sandbox/odeint/libs/numeric/odeint/examples/lorenz_controlled.cpp | 5 +
   sandbox/odeint/libs/numeric/odeint/examples/lorenz_integrator.cpp | 17 ++++-
   sandbox/odeint/libs/numeric/odeint/examples/pendulum_vibrating_pivot.cpp | 5 +
   6 files changed, 123 insertions(+), 100 deletions(-)

Modified: sandbox/odeint/boost/numeric/odeint.hpp
==============================================================================
--- sandbox/odeint/boost/numeric/odeint.hpp (original)
+++ sandbox/odeint/boost/numeric/odeint.hpp 2009-11-20 09:29:20 EST (Fri, 20 Nov 2009)
@@ -23,7 +23,7 @@
 #include <boost/numeric/odeint/stepper_half_step.hpp>
 #include <boost/numeric/odeint/stepper_midpoint.hpp>
 
-#include <boost/numeric/odeint/stepsize_controller_standard.hpp>
+#include <boost/numeric/odeint/controlled_stepper_standard.hpp>
 
 #include <boost/numeric/odeint/integrator_adaptive_stepsize.hpp>
 #include <boost/numeric/odeint/integrator_constant_stepsize.hpp>

Copied: sandbox/odeint/boost/numeric/odeint/controlled_stepper_standard.hpp (from r57806, /sandbox/odeint/boost/numeric/odeint/stepsize_controller_standard.hpp)
==============================================================================
--- /sandbox/odeint/boost/numeric/odeint/stepsize_controller_standard.hpp (original)
+++ sandbox/odeint/boost/numeric/odeint/controlled_stepper_standard.hpp 2009-11-20 09:29:20 EST (Fri, 20 Nov 2009)
@@ -1,17 +1,18 @@
-/* Boost odeint/stepsize_controller_standard.hpp header file
+/* Boost odeint/controlled_stepper_standard.hpp header file
  
  Copyright 2009 Karsten Ahnert
  Copyright 2009 Mario Mulansky
  
- This file includes the standard step size controller
+ This file includes the standard controlled stepper that should be
+ used with runge kutta routines.
 
  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)
 */
 
-#ifndef BOOST_NUMERIC_ODEINT_STEPSIZE_CONTROLLER_STANDARD_HPP
-#define BOOST_NUMERIC_ODEINT_STEPSIZE_CONTROLLER_STANDARD_HPP
+#ifndef BOOST_NUMERIC_ODEINT_CONTROLLED_STEPPER_STANDARD_HPP
+#define BOOST_NUMERIC_ODEINT_CONTROLLED_STEPPER_STANDARD_HPP
 
 #include <cmath> // for pow( ) and abs()
 #include <complex>
@@ -30,14 +31,6 @@
 
     /*
        The initial state is given in x.
- t is an vector including the times at which the state will be written into
- the vector x_vec.
- x_vec must provide enough space to hold times.size() states.
- dt is the initial step size (will be adjusted according to the errors).
- This function returns the total number of steps required to integrate the
- whole intervale times.begin() - times.end().
- Note that the values in times don't influence the stepsize, but only the
- time points at which the state is stored into x_vec.
        
        The stepsize is adjust such that the following maximal relative error is
        small enough for each step:
@@ -59,53 +52,77 @@
     */
 
     template<
- class ContainerType,
- class T,
- class ResizeType = resizer< ContainerType > >
- class step_controller_standard {
-
- typedef typename ContainerType::iterator iterator;
-
- T eps_abs;
- T eps_rel;
- T a_x;
- T a_dxdt;
- ContainerType dxdt;
- ContainerType x_tmp;
- ContainerType x_err;
- ResizeType resizer;
-
+ class ErrorStepper,
+ class ResizeType = resizer< typename ErrorStepper::container_type > >
+ class controlled_stepper_standard {
+
     public:
 
- typedef ContainerType container_type;
+ // forward types from ErrorStepper
+ typedef typename ErrorStepper::container_type container_type;
+ typedef typename ErrorStepper::resizer_type resizer_type;
+ typedef typename ErrorStepper::time_type time_type;
+ typedef typename container_type::value_type value_type;
+ typedef typename container_type::iterator iterator;
+
+ typedef const unsigned short order_type;
+
+ // private members
+ private:
+ ErrorStepper &m_stepper;
+
+ time_type eps_abs;
+ time_type eps_rel;
+ time_type a_x;
+ time_type a_dxdt;
+ container_type dxdt;
+ container_type x_tmp;
+ container_type x_err;
+ resizer_type resizer;
+
+
+ // public functions
+ public:
         
- step_controller_standard( T abs_err, T rel_err, T factor_x, T factor_dxdt )
- : eps_abs(abs_err), eps_rel(rel_err), a_x(factor_x), a_dxdt(factor_dxdt)
+ controlled_stepper_standard(
+ ErrorStepper &stepper,
+ time_type abs_err, time_type rel_err,
+ time_type factor_x, time_type factor_dxdt )
+ : m_stepper(stepper),
+ eps_abs(abs_err), eps_rel(rel_err), a_x(factor_x), a_dxdt(factor_dxdt)
         { }
 
- template< class Step, class DynamicalSystem >
- controlled_step_result controlled_step( Step &stepper,
- DynamicalSystem &system,
- ContainerType &x,
- T &t,
- T &dt )
+
+ /* Tries a controlled step with the given stepsize dt. If dt is too large,
+ x remains unchanged, an appropriate stepsize is assigned to dt and
+ step_size_decreased is returned. If dt is too small, the small step is
+ accomplished, a larger stepsize is assigned to dt and step_size_increased
+ is returned. If dt is appropriate, the step is accomplished and success
+ is returned.
+ */
+ template< class DynamicalSystem >
+ controlled_step_result next_step(
+ DynamicalSystem &system,
+ container_type &x,
+ time_type &t,
+ time_type &dt )
         {
             resizer.adjust_size(x, x_err);
 
             x_tmp = x; // copy current state
             system( x, dxdt, t ); // compute dxdt
- stepper.next_step(system, x, dxdt, t, dt, x_err ); // do step forward with error
+ m_stepper.next_step(system, x, dxdt, t, dt, x_err ); // do step forward with error
 
             iterator x_start = x_tmp.begin();
             iterator dxdt_start = dxdt.begin();
             iterator x_err_start = x_err.begin();
- T max_rel_err = 0.0;
+ time_type max_rel_err = 0.0;
 
             while( x_start != x_tmp.end() ) {
                 // get the maximal value of x_err/D where
                 // D = eps_abs + eps_rel * (a_x*|x| + a_dxdt*|dxdt|);
- T err = eps_abs + eps_rel * (a_x * std::abs(*x_start++) +
- a_dxdt * dt * std::abs(*dxdt_start++));
+ time_type err = eps_abs + eps_rel * (a_x * std::abs(*x_start++) +
+ a_dxdt * dt * std::abs(*dxdt_start++));
                 max_rel_err = max( std::abs(*x_err_start++)/err , max_rel_err );
             }
 
@@ -113,14 +130,14 @@
 
             if( max_rel_err > 1.1 ) { // error too large - decrease dt
                 // limit scaling factor to 0.2
- dt *= max( 0.9*pow(max_rel_err , -1.0/(stepper.order_error()-1.0)) , 0.2 );
+ dt *= max( 0.9*pow(max_rel_err , -1.0/(m_stepper.order_error()-1.0)) , 0.2 );
                 // reset state
                 x = x_tmp;
                 return step_size_decreased;
             } else if( max_rel_err < 0.5 ) { //error too small - increase dt
                 t += dt; // we keep the evolution -> increase time
                 // limit scaling factor to 5.0
- dt *= min( 0.9*pow(max_rel_err , -1.0/stepper.order()), 5.0 );
+ dt *= min( 0.9*pow(max_rel_err , -1.0/m_stepper.order()), 5.0 );
                 return step_size_increased;
             } else {
                 t += dt;

Modified: sandbox/odeint/boost/numeric/odeint/integrator_adaptive_stepsize.hpp
==============================================================================
--- sandbox/odeint/boost/numeric/odeint/integrator_adaptive_stepsize.hpp (original)
+++ sandbox/odeint/boost/numeric/odeint/integrator_adaptive_stepsize.hpp 2009-11-20 09:29:20 EST (Fri, 20 Nov 2009)
@@ -13,7 +13,7 @@
 #ifndef BOOST_NUMERIC_ODEINT_INTEGRATOR_ADAPTIVE_STEPSIZE_HPP
 #define BOOST_NUMERIC_ODEINT_INTEGRATOR_ADAPTIVE_STEPSIZE_HPP
 
-#include <boost/numeric/odeint/stepsize_controller_standard.hpp>
+#include <boost/numeric/odeint/controlled_stepper_standard.hpp>
 #include <boost/numeric/odeint/resizer.hpp>
 #include <boost/numeric/odeint/observer.hpp>
 #include <vector>
@@ -25,32 +25,30 @@
 
 
     template<
- class Stepper,
+ class ControlledStepper,
             class DynamicalSystem,
- class StepController,
             class Observer
>
     size_t integrate_adaptive(
- Stepper &stepper,
+ ControlledStepper &stepper,
             DynamicalSystem &system,
- StepController &controller,
- typename Stepper::container_type &state,
- typename Stepper::time_type start_time,
- typename Stepper::time_type end_time,
- typename Stepper::time_type dt,
+ typename ControlledStepper::container_type &state,
+ typename ControlledStepper::time_type start_time,
+ typename ControlledStepper::time_type end_time,
+ typename ControlledStepper::time_type dt,
             Observer &observer )
     {
         controlled_step_result result;
         size_t iterations = 0;
- typename Stepper::time_type t = start_time;
- typename Stepper::time_type dt_ = dt;
+ typename ControlledStepper::time_type t = start_time;
+ typename ControlledStepper::time_type dt_ = dt;
 
         observer(t, state, system);
         
         while( t < end_time )
         {
             // do a controlled step
- result = controller.controlled_step( stepper, system, state, t, dt_ );
+ result = stepper.next_step( system, state, t, dt_ );
 
             if( result != step_size_decreased )
             { // we actually did a step forward (dt was small enough)
@@ -65,26 +63,24 @@
     }
 
     template<
- class Stepper,
- class DynamicalSystem,
- class StepController
+ class ControlledStepper,
+ class DynamicalSystem
>
     size_t integrate_adaptive(
- Stepper &stepper,
+ ControlledStepper &stepper,
             DynamicalSystem &system,
- StepController &controller,
- typename Stepper::container_type &state,
- typename Stepper::time_type start_time,
- typename Stepper::time_type end_time,
- typename Stepper::time_type dt )
+ typename ControlledStepper::container_type &state,
+ typename ControlledStepper::time_type start_time,
+ typename ControlledStepper::time_type end_time,
+ typename ControlledStepper::time_type dt )
     {
         return integrate_adaptive(
- stepper , system , controller ,
- state, start_time , end_time,
- do_nothing_observer<
- typename Stepper::time_type ,
- typename Stepper::container_type ,
- DynamicalSystem >
+ stepper, system ,
+ state, start_time , end_time,
+ do_nothing_observer<
+ typename ControlledStepper::time_type ,
+ typename ControlledStepper::container_type ,
+ DynamicalSystem >
             );
     }
 
@@ -105,26 +101,24 @@
        time points at which the state is stored into x_vec.
     */
     template<
- class Stepper,
+ class ControlledStepper,
         class DynamicalSystem,
- class StepController,
         class TimeSequence,
         class InsertIterator
>
     size_t integrate(
- Stepper &stepper,
+ ControlledStepper &stepper,
             DynamicalSystem &system,
- StepController &controller,
- typename Stepper::container_type &state,
+ typename ControlledStepper::container_type &state,
             TimeSequence &times,
- typename Stepper::time_type &dt,
+ typename ControlledStepper::time_type dt,
             InsertIterator state_inserter)
     {
         if( times.empty() ) return 0;
         else
         {
             state_copy_observer<InsertIterator, TimeSequence> observer(times, state_inserter);
- return integrate_adaptive(stepper, system, controller, state,
+ return integrate_adaptive(stepper, system, state,
                                       times.front() , times.back(), dt , observer);
         }
     }
@@ -137,32 +131,33 @@
        given below.
     */
     template<
- class Stepper,
             class DynamicalSystem,
- class InsertIterator ,
- class TimeSequence
+ class ContainerType,
+ class InsertIterator,
+ class TimeSequence,
+ class T
>
     size_t integrate(
- Stepper &stepper,
             DynamicalSystem &system,
- typename Stepper::container_type &x,
+ ContainerType &x,
             TimeSequence &times,
             InsertIterator state_inserter,
- typename Stepper::time_type dt = 1E-4,
- typename Stepper::time_type eps_abs = 1E-6,
- typename Stepper::time_type eps_rel = 1E-7,
- typename Stepper::time_type a_x = 1.0 ,
- typename Stepper::time_type a_dxdt = 1.0
+ T dt = 1E-4,
+ T eps_abs = 1E-6,
+ T eps_rel = 1E-7,
+ T a_x = 1.0 ,
+ T a_dxdt = 1.0
                      )
     {
+ // we use cash karp stepper as base stepper
+ stepper_rk5_ck< ContainerType > stepper_cash_karp;
         // we use the standard controller for this adaptive integrator
- step_controller_standard< typename Stepper::container_type,
- typename Stepper::time_type,
- typename Stepper::resizer_type > controller(eps_abs, eps_rel, a_x, a_dxdt );
+ controlled_stepper_standard< ContainerType, T>
+ controlled_stepper(stepper_cash_karp, eps_abs, eps_rel, a_x, a_dxdt );
         // initialized with values from above
         
         // call the normal integrator
- return integrate(stepper, system, controller, x, times, dt, state_inserter);
+ return integrate(controlled_stepper, system, x, times, dt, state_inserter);
     }
     
 

Deleted: sandbox/odeint/boost/numeric/odeint/stepsize_controller_standard.hpp
==============================================================================
--- sandbox/odeint/boost/numeric/odeint/stepsize_controller_standard.hpp 2009-11-20 09:29:20 EST (Fri, 20 Nov 2009)
+++ (empty file)
@@ -1,137 +0,0 @@
-/* Boost odeint/stepsize_controller_standard.hpp header file
-
- Copyright 2009 Karsten Ahnert
- Copyright 2009 Mario Mulansky
-
- This file includes the standard step size controller
-
- 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)
-*/
-
-#ifndef BOOST_NUMERIC_ODEINT_STEPSIZE_CONTROLLER_STANDARD_HPP
-#define BOOST_NUMERIC_ODEINT_STEPSIZE_CONTROLLER_STANDARD_HPP
-
-#include <cmath> // for pow( ) and abs()
-#include <complex>
-
-#include <boost/concept_check.hpp>
-
-#include <boost/numeric/odeint/detail/iterator_algebra.hpp>
-#include <boost/numeric/odeint/concepts/state_concept.hpp>
-#include <boost/numeric/odeint/resizer.hpp>
-
-namespace boost {
-namespace numeric {
-namespace odeint {
-
- typedef enum{success, step_size_decreased, step_size_increased} controlled_step_result;
-
- /*
- The initial state is given in x.
- t is an vector including the times at which the state will be written into
- the vector x_vec.
- x_vec must provide enough space to hold times.size() states.
- dt is the initial step size (will be adjusted according to the errors).
- This function returns the total number of steps required to integrate the
- whole intervale times.begin() - times.end().
- Note that the values in times don't influence the stepsize, but only the
- time points at which the state is stored into x_vec.
-
- The stepsize is adjust such that the following maximal relative error is
- small enough for each step:
- R = max( x_err_n / [eps_abs + eps_rel*( a_x * |x_n| + a_dxdt * |dxdt_n| )] )
- where the max refers to the componentwise maximum the expression.
-
- if R > 1.1 the stepsize is decreased:
- dt = dt*S*R^(-1/(q-1))
-
- if R < 0.5 the stepsize is increased:
- dt = dt*S*R^(-1/q))
-
- q is the order of the error term provided by the stepper.order_error() function
- (e.g. 2 for simple euler and 5 for rk5_ck) and S is a safety factor set to
- S = 0.9. See e.g. Numerical Recipes for more details on this strategy.
-
- To avoid extensive chages in dt, the decrease factor is limited to 0.2 and
- the increase factor to 5.0.
- */
-
- template<
- class ContainerType,
- class T,
- class ResizeType = resizer< ContainerType > >
- class step_controller_standard {
-
- typedef typename ContainerType::iterator iterator;
-
- T eps_abs;
- T eps_rel;
- T a_x;
- T a_dxdt;
- ContainerType dxdt;
- ContainerType x_tmp;
- ContainerType x_err;
- ResizeType resizer;
-
- public:
-
- typedef ContainerType container_type;
-
- step_controller_standard( T abs_err, T rel_err, T factor_x, T factor_dxdt )
- : eps_abs(abs_err), eps_rel(rel_err), a_x(factor_x), a_dxdt(factor_dxdt)
- { }
-
- template< class Step, class DynamicalSystem >
- controlled_step_result controlled_step( Step &stepper,
- DynamicalSystem &system,
- ContainerType &x,
- T &t,
- T &dt )
- {
- resizer.adjust_size(x, x_err);
-
- x_tmp = x; // copy current state
- system( x, dxdt, t ); // compute dxdt
- stepper.next_step(system, x, dxdt, t, dt, x_err ); // do step forward with error
-
- iterator x_start = x_tmp.begin();
- iterator dxdt_start = dxdt.begin();
- iterator x_err_start = x_err.begin();
- T max_rel_err = 0.0;
-
- while( x_start != x_tmp.end() ) {
- // get the maximal value of x_err/D where
- // D = eps_abs + eps_rel * (a_x*|x| + a_dxdt*|dxdt|);
- T err = eps_abs + eps_rel * (a_x * std::abs(*x_start++) +
- a_dxdt * dt * std::abs(*dxdt_start++));
- max_rel_err = max( std::abs(*x_err_start++)/err , max_rel_err );
- }
-
- //std::cout<<max_rel_err<<std::endl;
-
- if( max_rel_err > 1.1 ) { // error too large - decrease dt
- // limit scaling factor to 0.2
- dt *= max( 0.9*pow(max_rel_err , -1.0/(stepper.order_error()-1.0)) , 0.2 );
- // reset state
- x = x_tmp;
- return step_size_decreased;
- } else if( max_rel_err < 0.5 ) { //error too small - increase dt
- t += dt; // we keep the evolution -> increase time
- // limit scaling factor to 5.0
- dt *= min( 0.9*pow(max_rel_err , -1.0/stepper.order()), 5.0 );
- return step_size_increased;
- } else {
- t += dt;
- return success;
- }
- }
- };
-
-} // namespace odeint
-} // namespace numeric
-} // namespace boost
-
-
-#endif // BOOST_NUMERIC_ODEINT_STEPSIZE_CONTROLLER_STANDARD_HPP

Modified: sandbox/odeint/libs/numeric/odeint/examples/lorenz_controlled.cpp
==============================================================================
--- sandbox/odeint/libs/numeric/odeint/examples/lorenz_controlled.cpp (original)
+++ sandbox/odeint/libs/numeric/odeint/examples/lorenz_controlled.cpp 2009-11-20 09:29:20 EST (Fri, 20 Nov 2009)
@@ -61,12 +61,13 @@
     x[2] = 20.0;
 
     stepper_half_step< stepper_euler< state_type > > euler;
- step_controller_standard< state_type, double > controller( eps_abs , eps_rel, 1.0, 1.0);
+ controlled_stepper_standard< stepper_half_step< stepper_euler< state_type > > >
+ controlled_stepper( euler, eps_abs , eps_rel, 1.0, 1.0);
     
     cout.precision(5);
     cout.setf(ios::fixed,ios::floatfield);
     
- size_t steps = integrate_adaptive( euler, lorenz, controller, x, 0.0, 10.0, 1E-4, print_state );
+ size_t steps = integrate_adaptive( controlled_stepper, lorenz, x, 0.0, 10.0, 1E-4, print_state );
 
     clog << "Number of steps: " << steps << endl;
 

Modified: sandbox/odeint/libs/numeric/odeint/examples/lorenz_integrator.cpp
==============================================================================
--- sandbox/odeint/libs/numeric/odeint/examples/lorenz_integrator.cpp (original)
+++ sandbox/odeint/libs/numeric/odeint/examples/lorenz_integrator.cpp 2009-11-20 09:29:20 EST (Fri, 20 Nov 2009)
@@ -35,8 +35,8 @@
 const double R = 28.0;
 const double b = 8.0 / 3.0;
 
-const double eps_abs = 1E-3;
-const double eps_rel = 1E-3;
+const double eps_abs = 1E-6;
+const double eps_rel = 1E-7;
 
 const size_t time_points = 101;
 
@@ -68,18 +68,25 @@
     }
 
     stepper_half_step< stepper_euler< state_type > > euler;
- size_t steps = integrate( euler, lorenz, x1, times, back_inserter(x1_t_vec));
+ controlled_stepper_standard< stepper_half_step< stepper_euler< state_type > > >
+ euler_controlled( euler , eps_abs, eps_rel, 1.0, 1.0);
+ size_t steps = integrate( euler_controlled, lorenz, x1,
+ times, 1E-4, back_inserter(x1_t_vec));
 
     clog << "Euler Half Step: #steps " << steps << endl;
 
     stepper_half_step< stepper_rk4< state_type > > rk4;
- steps = integrate( rk4, lorenz, x2, times, back_inserter(x2_t_vec));
+ controlled_stepper_standard< stepper_half_step< stepper_rk4< state_type > > >
+ rk4_controlled( rk4 , eps_abs, eps_rel, 1.0, 1.0);
+ steps = integrate( rk4_controlled, lorenz, x2, times, 1E-4, back_inserter(x2_t_vec));
 
     clog << "RK4 Half Step: #steps " << steps << endl;
 
 
     stepper_rk5_ck< state_type > rk5;
- steps = integrate( rk5, lorenz, x3, times, back_inserter(x3_t_vec));
+ controlled_stepper_standard< stepper_rk5_ck< state_type > >
+ rk5_controlled( rk5 , eps_abs, eps_rel, 1.0, 1.0);
+ steps = integrate( rk5_controlled, lorenz, x3, times, 1E-4, back_inserter(x3_t_vec));
     
     clog << "RK5 Cash-Karp: #steps: " << steps << endl;
 

Modified: sandbox/odeint/libs/numeric/odeint/examples/pendulum_vibrating_pivot.cpp
==============================================================================
--- sandbox/odeint/libs/numeric/odeint/examples/pendulum_vibrating_pivot.cpp (original)
+++ sandbox/odeint/libs/numeric/odeint/examples/pendulum_vibrating_pivot.cpp 2009-11-20 09:29:20 EST (Fri, 20 Nov 2009)
@@ -59,7 +59,10 @@
     
     stepper_half_step< stepper_rk4< state_type > > stepper;
 
- size_t steps = integrate( stepper, my_system, x, times, back_inserter(x_t_vec));
+ controlled_stepper_standard< stepper_half_step< stepper_rk4< state_type > > >
+ controlled_stepper( stepper, 1E-6 , 1E-7 , 1.0 , 1.0 );
+
+ size_t steps = integrate( controlled_stepper, my_system, x, times, 1E-4, back_inserter(x_t_vec)); \
 
         clog << "Steps: " << steps << endl;
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk