0

I am studying Numerical Methods for incompressible flows. Part of the tasks is to model the lid-driven cavity problem in 2D using the SIMPLE method.

I have been provided with Fortran code that is working and solved. However, is for a channel flow problem. I was informed that by modifying the boundary conditions I can convert it from channel flow to cavity flow. (by manipulating which walls as velocity etc).

channel visual

I have created a SIMPLE Solver for the Lid Driven Cavity Problem in MATLAB. It is known to work and Validated against Ghia et al.(1982). However when I modify the Fortran code to what I believe to be the correct boundary conditions my results.dat file contains NaN for all values of U and V for all X and Y locations.

lid cavity visual

here is the original Fortran code (in its channel form).

program SIMPLE_TDMA_2D
! variables
! dimensions:
      integer :: iNxCells, iNyCells, iNxNodes, iNyNodes, iNxUNodes, iNyUnodes, & 
                 iNxVNodes,iNyVNodes,iNxPNodes,iNyPNodes, iNxMax, iNyMax
!iterations
      integer :: iMaxIter, i,j,n
!convergence limit
      real :: rConvergence
!residuals
      real :: rURes, rVRes, rPRes, rMaxRes, rCRes
!underrelaxation
      real :: rAlphaP, rAlphaU, rAlphaV, rAlphaC
!Dimensionless numbers
      real :: rReynolds, rPeclet, rInjStart,rInjEnd
!massflow
      real :: rTotFlow, rMRatio, rCInFlow, rCOutFlow
!grid
      real :: rHeight, rWidth, rDX, rDY
! current auxiliary variables
      real :: rPCur, rUCur,rVCur,rCCur
! storage for variables
      real, allocatable, dimension (:,:) :: rU,rV,rP,rC,rDU,rDV,rDP


! read parameters from file
      
      open (unit=1, file="parameters.par",status="old")
      read (1,*) rHeight
      read (1,*) rWidth
      read (1,*) rReynolds
      read (1,*) rPeclet
      read (1,*) rInjStart
      read (1,*) rInjEnd
      read (1,*) iNxCells
      read (1,*) iNyCells
      read (1,*) iMaxIter
      read (1,*) rConvergence
      read (1,*) rAlphaP
      read (1,*) rAlphaU
      read (1,*) rAlphaV
      read (1,*) rAlphaC
      close(1)
! grid cells
      rDx=rWidth/iNxCells
      rDy=rHeight/iNyCells
! grid nodes
      iNxNodes=iNxCells+1
      iNyNodes=iNyCells+1
! nodes for P - control volumes + 2 for BCs
      iNxPNodes=iNxCells+2
      iNyPNodes=iNyCells+2
! nodes for U - control volumes + 1 in X and 2 in Y
      iNxUNodes=iNxCells+1
      iNyUNodes=iNyCells+2
! nodes for V - control volumes + 2 in X and 1 in Y
      iNxVNodes=iNxCells+2
      iNyVNodes=iNyCells+1
!
      iNxMax=iNxCells+2
      iNyMax=iNyCells+2
! allocate memory
! scalar - same control volume as P
      allocate(rU(iNxMax,iNyMax),rV(iNxMax,iNyMax),rP(iNxMax,iNyMax),rC(iNxMax,iNyMax))
      allocate(rDU(iNxMax,iNyMax),rDV(iNxMax,iNyMax),rDP(iNxMax,iNyMax))
! Initialise
      rP=0.
      rU=0.
      rV=0.
      rC=0.
      rMaxRes=10.e+3
      n=1
! start time loop
      do while(n.le.iMaxIter.and.rMaxRes.gt.rConvergence)
! compute u-momentum equation
       call UMomentum(iNxUNodes, iNyUNodes,iNxMax,iNyMax,rDx,rDy,rU,rV,rP,rDU,rAlphaU,rURes,rReynolds)
! compute v-momentum equation
       call VMomentum(iNxVNodes, iNyVNodes,iNxMax,iNyMax,rDx,rDy,rU,rV,rP,rDV,rAlphaV,rVRes,rReynolds)
! correct mass flux
       rTotFlow=0.
       do j = 2 , iNyUNodes-1
          rTotFlow=rTotFlow+rDY*rU(iNxUNodes,j)  
       end do
       if(rTotFlow.gt.0.0) then
            rMRatio=rHeight/rTotFlow
         else
            rMRatio=1.0
         end if
       do j = 2 , iNyUNodes-1
          rU(iNxUNodes,j)=rU(iNxUNodes,j)*rMRatio
       end do
