!================================================================================================
!=================================================================================================
! Paris-0.1
!
! Free surface extensions
! written by Leon Malan and Stephane Zaleski
!
! This program is free software; you can redistribute it and/or
! modify it under the terms of the GNU General Public License as
! published by the Free Software Foundation; either version 2 of the
! License, or (at your option) any later version.
!
! This program is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
! General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with this program; if not, write to the Free Software
! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
! 02111-1307, USA.  
!=================================================================================================
!=================================================================================================
!-------------------------------------------------------------------------------------------------
 subroutine set_topology(vof_phase,iout)
  use module_grid
  use module_freesurface
  use module_IO
  use module_BC
  implicit none
  include 'mpif.h' 
  integer, dimension(imin:imax,jmin:jmax,kmin:kmax), intent(in) :: vof_phase
  integer :: req(16),sta(MPI_STATUS_SIZE,16)
  integer :: i,j,k,level,iout,nbr,ierr,no

  !initialize all masks to 3
  if (.not.initialize_fs) call pariserror("Error: Free surface variables not initialized")
  u_cmask = 3; v_cmask = 3; w_cmask = 3; pcmask = 3
  !First loop to set level 0 velocities in liq-liq and liq-gas cells
  do k=ks,ke; do j=js,je; do i=is,ie
     if (vof_phase(i,j,k) == 1) then
        if (vof_phase(i+1,j,k) == 0) then
           u_cmask(i,j,k) = 0
        endif
        if (vof_phase(i,j+1,k) == 0) then
           v_cmask(i,j,k) = 0
        endif
        if (vof_phase(i,j,k+1) == 0) then 
           w_cmask(i,j,k) = 0
        endif
     endif
     if (vof_phase(i,j,k) == 0) then
        pcmask(i,j,k)=0
        u_cmask(i,j,k) = 0
        v_cmask(i,j,k) = 0
        w_cmask(i,j,k) = 0
     endif
  enddo; enddo; enddo
  !fill ghost layers for zero masks
  !call set_topology_bc
  call ighost_x(u_cmask,2,req(1:4)); call ighost_x(v_cmask,2,req(5:8)); call ighost_x(w_cmask,2,req(9:12))
  call ighost_x(pcmask,2,req(13:16)); call MPI_WAITALL(16,req(1:16),sta(:,1:16),ierr)
  call ighost_y(u_cmask,2,req(1:4)); call ighost_y(v_cmask,2,req(5:8)); call ighost_y(w_cmask,2,req(9:12))
  call ighost_y(pcmask,2,req(13:16)); call MPI_WAITALL(16,req(1:16),sta(:,1:16),ierr)
  call ighost_z(u_cmask,2,req(1:4)); call ighost_z(v_cmask,2,req(5:8)); call ighost_z(w_cmask,2,req(9:12))
  call ighost_z(pcmask,2,req(13:16)); call MPI_WAITALL(16,req(1:16),sta(:,1:16),ierr)
  !Set levels 1 to X_level
  do level=1,X_level
     do k=ks,ke; do j=js,je; do i=is,ie
        !u-neighbours
        if (u_cmask(i,j,k)==3) then
           if ((u_cmask(i+1,j,k)==level-1).or.(u_cmask(i-1,j,k)==level-1)&
                .or.(u_cmask(i,j+1,k)==level-1).or.(u_cmask(i,j-1,k)==level-1)&
                .or.(u_cmask(i,j,k+1)==level-1).or.(u_cmask(i,j,k-1)==level-1)) then
           u_cmask(i,j,k)=level
           endif
        endif
        !v-neighbours
        if (v_cmask(i,j,k)==3) then
           if ((v_cmask(i+1,j,k)==level-1).or.(v_cmask(i-1,j,k)==level-1)&
                .or.(v_cmask(i,j+1,k)==level-1).or.(v_cmask(i,j-1,k)==level-1)&
                .or.(v_cmask(i,j,k+1)==level-1).or.(v_cmask(i,j,k-1)==level-1)) then
           v_cmask(i,j,k)=level
           endif
        endif
        !w-neighbours
        if (w_cmask(i,j,k)==3) then
           if ((w_cmask(i+1,j,k)==level-1).or.(w_cmask(i-1,j,k)==level-1)&
                .or.(w_cmask(i,j+1,k)==level-1).or.(w_cmask(i,j-1,k)==level-1)&
                .or.(w_cmask(i,j,k+1)==level-1).or.(w_cmask(i,j,k-1)==level-1)) then
           w_cmask(i,j,k)=level
           endif
        endif
        !p-neighbours
        if (pcmask(i,j,k)==3) then
           if ((pcmask(i+1,j,k)==level-1).or.(pcmask(i-1,j,k)==level-1)&
                .or.(pcmask(i,j+1,k)==level-1).or.(pcmask(i,j-1,k)==level-1)&
                .or.(pcmask(i,j,k+1)==level-1).or.(pcmask(i,j,k-1)==level-1)) then
           pcmask(i,j,k)=level
           endif
        endif
     enddo; enddo; enddo
     call ighost_x(u_cmask,2,req(1:4)); call ighost_x(v_cmask,2,req(5:8)); call ighost_x(w_cmask,2,req(9:12))
     call ighost_x(pcmask,2,req(13:16)); call MPI_WAITALL(16,req(1:16),sta(:,1:16),ierr)
     call ighost_y(u_cmask,2,req(1:4)); call ighost_y(v_cmask,2,req(5:8)); call ighost_y(w_cmask,2,req(9:12))
     call ighost_y(pcmask,2,req(13:16)); call MPI_WAITALL(16,req(1:16),sta(:,1:16),ierr)
     call ighost_z(u_cmask,2,req(1:4)); call ighost_z(v_cmask,2,req(5:8)); call ighost_z(w_cmask,2,req(9:12))
     call ighost_z(pcmask,2,req(13:16)); call MPI_WAITALL(16,req(1:16),sta(:,1:16),ierr)
  enddo
