!=======================================================================
!
! This submodule contains the subroutines 
! for the advection of sea ice tracers
!
! Author: L. Zampieri ( lorenzo.zampieri@awi.de )
!  Modified by Qian Wang to apply to SCHISM
!
! Main driver: tracer_advection_icepack, which 
! calls fct_solve_icepack (sequence of lower- and higher-order FCT solver for
! each tracer)
!=======================================================================

submodule (icedrv_main) icedrv_advection

    use icedrv_kinds
    use icedrv_constants
    use icedrv_system,      only: icedrv_system_abort
    use schism_msgp,        only: parallel_abort,parallel_finalize,exchange_p2d,rtype,comm
    use icepack_intfc,      only: icepack_warnings_flush,         &
                                  icepack_warnings_aborted,       &
                                  icepack_query_tracer_indices,   &
                                  icepack_query_tracer_flags,     &
                                  icepack_query_parameters,       &
                                  icepack_query_tracer_sizes
    use schism_glbl, only: rkind,nea,np,npa,elnode,nnp,indnd,time_stamp,rnday, &
   &fdb,lfdb,xnd,ynd,iplg,idry,i34,isbnd,pframe,eframe,area,idry_e,nxq, &
   &elside,iself,indel,nne,distj,snx,sny,isbs,xel,yel,xctr,yctr,xcj,ycj,ics,isidenode, &
   &sframe2,mnei_p

    implicit none

    real(kind=dbl_kind), allocatable, dimension(:)   :: &
         d_tr,        trl,                              &
         rhs_tr,      rhs_trdiv,                        &
         icepplus,    icepminus,                        &
         mass_matrix, newwork, aream                

    real(kind=dbl_kind), allocatable, dimension(:,:) :: &
         icefluxes

    real(kind=dbl_kind), allocatable, dimension(:,:,:) :: &
         flux_matrix1,flux_matrix2,flux_matrix3,flux_matrix4

    real(kind=dbl_kind), allocatable, dimension(:,:,:,:) :: &
         flux_matrix0
    ! Variables needed for advection

    contains

    subroutine tg_rhs_icepack(trc)
    
        !use mod_mesh
        use mice_module
        !use g_parsup
        !use o_param
        !use g_config
    
        implicit none
    
        ! Input - output
    
        !type(t_mesh),        target,        intent(in)     :: mesh
        real(kind=dbl_kind), dimension(nx), intent(inout)  :: trc  !nx=npa
    
        ! Local variables
    
        real(kind=dbl_kind)              :: diff,       um,    vm,    vol, & 
                                            entries(3), dx(3), dy(3)
        integer(kind=int_kind)           :: n,          q,     row,        &
                                            elem,       elnodes(3)
    
!#include "../associate_mesh.h"
         !scalevol=2.0e8

        ! Taylor-Galerkin (Lax-Wendroff) rhs
      
        do row = 1, nx_nh !=np (no halo)
           rhs_tr(row)=c0
        enddo
    
        ! Velocities at nodes
    
        do elem = 1, nx_elem_nh  !assembling rhs over elements (no halo)
    
           elnodes = elnode(1:3,elem)
    
           ! Derivatives
           dx  = bafux(:,elem)
           dy  = bafuy(:,elem)
           vol = voltriangle(elem)
           um=sum(uvel(elnode(1:3,elem)))
           vm=sum(vvel(elnode(1:3,elem)))
    
           ! Diffusivity
    
           !diff = ice_diff * sqrt( elem_area(elem) / scale_area )

            diff = ice_diff *sqrt(voltriangle(elem)/scalevol)
            
           do n = 1, 3
              row = elnodes(n)
               !row = elnodes(n,elem)
              do q = 1, 3
                 entries(q) = vol*dt_dyn*((dx(n)*(um+uvel(elnodes(q))) +      &
                              dy(n)*(vm+vvel(elnodes(q))))/12.0 -             &
                              diff*(dx(n)*dx(q)+ dy(n)*dy(q)) -               &
                              0.5*dt_dyn*(um*dx(n)+vm*dy(n))*(um*dx(q)+vm*dy(q))/9.0)
              enddo
              rhs_tr(row)=rhs_tr(row)+sum(entries*trc(elnode(1:3,elem)))
           enddo
        enddo
    
    end subroutine tg_rhs_icepack
    
    !=======================================================================
    
    module subroutine init_advection_icepack
    
        !use o_param
        !use o_mesh
        !use g_parsup
         use mice_module
         
        implicit none
        integer (kind=int_kind) :: ntrcr,narr
        call icepack_query_tracer_sizes(ntrcr_out=ntrcr)
         narr   = 1 + ncat * (3 + ntrcr)
        !type(t_mesh), intent(in), target :: mesh
          
        ! Initialization of arrays necessary to implement FCT algorithm
        allocate(trl(nx))   ! low-order solutions
        allocate(d_tr(nx))  ! increments of high
                            ! order solutions
        allocate(icefluxes(nx_elem, 3))
        allocate(icepplus(nx), icepminus(nx))
        allocate(rhs_tr(nx),  rhs_trdiv(nx))
        allocate(newwork(nx))
        allocate(aream(nx))
        allocate(flux_matrix1(mnei_p,nx_nh,narr)) 
        allocate(flux_matrix2(mnei_p,nx_nh,narr))
        allocate(flux_matrix3(mnei_p,nx_nh,narr)) 
        allocate(flux_matrix4(mnei_p,nx_nh,narr)) 
        allocate(flux_matrix0(3,mnei_p,nx,narr))  
        !allocate(mass_matrix(sum(nn_num(1:nx_nh))))

      
        trl(:)    = c0
        d_tr(:)   = c0
        rhs_tr(:) = c0
        rhs_trdiv(:)   = c0
        icefluxes(:,:) = c0
        icepplus(:)    = c0
        icepminus(:)   = c0
        newwork(:)     = c0 
        aream(:)     = c0  
        flux_matrix1(:,:,:) = c0
        flux_matrix2(:,:,:) = c0
        flux_matrix3(:,:,:) = c0
        flux_matrix4(:,:,:) = c0
        flux_matrix0(:,:,:,:) = c0
        !mass_matrix(:) = c0
      
        ! Fill in  the mass matrix
        !call fill_mass_matrix_icepack
        !mass_matrix=ice_matrix
        if (myrank==0) write(*,*) 'Icepack FCT is initialized'
    
    end subroutine init_advection_icepack
    
    !=======================================================================
    
    subroutine fill_mass_matrix_icepack
    
        !use mod_mesh
        !use o_mesh
        !use i_param
        !use g_parsup
         use mice_module

        implicit none
      
        integer(kind=int_kind)                 :: n, n1, n2, row
        integer(kind=int_kind)                 :: elem, elnodes(3), q, offset, col, ipos
        integer(kind=int_kind), allocatable    :: col_pos(:)
        real(kind=dbl_kind)                    :: aa
        integer(kind=int_kind)                 :: flag=0 ,iflag=0
        !type(t_mesh), intent(in), target       :: mesh
      
!#include "../associate_mesh.h"
        
        !allocate(col_pos(nx))
          
        !do elem=1,nx_elem_nh
        !   elnodes=elnode(:,elem)
        !   do n = 1, 3
        !      row = elnodes(n)
        !      if ( row > nx_nh ) cycle
        !     ! Global-to-local neighbourhood correspondence
        !      do q = 1, nn_num(row)
        !         col_pos(nn_pos(q,row))=q
        !      enddo
        !      offset = ssh_stiff%rowptr(row) - ssh_stiff%rowptr(1)
        !      do q = 1, 3
        !         col  = elnodes(q)
        !         ipos = offset+col_pos(col)
        !         mass_matrix(ipos) = mass_matrix(ipos) + elem_area(elem) / 12.0_WP
        !         if ( q == n ) then
        !         mass_matrix(ipos) = mass_matrix(ipos) + elem_area(elem) / 12.0_WP
        !         end if
        !      enddo
        !   enddo
        !enddo
      
        ! TEST: area == sum of row entries in mass_matrix:
        !do q = 1, nx_nh
        !   offset = ssh_stiff%rowptr(q)   - ssh_stiff%rowptr(1) + 1
        !   n      = ssh_stiff%rowptr(q+1) - ssh_stiff%rowptr(1)
        !   aa     = sum(mass_matrix(offset:n))
        !   if ( abs(area(1,q)-aa) > p1) then
        !      iflag = q
        !      flag  = 1
        !   endif
        !enddo
      
        !if ( flag > 0 ) then
        !   offset = ssh_stiff%rowptr(iflag)   - ssh_stiff%rowptr(1)+1
        !   n      = ssh_stiff%rowptr(iflag+1) - ssh_stiff%rowptr(1)
        !   aa     = sum(mass_matrix(offset:n))
        ! 
         !  write(*,*) '#### MASS MATRIX PROBLEM', myrank, iflag, aa, area(1,iflag)
        !endif
        !deallocate(col_pos)
    
    end subroutine fill_mass_matrix_icepack
    
    !=======================================================================
    
    subroutine solve_low_order_icepack(trc)
    
        !============================
        ! Low-order solution
        !============================
        !
        ! It is assumed that m_ice, a_ice and m_snow from the previous time step
        ! are known at 1:myDim_nod2D+eDim_nod2D.
        ! We add diffusive contribution to the rhs. The diffusion operator
        ! is implemented as the difference between the consistent and lumped mass
        ! matrices acting on the field from the previous time step. The consistent
        ! mass matrix on the lhs is replaced with the lumped one.
    
        !use mod_mesh
        !use o_mesh
        !use i_param
        !use g_parsup
         use mice_module
      
        implicit none
      
        integer(kind=int_kind)           :: row,j, clo, clo2, cn, location(100)
        real   (kind=dbl_kind)           :: gamma,sum1
       !type(t_mesh),        target,        intent(in)     :: mesh
        real(kind=dbl_kind), dimension(nx), intent(inout)  :: trc
    
!#include "../associate_mesh.h"
      
        gamma = ice_gamma_fct       ! Added diffusivity parameter
                                    ! Adjust it to ensure posivity of solution
        trl(:)    = c0

        do row = 1, nx_nh
         sum1=ice_matrix(0,row)*trc(row)
            do j=1,nnp(row)
               clo=indnd(j,row)
               sum1=sum1+ice_matrix(j,row)*trc(clo)
            enddo !j
           !clo  = ssh_stiff%rowptr(row)   - ssh_stiff%rowptr(1) + 1
           !clo2 = ssh_stiff%rowptr(row+1) - ssh_stiff%rowptr(1)
           !cn   = clo2 - clo + 1
           !location(1:cn) = nn_pos(1:cn, row)
           trl(row) = (rhs_tr(row) + gamma * sum1) / lump_ice_matrix(row) +              &
                      (1.0-gamma) * trc(row)
        enddo
      
        call exchange_p2d(trl)
      
        ! Low-order solution must be known to neighbours
    
    end subroutine solve_low_order_icepack
    
    !=======================================================================
    
    subroutine solve_high_order_icepack(trc)
    
        !use mod_mesh
        !use o_mesh
        !use i_param
        !use g_parsup
         use mice_module
    
        implicit none
      
        integer(kind=int_kind)             :: n,i,j,clo,clo2,cn,location(100),row
        real   (kind=dbl_kind)          :: rhs_new,sum1
        integer(kind=int_kind), parameter  :: num_iter_solve = 3
        !type(t_mesh),        target,        intent(in)     :: mesh
        real(kind=dbl_kind), dimension(nx), intent(inout)  :: trc
      
!#include "../associate_mesh.h"
      
        ! Taylor-Galerkin solution
       
        ! First guess solution

        d_tr(:)   = c0
        trl(:)    = c0

        do row = 1, nx_nh
           d_tr(row) = rhs_tr(row) / lump_ice_matrix(row)
        end do
      
        call exchange_p2d(d_tr)
      
        ! Iterate
        do n = 1, num_iter_solve - 1
           do row = 1, nx_nh
              !clo  = ssh_stiff%rowptr(row) - ssh_stiff%rowptr(1) + 1
              !clo2 = ssh_stiff%rowptr(row+1) - ssh_stiff%rowptr(1)
              !cn   = clo2 - clo + 1
              !location(1:cn) = nn_pos(1:cn,row)
               sum1=ice_matrix(0,row)*d_tr(row)
               do j=1,nnp(row)
                  clo=indnd(j,row)
                  sum1=sum1+ice_matrix(j,row)*d_tr(clo)
               enddo !j
              rhs_new  = rhs_tr(row) - sum1
              trl(row) = d_tr(row) + rhs_new / lump_ice_matrix(row)
           enddo
           do row = 1, nx_nh
              d_tr(row) = trl(row)
           enddo
           call exchange_p2d(d_tr)
        enddo
      
    end subroutine solve_high_order_icepack
    
    !=======================================================================
    
    subroutine fem_fct_icepack(trc)
    
        !============================
        ! Flux corrected transport algorithm for tracer advection
        !============================
        !
        ! It is based on Loehner et al. (Finite-element flux-corrected
        ! transport (FEM-FCT) for the Euler and Navier-Stokes equation,
        ! Int. J. Numer. Meth. Fluids, 7 (1987), 1093--1109) as described by Kuzmin and
        ! Turek. (kuzmin@math.uni-dortmund.de)
    
        !use mod_mesh
        !use o_mesh
        !use o_param
        !use i_param
        !use g_parsup
        use mice_module
   
    
        integer(kind=int_kind)                            :: icoef(3,3), n, q, elem, elnodes(3), row
        real   (kind=dbl_kind), allocatable, dimension(:) :: tmax, tmin, trctmp
        real   (kind=dbl_kind)                            :: vol, flux, ae, gamma, tempmax
        !type(t_mesh),        target,        intent(in)     :: mesh  
        !nx=npa, nx_nh=np
        real(kind=dbl_kind), dimension(nx), intent(inout)  :: trc
    
!#include "../associate_mesh.h"
      
        gamma = ice_gamma_fct        ! It should coinside with gamma in
                                     ! ts_solve_low_order
    
        !==========================
        ! Compute elemental antidiffusive fluxes to nodes
        !==========================
        ! This is the most unpleasant part ---
        ! it takes memory and time. For every element
        ! we need its antidiffusive contribution to
        ! each of its 3 nodes
       
        allocate(tmax(nx_nh), tmin(nx_nh))
        allocate(trctmp(nx))
       
        ! Auxiliary elemental operator (mass matrix- lumped mass matrix)
       
        icoef = 1
        icefluxes(:,:) = c0
        trctmp(:) = trc(:)
        do n = 1, 3   ! three upper nodes
                      ! Cycle over rows  row=elnodes(n)
                 icoef(n,n) = -2
        enddo
       
        do elem = 1, nx_elem
           elnodes = elnode(1:3,elem)
           vol     = voltriangle(elem)
           do q = 1, 3
              icefluxes(elem,q) = -sum(icoef(:,q) * (gamma * trc(elnodes) +       &
                                  d_tr(elnodes))) * (vol / lump_ice_matrix(elnodes(q))) / 12.0
            !if(trc(elnodes(q))>10) write(12,*) elem,elnodes(q),trc(elnodes),trl(elnodes),d_tr(elnodes),vol,lump_ice_matrix(elnodes(q)),icefluxes(elem,q)
            !if(abs(icefluxes(elem,q))>0) write(12,*) elem,elnodes(q),trc(elnodes),trl(elnodes),d_tr(elnodes),icefluxes(elem,q)
           enddo
        enddo
       
        !==========================
        ! Screening the low-order solution
        !==========================
        ! TO BE ADDED IF FOUND NECESSARY
        ! Screening means comparing low-order solutions with the
        ! solution on the previous time step and using whichever
        ! is greater/smaller in computations of max/min below
       
        !==========================
        ! Cluster min/max
        !==========================
       
        do row = 1, nx_nh
           n = nnp(row)
            tmax(row) = maxval(trl(indnd(1:n,row)))
            tempmax   = maxval(trc(indnd(1:n,row)))
            tmax(row) = max(tmax(row),trl(row))
            tmax(row) = max(trc(row),tmax(row))
            tmax(row) = max(tempmax,tmax(row))
            tmin(row) = minval(trl(indnd(1:n,row)))
            tempmax   = minval(trc(indnd(1:n,row)))
            tmin(row) = min(tmin(row),trl(row))
            tmin(row) = min(trc(row),tmin(row))
            tmin(row) = min(tempmax,tmin(row))
           ! Admissible increments
           tmax(row) = tmax(row) - trl(row)
           tmin(row) = tmin(row) - trl(row)
        enddo
       
        !=========================
        ! Sums of positive/negative fluxes to node row
        !=========================
       
        icepplus = c0
        icepminus = c0
        do elem = 1, nx_elem
           elnodes = elnode(1:3,elem)
           do q = 1, 3
              n    = elnodes(q)
              flux = icefluxes(elem,q)
              if ( flux > 0 ) then
                 icepplus(n) = icepplus(n) + flux
              else
                 icepminus(n) = icepminus(n) + flux
              endif
           enddo
        enddo
       
        !========================
        ! The least upper bound for the correction factors
        !========================
    
        do n = 1, nx_nh
           flux = icepplus(n)
           if ( abs(flux) > 0 ) then
              icepplus(n) = min(1.0,tmax(n) / flux)
           else
              icepplus(n) = c0
           endif
       
           flux = icepminus(n)
           if ( abs(flux) > 0 ) then
              icepminus(n) = min(1.0,tmin(n) / flux)
           else
              icepminus(n) = c0
           endif
         enddo
       
         ! pminus and pplus are to be known to neighbouting PE
         call exchange_p2d(icepminus)
         call exchange_p2d(icepplus)
       
         !========================
         ! Limiting
         !========================
       
         do elem = 1, nx_elem
            elnodes = elnode(1:3,elem)
            ae = c1 !/ 10
            do q = 1, 3
               n    = elnodes(q)
               flux = icefluxes(elem,q)
               !if (sqrt(uvel(n)**2+vvel(n)**2).eq.0) ae=0
               if ( flux >=c0 ) ae = min(ae, icepplus(n))
               if ( flux < c0 ) ae = min(ae, icepminus(n))
               !if ( flux >=c0 ) then
               !   tempmax = minval(icepplus(indnd(1:nnp(n),n)))
               !   tempmax = min(icepplus(n),tempmax)
               !   ae = min(ae,tempmax)
               !endif
               !if ( flux < c0 ) then
               !   tempmax = minval(icepminus(indnd(1:nnp(n),n)))
               !   tempmax = min(icepminus(n),tempmax)
               !   ae = min(ae,tempmax)
               !endif
               !if(trc(elnodes(q))<10.and.trc(elnodes(q))>5) write(12,*) elem,n,trc(n),trl(n),rhs_tr(n)/lump_ice_matrix(n),d_tr(n),ae,icepplus(n),icepminus(n),flux
            enddo
            icefluxes(elem,:) = ae * icefluxes(elem,:)
         enddo
       
       
         !==========================
         ! Update the solution
         !==========================
         do elem = nx_elem_nh, nx_elem
            elnodes = elnode(1:3,elem)
            do q = 1, 3
               n = elnodes(q)
               !if(trc(elnodes(q))<20.and.trc(elnodes(q))>5) write(12,*) n, trc(n), trl(n), icefluxes(elem,q)
            enddo
         enddo
          do n = 1, nx_nh
             trc(n) = trl(n)
          end do
          call exchange_p2d(trc)
         
          do elem = 1, nx_elem_nh
             elnodes = elnode(1:3,elem)
             do q = 1, 3
                n = elnodes(q)
                trc(n) = trc(n) + icefluxes(elem,q)
             enddo
          enddo
          call exchange_p2d(trc)

         ! do n = 1, nx_nh
         !    if(trc(n)*trctmp(n)<0) trc(n) = trctmp(n)
         ! end do
          call exchange_p2d(trc)
       
          deallocate(tmin, tmax)
          deallocate(trctmp)
    
    end subroutine fem_fct_icepack
    
    !=======================================================================
    
    subroutine tg_rhs_div_icepack(trc)
    
        !use mod_mesh
        !use o_mesh
        !use o_param
        !use i_param
        !use g_parsup
        use mice_module
    
        implicit none
    
        real   (kind=dbl_kind)    :: diff, entries(3), um, vm, vol, dx(3), dy(3)
        integer(kind=int_kind)    :: n, q, row, elem, elnodes(3)
        real   (kind=dbl_kind)    :: c_1, c_2, c_3, c_4, c_x, entries2(3),entries3(3),utmp(3),vtmp(3)
        !type(t_mesh),        target,        intent(in)     :: mesh
        real(kind=dbl_kind), dimension(nx), intent(inout)  :: trc    

