UP | HOME

The Langford Attractor
A MRKISS Library Example Program

Author: Mitch Richling
Updated: 2025-08-18 15:21:31
Generated: 2025-08-18 15:22:47

Copyright © 2025 Mitch Richling. All rights reserved.

Table of Contents

1. Results

The code for this example is found in examples/langford.f90. Additionally the code may be found at the end of this document in the section Full Code Listing.

The Langford attractor is governed by the following equations:

\[ \begin{align*} \frac{\mathrm{d}x}{\mathrm{d}t} & = (z - \beta) x - \omega y \\ \frac{\mathrm{d}y}{\mathrm{d}t} & = \omega x + (z - \beta) y \\ \frac{\mathrm{d}z}{\mathrm{d}t} & = \lambda + \alpha z - \frac{z^3}{3} - (x^2 + y^2) (1 + \rho z) + \epsilon z x^3 \end{align*} \]

With the following parameter values:

\[ \begin{align*} \alpha & = 0.95 \\ \beta & = 0.70 \\ \lambda & = 0.60 \\ \omega & = 3.50 \\ \rho & = 0.25 \\ \epsilon & = 0.10 \end{align*} \]

And with the following initial conditions:

\[ \begin{align*} x(0) & = 0.1 \\ y(0) & = 0.0 \\ z(0) & = 0.0 \end{align*} \]

We can translate that equation to code like this:

subroutine eq(status, dydt, y, param)
  integer,          intent(out) :: status
  real(kind=rk),    intent(out) :: dydt(:)
  real(kind=rk),    intent(in)  :: y(:), param(:)
  dydt = [(y(3) - param(2)) * y(1) - param(4) * y(2), 
          param(4)*y(1) + (y(3) - param(2))*y(2), 
          param(3) + param(1)*y(3) - (y(3)**3/3) - (y(1)**2+y(2)**2)*(1 + param(5)*y(3)) + param(6)*y(3)*y(1)**3]
  status = 0
end subroutine eq

We can solve and output the solution to a CSV file like this:

y_iv = [0.1_rk, 0.0_rk, 0.0_rk]
call steps_fixed_stab(status, istats, solution, eq, y_iv, param, a, b, c, t_delta_o=t_delta, max_pts_o=15000)
call print_solution(status, solution, filename_o="langford_fixed.csv", end_o=istats(1))

If we then load the data into Paraview, we get something like this:

langford_pv_fixed.png

We could also graph it with GNUplot:

langford_fixed.png

Just for fun, let's solve the IVP 20 times with diffrent initial values on a little circle on the central "stalk" structure. We can do that, in parallel, with this little bit of code:

!$OMP PARALLEL DO private(solution, status, istats, filename, i, y_iv)
do i=0, num_lines-1
   y_iv(1) = cos(i * 2 * pi / num_lines) * 0.15_rk + 0.2_rk
   y_iv(2) = sin(i * 2 * pi / num_lines) * 0.15_rk
   y_iv(3) = 0.05_rk
   call steps_fixed_stab(status, istats, solution, eq, y_iv, param, a, b, c, t_delta_o=t_delta, max_pts_o=350)
   write (filename, '("langford_",i2.2,".csv")') i
   call print_solution(status, solution, filename_o=trim(filename), end_o=istats(1), tag_o=i)
   print *, 'Line Complete: ', i
end do
!$OMP END PARALLEL DO

We can take the resulting 20 CSV files, load them up into Paraview, and animate the results:

langford_mov_050.gif

2. Full Code Listing

2.1. Fortran Code

program langford
  use :: mrkiss_config,      only: rk, istats_size
  use :: mrkiss_solvers_nt,  only: steps_fixed_stab
  use :: mrkiss_utils,       only: print_solution
  use :: mrkiss_erk_kutta_4, only: a, b, c
  use :: omp_lib

  implicit none

  real(kind=rk),  parameter :: pi         = 4.0_rk * atan(1.0_rk)
  integer,        parameter :: num_lines  = 20
  integer,        parameter :: deq_dim    = 3
  integer,        parameter :: num_points = 100000
  real(kind=rk),  parameter :: param(6)   = [0.95_rk, 0.7_rk, 0.6_rk, 3.5_rk, 0.25_rk, 0.1_rk]
  real(kind=rk),  parameter :: t_delta    = 0.01_rk

  real(kind=rk)             :: solution(1+2*deq_dim, num_points), y_iv(deq_dim)
  integer                   :: status, istats(istats_size), i
  character(len=512)        :: filename

  y_iv = [0.1_rk, 0.0_rk, 0.0_rk]
  call steps_fixed_stab(status, istats, solution, eq, y_iv, param, a, b, c, t_delta_o=t_delta, max_pts_o=15000)
  call print_solution(status, solution, filename_o="langford_fixed.csv", end_o=istats(1))

  !$OMP PARALLEL DO private(solution, status, istats, filename, i, y_iv)
  do i=0, num_lines-1
     y_iv(1) = cos(i * 2 * pi / num_lines) * 0.15_rk + 0.2_rk
     y_iv(2) = sin(i * 2 * pi / num_lines) * 0.15_rk
     y_iv(3) = 0.05_rk
     call steps_fixed_stab(status, istats, solution, eq, y_iv, param, a, b, c, t_delta_o=t_delta, max_pts_o=350)
     write (filename, '("langford_",i2.2,".csv")') i
     call print_solution(status, solution, filename_o=trim(filename), end_o=istats(1), tag_o=i)
     print *, 'Line Complete: ', i
  end do
  !$OMP END PARALLEL DO

contains

  subroutine eq(status, dydt, y, param)
    integer,          intent(out) :: status
    real(kind=rk),    intent(out) :: dydt(:)
    real(kind=rk),    intent(in)  :: y(:), param(:)
    dydt = [(y(3) - param(2)) * y(1) - param(4) * y(2), 
            param(4)*y(1) + (y(3) - param(2))*y(2), 
            param(3) + param(1)*y(3) - (y(3)**3/3) - (y(1)**2+y(2)**2)*(1 + param(5)*y(3)) + param(6)*y(3)*y(1)**3]
    status = 0
  end subroutine eq

end program langford

2.2. GNUplot Code

The images were produced with GNUplot.

set encoding utf8
set termoption noenhanced
set datafile separator ','
set margins 0, 0, 0, 0
set view 50, 40, 1.3, 1.4
set xyplane at 0
unset border
unset ytics
unset ztics
unset xtics
set terminal svg
set pointsize 0.2

set title "Langford (fixed)"
set output "langford_fixed.svg"
splot 'langford_fixed.csv' using 3:4:5 with lines title ""

set title "Langford (fixed)"
set output "langford_multi.svg"
splot for [i=1:20] sprintf("langford_%02d.csv", i) using 4:5:6 with lines title ""

The multiple curve graph may be explored interactively with the following code.

set encoding utf8
set termoption noenhanced
set datafile separator ','
unset xlabel
unset ylabel
unset zlabel
unset grid
unset border
unset ytics
unset ztics
unset xtics
set view equal xyz
set view 160, 90

set title "Langford"
splot for [i=1:20] sprintf("langford_%02d.csv", i) using 4:5:6 with lines title ""

pause -1