29) HW3 Solution#
In this assignment we covered some of the topics of the Fortran programming language seen in class, such as some basic I/O.
We revisted an interpolation method seen in class, Lagrange’s interpolation method, and we learned how to use Lagrange’s interpolating formula to approximate a function \(f(x)\) over a domain \([a,b]\).
Remeber: Interpolation \(\neq\) Function Approximation.
But we can use interpolation to accurately approximate continuous functions.
PROGRAM lagrange_program
! this is the main program that will call the subroutine
IMPLICIT NONE
INTERFACE
SUBROUTINE lagrange_interpolation(x_data,y_data,x,y)
REAL, dimension(:),intent(in) :: x_data
REAL, dimension(:),intent(in) :: y_data
REAL, dimension(:),intent(in) :: x
REAL, dimension(:),intent(out) :: y
END SUBROUTINE lagrange_interpolation
END INTERFACE
INTEGER, parameter :: n = 5 ! number of data points
INTEGER, parameter :: s = 50 ! number of domain points for the function approximation
INTEGER :: i
REAL :: x_data(n), y_data(n)
REAL :: x(s), y(s)
OPEN(1, file = 'input_data.txt', ACTION='READ')
WRITE(*,*) 'Reading input data from file' ! this prints out on the screen
do i = 1, n
READ(1,100)x_data(i), y_data(i) ! read the data using the 100 Format specified below
end do
WRITE(*,*) 'Writing input data to screen' ! this prints out on the screen
do i = 1, n
WRITE(*,100)x_data(i), y_data(i) ! write the data using the 100 Format specified below
end do
WRITE(*,*) 'Reading domain data from file' ! this prints out on the screen
OPEN(2, file = 'domain_points.txt', ACTION='READ')
do i = 1, s
READ(2,101)x(i) ! read the data using the 101 Format specified below
end do
CLOSE(1)
CLOSE(2)
CALL flush(1)
CALL flush(2)
y = 0.0 ! initialize the output array
WRITE(*,*) 'Call lagrange_interpolation subroutine' ! this prints out on the screen
CALL lagrange_interpolation(x_data,y_data,x,y)
WRITE(*,*) 'Writing data to output file' ! this prints out on the screen
OPEN(3, file = 'output.txt')
do i = 1, s
WRITE(3,102)y(i) ! write the data using the 102 Format specified below
end do
CLOSE(3)
CALL flush(3)
100 FORMAT(F3.1, F6.3) ! Format specifier for two floating point values: one 3 columns wide, with 1 decimal place, and the other one 6 columns wide (counting from the end of the previous one), with 3 decimal places
101 FORMAT(F19.17) ! Floating point format specifier 19 columns wide, with 17 decimal places
102 FORMAT(F0.17) ! the 0 here means that processor selects the smallest positive field width necessary
END PROGRAM lagrange_program
SUBROUTINE lagrange_interpolation(x_data,y_data,x,p)
! This subroutine interpolates data points x_data=[x1,x2,...xn] and y_data=[f(x1),f(x2),...,f(xn)]
! Defines the Lagrange interpolating polynomial P(x) using Lagrange's interpolating polynomial formula over a domain of x points and
! Returns p = P(x)
IMPLICIT NONE
REAL, dimension(:),intent(in) :: x_data
REAL, dimension(:),intent(in) :: y_data
REAL, dimension(:),intent(in) :: x
REAL, dimension(:),intent(out) :: p
!local variables:
INTEGER :: i,j,n,m
INTEGER, parameter :: s = 50 ! instead of redefining this here, we could have defined in a module and imported it here with the USE statement
REAL :: Li(s)
!check number of points:
n = size(x_data)
m = size(y_data)
if (n/=m) error stop &
'Error: data point vectors must be the same size.'
do i=1,n
Li = 1.0 ! initialize the L variable for the Lagrange interpolant
do j=1,n
if (i/=j) Li = Li * (x-x_data(j)) / (x_data(i)-x_data(j))
end do
p = p + Li*y_data(i)
end do
END SUBROUTINE lagrange_interpolation
Extra Credit Question in Julia#
The Fortran program above produced the appximating polynomial over a domain of 50 equally spaced points. Let’s use Julia to read these values in, plot the original function \(f(x)\), the approximating interpolating polynomial \(p(x)\) and the discrete set of data points \((x_i,y_i)\).
using Plots
using LaTeXStrings
default(linewidth=4, legendfontsize=12)
s = 50
x_domain = LinRange(0,2,s)
p = zeros(length(x_domain))
f(x) = exp.(-3 .* x)
x_data = LinRange(0,2,5)
y_data = f.(x_data)
# open output.txt data and store values in the array called p
open("../fortran_programs/midterm/output.txt","r") do f
line = 1
while ! eof(f)
l = readline(f)
p[line] = parse.(Float64,l)
line += 1
end
end
# Plots
scatter(x_data,y_data, markersize = 6, label = L"(x_i, y_i)")
plot!(x_domain, [f.(x_domain) p ], linestyle = [:solid :dash], label = [" exp(-3x)" "p(x)"], title="Lagrange interpolation")
# to save in png file format, uncomment and use the following line (commented for Jupyter Book execution)
# png(plot!(x_domain, [f.(x_domain) p ], linestyle = [:solid :dash], label = [" exp(-3x)" "p(x)"], title="Lagrange interpolation"), "lagrange_plot.png")