๐ป Fortran Source Code Library
We currently offer 172 open-source, production-grade Fortran codes for offline testing. Run calculations locally on your own machine, view code structure, read technical explanations, and download compilation packages including sample input files.
ODE Solver Stability Regions
Core Numerical Engine in Fortran 90 โข 30 total downloads
stability_regions.f90
! =========================================================================
! Source File: stability_regions.f90
! =========================================================================
!==============================================================================
! ThermoFluidCalc โ Calculator #21 : Stability Regions
!==============================================================================
! Physics : Maps the |G(z)| = 1 boundary in the complex z = ฮปฮt plane
! for 6 classical ODE/PDE time-integration schemes.
!
! Schemes:
! 1 = Forward Euler G = 1 + z
! 2 = Backward Euler G = 1/(1 - z)
! 3 = Crank-Nicolson G = (2 + z)/(2 - z)
! 4 = Leapfrog G = z ยฑ sqrt(zยฒ + 1) (two roots; max |G|)
! 5 = RK2 (Heun) G = 1 + z + zยฒ/2
! 6 = RK4 (Classical) G = 1 + z + zยฒ/2 + zยณ/6 + zโด/24
!
! Reference : Gupta ยง2.8; Hairer & Wanner, "Solving ODEs II"
!
! Build:
! gfortran -O2 -o stability_regions stability_regions.f90
!
! Input (stdin): npts z_test_re z_test_im
! Output (stdout): structured data (see below)
!==============================================================================
program stability_regions
implicit none
integer, parameter :: dp = selected_real_kind(15, 307)
real(dp), parameter :: PI = 3.141592653589793238_dp
integer, parameter :: NSCHEMES = 6
integer, parameter :: MAX_BISECT = 80
integer :: npts, i, s
real(dp) :: z_test_re, z_test_im
complex(dp) :: z_test, gz
real(dp) :: angle, dangle, r_lo, r_hi, r_mid, gm
real(dp) :: cx, cy ! center for sweep
real(dp) :: x, y
real(dp) :: probe_mag(NSCHEMES)
logical :: probe_stable(NSCHEMES)
character(len=40) :: sname(NSCHEMES)
character(len=80) :: sformula(NSCHEMES)
character(len=80) :: sregion(NSCHEMES)
! Scheme metadata
sname(1) = 'Forward Euler (Explicit)'
sname(2) = 'Backward Euler (Implicit)'
sname(3) = 'Crank-Nicolson'
sname(4) = 'Leapfrog (Midpoint)'
sname(5) = 'RK2 (Heun)'
sname(6) = 'RK4 (Classical)'
sformula(1) = 'G = 1 + z'
sformula(2) = 'G = 1 / (1 - z)'
sformula(3) = 'G = (2 + z) / (2 - z)'
sformula(4) = 'G = z +/- sqrt(z^2 + 1)'
sformula(5) = 'G = 1 + z + z^2/2'
sformula(6) = 'G = 1 + z + z^2/2 + z^3/6 + z^4/24'
sregion(1) = 'Disk center(-1,0) radius 1'
sregion(2) = 'Exterior of disk center(1,0) radius 1'
sregion(3) = 'Left half-plane Re(z) <= 0'
sregion(4) = 'Imaginary segment [-i, i]'
sregion(5) = 'Closed region (computed numerically)'
sregion(6) = 'Closed region (computed numerically)'
! โโ Read input โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
read(*,*) npts, z_test_re, z_test_im
if (npts < 40) npts = 40
if (npts > 4000) npts = 4000
z_test = cmplx(z_test_re, z_test_im, dp)
dangle = 2.0_dp * PI / real(npts, dp)
! โโ Loop over each scheme โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
do s = 1, NSCHEMES
! --- Probe point evaluation ---
gz = eval_G(s, z_test)
probe_mag(s) = abs(gz)
probe_stable(s) = (probe_mag(s) <= 1.0_dp + 1.0e-10_dp)
! --- Header for this scheme ---
write(*,'(A,I1,A,A)') 'SCHEME_', s, '=', trim(sname(s))
write(*,'(A,I1,A,A)') 'FORMULA_', s, '=', trim(sformula(s))
write(*,'(A,I1,A,A)') 'REGION_', s, '=', trim(sregion(s))
write(*,'(A,I1,A,ES15.8)') 'PROBE_', s, '=', probe_mag(s)
if (probe_stable(s)) then
write(*,'(A,I1,A)') 'STABLE_', s, '=YES'
else
write(*,'(A,I1,A)') 'STABLE_', s, '=NO'
end if
! --- Contour data ---
write(*,'(A,I1,A)') 'CONTOUR_', s, '_START'
select case (s)
case (1) ! Forward Euler: unit circle centered at (-1, 0)
do i = 0, npts
angle = real(i, dp) * dangle
x = -1.0_dp + cos(angle)
y = sin(angle)
write(*,'(F12.8,A,F12.8)') x, ',', y
end do
case (2) ! Backward Euler: unit circle centered at (1, 0) โ boundary
do i = 0, npts
angle = real(i, dp) * dangle
x = 1.0_dp + cos(angle)
y = sin(angle)
write(*,'(F12.8,A,F12.8)') x, ',', y
end do
case (3) ! Crank-Nicolson: imaginary axis x = 0
do i = 0, npts
y = -4.0_dp + 8.0_dp * real(i, dp) / real(npts, dp)
write(*,'(F12.8,A,F12.8)') 0.0_dp, ',', y
end do
case (4) ! Leapfrog: segment on imaginary axis from -i to i
do i = 0, npts
y = -1.0_dp + 2.0_dp * real(i, dp) / real(npts, dp)
write(*,'(F12.8,A,F12.8)') 0.0_dp, ',', y
end do
case (5, 6) ! RK2 or RK4: numerical boundary via bisection sweep
! Sweep angle from center, find |G|=1 boundary by bisection
cx = -1.0_dp
cy = 0.0_dp
do i = 0, npts
angle = real(i, dp) * dangle
! Bisection: find r such that |G(center + r*e^{i*angle})| = 1
r_lo = 0.0_dp
r_hi = 5.0_dp ! generous upper bound
! First check if boundary exists along this ray
x = cx + r_hi * cos(angle)
y = cy + r_hi * sin(angle)
gm = abs(eval_G(s, cmplx(x, y, dp)))
if (gm <= 1.0_dp) then
! Entire ray is stable up to r_hi, write the outer point
write(*,'(F12.8,A,F12.8)') x, ',', y
cycle
end if
! Bisection
call bisect_boundary(s, cx, cy, angle, r_lo, r_hi, r_mid)
x = cx + r_mid * cos(angle)
y = cy + r_mid * sin(angle)
write(*,'(F12.8,A,F12.8)') x, ',', y
end do
end select
write(*,'(A,I1,A)') 'CONTOUR_', s, '_END'
end do
contains
!------------------------------------------------------------------------
! Evaluate G(z) for scheme s
!------------------------------------------------------------------------
function eval_G(s, z) result(gz)
integer, intent(in) :: s
complex(dp), intent(in) :: z
complex(dp) :: gz, g1, g2, disc
select case (s)
case (1) ! Forward Euler
gz = cmplx(1.0_dp, 0.0_dp, dp) + z
case (2) ! Backward Euler
gz = cmplx(1.0_dp, 0.0_dp, dp) / (cmplx(1.0_dp, 0.0_dp, dp) - z)
case (3) ! Crank-Nicolson
gz = (cmplx(2.0_dp, 0.0_dp, dp) + z) / (cmplx(2.0_dp, 0.0_dp, dp) - z)
case (4) ! Leapfrog: two roots, return max |G|
disc = z*z + cmplx(1.0_dp, 0.0_dp, dp)
disc = sqrt(disc)
g1 = z + disc
g2 = z - disc
if (abs(g1) >= abs(g2)) then
gz = g1
else
gz = g2
end if
case (5) ! RK2
gz = cmplx(1.0_dp,0.0_dp,dp) + z + z*z/cmplx(2.0_dp,0.0_dp,dp)
case (6) ! RK4
gz = cmplx(1.0_dp,0.0_dp,dp) + z &
+ z*z / cmplx(2.0_dp,0.0_dp,dp) &
+ z*z*z / cmplx(6.0_dp,0.0_dp,dp) &
+ z*z*z*z / cmplx(24.0_dp,0.0_dp,dp)
case default
gz = cmplx(0.0_dp, 0.0_dp, dp)
end select
end function eval_G
!------------------------------------------------------------------------
! Bisection: find radius r from (cx,cy) at angle where |G| crosses 1
!------------------------------------------------------------------------
subroutine bisect_boundary(s, cx, cy, angle, r_lo_in, r_hi_in, r_out)
integer, intent(in) :: s
real(dp), intent(in) :: cx, cy, angle, r_lo_in, r_hi_in
real(dp), intent(out) :: r_out
real(dp) :: rlo, rhi, rmid, xm, ym, gm
complex(dp) :: zm
integer :: iter
rlo = r_lo_in
rhi = r_hi_in
do iter = 1, MAX_BISECT
rmid = 0.5_dp * (rlo + rhi)
xm = cx + rmid * cos(angle)
ym = cy + rmid * sin(angle)
zm = cmplx(xm, ym, dp)
gm = abs(eval_G(s, zm))
if (gm <= 1.0_dp) then
rlo = rmid
else
rhi = rmid
end if
if (abs(rhi - rlo) < 1.0e-12_dp) exit
end do
r_out = 0.5_dp * (rlo + rhi)
end subroutine bisect_boundary
end program stability_regions
Solver Description
Visualize stability regions in the complex plane for popular ODE integrators (Runge-Kutta, Euler, etc.).
Key Numerical Methods & Architecture
- Input Redirection: Reads parameters sequentially from standard input (`stdin`) using Fortran sequential read (`read(*,*)`), ensuring modular integration.
- Modular Design: Formulated using pure mathematical routines, separation of equations from output formatting, and precise numerical solvers (e.g. bisection, Newton-Raphson).
- Standard Compliant: Written in clean, standards-compliant Fortran 90 to ensure cross-compiler compatibility.
๐ ๏ธ Local Compilation
To test this code on your machine, compile the source code file(s) using a standard Fortran compiler (e.g., `gfortran`).
Compilation Command:
gfortran -O3 stability_regions.f90 -o stability_regions
Execution Command:
Execute the program by feeding the sample input file into the program using stdin redirection:
stability_regions < input.txt
๐ฅ Downloads & Local Files
Preview of the required input file (input.txt):
! Number of points\nReal part of z (lambda*dt)\nImaginary part of z (lambda*dt)
400
! Parameter 2
-0.5
! Parameter 3
0.5
400
! Parameter 2
-0.5
! Parameter 3
0.5