! check scalar flux
       rCOutFlow=0.
       do j = 2 , iNyUNodes-1
          rCOutFlow=rCOutFlow+rDY*rC(iNxUNodes,j)  
       end do
! check scalar flux
       rCInFlow=0.
       do j = 2 , iNyUNodes-1
          rCInFlow=rCInFlow+rDY*rC(2,j)  
       end do
!       print *, "Scalar: ", rCInFlow,rCOutFlow
! compute pressure correction
       call PCorrection(iNxPNodes, iNyPNodes,iNxMax,iNyMax,rDx,rDy,rU,rV,rDU,rDV,rDP,rPRes)
! correct velocities 
       do i=2,iNxUNodes-1
        do j=2,iNyUNodes-1
          rU(i,j)=rU(i,j)-rDU(i,j)*(rDP(i+1,j)-rDP(i,j))
        end do
       end do
       do i=2,iNxVNodes-1
        do j=2,iNyVNodes-1
          rV(i,j)=rV(i,j)-rDV(i,j)*(rDP(i,j+1)-rDP(i,j))
        end do
       end do
! correct pressure
       rP=rP+rAlphaP*rDP
! scale pressure
       rP=rP-rP(2,2)
! Solve the scalar equation for corrected flow field:
       call Scalar(iNxPNodes, iNyPNodes,iNxMax,iNyMax,rDx,rDy,rU,rV,rC,rAlphaC,rCRes,rPeclet,rInjStart,rInjEnd)
! maximum residual
       rMaxRes=max(rURes,rVRes,rPRes,rCRes)
       write(*,"(2X,I4,2X,5(2X,E10.3))") n,rURes,rVRes,rPRes,rCRes,rP(2,2)
! advance iterations
       n=n+1
      end do
! check convergence3
      if(rMaxRes.gt.rConvergence) then 
       write(*,*) "Stat: Convergence not reached. Exiting..."
      else
       write(*,*) "Stat: Converged."
      end if
!output tecplot file:
      open (unit=1,file="resultn.dat",status="replace",action="write")
      write(1,*) 'Variables="X","Y","P","U","V", "Scalar"'
      write(1,'("ZONE DATAPACKING=POINT, I=",I4,", J=",I4)') iNxNodes,iNyNodes
      do j=1,iNyNodes
       do i=1,iNxNodes
         rPCur=0.25*(rP(i,j)+rP(i+1,j)+rP(i,j+1)+rP(i+1,j+1))
         rCCur=0.25*(rC(i,j)+rC(i+1,j)+rC(i,j+1)+rC(i+1,j+1))
         rUCur=0.5 *(rU(i,j)+rU(i,j+1))
         rVCur=0.5 *(rV(i,j)+rV(i+1,j))
         write(1,"(8E15.7)") (i-1)*rDX,(j-1)*rDY,rPCur,rUCur,rVCur,rCCur
       end do
      end do
      close(1)
end program SIMPLE_TDMA_2D


subroutine UMomentum(iNxUNodes, iNyUNodes,iNxMax,iNyMax,rDx,rDy,rU,rV,rP,rDU,rAlphaU,rURes,rReynolds)
!arguments
    integer, intent(in) :: iNxUNodes, iNyUNodes,iNxMax,iNyMax
    real, intent(in)    :: rDx,rDy, rAlphaU,rReynolds
    real, intent(inout) :: rURes
    real, dimension (iNxMax, iNyMax), intent (in) :: rV,rP
    real, dimension (iNxMax, iNyMax), intent (inout) :: rU,rDU
! local variables
    real ::  de, dw, dn, ds, ge, gw, gn, gs,rTemp
    real, dimension(iNxMax,iNyMax) ::aw,ae,as,an,ap,su
    integer :: i,j

! set boundary conditions for coefficients in the equations
! south
    aw(:,1)=0.
    ae(:,1)=0.
    as(:,1)=0.
    an(:,1)=0.
    ap(:,1)=1.
    su(:,1)=0.
! west
    aw(1,:)=0.
    ae(1,:)=0.
    as(1,:)=0.
    an(1,:)=0.
    ap(1,:)=1.
    su(1,:)=1.
! north
    aw(:,iNyUNodes)=0.
    ae(:,iNyUNodes)=0.
    as(:,iNyUNodes)=0.
    an(:,iNyUNodes)=0.
    ap(:,iNyUNodes)=1.
    su(:,iNyUNodes)=0.
! east
    aw(iNxUNodes,:)=1.
    ae(iNxUNodes,:)=0.
    as(iNxUNodes,:)=0.
    an(iNxUNodes,:)=0.
    ap(iNxUNodes,:)=1.
    su(iNxUNodes,:)=0.
