![]() | ![]() | ![]() | 6 Algorithm for numerical solution of flat-bottom Riemann problem by different finite volume methods of Godunov type | Contents | Index |
program godunov c----67-------------------------------------------------------flowtec-| c solves the flat-bottom st.venant equations numerically in c one dimension (dam-break problem) by a finite-volume c method using: c ischeme fluxes c 1 godunov (exact riemann solver) c 3 roe (lin. riemann solver, flux-diff-split) c 2 gallouet (lin. riemann solver, var-diff-split) c----67-------------------------------------------------------flowtec-| c 12.05.99 c BUGS: -?- c----67---------------------------------------------------------------| implicit double precision (a-h,o-z) parameter(nmax=400,g=2.d0) dimension q(nmax,2),rhs(nmax,2),flux(2) parameter(cfl=.4d0) c----67---------------------------------------------------------------| parameter(hll=1.d0,ull=0.d0,hrr=5.d-1,urr=0.d0) parameter(flx=1.d0,tfin=.1d0,nitmx=50000) parameter(ischeme=3) c----67---------------------------------------------------------------| time=0.d0 nit=0 dx=flx/dfloat(nmax) do i=1,nmax rhs(i,1)=0.d0 rhs(i,2)=0.d0 enddo c /* set the initial state (diaphragm at center)*/ do i=1,nmax/2 q(i,1)=hll q(i,2)=ull*hll enddo do i=nmax/2+1,nmax q(i,1)=hrr q(i,2)=urr*hrr enddo c /* main time loop */ 11 continue nit=nit+1 dt=1.d35 c /* flux balance for each cell-interface */ do 20 icell=1,nmax-1 c /* solve interfacial riemann problem analytically */ if(ischeme.eq.1)then call riemann(q(icell,1),q(icell,2)/q(icell,1), $ q(icell+1,1),q(icell+1,2)/q(icell+1,1), $ g, $ fhc,uc,flamx) elseif(ischeme.eq.2)then call gallouet(q(icell,1),q(icell,2), $ q(icell+1,1),q(icell+1,2), $ g, $ fhc,uc,flamx) elseif(ischeme.eq.3)then call roeflux(q(icell,1),q(icell,2), $ q(icell+1,1),q(icell+1,2), $ g, $ flux,flamx) else write(*,*)'small problem here...',ischeme endif c /* calculate maximum GLOBAL time step */ dt=dmin1(dt,dx*cfl/flamx) if(dt.eq.0.d0.or.flamx.eq.0.d0)then write(*,*)'icell =',icell,dx,cfl,flamx stop endif c /* accumulate rhs fluxes */ if (ischeme.eq.1.or.ischeme.eq.2)then do ic=1,2 add=dflux(fhc,uc,g,ic) rhs(icell,ic)=rhs(icell,ic)+add rhs(icell+1,ic)=rhs(icell+1,ic)-add enddo else do ic=1,2 rhs(icell,ic)=rhs(icell,ic)+flux(ic) rhs(icell+1,ic)=rhs(icell+1,ic)-flux(ic) enddo endif 20 continue time=time+dt write(*,*)'time = ',time, ' dt= ',dt, ' tfin = ',tfin if(time.gt.tfin.or.nit.gt.nitmx)then call output(q,time,flx,nmax,g) goto 10 endif c /* update the variables */ do ival=2,nmax-1 do ic=1,2 q(ival,ic)=q(ival,ic)-dt/dx*rhs(ival,ic) rhs(ival,ic)=0.d0 enddo enddo c /* check for non-physical values */ do i=1,nmax if(q(i,1).lt.0d0)then WRITE(*,*)'negative height: ',i,q(i,1),q(i,2) stop endif enddo goto 11 10 continue stop end c----67-------------------------------------------------------flowtec-| subroutine output(q,time,flx,ni,g) implicit double precision (a-h,o-z) dimension q(ni,2) open(12,file='sol.dat') write(12,100)time,ni do i=1,ni write(12,*)dfloat(i-1)/dfloat(ni-1)*flx, $ q(i,1),q(i,2)/q(i,1),q(i,2),sqrt(g*q(i,1)) enddo close(12) 100 format('# 1:x 2:h 3:u 4:h*u 5:c') return end c----67-------------------------------------------------------flowtec-| subroutine riemann(fhl,ul,fhr,ur,g,fhc,uc,flamx) c----67-------------------------------------------------------flowtec-| c solves the riemann problem for st.venant equations (flat bottom) c analytically by considering the following zones: c (e.g. for a rarefaction-shock configuration) c c (L) (1) (C) (2) (R) c ------ c \\\\\\ ---------- c \\\\\ | c \\\\ | c \\\ | ^ state q c \\ | | c \ | | c --------------------- -----> (x/t) c----67---------------------------------------------------------------| c 12.02.99 c BUGS: -?- c----67---------------------------------------------------------------| implicit double precision (a-h,o-z) logical lvacuum,l1simple,l2simple,lldry,lrdry parameter (f23=2.d0/3.d0,f13=1.d0/3.d0,f19=1.d0/9.d0) c----67---------------------------------------------------------------| c parameter (g=2.,time=1.d0,x0=2.5d0) parameter (nnwtmx=20,small=1.d-6,width=1.2d0) c----67---------------------------------------------------------------| lrdry=.FALSE. lldry=.FALSE. cL=dsqrt(g*fhL) cR=dsqrt(g*fhR) if(fhl.ne.0.d0)then if(fhR.eq.0.d0)then c write(*,*)'dry bed on the right' lrdry=.TRUE. endif B=fhR/fhL C=(uR-uL)/cL else c write(*,*)'dry bed on the left' lldry=.TRUE. B=0.d0 C=0.d0 endif c /* check for equal states on left and right */ if(fhr.eq.fhl.and.ur.eq.ul)then fhc=fhr uc=ur flamx=dmax1(dabs(ur+sqrt(g*fhr)),dabs(ur-sqrt(g*fhr)), $ dabs(ul+sqrt(g*fhl)),dabs(ul-sqrt(g*fhl))) goto 112 endif c /* check for vacuum (i.e. dry bed) */ lvacuum=.FALSE. if(2.d0*(1.d0+dsqrt(B)).le.C)lvacuum=.TRUE. c write(*,*)'appearance of vacuum:',lvacuum c if(lvacuum)write(*,*)'will set velocity arbitrarily to zero' c /* check of which type are the 1- and 2-families */ l1simple=.FALSE. l2simple=.FALSE. if(B.gt.0.d0) $ check1=f1(dlog(B))*dsqrt(B) if(check1.lt.C.or.lrdry)l1simple=.TRUE. if(B.gt.0.d0) $ check2=f1(-dlog(b)) if(check2.lt.C.or.lldry)l2simple=.TRUE. c write(*,*)fhl,ul,fhr,ur c write(*,*)'1-family:' c if(l1simple)write(*,*)'simple wave' c if(.not.l1simple.and..not.lldry)write(*,*)'shock' c write(*,*)'2-family:' c if(l2simple)write(*,*)'simple wave' c if(.not.l2simple.and..not.lrdry)write(*,*)'shock' c /* solve the 1-family */ if(l1simple)then if(lvacuum.or.lrdry)then fhC=0.d0 uc=0.d0 else x1=-2.d0*dlog((1.d0+dsqrt(B))/2.-C/4.d0) fhC=fhL*dexp(-x1) CC=dsqrt(g*fhc) uC=uL+cL*2.d0*(1.d0-dexp(-x1/2.d0)) c write(*,*)'1-rarefaction: hC=',fhC,' uC=',uC endif else if(l2simple)then if(lvacuum.or.lldry)then fhC=0.d0 uc=0.d0 else x2=-2.d0*dlog(-C/(dsqrt(B)*4.d0)+1.d0/(2.d0*dsqrt(B))+ $ .5d0) fhC=fhR*dexp(-x2) CC=dsqrt(g*fhc) uC=uR-cC*2.d0*(dexp(x2/2.d0)-1.d0) c write(*,*)'2-rarefaction: hC=',fhC,' uC=',uC endif else c /* we have in fact two shocks: need to iterate */ z1=1.1d0 do n=1,nnwtmx zold=z1 z1=zold-funcz1(zold,B,C)/dfuncz1(zold,B) if(dabs(z1-zold).le.small)goto 111 enddo write(*,*)'newton iteration not converged',z1,zold stop 111 continue fhC=z1*fhL cc=dsqrt(fhc*g) uC=uL-cL*(z1-1.d0)*dsqrt((z1+1.d0)/(2.d0*z1)) endif endif c /* we now know about the center state (c) */ c /* calculate limits of zone (1) and (2) */ c /* note: "positions" x** are actually given in "xi/t",i.e. velocities */ if(l1simple)then xL1=uL-cL if(.not.lvacuum.and..not.lrdry)then x1C=uC-cC else c /* limit zone (1) such that vacuum is just reached through */ c /* the expansion */ x1C=uL+2.d0*cL endif else c /* find shock position: calc shock speed from jump cond. */ c /* note: in this case, the zone has zero width */ if(.not.lldry)then z=fhC/fhL c write(*,*)'1-shock: hL/hC=',z if(dabs(z-1.d0).gt.small)then sigma=(uC*z-uL)/(z-1.d0) else sigma=ul-sqrt(g*fhl) endif xl1=sigma x1C=sigma else c /* leave this bound undefined */ endif endif if(l2simple)then x2R=uR+cR if(.not.lvacuum.and..not.lldry)then xC2=uC+cC else xC2=uR-2.d0*cR endif else if(.not.lrdry)then z=fhR/fhC c write(*,*)'2-shock: hR/hC=',z if(dabs(z-1.d0).gt.small)then sigma=(uR*z-uC)/(z-1.d0) else sigma=ur+sqrt(g*fhr) endif x2R=sigma xC2=sigma else c /* since nothing happens in the dry zone, extend it a bit from (1)(C) */ x2R=x1C+dabs(.1d0*x1c) xC2=x2R endif endif c /* get back to the case of a dry bed on the left */ if(lldry)then x1C=xC2-dabs(.1d0*xC2) xl1=x1c endif c /* compute maximum wave speed from limiting velocities xL1,x2R */ flamx=dmax1(dabs(xL1),dabs(x2R)) c /* finalize */ 112 continue return end c----67-------------------------------------------------------flowtec-| subroutine gallouet(fhl,ql,fhr,qr,g,fhc,uc,flamx) c----67-------------------------------------------------------flowtec-| c solves the riemann problem for st.venant equations (flat bottom) c in its linearized form, cf Buffard, Gallouet, Herard, CRAcadSci, c t.326,Serie I,p.385-390, 1998 c----67---------------------------------------------------------------| c 12.02.99 c BUGS: -?- c----67---------------------------------------------------------------| implicit double precision (a-h,o-z) logical lvacuum parameter (f23=2.d0/3.d0,f13=1.d0/3.d0,f19=1.d0/9.d0) parameter (small=1.d-6) c----67---------------------------------------------------------------| if(fhl.ne.0.d0)then ul=ql/fhl else ul=0.d0 endif if(fhr.ne.0.d0)then ur=qr/fhr else ur=0.d0 endif cl=dsqrt(g*fhl) cr=dsqrt(g*fhr) um=(ul+ur)/2.d0 fhm=(fhr+fhl)/2.d0 cm=(cl+cr)/2.d0 c /* check for existence of dry bottom */ if((ul-ur).ge.2.d0*(cl+cr))then lvacuum=.true. uc=0.d0 cc=0.d0 flamx=small goto 111 endif c /* intermediate state in non-vacuum case */ uc=(um-(cr-cl)) cc=(cr+cl)/4.d0*(2.d0-(ur-ul)/(cr+cl)) flamx=dmax1(dabs(um+cm),dabs(um-cm)) 111 continue fhc=cc*cc/g c return end c----67---------------------------------------------------------------| subroutine roeflux(fhl,ul,fhr,ur,g,rflux,flamx) c----67-------------------------------------------------------flowtec-| c solves the linearized riemann problem for st.venant equations c (flat bottom) by using Roe's method (J.Comp.Physics, vol.43,1981) c * fluxes are passed upon exit in vector rflux(1:2) c----67---------------------------------------------------------------| c 21.05.99 c BUGS: -?- c----67---------------------------------------------------------------| implicit double precision (a-h,o-z) dimension a(2,2),cflux(2),uflux(2),diffv(2),rflux(2) logical lvacuum parameter (f23=2.d0/3.d0,f13=1.d0/3.d0,f19=1.d0/9.d0) parameter (small=1.d-6) c----67---------------------------------------------------------------| cl=dsqrt(g*fhl) cr=dsqrt(g*fhr) c /* roe's average for shallow water */ fhc=(fhl+fhr)/2.d0 uc=(dsqrt(fhr)*ur+dsqrt(fhl)*ul)/(dsqrt(fhr)+dsqrt(fhl)) cc=dsqrt(g*fhc) c /* diagonalization |A|=R*|lambda|*R1 */ call aroe(fhc,uc,cc,a) c /* variable difference vector */ diffv(1)=fhr-fhl diffv(2)=fhr*ur-fhl*ul c /* centered flux */ do i=1,2 cflux(i)=dflux(fhr,ur,g,i)+dflux(fhl,ul,g,i) enddo c /* evaluate roe's flux: f=(fl+fr-|a|*(qr-ql))/2 */ do i=1,2 rflux(i)=cflux(i) do j=1,2 rflux(i)=rflux(i)-a(i,j)*diffv(j) enddo rflux(i)=rflux(i)/2.d0 enddo c /* estimate the maximum signal velocity */ flamx=dmax1(dabs(uc+cc),dabs(uc-cc)) c return end c----67---------------------------------------------------------------| subroutine aroe(hc,uc,cc,a) c----67-------------------------------------------------------flowtec-| c calculates roe's matrix c----67---------------------------------------------------------------| implicit double precision (a-h,o-z) dimension a(2,2),r(2,2),r1(2,2),flambda(2) c----67---------------------------------------------------------------| c /* diagonalization matrix r */ r(1,1)=1.d0 r(1,2)=1.d0 r(2,1)=uc-cc r(2,2)=uc+cc c /* inverse r1 */ r1(1,1)=(uc+cc)/(2.d0*cc) r1(1,2)=-1.d0/(2.d0*cc) r1(2,1)=(cc-uc)/(2.d0*cc) r1(2,2)=1.d0/(2.d0*cc) c /* eigenvalues */ flambda(1)=uc-cc flambda(2)=uc+cc c /* matrix*diag*matrix multiply */ do i=1,2 do j=1,2 a(i,j)=0.d0 do k=1,2 a(i,j)=a(i,j)+r(i,k)*dabs(flambda(k))*r1(k,j) enddo enddo enddo c return end c----67---------------------------------------------------------------| double precision function f1(x) implicit double precision (a-h,o-z) c if(x.lt.0.d0)then f1=-(dexp(-x)-1.d0)*dsqrt((dexp(-x)+1)/(2.d0*dexp(-x))) elseif(x.gt.0.d0)then f1=2.d0*(1.d0-dexp(-x/2.d0)) else f1=0.d0 endif end c----67---------------------------------------------------------------| double precision function f2(x) implicit double precision (a-h,o-z) c if(x.lt.0.d0)then f2=(dexp(x)-1.d0)*dsqrt((dexp(x)+1.d0)/(2.d0*dexp(x))) elseif(x.gt.0.d0)then f2=2.d0*(dexp(x/2.d0)-1.d0) else f2=0.d0 endif end c----67---------------------------------------------------------------| double precision function funcz1(z,B,C) implicit double precision (a-h,o-z) c funcz1= -(z-1.D0)*dsqrt(2.D0)*dsqrt((z+1.D0)/z)/2.D0- $ (z/B-1.D0)*dsqrt(2.D0)*dsqrt((z/B+1.D0)/z*B)* $ dsqrt(B)/2.D0-C c end c----67---------------------------------------------------------------| double precision function dfuncz1(z,B) implicit double precision (a-h,o-z) c dfuncz1= -dsqrt(2.D0)*dsqrt((z+1.D0)/z)/2.D0- $ (z-1.D0)*dsqrt(2.D0)/dsqrt((z+1.D0)/z)* $ (1.D0/z-(z+1.D0)/z**2)/4.D0-1.D0/dsqrt(B)* $ dsqrt(2.D0)*dsqrt((z/B+1.D0)/z*B)/2.D0- $ (z/B-1.D0)*dsqrt(2.D0)/dsqrt((z/B+1.D0)/z*B)* $ dsqrt(B)*(1.D0/z-(z/B+1.D0)/z**2*B)/4.D0 c end c----67---------------------------------------------------------------| double precision function dflux(h,u,g,i) implicit double precision (a-h,o-z) c if (i.eq.1)then dflux=h*u elseif(i.eq.2)then dflux=u*u*h+g*h*h/2.d0 else write(*,*)'problem here:..',i stop endif c end c----67---------------------------------------------------------------|
markus.uhlmann AT ciemat.es
![]() | ![]() | ![]() | 6 Algorithm for numerical solution of flat-bottom Riemann problem by different finite volume methods of Godunov type | Contents | Index |