!#include "../associate_mesh.h"
    
        ! Computes the rhs in a Taylor-Galerkin way (with urrayspwind 
        ! type of correction for the advection operator).
        ! In this version I tr to split divergent term off, 
        ! so that FCT works without it.
    
        do row = 1, nx !=npa
           ! row=myList_nod2D(m)
           rhs_tr(row)    = c0
           rhs_trdiv(row) = c0
        enddo

        do elem = 1, nx_elem   !! assembling rhs over elements
                                  !! elem=myList_elem2D(m)

           elnodes = elnode(1:3,elem)
            do n = 1, 3
               !transform pframe to eframe
               utmp(n) = uvel(elnodes(n)) * dot_product(pframe(1:3,1,elnodes(n)),eframe(1:3,1,elem)) + vvel(elnodes(n)) * dot_product(pframe(1:3,2,elnodes(n)),eframe(1:3,1,elem))
               vtmp(n) = uvel(elnodes(n)) * dot_product(pframe(1:3,1,elnodes(n)),eframe(1:3,2,elem)) + vvel(elnodes(n)) * dot_product(pframe(1:3,2,elnodes(n)),eframe(1:3,2,elem))
           enddo
           ! Derivatives
           dx  = bafux(:,elem)
           dy  = bafuy(:,elem)
           vol = voltriangle(elem)
           um  = sum(utmp)
           vm  = sum(vtmp)
      
           ! This is exact computation (no assumption of u=const 
           ! on elements used in the standard version)
           c_1 = (um*um+sum(utmp(1:3)*utmp(1:3))) / 12.0_dbl_kind
           c_2 = (vm*vm+sum(vtmp(1:3)*vtmp(1:3))) / 12.0_dbl_kind
           c_3 = (um*vm+sum(vtmp(1:3)*utmp(1:3))) / 12.0_dbl_kind
           c_4 = sum(dx*utmp(1:3)+dy*vtmp(1:3))
      
           do n = 1, 3
              row = elnodes(n)
      
              do q = 1, 3
                 entries(q)  = vol*dt_dyn*((c1-p5*dt_dyn*c_4)*(dx(n)*(um+utmp(q))+ &
                               dy(n)*(vm+vtmp(q)))/12.0_dbl_kind                 - &
                               p5*dt_dyn*(c_1*dx(n)*dx(q)+c_2*dy(n)*dy(q)+c_3*(dx(n)*dy(q)+dx(q)*dy(n))))
                 entries2(q) = p5*dt_dyn*(dx(n)*(um+utmp(q))                     + &
                               dy(n)*(vm+vtmp(q))-dx(q)*(um+utmp(n))      - &
                               dy(q)*(vm+vtmp(n)))
                 entries3(q)=  vol*dt_dyn*(((dx(n)*(um+utmp(q)))+ dy(n)*(vm+vtmp(q)))/12.0_dbl_kind &
                               -p5*dt_dyn*(um*dx(n)+vm*dy(n))*(um*dx(q)+vm*dy(q))/9.0)

              enddo
              c_x = vol*dt_dyn*c_4*(sum(trc(elnodes))+trc(elnodes(n))+sum(entries2*trc(elnodes))) / 12.0_dbl_kind
              rhs_tr(row)    = rhs_tr(row) + sum(entries * trc(elnodes)) + c_x
              !rhs_tr(row)    = rhs_tr(row) + sum(entries3 * trc(elnodes)) 
              rhs_trdiv(row) = rhs_trdiv(row) - c_x
           enddo
        enddo
    
        call exchange_p2d(rhs_tr)
        call exchange_p2d(rhs_trdiv)
    end subroutine tg_rhs_div_icepack
    
    !=======================================================================
    
    subroutine update_for_div_icepack(trc)
    
        !use mod_mesh
        !use o_mesh
        !use o_param
        !use i_param
        !use g_parsup
        use mice_module
    
    
        implicit none
    
        integer(kind=int_kind)            :: n, i, clo, clo2, cn, &
                                             location(100), row,j
        real   (kind=dbl_kind)            :: rhs_new,sum1
        integer(kind=int_kind), parameter :: num_iter_solve=3
        !type(t_mesh),        target,        intent(in)     :: mesh
        real(kind=dbl_kind), dimension(nx), intent(inout)  :: trc
    
!#include "../associate_mesh.h"
    
        ! Computes Taylor-Galerkin solution
        ! first approximation

        d_tr(:)   = c0
        trl(:)    = c0

        do row = 1, nx_nh
           d_tr(row) = rhs_trdiv(row) / lump_ice_matrix(row)
        enddo
      
        call exchange_p2d(d_tr)
      
        ! Iterate
      
        do n = 1, num_iter_solve-1
           do row = 1, nx_nh
              !clo            = ssh_stiff%rowptr(row)   - ssh_stiff%rowptr(1) + 1
              !clo2           = ssh_stiff%rowptr(row+1) - ssh_stiff%rowptr(1)
              !cn             = clo2 - clo + 1
              !location(1:cn) = nn_pos(1:cn, row)
               sum1=ice_matrix(0,row)*d_tr(row)
            do j=1,nnp(row)
               clo = indnd(j,row)
               sum1=sum1+ice_matrix(j,row)*d_tr(clo)
            enddo !j
              rhs_new        = rhs_trdiv(row) - sum1
              trl(row)       = d_tr(row) + rhs_new / lump_ice_matrix(row)
           enddo
           do row = 1, nx_nh
              d_tr(row) = trl(row)
           enddo
           call exchange_p2d(d_tr)
        enddo
      
        trc = trc + d_tr

        call exchange_p2d(trc)
    
    end subroutine update_for_div_icepack 
    
    !=======================================================================
    
    subroutine fct_solve_icepack(trc)
        
        !use mod_mesh     
     
        implicit none

        real(kind=dbl_kind), dimension(nx), intent(inout) :: trc      
        !type(t_mesh),        target,        intent(in)    :: mesh
      
        ! Driving sequence
        call tg_rhs_div_icepack(trc)
        call solve_high_order_icepack(trc) ! uses arrays of low-order solutions as temp
                                                 ! storage. It should preceed the call of low
                                                 ! order solution.
        call solve_low_order_icepack(trc)
        call fem_fct_icepack(trc)
        call update_for_div_icepack(trc)

        trl(:)    = c0
        d_tr(:)   = c0
        rhs_tr(:) = c0
        rhs_trdiv(:)   = c0
        icefluxes(:,:) = c0

    end subroutine fct_solve_icepack

!=======================================================================
    
    subroutine tg_rhs_div_icepack_upwind(trc,trc_n)
    
        !use mod_mesh
        !use o_mesh
        !use o_param
        !use i_param
        !use g_parsup
        use mice_module
    
        implicit none
        integer (kind=int_kind), intent(in) :: trc_n
        real   (kind=dbl_kind)    :: diff, entries(3), um, vm, vol, dx(3), dy(3)
        integer(kind=int_kind)    :: n, q, row, elem, m, jj, indx, elnodes(3)
        real   (kind=dbl_kind)    :: c_1, c_2, c_3, c_4, c_x, entries2(3),entries3(3),utmp(3),vtmp(3)
        !type(t_mesh),        target,        intent(in)     :: mesh
        real(kind=dbl_kind), dimension(nx), intent(inout)  :: trc    

!#include "../associate_mesh.h"
    
        ! Computes the rhs in a Taylor-Galerkin way (with urrayspwind 
        ! type of correction for the advection operator).
        ! In this version I tr to split divergent term off, 
        ! so that FCT works without it.
    
        !do row = 1, nx !=npa
           ! row=myList_nod2D(m)
        !   rhs_tr(row)    = c0
        !   rhs_trdiv(row) = c0
        !enddo

        do elem = 1, nx_elem   !! assembling rhs over elements
                                  !! elem=myList_elem2D(m)

           elnodes = elnode(1:3,elem)
            do n = 1, 3
               !transform pframe to eframe
               utmp(n) = uvel(elnodes(n)) * dot_product(pframe(1:3,1,elnodes(n)),eframe(1:3,1,elem)) + vvel(elnodes(n)) * dot_product(pframe(1:3,2,elnodes(n)),eframe(1:3,1,elem))
               vtmp(n) = uvel(elnodes(n)) * dot_product(pframe(1:3,1,elnodes(n)),eframe(1:3,2,elem)) + vvel(elnodes(n)) * dot_product(pframe(1:3,2,elnodes(n)),eframe(1:3,2,elem))
           enddo
           ! Derivatives
           dx  = bafux(:,elem)
           dy  = bafuy(:,elem)
           vol = voltriangle(elem)
           um  = sum(utmp)
           vm  = sum(vtmp)
      
           ! This is exact computation (no assumption of u=const 
           ! on elements used in the standard version)
           c_1 = (um*um+sum(utmp(1:3)*utmp(1:3))) / 12.0_dbl_kind
           c_2 = (vm*vm+sum(vtmp(1:3)*vtmp(1:3))) / 12.0_dbl_kind
           c_3 = (um*vm+sum(vtmp(1:3)*utmp(1:3))) / 12.0_dbl_kind
           c_4 = sum(dx*utmp(1:3)+dy*vtmp(1:3))
      
           do n = 1, 3
              row = elnodes(n)
      
              do q = 1, 3
                 entries(q)  = vol*dt_dyn*((c1-p5*dt_dyn*c_4)*(dx(n)*(um+utmp(q))+ &
                               dy(n)*(vm+vtmp(q)))/12.0_dbl_kind                 - &
                               p5*dt_dyn*(c_1*dx(n)*dx(q)+c_2*dy(n)*dy(q)+c_3*(dx(n)*dy(q)+dx(q)*dy(n))))
                 entries2(q) = p5*dt_dyn*(dx(n)*(um+utmp(q))                     + &
                               dy(n)*(vm+vtmp(q))-dx(q)*(um+utmp(n))      - &
                               dy(q)*(vm+vtmp(n)))
                 entries3(q)=  vol*dt_dyn*(((dx(n)*(um+utmp(q)))+ dy(n)*(vm+vtmp(q)))/12.0_dbl_kind &
                               -p5*dt_dyn*(um*dx(n)+vm*dy(n))*(um*dx(q)+vm*dy(q))/9.0)

              enddo
              c_x = vol*dt_dyn*c_4*(sum(trc(elnodes))+trc(elnodes(n))+sum(entries2*trc(elnodes))) / 12.0_dbl_kind
              !rhs_tr(row)    = rhs_tr(row) + sum(entries * trc(elnodes)) + c_x
              !rhs_tr(row)    = rhs_tr(row) + sum(entries3 * trc(elnodes)) 
               indx=0
                  do m=1,nne(row)
                  if(indel(m,row)==elem) then
                     indx=m; exit
                  endif
                  enddo !m
                  if(indx==0) call parallel_abort('STEP: failed to find (tg_rhs_div_icepack_upwind)')  
              flux_matrix0(1,indx,row,trc_n) = entries3(1) * trc(elnodes(1))/ lump_ice_matrix(row)
              flux_matrix0(2,indx,row,trc_n) = entries3(2) * trc(elnodes(2))/ lump_ice_matrix(row)
              flux_matrix0(3,indx,row,trc_n) = entries3(3) * trc(elnodes(3))/ lump_ice_matrix(row)
              !rhs_trdiv(row) = rhs_trdiv(row) - c_x
           enddo
        enddo
    

    end subroutine tg_rhs_div_icepack_upwind
    
    !=======================================================================
    
    subroutine upwind_icepack(trc,trc_n)
        
        !use mod_mesh     
     
        implicit none
        integer (kind=int_kind), intent(in) :: trc_n
        real(kind=dbl_kind), dimension(nx), intent(inout) :: trc  
        real   (kind=dbl_kind)            :: fluxchan1,fluxchan2,suma,xctr2,yctr2,vnor1,vnor2,&
                                             & tmpx2,tmpx3,tmpy2,tmpy3,utmp,vtmp,xtmp,ytmp,vnorm,&
                                             & trctmp, trcmin, trcmax   
        integer (kind=int_kind) :: i,j,ie,id,id2,id3,isd3,isd2,     &
                                   m,n1,n2,jj,indx,nd
        logical (kind=log_kind) :: flag_noadv
         real(rkind) :: swild10(3,2),swild(3),swild2(3,2),trl0(nx),d_tr0(nx)
        !type(t_mesh),        target,        intent(in)    :: mesh

      trl0(:) = c0
      d_tr0(:) = trc(:)
      flux_matrix1(:,:,trc_n) = c0
      flux_matrix2(:,:,trc_n) = c0
      flux_matrix3(:,:,trc_n) = c0
      flux_matrix4(:,:,trc_n) = c0
      flux_matrix0(:,:,:,trc_n) = c0
        ! Driving sequence
      do i=1,nx_nh
         fluxchan2=0.d0 !sum of fluxes;
        if(idry(i)==1) cycle
        !if(isbnd(1,i)/=0) cycle
        !if(any(isbnd(1,indnd(1:nnp(i),i))/=0)) cycle
        !Wet node
          fluxchan1=0.d0 !sum of fluxes;\int_\Gamma u*u_n d\Gamma
          
          suma=0.d0 !sum of areas
          aream(i) = 0
          do j=1,nne(i)
            ie=indel(j,i)
            if(idry_e(ie)==1) cycle
            suma=suma+area(ie)/3 !approx for quad
            !Wet elem
            
            id=iself(j,i)
            id3=nxq(i34(ie)-1,id,i34(ie)) !adjacent side index
            id2=nxq(i34(ie)-2,id,i34(ie)) !adjacent side index
            isd3=elside(id3,ie)
            isd2=elside(id2,ie)

            do m=1,i34(ie) !side
                n1=isidenode(1,elside(m,ie))
                n2=isidenode(2,elside(m,ie))
                !swild10(m,1) = 0.5*(uvel(n1)*trc(n1)*dot_product(pframe(:,1,n1),sframe2(:,1,elside(m,ie)))+vvel(n1)*trc(n1)*dot_product(pframe(:,2,n1),sframe2(:,1,elside(m,ie)))&
                !                 &+uvel(n2)*trc(n2)*dot_product(pframe(:,1,n2),sframe2(:,1,elside(m,ie)))+vvel(n2)*trc(n2)*dot_product(pframe(:,2,n1),sframe2(:,1,elside(m,ie))))
                !swild10(m,2) = 0.5*(uvel(n1)*trc(n1)*dot_product(pframe(:,1,n1),sframe2(:,2,elside(m,ie)))+vvel(n1)*trc(n1)*dot_product(pframe(:,2,n1),sframe2(:,2,elside(m,ie)))&
                !                 &+uvel(n2)*trc(n2)*dot_product(pframe(:,1,n2),sframe2(:,2,elside(m,ie)))+vvel(n2)*trc(n2)*dot_product(pframe(:,2,n1),sframe2(:,2,elside(m,ie))))
                swild10(m,1) = 0.5*(uvel(n1)*dot_product(pframe(:,1,n1),sframe2(:,1,elside(m,ie)))+vvel(n1)*dot_product(pframe(:,2,n1),sframe2(:,1,elside(m,ie)))&
                                 &+uvel(n2)*dot_product(pframe(:,1,n2),sframe2(:,1,elside(m,ie)))+vvel(n2)*dot_product(pframe(:,2,n2),sframe2(:,1,elside(m,ie))))
                swild10(m,2) = 0.5*(uvel(n1)*dot_product(pframe(:,1,n1),sframe2(:,2,elside(m,ie)))+vvel(n1)*dot_product(pframe(:,2,n1),sframe2(:,2,elside(m,ie)))&
                                 &+uvel(n2)*dot_product(pframe(:,1,n2),sframe2(:,2,elside(m,ie)))+vvel(n2)*dot_product(pframe(:,2,n2),sframe2(:,2,elside(m,ie))))
                !swild10(m,1) = 0.5*(uvel(n1)*dot_product(pframe(:,1,n1),eframe(:,1,ie))+vvel(n1)*dot_product(pframe(:,2,n1),eframe(:,1,ie))&
                !                 &+uvel(n2)*dot_product(pframe(:,1,n2),eframe(:,1,ie))+vvel(n2)*dot_product(pframe(:,2,n2),eframe(:,1,ie)))
                !swild10(m,2) = 0.5*(uvel(n1)*dot_product(pframe(:,1,n1),eframe(:,2,ie))+vvel(n1)*dot_product(pframe(:,2,n1),eframe(:,2,ie))&
                !                 &+uvel(n2)*dot_product(pframe(:,1,n2),eframe(:,2,ie))+vvel(n2)*dot_product(pframe(:,2,n2),eframe(:,2,ie)))                      
                swild(m) = (trc(n1)+trc(n2))*0.5
                swild2(m,1) = uvel(elnode(m,ie))*dot_product(pframe(:,1,elnode(m,ie)),eframe(:,1,ie))+vvel(elnode(m,ie))*dot_product(pframe(:,2,elnode(m,ie)),eframe(:,1,ie))
                swild2(m,2) = uvel(elnode(m,ie))*dot_product(pframe(:,1,elnode(m,ie)),eframe(:,2,ie))+vvel(elnode(m,ie))*dot_product(pframe(:,2,elnode(m,ie)),eframe(:,2,ie))
            enddo
            !utmp=sum(swild10(1:i34(ie),1))/3 !vel @ centroid
            !vtmp=sum(swild10(1:i34(ie),2))/3 !vel @ centroid
            utmp=sum(swild2(1:i34(ie),1))/3 !vel @ centroid
            vtmp=sum(swild2(1:i34(ie),2))/3 !vel @ centroid
            trctmp=sum(swild(1:i34(ie)))/3
            trcmin = minval(trc(indnd(1:nnp(i),i)))
            trcmin = min(trcmin,trc(i))
            trcmax = maxval(trc(indnd(1:nnp(i),i)))
            trcmax = max(trcmax,trc(i))

            !Compute coord of side center and centroid (for ics=2)
            if(ics==1) then
              xctr2=xctr(ie); yctr2=yctr(ie)
              tmpx2=xcj(isd2); tmpy2=ycj(isd2)
              tmpx3=xcj(isd3); tmpy3=ycj(isd3)
            else !ll; use [xy]el defined in eframe
              xctr2=0.d0 !sum(xel(elnode(1:i34(ie),ie)))/i34(ie)
              yctr2=0.d0 !sum(yel(elnode(1:i34(ie),ie)))/i34(ie)
              tmpx3=(xel(id,ie)+xel(nxq(1,id,i34(ie)),ie))/2.d0
              tmpy3=(yel(id,ie)+yel(nxq(1,id,i34(ie)),ie))/2.d0
              tmpx2=(xel(id,ie)+xel(nxq(i34(ie)-1,id,i34(ie)),ie))/2.d0
              tmpy2=(yel(id,ie)+yel(nxq(i34(ie)-1,id,i34(ie)),ie))/2.d0
            endif !ics

            !1st segment
            !Normal dir x length