! set the coefficeints in the interior staggered cells

      do i = 2 , iNxUNodes-1
         do J = 2 , iNyUNodes-1
            dw = rDY/(rDX*rReynolds)
            gw = rDY*(rU(i-1, j) + rU(i, j)) / 2.
            de = rDY/(rDX*rReynolds)
            ge = rDY*(rU(i, j) + rU(i+1, j)) / 2.
            if ( j .eq. 2 ) then
               ds = 2.*rDX/(rDY*rReynolds)
               gs = 0.0
            else
               ds = rDX/(rDY*rReynolds)
               gs = rDX*(rV(i, j-1) + rV(i+1, j-1)) / 2.
            end if 
            if ( j .eq. (iNyUNodes - 1)) then   
               dn = 2.*rDX/(rDY*rReynolds)
               gn = 0.0
            else   
               dn = rDX/(rDY*rReynolds)
               gn = rDX*(rV(i, j) + rV(i+1, j)) / 2.
            end if
            aw(i, j) = dw + max( 0.0 ,  gw)
            ae(i, j) = de + max( 0.0 , -ge)
            as(i, j) = ds + max( 0.0 ,  gs)
            an(i, j) = dn + max( 0.0 , -gn)
            ap(i, j) = dw+de+ds+dn+max( 0.0 ,  -gw) + max( 0.0 , ge) +max( 0.0 ,  -gs)+max( 0.0 ,  gn)
            su(i, j) = -(rP(i+1, j) - rP(i, j))*rDY
         end do
      end do


! evaluate the residual in the interior
      rURes=0.
      do i = 2 , iNxUNodes - 1
         do j = 2 , iNyUNodes - 1 
           rTemp = abs( ap(i, j)*rU(i, j) & 
                      - ae(i, j)*rU(i+1, j) - aw(i, j)*rU(i-1, j) &
                      - an(i, j)*rU(i, j+1) - as(i, j)*rU(i, j-1) &
                      - su(i, j))
           if(rTemp.ge.rURes) rURes=rTemp
         end do
      end do
! apply underrelaxation to interior cells
      ap(2:iNxUNodes-1,2:iNyUNodes-1)=ap(2:iNxUNodes-1,2:iNyUNodes-1)/rAlphaU
      su(2:iNxUNodes-1,2:iNyUNodes-1)=su(2:iNxUNodes-1,2:iNyUNodes-1)+ &
         (1.-rAlphaU)*ap(2:iNxUNodes-1,2:iNyUNodes-1)*rU(2:iNxUNodes-1,2:iNyUNodes-1)
! store dU for pressure correction:
      rDU(2:iNxUNodes-1,2:iNyUNodes-1)=rDY/ap(2:iNxUNodes-1,2:iNyUNodes-1)
! solve the tridiagonal systems
!  for each i-direction line
      call tridag_i(as,aw,ap,ae,an,su,rU,iNxUNodes,iNyUNodes,iNxMax,iNyMax)
!  for each j-direction line
      call tridag_j(aw,as,ap,an,ae,su,rU,iNyUNodes,iNxUNodes,iNxMax,iNyMax)

      return 
end subroutine UMomentum



subroutine VMomentum(iNxVNodes, iNyVNodes,iNxMax,iNyMax,rDx,rDy,rU,rV,rP,rDV,rAlphaV,rVRes,rReynolds)
!arguments
    integer, intent(in) :: iNxVNodes, iNyVNodes,iNxMax,iNyMax
    real, intent(in)    :: rDx,rDy, rAlphaV,rReynolds
    real, intent(inout) :: rVRes
    real, dimension (iNxMax, iNyMax), intent (in) :: rU,rP
    real, dimension (iNxMax, iNyMax), intent (inout) :: rV,rDV
! local variables
    real ::  de, dw, dn, ds, ge, gw, gn, gs, rTemp
    real, dimension(iNxMax,iNyMax) ::aw,ae,as,an,ap,su
    integer :: i,j

! set boundary conditions for coefficients in the equations
! south
    aw(:,1)=0.
    ae(:,1)=0.
    as(:,1)=0.
    an(:,1)=0.
    ap(:,1)=1.
    su(:,1)=0.
! west
    aw(1,:)=0.
    ae(1,:)=0.
    as(1,:)=0.
    an(1,:)=0.
    ap(1,:)=1.
    su(1,:)=0.
! north
    aw(:,iNyVNodes)=0.
    ae(:,iNyVNodes)=0.
    as(:,iNyVNodes)=0.
    an(:,iNyVNodes)=0.
    ap(:,iNyVNodes)=1.
    su(:,iNyVNodes)=0.
