test_diffusion1D.f90 Source File


This file depends on

sourcefile~~test_diffusion1d.f90~~EfferentGraph sourcefile~test_diffusion1d.f90 test_diffusion1D.f90 sourcefile~pdeparabolic.f90 PDEparabolic.f90 sourcefile~test_diffusion1d.f90->sourcefile~pdeparabolic.f90 sourcefile~phys_consts.f90 phys_consts.F90 sourcefile~test_diffusion1d.f90->sourcefile~phys_consts.f90 sourcefile~pdeparabolic.f90->sourcefile~phys_consts.f90 sourcefile~gbsv.f90 gbsv.f90 sourcefile~pdeparabolic.f90->sourcefile~gbsv.f90

Contents

Source Code


Source Code

program test_diffusion1d
!! Need program statement for FORD
!! Solve a time-dependent heat equation in 1D.  See GEMINI-docs repo for
!! a description of the specific problem solved here

use phys_consts, only : wp,pi
use PDEparabolic, only : backEuler1D,TRBDF21D
use h5fortran, only : hdf5_file
implicit none

type(hdf5_file) :: h5f
integer, parameter :: npts=256,lt=20*5
character(*), parameter :: outfile='test_diffusion1d.h5'
character(4) :: ic

real(wp), dimension(npts) :: v1,dx1i
real(wp), dimension(-1:npts+2) :: x1,TsEuler,TsBDF2,Tstrue
real(wp), dimension(npts) :: lambda,A,B,C,D,E
real(wp), dimension(npts+1) :: x1i
real(wp), dimension(0:npts+2) :: dx1
integer :: lx1,it,ix1,ierr
real(wp) :: t=0,dt
real(wp) :: Tsminx1,Tsmaxx1

real(wp), dimension(npts) :: errorEuler,errorBDF2


!! create a grid for the calculation
x1=[ (real(ix1-1,wp)/real(npts-1,wp), ix1=-1,npts+2) ]
lx1=npts   !exclude ghost cells in count
dx1=x1(0:lx1+2)-x1(-1:lx1+1)
x1i(1:lx1+1)=0.5*(x1(0:lx1)+x1(1:lx1+1))
dx1i=x1i(2:lx1+1)-x1i(1:lx1)


!! write the time, space length adn spatial grid to a file
print *,'writing ',outfile
! open(newunit=u,file=outfile,status='replace')
! write(u,*) lt
! write(u,*) lx1
! call writearray(u,x1)
call h5f%initialize(outfile, ierr, status='replace')
call h5f%write('/lt', lt, ierr)
call h5f%write('/lx1', lx1, ierr)
call h5f%write('/x1', x1, ierr)

!! initial conditions
TsEuler(-1:lx1+2)=sin(2.0_wp*pi*x1(-1:lx1+2))+sin(8.0_wp*pi*x1(-1:lx1+2))
TsBDF2=TsEuler
lambda(:)=1.0_wp     !thermal conductivity


!! typical diffusion time, make our time step a fraction of this
dt=0.05*1/8.0_wp**2/pi**2/maxval(lambda)


!! time interations
do it=1,lt
  write(ic, '(I4.4)') it
  !boundary values
  Tsminx1=0.0
  Tsmaxx1=0.0

  !solve using two different numerical schemes
  A(:)=0
  B(:)=0
  C(:)=1
  D(:)=lambda(:)
  E(:)=0.0
  TsEuler(1:lx1)=backEuler1D(TsEuler(1:lx1),A,B,C,D,E,Tsminx1,Tsmaxx1,dt,dx1,dx1i)
  TsBDF2(1:lx1)=TRBDF21D(TsBDF2(1:lx1),A,B,C,D,E,Tsminx1,Tsmaxx1,dt,dx1,dx1i)
  t=t+dt


  !compute analytical solution to compare
  Tstrue(1:lx1) = exp(-4.0_wp*pi**2*lambda*t)*sin(2.0_wp*pi*x1(1:lx1))+exp(-64.0_wp*pi**2*lambda*t)*sin(8.0_wp*pi*x1(1:lx1))


  !! output
  ! write(u,*) t
  ! call writearray(u,TsEuler(1:lx1))
  ! call writearray(u,TsBDF2(1:lx1))
  ! call writearray(u,Tstrue(1:lx1))
  call h5f%write('/t'//ic, t, ierr)
  call h5f%write('/TsEuler'//ic, TsEuler(1:lx1), ierr)
  call h5f%write('/TsBDF2'//ic, TsBDF2(1:lx1), ierr)
  call h5f%write('/TsTrue'//ic, Tstrue(1:lx1), ierr)

  !check the validity of the numerical solutions at this time step
  errorEuler(1:lx1)=TsEuler(1:lx1)-Tstrue(1:lx1)
  errorBDF2(1:lx1)=TsBDF2(1:lx1)-Tstrue(1:lx1)
  if (mod(it,5) == 0) then
    print*, 'At time step:  ',it,' max error:  ',maxval(abs(errorEuler)),maxval(abs(errorBDF2))
  end if
  if (maxval(abs(errorEuler)) > 0.05_wp) then    !more that 5% error at a point means something really bad happened...
    print*, 'Time step:  ',it,dt
    error stop 'Excessive error (large max diff) in backward Euler solution, check time step maybe???'
  end if
  if (maxval(abs(errorBDF2)) > 0.05_wp) then
    print*, 'Time step:  ',it,dt
    error stop 'Excessive error (large max diff) in backward TRBDF2 solution, check time step maybe???'
  end if
end do

! close(u)
call h5f%finalize(ierr)

contains

! subroutine writearray(u,array)
! integer, intent(in) :: u
! real(wp), dimension(:), intent(in) :: array

! integer :: k

! do k=1,size(array)
!   write(u,*) array(k)
! end do
! end subroutine writearray

!
!  subroutine write2Darray(u,array)
!    integer, intent(in) :: u
!    real(wp), dimension(:,:), intent(in) :: array
!
!    integer :: k1,k2
!
!    do k1=1,size(array,1)
!      write(u,'(f8.0)') (array(k1,k2), k2=1,size(array,2))
!    end do
!  end subroutine write2Darray
!

end program