!            xtmp=yctr(ie)-ycj(isd3)
!            ytmp=xcj(isd3)-xctr(ie)
            xtmp=yctr2-tmpy3
            ytmp=tmpx3-xctr2
            vnor1=utmp*xtmp+vtmp*ytmp !normal vel x length 
            vnor2=swild10(id3,1)*xtmp+swild10(id3,2)*ytmp !normal vel@side x length 
            !fluxchan1=fluxchan1+(utmp*vnor1+swild10(id3,1)*vnor2)/2.d0
            !fluxchan2=fluxchan2+(vtmp*vnor1+swild10(id3,2)*vnor2)/2.d0
            !fluxchan1=fluxchan1+dt_dyn*(swild(id3)*vnor2)

            fluxchan1=fluxchan1+dt_dyn*(trctmp*vnor1+swild(id3)*vnor2)/2.d0
            !fluxchan1=fluxchan1+dt_dyn*(trctmp+swild(id3))*(vnor1+vnor2)/4.d0
            fluxchan2=fluxchan2+dt_dyn*(trctmp*vnor1+swild(id3)*vnor2)/2.d0
            flux_matrix1(j,i,trc_n) = dt_dyn*trctmp*vnor1
            flux_matrix2(j,i,trc_n) = dt_dyn*swild(id3)*vnor2
            suma = suma !+ dt_dyn*(vnor1+vnor2)/2.d0
            !if(isbs(isd3)>0) then !open bnd
            !  !vnorm=swild10(id3,1)*sframe(1,1,isd3)+swild10(id3,2)*sframe(2,1,isd3) !outer normal vel
            !  vnorm=swild(id3)*swild10(id3,1)*snx(isd3)+swild(id3)*swild10(id3,2)*sny(isd3) !outer normal vel
            !  fluxchan1=fluxchan1+dt_dyn*vnorm*distj(isd3)/2.d0
            !  fluxchan2=fluxchan2+dt_dyn*vnorm*distj(isd3)/2.d0
            !endif !isbs>0
            
            !2nd segment
            !Normal dir x length
!            xtmp=ycj(isd2)-yctr(ie)
!            ytmp=xctr(ie)-xcj(isd2)
            xtmp=tmpy2-yctr2
            ytmp=xctr2-tmpx2
            vnor1=utmp*xtmp+vtmp*ytmp !normal vel x length
            vnor2=swild10(id2,1)*xtmp+swild10(id2,2)*ytmp !normal vel x length


            !fluxchan1=fluxchan1+dt_dyn*(swild(id2)*vnor2)
            fluxchan1=fluxchan1+dt_dyn*(trctmp*vnor1+swild(id2)*vnor2)/2.d0
            !fluxchan1=fluxchan1+dt_dyn*(trctmp+swild(id2))*(vnor1+vnor2)/4.d0
            fluxchan2=fluxchan2+dt_dyn*(trctmp*vnor1+swild(id2)*vnor2)/2.d0
            flux_matrix3(j,i,trc_n) = dt_dyn*trctmp*vnor1
            flux_matrix4(j,i,trc_n) = dt_dyn*swild(id2)*vnor2
            suma = suma !+ dt_dyn*(vnor1+vnor2)/2.d0
            !if(isbs(isd2)>0) then !open bnd
            ! !vnorm=swild10(id2,1)*sframe(1,1,isd2)+swild10(id2,2)*sframe(2,1,isd2) !outer normal
            !  vnorm=swild(id2)*swild10(id2,1)*snx(isd2)+swild(id2)*swild10(id2,2)*sny(isd2) !outer normal
            !  fluxchan1=fluxchan1+dt_dyn*vnorm*distj(isd2)/2.d0
            !  fluxchan2=fluxchan2+dt_dyn*vnorm*distj(isd2)/2.d0
            !endif !isbs>0
          enddo !j=1,nne(i)
          if(suma<0) write(12,*) i,suma,vnor1,vnor2
          if(suma/=0) then
            trl0(i)=fluxchan1/suma !m/s/s
            !trl0(i)=fluxchan1/aream(i) !m/s/s
            aream(i) = suma
            !d_tr(i)=fluxchan2/suma
          endif !suma/=0

      enddo !i=1,np
      call exchange_p2d(trc)
      call exchange_p2d(d_tr0)
      call exchange_p2d(trl0)

      do i = 1,nx_nh
       trc(i) = d_tr0(i) - trl0(i) !+ d_tr(i)

       if(trc(i)>10.or.trc(i)<-10) then
         write(12,*)'upwind mystery',i,trc(i),d_tr0(i),trl0(i)
            flux_matrix1(:,i,trc_n) = 0
            flux_matrix2(:,i,trc_n) = 0
            flux_matrix3(:,i,trc_n) = 0
            flux_matrix4(:,i,trc_n) = 0
            trc(i) = d_tr0(i)
            do j=1,nne(i)
               ie=indel(j,i)
               id=iself(j,i)
               !id=indnd(j,i)
               do jj=1,2 !other 2 nodes
                  nd=elnode(nxq(jj,id,i34(ie)),ie)
                  indx=0
                  do m=1,nne(nd)
                  if(indel(m,nd)==ie) then
                     indx=m; exit
                  endif
                  enddo !m
                  if(indx==0) call parallel_abort('STEP: failed to find (9.1)')  
                  flux_matrix1(indx,nd,trc_n) = 0
                  flux_matrix2(indx,nd,trc_n) = 0
                  flux_matrix3(indx,nd,trc_n) = 0
                  flux_matrix4(indx,nd,trc_n) = 0
               enddo
            enddo
         endif
      enddo
      call exchange_p2d(trc)
    end subroutine upwind_icepack

    !=======================================================================
subroutine upwind_icepack_other(trc,trc_o,trc_n,trc_d,trc_d1,trc_d2)
        
        !use mod_mesh     
     
        implicit none
        integer (kind=int_kind), intent(in) :: trc_n,trc_d
        real (kind=dbl_kind), dimension(nx), intent(inout) :: trc   ,trc_o
        real (kind=dbl_kind), dimension(nx), intent(in), optional :: trc_d1,trc_d2
        real   (kind=dbl_kind)            :: fluxchan1,fluxchan2,suma,xctr2,yctr2,vnor1,vnor2,&
                                             & tmpx2,tmpx3,tmpy2,tmpy3,utmp,vtmp,xtmp,ytmp,vnorm,&
                                             & trctmp  , trcmin, trcmax   
        integer (kind=int_kind) :: i,j,ie,id,id2,id3,isd3,isd2,     &
                                   m,n1,n2,jj
        logical (kind=log_kind) :: flag_noadv
         real(rkind) :: swild10(3,2),swild(3),trl0(nx),d_tr0(nx)
        !type(t_mesh),        target,        intent(in)    :: mesh

      trl0(:) = c0
      d_tr0(:) = trc(:)
      flux_matrix1(:,:,trc_n) = c0
      flux_matrix2(:,:,trc_n) = c0
      flux_matrix3(:,:,trc_n) = c0
      flux_matrix4(:,:,trc_n) = c0
      flux_matrix0(:,:,:,trc_n) = c0
        ! Driving sequence
      do i=1,nx_nh
        if(idry(i)==1) cycle
        !if(isbnd(1,i)/=0) cycle
        !Wet node
          fluxchan1=0.d0 !sum of fluxes;\int_\Gamma u*u_n d\Gamma
          fluxchan2=0.d0 !sum of fluxes;
          suma=0.d0 !sum of areas
          do j=1,nne(i)
            ie=indel(j,i)
            if(idry_e(ie)==1) cycle
 
            !Wet elem
            suma=suma+area(ie)/3 !approx for quad
            id=iself(j,i)
            id3=nxq(i34(ie)-1,id,i34(ie)) !adjacent side index
            id2=nxq(i34(ie)-2,id,i34(ie)) !adjacent side index
            isd3=elside(id3,ie)
            isd2=elside(id2,ie)

            do m=1,i34(ie) !side
                n1=isidenode(1,elside(m,ie))
                n2=isidenode(2,elside(m,ie))
                tmpx2 = trc_o(n1)
                tmpy2 = trc_o(n2)
                if (present(trc_d1)) then
                  tmpx2 = tmpx2 * trc_d1(n1)
                  tmpy2 = tmpy2 * trc_d1(n2)
                endif
                if (present(trc_d2)) then
                  tmpx2 = tmpx2 * trc_d2(n1)
                  tmpy2 = tmpy2 * trc_d2(n2)
                endif
                swild(m) = (tmpx2+tmpy2)*0.5
            enddo
            trctmp=sum(swild(1:i34(ie)))/3
            trcmin = minval(trc_o(indnd(1:nnp(i),i)))
            trcmin = min(trcmin,trc_o(i))
            trcmax = maxval(trc_o(indnd(1:nnp(i),i)))
            trcmax = max(trcmax,trc_o(i))

            !1st segment
            flux_matrix1(j,i,trc_n) = flux_matrix1(j,i,trc_d)*trctmp
            flux_matrix2(j,i,trc_n) = flux_matrix2(j,i,trc_d)*swild(id3)
            !fluxchan1=fluxchan1+(flux_matrix2(j,i,trc_d)*swild(id3))
            fluxchan1=fluxchan1+(flux_matrix1(j,i,trc_d)*trctmp+flux_matrix2(j,i,trc_d)*swild(id3))/2.d0
            !fluxchan1=fluxchan1+(flux_matrix1(j,i,trc_d)+flux_matrix2(j,i,trc_d))*(trctmp+swild(id3))/4.d0
             
            
            !2nd segment
            !Normal dir x length
!            xtmp=ycj(isd2)-yctr(ie)
!            ytmp=xctr(ie)-xcj(isd2)
            flux_matrix3(j,i,trc_n) = flux_matrix3(j,i,trc_d)*trctmp
            flux_matrix4(j,i,trc_n) = flux_matrix4(j,i,trc_d)*swild(id2)
            !fluxchan1=fluxchan1+(flux_matrix4(j,i,trc_d)*swild(id2))
            fluxchan1=fluxchan1+(flux_matrix3(j,i,trc_d)*trctmp+flux_matrix4(j,i,trc_d)*swild(id2))/2.d0
            !fluxchan1=fluxchan1+(flux_matrix3(j,i,trc_d)+flux_matrix4(j,i,trc_d))*(trctmp+swild(id2))/4.d0
          enddo !j=1,nne(i)
          
          if(suma/=0 .and. aream(i)/=0) then
            trl0(i)=fluxchan1/suma !m/s/s
            !trl0(i)=fluxchan1/aream(i) !m/s/s
            !d_tr(i)=fluxchan2/suma
          endif !suma/=0
      enddo !i=1,np
      call exchange_p2d(trc)
      call exchange_p2d(d_tr0)
      call exchange_p2d(trl0)
      do i = 1,nx_nh
       trc(i) = d_tr0(i) - trl0(i) !+ d_tr(i)
       !if(trc(i)*d_tr0(i)<0) write(12,*)'upwind_other mystery',i,trc(i),d_tr0(i),trl0(i)
       !if(trc(i)*d_tr(i)<0) trc(i) = d_tr(i)
      enddo

      call exchange_p2d(trc)
    end subroutine upwind_icepack_other

    !=======================================================================
    subroutine upwind_icepack_dep(trc,trc_o,trc_n,trc_d)
        
        !use mod_mesh     
     
        implicit none
        integer (kind=int_kind), intent(in) :: trc_n,trc_d
        real (kind=dbl_kind), dimension(nx), intent(inout) :: trc   ,trc_o
        real   (kind=dbl_kind)            :: fluxchan1,fluxchan2,suma,xctr2,yctr2,vnor1,vnor2,&
                                             & tmpx2,tmpx3,tmpy2,tmpy3,utmp,vtmp,xtmp,ytmp,vnorm,&
                                             & trctmp, trcmin, trcmax   
        integer (kind=int_kind) :: i,j,ie,id,id2,id3,isd3,isd2,     &
                                   m,n1,n2,jj,indx,nd
        logical (kind=log_kind) :: flag_noadv
         real(rkind) :: swild10(3,2),swild(3),trl0(nx),d_tr0(nx)
        !type(t_mesh),        target,        intent(in)    :: mesh

      trl0(:) = c0
      d_tr0(:) = trc(:)
      flux_matrix1(:,:,trc_n) = c0
      flux_matrix2(:,:,trc_n) = c0
      flux_matrix3(:,:,trc_n) = c0
      flux_matrix4(:,:,trc_n) = c0
      flux_matrix0(:,:,:,trc_n) = c0
        ! Driving sequence
      do i=1,nx_nh
        if(idry(i)==1) cycle
        !if(trc(i)<0.01) cycle
        !if(isbnd(1,i)/=0) cycle
        !Wet node
          fluxchan1=0.d0 !sum of fluxes;\int_\Gamma u*u_n d\Gamma
          fluxchan2=0.d0 !sum of fluxes;
          suma=0.d0 !sum of areas
          do j=1,nne(i)
            ie=indel(j,i)
            if(idry_e(ie)==1) cycle
 
            !Wet elem
            suma=suma+area(ie)/3 !approx for quad
            id=iself(j,i)
            id3=nxq(i34(ie)-1,id,i34(ie)) !adjacent side index
            id2=nxq(i34(ie)-2,id,i34(ie)) !adjacent side index
            isd3=elside(id3,ie)
            isd2=elside(id2,ie)

            do m=1,i34(ie) !side
                n1=isidenode(1,elside(m,ie))
                n2=isidenode(2,elside(m,ie))
                tmpx2 = trc_o(n1)
                tmpy2 = trc_o(n2)
                swild(m) = (tmpx2+tmpy2)*0.5
            enddo
            trctmp=sum(swild(1:i34(ie)))/3
            !1st segment
            flux_matrix1(j,i,trc_n) = flux_matrix1(j,i,trc_d)*trctmp
            flux_matrix2(j,i,trc_n) = flux_matrix2(j,i,trc_d)*swild(id3)
            !fluxchan1=fluxchan1+(flux_matrix2(j,i,trc_d)*swild(id3))
            fluxchan1=fluxchan1+(flux_matrix1(j,i,trc_d)*trctmp+flux_matrix2(j,i,trc_d)*swild(id3))/2.d0
            !fluxchan1=fluxchan1+(flux_matrix1(j,i,trc_d)+flux_matrix2(j,i,trc_d))*(trctmp+swild(id3))/4.d0
             
            
            !2nd segment
            !Normal dir x length