! east
    aw(iNxVNodes,:)=1.
    ae(iNxVNodes,:)=0.
    as(iNxVNodes,:)=0.
    an(iNxVNodes,:)=0.
    ap(iNxVNodes,:)=1.
    su(iNxVNodes,:)=0.
! set the coefficeints in the interior staggered cells

      do i = 2 , iNxVNodes-1
         do j = 2 , iNyVNodes-1
            if ( i .eq. 2 ) then
             dw = 2.*rDY/(rDX*rReynolds)
             gw = rDY*(rU(i-1, j) + rU(i-1, j+1)) / 2.
            else
             dw = rDY/(rDX*rReynolds)
             gw = rDY*(rU(i-1, j) + rU(i-1, j+1)) / 2.
            end if
            if ( i .eq. (iNxVNodes - 1)) then   
             de = 2.*rDY/(rDX*rReynolds)
             ge = rDY*(rU(i, j) + rU(i, j+1)) / 2.
        else
             de = rDY/(rDX*rReynolds)
             ge = rDY*(rU(i, j) + rU(i, j+1)) / 2.
        end if
            ds = rDX/(rDY*rReynolds)
            gs = rDX*(rV(i, j-1) + rV(i, j)) / 2.
            dn = rDX/(rDY*rReynolds)
            gn = rDX*(rV(i, j) + rV(i, j+1)) / 2.

            aw(i, j) = dw + max( 0.0 ,  gw)
            ae(i, j) = de + max( 0.0 , -ge)
            as(i, j) = ds + max( 0.0 ,  gs)
            an(i, j) = dn + max( 0.0 , -gn)
            ap(i, j) = dw+de+ds+dn+max( 0.0 ,  -gw) + max( 0.0 , ge) +max( 0.0 ,  -gs)+max( 0.0 ,  gn)
            su(i, j) = -(rP(i, j+1) - rP(i, J))*rDX
         end do
      end do
! evaluate the residual in the interior
      rVRes=0.
      do i = 2 , iNxVNodes - 1
         do j = 2 , iNyVNodes - 1 
           rTemp=abs( ap(i, j)*rV(i, j) & 
                    - ae(i, j)*rV(i+1, j) - aw(i, j)*rV(i-1, j) &
                    - an(i, j)*rV(i, j+1) - as(i, j)*rV(i, j-1) &
                    - su(i, j))
           if(rTemp.ge.rVRes) rVRes=rTemp
         end do
      end do

!output tecplot file:
! apply underrelaxation to interior cells
      ap(2:iNxVNodes-1,2:iNyVNodes-1)=ap(2:iNxVNodes-1,2:iNyVNodes-1)/rAlphaV
      su(2:iNxVNodes-1,2:iNyVNodes-1)=su(2:iNxVNodes-1,2:iNyVNodes-1)+ &
        (1.-rAlphaV)*ap(2:iNxVNodes-1,2:iNyVNodes-1)*rV(2:iNxVNodes-1,2:iNyVNodes-1)
! store dV for pressure correction:
      rDV(2:iNxVNodes-1,2:iNyVNodes-1)=rDX/ap(2:iNxVNodes-1,2:iNyVNodes-1)
! solve the tridiagonal systems
!  for each i-direction line
      call tridag_i(as,aw,ap,ae,an,su,rV,iNxVNodes,iNyVNodes,iNxMax,iNyMax)
!  for each j-direction line
      call tridag_j(aw,as,ap,an,ae,su,rV,iNyVNodes,iNxVNodes,iNxMax,iNyMax)
      return 
end subroutine VMomentum

subroutine PCorrection(iNxPNodes,iNyPNodes,iNxMax,iNyMax,rDx,rDy,rU,rV,rDU,rDV,rDP,rPRes)
!arguments
    integer, intent(in) :: iNxPNodes, iNyPNodes,iNxMax,iNyMax
    real, intent(in)    :: rDx,rDy
    real, intent(inout) :: rPRes
    real, dimension (iNxMax, iNyMax), intent (in) :: rU,rV,rDU,rDV
    real, dimension (iNxMax, iNyMax), intent (inout) :: rDP
! local variables
    real, dimension(iNxMax,iNyMax) ::aw,ae,as,an,ap,su
    integer :: i,j
    real :: rTemp

! initalise pressure correction
    rDP=0.
! set boundary conditions for coefficients in the equations
    aw=0.
    ae=0.
    as=0.
    an=0.
    ap=0.
    su=0.
