c=========================================================== c Solves 1-dimensional wave equation c c u_tt = u_xx 0 <= x <= 1 u(0,t) = u(1,t) = 0 c c using second-order finite difference techniques. c=========================================================== program wave1d implicit none integer iargc, i4arg real*8 r8arg integer maxn parameter ( maxn = 2**15 + 1 ) c----------------------------------------------------------- c Storage for grid functions: c c u(maxn,2) Difference solution (two time levels) c lm(maxn,3) Initial left-moving profile (lm(1:n,1)) c and first (lm(1:n,2)) and second c (lm(1:n,3)) derivatives. c rm(maxn,3) Initial right-moving profile (rm(1:n,1)) c and first (rm(1:n,2)) and second c (rm(1:n,3)) derivatives. c x(maxn) Difference mesh c----------------------------------------------------------- real*8 u(maxn,2), lm(maxn,3), rm(maxn,3), & x(maxn) c----------------------------------------------------------- c Command-line arguments c----------------------------------------------------------- integer level, ncross, olevel real*8 lambda, alm, arm c----------------------------------------------------------- c Locals. Note the use of the integers 'n', 'np1' c and 'nm1' as "pointers"---indices for the second c dimension (time level) of u. 'np1' and 'nm1' c will always have the same value (1 or 2); in effect c "aliasing" the n + 1 and n - 1 storage. 'n' will c always have the complementary value (2 or 1). c Time step advancement can then be effected (with c no copying of data) by simply "swapping" the 'n' and c 'np1/nm1' values. c----------------------------------------------------------- integer nt, nx, & n, np1, nm1, & j, it, ofreq real*8 dx, dt, lamsq, & t c----------------------------------------------------------- c Argument parsing. c----------------------------------------------------------- if( iargc() .ne. 6 ) go to 900 level = i4arg(1,-1) if( level .lt. 1 ) go to 900 lambda = r8arg(2,-1.0d0) if( lambda .lt. 0.0d0 ) go to 900 ncross = i4arg(3,-1) if( ncross .lt. 1 ) go to 900 alm = r8arg(4,0.5d0) arm = r8arg(5,0.5d0) olevel = i4arg(6,level) if( olevel .gt. level .or. olevel .lt. 1 ) olevel = level ofreq = 2 ** (level - olevel) c----------------------------------------------------------- c Set up finite-difference mesh. c----------------------------------------------------------- nx = 2 ** level + 1 dx = 1.0d0 / (nx - 1) dt = lambda * dx c----------------------------------------------------------- c 'nt' is the total number of time steps, including c the intial time. c----------------------------------------------------------- nt = ncross * (nx - 1) / lambda + 1.5d0 do j = 1 , nx x(j) = (j - 1) * dx end do c----------------------------------------------------------- c Define initial left-moving and right-moving pulses and c derivatives. c----------------------------------------------------------- call dvgaussian(lm(1,1),lm(1,2),lm(1,3),x,nx, & alm,0.5d0,0.1d0) call dvgaussian(rm(1,1),rm(1,2),rm(1,3),x,nx, & arm,0.5d0,0.1d0) c----------------------------------------------------------- c Define t=0, t=dt data. c----------------------------------------------------------- n = 1 np1 = 2 nm1 = 2 u(1,nm1) = 0.0d0 u(1,n ) = 0.0d0 do j = 2 , nx - 1 u(j,nm1) = lm(j,1) + rm(j,1) u(j,n) = u(j,nm1) + dt * (lm(j,2) - rm(j,2)) + & 0.5d0 * dt * dt * (lm(j,3) + rm(j,3)) end do u(nx,nm1) = 0.0d0 u(nx,n ) = 0.0d0 c----------------------------------------------------------- c Output t=0 and (posssibly) t=dt data c----------------------------------------------------------- call gnuout(u(1,nm1),x,nx,0.0d0,ofreq) t = dt if( ofreq .eq. 1 ) then call gnuout(u(1,nm1),x,nx,t,ofreq) end if c----------------------------------------------------------- c Main evolution loop. Note time indexing from 2 to c nt - 1 to ensure that mod(it,ofreq) works properly. c c Alternatively c c do it = 3 , nt c if( mod(it-1,ofreq) ... ) then c----------------------------------------------------------- lamsq = lambda * lambda do it = 2 , nt - 1 do j = 2 , nx - 1 u(j,np1) = 2.0d0 * u(j,n) - u(j,nm1) + lamsq * ( & u(j-1,n) - 2.0d0 * u(j,n) + u(j+1,n) ) end do t = t + dt c----------------------------------------------------------- c 'gnuplot' style output every 'ofreq' steps c----------------------------------------------------------- if( mod(it,ofreq) .eq. 0 ) then call gnuout(u(1,np1),x,nx,t,ofreq) end if c----------------------------------------------------------- c Swap 'pointers'. c----------------------------------------------------------- np1 = n n = nm1 nm1 = np1 end do stop c----------------------------------------------------------- c Usage. c----------------------------------------------------------- 900 continue write(0,*) 'usage: wave1d
'// & ' '// & '' stop end