!            xtmp=ycj(isd2)-yctr(ie)
!            ytmp=xctr(ie)-xcj(isd2)
            flux_matrix3(j,i,trc_n) = flux_matrix3(j,i,trc_d)*trctmp
            flux_matrix4(j,i,trc_n) = flux_matrix4(j,i,trc_d)*swild(id2)
            !fluxchan1=fluxchan1+(flux_matrix4(j,i,trc_d)*swild(id2))
            fluxchan1=fluxchan1+(flux_matrix3(j,i,trc_d)*trctmp+flux_matrix4(j,i,trc_d)*swild(id2))/2.d0
            !fluxchan1=fluxchan1+(flux_matrix3(j,i,trc_d)+flux_matrix4(j,i,trc_d))*(trctmp+swild(id2))/4.d0
          enddo !j=1,nne(i)
          
          if(suma/=0 .and. aream(i)/=0) then
            trl0(i)=fluxchan1/suma !m/s/s
            !trl0(i)=fluxchan1/aream(i) !m/s/s
            !d_tr(i)=fluxchan2/suma
          endif !suma/=0
      enddo !i=1,np
      call exchange_p2d(trc)
      call exchange_p2d(d_tr0)
      call exchange_p2d(trl0)
      do i = 1,nx_nh
       trc(i) = d_tr0(i) - trl0(i) !+ d_tr(i)
         if(trc(i)<-100) then
         !write(12,*)'upwind mystery',i,trc(i),d_tr(i),trl(i)
            flux_matrix1(:,i,trc_n) = 0
            flux_matrix2(:,i,trc_n) = 0
            flux_matrix3(:,i,trc_n) = 0
            flux_matrix4(:,i,trc_n) = 0
            trc(i) = d_tr0(i)
            do j=1,nne(i)
               ie=indel(j,i)
               id=iself(j,i)
               !id=indnd(j,i)
               do jj=1,2 !other 2 nodes
                  nd=elnode(nxq(jj,id,i34(ie)),ie)
                  indx=0
                  do m=1,nne(nd)
                  if(indel(m,nd)==ie) then
                     indx=m; exit
                  endif
                  enddo !m
                  if(indx==0) call parallel_abort('STEP: failed to find (9.1)')  
                  flux_matrix1(indx,nd,trc_n) = 0
                  flux_matrix2(indx,nd,trc_n) = 0
                  flux_matrix3(indx,nd,trc_n) = 0
                  flux_matrix4(indx,nd,trc_n) = 0
               enddo
            enddo
         endif
      enddo

      call exchange_p2d(trc)
    end subroutine upwind_icepack_dep

!=======================================================================
    
    subroutine upwind_icepack2(trc,trc_n)
        
        !use mod_mesh     
     
        implicit none
        integer (kind=int_kind), intent(in) :: trc_n
        real(kind=dbl_kind), dimension(nx), intent(inout) :: trc  
        real   (kind=dbl_kind)            :: fluxchan1,fluxchan2,suma,xctr2,yctr2,vnor1,vnor2,&
                                             & tmpx2,tmpx3,tmpy2,tmpy3,utmp,vtmp,xtmp,ytmp,vnorm,&
                                             & trctmp, trcmin, trcmax   
        integer (kind=int_kind) :: i,j,ie,id,id2,id3,isd3,isd2,     &
                                   m,n1,n2,jj,indx,nd
        logical (kind=log_kind) :: flag_noadv
         real(rkind) :: swild10(3,2),swild(3),swild2(3,2),trl0(nx),d_tr0(nx)
        !type(t_mesh),        target,        intent(in)    :: mesh

      trl0(:) = c0
      d_tr0(:) = trc(:)
      flux_matrix0(:,:,:,trc_n) = c0
      call tg_rhs_div_icepack_upwind(trc,trc_n)
      do i = 1,nx_nh
         !if(isbnd(1,i)/=0) cycle
         !if(any(isbnd(1,indnd(1:nnp(i),i))/=0)) cycle
         fluxchan2=0.d0 !sum of fluxes;
         do j=1,nne(i)
            ie=indel(j,i)
            fluxchan2 = fluxchan2+sum(flux_matrix0(1:3,j,i,trc_n))
         enddo
            trc(i) = d_tr0(i) + fluxchan2 !+ d_tr(i)
         if(trc(i)<0) then 
            !write(12,*) i, trc(i), fluxchan2
            do j=1,nne(i)
               ie=indel(j,i)
               flux_matrix0(1:3,j,i,trc_n) = flux_matrix0(1:3,j,i,trc_n)*abs(d_tr0(i)/fluxchan2)
            enddo
            trc(i) = 0
         endif
       enddo
      call exchange_p2d(trc)
    end subroutine upwind_icepack2

    !=======================================================================
subroutine upwind_icepack_other2(trc,trc_o,trc_n,trc_d,trc_d1,trc_d2)
        
        !use mod_mesh     
     
        implicit none
        integer (kind=int_kind), intent(in) :: trc_n,trc_d
        real (kind=dbl_kind), dimension(nx), intent(inout) :: trc   ,trc_o
        real (kind=dbl_kind), dimension(nx), intent(in), optional :: trc_d1,trc_d2
        real   (kind=dbl_kind)            :: fluxchan1,fluxchan2,suma,xctr2,yctr2,vnor1,vnor2,&
                                             & tmpx2,tmpx3,tmpy2,tmpy3,utmp,vtmp,xtmp,ytmp,vnorm,&
                                             & trctmp  , trcmin, trcmax   
        integer (kind=int_kind) :: i,j,ie,id,id2,id3,isd3,isd2,     &
                                   m,n1,n2,jj
        logical (kind=log_kind) :: flag_noadv
         real(rkind) :: swild10(3,2),swild(3),trl0(nx),d_tr0(nx)
        !type(t_mesh),        target,        intent(in)    :: mesh

      trl0(:) = c0
      d_tr0(:) = trc(:)
      flux_matrix0(:,:,:,trc_n) = c0
        ! Driving sequence
      do i = 1,nx_nh
         !if(isbnd(1,i)/=0) cycle
         !if(any(isbnd(1,indnd(1:nnp(i),i))/=0)) cycle
         fluxchan2=0.d0 !sum of fluxes;
         do j=1,nne(i)
            ie=indel(j,i)
            !fluxchan2 = fluxchan2+sum(flux_matrix0(1:3,j,i,trc_d)*trc_o(elnode(1:3,ie)))
            do jj=1,3
               fluxchan2 = fluxchan2+flux_matrix0(jj,j,i,trc_d)*trc_o(elnode(jj,ie))
               flux_matrix0(jj,j,i,trc_n)=flux_matrix0(jj,j,i,trc_d)*trc_o(elnode(jj,ie))
            enddo
         enddo
         trc(i) = d_tr0(i) + fluxchan2 !+ d_tr(i)
       enddo

      call exchange_p2d(trc)
    end subroutine upwind_icepack_other2

    !=======================================================================
    subroutine upwind_icepack_dep2(trc,trc_o,trc_n,trc_d)
        
        !use mod_mesh     
     
        implicit none
        integer (kind=int_kind), intent(in) :: trc_n,trc_d
        real (kind=dbl_kind), dimension(nx), intent(inout) :: trc   ,trc_o
        real   (kind=dbl_kind)            :: fluxchan1,fluxchan2,suma,xctr2,yctr2,vnor1,vnor2,&
                                             & tmpx2,tmpx3,tmpy2,tmpy3,utmp,vtmp,xtmp,ytmp,vnorm,&
                                             & trctmp, trcmin, trcmax   
        integer (kind=int_kind) :: i,j,ie,id,id2,id3,isd3,isd2,     &
                                   m,n1,n2,jj,indx,nd
        logical (kind=log_kind) :: flag_noadv
         real(rkind) :: swild10(3,2),swild(3),trl0(nx),d_tr0(nx)

      trl0(:) = c0
      d_tr0(:) = trc(:)
      flux_matrix0(:,:,:,trc_n) = c0
        ! Driving sequence
      do i = 1,nx_nh
         !if(isbnd(1,i)/=0) cycle
         !if(any(isbnd(1,indnd(1:nnp(i),i))/=0)) cycle
         fluxchan2=0.d0 !sum of fluxes;
         do j=1,nne(i)
            ie=indel(j,i)
            !fluxchan2 = fluxchan2+sum(flux_matrix0(1:3,j,i,trc_d)*trc_o(elnode(1:3,ie)))
            do jj=1,3
               fluxchan2 = fluxchan2+flux_matrix0(jj,j,i,trc_d)*trc_o(elnode(jj,ie))
               flux_matrix0(jj,j,i,trc_n)=flux_matrix0(jj,j,i,trc_d)*trc_o(elnode(jj,ie))
            enddo
         enddo
         trc(i) = d_tr0(i) + fluxchan2
          if(trc(i)<0) then 
            do j=1,nne(i)
               ie=indel(j,i)
               flux_matrix0(1:3,j,i,trc_n) = flux_matrix0(1:3,j,i,trc_n)*abs(d_tr0(i)/fluxchan2)
            enddo
            trc(i) = 0
         endif
       enddo

      call exchange_p2d(trc)
    end subroutine upwind_icepack_dep2

    !=======================================================================
    module subroutine tracer_advection_icepack

        !use mod_mesh
        use mice_module
        use icepack_intfc,        only: icepack_aggregate
        use icepack_itd,          only: cleanup_itd
        use schism_glbl,          only: dt,nstep_ice
        !use g_config,             only: dt
        use icepack_intfc,         only: icepack_init_trcr
        implicit none
            
        integer (kind=int_kind) :: ntrcr, ntrace, narr, nbtrcr, i,     &
                                   nt,   nt1,    k,   n ,ktherm,narrays,it,ierr
        integer (kind=int_kind) :: nt_Tsfc, nt_qice, nt_qsno,                          & 
                                   nt_sice, nt_fbri, nt_iage, nt_FY, nt_alvl, nt_vlvl, &
                                   nt_apnd, nt_hpnd, nt_ipnd, nt_bgc_Nit, nt_bgc_S
        logical (kind=log_kind) :: tr_pond_topo, tr_pond_lvl, tr_pond_cesm,            &
                                   tr_pond,      tr_aero,     tr_FY,                   &
                                   tr_iage,      heat_capacity,  flag_old,             &
                                   flag_old_0
        real    (kind=dbl_kind) :: puny ,Tsfc ,rhos, Lfresh, jj, kk, njj, pi, trcmin, trcmax,totalicea,totaliceh, &
        total_a,total_h
      
        ! Tracer dependencies and additional arrays
         real (kind=dbl_kind), dimension(ncat) :: &
               tmp, exc
        integer (kind=int_kind), dimension(:),    allocatable    ::    &
                tracer_type    , & ! = 1, 2, or 3 (depends on 0, 1 or 2 other tracers)
                depend             ! tracer dependencies (see below)
      
        logical (kind=log_kind), dimension (:),   allocatable   ::     &
                has_dependents    ! true if a tracer has dependent tracers
      
        real (kind=dbl_kind),    dimension (:,:), allocatable ::       &
               works,works_old, vicen_init, aicen_init, vsnon_init, aicen_tmp
        real (kind=dbl_kind),    dimension (:), allocatable ::       &
               fiso_ocn,swild,swild1,swild2, iniflag
         real (kind=dbl_kind),    dimension (:,:,:), allocatable ::       &
         trcrn_ini

         real (kind=dbl_kind), dimension(nilyr) :: &
           qin            , & ! ice enthalpy (J/m3)
           qin_max        , & ! maximum ice enthalpy (J/m3)
           zTin               ! initial ice temperature
  
        real (kind=dbl_kind), dimension(nslyr) :: &
           qsn            , & ! snow enthalpy (J/m3)
           zTsn               ! initial snow temperature

        !type(t_mesh),        target,       intent(in)    :: mesh
           character(len=*), parameter :: subname = '(tracer_advection_icepack)'

        call icepack_query_parameters(heat_capacity_out=heat_capacity, ktherm_out=ktherm,    &
                                      puny_out=puny,rhos_out=rhos,                   &
                                      Lfresh_out=Lfresh  ,pi_out=pi)
        call icepack_query_tracer_sizes(ntrcr_out=ntrcr, nbtrcr_out=nbtrcr)
        call icepack_query_tracer_flags(                                  &
               tr_iage_out=tr_iage, tr_FY_out=tr_FY,                      &
               tr_aero_out=tr_aero, tr_pond_out=tr_pond,                  &
               tr_pond_cesm_out=tr_pond_cesm,                             &
               tr_pond_lvl_out=tr_pond_lvl, tr_pond_topo_out=tr_pond_topo)
        call icepack_query_tracer_indices(nt_Tsfc_out=nt_Tsfc, nt_qice_out=nt_qice, &
               nt_qsno_out=nt_qsno, nt_sice_out=nt_sice, nt_fbri_out=nt_fbri,       &
               nt_iage_out=nt_iage, nt_FY_out=nt_FY, nt_alvl_out=nt_alvl,           &
               nt_vlvl_out=nt_vlvl, nt_apnd_out=nt_apnd, nt_hpnd_out=nt_hpnd,       &
               nt_ipnd_out=nt_ipnd, nt_bgc_Nit_out=nt_bgc_Nit, nt_bgc_S_out=nt_bgc_S)
      
        narr   = 1 + ncat * (3 + ntrcr) ! max number of state variable arrays
      
        ! Allocate works array
        flag_old = .false.
        flag_old_0 = .false.

        if (allocated(works)) deallocate(works)
        if (allocated(works_old)) deallocate(works_old)
        allocate ( works(nx,narr) ) !(npa, max number of state variable arrays)
        allocate ( works_old(nx,narr) )
        allocate ( fiso_ocn(nx) )
        allocate ( swild(nx) )
        allocate ( swild1(nx) )
        allocate ( swild2(nx) )
        allocate ( iniflag(nx) )
        allocate (trcrn_ini(nx,ntrcr,ncat) )
        allocate (vicen_init(nx,ncat) )
        allocate (aicen_init(nx,ncat) )
        allocate (aicen_tmp(nx,ncat) )
        allocate (vsnon_init(nx,ncat) )
        works(:,:) = c0
        works_old(:,:) = c0
        fiso_ocn(:) = c0
        swild(:) = c0
        swild1(:) = c0
        swild2(:) = c0
        totalicea = 0
        totaliceh = 0
        do i=1,nx_nh
         totalicea = totalicea + aice(i)*lump_ice_matrix(i)
         !totaliceh = totaliceh + aice(i)*vice(i)*lump_ice_matrix(i)
         totaliceh = totaliceh + vice(i)*lump_ice_matrix(i)
        enddo
        !write(12,*) 'before advec. ice ', totalicea,totaliceh
        call mpi_allreduce(totalicea,total_a,1,rtype,MPI_SUM,comm,ierr)
        call mpi_allreduce(totaliceh,total_h,1,rtype,MPI_SUM,comm,ierr)
        if(myrank == 0) write(16,*) 'before advec. ice ',total_a,total_h
        trcrn_ini=trcrn
        vicen_init=vicen
        aicen_init=aicen
        vsnon_init=vsnon

        call state_to_work (ntrcr, narr, works(:,:))
         works_old=works
        ! Advect each tracer
      
        do nt = 1, narr    
              call fct_solve_icepack (works(:,nt) )
        end do
        !call fct_solve_icepack (works(:,1) )
        !narrays = 1
        ! do nt = 1, ncat
        !    call fct_solve_icepack (works(:,narrays+1) ) 
        !    call fct_solve_icepack (works(:,narrays+2) )  
        !    call fct_solve_icepack (works(:,narrays+3) )  
        !    narrays = narrays + 3 + ntrcr
        ! enddo

        !do nt = 1, narr    
        !      call upwind_icepack (works(:,nt) )
        !end do
        
        newwork(:) = c0
         !do i = 1, nx
         !   if(ylat2(i)/pi*180>89.5) works(i,:) = works_old(i,:)
         !enddo
        call work_to_state (ntrcr, narr, works(:,:))
        iniflag(:) = c0
         do nt = 1, ncat
            do it = 1, ntrcr

               do i=1,nx_nh
                  trcmin = minval(trcrn_ini(indnd(1:nnp(i),i),it,nt))
                  trcmin = min(trcmin,trcrn_ini(i,it,nt))
                  trcmax = maxval(trcrn_ini(indnd(1:nnp(i),i),it,nt))
                  trcmax = max(trcmax,trcrn_ini(i,it,nt))
                  if(trcrn(i,it,nt) > trcmax) iniflag(i) = 1 !trcrn(i,it,nt) = trcrn_ini(i,it,nt) !trcrn_ini(i,it,nt) !trcmax
                  if(trcrn(i,it,nt) < trcmin) iniflag(i) = 1 !trcrn(i,it,nt) = trcrn_ini(i,it,nt) !trcrn_ini(i,it,nt) !trcmin
               enddo
            enddo
         enddo

         call exchange_p2d(iniflag)
         
         do nt = 1, ncat
            do it = 1, ntrcr

               do i=1,nx
                  if(iniflag(i) > 0) trcrn(i,it,nt) = trcrn_ini(i,it,nt)
               enddo

               !swild=trcrn(:,it,nt)
               !call exchange_p2d(swild)
               !trcrn(:,it,nt)=swild
               
            enddo
         enddo
        ! cut off icepack
      
         call cut_off_icepack
       
        do i=1,nx
           !if (ncat < 0) then ! Do we really need this?
              call cleanup_itd  (dt*nstep_ice,           ntrcr,                &
                                 nilyr,                  nslyr,                &
                                 ncat,                   hin_max(:),           &
                                 aicen(i,:),             trcrn(i,1:ntrcr,:),   &
                                 vicen(i,:),             vsnon(i,:),           &
                                 aice0(i),               aice(i),              &
                                 n_aero,                                       &
                                 nbtrcr,                 nblyr,                &
                                 tr_aero,                                      &
                                 tr_pond_topo,                                 &
                                 heat_capacity,                                &
                                 first_ice(i,:),                               &
                                 trcr_depend(1:ntrcr),   trcr_base(1:ntrcr,:), &
                                 n_trcr_strata(1:ntrcr), nt_strata(1:ntrcr,:), &
                                 fpond(i),               fresh(i),             &
                                 fsalt(i),               fhocn(i),             &
                                 faero_ocn(i,:),         fiso_ocn,          &
                                 fzsal(i),               flux_bio(i,1:nbtrcr))
      
              call icepack_aggregate (ncat,                    &
                                     aicen(i,:),               &
                                     trcrn(i,1:ntrcr,:),       &
                                     vicen(i,:),               &
                                     vsnon(i,:),               &
                                     aice (i),                 &
                                     trcr (i,1:ntrcr),         &
                                     vice (i),                 &
                                     vsno (i),                 &
                                     aice0(i),                 &
                                     ntrcr,                    &
                                     trcr_depend  (1:ntrcr),   &
                                     trcr_base    (1:ntrcr,:), &
                                     n_trcr_strata(1:ntrcr),   &
                                     nt_strata    (1:ntrcr,:))
           !endif
        end do
        totalicea = 0
        totaliceh = 0
        do i=1,nx_nh
         totalicea = totalicea + aice(i)*lump_ice_matrix(i)
         !totaliceh = totaliceh + aice(i)*vice(i)*lump_ice_matrix(i)
         totaliceh = totaliceh + vice(i)*lump_ice_matrix(i)
        enddo
        !write(12,*) 'after advec. ice ', totalicea,totaliceh
        call mpi_allreduce(totalicea,total_a,1,rtype,MPI_SUM,comm,ierr)
        call mpi_allreduce(totaliceh,total_h,1,rtype,MPI_SUM,comm,ierr)
        if(myrank == 0) write(16,*) 'after advec. ice ',total_a,total_h
        deallocate(works)
        deallocate(works_old)
        deallocate(trcrn_ini)
        deallocate(vicen_init)
        deallocate(aicen_init)
        deallocate(vsnon_init)
        deallocate(swild)
        deallocate(swild1)
        deallocate(swild2)

    end subroutine tracer_advection_icepack

    !=======================================================================
    module subroutine tracer_advection_icepack2

        !use mod_mesh
        use mice_module
        use icepack_intfc,        only: icepack_aggregate
        use icepack_itd,          only: cleanup_itd
        use schism_glbl,          only: dt,nstep_ice
        !use g_config,             only: dt
        use icepack_intfc,         only: icepack_init_trcr
        implicit none
            
        integer (kind=int_kind) :: ntrcr, ntrace, narr, nbtrcr, i,     &
                                   nt,   nt1,    k,   n ,ktherm,narrays,it,ierr
        integer (kind=int_kind) :: nt_Tsfc, nt_qice, nt_qsno,                          & 
                                   nt_sice, nt_fbri, nt_iage, nt_FY, nt_alvl, nt_vlvl, &
                                   nt_apnd, nt_hpnd, nt_ipnd, nt_bgc_Nit, nt_bgc_S
        logical (kind=log_kind) :: tr_pond_topo, tr_pond_lvl, tr_pond_cesm,            &
                                   tr_pond,      tr_aero,     tr_FY,                   &
                                   tr_iage,      heat_capacity,  flag_old,             &
                                   flag_old_0
        real    (kind=dbl_kind) :: puny ,Tsfc ,rhos, Lfresh, jj, kk, njj, pi, trcmin, trcmax,totalicea,totaliceh, &
        total_a,total_h
      
        ! Tracer dependencies and additional arrays
         real (kind=dbl_kind), dimension(ncat) :: &
               tmp, exc
        integer (kind=int_kind), dimension(:),    allocatable    ::    &
                tracer_type    , & ! = 1, 2, or 3 (depends on 0, 1 or 2 other tracers)
                depend             ! tracer dependencies (see below)
      
        logical (kind=log_kind), dimension (:),   allocatable   ::     &
                has_dependents    ! true if a tracer has dependent tracers
      
        real (kind=dbl_kind),    dimension (:,:), allocatable ::       &
               works,works_old, vicen_init, aicen_init, vsnon_init, aicen_tmp, iniflag
        real (kind=dbl_kind),    dimension (:), allocatable ::       &
               fiso_ocn,swild,swild1,swild2
         real (kind=dbl_kind),    dimension (:,:,:), allocatable ::       &
         trcrn_ini

         real (kind=dbl_kind), dimension(nilyr) :: &
           qin            , & ! ice enthalpy (J/m3)
           qin_max        , & ! maximum ice enthalpy (J/m3)
           zTin               ! initial ice temperature
  
        real (kind=dbl_kind), dimension(nslyr) :: &
           qsn            , & ! snow enthalpy (J/m3)
           zTsn               ! initial snow temperature

        !type(t_mesh),        target,       intent(in)    :: mesh
           character(len=*), parameter :: subname = '(tracer_advection_icepack2)'

        call icepack_query_parameters(heat_capacity_out=heat_capacity, ktherm_out=ktherm,    &
                                      puny_out=puny,rhos_out=rhos,                   &
                                      Lfresh_out=Lfresh  ,pi_out=pi)
        call icepack_query_tracer_sizes(ntrcr_out=ntrcr, nbtrcr_out=nbtrcr)
        call icepack_query_tracer_flags(                                  &
               tr_iage_out=tr_iage, tr_FY_out=tr_FY,                      &
               tr_aero_out=tr_aero, tr_pond_out=tr_pond,                  &
               tr_pond_cesm_out=tr_pond_cesm,                             &
               tr_pond_lvl_out=tr_pond_lvl, tr_pond_topo_out=tr_pond_topo)
        call icepack_query_tracer_indices(nt_Tsfc_out=nt_Tsfc, nt_qice_out=nt_qice, &
               nt_qsno_out=nt_qsno, nt_sice_out=nt_sice, nt_fbri_out=nt_fbri,       &
               nt_iage_out=nt_iage, nt_FY_out=nt_FY, nt_alvl_out=nt_alvl,           &
               nt_vlvl_out=nt_vlvl, nt_apnd_out=nt_apnd, nt_hpnd_out=nt_hpnd,       &
               nt_ipnd_out=nt_ipnd, nt_bgc_Nit_out=nt_bgc_Nit, nt_bgc_S_out=nt_bgc_S)
      
        narr   = 1 + ncat * (3 + ntrcr) ! max number of state variable arrays
      
        ! Allocate works array
        flag_old = .false.
        flag_old_0 = .false.

        if (allocated(works)) deallocate(works)
        if (allocated(works_old)) deallocate(works_old)
        allocate ( works(nx,narr) ) !(npa, max number of state variable arrays)
        allocate ( works_old(nx,narr) )
        allocate ( fiso_ocn(nx) )
        allocate ( swild(nx) )
        allocate ( swild1(nx) )
        allocate ( swild2(nx) )
        allocate ( iniflag(nx,ncat) )
        allocate (trcrn_ini(nx,ntrcr,ncat) )
        allocate (vicen_init(nx,ncat) )
        allocate (aicen_init(nx,ncat) )
        allocate (aicen_tmp(nx,ncat) )
        allocate (vsnon_init(nx,ncat) )
        works(:,:) = c0
        works_old(:,:) = c0
        fiso_ocn(:) = c0
        swild(:) = c0
        swild1(:) = c0
        swild2(:) = c0

        totalicea = 0
        totaliceh = 0
        do i=1,nx_nh
         totalicea = totalicea + aice(i)*lump_ice_matrix(i)
         !totaliceh = totaliceh + aice(i)*vice(i)*lump_ice_matrix(i)
         totaliceh = totaliceh + vice(i)*lump_ice_matrix(i)
        enddo
        call mpi_allreduce(totalicea,total_a,1,rtype,MPI_SUM,comm,ierr)
        call mpi_allreduce(totaliceh,total_h,1,rtype,MPI_SUM,comm,ierr)
        if(myrank == 0) write(16,*) 'before advec. ice ',total_a,total_h

        trcrn_ini=trcrn
        vicen_init=vicen
        aicen_init=aicen
        vsnon_init=vsnon

        call state_to_work (ntrcr, narr, works(:,:))
         works_old=works
        ! Advect each tracer
      
        !do nt = 1, narr    
        !      call upwind_icepack (works(:,nt) )
        !end do