!-Debugging
  debug = .false.
  no = 1
  if (debug .and. mod(iout,no)==0) then
     Open(unit=20,FILE=TRIM(out_path)//'/Top_0-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=21,FILE=TRIM(out_path)//'/Top_1-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=22,FILE=TRIM(out_path)//'/Top_2-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=23,FILE=TRIM(out_path)//'/u_ass-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=24,FILE=TRIM(out_path)//'/v_ass-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=25,FILE=TRIM(out_path)//'/w_ass-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=26,FILE=TRIM(out_path)//'/P1-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=27,FILE=TRIM(out_path)//'/P2-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=28,FILE=TRIM(out_path)//'/P3-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt') 
     Open(unit=29,FILE=TRIM(out_path)//'/P0-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt') 
     !j=(js+je)/2
     k=(ks+ke)/2
     !do k=kmin,kmax; do i=imin,imax
     do j=jmin,jmax; do i=imin,imax
        !write outputs for gnuplot 2D
        if (u_cmask(i,j,k)==0) write(20,13)xh(i),y(j),z(k)
        if (v_cmask(i,j,k)==0) write(20,13)x(i),yh(j),z(k)
        !if (w_cmask(i,j,k)==0) write(20,13)x(i),y(j),zh(k)
        if (pcmask(i,j,k)==0) write(29,13)x(i),y(j),z(k)
        if (u_cmask(i,j,k)==1) write(21,13)xh(i),y(j),z(k)
        if (v_cmask(i,j,k)==1) write(21,13)x(i),yh(j),z(k)
        !if (w_cmask(i,j,k)==1) write(21,13)x(i),y(j),zh(k)
        if (pcmask(i,j,k)==1) write(26,13)x(i),y(j),z(k)
        if (u_cmask(i,j,k)==2) write(22,13)xh(i),y(j),z(k)
        if (v_cmask(i,j,k)==2) write(22,13)x(i),yh(j),z(k)
        !if (w_cmask(i,j,k)==2) write(22,13)x(i),y(j),zh(k)
        if (pcmask(i,j,k)==2) write(27,13)x(i),y(j),z(k)
        if (u_cmask(i,j,k)==3) write(23,13)xh(i),y(j),z(k)
        if (v_cmask(i,j,k)==3) write(24,13)x(i),yh(j),z(k)
        !if (w_cmask(i,j,k)==3) write(25,13)x(i),y(j),zh(k)
        if (pcmask(i,j,k)==3) write(28,13)x(i),y(j),z(k)
     enddo; enddo
     close(unit=20); close(unit=21); close(unit=22); close(unit=23); close(unit=24); close(unit=25)
     close(unit=26); close(unit=27); close(unit=28)
  endif
13 format(3e14.5)
end subroutine set_topology
!-------------------------------------------------------------------------------------------------
subroutine setuppoisson_fs(utmp,vtmp,wtmp,vof_phase,rhot,dt,A,cvof,n1,n2,n3,kap,iout)    
  use module_grid
  use module_BC
  use module_2phase
  use module_freesurface
  use module_IO
  implicit none
  include 'mpif.h'
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax), intent(in) :: utmp,vtmp,wtmp,rhot
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax), intent(in) :: kap
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax), intent(in) :: cvof,n1,n2,n3
  real(8), dimension(is:ie,js:je,ks:ke,8), intent(inout) :: A
  integer, dimension(imin:imax,jmin:jmax,kmin:kmax), intent(in) :: vof_phase
  integer :: req(24),sta(MPI_STATUS_SIZE,24)
  real(8) :: alpha2, x_test2, y_test2, z_test2
  real(8) :: nr(3),al3dnew,x0(3),dc(3),FL3DNEW,n_avg(3)
  real(8) :: dt, limit
  integer :: i,j,k,l,iout,nbr,ierr,no
  real(8) :: c1, c0, c_stag, c_min
  real(8), dimension(4) :: P_bc

  x_mod=dxh((is+ie)/2); y_mod=dyh((js+je)/2); z_mod=dzh((ks+ke)/2) !assumes an unstretched grid
  P_gx = 0d0; P_gy = 0d0; P_gz = 0d0
  limit = 1d-3/dx((is+ie)/2)
  c_min = 1d-2
  !Debugging
  debug = .false.
  no=1
  if (debug .and. mod(iout,no)==0) then
     Open(unit=50,file=TRIM(out_path)//'/C_int-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     !Open(unit=51,file=TRIM(out_path)//'/COEFFS-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=55,file=TRIM(out_path)//'/C0-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=56,file=TRIM(out_path)//'/C1-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
  endif
  do k=ks,ke; do j=js,je; do i=is,ie
     !----Cav-liquid neighbours, set P_g in cavity cells
     if(vof_phase(i,j,k)==1) then
        if (vof_phase(i+1,j,k)==0) then
           P_gx(i,j,k) = sigma*kap(i,j,k)/dx(i) !!filaments and droplets of one cell will be an issue here
           if (P_gx(i,j,k) /= P_gx(i,j,k)) write(*,*)'WARNING, P_g NaN x-dir'
        endif
        if (vof_phase(i,j+1,k)==0) then
           P_gy(i,j,k) = sigma*kap(i,j,k)/dy(j)
           if (P_gy(i,j,k) /= P_gy(i,j,k)) write(*,*)'WARNING, P_g NaN y-dir'
        endif
        if (vof_phase(i,j,k+1)==0) then
           P_gz(i,j,k) = sigma*kap(i,j,k)/dz(k)
           if (P_gz(i,j,k) /= P_gz(i,j,k)) write(*,*)'WARNING, P_g NaN z-dir'
        endif

        !Check x-neighbour         
        if (vof_phase(i+1,j,k) == 0) then
           !get_intersection for liq cell
           nr(1)=n1(i+1,j,k); nr(2)=n2(i+1,j,k); nr(3)=n3(i+1,j,k)
           alpha2 = al3dnew(nr,cvof(i+1,j,k))
           x0(1) = 0d0; 
           x0(2) = 0d0; x0(3) = 0d0
           dc(1) = 0.5d0 
           dc(2) = 1d0; dc(3) = 1d0
           c0 = FL3DNEW(nr,alpha2,x0,dc)
           if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) write(56,314)x(i+1),y(j),c0,cvof(i+1,j,k)
           !get_intersection for cav cell
           nr(1) = n1(i,j,k); nr(2) = n2(i,j,k); nr(3) = n3(i,j,k)
           alpha2 = al3dnew(nr,cvof(i,j,k))
           x0(1) = 0.5d0; 
           x0(2) = 0d0; x0(3) = 0d0
           dc(1) = 0.5d0; 
           dc(2) = 1d0; dc(3) = 1d0
           c1 = FL3DNEW(nr,alpha2,x0,dc)
           if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) write(55,314)x(i),y(j),c1,cvof(i,j,k)
           c_stag = c1+c0
           if (c0>c_min) then
              nr(1)=n1(i+1,j,k)*c0/c_stag + n1(i,j,k)*c1/c_stag
              nr(2)=n2(i+1,j,k)*c0/c_stag + n2(i,j,k)*c1/c_stag
              nr(3)=n3(i+1,j,k)*c0/c_stag + n3(i,j,k)*c1/c_stag
              n_avg(1) = nr(1)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(2) = nr(2)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(3) = nr(3)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
           else
              n_avg(1)= n1(i,j,k)
              n_avg(2)= n2(i,j,k)
              n_avg(3)= n3(i,j,k)
           endif
           if (ABS((ABS(n_avg(1))+ABS(n_avg(2))+ABS(n_avg(3)))-1d0) > 1d-12) then
              write(*,*)'Normals not normalised'
              call pariserror('Normals not normalised')
           endif
           alpha2=al3dnew(n_avg,c_stag)
           if (ABS(n_avg(1))>1d-12) then
              x_test2 = (alpha2 - (n_avg(2)+n_avg(3))/2d0)/n_avg(1)
              if (x_test2 < 0.5d0) P_gx(i,j,k) = sigma*kap(i+1,j,k)/dx(i+1)
              x_mod(i,j,k) = dxh(i)*(1d0-x_test2)
              if (x_mod(i,j,k)>dxh(i)) x_mod(i,j,k) = dxh(i)
              if (x_mod(i,j,k)<limit*dxh(i)) x_mod(i,j,k) = limit*dxh(i)
              if (x_mod(i,j,k) /= x_mod(i,j,k)) then
                 write(*,'("x_mod NaN. c_st, n, vofs, phases:",6e14.5,5I8)')&
                      c_stag,n_avg(1),n_avg(2),n_avg(3),cvof(i,j,k),cvof(i+1,j,k),vof_phase(i,j,k),vof_phase(i+1,j,k),i,j,k
              endif
              if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) then
                 write(50,314)x(i+1)-x_mod(i,j,k),y(j)
              endif
           endif
        endif
        !-------Check y-neighbour
        if (vof_phase(i,j+1,k) == 0) then
           !get_intersection for liq cell
           nr(1) = n1(i,j+1,k); nr(2) = n2(i,j+1,k); nr(3) = n3(i,j+1,k)
           alpha2 = al3dnew(nr,cvof(i,j+1,k))
           x0(1) = 0d0; x0(3) = 0d0 
           x0(2) = 0d0
           dc(1) = 1d0 
           dc(2) = 0.5d0; dc(3) = 1d0
           c0 = FL3DNEW(nr,alpha2,x0,dc)
           if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) write(56,314)x(i),y(j+1),c0,cvof(i,j+1,k)
           !get_intersection for cav cell----------------------------------------
           nr(1) = n1(i,j,k); nr(2) = n2(i,j,k); nr(3) = n3(i,j,k)
           alpha2 = al3dnew(nr,cvof(i,j,k))
           x0(2) = 0.5d0; 
           x0(1) = 0d0; x0(3) = 0d0
           dc(2) = 0.5d0; 
           dc(1) = 1d0; dc(3) = 1d0
           c1 = FL3DNEW(nr,alpha2,x0,dc)
           if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) write(55,314)x(i),y(j),c1,cvof(i,j,k)
           c_stag = c1+c0
           if (c0>c_min) then ! use weighted average if liq VOF is not small, otherwise use cav normals
              nr(1)=n1(i,j+1,k)*c0/c_stag + n1(i,j,k)*c1/c_stag
              nr(2)=n2(i,j+1,k)*c0/c_stag + n2(i,j,k)*c1/c_stag
              nr(3)=n3(i,j+1,k)*c0/c_stag + n3(i,j,k)*c1/c_stag
              n_avg(1) = nr(1)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(2) = nr(2)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(3) = nr(3)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
           else
              n_avg(1)= n1(i,j,k)
              n_avg(2)= n2(i,j,k)
              n_avg(3)= n3(i,j,k)
           endif
           if (ABS((ABS(n_avg(1))+ABS(n_avg(2))+ABS(n_avg(3)))-1d0) > 1d-12) then
              write(*,*)'Normals not normalised'
              call pariserror('Normals not normalised')
           endif
           alpha2=al3dnew(n_avg,c_stag)
           if (ABS(n_avg(2))>1d-12) then
              y_test2 = (alpha2 - (n_avg(1)+n_avg(3))/2d0)/n_avg(2)
              if (y_test2 < 0.5d0) P_gy(i,j,k) = sigma*kap(i,j+1,k)/dy(j+1)
              y_mod(i,j,k) = dyh(j)*(1d0-y_test2)
              if (y_mod(i,j,k)>dyh(j)) y_mod(i,j,k) = dyh(j)
              if (y_mod(i,j,k)<limit*dyh(j)) y_mod(i,j,k) = limit*dyh(j)
              if (y_mod(i,j,k) /= y_mod(i,j,k)) write(*,'("y_mod NaN. c_st, n, vofs, phases:",4e14.5,2I8)')&
                   c_stag,n_avg(2),cvof(i,j,k),cvof(i,j+1,k),vof_phase(i,j,k),vof_phase(i,j+1,k)
              if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) then
                 write(50,314)x(i),y(j+1)-y_mod(i,j,k)
              endif
           endif
        endif
        !-------Check z-neighbours
        if (vof_phase(i,j,k+1) == 0) then
           !vof fraction in half of liq cell
           nr(1) = n1(i,j,k+1); nr(2) = n2(i,j,k+1); nr(3) = n3(i,j,k+1)
           alpha2 = al3dnew(nr,cvof(i,j,k+1))
           x0(1) = 0d0; x0(2) = 0d0 
           x0(3) = 0d0
           dc(3) = 0.5d0 
           dc(1) = 1d0; dc(2) = 1d0
           c0 = FL3DNEW(nr,alpha2,x0,dc)
           !vof fraction in half of cav cell
           nr(1) = n1(i,j,k); nr(2) = n2(i,j,k); nr(3) = n3(i,j,k)
           alpha2 = al3dnew(nr,cvof(i,j,k))
           x0(1) = 0d0; x0(2) = 0d0 
           x0(3) = 0.5d0
           dc(3) = 0.5d0 
           dc(1) = 1d0; dc(2) = 1d0
           c1 = FL3DNEW(nr,alpha2,x0,dc)
           c_stag = c1+c0
           if (c0>c_min) then ! use weighted average if liq VOF is not small, otherwise use cav normals
              nr(1)=n1(i,j,k+1)*c0/c_stag + n1(i,j,k)*c1/c_stag
              nr(2)=n2(i,j,k+1)*c0/c_stag + n2(i,j,k)*c1/c_stag
              nr(3)=n3(i,j,k+1)*c0/c_stag + n3(i,j,k)*c1/c_stag
              n_avg(1) = nr(1)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(2) = nr(2)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(3) = nr(3)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
           else
              n_avg(1)= n1(i,j,k)
              n_avg(2)= n2(i,j,k)
              n_avg(3)= n3(i,j,k)
           endif
           if (ABS((ABS(n_avg(1))+ABS(n_avg(2))+ABS(n_avg(3)))-1d0) > 1d-12) then
              write(*,*)'Normals not normalised'
              call pariserror('Normals not normalised')
           endif
           alpha2=al3dnew(n_avg,c_stag)
           if (ABS(n_avg(3))>1d-12) then
              z_test2 = (alpha2 - (n_avg(1)+n_avg(2))/2d0)/n_avg(3)
              if (z_test2 < 0.5d0) P_gz(i,j,k) = sigma*kap(i,j,k+1)/dz(k+1)
              z_mod(i,j,k) = dzh(k)*(1d0-z_test2)
              if (z_mod(i,j,k)>dzh(k)) z_mod(i,j,k) = dzh(k)
              if (z_mod(i,j,k)<limit*dzh(k)) z_mod(i,j,k) = limit*dzh(k)
              if (z_mod(i,j,k) /= z_mod(i,j,k)) write(*,'("z_mod NaN. c_st, n, vofs, phases:",4e14.5,2I8)')&
                   c_stag,n_avg(3),cvof(i,j,k),cvof(i,j,k+1),vof_phase(i,j,k),vof_phase(i,j,k+1)
           endif
        endif
     endif