! south
    aw(2:iNxPNodes-1,1)=0.
    ae(2:iNxPNodes-1,1)=0.
    as(2:iNxPNodes-1,1)=0.
    an(2:iNxPNodes-1,1)=1.
    ap(2:iNxPNodes-1,1)=1.
    su(2:iNxPNodes-1,1)=0.
! west
    aw(1,2:iNyPNodes-1)=0.
    ae(1,2:iNyPNodes-1)=1.
    as(1,2:iNyPNodes-1)=0.
    an(1,2:iNyPNodes-1)=0.
    ap(1,2:iNyPNodes-1)=1.
    su(1,2:iNyPNodes-1)=0.
! north
    aw(2:iNxPNodes-1,iNyPNodes)=0.
    ae(2:iNxPNodes-1,iNyPNodes)=0.
    as(2:iNxPNodes-1,iNyPNodes)=1.
    an(2:iNxPNodes-1,iNyPNodes)=0.
    ap(2:iNxPNodes-1,iNyPNodes)=1.
    su(2:iNxPNodes-1,iNyPNodes)=0.
! east
    aw(iNxPNodes,2:iNyPNodes-1)=1.
    ae(iNxPNodes,2:iNyPNodes-1)=0.
    as(iNxPNodes,2:iNyPNodes-1)=0.
    an(iNxPNodes,2:iNyPNodes-1)=0.
    ap(iNxPNodes,2:iNyPNodes-1)=1.
    su(iNxPNodes,2:iNyPNodes-1)=0.
! set the coefficeints in the interior staggered cells

      do j = 2 , iNyPNodes-1
       do i = 2 , iNxPNodes-1
           aw(i, j) = rDY*rDU(i-1, j)
           ae(i, j) = rDY*rDU(i, j)
           as(i, j) = rDX*rDV(i, j-1)
           an(i, j) = rDX*rDV(i, j)            
           ap(i,j)  = aw(i, j)+ae(i, j)+as(i, j)+an(i, j)
           su(i, j) = rDY*(rU(i-1, j)-rU(i, j))+ &
                      rDX*(rV(i, j-1)-rV(i, j))
         end do
      end do
! sweep through the domain repeatedly and solve the algebraic equations in each line
      do i=1,10
        call tridag_i(as,aw,ap,ae,an,su,rDP,iNxPNodes,iNyPNodes,iNxMax,iNyMax)
        call tridag_j(aw,as,ap,an,ae,su,rDP,iNyPNodes,iNxPNodes,iNxMax,iNyMax)
      end do
! compute the pressure residual 
      rPRes=0.
      do j=2,iNyPNodes-1
       do i=2,iNxPNodes-1
        rTemp=abs(su(i,j))
        if(rTemp.ge.rPRes) rPRes=rTemp

       end do
      end do
      return 
end subroutine PCorrection


subroutine Scalar(iNxPNodes, iNyPNodes,iNxMax,iNyMax,rDx,rDy,rU,rV,rC,rAlphaC,rCRes,rPeclet,rInjStart,rInjEnd)
!arguments
    integer, intent(in) :: iNxPNodes, iNyPNodes,iNxMax,iNyMax
    real, intent(in)    :: rDx,rDy, rAlphaC,rPeclet,rInjStart,rInjEnd
    real, intent(inout) :: rCRes
    real, dimension (iNxMax, iNyMax), intent (in) :: rU,rV
    real, dimension (iNxMax, iNyMax), intent (inout) :: rC
! local variables
    real ::  de, dw, dn, ds, ge, gw, gn, gs, rTemp
    real, dimension(iNxMax,iNyMax) ::aw,ae,as,an,ap,su
    integer :: i,j

! set boundary conditions for coefficients in the equations
! south
    aw(:,1)=0.
    ae(:,1)=0.
    as(:,1)=0.
    an(:,1)=1.
    ap(:,1)=1.
    su(:,1)=0.
! west
    aw(1,:)=0.
    ae(1,:)=0.
    as(1,:)=0.
    an(1,:)=0.
    do j=2,iNyPNodes-1
     rTemp=(j-2)*rDY+0.5*rDY
     if (rTemp.ge.rInjStart.and.rTemp.le.rInjEnd) then
      ap(1,j)=1.
      su(1,j)=1.
     else
      ap(1,j)=1.
      su(1,j)=0.
     end if
    end do
! north
    aw(:,iNyPNodes)=0.
    ae(:,iNyPNodes)=0.
    as(:,iNyPNodes)=1.
    an(:,iNyPNodes)=0.
    ap(:,iNyPNodes)=1.
    su(:,iNyPNodes)=0.