!upwind2
        call upwind_icepack2 (works(:,1),1 )
        narrays = 1
         do nt = 1, ncat
            call upwind_icepack2 (works(:,narrays+1),narrays+1 ) 
            aicen_tmp(:,nt) = works(:,narrays+1)
            narrays = narrays + 3 + ntrcr
         enddo

         !do i = 1, nx  ! For each grid cell
         !  if (sum(aicen_tmp(i,:)) > c1) then
         !     tmp(:) = c0
         !     exc(:) = c0
         !     do n = 1, ncat
         !        if (aicen_tmp(i,n) > puny) tmp(n) = c1
         !     end do
         !     do n = 1, ncat
         !         exc(n) = max(c0,(sum(aicen_tmp(i,:)) - c1 + puny))  &
         !                  * aicen_tmp(i,n) / sum(aicen_tmp(i,:))
         !     end do
         !     do n = 1, ncat
         !        aicen_tmp(i,n) = max(c0,aicen_tmp(i,n) - exc(n))
         !     end do
         !        aice0      = max(c0,1-sum(aicen_tmp(i,:)))
         !        if (sum(aicen_tmp(i,:)) > c1) write(12,*) 'here1',sum(aicen_tmp(i,:)),aicen_tmp(i,:)
         !  end if
         !end do

         narrays = 1
         do nt = 1, ncat
         !   do i = 1, nx_nh
         !      if(works(i,narrays+1) > puny) then
         !         flux_matrix1(:,i,narrays+1) = flux_matrix1(:,i,narrays+1) / works(i,narrays+1) * aicen_tmp(i,nt) 
         !         flux_matrix2(:,i,narrays+1) = flux_matrix2(:,i,narrays+1) / works(i,narrays+1) * aicen_tmp(i,nt) 
         !         flux_matrix3(:,i,narrays+1) = flux_matrix3(:,i,narrays+1) / works(i,narrays+1) * aicen_tmp(i,nt) 
         !         flux_matrix4(:,i,narrays+1) = flux_matrix4(:,i,narrays+1) / works(i,narrays+1) * aicen_tmp(i,nt) 
         !         flux_matrix0(:,:,i,narrays+1) = flux_matrix0(:,:,i,narrays+1) / works(i,narrays+1) * aicen_tmp(i,nt) 
         !      endif
         !      works(i,narrays+1) = aicen_tmp(i,nt) 
         !   enddo
         !   swild = works(:,narrays+1)
         !   call exchange_p2d(swild)
         !   works(:,narrays+1) = swild
            !call upwind_icepack (works(:,narrays+2),narrays+2 )  
            !call upwind_icepack (works(:,narrays+3),narrays+3 )
            do i = 1, nx
               if(aicen(i,nt)<puny.or.vicen(i,nt)<puny) then
                  swild1(i) = 0
                  swild2(i) = 0
               else
                  swild1(i) = vicen(i,nt)/aicen(i,nt)
                  swild2(i) = vsnon(i,nt)/aicen(i,nt)
               endif
            enddo
            call upwind_icepack_dep2(works(:,narrays+2),swild1,narrays+2,narrays+1)
            call upwind_icepack_dep2(works(:,narrays+3),swild2,narrays+3,narrays+1) 
            narrays = narrays + 3 + ntrcr
         enddo

         

        call work_to_other2  (ntrcr, narr, works(:,:)) 
        

        newwork(:) = c0
         !do i = 1, nx
         !   if(ylat2(i)/pi*180>89.5) works(i,:) = works_old(i,:)
         !enddo
        call work_to_state (ntrcr, narr, works(:,:))
        iniflag(:,:) = c0
         do nt = 1, ncat
            do it = 1, ntrcr
        
               do i=1,nx_nh
                  trcmin = minval(trcrn_ini(indnd(1:nnp(i),i),it,nt))
                  trcmin = min(trcmin,trcrn_ini(i,it,nt))
                  trcmax = maxval(trcrn_ini(indnd(1:nnp(i),i),it,nt))
                  trcmax = max(trcmax,trcrn_ini(i,it,nt))
                  if(trcrn(i,it,nt) > trcmax) iniflag(i,nt) = 1 !trcrn(i,it,nt) = trcrn_ini(i,it,nt) !trcrn_ini(i,it,nt) !trcmax
                  if(trcrn(i,it,nt) < trcmin) iniflag(i,nt) = 1 !trcrn(i,it,nt) = trcrn_ini(i,it,nt) !trcrn_ini(i,it,nt) !trcmin
               enddo
            enddo
         enddo
         do nt = 1, ncat
            swild = iniflag(:,nt)
            call exchange_p2d(swild)
            iniflag(:,nt) = swild
         enddo
         do nt = 1, ncat
            !do it = 1, ntrcr

               do i=1,nx
                  if(iniflag(i,nt) > 0) then
                     !vicen(i,nt)=vicen_init(i,nt)
                     !aicen(i,nt)=aicen_init(i,nt)
                     !vsnon(i,nt)=vsnon_init(i,nt)
                     trcrn(i,:,nt) = trcrn_ini(i,:,nt)
                  endif
               enddo
               !swild=trcrn(:,it,nt)
              !call exchange_p2d(swild)
              !trcrn(:,it,nt)=swild
              
           !enddo
          enddo

        ! cut off icepack
      
        call cut_off_icepack
       
        do i=1,nx
           !if (ncat < 0) then ! Do we really need this?
              call cleanup_itd  (dt*nstep_ice,           ntrcr,                &
                                 nilyr,                  nslyr,                &
                                 ncat,                   hin_max(:),           &
                                 aicen(i,:),             trcrn(i,1:ntrcr,:),   &
                                 vicen(i,:),             vsnon(i,:),           &
                                 aice0(i),               aice(i),              &
                                 n_aero,                                       &
                                 nbtrcr,                 nblyr,                &
                                 tr_aero,                                      &
                                 tr_pond_topo,                                 &
                                 heat_capacity,                                &
                                 first_ice(i,:),                               &
                                 trcr_depend(1:ntrcr),   trcr_base(1:ntrcr,:), &
                                 n_trcr_strata(1:ntrcr), nt_strata(1:ntrcr,:), &
                                 fpond(i),               fresh(i),             &
                                 fsalt(i),               fhocn(i),             &
                                 faero_ocn(i,:),         fiso_ocn,          &
                                 fzsal(i),               flux_bio(i,1:nbtrcr))
      
              call icepack_aggregate (ncat,                    &
                                     aicen(i,:),               &
                                     trcrn(i,1:ntrcr,:),       &
                                     vicen(i,:),               &
                                     vsnon(i,:),               &
                                     aice (i),                 &
                                     trcr (i,1:ntrcr),         &
                                     vice (i),                 &
                                     vsno (i),                 &
                                     aice0(i),                 &
                                     ntrcr,                    &
                                     trcr_depend  (1:ntrcr),   &
                                     trcr_base    (1:ntrcr,:), &
                                     n_trcr_strata(1:ntrcr),   &
                                     nt_strata    (1:ntrcr,:))
           !endif
        end do
        totalicea = 0
        totaliceh = 0
        do i=1,nx_nh
         totalicea = totalicea + aice(i)*lump_ice_matrix(i)
         !totaliceh = totaliceh + aice(i)*vice(i)*lump_ice_matrix(i)
         totaliceh = totaliceh + vice(i)*lump_ice_matrix(i)
        enddo
        call mpi_allreduce(totalicea,total_a,1,rtype,MPI_SUM,comm,ierr)
        call mpi_allreduce(totaliceh,total_h,1,rtype,MPI_SUM,comm,ierr)
        if(myrank == 0) write(16,*) 'after advec. ice ',total_a,total_h
        deallocate(works)
        deallocate(works_old)
        deallocate(trcrn_ini)
        deallocate(vicen_init)
        deallocate(aicen_init)
        deallocate(vsnon_init)
        deallocate(swild)
        deallocate(swild1)
        deallocate(swild2)

    end subroutine tracer_advection_icepack2