!----Liquid-cavity neighbours-----------------------------------------------------
     if (vof_phase(i,j,k)==0) then
        A(i,j,k,1) = 2d0*dt/(dx(i)*dxh(i-1)*(rhot(i-1,j,k)+rhot(i,j,k)))
        A(i,j,k,2) = 2d0*dt/(dx(i)*dxh(i  )*(rhot(i+1,j,k)+rhot(i,j,k)))
        A(i,j,k,3) = 2d0*dt/(dy(j)*dyh(j-1)*(rhot(i,j-1,k)+rhot(i,j,k)))
        A(i,j,k,4) = 2d0*dt/(dy(j)*dyh(j  )*(rhot(i,j+1,k)+rhot(i,j,k)))
        A(i,j,k,5) = 2d0*dt/(dz(k)*dzh(k-1)*(rhot(i,j,k-1)+rhot(i,j,k)))
        A(i,j,k,6) = 2d0*dt/(dz(k)*dzh(k  )*(rhot(i,j,k+1)+rhot(i,j,k)))
        A(i,j,k,7) = sum(A(i,j,k,1:6))
        A(i,j,k,8) =  -( (utmp(i,j,k)-utmp(i-1,j,k))/dx(i) &
             +  (vtmp(i,j,k)-vtmp(i,j-1,k))/dy(j) &
             +  (wtmp(i,j,k)-wtmp(i,j,k-1))/dz(k) )
        ! set Laplace pressure jumps
        if (vof_phase(i+1,j,k)==1) then
           P_gx(i+1,j,k) = sigma*kap(i+1,j,k)/dx(i) !!filaments and droplets of one cell will be an issue here
           if (P_gx(i+1,j,k) /= P_gx(i+1,j,k)) write(*,*)'WARNING, P_g NaN x-dir'
        endif
        if (vof_phase(i,j+1,k)==1) then
           P_gy(i,j+1,k) = sigma*kap(i,j+1,k)/dy(j)
           if (P_gy(i,j+1,k) /= P_gy(i,j+1,k)) write(*,*)'WARNING, P_g NaN y-dir'
        endif
        if (vof_phase(i,j,k+1)==1) then
           P_gz(i,j,k+1) = sigma*kap(i,j,k+1)/dz(k)
           if (P_gz(i,j,k+1) /= P_gz(i,j,k+1)) write(*,*)'WARNING, P_g NaN z-dir'
        endif
        !Check x-neighbour
        if (vof_phase(i+1,j,k) == 1) then
           !if (cvof(i+1,j,k)<0.499d0) write(*,'("Vof phase error. Phase test 1, cvof: ",e14.5)')cvof(i+1,j,k) !debugging
           !vof fraction in half of cav cell
           nr(1)=n1(i+1,j,k); nr(2)=n2(i+1,j,k); nr(3)=n3(i+1,j,k)
           alpha2 = al3dnew(nr,cvof(i+1,j,k))
           x0(1) = 0d0; 
           x0(2) = 0d0; x0(3) = 0d0
           dc(1) = 0.5d0 
           dc(2) = 1d0; dc(3) = 1d0
           c1 = FL3DNEW(nr,alpha2,x0,dc)
           if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) write(56,314)x(i+1),y(j),c1,cvof(i+1,j,k)
           !vof fraction in half of liq cell
           nr(1) = n1(i,j,k); nr(2) = n2(i,j,k); nr(3) = n3(i,j,k)
           alpha2 = al3dnew(nr,cvof(i,j,k))
           x0(1) = 0.5d0; 
           x0(2) = 0d0; x0(3) = 0d0
           dc(1) = 0.5d0; 
           dc(2) = 1d0; dc(3) = 1d0
           c0 = FL3DNEW(nr,alpha2,x0,dc)
           if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) write(55,314)x(i),y(j),c0,cvof(i,j,k)
           c_stag = c1+c0
           if (c0>c_min) then ! use weighted average if liq VOF is not small, otherwise use cav normals
              nr(1)=n1(i,j,k)*c0/c_stag + n1(i+1,j,k)*c1/c_stag
              nr(2)=n2(i,j,k)*c0/c_stag + n2(i+1,j,k)*c1/c_stag
              nr(3)=n3(i,j,k)*c0/c_stag + n3(i+1,j,k)*c1/c_stag
              n_avg(1) = nr(1)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(2) = nr(2)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(3) = nr(3)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
           else
              n_avg(1)= n1(i+1,j,k)
              n_avg(2)= n2(i+1,j,k)
              n_avg(3)= n3(i+1,j,k)
           endif
           if (ABS((ABS(n_avg(1))+ABS(n_avg(2))+ABS(n_avg(3)))-1d0) > 1d-12) then
              write(*,*)'Normals not normalised'
              call pariserror('Normals not normalised')
           endif
           alpha2=al3dnew(n_avg,c_stag)
           if (ABS(n_avg(1))>1d-12) then
              x_test2 = (alpha2 - (n_avg(2)+n_avg(3))/2d0)/n_avg(1)
              if (x_test2 < 0.5d0) P_gx(i+1,j,k) = sigma*kap(i,j,k)/dx(i)
              x_mod(i,j,k) = dxh(i)*x_test2
              if (x_mod(i,j,k)>dxh(i)) x_mod(i,j,k) = dxh(i)
              if (x_mod(i,j,k)<limit*dxh(i)) x_mod(i,j,k) = limit*dxh(i)
              if (x_mod(i,j,k) /= x_mod(i,j,k)) write(*,'("x_mod NaN. c_st, n, vofs, phases:",4e14.5,2I8)')&
                   c_stag,n_avg(1),cvof(i,j,k),cvof(i+1,j,k),vof_phase(i,j,k),vof_phase(i+1,j,k)
              if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) then
                 write(50,314)x(i)+x_mod(i,j,k),y(j) 
              endif
           endif
        endif
        !-------Check y-neighbours in both directions 
        if (vof_phase(i,j+1,k) == 1) then
           !vof fraction in half of cav cell
           nr(1) = n1(i,j+1,k); nr(2) = n2(i,j+1,k); nr(3) = n3(i,j+1,k)
           alpha2 = al3dnew(nr,cvof(i,j+1,k))
           x0(1) = 0d0; x0(3) = 0d0 
           x0(2) = 0d0
           dc(1) = 1d0 
           dc(2) = 0.5d0; dc(3) = 1d0
           c1 = FL3DNEW(nr,alpha2,x0,dc)
           if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) write(56,314)x(i),y(j+1),c1,cvof(i,j+1,k)
           !vof fraction in half of liq cell----------------------------------------
           nr(1) = n1(i,j,k); nr(2) = n2(i,j,k); nr(3) = n3(i,j,k)
           alpha2 = al3dnew(nr,cvof(i,j,k))
           x0(2) = 0.5d0; 
           x0(1) = 0d0; x0(3) = 0d0
           dc(2) = 0.5d0; 
           dc(1) = 1d0; dc(3) = 1d0
           c0 = FL3DNEW(nr,alpha2,x0,dc)
           if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) write(55,314)x(i),y(j),c0,cvof(i,j,k)
           c_stag = c1+c0
           if (c0>c_min) then ! use weighted average if liq VOF is not small, otherwise use cav normals
              nr(1)=n1(i,j,k)*c0/c_stag + n1(i,j+1,k)*c1/c_stag
              nr(2)=n2(i,j,k)*c0/c_stag + n2(i,j+1,k)*c1/c_stag
              nr(3)=n3(i,j,k)*c0/c_stag + n3(i,j+1,k)*c1/c_stag
              n_avg(1) = nr(1)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(2) = nr(2)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(3) = nr(3)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
           else
              n_avg(1)= n1(i,j+1,k)
              n_avg(2)= n2(i,j+1,k)
              n_avg(3)= n3(i,j+1,k)
           endif
           if (ABS((ABS(n_avg(1))+ABS(n_avg(2))+ABS(n_avg(3)))-1d0) > 1d-12) then
              write(*,*)'Normals not normalised'
              call pariserror('Normals not normalised')
           endif
           alpha2=al3dnew(n_avg,c_stag)
           if (ABS(n_avg(2))>1d-12) then
              y_test2 = (alpha2 - (n_avg(1)+n_avg(3))/2d0)/n_avg(2)
              if (y_test2 < 0.5d0) P_gy(i,j+1,k) = sigma*kap(i,j,k)/dy(j)
              y_mod(i,j,k) = dyh(j)*y_test2
              if (y_mod(i,j,k)>dyh(j)) y_mod(i,j,k) = dyh(j)
              if (y_mod(i,j,k)<limit*dyh(j)) y_mod(i,j,k) = limit*dyh(j)
              if (y_mod(i,j,k) /= y_mod(i,j,k)) write(*,'("y_mod NaN. c_st, n, vofs, phases:",4e14.5,2I8)')&
                   c_stag,n_avg(2),cvof(i,j,k),cvof(i,j+1,k),vof_phase(i,j,k),vof_phase(i,j+1,k)
              if (debug .and. k==(ks+ke)/2 .and. mod(iout,no)==0) then
                 write(50,314)x(i),y(j)+y_mod(i,j,k) 
              endif
           endif
        endif
        !-------Check z-neighbours
        if (vof_phase(i,j,k+1) == 1) then
           !vof fraction in half of cav cell
           nr(1) = n1(i,j,k+1); nr(2) = n2(i,j,k+1); nr(3) = n3(i,j,k+1)
           alpha2 = al3dnew(nr,cvof(i,j,k+1))
           x0(1) = 0d0; x0(2) = 0d0 
           x0(3) = 0d0
           dc(3) = 0.5d0 
           dc(1) = 1d0; dc(2) = 1d0
           c1 = FL3DNEW(nr,alpha2,x0,dc)
           !vof fraction in half of liq cell
           nr(1) = n1(i,j,k); nr(2) = n2(i,j,k); nr(3) = n3(i,j,k)
           alpha2 = al3dnew(nr,cvof(i,j,k))
           x0(1) = 0d0; x0(2) = 0d0 
           x0(3) = 0.5d0
           dc(3) = 0.5d0 
           dc(1) = 1d0; dc(2) = 1d0
           c0 = FL3DNEW(nr,alpha2,x0,dc)
           c_stag = c1+c0
           if (c0>c_min) then ! use weighted average if liq VOF is not small, otherwise use cav normals
              nr(1)=n1(i,j,k)*c0/c_stag + n1(i,j,k+1)*c1/c_stag
              nr(2)=n2(i,j,k)*c0/c_stag + n2(i,j,k+1)*c1/c_stag
              nr(3)=n3(i,j,k)*c0/c_stag + n3(i,j,k+1)*c1/c_stag
              n_avg(1) = nr(1)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(2) = nr(2)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
              n_avg(3) = nr(3)/(ABS(nr(1))+ABS(nr(2))+ABS(nr(3)))
           else
              n_avg(1)= n1(i,j,k+1)
              n_avg(2)= n2(i,j,k+1)
              n_avg(3)= n3(i,j,k+1)
           endif
           if (ABS((ABS(n_avg(1))+ABS(n_avg(2))+ABS(n_avg(3)))-1d0) > 1d-12) then
              write(*,*)'Normals not normalised'
              call pariserror('Normals not normalised')
           endif
           alpha2=al3dnew(n_avg,c_stag)
           if (ABS(n_avg(3))>1d-12) then
              z_test2 = (alpha2 - (n_avg(1)+n_avg(2))/2d0)/n_avg(3)
              if (z_test2 < 0.5d0) P_gz(i,j,k+1) = sigma*kap(i,j,k)/dz(k)
              z_mod(i,j,k) = dzh(k)*z_test2
              if (z_mod(i,j,k)>dzh(k)) z_mod(i,j,k) = dzh(k)
              if (z_mod(i,j,k)<limit*dzh(k)) z_mod(i,j,k) = limit*dzh(k)
              if (z_mod(i,j,k) /= z_mod(i,j,k)) write(*,'("z_mod NaN. c_st, n, vofs, phases:",4e14.5,2I8)')&
                   c_stag,n_avg(3),cvof(i,j,k),cvof(i,j,k+1),vof_phase(i,j,k),vof_phase(i,j,k+1)
           endif
           if (debug .and. j==(js+je)/2 .and. mod(iout,no)==0) then
              write(50,314)x(i),z(k)+z_mod(i,j,k) 
              !write(51,314)x(i),z(k),0d0,z_mod(i,j,k)
           endif
        endif
     endif
  enddo;enddo;enddo
  call ghost_x(P_gx,1,req(1:4)); call ghost_y(P_gy,1,req(5:8)); call ghost_z(P_gz,1,req(9:12)) 
  call ghost_x(x_mod,1,req(13:16)); call ghost_y(y_mod,1,req(17:20)); call ghost_z(z_mod,1,req(21:24)) 
  call MPI_WAITALL(24,req(1:24),sta(:,1:24),ierr)