! east
    aw(iNxPNodes,:)=1.
    ae(iNxPNodes,:)=0.
    as(iNxPNodes,:)=0.
    an(iNxPNodes,:)=0.
    ap(iNxPNodes,:)=1.
    su(iNxPNodes,:)=0.
! set the coefficeints in the interior staggered cells

      do i = 2 , iNxPNodes-1
         do j = 2 , iNyPNodes-1
          dw = rDY/(rDX*rPeclet)
          gw = rDY*rU(i-1, j)
          de = rDY/(rDX*rPeclet)
          ge = rDY*rU(i, j)
          if (j.eq.2) then
            ds = 0.0
            gs = 0.0
          else
            ds = rDX/(rDY*rPeclet)
            gs = rDX*rV(i, j-1)
          end if 
          if (j.eq.(iNyPNodes-1)) then   
           dn = 0.0
           gn = 0.0
          else   
           dn = rDX/(rDY*rPeclet)
           gn = rDX*rV(i, j)
          end if
           aw(i, j) = dw + max( 0.0 ,  gw)
       ae(i, j) = de + max( 0.0 , -ge)
       as(i, j) = ds + max( 0.0 ,  gs)
       an(i, j) = dn + max( 0.0 , -gn)
       ap(i, j) =  dw+de+ds+dn+max( 0.0 ,  -gw) + max( 0.0 , ge) +max( 0.0 ,  -gs)+max( 0.0 ,  gn)
       su(i, j) = 0.0
         end do
      end do
! evaluate the residual in the interior
      rCRes=0.
      do i = 2 , iNxPNodes - 1
         do j = 2 , iNyPNodes - 1 
           rTemp=abs( ap(i, j)*rC(i, j) & 
                    - ae(i, j)*rC(i+1, j) - aw(i, j)*rC(i-1, j) &
                    - an(i, j)*rC(i, j+1) - as(i, j)*rC(i, j-1) &
                    - su(i, j))
           if(rTemp.ge.rCRes) rCRes=rTemp
         end do
      end do

!output tecplot file:
! apply underrelaxation to interior cells
      ap(2:iNxPNodes-1,2:iNyPNodes-1)=ap(2:iNxPNodes-1,2:iNyPNodes-1)/rAlphaC
      su(2:iNxPNodes-1,2:iNyPNodes-1)=su(2:iNxPNodes-1,2:iNyPNodes-1)+ &
        (1.-rAlphaC)*ap(2:iNxPNodes-1,2:iNyPNodes-1)*rC(2:iNxPNodes-1,2:iNyPNodes-1)
! solve the tridiagonal systems
!  for each i-direction line
      call tridag_i(as,aw,ap,ae,an,su,rC,iNxPNodes,iNyPNodes,iNxMax,iNyMax)
!  for each j-direction linE
      call tridag_j(aw,as,ap,an,ae,su,rC,iNyPNodes,iNxPNodes,iNxMax,iNyMax)
      return 
end subroutine Scalar

!-----------------------------------------------------------------------
!     Tri-diagonal matrix solver (based on Numerical Recipes)  
!
!     Solving i-lines, looping over domain in j-direction
!
!     Note signs of Coefficients 
! note - r - righthand side 
!-----------------------------------------------------------------------
      subroutine tridag_i(d, a, b, c, e, r, u, n, l,iNxMax,iNyMax)
!-----------------------------------------------------------------------
!     Argument type declarations
!-----------------------------------------------------------------------
      integer, intent(in) ::  n, l, iNxMax, iNyMax
      real, dimension(iNxMax,iNyMax) ::     a, b, c,d,e,r,u
!-----------------------------------------------------------------------
!     Local variable type declarations
!-----------------------------------------------------------------------
      integer j, m
      real    bet,gam(n),rhs
!-----------------------------------------------------------------------
!     Loop in j-direction
!-----------------------------------------------------------------------
      do j = 2 , l-1
!-----------------------------------------------------------------------
!     Forward recurrence
!-----------------------------------------------------------------------
         bet  = b(1, j)
         u(1, j) = r(1, j)/bet
         do m = 2 , n
            gam(m) = -c(m-1, j) / bet
            bet    = b(m, j) + a(m, j)*gam(m)
            rhs    = r(m,j) + d(m,j)*u(m,j-1) + e(m,j)*u(m,j+1)
            u(m, j)= (rhs + a(m, j)*u(m-1, j))/bet
         end do
!-----------------------------------------------------------------------
!     Backward recurrence
!-----------------------------------------------------------------------
         do m = n-1, 1, -1
            u(m, j) = u(m, j) - gam(m+1)*u(m+1, j)
         end do