!=======================================================================
    module subroutine tracer_advection_icepack3

      !use mod_mesh
      use mice_module
      use icepack_intfc,        only: icepack_aggregate
      use icepack_itd,          only: cleanup_itd
      use schism_glbl,          only: dt,nstep_ice
      !use g_config,             only: dt
      use icepack_intfc,         only: icepack_init_trcr
      implicit none
          
      integer (kind=int_kind) :: ntrcr, ntrace, narr, nbtrcr, i,     &
                                 nt,   nt1,    k,   n ,ktherm,narrays,it,ierr
      integer (kind=int_kind) :: nt_Tsfc, nt_qice, nt_qsno,                          & 
                                 nt_sice, nt_fbri, nt_iage, nt_FY, nt_alvl, nt_vlvl, &
                                 nt_apnd, nt_hpnd, nt_ipnd, nt_bgc_Nit, nt_bgc_S
      logical (kind=log_kind) :: tr_pond_topo, tr_pond_lvl, tr_pond_cesm,            &
                                 tr_pond,      tr_aero,     tr_FY,                   &
                                 tr_iage,      heat_capacity,  flag_old,             &
                                 flag_old_0
      real    (kind=dbl_kind) :: puny ,Tsfc ,rhos, Lfresh, jj, kk, njj, pi, trcmin, trcmax,totalicea,totaliceh, &
      total_a,total_h
    
      ! Tracer dependencies and additional arrays
       real (kind=dbl_kind), dimension(ncat) :: &
             tmp, exc
      integer (kind=int_kind), dimension(:),    allocatable    ::    &
              tracer_type    , & ! = 1, 2, or 3 (depends on 0, 1 or 2 other tracers)
              depend             ! tracer dependencies (see below)
    
      logical (kind=log_kind), dimension (:),   allocatable   ::     &
              has_dependents    ! true if a tracer has dependent tracers
    
      real (kind=dbl_kind),    dimension (:,:), allocatable ::       &
             works,works_old, vicen_init, aicen_init, vsnon_init, aicen_tmp, iniflag
      real (kind=dbl_kind),    dimension (:), allocatable ::       &
             fiso_ocn,swild,swild1,swild2
       real (kind=dbl_kind),    dimension (:,:,:), allocatable ::       &
       trcrn_ini

       real (kind=dbl_kind), dimension(nilyr) :: &
         qin            , & ! ice enthalpy (J/m3)
         qin_max        , & ! maximum ice enthalpy (J/m3)
         zTin               ! initial ice temperature

      real (kind=dbl_kind), dimension(nslyr) :: &
         qsn            , & ! snow enthalpy (J/m3)
         zTsn               ! initial snow temperature

      !type(t_mesh),        target,       intent(in)    :: mesh
         character(len=*), parameter :: subname = '(tracer_advection_icepack2)'

      call icepack_query_parameters(heat_capacity_out=heat_capacity, ktherm_out=ktherm,    &
                                    puny_out=puny,rhos_out=rhos,                   &
                                    Lfresh_out=Lfresh  ,pi_out=pi)
      call icepack_query_tracer_sizes(ntrcr_out=ntrcr, nbtrcr_out=nbtrcr)
      call icepack_query_tracer_flags(                                  &
             tr_iage_out=tr_iage, tr_FY_out=tr_FY,                      &
             tr_aero_out=tr_aero, tr_pond_out=tr_pond,                  &
             tr_pond_cesm_out=tr_pond_cesm,                             &
             tr_pond_lvl_out=tr_pond_lvl, tr_pond_topo_out=tr_pond_topo)
      call icepack_query_tracer_indices(nt_Tsfc_out=nt_Tsfc, nt_qice_out=nt_qice, &
             nt_qsno_out=nt_qsno, nt_sice_out=nt_sice, nt_fbri_out=nt_fbri,       &
             nt_iage_out=nt_iage, nt_FY_out=nt_FY, nt_alvl_out=nt_alvl,           &
             nt_vlvl_out=nt_vlvl, nt_apnd_out=nt_apnd, nt_hpnd_out=nt_hpnd,       &
             nt_ipnd_out=nt_ipnd, nt_bgc_Nit_out=nt_bgc_Nit, nt_bgc_S_out=nt_bgc_S)
    
      narr   = 1 + ncat * (3 + ntrcr) ! max number of state variable arrays
    
      ! Allocate works array
      flag_old = .false.
      flag_old_0 = .false.

      if (allocated(works)) deallocate(works)
      if (allocated(works_old)) deallocate(works_old)
      allocate ( works(nx,narr) ) !(npa, max number of state variable arrays)
      allocate ( works_old(nx,narr) )
      allocate ( fiso_ocn(nx) )
      allocate ( swild(nx) )
      allocate ( swild1(nx) )
      allocate ( swild2(nx) )
      allocate ( iniflag(nx,ncat) )
      allocate (trcrn_ini(nx,ntrcr,ncat) )
      allocate (vicen_init(nx,ncat) )
      allocate (aicen_init(nx,ncat) )
      allocate (aicen_tmp(nx,ncat) )
      allocate (vsnon_init(nx,ncat) )
      works(:,:) = c0
      works_old(:,:) = c0
      fiso_ocn(:) = c0
      swild(:) = c0
      swild1(:) = c0
      swild2(:) = c0

      totalicea = 0
      totaliceh = 0
      do i=1,nx_nh
       totalicea = totalicea + aice(i)*lump_ice_matrix(i)
       !totaliceh = totaliceh + aice(i)*vice(i)*lump_ice_matrix(i)
       totaliceh = totaliceh + vice(i)*lump_ice_matrix(i)
      enddo
      call mpi_allreduce(totalicea,total_a,1,rtype,MPI_SUM,comm,ierr)
      call mpi_allreduce(totaliceh,total_h,1,rtype,MPI_SUM,comm,ierr)
      if(myrank == 0) write(16,*) 'before advec. ice ',total_a,total_h

      trcrn_ini=trcrn
      vicen_init=vicen
      aicen_init=aicen
      vsnon_init=vsnon

      call state_to_work (ntrcr, narr, works(:,:))
       works_old=works
      ! Advect each tracer
    
      !do nt = 1, narr    
      !      call upwind_icepack (works(:,nt) )
      !end do
!upwind2
      call upwind_icepack (works(:,1),1 )
      narrays = 1
       do nt = 1, ncat
          call upwind_icepack (works(:,narrays+1),narrays+1 ) 
          aicen_tmp(:,nt) = works(:,narrays+1)
          narrays = narrays + 3 + ntrcr
       enddo

       !do i = 1, nx  ! For each grid cell
       !  if (sum(aicen_tmp(i,:)) > c1) then
       !     tmp(:) = c0
       !     exc(:) = c0
       !     do n = 1, ncat
       !        if (aicen_tmp(i,n) > puny) tmp(n) = c1
       !     end do
       !     do n = 1, ncat
       !         exc(n) = max(c0,(sum(aicen_tmp(i,:)) - c1 + puny))  &
       !                  * aicen_tmp(i,n) / sum(aicen_tmp(i,:))
       !     end do
       !     do n = 1, ncat
       !        aicen_tmp(i,n) = max(c0,aicen_tmp(i,n) - exc(n))
       !     end do
       !        aice0      = max(c0,1-sum(aicen_tmp(i,:)))
       !        if (sum(aicen_tmp(i,:)) > c1) write(12,*) 'here1',sum(aicen_tmp(i,:)),aicen_tmp(i,:)
       !  end if
       !end do

       narrays = 1
       do nt = 1, ncat
       !   do i = 1, nx_nh
       !      if(works(i,narrays+1) > puny) then
       !         flux_matrix1(:,i,narrays+1) = flux_matrix1(:,i,narrays+1) / works(i,narrays+1) * aicen_tmp(i,nt) 
       !         flux_matrix2(:,i,narrays+1) = flux_matrix2(:,i,narrays+1) / works(i,narrays+1) * aicen_tmp(i,nt) 
       !         flux_matrix3(:,i,narrays+1) = flux_matrix3(:,i,narrays+1) / works(i,narrays+1) * aicen_tmp(i,nt) 
       !         flux_matrix4(:,i,narrays+1) = flux_matrix4(:,i,narrays+1) / works(i,narrays+1) * aicen_tmp(i,nt) 
       !         flux_matrix0(:,:,i,narrays+1) = flux_matrix0(:,:,i,narrays+1) / works(i,narrays+1) * aicen_tmp(i,nt) 
       !      endif
       !      works(i,narrays+1) = aicen_tmp(i,nt) 
       !   enddo
       !   swild = works(:,narrays+1)
       !   call exchange_p2d(swild)
       !   works(:,narrays+1) = swild
          !call upwind_icepack (works(:,narrays+2),narrays+2 )  
          !call upwind_icepack (works(:,narrays+3),narrays+3 )
          do i = 1, nx
             if(aicen(i,nt)<puny.or.vicen(i,nt)<puny) then
                swild1(i) = 0
                swild2(i) = 0
             else
                swild1(i) = vicen(i,nt)/aicen(i,nt)
                swild2(i) = vsnon(i,nt)/aicen(i,nt)
             endif
          enddo
          call upwind_icepack_dep(works(:,narrays+2),swild1,narrays+2,narrays+1)
          call upwind_icepack_dep(works(:,narrays+3),swild2,narrays+3,narrays+1) 
          narrays = narrays + 3 + ntrcr
       enddo

       

      call work_to_other  (ntrcr, narr, works(:,:)) 
      

      newwork(:) = c0
       !do i = 1, nx
       !   if(ylat2(i)/pi*180>89.5) works(i,:) = works_old(i,:)
       !enddo
      call work_to_state (ntrcr, narr, works(:,:))
      iniflag(:,:) = c0
       do nt = 1, ncat
          do it = 1, ntrcr
      
             do i=1,nx_nh
                trcmin = minval(trcrn_ini(indnd(1:nnp(i),i),it,nt))
                trcmin = min(trcmin,trcrn_ini(i,it,nt))
                trcmax = maxval(trcrn_ini(indnd(1:nnp(i),i),it,nt))
                trcmax = max(trcmax,trcrn_ini(i,it,nt))
                if(trcrn(i,it,nt) > trcmax) iniflag(i,nt) = 1 !trcrn(i,it,nt) = trcrn_ini(i,it,nt) !trcrn_ini(i,it,nt) !trcmax
                if(trcrn(i,it,nt) < trcmin) iniflag(i,nt) = 1 !trcrn(i,it,nt) = trcrn_ini(i,it,nt) !trcrn_ini(i,it,nt) !trcmin
             enddo
          enddo
       enddo
       do nt = 1, ncat
          swild = iniflag(:,nt)
          call exchange_p2d(swild)
          iniflag(:,nt) = swild
       enddo
       do nt = 1, ncat
          !do it = 1, ntrcr

             do i=1,nx
                if(iniflag(i,nt) > 0) then
                   !vicen(i,nt)=vicen_init(i,nt)
                   !aicen(i,nt)=aicen_init(i,nt)
                   !vsnon(i,nt)=vsnon_init(i,nt)
                   trcrn(i,:,nt) = trcrn_ini(i,:,nt)
                endif
             enddo
             !swild=trcrn(:,it,nt)
            !call exchange_p2d(swild)
            !trcrn(:,it,nt)=swild
            
         !enddo
        enddo

      ! cut off icepack
    
      call cut_off_icepack
     
      do i=1,nx
         !if (ncat < 0) then ! Do we really need this?
            call cleanup_itd  (dt*nstep_ice,           ntrcr,                &
                               nilyr,                  nslyr,                &
                               ncat,                   hin_max(:),           &
                               aicen(i,:),             trcrn(i,1:ntrcr,:),   &
                               vicen(i,:),             vsnon(i,:),           &
                               aice0(i),               aice(i),              &
                               n_aero,                                       &
                               nbtrcr,                 nblyr,                &
                               tr_aero,                                      &
                               tr_pond_topo,                                 &
                               heat_capacity,                                &
                               first_ice(i,:),                               &
                               trcr_depend(1:ntrcr),   trcr_base(1:ntrcr,:), &
                               n_trcr_strata(1:ntrcr), nt_strata(1:ntrcr,:), &
                               fpond(i),               fresh(i),             &
                               fsalt(i),               fhocn(i),             &
                               faero_ocn(i,:),         fiso_ocn,          &
                               fzsal(i),               flux_bio(i,1:nbtrcr))
    
            call icepack_aggregate (ncat,                    &
                                   aicen(i,:),               &
                                   trcrn(i,1:ntrcr,:),       &
                                   vicen(i,:),               &
                                   vsnon(i,:),               &
                                   aice (i),                 &
                                   trcr (i,1:ntrcr),         &
                                   vice (i),                 &
                                   vsno (i),                 &
                                   aice0(i),                 &
                                   ntrcr,                    &
                                   trcr_depend  (1:ntrcr),   &
                                   trcr_base    (1:ntrcr,:), &
                                   n_trcr_strata(1:ntrcr),   &
                                   nt_strata    (1:ntrcr,:))
         !endif
      end do
      totalicea = 0
      totaliceh = 0
      do i=1,nx_nh
       totalicea = totalicea + aice(i)*lump_ice_matrix(i)
       !totaliceh = totaliceh + aice(i)*vice(i)*lump_ice_matrix(i)
       totaliceh = totaliceh + vice(i)*lump_ice_matrix(i)
      enddo
      call mpi_allreduce(totalicea,total_a,1,rtype,MPI_SUM,comm,ierr)
      call mpi_allreduce(totaliceh,total_h,1,rtype,MPI_SUM,comm,ierr)
      if(myrank == 0) write(16,*) 'after advec. ice ',total_a,total_h
      deallocate(works)
      deallocate(works_old)
      deallocate(trcrn_ini)
      deallocate(vicen_init)
      deallocate(aicen_init)
      deallocate(vsnon_init)
      deallocate(swild)
      deallocate(swild1)
      deallocate(swild2)

  end subroutine tracer_advection_icepack3

  !=======================================================================

    subroutine work_to_state (ntrcr, narr, works)

        use icepack_intfc,    only: icepack_compute_tracers,icepack_aggregate

        integer (kind=int_kind), intent(in) :: ntrcr, narr

        real (kind=dbl_kind), dimension(nx,narr), intent (inout) :: &
           works     ! work array
  
        ! local variables
  
        integer (kind=int_kind) :: &
           nt_alvl, nt_apnd, nt_fbri, nt_Tsfc, ktherm ,nt_vlvl
  
        logical (kind=log_kind) :: &
           tr_lvl, tr_pond_cesm, tr_pond_lvl, tr_pond_topo, heat_capacity ,tr_brine
  
        integer (kind=int_kind) ::      &
           k, i, n, it   , & ! counting indices
           narrays       , & ! counter for number of state variable arrays
           nt_qsno       , &
           nt_qice       , &
           nt_sice
  
        real (kind=dbl_kind) :: &
           rhos       , &
           rhoi       , &
           Lfresh     , &
           Tsmelt
  
        real (kind=dbl_kind), dimension(ncat) :: &
           tmp, exc

        real (kind=dbl_kind) :: puny,small
        real (kind=dbl_kind),    dimension (:,:), allocatable ::       &
               aicen_tmp

       ! real (kind=dbl_kind), parameter :: &
       !    small = 0.000001_dbl_kind
         
        character(len=*), parameter :: subname = '(state_to_work)'
  
        call icepack_query_tracer_flags(tr_pond_cesm_out=tr_pond_cesm,              &
             tr_pond_lvl_out=tr_pond_lvl, tr_pond_topo_out=tr_pond_topo,            &
             tr_lvl_out=tr_lvl,tr_brine_out=tr_brine)
        call icepack_query_tracer_indices(nt_alvl_out=nt_alvl, nt_apnd_out=nt_apnd, &
             nt_fbri_out=nt_fbri, nt_qsno_out=nt_qsno, nt_vlvl_out=nt_vlvl,                              &
             nt_qice_out=nt_qice, nt_sice_out=nt_sice, nt_Tsfc_out=nt_Tsfc) 
        call icepack_query_parameters(rhoi_out=rhoi,     rhos_out=rhos,                   &
                                      Lfresh_out=Lfresh, heat_capacity_out=heat_capacity, &
                                      Tsmelt_out=Tsmelt, ktherm_out=ktherm,               &
                                      puny_out=puny)
        call icepack_warnings_flush(ice_stderr)
        if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, &
           file=__FILE__, line=__LINE__)

        allocate (aicen_tmp(nx,ncat) )
        aicen_tmp(:,:) = c0
        trcrn(:,:,:) = c0
        aicen(:,:)   = c0
        vicen(:,:)   = c0
        vsnon(:,:)   = c0
        aice0(:)     = c0

        small       = puny
        ! Open water fraction
  
        do i = 1, nx
           if (works(i,1) <= puny) then
               aice0(i) = c0
           else if (works(i,1) >= c1) then
               aice0(i) = c1
           else
               aice0(i) = works(i,1)
           end if
        enddo
        narrays = 1
  
        ! Sea ice area and volume per unit area of ice and snow
  
        do n=1,ncat
           do i = 1, nx
              if (works(i,narrays+1) > c1) then
                  works(i,narrays+1) = c1
              end if
              if (works(i,narrays+1) <= small .or. works(i,narrays+2) <= small) then
                  works(i,narrays+1) = c0
                  works(i,narrays+2) = c0
                  works(i,narrays+3) = c0
              end if
              if (works(i,narrays+3) <= small) then
                 works(i,narrays+3) = c0
              end if
              aicen(i,n) = works(i,narrays+1)
              vicen(i,n) = works(i,narrays+2)
              vsnon(i,n) = works(i,narrays+3)
           end do
           narrays = narrays + 3 + ntrcr
        end do
  
 
        narrays = 1

        do n=1, ncat
            narrays = narrays + 3

           do i = 1, nx

                  call icepack_compute_tracers(ntrcr=ntrcr,trcr_depend=trcr_depend(:),    &
                                                atrcrn = works(i,narrays+1:narrays+ntrcr), &
                                                aicen  = aicen(i,n),                       &
                                                vicen  = vicen(i,n),                       &
                                                vsnon  = vsnon(i,n),                       &
                                                trcr_base     = trcr_base(:,:),            &
                                                n_trcr_strata = n_trcr_strata(:),          &
                                                nt_strata     = nt_strata(:,:),            &
                                                trcrn  = trcrn(i,:,n))
                  !trcrn(i,nt_qsno:(nt_qsno+nslyr-1),n) = trcrn(i,nt_qsno:(nt_qsno+nslyr-1),n) - rhos*Lfresh
           enddo
          
           narrays = narrays + ntrcr
        enddo
         aicen_tmp = aicen
        do i = 1, nx  ! For each grid cell
           if (sum(aicen(i,:)) > c1) then
           ! write(12,*) 'sum(aicen(i,:)) > c1',aicen(i,:)
              tmp(:) = c0
              exc(:) = c0
              do n = 1, ncat
                 if (aicen(i,n) > puny) tmp(n) = c1
              end do
              do n = 1, ncat
                  exc(n) = max(c0,(sum(aicen(i,:)) - c1))  &
                           * aicen(i,n) / sum(aicen(i,:))
              end do
              do n = 1, ncat
                 aicen(i,n) = max(c0,aicen(i,n) - exc(n))
                 aice0(i)   = max(c0,1-sum(aicen(i,:)))
              end do
           end if
        end do

         do n = 1, ncat
            do i = 1, nx
               if(aicen_tmp(i,n) > puny) then
                  vicen(i,n) = vicen(i,n) / aicen_tmp(i,n) * aicen(i,n)
                  vsnon(i,n) = vsnon(i,n) / aicen_tmp(i,n) * aicen(i,n)
               else
                  vicen(i,n) = c0
                  vsnon(i,n) = c0
               endif
            enddo
         enddo

        do i = 1, nx
         aice(i) = c0
         vice(i) = c0
         vsno(i) = c0
         do it = 1, ntrcr
            trcr(i,it) = c0
         enddo
         call icepack_aggregate (ncat,                    &
                                aicen(i,:),               &
                                trcrn(i,1:ntrcr,:),       &
                                vicen(i,:),               &
                                vsnon(i,:),               &
                                aice (i),                 &
                                trcr (i,1:ntrcr),         &
                                vice (i),                 &
                                vsno (i),                 &
                                aice0(i),                 &
                                ntrcr,                    &
                                trcr_depend  (1:ntrcr),   &
                                trcr_base    (1:ntrcr,:), &
                                n_trcr_strata(1:ntrcr),   &
                                nt_strata    (1:ntrcr,:))
         end do


