2.2 Periodic orbits
2.2.3 Chosen algorithm
This subsection describes in detail the implementation and development of the direct forward integration algorithm described in the previous section. This method was chosen initially for simplicity, and as described in Subsection 2.2.4 on page 43, it achieves good results, when combined with certain refinements to the algorithm. The fact that this algorithm is unable to find unstable limit cycles is not of major concern, because they biologically less important. The details of the precise algorithm used are discussed in Box 2.1.
First of all, a parameter space was chosen to represent biologically realistic ranges for each of the three parameters. β/g(≈R0) was chosen to run from 0.98—just less than unity to test that the numerics show the infection dying out—to 20. x was chosen to run from 0.01 to 0.5. This corresponds to a birth/death rate varying from 2.7535×10−5 to 1.8990×10−3 per day or an average life expectancy of about 100 years to 18 months. Realistic values of g were considered to be between 0.075 and 0.5, so that the infectious period ranges from about two weeks to two days. A grid was then placed on this space and the dynamics considered at discrete points in this space. Forβ/g the range was covered by 318 points, including the end points, with a regular spacing of 0.06. The x range was covered by 301 logarithmically spaced points including the end points. This grid in β/g-x space will from here on in be referred to as parameter space. Forg however, only 4 values 0.075, 0.100, 0.250 and 0.500 were chosen. This was done forg rather than one of the other two parameters because in practise it is much easier to measure g. Out of the three parameters g is, to a greatest extent, a function of the disease rather than the population—or even a combination of the two. Thus when trying to fit the model to a real disease this approach makes comparing epidemics, of the same disease, across different populations possible.
2.1 Calculating the period
Accurately determining the period of an attractor numerically has proved to be a challenging problem. Firstly, the possibility that a point may not have converged to a limit cycle and indeed may never do so must be considered!
In some areas of parameter space the convergence can be very slow (of the
order of several thousand years) so determining when to stop and assume a periodic attractor doesn’t exist can be problematic. How the algorithm works is now described. All the numerics only consider the state variablesS andI, together denoted here byP. The value ofRis not calculated because it is simply a function ofI. A fixed time step fourth order Runge-Kutta scheme was used for integration [Hairer et al., 2002], as discussed in Subsection 2.2.1 on page 35.
The core of the period finding is the functiontry_periods():
t
T
Figure 2.7: The period calculation algorithm explained graphically, showing how try_periods() works. The sys- tem starts at P_start—denoted by the left most pair of crosses. Iterating forward in time—moving to the right—
try_periods() checks if the state—denoted by circles—is
close toP_start. After four years the system returns to the
original stateP_start—right most pair of crosses.
P_start=P
for period = 0 to MAX_PERIOD : iterate_forward(ONE_YEAR,P)
if is_close(P,P_start) : return period return -1
This function simply checks if the the system returns to the same state (up
to a tolerance, see Box 2.2 on page 43) indicating that the system maybe on, or converging to a limit cycle. If the system doesn’t return the the same state withinMAX_PERIODyears it terminates and returns a period of −1 signifying failure. This function is illustrated in Figure 2.7.
The above process works well when starting on or close to an attrac- tor, but will fail if the system has not yet converged. The next func- tion check_again() deals with this by iterating the system forward for
TRY_AGAIN_YEARS, usually 100, before calling try_periods()again:
function period=check_again(P) : for k = 1 to MAX_TRIES :
period = try_periods(P) if period == -1 : iterate_forward(TRY_AGAIN_YEARS,P) else if period == 1 : if I < 1e-200 : return 0 else :
if period is even : check_half_period(P,period) return period
return -1
There is a limit of MAX_TRIES (usually 50) calls to try_periods() to avoid an infinite loop. If this limit is reached−1 is returned.
If the system fails to get back to the same state again withinMAX_PERIOD
years one of three things could be happening:
• Pis not in the basin of attraction of a periodic attractor and thus will never converge.
• Phas not yet converged to an attractor.
• It is on a periodic orbit with period greater thanMAX_PERIOD.
• It is on a chaotic attractor.
In all four cases try_periods() will return −1. When this happens
check_again()will iterate the system forward for TRY_AGAIN_YEARS and calltry_periods()again, assumingMAX_TRIEShas not been reached. When
MAX_TRIESis reached the presence of a chaotic attractor is usually presumed. A possible improvement would be to confirm this by checking the Lyapunov exponent to confirm if the dynamics are in fact chaotic.
Thecheck_again()function also deals with a couple of special cases. If
try_periods()returns 1, the state is the same after only one year, then it
is quite possible that the state has not changed at all. Some basic analysis
shows that the only time that this can happen is through extinction, thus a check of whetherI is approaching machine precision is carried out in the period 1 case. In the case that the period returned by try_periods() is
even, the half period check is applied. This is discussed in detail in Box 2.4
Before finally returning the period the top level functioncalc_period(), if it has locked on to an attractor, moves P to the annual point on the attractor with maximalI:
function period=calc_period(P){ period=check_again(P) if period > 0 : minimise_I(P) return period } 2.2 Closeness
A key method in these numerics is to decide if two points in phase space are in some sense close. To determine this the following function was chosen. Given two points P1 = (S1, I1) and P2 = (S2, I2) they are said to be close if
d(P1, P2) = 1−S1 S2 + 1− I1 I2 <
This function was chosen instead of the Euclidean metric because it gives a
more comparable measure of closeness for both large and extremely small numbers. In essence it ensures that the relative error is small, not just the absolute error when S, I≤1. This is important because I can range from order 1 to order 10−15 or smaller. In most calculations, including period calculations, = 10−8.
It is worth noting that d is not a metric on R2. While d satisfies the non-negativity and identity axioms it is obviously not symmetric. This could be rectified by defining
D(P1, P2) =d(P1, P2) +d(P2, P1).
This was not done for performance reasons.