!-----------------------------------------------------------------------
!     Next j line
!-----------------------------------------------------------------------
      end do
!-----------------------------------------------------------------------
!     finished so return
!-----------------------------------------------------------------------
      return
      end



!-----------------------------------------------------------------------
!     Tri-diagonal matrix solver (based on Numerical Recipes)  
!
!     Solving j-lines, looping over domain in i-direction
!
!     Note signs of Coefficients 
! note - r - righthand side 
!-----------------------------------------------------------------------
      subroutine tridag_j(d, a, b, c, e, r, u, n, l,iNxMax,iNyMax)
!-----------------------------------------------------------------------
!     Argument type declarations
!-----------------------------------------------------------------------
      integer, intent(in) ::  l, n,iNxMax,iNyMax
      real, dimension (iNxMax,iNyMax) ::  a,b,c,d,e,r,u

!-----------------------------------------------------------------------
!     Local variable type declarations
!-----------------------------------------------------------------------
      integer i, m
      real    bet,gam(n),rhs
!-----------------------------------------------------------------------
!     Loop in i-diection
!-----------------------------------------------------------------------
      do i = 2, l-1
!
!-----------------------------------------------------------------------
!     Forward recurrence
!-----------------------------------------------------------------------
         bet  = b(i, 1)
         u(i, 1) = r(i, 1)/bet
         do m = 2, n
            gam(m) = -c(i, m-1) / bet
            bet    = b(i, m) + a(i, m)*gam(m)
            rhs    = r(i,m) + d(i,m)*u(i-1,m) + e(i,m)*u(i+1,m)
            u(i, m)= (rhs + a(i, m)*u(i, m-1))/bet
         end do
!-----------------------------------------------------------------------
!     Backward recurrence
!-----------------------------------------------------------------------
         do m = n-1, 1, -1
            u(i, m) = u(i, m) - gam(m+1)*u(i, m+1)
         end do
!-----------------------------------------------------------------------
!     Next i line
!-----------------------------------------------------------------------
      end do
!-----------------------------------------------------------------------
!     finished so return
!-----------------------------------------------------------------------
      return
      end

and parameter file.

1.              ! domain height
1.              ! domain width
300.        ! Reynolds
10.             ! Peclet
0.              ! Injection start
0.              ! Injection end
10          ! cells in X
10          ! cells in Y
5000            ! max iterations
1.e-6       ! convergence criteria
0.6             ! P underrelaxation
0.6     ! U underrelaxation
0.6             ! V underrelaxation
1.              ! Scalar underrelaxation

I believe by modifying the boundary conditions in UMomentum,Vmomentum, Pressure Correction and Scalar I can convert it to a lid driven cavity. as south is a known wall in the channel flow I based my edits on this fact when converting the east and west inlets to walls as such I used these as the correct boundary conditions.

for U Momentum function

! set boundary conditions for coefficients in the equations
! south
    aw(:,1)=0.
    ae(:,1)=0.
    as(:,1)=0.
    an(:,1)=0.
    ap(:,1)=1.
    su(:,1)=0.
! west
    aw(1,:)=0.
    ae(1,:)=0.
    as(1,:)=0.
    an(1,:)=0.
    ap(1,:)=1.
    su(1,:)=0.
! north
    aw(:,iNyUNodes)=0.
    ae(:,iNyUNodes)=0.
    as(:,iNyUNodes)=0.
    an(:,iNyUNodes)=0.
    ap(:,iNyUNodes)=1.
    su(:,iNyUNodes)=1.
! east
    aw(iNxUNodes,:)=0.
    ae(iNxUNodes,:)=0.
    as(iNxUNodes,:)=0.
    an(iNxUNodes,:)=0.
    ap(iNxUNodes,:)=1.
    su(iNxUNodes,:)=0.

as there is no momentum in the Y direction I believe these to be the correct Boundary Conditions for VMomentum Function.

! south
    aw(:,1)=0.
    ae(:,1)=0.
    as(:,1)=0.
    an(:,1)=0.
    ap(:,1)=1.
    su(:,1)=0.
! west
    aw(1,:)=0.
    ae(1,:)=0.
    as(1,:)=0.
    an(1,:)=0.
    ap(1,:)=1.
    su(1,:)=0.
! north
    aw(:,iNyVNodes)=0.
    ae(:,iNyVNodes)=0.
    as(:,iNyVNodes)=0.
    an(:,iNyVNodes)=0.
    ap(:,iNyVNodes)=1.
    su(:,iNyVNodes)=0.