!        do n=1, ncat
!  
!           narrays = narrays + 3
!  
!           do it = 1, ntrcr
!  
!              if (trcr_depend(it) == 0) then
!                 do i = 1, nx
!                    if (aicen(i,n) > c0) then
!                       if (it == nt_Tsfc) then
!                           trcrn(i,it,n) = min(c0,works(i,narrays+it)/aicen(i,n))
!                       else if (it == nt_alvl .or. it == nt_apnd) then
!                           trcrn(i,it,n) = max(c0,min(c1,works(i,narrays+it) / aicen(i,n)))
!                       endif
!                    end if
!                 enddo
!              elseif (trcr_depend(it) == 1) then
!                 do i = 1, nx
!                    if (vicen(i,n) > c0) then
!                        if (it >= nt_qice .and. it < nt_qice+nilyr) then
!                            trcrn(i,it,n) = min(c0,works(i,narrays+it)/vicen(i,n))
!                            if (.not. heat_capacity) trcrn(i,it,n) = -rhoi * Lfresh
!                        else if (it >= nt_sice .and. it < nt_sice+nilyr) then
!                            trcrn(i,it,n) = max(c0,works(i,narrays+it)/vicen(i,n))
!                        else
!                            trcrn(i,it,n) = max(c0,works(i,narrays+it)/vicen(i,n))
!                        end if
!                    end if
!                 enddo
!              elseif (trcr_depend(it) == 2) then
!                 do i = 1, nx
!                     if (vsnon(i,n) > c0) then
!                         if (it >= nt_qsno .and. it < nt_qsno+nslyr) then
!                             trcrn(i,it,n) = min(c0,works(i,narrays+it)/vsnon(i,n)) - rhos*Lfresh
!                             if (.not. heat_capacity) trcrn(i,it,n) = -rhos * Lfresh
!                         else
!                             trcrn(i,it,n) = min(c0,works(i,narrays+it)/vsnon(i,n)) - rhos*Lfresh
!                         end if
!                     end if
!                 enddo
!              elseif (trcr_depend(it) == 2+nt_alvl) then
!                 do i = 1, nx
!                    if (trcrn(i,nt_alvl,n) > small) then
!                       trcrn(i,it,n) = max( c0, works(i,narrays+it)  &
!                                           / trcrn(i,nt_alvl,n) )     
!                    endif
!                 enddo
!              elseif (trcr_depend(it) == 2+nt_apnd .and. &
!                      tr_pond_cesm .or. tr_pond_topo) then
!                 do i = 1, nx
!                    if (trcrn(i,nt_apnd,n) > small) then
!                       trcrn(i,it,n) = max( c0, works(i,narrays+it)  &
!                                           / trcrn(i,nt_apnd,n) )      
!                    endif
!                 enddo
!              elseif (trcr_depend(it) == 2+nt_apnd .and. &
!                      tr_pond_lvl) then
!                 do i = 1, nx
!                    if (trcrn(i,nt_apnd,n) > small .and. trcrn(i,nt_alvl,n) > small) then
!                       trcrn(i,it,n) = max( c0, works(i,narrays+it)  &
!                                           / trcrn(i,nt_apnd,n)      &
!                                           / trcrn(i,nt_alvl,n)      &
!                                           / aicen(i,n) )
!                    endif
!                 enddo
!              elseif (trcr_depend(it) == 2+nt_fbri) then
!                 do i = 1, nx
!                        works(i,narrays+it) = vicen(i,n) &
!                                            / trcrn(i,nt_fbri,n) &
!                                            / trcrn(i,it,n)
!                 enddo
!              endif
!           enddo
!  
!           narrays = narrays + ntrcr
!  
!        enddo                 ! number of categories 

!        if (mype == 0) write(*,*) 'Tracer salinity: ', nt_sice, ' - ', (nt_sice + nilyr - 1)
!        if (mype == 0) write(*,*) 'ktherm: ', ktherm

        if (ktherm == 1) then ! For bl99 themodynamics
                              ! always ridefine salinity
                              ! after advection
           do i = 1, nx       ! For each grid cell
              do k = 1, nilyr
                 trcrn(i,nt_sice+k-1,:) = salinz(i,k)
              end do          ! nilyr
           end do
        end if                ! ktherm==1

    end subroutine work_to_state

    !=======================================================================

    subroutine state_to_work (ntrcr, narr, works)

        integer (kind=int_kind), intent(in) :: ntrcr, narr
  
        real (kind=dbl_kind), dimension(nx,narr), intent (out) :: &
           works     ! work array
  
        ! local variables
  
        integer (kind=int_kind) :: &
           nt_alvl, nt_apnd, nt_fbri, nt_Tsfc, nt_qice
  
        logical (kind=log_kind) :: &
           tr_pond_cesm, tr_pond_lvl, tr_pond_topo
  
        integer (kind=int_kind) ::      &
           i, n, it   , & ! counting indices
           narrays    , & ! counter for number of state variable arrays
           nt_qsno,k,itl,ntr
  
        real (kind=dbl_kind) :: &
           rhos       , &
           Lfresh,small
  
        character(len=*), parameter :: subname = '(state_to_work)'
  
        call icepack_query_tracer_flags(tr_pond_cesm_out=tr_pond_cesm, &
             tr_pond_lvl_out=tr_pond_lvl, tr_pond_topo_out=tr_pond_topo)
        call icepack_query_tracer_indices(nt_alvl_out=nt_alvl, nt_apnd_out=nt_apnd, &
             nt_fbri_out=nt_fbri, nt_qsno_out=nt_qsno, nt_Tsfc_out=nt_Tsfc,nt_qice_out=nt_qice)
        call icepack_query_parameters(rhos_out=rhos, Lfresh_out=Lfresh)
        call icepack_warnings_flush(ice_stderr)
        if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, &
           file=__FILE__, line=__LINE__)

         works(:,:) = c0
         small = 0.0000001
        do i = 1, nx
           works(i,1) = aice0(i)
        enddo
        narrays = 1
  
        do n=1, ncat
  
           do i = 1, nx
              works(i,narrays+1) = aicen(i,n)
              works(i,narrays+2) = vicen(i,n)
              works(i,narrays+3) = vsnon(i,n)

              if (vicen(i,n)>10) write(12,*) 'before fct', i, n, vicen(i,n)
           enddo                  ! i
           narrays = narrays + 3
  
           do it = 1, ntrcr
            !do i = 1, nx
            !      if (it >= nt_qsno .and. it < nt_qsno+nslyr) then
            !         works(i,narrays+it)= (trcrn(i,it,n)+ rhos*Lfresh)*(trcr_base(it,1) * aicen(i,n) &
            !                                       + trcr_base(it,2) * vicen(i,n) &
            !                                       + trcr_base(it,3) * vsnon(i,n))
            !      else
            !      works(i,narrays+it)= trcrn(i,it,n)*(trcr_base(it,1) * aicen(i,n) &
            !                                       + trcr_base(it,2) * vicen(i,n) &
            !                                       + trcr_base(it,3) * vsnon(i,n))
            !      endif
            !      if (n_trcr_strata(it) > 0) then    ! additional tracer layers
            !         do itl = 1, n_trcr_strata(it)
            !            ntr = nt_strata(it,itl)
            !            works(i,narrays+it) = works(i,narrays+it) * trcrn(i,ntr,n)
            !         enddo
            !      endif
            !   enddo

              if (trcr_depend(it) == 0) then
                 do i = 1, nx
                    works(i,narrays+it) = aicen(i,n)*trcrn(i,it,n)
                 enddo
              elseif (trcr_depend(it) == 1) then
                 do i = 1, nx
                    works(i,narrays+it) = vicen(i,n)*trcrn(i,it,n)
                 enddo
              elseif (trcr_depend(it) == 2) then
                 do i = 1, nx
                    if (it >= nt_qsno .and. it < nt_qsno+nslyr) then
                        works(i,narrays+it) = vsnon(i,n)*trcrn(i,it,n)
                        !works(i,narrays+it) = vsnon(i,n)*(trcrn(i,it,n)+ rhos*Lfresh) 
                    else
                        works(i,narrays+it) = vsnon(i,n)*trcrn(i,it,n)
                    end if
                 enddo
              elseif (trcr_depend(it) == 2+nt_alvl) then
                 do i = 1, nx
                    works(i,narrays+it) = aicen(i,n) &
                                        * trcrn(i,nt_alvl,n) &
                                        * trcrn(i,it,n)
                 enddo
              elseif (trcr_depend(it) == 2+nt_apnd .and. &
                      tr_pond_cesm .or. tr_pond_topo) then
                 do i = 1, nx
                    works(i,narrays+it) = aicen(i,n) &
                                        * trcrn(i,nt_apnd,n) &
                                        * trcrn(i,it,n)
                 enddo
              elseif (trcr_depend(it) == 2+nt_apnd .and. &
                      tr_pond_lvl) then
                 do i = 1, nx
                    works(i,narrays+it) = aicen(i,n) &
                                        * trcrn(i,nt_alvl,n) &
                                        * trcrn(i,nt_apnd,n) &
                                        * trcrn(i,it,n)
                 enddo
              elseif (trcr_depend(it) == 2+nt_fbri) then
                 do i = 1, nx
                    works(i,narrays+it) = vicen(i,n) &
                                        * trcrn(i,nt_fbri,n) &
                                        * trcrn(i,it,n)
                 enddo
              endif
           enddo
           narrays = narrays + ntrcr
  
        enddo                     ! n

        
        if (narr /= narrays .and. myrank == 0 ) write(ice_stderr,*)      &
            "Wrong number of arrays in transport bound call"

    end subroutine state_to_work

!=======================================================================

    subroutine work_to_other (ntrcr, narr, works)

        integer (kind=int_kind), intent(in) :: ntrcr, narr
  
        real (kind=dbl_kind), dimension(nx,narr), intent (inout) :: &
           works     ! work array
  
        ! local variables
  
        integer (kind=int_kind) :: &
           nt_alvl, nt_apnd, nt_fbri, nt_Tsfc, nt_qice, &
           &arr_alvl,arr_apnd,arr_fbri
  
        logical (kind=log_kind) :: &
           tr_pond_cesm, tr_pond_lvl, tr_pond_topo
  
        integer (kind=int_kind) ::      &
           i, n, it   , & ! counting indices
           narrays    , & ! counter for number of state variable arrays
           nt_qsno,k,j
  
        real (kind=dbl_kind) :: &
           rhos       , &
           Lfresh,small
  
        character(len=*), parameter :: subname = '(state_to_work)'
  
        call icepack_query_tracer_flags(tr_pond_cesm_out=tr_pond_cesm, &
             tr_pond_lvl_out=tr_pond_lvl, tr_pond_topo_out=tr_pond_topo)
        call icepack_query_tracer_indices(nt_alvl_out=nt_alvl, nt_apnd_out=nt_apnd, &
             nt_fbri_out=nt_fbri, nt_qsno_out=nt_qsno, nt_Tsfc_out=nt_Tsfc,nt_qice_out=nt_qice)
        call icepack_query_parameters(rhos_out=rhos, Lfresh_out=Lfresh)
        call icepack_warnings_flush(ice_stderr)
        if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, &
           file=__FILE__, line=__LINE__)

        small = 0.0000001

        narrays = 1
  
        do n=1, ncat
    
           do it = 1, ntrcr
              if (trcr_depend(it) == 0) then
                 call upwind_icepack_other(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+1)
              elseif (trcr_depend(it) == 1) then
                 call upwind_icepack_other(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+2)
              elseif (trcr_depend(it) == 2) then
                 call upwind_icepack_other(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+3)
              elseif (trcr_depend(it) == 2+nt_alvl) then
                call upwind_icepack_other(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+1,trcrn(:,nt_alvl,n))!narrays+3+nt_alvl)
              elseif (trcr_depend(it) == 2+nt_apnd .and. &
                      tr_pond_cesm .or. tr_pond_topo) then
               call upwind_icepack_other(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+1,trcrn(:,nt_apnd,n))!narrays+3+nt_apnd)
              elseif (trcr_depend(it) == 2+nt_apnd .and. &
                      tr_pond_lvl) then
                 call upwind_icepack_other(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+1,trcrn(:,nt_alvl,n),trcrn(:,nt_apnd,n))
                 !,narrays+3+nt_alvl,narrays+3+nt_apnd)
              elseif (trcr_depend(it) == 2+nt_fbri) then
                  call upwind_icepack_other(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+2,trcrn(:,nt_fbri,n))!,narrays+3+nt_fbri)
              endif
           enddo
           narrays = narrays + ntrcr +3
  
        enddo                     ! n

        
        if (narr /= narrays .and. myrank == 0 ) write(ice_stderr,*)      &
            "Wrong number of arrays in transport bound call"

    end subroutine work_to_other