!!$  call ghost_y(P_gx,1,req(1:4)); call ghost_y(P_gy,1,req(5:8)); call ghost_y(P_gz,1,req(9:12)) 
!!$  call ghost_y(x_mod,1,req(13:16)); call ghost_y(y_mod,1,req(17:20)); call ghost_y(z_mod,1,req(21:24)) 
!!$  call MPI_WAITALL(24,req(1:24),sta(:,1:24),ierr)
!!$  call ghost_z(P_gx,1,req(1:4)); call ghost_z(P_gy,1,req(5:8)); call ghost_z(P_gz,1,req(9:12)) 
!!$  call ghost_z(x_mod,1,req(13:16)); call ghost_z(y_mod,1,req(17:20)); call ghost_z(z_mod,1,req(21:24)) 
!!$  call MPI_WAITALL(24,req(1:24),sta(:,1:24),ierr)
!--Debugging
  if (debug .and. mod(iout,no)==0) then
     Open(unit=52,file=TRIM(out_path)//'/P_int1-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=53,file=TRIM(out_path)//'/P_int2-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=54,file=TRIM(out_path)//'/P_int3-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt') 
!!$     Open(unit=57,file=TRIM(out_path)//'/x_mod-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
!!$     Open(unit=58,file=TRIM(out_path)//'/y_mod-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
!!$     Open(unit=59,file=TRIM(out_path)//'/z_mod-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=60,file=TRIM(out_path)//'/phase-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=61,file=TRIM(out_path)//'/kappa-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=62,file=TRIM(out_path)//'/n1-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=63,file=TRIM(out_path)//'/n2-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
     Open(unit=64,file=TRIM(out_path)//'/n3-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt') 
     j=(js+je)/2
     !k=(ks+ke)/2
     do k=ks-1,ke; do i=is-1,ie
        write(52,313)x(i),z(k),P_gx(i,j,k)
        !write(53,313)x(i),y(j),P_gy(i,j,k)
        write(54,313)x(i),z(k),P_gz(i,j,k)
        !write(57,313)xh(i),y(j),x_mod(i,j,k)
        !write(58,313)x(i),y(j),y_mod(i,j,k)
        !write(59,313)x(i),zh(k),z_mod(i,j,k)
        write(60,212)x(i),z(k),vof_phase(i,j,k)
        write(61,313)x(i),z(k),kap(i,j,k)
        Write(62,313)x(i),z(k),n1(i,j,k)
        Write(63,313)x(i),z(k),n2(i,j,k)
        Write(64,313)x(i),z(k),n3(i,j,k)
     enddo; enddo   
     close(unit=50);
     close(unit=52); close(unit=53); close(unit=54)
!!$     close(unit=55); close(unit=56); 
!!$     close(unit=57); close(unit=58); close(unit=59)
     close(unit=60); close(unit=61); close(unit=62); close(unit=63)
     close(unit=64)
  endif
212 format(2e14.5,I8)
312 format(2e14.5) !remove, debugging
313 format(3e14.5) !remove, debugging
323 format(2e14.5,e14.4) !remove, debugging
314 format(4e14.5) !remove, debugging
414 format(3e14.5,I8)
!--------------------------------------------------------------------------------------------------------
  do k=ks,ke; do j=js,je; do i=is,ie
     if (vof_phase(i,j,k)==0) then
        A(i,j,k,1) = 2d0*dt/(dx(i)*x_mod(i-1,j,k)*(rhot(i-1,j,k)+rhot(i,j,k)))
        if (A(i,j,k,1) /= A(i,j,k,1)) write(*,'("ERROR: A1 NaN :",2e14.5)')A(i,j,k,1),x_mod(i-1,j,k) 
        A(i,j,k,2) = 2d0*dt/(dx(i)*x_mod(i,j,k)*(rhot(i+1,j,k)+rhot(i,j,k)))
        if (A(i,j,k,2) /= A(i,j,k,2)) write(*,'("ERROR: A2 NaN :",2e14.5)')A(i,j,k,2),x_mod(i,j,k)
        A(i,j,k,3) = 2d0*dt/(dy(j)*y_mod(i,j-1,k)*(rhot(i,j-1,k)+rhot(i,j,k)))
        if (A(i,j,k,3) /= A(i,j,k,3)) write(*,'("ERROR: A3 NaN :",2e14.5)')A(i,j,k,3),y_mod(i,j-1,k)
        A(i,j,k,4) = 2d0*dt/(dy(j)*y_mod(i,j,k)*(rhot(i,j+1,k)+rhot(i,j,k)))
        if (A(i,j,k,4) /= A(i,j,k,4)) write(*,'("ERROR: A4 NaN :",2e14.5)')A(i,j,k,4),y_mod(i,j,k)
        A(i,j,k,5) = 2d0*dt/(dz(k)*z_mod(i,j,k-1)*(rhot(i,j,k-1)+rhot(i,j,k)))
        if (A(i,j,k,5) /= A(i,j,k,5)) write(*,'("ERROR: A5 NaN :",2e14.5)')A(i,j,k,5),z_mod(i,j,k-1)
        A(i,j,k,6) = 2d0*dt/(dz(k)*z_mod(i,j,k)*(rhot(i,j,k+1)+rhot(i,j,k)))
        if (A(i,j,k,6) /= A(i,j,k,6)) write(*,'("ERROR: A6 NaN :",2e14.5)')A(i,j,k,6),z_mod(i,j,k)
        A(i,j,k,7) = sum(A(i,j,k,1:6))
        A(i,j,k,8) = A(i,j,k,8) + dt/rhot(i,j,k)*&
             (P_gx(i+1,j,k)/(dx(i)*x_mod(i,j,k))+P_gx(i-1,j,k)/(dx(i)*x_mod(i-1,j,k))&
             +P_gy(i,j+1,k)/(dy(j)*y_mod(i,j,k))+P_gy(i,j-1,k)/(dy(j)*y_mod(i,j-1,k))&
             +P_gz(i,j,k+1)/(dz(k)*z_mod(i,j,k))+P_gz(i,j,k-1)/(dz(k)*z_mod(i,j,k-1)))
        if (A(i,j,k,8) /= A(i,j,k,8)) then
           write(*,'("A8 NaN, error imminent. Neigbours mods :",6e14.5)')x_mod(i-1,j,k),x_mod(i,j,k),&
                y_mod(i,j-1,k),y_mod(i,j,k),z_mod(i,j,k-1),z_mod(i,j,k)
           write(*,'("A8 NaN, error imminent. P_g :",6e14.5,2I8)')P_gx(i-1,j,k),P_gx(i+1,j,k),&
                P_gy(i,j-1,k),P_gy(i,j+1,k),P_gz(i,j,k-1),P_gz(i,j,k+1),i,k
           write(*,'("rho :",e14.5)')rhot(i,j,k)
        endif
        if (debug .and. mod(iout,no)==0 .and. j==(js+je)/2) then
           Open(unit=51,file=TRIM(out_path)//'/COEFFS-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
           Open(unit=52,file=TRIM(out_path)//'/A-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout/no,padding))//'.txt')
           write(51,314)x(i),z(k),-x_mod(i-1,j,k),0d0
           write(51,314)x(i),z(k),x_mod(i,j,k),0d0
           write(51,314)x(i),z(k),0d0,-z_mod(i,j,k-1)
           write(51,314)x(i),z(k),0d0,z_mod(i,j,k)
           if (cvof(i,j,k)>1d-20) write(52,'(10e14.5)')x(i),z(k),A(i,j,k,1:8)
        endif
        if (pcmask(i,j,k).ne.0) write(*,'("Error topology, phase 0, pcmask :",i8)')pcmask(i,j,k)
     endif
  enddo;enddo;enddo

  P_bc = 0d0
  ! dp/dn = 0 for inflow bc on face 1 == x- : do not correct u(is-1)
  ! inflow bc on other faces not implemented yet.  !@@ generalize this ! 
  if(coords(1)==0) then
     if(bdry_cond(1)==3) then  
        A(is,:,:,7) = A(is,:,:,7) - A(is,:,:,1)
        A(is,:,:,1) = 0d0
        ! pressure boundary condition
     else if(bdry_cond(1)==5 .and. (.not.RP_test)) then 
        A(is,:,:,8) = (2d0/3d0)*BoundaryPressure(1)  ! P_0 =  1/3 (Pinner - P_b) + P_b
        A(is,:,:,7) = 1d0                      ! P_0  - 1/3 Pinner =  2/3 P_b
        A(is,:,:,1:6) = 0d0                    ! A7 P_is + A2 P_is+1 = A8 
        A(is,:,:,2) = 1d0/3d0 !sign due to definition in Poisson solver
        P_bc(1) = 1d0
     endif
  endif
  ! dp/dn = 0 for outflow/fixed velocity bc on face 4 == x+
  ! outflow/fixed velocity bc on other faces not implemented yet.  
  if(coords(1)==Npx-1) then
     if(bdry_cond(4)==4) then
        A(ie,:,:,7) = A(ie,:,:,7) - A(ie,:,:,2)
        A(ie,:,:,2) = 0d0
        ! pressure boundary condition
     else if(bdry_cond(4)==5 .and. (.not.RP_test)) then
        A(ie,:,:,8) = (2d0/3d0)*BoundaryPressure(2)
        A(ie,:,:,7) = 1d0  
        A(ie,:,:,2:6) = 0d0
        A(ie,:,:,1) = 1d0/3d0
        P_bc(2) = 1d0
     endif
  endif
 
  if (.not. RP_test) then
     ! Pressure BC for y-
     if(coords(2)==0 .and. (bdry_cond(2)==5)) then
        A(:,js,:,8) = (2d0/3d0)*BoundaryPressure(3)
        A(is,js,:,8) = (2d0/3d0)*(BoundaryPressure(3)+BoundaryPressure(1)*P_bc(1))
        A(ie,js,:,8) = (2d0/3d0)*(BoundaryPressure(3)+BoundaryPressure(2)*P_bc(2))
        A(:,js,:,7) = 1d0
        A(is,js,:,7) = 1d0 + P_bc(1)
        A(ie,js,:,7) = 1d0 + P_bc(2)
        A(:,js,:,1:6) = 0d0      
        A(is,js,:,2) = 1d0/3d0*P_bc(1)
        A(ie,js,:,1) = 1d0/3d0*P_bc(2)
        A(:,js,:,4) = 1d0/3d0
        P_bc(3) = 1d0
     endif
     ! Pressure BC for y+
     if(coords(2)==Npy-1 .and. (bdry_cond(5)==5) ) then
        A(:,je,:,8) = (2d0/3d0)*BoundaryPressure(4)
        A(is,je,:,8) = (2d0/3d0)*(BoundaryPressure(4)+BoundaryPressure(1)*P_bc(1))
        A(ie,je,:,8) = (2d0/3d0)*(BoundaryPressure(4)+BoundaryPressure(2)*P_bc(2))
        A(:,je,:,7) = 1d0  
        A(is,je,:,7) = 1d0 + P_bc(1)
        A(ie,je,:,7) = 1d0 + P_bc(2)
        A(:,je,:,1:6) = 0d0
        A(is,je,:,2) = 1d0/3d0*P_bc(1)
        A(ie,je,:,1) = 1d0/3d0*P_bc(2)
        A(:,je,:,3) = 1d0/3d0
        P_bc(4) = 1d0
     endif

     ! Pressure BC for z-
     if(coords(3)==0 .and. (bdry_cond(3)==5)) then
        A(:,:,ks,8) = (2d0/3d0)*BoundaryPressure(5)
        A(is,js,ks,8) = (2d0/3d0)*(BoundaryPressure(5)+BoundaryPressure(1)*P_bc(1)+BoundaryPressure(3)*P_bc(3))
        A(ie,js,ks,8) = (2d0/3d0)*(BoundaryPressure(5)+BoundaryPressure(2)*P_bc(2)+BoundaryPressure(3)*P_bc(3))
        A(is,je,ks,8) = (2d0/3d0)*(BoundaryPressure(5)+BoundaryPressure(1)*P_bc(1)+BoundaryPressure(4)*P_bc(4))
        A(ie,je,ks,8) = (2d0/3d0)*(BoundaryPressure(5)+BoundaryPressure(2)*P_bc(2)+BoundaryPressure(4)*P_bc(4))
        A(:,:,ks,7) = 1d0
        A(is,js,ks,7) = 1d0 + P_bc(1) + P_bc(3)
        A(ie,js,ks,7) = 1d0 + P_bc(2) + P_bc(3)
        A(is,je,ks,7) = 1d0 + P_bc(1) + P_bc(4)
        A(ie,je,ks,7) = 1d0 + P_bc(2) + P_bc(4)
        A(:,:,ks,1:6) = 0d0   
        A(is,js,ks,2) = 1d0/3d0*P_bc(1); A(is,js,ks,4) = 1d0/3d0*P_bc(3)
        A(ie,js,ks,1) = 1d0/3d0*P_bc(2); A(ie,js,ks,4) = 1d0/3d0*P_bc(3)
        A(is,je,ks,2) = 1d0/3d0*P_bc(1); A(is,je,ks,3) = 1d0/3d0*P_bc(4)
        A(ie,je,ks,1) = 1d0/3d0*P_bc(2); A(ie,je,ks,3) = 1d0/3d0*P_bc(4)
        A(:,:,ks,6) = 1d0/3d0
     endif
     ! Pressure BC for z+
     if(coords(3)==Npz-1 .and. (bdry_cond(6)==5) ) then
        A(:,:,ke,8) = (2d0/3d0)*BoundaryPressure(6)
        A(is,js,ke,8) = (2d0/3d0)*(BoundaryPressure(6)+BoundaryPressure(1)*P_bc(1)+BoundaryPressure(3)*P_bc(3))
        A(ie,js,ke,8) = (2d0/3d0)*(BoundaryPressure(6)+BoundaryPressure(2)*P_bc(2)+BoundaryPressure(3)*P_bc(3))
        A(is,je,ke,8) = (2d0/3d0)*(BoundaryPressure(6)+BoundaryPressure(1)*P_bc(1)+BoundaryPressure(4)*P_bc(4))
        A(ie,je,ke,8) = (2d0/3d0)*(BoundaryPressure(6)+BoundaryPressure(2)*P_bc(2)+BoundaryPressure(4)*P_bc(4))
        A(:,:,ke,7) = 1d0  
        A(is,js,ke,7) = 1d0 + P_bc(1) + P_bc(3)
        A(ie,js,ke,7) = 1d0 + P_bc(2) + P_bc(3)
        A(is,je,ke,7) = 1d0 + P_bc(1) + P_bc(4)
        A(ie,je,ke,7) = 1d0 + P_bc(2) + P_bc(4)
        A(:,:,ke,1:6) = 0d0
        A(is,js,ke,2) = 1d0/3d0*P_bc(1); A(is,js,ks,4) = 1d0/3d0*P_bc(3)
        A(ie,js,ke,1) = 1d0/3d0*P_bc(2); A(ie,js,ks,4) = 1d0/3d0*P_bc(3)
        A(is,je,ke,2) = 1d0/3d0*P_bc(1); A(is,je,ks,3) = 1d0/3d0*P_bc(4)
        A(ie,je,ke,1) = 1d0/3d0*P_bc(2); A(ie,je,ks,3) = 1d0/3d0*P_bc(4)
        A(:,:,ke,5) = 1d0/3d0
     endif
  endif
end subroutine setuppoisson_fs
!--------------------------------------------------------------------------------------------------------------------
subroutine setuppoisson_fs2(utmp,vtmp,wtmp,dt,A,vof_phase,istep)
  use module_grid
  use module_BC
  use module_2phase
  use module_freesurface
  use module_IO
  implicit none
  real(8), dimension(is:ie,js:je,ks:ke,8), intent(out) :: A
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax), intent(in) :: utmp,vtmp,wtmp
  integer, dimension(imin:imax,jmin:jmax,kmin:kmax), intent(in) :: vof_phase
  real(8) :: dt,h_mod
  integer :: i,j,k,nbr
  integer :: istep

  do k=ks,ke; do j=js,je; do i=is,ie
     if (pcmask(i,j,k)==1 .or. pcmask(i,j,k)==2) then !rho is 1d0
        A(i,j,k,1) = 1d0/(dx(i)*dxh(i-1))
        if (A(i,j,k,1) /= A(i,j,k,1)) write(*,'("ERROR: A1 NaN in fs2:",e14.5)')A(i,j,k,1)
        A(i,j,k,2) = 1d0/(dx(i)*dxh(i))
        if (A(i,j,k,2) /= A(i,j,k,2)) write(*,'("ERROR: A2 NaN in fs2:",e14.5)')A(i,j,k,2)
        A(i,j,k,3) = 1d0/(dy(j)*dyh(j-1))
        if (A(i,j,k,3) /= A(i,j,k,3)) write(*,'("ERROR: A3 NaN in fs2:",e14.5)')A(i,j,k,3)
        A(i,j,k,4) = 1d0/(dy(j)*dyh(j))
        if (A(i,j,k,4) /= A(i,j,k,4)) write(*,'("ERROR: A4 NaN in fs2:",e14.5)')A(i,j,k,4)
        A(i,j,k,5) = 1d0/(dz(k)*dzh(k-1))
        if (A(i,j,k,5) /= A(i,j,k,5)) write(*,'("ERROR: A5 NaN in fs2:",e14.5)')A(i,j,k,5)
        A(i,j,k,6) = 1d0/(dz(k)*dzh(k))
        if (A(i,j,k,6) /= A(i,j,k,6)) write(*,'("ERROR: A6 NaN in fs2:",e14.5)')A(i,j,k,6)

        if (pcmask(i,j,k)==2 .and. vof_phase(i,j,k)/=1) call pariserror("Fatal topology error in FS 2nd projection")

        if (pcmask(i,j,k)==1) then
           if (vof_phase(i,j,k)/=1) call pariserror("Fatal topology error in FS 2nd projection")
           do nbr=-1,1,2
              if (pcmask(i+nbr,j,k) == 0) then
                 A(i,j,k,2+(nbr-1)/2) = 0d0
              endif
              if (pcmask(i,j+nbr,k) == 0) then
                 A(i,j,k,4+(nbr-1)/2) = 0d0
              endif
              if (pcmask(i,j,k+nbr) == 0) then
                 A(i,j,k,6+(nbr-1)/2) = 0d0
              endif
           enddo
        endif
        A(i,j,k,7) = sum(A(i,j,k,1:6))
        A(i,j,k,8) =  -1d0*((utmp(i,j,k)-utmp(i-1,j,k))/dx(i) &
             +  (vtmp(i,j,k)-vtmp(i,j-1,k))/dy(j) &
             +  (wtmp(i,j,k)-wtmp(i,j,k-1))/dz(k))
        if (A(i,j,k,8) /= A(i,j,k,8)) write(*,'("ERROR: A8 NaN in fs2:",e14.5)')A(i,j,k,8) 
     endif
  enddo; enddo; enddo
end subroutine setuppoisson_fs2
!--------------------------------------------------------------------------------------------------------------------
subroutine discrete_divergence(u,v,w,iout)
  use module_grid
  use module_freesurface
  use module_IO
  implicit none
  include 'mpif.h'
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax), intent(in) :: u,v,w 
  real(8), dimension(is:ie,js:je,ks:ke) :: div, t
  real(8), dimension(0:3) :: divtot, domain, n_level, n_total
  real(8) :: avg2
  integer :: i,j,k,l,iout,ierr

!OPEN(unit=20,file=TRIM(out_path)//'/divergence-'//TRIM(int2text(rank,padding))//'-'//TRIM(int2text(iout,padding))//'.txt')
OPEN(unit=21,file='div_type.txt',access='append')

divtot = 0d0; n_level = 0d0

do k=ks,ke; do j=js,je; do i=is,ie
   !div(i,j,k)=(u(i-1,j,k)-u(i,j,k))/dx(i)+(v(i,j-1,k)-v(i,j,k))/dy(j)+(w(i,j,k-1)-w(i,j,k))/dz(k)
   div(i,j,k)=(u(i-1,j,k)-u(i,j,k))*dy(j)*dz(k)+(v(i,j-1,k)-v(i,j,k))*dx(i)*dz(k)+(w(i,j,k-1)-w(i,j,k))*dx(i)*dy(j)
   do l=0,3
      if (pcmask(i,j,k)==l) then
         divtot(l)=divtot(l)+ABS(div(i,j,k))
         n_level(l) = n_level(l) + 1d0
      endif
   enddo
enddo; enddo; enddo
call MPI_ALLREDUCE(divtot,domain,4, MPI_DOUBLE_PRECISION, MPI_SUM, MPI_COMM_Cart, ierr)
call MPI_ALLREDUCE(n_level,n_total,4, MPI_DOUBLE_PRECISION, MPI_SUM, MPI_COMM_Cart, ierr)
do l=0,3
   if (n_total(l) > 1d-10) domain(l)=domain(l)/n_total(l)
enddo
avg2 = (domain(1)+domain(2))/(n_total(1)+n_total(2))
if (rank==0) then
   OPEN(unit=21,file='div_type.txt',access='append')
   write(21,15)iout,domain(0),domain(1),domain(2),domain(3),avg2
   close(unit=21)
endif
15 format(I8,5e14.5)
end subroutine discrete_divergence
!--------------------------------------------------------------------------------------------------------------------
subroutine get_ref_volume
  use module_2phase
  use module_BC
  use module_freesurface
  implicit none
  real(8), parameter :: pi=3.1415926535897932384626433833

  if (NumBubble /= 1) call pariserror('For the Rayleigh-Plesset test, only a single bubble is allowed')
  V_0 = 4d0/3d0*pi*(R_ref**3d0)
  R_RK = rad(1)
  dR_RK = 0d0 
  P_inf = BoundaryPressure(1)
  ddR_RK = (P_ref*(R_ref/R_RK)**(3d0*gamma)-P_inf)/R_RK
  !if (rank==0) then
  !   write(*,'("RP test initial bubble volume:",e14.5)')V_0
  !   write(*,'("Free surface ddR: ",e14.5)')ddR_RK
  !endif
end subroutine get_ref_volume
!--------------------------------------------------------------------------------------------------------------------
! This is a straight copy of NewSolver. The idea is to not clutter NewSolver with all the FreeSurface flags and tests, 
! therefore it was copied here and named FreeSolver.
!Solves the following linear equiation:
! A7*Pijk = A1*Pi-1jk + A2*Pi+1jk + A3*Pij-1k + 
!           A4*Pij+1k + A5*Pijk-1 + A6*Pijk+1 + A8
!-------------------------------------------------------------------------------------------------
subroutine FreeSolver(A,p,maxError,beta,maxit,it,ierr,iout,time,tres2)
  use module_grid
  use module_BC
  use module_IO
  use module_freesurface
  implicit none
  include 'mpif.h'
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax), intent(inout) :: p
  real(8), dimension(is:ie,js:je,ks:ke,8), intent(in) :: A
  real(8), intent(in) :: beta, maxError
  integer, intent(in) :: maxit
  integer, intent(out) :: it, ierr
  real(8) :: res1,res2,resinf,intvol
  real(8) :: tres2, cells, p_c, Vol, time, tcells
  integer :: i,j,k, iout
  integer :: req(12),sta(MPI_STATUS_SIZE,12)
  logical :: mask(imin:imax,jmin:jmax,kmin:kmax)
  integer, parameter :: norm=2, relaxtype=1
  logical, parameter :: recordconvergence=.false.
  integer, save :: itime=0
! Open file for convergence history
  if(rank==0.and.recordconvergence) then
     OPEN(UNIT=89,FILE=TRIM(out_path)//'/convergence_history-'//TRIM(int2text(itime,padding))//'.txt')
  endif
  itime=itime+1
  if (RP_test) then
     call get_vol(Vol)
     p_c = P_ref*(V_0/Vol)**gamma
     if(mod(iout,10)==0 .and. rank==0 .and. solver_flag==2) then
        OPEN(unit=11,file='RP_volume',position='append')
        write(11,2)time,Vol
     endif
  else
     p_c = 0d0
  endif
2 format(2e14.5)
  if (solver_flag == 0) call pariserror("Free Surface solver flag needs to be 1 or 2")
  do k=ks,ke; do j=js,je; do i=is,ie
     if (solver_flag == 1 .and. pcmask(i,j,k) /= 0) p(i,j,k) = p_c
     if (solver_flag == 2 .and. pcmask(i,j,k)==3) p(i,j,k) = 0d0
  enddo; enddo; enddo
  !--------------------------------------ITERATION LOOP--------------------------------------------  
  do it=1,maxit
     if(relaxtype==2) then 
        call LineRelax_fs(A,p,beta)
     elseif(relaxtype==1) then
        call RedBlackRelax_fs(A,p,beta)
     endif
!---------------------------------CHECK FOR CONVERGENCE-------------------------------------------
    res1 = 0d0; res2=0.d0; resinf=0.d0; intvol=0.d0; cells = 0d0
    call ghost_x(p,1,req( 1: 4)); call ghost_y(p,1,req( 5: 8)); call ghost_z(p,1,req( 9:12))
    do k=ks+1,ke-1; do j=js+1,je-1; do i=is+1,ie-1
       if ((pcmask(i,j,k)==0 .and. solver_flag==1)&
            .or.((pcmask(i,j,k)==1 .or. pcmask(i,j,k)==2) .and. solver_flag==2)) then
          res2=res2+abs(-p(i,j,k) * A(i,j,k,7) +                           &
               A(i,j,k,1) * p(i-1,j,k) + A(i,j,k,2) * p(i+1,j,k) +            &
               A(i,j,k,3) * p(i,j-1,k) + A(i,j,k,4) * p(i,j+1,k) +            &
               A(i,j,k,5) * p(i,j,k-1) + A(i,j,k,6) * p(i,j,k+1) + A(i,j,k,8) )**norm
          cells = cells + 1d0
       endif
    enddo; enddo; enddo
    call MPI_WAITALL(12,req,sta,ierr)
    mask=.true.
    mask(is+1:ie-1,js+1:je-1,ks+1:ke-1)=.false.
    do k=ks,ke; do j=js,je; do i=is,ie
       if(mask(i,j,k) .and. ((pcmask(i,j,k)==0 .and. solver_flag==1) .or. &
            ((pcmask(i,j,k)==1 .or. pcmask(i,j,k)==2) .and. solver_flag==2))) then
          res2=res2+abs(-p(i,j,k) * A(i,j,k,7) +&
               A(i,j,k,1) * p(i-1,j,k) + A(i,j,k,2) * p(i+1,j,k) +            &
               A(i,j,k,3) * p(i,j-1,k) + A(i,j,k,4) * p(i,j+1,k) +            &
               A(i,j,k,5) * p(i,j,k-1) + A(i,j,k,6) * p(i,j,k+1) + A(i,j,k,8) )**norm
          cells = cells + 1d0
       endif
    enddo; enddo; enddo
    !if (cells > 1d-10) then
    !   res2 = res2/cells
    !else
    !   write(*,*)'No cells for this topology present in this processor'
    !endif
    call catch_divergence_fs(res2,cells,ierr)
    call MPI_ALLREDUCE(res2, tres2, 1, MPI_DOUBLE_PRECISION, MPI_SUM, MPI_Comm_Cart, ierr)
    call MPI_ALLREDUCE(cells, tcells, 1, MPI_DOUBLE_PRECISION, MPI_SUM, MPI_Comm_Cart, ierr)
    if(norm==2) tres2=sqrt(tres2)
    tres2 = tres2/tcells
    if(rank==0.and.mod(it,10) == 0.and.recordconvergence) write(89,310) it, solver_flag, tres2
310 format(2I6,'  ',(e14.5))
    if (tres2<maxError) then 
       if(rank==0.and.recordconvergence) close(89)
       exit
    endif
  enddo
  if(rank==0.and.recordconvergence) close(89)
  if(it==maxit+1 .and. rank==0) then
     write(*,*) 'Warning: LinearSolver reached maxit: ||res||: ',tres2
     write(*,'("Solver flag:",I8)')solver_flag
  endif
contains
  subroutine catch_divergence_fs(res2,cells,ierr)
    real(8), intent(in) :: res2, cells
    integer, intent(out) :: ierr
    logical :: diverged=.false.
    logical :: extended=.true.
    integer :: l
    if(extended) then
       do k=ks,ke; do j=js,je; do i=is,ie
          do l=1,8
             if(A(i,j,k,l)/=A(i,j,k,l).or.p(i,j,k)/=p(i,j,k)) then
                diverged=.true.
             endif
          enddo
          if(diverged) then
             OPEN(UNIT=88,FILE=TRIM(out_path)//'/message-rank-'//TRIM(int2text(rank,padding))//'.txt')
             write(88,*) "ijk rank",i,j,k,rank
             write(88,*) "A",  A(i,j,k,:)
             write(88,*) "p",  p(i,j,k)
             write(88,*) 'A or p is NaN after',it,'iterations at rank ',rank
             close(88)
             if(rank<=30) print*,'A or p is NaN after',it,'iterations at rank ',rank
             call pariserror("A or p is NaN")
             exit
          endif
       end do; end do; end do
    endif
    if ((res2*npx*npy*npz)>1.d16 ) then
       if(rank<=30) then
          print*,'Pressure solver diverged after',it,'iterations at rank ',rank
          write(*,'("Res2, cells, solver_flag :",2e14.5,I8)')res2,cells,solver_flag
       endif
       call pariserror("freesolver error")
    else if (res2 .ne. res2) then 
       if(rank<=30) then
          print*, 'it:',it,'Pressure residual value is invalid at rank', rank
          write(*,'("Res2, cells, solver_flag :",2e14.5,I8)')res2,cells,solver_flag
       endif
       call pariserror("freesolver error")
    else
       ierr=0
    endif
  end subroutine catch_divergence_fs
  subroutine get_vol(Vol_RP)
    !use module_grid
    use module_VOF
    !use module_2phase
    !implicit none
    !include 'mpif.h'
    real(8) :: Vol_RP, bub_vol, vol_tot
    integer :: i,j,k,ierr
    bub_vol = 0d0
    do k=ks,ke; do j=js,je; do i=is,ie
       bub_vol = bub_vol + cvof(i,j,k)*dx(i)*dy(j)*dz(k)
    enddo; enddo; enddo
    call MPI_ALLREDUCE(bub_vol,vol_tot,1, MPI_DOUBLE_PRECISION, MPI_SUM, MPI_Comm_Cart, ierr)
    Vol_RP = vol_tot/(xLength*yLength*zLength)
    !get_vol = sum(cvof(i=is:ie,j=js:je,k=ks:ke))
  end subroutine get_vol
end subroutine FreeSolver
!--------------------------------------ONE RELAXATION ITERATION (SMOOTHER)----------------------------------
subroutine RedBlackRelax_fs(A,p,beta)
  use module_grid
  use module_BC
  use module_IO
  use module_freesurface
  implicit none
  include 'mpif.h'
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax), intent(inout) :: p
  real(8), dimension(is:ie,js:je,ks:ke,8), intent(in) :: A
  real(8), intent(in) :: beta
  integer :: req(12),sta(MPI_STATUS_SIZE,12)
  integer :: i,j,k,ierr
  integer :: isw,jsw,ksw,ipass
  ksw=1
  do ipass=1,2
     jsw=ksw
     do k=ks,ke
        isw=jsw
        do j=js,je
           do i=isw+is-1,ie,2
              if ((pcmask(i,j,k)==0 .and. solver_flag==1) &
                   .or.((pcmask(i,j,k)==1 .or. pcmask(i,j,k)==2) .and. solver_flag==2)) then
                 p(i,j,k)=(1d0-beta)*p(i,j,k) + (beta/A(i,j,k,7))*(              &
                      A(i,j,k,1) * p(i-1,j,k) + A(i,j,k,2) * p(i+1,j,k) +        &
                      A(i,j,k,3) * p(i,j-1,k) + A(i,j,k,4) * p(i,j+1,k) +        &
                      A(i,j,k,5) * p(i,j,k-1) + A(i,j,k,6) * p(i,j,k+1) + A(i,j,k,8))   
              endif
           enddo
           isw=3-isw
        enddo
        jsw=3-jsw
     enddo
     ksw=3-ksw
     if(ipass==1) then
        call ghost_x(p,1,req( 1: 4)); call ghost_y(p,1,req( 5: 8)); call ghost_z(p,1,req( 9:12))
        call MPI_WAITALL(12,req,sta,ierr)
     endif
  enddo
end subroutine RedBlackRelax_fs
!--------------------------------------ONE RELAXATION ITERATION (SMOOTHER)----------------------------------
subroutine LineRelax_fs(A,p,beta)
  use module_grid
  use module_freesurface
  implicit none
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax), intent(inout) :: p
  real(8), dimension(is:ie,js:je,ks:ke,8), intent(in) :: A
  real(8), intent(in) :: beta
  integer :: i,j,k
!--------------------------------------ITERATION LOOP--------------------------------------------  
  do k=ks,ke; do j=js,je; do i=is,ie
     if ((pcmask(i,j,k)==0 .and. solver_flag==1).or.((pcmask(i,j,k)==1 .or. pcmask(i,j,k)==2) .and. solver_flag==2)) then
        p(i,j,k)=(1d0-beta)*p(i,j,k) + (beta/A(i,j,k,7))*(              &
             A(i,j,k,1) * p(i-1,j,k) + A(i,j,k,2) * p(i+1,j,k) +        &
             A(i,j,k,3) * p(i,j-1,k) + A(i,j,k,4) * p(i,j+1,k) +        &
             A(i,j,k,5) * p(i,j,k-1) + A(i,j,k,6) * p(i,j,k+1) + A(i,j,k,8))
     endif
  enddo; enddo; enddo
end subroutine LineRelax_fs
!-------------------------------------------------------------------------------------------------
!-------------------------------------------------------------------------------------------------
!------------VTK output routines------------------------------------------------------------------
!
! These routines output data used to debug and/or display variables in the free surface part of the
! code.
!
!-------------------------------------------------------------------------------------------------
subroutine append_visit_fs(index,iout)
  use module_flow
  use module_grid
  use module_IO
  use module_freesurface
  implicit none
  character(len=10) :: file
  character(len=40) :: file_root
  integer index, iout, prank
  if(rank.ne.0) call pariserror("rank.ne.0 in append")
  file = TRIM(visit_file(index))
  if(.not.vtk_open(index)) then
     OPEN(UNIT=100,FILE=TRIM(file)//'.visit')
     write(100,10) nPdomain
10   format('!NBLOCKS ',I4)
     vtk_open(index) = .true.
  else
     OPEN(UNIT=100,FILE=TRIM(file)//'.visit',position='append')
  endif

  file_root = TRIM(out_path)//'/VTK/'//TRIM(file_short(index))
  do prank=0,NpDomain-1
     write(100,11) TRIM(file_root)//TRIM(int2text(iout,padding))//'-'//TRIM(int2text(prank,padding))//'.vtk'
11   format(A)
  enddo
  close(100)
end subroutine  append_visit_fs
!-------------------------------------------------------------------------------------------------
subroutine VTK_scalar_struct(index,iout,var)
  use module_flow
  use module_grid
  use module_IO
  use module_freesurface
  implicit none
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax) :: var 
  character(len=40) :: file_root
  integer index, iout, i,j,k
  file_root = TRIM(out_path)//'/VTK/'//TRIM(file_short(index))//TRIM(int2text(iout,padding))//'-'
  !Write to VTK file
  OPEN(UNIT=8,FILE=TRIM(file_root)//TRIM(int2text(rank,padding))//'.vtk')
  write(8,10)
  write(8,11) time
  write(8,12)
  write(8,13)
  write(8,14)ie+1-is+1,je+1-js+1,ke+1-ks+1
  write(8,15) x(is),y(js),z(ks)
  write(8,16) x(is+1)-x(is),y(js+1)-y(js),z(ks+1)-z(ks)
10 format('# vtk DataFile Version 2.0')
11 format('grid, time ',F16.8)
12 format('ASCII')
13 format('DATASET STRUCTURED_POINTS')
14 format('DIMENSIONS ',I5,I5,I5)
15 format('ORIGIN ',F16.8,F16.8,F16.8)
16 format('SPACING ',F16.8,F16.8,F16.8)

  write(8,19)(ie+1-is+1)*(je+1-js+1)*(ke+1-ks+1)
  write(8,17)file_short(index)
  write(8,18)
19 format('POINT_DATA ',I17)
17 format('SCALARS ',A20,' float 1')
18 format('LOOKUP_TABLE default')

  do k=ks,ke+1; do j=js,je+1; do i=is,ie+1
     write(8,210) var(i,j,k)
  enddo; enddo; enddo
210 format(e14.5)
  close(8)
end subroutine VTK_scalar_struct
!==============================================================================================================================
! Routine to numerically integrate the Rayleigh-Plesset equation
subroutine Integrate_RP(dt,t)
  !use module_2phase
  use module_freesurface
  implicit none 
  integer :: j
  real(8) :: dt, t, Volume
  real(8), parameter :: pi=3.141592653589793238462643383
  integer, parameter :: nvar = 2
  real(8) :: y(nvar), ytmp(nvar)
  real(8) :: dydt1(nvar), dydt2(nvar),dydt3(nvar),dydt0(nvar),dydt4(nvar)

    ! start at previous RP values
    y(1) = R_RK
    y(2) = dR_RK
    ! RK4
    !1st step
    ytmp(:)  = y(:)
    call func(ytmp,dydt0)
    !2nd step
    do j=1,nvar
       ytmp(j) = y(j) + dydt0(j)*dt/2.d0
    enddo
    call func(ytmp,dydt1)
    !3rd step
    do j=1,nvar
       ytmp(j) = y(j) + dydt1(j)*dt/2.d0
    enddo
    call func(ytmp,dydt2)
    !4th step
    do j=1,nvar
       ytmp(j) = y(j) + dydt2(j)*dt
    enddo
    call func(ytmp,dydt3)

    do j=1,nvar
       y(j) = y(j) + dt*(dydt0(j)/6d0 + dydt1(j)/3d0 + dydt2(j)/3d0 + dydt3(j)/6d0)
    enddo
    Volume = 4d0/3d0*pi*y(1)**3d0
    call func(y,dydt4)
    R_RK = y(1); dR_RK = y(2); ddR_RK = dydt4(2)
    
contains
subroutine func(y,dydt)
  use module_2phase
  use module_freesurface
    real(8) :: P_c
    real(8) :: y(2), dydt(2)
    P_c = P_ref*(R_ref/y(1))**(3d0*gamma)-2d0*sigma/y(1)

    dydt(2) = -3d0*(y(2)**2d0)/(2d0*y(1)) + (P_c - P_inf)/y(1)
    dydt(1) = y(2)
  end subroutine func
end subroutine Integrate_RP
!=======================================================================================================================================
subroutine write_RP_test(t) 
  use module_freesurface
  implicit none
  real(8) :: t, vol, p_mid, p_corner
  real(8), parameter :: pi=3.141592653589793238462643383
  vol = 4d0/3d0*pi*R_RK**3d0
  p_mid = pressure(0.5d0)
  p_corner = pressure(sqrt(2d0)/2d0)
  OPEN(UNIT=20,FILE='RK_int_RP.txt',position='append')
  WRITE(20,2) t, R_RK, dR_RK, ddR_RK, vol, p_mid, p_corner
  CLOSE(unit=20)
2 format(7e14.5)
contains
  function pressure(r)
    use module_2phase
    use module_freesurface
    real(8) :: r, P_l, pressure
    P_l = P_ref*(R_ref/R_RK)**(3d0*gamma)-2d0*sigma/R_RK
    pressure = P_l - (dR_RK**2d0 * R_RK**4d0/(2d0*r**4d0) - (ddR_RK*R_RK**2d0 + 2d0*R_RK*dR_RK**2d0)/r +&
         ddR_RK*R_RK + 3d0/2d0*dR_RK**2d0)
  end function pressure
end subroutine write_RP_test
!======================================================================================================================================
! Idea is to set free outflow in the radial direction for the RP test case. In combination with variable Pressure bx's, we can have more
! accurate results on a truncated domain.
!
subroutine set_RP_radial_velocity(u,v,w)
  use module_grid
  use module_2phase
  use module_freesurface
  implicit none
  include 'mpif.h'
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax), intent(inout) :: u, v, w
  real(8) :: di1, di2
  integer :: ih1, ih2
  integer :: i,j,k

  !x- face
  if (coords(1)==0) then
     !write(*,*)'x- face loop'
     do j=js,je; do k=ks,ke
        ! Components to be done independently, starting xith u on the boundary
        if (y(j).ge.yc(1)) then 
           ih1 = -1
        else
           ih1 = 1
        endif
        if (z(k).ge.zc(1)) then 
           ih2 = -1
        else
           ih2 = 1
        endif
        !get cuts, will be non-dimensional if dx=dy=dz
        di1 = ABS(yc(1)-y(j))/ABS(xc(1)-xh(is-1))
        di2 = ABS(zc(1)-z(k))/ABS(xc(1)-xh(is-1))
        !set
        u(is-1,j,k)=u(is,j,k)*(1d0-di1)*(1d0-di2)+u(is,j+ih1,k)*di1*(1d0-di2)&
             +u(is,j,k+ih2)*(1d0-di1)*di2+u(is,j+ih1,k+ih2)*di1*di2
        !same for v
        if (yh(j).ge.yc(1)) then 
           ih1 = -1
        else
           ih1 = 1
        endif
        if (zh(k).ge.zc(1)) then 
           ih2 = -1
        else
           ih2 = 1
        endif
        !get cuts, will be non-dimensional if dx=dy=dz
        di1 = ABS(yc(1)-yh(j))/ABS(xc(1)-x(is-1))
        di2 = ABS(zc(1)-zh(k))/ABS(xc(1)-x(is-1))
        !set
        v(is-1,j,k)=v(is,j,k)*(1d0-di1)*(1d0-di2)+v(is,j+ih1,k)*di1*(1d0-di2)&
             +v(is,j,k+ih2)*(1d0-di1)*di2+v(is,j+ih1,k+ih2)*di1*di2
        !same for w
        w(is-1,j,k)=w(is,j,k)*(1d0-di1)*(1d0-di2)+w(is,j+ih1,k)*di1*(1d0-di2)&
             +w(is,j,k+ih2)*(1d0-di1)*di2+w(is,j+ih1,k+ih2)*di1*di2
        !set u(is-2) to allow cell is-1 to be divergence free
     enddo; enddo
  endif
  !x+ face
  if (coords(1)==nPx-1) then
    !write(*,*)'x+ face loop' 
     do j=js,je; do k=ks,ke
        ! Components to be done independently, starting xith u on the boundary
        if (y(j).ge.yc(1)) then 
           ih1 = -1
        else
           ih1 = 1
        endif
        if (z(k).ge.zc(1)) then 
           ih2 = -1
        else
           ih2 = 1
        endif
        !get cuts, will be non-dimensional if dx=dy=dz
        di1 = ABS(yc(1)-y(j))/ABS(xc(1)-xh(ie))
        di2 = ABS(zc(1)-z(k))/ABS(xc(1)-xh(ie))
        !set
        u(ie,j,k)=u(ie-1,j,k)*(1d0-di1)*(1d0-di2)+u(ie-1,j+ih1,k)*di1*(1d0-di2)&
             +u(ie-1,j,k+ih2)*(1d0-di1)*di2+u(ie-1,j+ih1,k+ih2)*di1*di2
        !same for v
        if (yh(j).ge.yc(1)) then 
           ih1 = -1
        else
           ih1 = 1
        endif
        if (zh(k).ge.zc(1)) then 
           ih2 = -1
        else
           ih2 = 1
        endif
        !get cuts, will be non-dimensional if dx=dy=dz
        di1 = ABS(yc(1)-yh(j))/ABS(xc(1)-x(ie+1))
        di2 = ABS(zc(1)-zh(k))/ABS(xc(1)-x(ie+1))
        !set
        v(ie,j,k)=v(ie-1,j,k)*(1d0-di1)*(1d0-di2)+v(ie-1,j+ih1,k)*di1*(1d0-di2)&
             +v(ie-1,j,k+ih2)*(1d0-di1)*di2+v(ie-1,j+ih1,k+ih2)*di1*di2
        !same for w
        w(ie,j,k)=w(ie-1,j,k)*(1d0-di1)*(1d0-di2)+w(ie-1,j+ih1,k)*di1*(1d0-di2)&
             +w(ie-1,j,k+ih2)*(1d0-di1)*di2+w(ie-1,j+ih1,k+ih2)*di1*di2
        !set u(ie+2) to allow cell to be divergence free
     enddo; enddo
  endif

  !y-face
  if (coords(2)==0) then
     !write(*,*)'y- face loop'
     do i=is,ie; do k=ks,ke
        if (x(i).ge.xc(1)) then 
           ih1 = -1
        else
           ih1 = 1
        endif
        if (z(k).ge.zc(1)) then 
           ih2 = -1
        else
           ih2 = 1
        endif
        !get cuts, will be non-dimensional if dx=dy=dz
        di1 = ABS(xc(1)-x(i))/ABS(yc(1)-yh(is-1))
        di2 = ABS(zc(1)-z(k))/ABS(yc(1)-yh(is-1))
        !set
        v(i,js-1,k)=v(i,js,k)*(1d0-di1)*(1d0-di2)+v(is,js+ih1,k)*di1*(1d0-di2)&
             +v(i,js,k+ih2)*(1d0-di1)*di2+v(i,js+ih1,k+ih2)*di1*di2
        !same for v
        if (xh(i).ge.xc(1)) then 
           ih1 = -1
        else
           ih1 = 1
        endif
        if (zh(k).ge.zc(1)) then 
           ih2 = -1
        else
           ih2 = 1
        endif
        !get cuts, will be non-dimensional if dx=dy=dz
        di1 = ABS(xc(1)-xh(i))/ABS(yc(1)-y(is-1))
        di2 = ABS(zc(1)-zh(k))/ABS(yc(1)-y(is-1))
        !set
        u(i,js-1,k)=u(i,js,k)*(1d0-di1)*(1d0-di2)+u(i+ih1,js,k)*di1*(1d0-di2)&
             +u(i,js,k+ih2)*(1d0-di1)*di2+u(i+ih1,js,k+ih2)*di1*di2
        !same for w
        w(i,js-1,k)=w(i,js,k)*(1d0-di1)*(1d0-di2)+w(i+ih1,js,k)*di1*(1d0-di2)&
             +w(i,js,k+ih2)*(1d0-di1)*di2+w(i+ih1,js,k+ih2)*di1*di2
        !set u(is-2) to allow cell is-1 to be divergence free
     enddo; enddo
  endif
  !y+ face
  if (coords(2)==nPy-1) then
     !write(*,*)'y+ face loop'
     do i=is,ie; do k=ks,ke
        if (x(i).ge.xc(1)) then 
           ih1 = -1
        else
           ih1 = 1
        endif
        if (z(k).ge.zc(1)) then 
           ih2 = -1
        else
           ih2 = 1
        endif
        !get cuts, will be non-dimensional if dx=dy=dz
        di1 = ABS(xc(1)-x(i))/ABS(yc(1)-yh(je))
        di2 = ABS(zc(1)-z(k))/ABS(yc(1)-yh(je))
        !set
        v(i,je,k)=v(i,je-1,k)*(1d0-di1)*(1d0-di2)+v(i+ih1,je-1,k)*di1*(1d0-di2)&
             +v(i,je-1,k+ih2)*(1d0-di1)*di2+v(i+ih1,je-1,k+ih2)*di1*di2
        !same for u
        if (xh(i).ge.xc(1)) then 
           ih1 = -1
        else
           ih1 = 1
        endif
        if (zh(k).ge.zc(1)) then 
           ih2 = -1
        else
           ih2 = 1
        endif
        !get cuts, will be non-dimensional if dx=dy=dz
        di1 = ABS(xc(1)-xh(i))/ABS(yc(1)-y(je+1))
        di2 = ABS(zc(1)-zh(k))/ABS(yc(1)-y(je+1))
        !set
        u(i,je+1,k)=u(i,je,k)*(1d0-di1)*(1d0-di2)+u(i+ih1,je,k)*di1*(1d0-di2)&
             +u(i,je,k+ih2)*(1d0-di1)*di2+u(i+ih1,je,k+ih2)*di1*di2
        !same for w
        w(i,je+1,k)=w(i,je,k)*(1d0-di1)*(1d0-di2)+w(i+ih1,je,k)*di1*(1d0-di2)&
             +w(i,je,k+ih2)*(1d0-di1)*di2+w(i+ih1,je,k+ih2)*di1*di2
        !set u(ie+2) to allow cell to be divergence free
     enddo; enddo
  endif
end subroutine set_RP_radial_velocity
!====================================================================================================================================================
subroutine set_RP_pressure(p)
  use module_grid
  use module_2phase
  use module_freesurface
  implicit none
  include 'mpif.h'
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax), intent(inout) :: p
  real(8) :: r, P_l
  integer :: i,j,k
  P_l = P_ref*(R_ref/R_RK)**(3d0*gamma)-2d0*sigma/R_RK
  if (coords(1)==0) then 
     do k=ks-1,ke+1; do j=js-1,je+1
        r = sqrt((x(is-1)-xc(1))**2d0 + (y(j)-yc(1))**2d0 + (z(k)-zc(1))**2d0)
        p(is-1,j,k) = P_l - (dR_RK**2d0 * R_RK**4d0/(2d0*r**4d0) - (ddR_RK*R_RK**2d0 + 2d0*R_RK*dR_RK**2d0)/r +&
             ddR_RK*R_RK + 3d0/2d0*dR_RK**2d0)
     enddo; enddo
  endif
  if(coords(1)==Npx-1) then
     do k=ks-1,ke+1; do j=js-1,je+1
        r = sqrt((x(ie+1)-xc(1))**2d0 + (y(j)-yc(1))**2d0 + (z(k)-zc(1))**2d0)
        p(ie+1,j,k) = P_l - (dR_RK**2d0 * R_RK**4d0/(2d0*r**4d0) - (ddR_RK*R_RK**2d0 + 2d0*R_RK*dR_RK**2d0)/r +&
             ddR_RK*R_RK + 3d0/2d0*dR_RK**2d0)
     enddo; enddo 
  endif
  if(coords(2)==0) then
     do k=ks-1,ke+1; do i=is-1,ie+1
        r = sqrt((x(i)-xc(1))**2d0 + (y(js-1)-yc(1))**2d0 + (z(k)-zc(1))**2d0)
        p(i,js-1,k) = P_l - (dR_RK**2d0 * R_RK**4d0/(2d0*r**4d0) - (ddR_RK*R_RK**2d0 + 2d0*R_RK*dR_RK**2d0)/r +&
             ddR_RK*R_RK + 3d0/2d0*dR_RK**2d0)
     enddo; enddo 
  endif
  if(coords(2)==Npy-1) then
    do k=ks-1,ke+1; do i=is-1,ie+1
        r = sqrt((x(i)-xc(1))**2d0 + (y(je+1)-yc(1))**2d0 + (z(k)-zc(1))**2d0)
        p(i,je+1,k) = P_l - (dR_RK**2d0 * R_RK**4d0/(2d0*r**4d0) - (ddR_RK*R_RK**2d0 + 2d0*R_RK*dR_RK**2d0)/r +&
             ddR_RK*R_RK + 3d0/2d0*dR_RK**2d0)
     enddo; enddo  
  endif

  ! Pressure BC for z-
  if(coords(3)==0) then
     do j=js-1,je+1; do i=is-1,ie+1
        r = sqrt((x(i)-xc(1))**2d0 + (y(j)-yc(1))**2d0 + (z(ks-1)-zc(1))**2d0)
        p(i,j,ks-1) = P_l - (dR_RK**2d0 * R_RK**4d0/(2d0*r**4d0) - (ddR_RK*R_RK**2d0 + 2d0*R_RK*dR_RK**2d0)/r +&
             ddR_RK*R_RK + 3d0/2d0*dR_RK**2d0)
     enddo; enddo 
  endif
  ! Pressure BC for z+
  if(coords(3)==Npz-1) then
     do j=js-1,je+1; do i=is-1,ie+1
        r = sqrt((x(i)-xc(1))**2d0 + (y(j)-yc(1))**2d0 + (z(ke+1)-zc(1))**2d0)
        p(i,j,ke+1) = P_l - (dR_RK**2d0 * R_RK**4d0/(2d0*r**4d0) - (ddR_RK*R_RK**2d0 + 2d0*R_RK*dR_RK**2d0)/r +&
             ddR_RK*R_RK + 3d0/2d0*dR_RK**2d0)
     enddo; enddo 
  endif
end subroutine set_RP_pressure
!====================================================================================================================================================
subroutine initialize_P_RP(p)
  use module_grid
  use module_2phase
  use module_freesurface
  implicit none
  real(8), dimension(imin:imax,jmin:jmax,kmin:kmax), intent(inout) :: p
  real(8) :: r, P_l
  integer :: i,j,k,ierr
  P_l = P_ref*(R_ref/R_RK)**(3d0*gamma)-2d0*sigma/R_RK
  do k=ks,ke; do j=js,je; do i=is,ie
     r = sqrt((x(i)-xc(1))**2d0 + (y(j)-yc(1))**2d0 + (z(k)-zc(1))**2d0)
     if (r .ge. rad(1)) then
        p(i,j,k) = P_l - (dR_RK**2d0 * R_RK**4d0/(2d0*r**4d0) - (ddR_RK*R_RK**2d0 + 2d0*R_RK*dR_RK**2d0)/r +&
             ddR_RK*R_RK + 3d0/2d0*dR_RK**2d0)
     endif
  enddo; enddo; enddo
end subroutine initialize_P_RP
!====================================================================================================================================================