! east
    aw(iNxVNodes,:)=0.
    ae(iNxVNodes,:)=0.
    as(iNxVNodes,:)=0.
    an(iNxVNodes,:)=0.
    ap(iNxVNodes,:)=1.
    su(iNxVNodes,:)=0.

I am unsure how to manipulate the Pressure Corrections and Scalar Function's Boundary Conditions.

and the output of my code is either incorrect values or NaN with different attempts of the boundary conditions

Apologies for this being long, I wanted to be as thorough as possible as I cannot understand what is incorrect.

(it is known that the Fortran solver is validated as accurate, and my MATLAB solver) however these results do not matchup after my boundary edits.

Thanks in advance

Ian Bush
  • 6,996
  • 1
  • 21
  • 27
Xray25
  • 115
  • 13
  • What do you do mathematically? Please explain what the code is supposed to do. This is a coding site rather than a scientific computing site (see https://scicomp.stackexchange.com/ for that). Do you use ghost cells for the boundary conditions or do you modify the stencil at the boundary? How exactly is the subroutine supposed to set them? Staggered or collocated grid? What is the actual meaning of those *a* coefficients? My guess is that you are modifying the stencil and the operator at the boundary and there are no ghost cells but please explain what the code does, this is a programming site. – Vladimir F Героям слава Jan 23 '23 at 13:01
  • The code is probably way too big for anyone to realistically go through it. Try to find out where the NaNs appear. Does the simulation blow up gradually? How does the velocity field change from iteration to iteration? You often get the most important insight from this kind of exploration and visualization. – Vladimir F Героям слава Jan 23 '23 at 13:05
  • Now I see you posted the exact same question on the other site https://scicomp.stackexchange.com/ as well. That is somewhat a poor form. Maybe not completely forbidden, but quite a poor form anyway. If I were you, i would just delete it here. – Vladimir F Героям слава Jan 23 '23 at 13:07
  • Please read https://meta.stackexchange.com/questions/64068/is-cross-posting-a-question-on-multiple-stack-exchange-sites-permitted-if-the-qu – Vladimir F Героям слава Jan 23 '23 at 13:32
  • @Xray25, your code is weird. It ran OK every time with NAG and Intel Compilers, but failed intermittently with gfortran. This suggests (to me) something being used without initialisation. So I initialised rDU, rDV and rDP to 0.0 immediately after allocation, and it ran fine with gfortran every time. But it shouldn't really be necessary to initialise these first as they should be set in PCorrection(); I suspect that not all the required values are being set there. Your modification for lid-driven cavity looks mainly OK, but you clearly won't have to scale the outflow (rMRatio) – lastchance Jan 23 '23 at 15:59
  • @VladimirFГероямслава I appreciate it I only found that exchange today after having posted there i shall do that! – Xray25 Jan 23 '23 at 17:11
  • @lastchance Thank you! What do you mean mainly ok? Where am I lacking in? – Xray25 Jan 23 '23 at 17:12
  • Your changes to UMomentum and VMomentum appear correct to fix the velocity (at 1,0)) on the upper wall. The pressure and scalar boundary conditions are probably the same as the channel flow. However, your channel-flow code does a rescaling of the output conditions (using rMRatio) in the main program to (correctly) ensure global mass conservation in the channel-flow case. That is unnecessary (and wrong) for the lid-driven case. – lastchance Jan 23 '23 at 17:18
  • @lastchance as it’s unnecessary can it simply be removed or do I need to implement something else – Xray25 Jan 23 '23 at 17:23
  • @Xray25 - you can remove the rMRatio rescaling (or, better, comment it out) for the lid-driven cavity case. It is necessary for an inlet-outlet case like channel flow. Make sure that you check those rDU, rDV and rDP initialisations, though - don't rely on compilers automatically setting uninitialised variables to 0. I don't have access to TecPlot at the moment, so can't check your output graphs. – lastchance Jan 23 '23 at 17:28
  • @Xray25 OK, I understand that you found the site recently and since you got some feedback here you probably do not want to delete your question. But still, can you try to answer I asked in my question in my comments? Also, Wolfgang had some question at the other site, quite related to my points. You should try to do some exploration and debugging and I tried to give you some suggestions how that could be done. When i have issues with my CFD code, I always try to look how the fields evolve and where the problem appears. I let my program to print the relevant quantities during the computation. – Vladimir F Героям слава Jan 23 '23 at 18:33
  • @VladimirFГероямслава I will attempt both exploration and Debug and report back with more concise answers – Xray25 Jan 23 '23 at 18:38

0 Answers0