!=======================================================================

    subroutine work_to_other2 (ntrcr, narr, works)

        integer (kind=int_kind), intent(in) :: ntrcr, narr
  
        real (kind=dbl_kind), dimension(nx,narr), intent (inout) :: &
           works     ! work array
  
        ! local variables
  
        integer (kind=int_kind) :: &
           nt_alvl, nt_apnd, nt_fbri, nt_Tsfc, nt_qice, &
           &arr_alvl,arr_apnd,arr_fbri
  
        logical (kind=log_kind) :: &
           tr_pond_cesm, tr_pond_lvl, tr_pond_topo
  
        integer (kind=int_kind) ::      &
           i, n, it   , & ! counting indices
           narrays    , & ! counter for number of state variable arrays
           nt_qsno,k,j
  
        real (kind=dbl_kind) :: &
           rhos       , &
           Lfresh,small
        real (kind=dbl_kind),    dimension (:), allocatable ::       &
           swild
        character(len=*), parameter :: subname = '(state_to_work)'

        allocate ( swild(nx) )

        call icepack_query_tracer_flags(tr_pond_cesm_out=tr_pond_cesm, &
             tr_pond_lvl_out=tr_pond_lvl, tr_pond_topo_out=tr_pond_topo)
        call icepack_query_tracer_indices(nt_alvl_out=nt_alvl, nt_apnd_out=nt_apnd, &
             nt_fbri_out=nt_fbri, nt_qsno_out=nt_qsno, nt_Tsfc_out=nt_Tsfc,nt_qice_out=nt_qice)
        call icepack_query_parameters(rhos_out=rhos, Lfresh_out=Lfresh)
        call icepack_warnings_flush(ice_stderr)
        if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, &
           file=__FILE__, line=__LINE__)

        small = 0.0000001
        swild(:) = c0
        narrays = 1
  
        do n=1, ncat
    
           do it = 1, ntrcr
              if (trcr_depend(it) == 0) then
                 call upwind_icepack_other2(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+1)
              elseif (trcr_depend(it) == 1) then
                 call upwind_icepack_other2(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+2)
              elseif (trcr_depend(it) == 2) then
                  if (it >= nt_qsno .and. it < nt_qsno+nslyr) then
                     swild = trcrn(:,it,n)!+ rhos*Lfresh
                     call upwind_icepack_other2(works(:,narrays+3+it),swild,narrays+3+it,narrays+3)
                  else
                     call upwind_icepack_other2(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+3)
                  endif 
              elseif (trcr_depend(it) == 2+nt_alvl) then
                call upwind_icepack_other2(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+1,trcrn(:,nt_alvl,n))!narrays+3+nt_alvl)
              elseif (trcr_depend(it) == 2+nt_apnd .and. &
                      tr_pond_cesm .or. tr_pond_topo) then
               call upwind_icepack_other2(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+1,trcrn(:,nt_apnd,n))!narrays+3+nt_apnd)
              elseif (trcr_depend(it) == 2+nt_apnd .and. &
                      tr_pond_lvl) then
                 call upwind_icepack_other2(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+1,trcrn(:,nt_alvl,n),trcrn(:,nt_apnd,n))
                 !,narrays+3+nt_alvl,narrays+3+nt_apnd)
              elseif (trcr_depend(it) == 2+nt_fbri) then
                  call upwind_icepack_other2(works(:,narrays+3+it),trcrn(:,it,n),narrays+3+it,narrays+2,trcrn(:,nt_fbri,n))!,narrays+3+nt_fbri)
              endif
           enddo
           narrays = narrays + ntrcr +3
  
        enddo                     ! n

        
        if (narr /= narrays .and. myrank == 0 ) write(ice_stderr,*)      &
            "Wrong number of arrays in transport bound call"

    end subroutine work_to_other2

    !=======================================================================

    module subroutine cut_off_icepack

      use icepack_intfc,         only: icepack_compute_tracers
      use icepack_intfc,         only: icepack_aggregate
      use icepack_intfc,         only: icepack_init_trcr
      use icepack_intfc,         only: icepack_sea_freezing_temperature
      use icepack_therm_shared,  only: calculate_Tin_from_qin
      use icepack_mushy_physics, only: icepack_mushy_temperature_mush
      use icepack_mushy_physics, only: liquidus_temperature_mush
      use icepack_mushy_physics, only: enthalpy_mush,enthalpy_of_melting

      ! local variables

      real (kind=dbl_kind), dimension(nilyr) :: &
         qin            , & ! ice enthalpy (J/m3)
         qin_max        , & ! maximum ice enthalpy (J/m3)
         zTin           , & ! initial ice temperature
         tmltz0

      real (kind=dbl_kind), dimension(nslyr) :: &
         qsn            , & ! snow enthalpy (J/m3)
         zTsn               ! initial snow temperature
      integer (kind=int_kind) ::      &
         i, n, k, it    , & ! counting indices
         narrays        , & ! counter for number of state variable arrays
         icells         , & ! number of ocean/ice cells
         ktherm         , &
         ntrcr

       real (kind=dbl_kind), dimension(ncat) :: &
         aicecat

      real (kind=dbl_kind) ::         &
         rhos,       Lfresh,          &
         cp_ice,     cp_ocn,          &
         qrd_snow,   qrd_ice,         &
         Tsfc,       exc,             &
         depressT,   Tmin,            &
         T_air_C,    hice,            &
         puny,       Tsmelt,          &
         small,      rhoi,            &
         hpnd_max,   Tmax          
         
         

      logical (kind=log_kind) :: tr_brine, tr_lvl, flag_snow, flag_cold_ice, flag_warm_ice, &
                                 tr_pond_cesm, tr_pond_topo, tr_pond_lvl, tr_FY, tr_iage,   &
                                 heat_capacity
      integer (kind=int_kind) :: nt_Tsfc, nt_qice, nt_qsno, nt_sice
      integer (kind=int_kind) :: nt_fbri, nt_alvl, nt_vlvl, nt_apnd, nt_hpnd, nt_ipnd, nt_FY, nt_iage

      character(len=*), parameter :: subname = '(cut_off_icepack)'

      call icepack_query_tracer_sizes(ntrcr_out=ntrcr)
      call icepack_query_tracer_flags(tr_brine_out=tr_brine, tr_lvl_out=tr_lvl,      &
        tr_pond_cesm_out=tr_pond_cesm, tr_pond_topo_out=tr_pond_topo,                &
        tr_pond_lvl_out=tr_pond_lvl, tr_FY_out=tr_FY, tr_iage_out=tr_iage            )
      call icepack_query_tracer_indices( nt_Tsfc_out=nt_Tsfc, nt_qice_out=nt_qice,   &
        nt_qsno_out=nt_qsno, nt_sice_out=nt_sice, nt_FY_out=nt_FY,                   &
        nt_fbri_out=nt_fbri, nt_alvl_out=nt_alvl, nt_vlvl_out=nt_vlvl,               &         
        nt_apnd_out=nt_apnd, nt_hpnd_out=nt_hpnd, nt_ipnd_out=nt_ipnd,               &
        nt_iage_out=nt_iage                                                          )
      call icepack_query_parameters(rhos_out=rhos, rhoi_out=rhoi, Lfresh_out=Lfresh, &
                                    cp_ice_out=cp_ice, cp_ocn_out=cp_ocn)
      call icepack_query_parameters(depressT_out=depressT, puny_out=puny, &
        Tsmelt_out=Tsmelt, ktherm_out=ktherm, heat_capacity_out=heat_capacity)
      call icepack_warnings_flush(ice_stderr)

      small = puny
      !small=0.005_dbl_kind        
      Tmin  = -100.0_dbl_kind

      if (.not. heat_capacity) then ! for 0 layer thermodynamics
         do n = 1, ncat
            do i = 1, nx
               if (trcrn(i,nt_Tsfc,n) > Tf(i) .or. trcrn(i,nt_Tsfc,n)< Tmin) then
                   trcrn(i,nt_Tsfc,n) = min(Tf(i), (T_air(i) + 273.15_dbl_kind))
               endif
            enddo
         enddo
      endif

      if (heat_capacity) then    ! only for bl99 and mushy thermodynamics

      ! Here we should implement some conditions to check the tracers
      ! when ice is present, particularly enthalpy, surface temperature
      ! and salinity.

      do n = 1, ncat                      ! For each thickness cathegory
           do i = 1, nx                   ! For each grid point

            call icepack_init_trcr(T_air(i),    Tf(i),         &
                                   !salinz(i,:), Tmltz(i,:),    &
                                  trcrn(i,nt_sice:nt_sice+nilyr-1,n), Tmltz(i,:),    &
                                   Tsfc,                       &
                                   nilyr,        nslyr,        &
                                   qin   (:),    qsn  (:))
            call icepack_warnings_flush(ice_stderr)
            if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, &
            file=__FILE__, line=__LINE__)  
                do k = 1, nilyr
                   if (ktherm == 2) then
                      tmltz0(k) = liquidus_temperature_mush(trcrn(i,nt_sice+k-1,n))
                      !qin(k)=enthalpy_mush(tmltz0(k), trcrn(i,nt_sice+k-1,n))
                      qin_max(k) = enthalpy_of_melting(trcrn(i,nt_sice+k-1,n)) - c1
                      !qin_max(k) = enthalpy_mush((Tmltz(i,k)-0.1), trcrn(i,nt_sice+k-1,n))
                   else
                      tmltz0(k) = -trcrn(i,nt_sice+k-1,n) * depressT
                      qin_max(k) = rhoi * cp_ocn * (tmltz0(k) - 0.1_dbl_kind) 
                      !qin_max(:) = rhoi * cp_ocn * (Tmltz(i,k) - 0.1_dbl_kind)  
                   endif
                enddo
                ! Correct qin profile for melting temperatures

                ! Maximum ice enthalpy 

                !qin_max(:) = rhoi * cp_ocn * (tmltz0(:) - 60_dbl_kind) 
                !qin_max(:) = rhoi * cp_ocn * (Tmltz(i,:) - 0.1_dbl_kind)  
                if (vicen(i,n) > small .and. aicen(i,n) > small) then

                    ! Condition on surface temperature
                    if (trcrn(i,nt_Tsfc,n) > Tsmelt .or. trcrn(i,nt_Tsfc,n) < Tmin) then
                        trcrn(i,nt_Tsfc,n) = Tsfc
                    endif

                    ! Condition on ice enthalpy

                    flag_warm_ice = .false.
                    flag_cold_ice = .false.
                    flag_snow     = .false.

                      do k = 1, nilyr  ! Check for problems

                         if (ktherm == 2) then
                            zTin(k) = icepack_mushy_temperature_mush(trcrn(i,nt_qice+k-1,n),trcrn(i,nt_sice+k-1,n))
                         else
                            zTin(k) = calculate_Tin_from_qin(trcrn(i,nt_qice+k-1,n),Tmltz(i,k))
                         endif

                         if (zTin(k) <  Tmin      ) flag_cold_ice = .true.
                         !if (zTin(k) >= Tmltz(i,k)) flag_warm_ice = .true.
                         if (zTin(k) >= tmltz0(k)) flag_warm_ice = .true.

                      enddo !nilyr

                if (flag_cold_ice) then
                   ! write(12,*) i,zTin(k),qin_max(k), qin(k), trcrn(i,nt_qice+k-1,n)
                    trcrn(i,nt_Tsfc,n) = Tsfc

                    do k = 1, nilyr
                      !write(12,*) i,zTin(k),qin_max(k), qin(k), trcrn(i,nt_qice+k-1,n),tmltz0(k), trcrn(i,nt_sice+k-1,n)
                         trcrn(i,nt_qice+k-1,n) = min(qin_max(k), qin(k))
                    enddo        ! nilyr

                    if (vsnon(i,n) > small) then ! Only if there is snow
                                                 ! on top of the sea ice
                        do k = 1, nslyr
                              trcrn(i,nt_qsno+k-1,n) = qsn(k)
                        enddo   
                    else                        ! No snow 
                        trcrn(i,nt_qsno:nt_qsno+nslyr-1,n) = c0
                    endif

                end if            ! flag cold ice

                if (flag_warm_ice) then         ! This sea ice should have melted already 

                    aicen(i,n)   = c0
                    vicen(i,n)   = c0
                    vsnon(i,n)   = c0
                    trcrn(i,:,n) = c0
                    trcrn(i,nt_Tsfc,n) = Tf(i)

                     !trcrn(i,nt_Tsfc,n) = Tsfc

                    !do k = 1, nilyr
                      !write(12,*) i,zTin(k),qin_max(k), qin(k), trcrn(i,nt_qice+k-1,n),tmltz0(k), trcrn(i,nt_sice+k-1,n)
                    !     trcrn(i,nt_qice+k-1,n) = min(qin_max(k), qin(k))
                    !enddo        ! nilyr

                end if

                    if (vsnon(i,n) > small) then

                        flag_snow = .false.

                        do k = 1, nslyr  
                           if (trcrn(i,nt_qsno+k-1,n) >= -rhos*Lfresh) flag_snow = .true.
                           zTsn(k) = (Lfresh + trcrn(i,nt_qsno+k-1,n)/rhos)/cp_ice
                           if (zTsn(k) < Tmin) flag_snow = .true.
                        end do 
                        !flag_snow = .false.

                        if (flag_snow) then
                            trcrn(i,nt_Tsfc,n) = Tsfc
                            do k = 1, nslyr
                                 trcrn(i,nt_qsno+k-1,n) = qsn(k)
                            enddo        ! nslyr
                        endif            ! flag snow
                    endif ! vsnon(i,n) > c0

                else

                    aicen(i,n)   = c0
                    vicen(i,n)   = c0
                    vsnon(i,n)   = c0
                    trcrn(i,:,n) = c0
                    trcrn(i,nt_Tsfc,n) = Tf(i)

                endif

           enddo   ! nx
      enddo        ! ncat

      ! Melt ponds and level ice cutoff

      do n = 1, ncat
         do i = 1, nx
            if (aicen(i,n) > c0) then
               hpnd_max = 0.9_dbl_kind * vicen(i,n) / aicen(i,n)
               ! Sea ice age
               if (tr_iage) then
                   if (trcrn(i,nt_iage,n) < 0.000001_dbl_kind) trcrn(i,nt_iage,n) = c0
               end if
               ! First year ice fraction
               if (tr_FY) then
                   if (trcrn(i,nt_FY,n) < 0.000001_dbl_kind) trcrn(i,nt_FY,n) = c0
                   if (trcrn(i,nt_FY,n) > c1) trcrn(i,nt_FY,n) = c1
               end if
               ! Level ice
               if (tr_lvl) then
                   if (trcrn(i,nt_alvl,n) > aicen(i,n)) then
                       trcrn(i,nt_alvl,n) = aicen(i,n)
                   elseif (trcrn(i,nt_alvl,n) < 0.000001_dbl_kind) then
                       trcrn(i,nt_alvl,n) = c0
                   endif
                   if (trcrn(i,nt_vlvl,n) < 0.000001_dbl_kind .or. trcrn(i,nt_alvl,n) < 0.000001_dbl_kind) trcrn(i,nt_vlvl,n) = c0
                   if (trcrn(i,nt_vlvl,n) > vicen(i,n)) trcrn(i,nt_vlvl,n) = vicen(i,n)
               end if
               ! CESM melt pond parameterization
               if (tr_pond_cesm) then
                   if (trcrn(i,nt_apnd,n) > c1) then
                       trcrn(i,nt_apnd,n) = c1
                   elseif (trcrn(i,nt_apnd,n) < 0.000001_dbl_kind) then
                       trcrn(i,nt_apnd,n) = c0
                   endif
                   if (trcrn(i,nt_hpnd,n) < 0.000001_dbl_kind .or. trcrn(i,nt_apnd,n) < 0.000001_dbl_kind) trcrn(i,nt_hpnd,n) = c0
                   if (trcrn(i,nt_hpnd,n) > hpnd_max) trcrn(i,nt_hpnd,n) = hpnd_max
               end if
               ! Topo and level melt pond parameterization
               if (tr_pond_topo .or. tr_pond_lvl) then
                   if (trcrn(i,nt_apnd,n) > c1) then
                       trcrn(i,nt_apnd,n) = c1
                   elseif (trcrn(i,nt_apnd,n) < 0.000001_dbl_kind) then
                       trcrn(i,nt_apnd,n) = c0
                   endif
                   if (trcrn(i,nt_hpnd,n) < 0.000001_dbl_kind .or. trcrn(i,nt_apnd,n) < 0.000001_dbl_kind) trcrn(i,nt_hpnd,n) = c0
                   if (trcrn(i,nt_hpnd,n) > hpnd_max) trcrn(i,nt_hpnd,n) = hpnd_max
                   if (trcrn(i,nt_ipnd,n) < 0.000001_dbl_kind .or. trcrn(i,nt_apnd,n) < 0.000001_dbl_kind) trcrn(i,nt_ipnd,n) = c0
               end if
               ! Dynamic salt
               if (tr_brine) then
                   if (trcrn(i,nt_fbri,n) < 0.000001_dbl_kind) trcrn(i,nt_fbri,n) = c0
               endif
            endif
         enddo
      enddo

      do i = 1, nx
         aice(i) = c0
         vice(i) = c0
         vsno(i) = c0
         do it = 1, ntrcr
            trcr(i,it) = c0
         enddo
         call icepack_aggregate (ncat,                    &
                                aicen(i,:),               &
                                trcrn(i,1:ntrcr,:),       &
                                vicen(i,:),               &
                                vsnon(i,:),               &
                                aice (i),                 &
                                trcr (i,1:ntrcr),         &
                                vice (i),                 &
                                vsno (i),                 &
                                aice0(i),                 &
                                ntrcr,                    &
                                trcr_depend  (1:ntrcr),   &
                                trcr_base    (1:ntrcr,:), &
                                n_trcr_strata(1:ntrcr),   &
                                nt_strata    (1:ntrcr,:))
      end do

      end if ! heat_capacity

      call icepack_warnings_flush(ice_stderr)
      if (icepack_warnings_aborted()) call icedrv_system_abort(string=subname, &
          file=__FILE__, line=__LINE__)

  end subroutine cut_off_icepack


end submodule icedrv_advection