LCOV - code coverage report
Current view: top level - cicecore/cicedyn/dynamics - ice_dyn_vp.F90 (source / functions) Hit Total Coverage
Test: 231018-211459:8916b9ff2c:1:quick Lines: 0 1041 0.00 %
Date: 2023-10-18 15:30:36 Functions: 0 23 0.00 %

          Line data    Source code
       1             : !=======================================================================
       2             : !
       3             : ! Viscous-plastic sea ice dynamics model
       4             : ! Computes ice velocity and deformation
       5             : !
       6             : ! See:
       7             : !
       8             : ! Lemieux, J.‐F., Tremblay, B., Thomas, S., Sedláček, J., and Mysak, L. A. (2008),
       9             : ! Using the preconditioned Generalized Minimum RESidual (GMRES) method to solve
      10             : ! the sea‐ice momentum equation, J. Geophys. Res., 113, C10004, doi:10.1029/2007JC004680.
      11             : !
      12             : ! Hibler, W. D., and Ackley, S. F. (1983), Numerical simulation of the Weddell Sea pack ice,
      13             : ! J. Geophys. Res., 88( C5), 2873– 2887, doi:10.1029/JC088iC05p02873.
      14             : !
      15             : ! Y. Saad. A Flexible Inner-Outer Preconditioned GMRES Algorithm. SIAM J. Sci. Comput.,
      16             : ! 14(2):461–469, 1993. URL: https://doi.org/10.1137/0914028, doi:10.1137/0914028.
      17             : !
      18             : ! C. T. Kelley, Iterative Methods for Linear and Nonlinear Equations, SIAM, 1995.
      19             : ! (https://www.siam.org/books/textbooks/fr16_book.pdf)
      20             : !
      21             : ! Y. Saad, Iterative Methods for Sparse Linear Systems. SIAM, 2003.
      22             : ! (http://www-users.cs.umn.edu/~saad/IterMethBook_2ndEd.pdf)
      23             : !
      24             : ! Walker, H. F., & Ni, P. (2011). Anderson Acceleration for Fixed-Point Iterations.
      25             : ! SIAM Journal on Numerical Analysis, 49(4), 1715–1735. https://doi.org/10.1137/10078356X
      26             : !
      27             : ! Fang, H., & Saad, Y. (2009). Two classes of multisecant methods for nonlinear acceleration.
      28             : ! Numerical Linear Algebra with Applications, 16(3), 197–221. https://doi.org/10.1002/nla.617
      29             : !
      30             : ! Birken, P. (2015) Termination criteria for inexact fixed‐point schemes.
      31             : ! Numer. Linear Algebra Appl., 22: 702– 716. doi: 10.1002/nla.1982.
      32             : !
      33             : ! authors: JF Lemieux, ECCC, Philppe Blain, ECCC
      34             : !
      35             : 
      36             :       module ice_dyn_vp
      37             : 
      38             :       use ice_kinds_mod
      39             :       use ice_blocks, only: nx_block, ny_block
      40             :       use ice_boundary, only: ice_halo
      41             :       use ice_communicate, only: my_task, master_task, get_num_procs
      42             :       use ice_constants, only: field_loc_center, field_loc_NEcorner, &
      43             :           field_type_scalar, field_type_vector
      44             :       use ice_constants, only: c0, p027, p055, p111, p166, &
      45             :           p222, p25, p333, p5, c1
      46             :       use ice_domain, only: nblocks, distrb_info
      47             :       use ice_domain_size, only: max_blocks
      48             :       use ice_dyn_shared, only: dyn_prep1, dyn_prep2, dyn_finish, &
      49             :           cosw, sinw, fcor_blk, uvel_init, vvel_init, &   ! LCOV_EXCL_LINE
      50             :           seabed_stress_factor_LKD, seabed_stress_factor_prob, seabed_stress_method, &   ! LCOV_EXCL_LINE
      51             :           seabed_stress, Ktens, stack_fields,  unstack_fields, fld2, fld3, fld4
      52             :       use ice_fileunits, only: nu_diag
      53             :       use ice_flux, only: fmU
      54             :       use ice_global_reductions, only: global_sum
      55             :       use ice_grid, only: dxT, dyT, dxhy, dyhx, cxp, cyp, cxm, cym, uarear
      56             :       use ice_exit, only: abort_ice
      57             :       use icepack_intfc, only: icepack_warnings_flush, icepack_warnings_aborted
      58             :       use icepack_intfc, only: icepack_ice_strength, icepack_query_parameters
      59             : 
      60             :       implicit none
      61             :       private
      62             :       public :: implicit_solver, init_vp
      63             : 
      64             :       ! namelist parameters
      65             : 
      66             :       integer (kind=int_kind), public :: &
      67             :          maxits_nonlin  , & ! max nb of iteration for nonlinear solver   ! LCOV_EXCL_LINE
      68             :          dim_fgmres     , & ! size of fgmres Krylov subspace   ! LCOV_EXCL_LINE
      69             :          dim_pgmres     , & ! size of pgmres Krylov subspace   ! LCOV_EXCL_LINE
      70             :          maxits_fgmres  , & ! max nb of iteration for fgmres   ! LCOV_EXCL_LINE
      71             :          maxits_pgmres  , & ! max nb of iteration for pgmres   ! LCOV_EXCL_LINE
      72             :          fpfunc_andacc  , & ! fixed point function for Anderson acceleration:   ! LCOV_EXCL_LINE
      73             :                             ! 1: g(x) = FMGRES(A(x),b(x)), 2: g(x) = x - A(x)x + b(x)
      74             :          dim_andacc     , & ! size of Anderson minimization matrix (number of saved previous residuals)
      75             :          start_andacc       ! acceleration delay factor (acceleration starts at this iteration)
      76             : 
      77             :       logical (kind=log_kind), public :: &
      78             :          monitor_nonlin , & ! print nonlinear residual norm   ! LCOV_EXCL_LINE
      79             :          monitor_fgmres , & ! print fgmres residual norm   ! LCOV_EXCL_LINE
      80             :          monitor_pgmres , & ! print pgmres residual norm   ! LCOV_EXCL_LINE
      81             :          use_mean_vrel      ! use mean of previous 2 iterates to compute vrel (see Hibler and Ackley 1983)
      82             : 
      83             :       real (kind=dbl_kind), public :: &
      84             :          reltol_nonlin  , & ! nonlinear stopping criterion: reltol_nonlin*res(k=0)   ! LCOV_EXCL_LINE
      85             :          reltol_fgmres  , & ! fgmres stopping criterion: reltol_fgmres*res(k)   ! LCOV_EXCL_LINE
      86             :          reltol_pgmres  , & ! pgmres stopping criterion: reltol_pgmres*res(k)   ! LCOV_EXCL_LINE
      87             :          damping_andacc , & ! damping factor for Anderson acceleration   ! LCOV_EXCL_LINE
      88             :          reltol_andacc      ! relative tolerance for Anderson acceleration
      89             : 
      90             :       character (len=char_len), public :: &
      91             :          precond        , & ! preconditioner for fgmres: 'ident' (identity), 'diag' (diagonal),   ! LCOV_EXCL_LINE
      92             :                             ! 'pgmres' (Jacobi-preconditioned GMRES)
      93             :          algo_nonlin    , & ! nonlinear algorithm: 'picard' (Picard iteration), 'anderson' (Anderson acceleration)
      94             :          ortho_type         ! type of orthogonalization for FGMRES ('cgs' or 'mgs')
      95             : 
      96             :       ! module variables
      97             : 
      98             :       integer (kind=int_kind), allocatable :: &
      99             :          icellT(:)    , & ! no. of cells where iceTmask = .true.   ! LCOV_EXCL_LINE
     100             :          icellU(:)        ! no. of cells where iceUmask = .true.
     101             : 
     102             :       integer (kind=int_kind), allocatable :: &
     103             :          indxTi(:,:)  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
     104             :          indxTj(:,:)  , & ! compressed index in j-direction   ! LCOV_EXCL_LINE
     105             :          indxUi(:,:)  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
     106             :          indxUj(:,:)      ! compressed index in j-direction
     107             : 
     108             : !=======================================================================
     109             : 
     110             :       contains
     111             : 
     112             : !=======================================================================
     113             : 
     114             : ! Initialize parameters and variables needed for the vp dynamics
     115             : ! author: Philippe Blain, ECCC
     116             : 
     117           0 :       subroutine init_vp
     118             : 
     119             :       use ice_blocks, only: get_block, block
     120             :       use ice_boundary, only: ice_HaloUpdate
     121             :       use ice_constants, only: c1, &
     122             :           field_loc_center, field_type_scalar
     123             :       use ice_domain, only: blocks_ice, halo_info
     124             :       use ice_calendar, only: dt_dyn
     125             :       use ice_dyn_shared, only: init_dyn_shared
     126             : !      use ice_grid, only: tarea
     127             : 
     128             :       ! local variables
     129             : 
     130             :       integer (kind=int_kind) :: &
     131             :          i, j, iblk, &   ! LCOV_EXCL_LINE
     132             :          ilo,ihi,jlo,jhi      ! beginning and end of physical domain
     133             : 
     134             :       type (block) :: &
     135             :          this_block           ! block information for current block
     136             : 
     137           0 :       call init_dyn_shared(dt_dyn)
     138             : 
     139             :       ! Initialize module variables
     140           0 :       allocate(icellT(max_blocks), icellU(max_blocks))
     141           0 :       allocate(indxTi(nx_block*ny_block, max_blocks), &
     142             :                indxTj(nx_block*ny_block, max_blocks), &   ! LCOV_EXCL_LINE
     143             :                indxUi(nx_block*ny_block, max_blocks), &   ! LCOV_EXCL_LINE
     144           0 :                indxUj(nx_block*ny_block, max_blocks))
     145             : 
     146           0 :       end subroutine init_vp
     147             : 
     148             : !=======================================================================
     149             : 
     150             : ! Viscous-plastic dynamics driver
     151             : !
     152             : #ifdef CICE_IN_NEMO
     153             : ! Wind stress is set during this routine from the values supplied
     154             : ! via NEMO (unless calc_strair is true).  These values are supplied
     155             : ! rotated on u grid and multiplied by aice.  strairxT = 0 in this
     156             : ! case so operations in dyn_prep1 are pointless but carried out to
     157             : ! minimise code changes.
     158             : #endif
     159             : !
     160             : ! author: JF Lemieux, A. Qaddouri and F. Dupont ECCC
     161             : 
     162           0 :       subroutine implicit_solver (dt)
     163             : 
     164             :       use ice_arrays_column, only: Cdn_ocn
     165             :       use ice_boundary, only: ice_HaloMask, ice_HaloUpdate, &
     166             :           ice_HaloDestroy, ice_HaloUpdate_stress
     167             :       use ice_blocks, only: block, get_block, nx_block, ny_block
     168             :       use ice_domain, only: blocks_ice, halo_info, maskhalo_dyn
     169             :       use ice_domain_size, only: max_blocks, ncat
     170             :       use ice_dyn_shared, only: deformations, iceTmask, iceUmask
     171             :       use ice_flux, only: rdg_conv, rdg_shear, strairxT, strairyT, &
     172             :           strairxU, strairyU, uocn, vocn, ss_tltx, ss_tlty, fmU, &   ! LCOV_EXCL_LINE
     173             :           strtltxU, strtltyU, strocnxU, strocnyU, strintxU, strintyU, taubxU, taubyU, &   ! LCOV_EXCL_LINE
     174             :           strax, stray, &   ! LCOV_EXCL_LINE
     175             :           TbU, hwater, &   ! LCOV_EXCL_LINE
     176             :           stressp_1, stressp_2, stressp_3, stressp_4, &   ! LCOV_EXCL_LINE
     177             :           stressm_1, stressm_2, stressm_3, stressm_4, &   ! LCOV_EXCL_LINE
     178             :           stress12_1, stress12_2, stress12_3, stress12_4
     179             :       use ice_grid, only: tmask, umask, dxT, dyT, cxp, cyp, cxm, cym, &
     180             :           tarear, grid_type, grid_average_X2Y, &   ! LCOV_EXCL_LINE
     181             :           grid_atm_dynu, grid_atm_dynv, grid_ocn_dynu, grid_ocn_dynv
     182             :       use ice_state, only: aice, aiU, vice, vsno, uvel, vvel, divu, shear, &
     183             :           aice_init, aice0, aicen, vicen, strength
     184             :       use ice_timers, only: timer_dynamics, timer_bound, &
     185             :           ice_timer_start, ice_timer_stop
     186             : 
     187             :       real (kind=dbl_kind), intent(in) :: &
     188             :          dt      ! time step
     189             : 
     190             :       ! local variables
     191             : 
     192             :       integer (kind=int_kind) :: &
     193             :          ntot           , & ! size of problem for Anderson   ! LCOV_EXCL_LINE
     194             :          iblk           , & ! block index   ! LCOV_EXCL_LINE
     195             :          ilo,ihi,jlo,jhi, & ! beginning and end of physical domain   ! LCOV_EXCL_LINE
     196             :          i, j, ij
     197             : 
     198             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks) :: &
     199             :          uocnU    , & ! i ocean current (m/s)   ! LCOV_EXCL_LINE
     200             :          vocnU    , & ! j ocean current (m/s)   ! LCOV_EXCL_LINE
     201             :          ss_tltxU , & ! sea surface slope, x-direction (m/m)   ! LCOV_EXCL_LINE
     202             :          ss_tltyU , & ! sea surface slope, y-direction (m/m)   ! LCOV_EXCL_LINE
     203             :          cdn_ocnU , & ! ocn drag coefficient   ! LCOV_EXCL_LINE
     204             :          tmass    , & ! total mass of ice and snow (kg/m^2)   ! LCOV_EXCL_LINE
     205             :          waterxU  , & ! for ocean stress calculation, x (m/s)   ! LCOV_EXCL_LINE
     206             :          wateryU  , & ! for ocean stress calculation, y (m/s)   ! LCOV_EXCL_LINE
     207             :          forcexU  , & ! work array: combined atm stress and ocn tilt, x   ! LCOV_EXCL_LINE
     208             :          forceyU  , & ! work array: combined atm stress and ocn tilt, y   ! LCOV_EXCL_LINE
     209             :          bxfix    , & ! part of bx that is constant during Picard   ! LCOV_EXCL_LINE
     210             :          byfix    , & ! part of by that is constant during Picard   ! LCOV_EXCL_LINE
     211             :          Cb       , & ! seabed stress coefficient   ! LCOV_EXCL_LINE
     212             :          fpresx   , & ! fixed point residual vector, x components: fx = uvel - uprev_k   ! LCOV_EXCL_LINE
     213             :          fpresy   , & ! fixed point residual vector, y components: fy = vvel - vprev_k   ! LCOV_EXCL_LINE
     214             :          umass    , & ! total mass of ice and snow (u grid)   ! LCOV_EXCL_LINE
     215           0 :          umassdti     ! mass of U-cell/dte (kg/m^2 s)
     216             : 
     217             :       real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks,4):: &
     218             :          zetax2   , & ! zetax2 = 2*zeta (bulk viscosity)   ! LCOV_EXCL_LINE
     219             :          etax2    , & ! etax2  = 2*eta  (shear viscosity)   ! LCOV_EXCL_LINE
     220           0 :          rep_prs      ! replacement pressure
     221             : 
     222             :       logical (kind=log_kind) :: calc_strair
     223             : 
     224             :       integer (kind=int_kind), dimension (nx_block,ny_block,max_blocks) :: &
     225           0 :          halomask     ! generic halo mask
     226             : 
     227             :       type (ice_halo) :: &
     228             :          halo_info_mask !  ghost cell update info for masked halo
     229             : 
     230             :       type (block) :: &
     231             :          this_block           ! block information for current block
     232             : 
     233             :       real (kind=dbl_kind), allocatable :: &
     234           0 :          sol(:)          ! solution vector
     235             : 
     236             :       character(len=*), parameter :: subname = '(implicit_solver)'
     237             : 
     238           0 :       call ice_timer_start(timer_dynamics) ! dynamics
     239             : 
     240             :       !-----------------------------------------------------------------
     241             :       ! Initialize
     242             :       !-----------------------------------------------------------------
     243             : 
     244             :        ! This call is needed only if dt changes during runtime.
     245             : !      call set_evp_parameters (dt)
     246             : 
     247             :       !-----------------------------------------------------------------
     248             :       ! boundary updates
     249             :       ! commented out because the ghost cells are freshly
     250             :       ! updated after cleanup_itd
     251             :       !-----------------------------------------------------------------
     252             : 
     253             : !      call ice_timer_start(timer_bound)
     254             : !      call ice_HaloUpdate (aice,              halo_info, &
     255             : !                           field_loc_center,  field_type_scalar)
     256             : !      call ice_HaloUpdate (vice,              halo_info, &
     257             : !                           field_loc_center,  field_type_scalar)
     258             : !      call ice_HaloUpdate (vsno,              halo_info, &
     259             : !                           field_loc_center,  field_type_scalar)
     260             : !      call ice_timer_stop(timer_bound)
     261             : 
     262           0 :       !$OMP PARALLEL DO PRIVATE(iblk,i,j,ilo,ihi,jlo,jhi,this_block)
     263           0 :       do iblk = 1, nblocks
     264             : 
     265           0 :          do j = 1, ny_block
     266           0 :          do i = 1, nx_block
     267           0 :             rdg_conv (i,j,iblk) = c0
     268           0 :             rdg_shear(i,j,iblk) = c0
     269           0 :             divu (i,j,iblk) = c0
     270           0 :             shear(i,j,iblk) = c0
     271             :          enddo
     272             :          enddo
     273             : 
     274             :       !-----------------------------------------------------------------
     275             :       ! preparation for dynamics
     276             :       !-----------------------------------------------------------------
     277             : 
     278           0 :          this_block = get_block(blocks_ice(iblk),iblk)
     279           0 :          ilo = this_block%ilo
     280           0 :          ihi = this_block%ihi
     281           0 :          jlo = this_block%jlo
     282           0 :          jhi = this_block%jhi
     283             : 
     284             :          call dyn_prep1 (nx_block,           ny_block,           &
     285             :                          ilo, ihi,           jlo, jhi,           &   ! LCOV_EXCL_LINE
     286             :                          aice    (:,:,iblk), vice    (:,:,iblk), &   ! LCOV_EXCL_LINE
     287             :                          vsno    (:,:,iblk), tmask   (:,:,iblk), &   ! LCOV_EXCL_LINE
     288           0 :                          tmass   (:,:,iblk), iceTmask(:,:,iblk))
     289             : 
     290             :       enddo                     ! iblk
     291             :       !$OMP END PARALLEL DO
     292             : 
     293           0 :       call ice_timer_start(timer_bound)
     294             :       call ice_HaloUpdate (iceTmask,          halo_info, &
     295           0 :                            field_loc_center,  field_type_scalar)
     296           0 :       call ice_timer_stop(timer_bound)
     297             : 
     298             :       !-----------------------------------------------------------------
     299             :       ! convert fields from T to U grid
     300             :       !-----------------------------------------------------------------
     301             : 
     302           0 :       call stack_fields(tmass, aice_init, cdn_ocn, fld3)
     303             :       call ice_HaloUpdate (fld3,             halo_info, &
     304           0 :                            field_loc_center, field_type_scalar)
     305           0 :       call stack_fields(uocn, vocn, ss_tltx, ss_tlty, fld4)
     306             :       call ice_HaloUpdate (fld4,             halo_info, &
     307           0 :                            field_loc_center, field_type_vector)
     308           0 :       call unstack_fields(fld3, tmass, aice_init, cdn_ocn)
     309           0 :       call unstack_fields(fld4, uocn, vocn, ss_tltx, ss_tlty)
     310             : 
     311           0 :       call grid_average_X2Y('S',tmass    , 'T'          , umass   , 'U')
     312           0 :       call grid_average_X2Y('S',aice_init, 'T'          , aiU     , 'U')
     313           0 :       call grid_average_X2Y('S',cdn_ocn  , 'T'          , cdn_ocnU, 'U')
     314           0 :       call grid_average_X2Y('S',uocn     , grid_ocn_dynu, uocnU   , 'U')
     315           0 :       call grid_average_X2Y('S',vocn     , grid_ocn_dynv, vocnU   , 'U')
     316           0 :       call grid_average_X2Y('S',ss_tltx  , grid_ocn_dynu, ss_tltxU, 'U')
     317           0 :       call grid_average_X2Y('S',ss_tlty  , grid_ocn_dynv, ss_tltyU, 'U')
     318             : 
     319             :       !----------------------------------------------------------------
     320             :       ! Set wind stress to values supplied via NEMO or other forcing
     321             :       ! This wind stress is rotated on u grid and multiplied by aice
     322             :       !----------------------------------------------------------------
     323           0 :       call icepack_query_parameters(calc_strair_out=calc_strair)
     324           0 :       call icepack_warnings_flush(nu_diag)
     325           0 :       if (icepack_warnings_aborted()) call abort_ice(error_message=subname, &
     326           0 :          file=__FILE__, line=__LINE__)
     327             : 
     328           0 :       if (.not. calc_strair) then
     329           0 :          call grid_average_X2Y('F', strax, grid_atm_dynu, strairxU, 'U')
     330           0 :          call grid_average_X2Y('F', stray, grid_atm_dynv, strairyU, 'U')
     331             :       else
     332             :          call ice_HaloUpdate (strairxT,         halo_info, &
     333           0 :                               field_loc_center, field_type_vector)
     334             :          call ice_HaloUpdate (strairyT,         halo_info, &
     335           0 :                               field_loc_center, field_type_vector)
     336           0 :          call grid_average_X2Y('F',strairxT,'T',strairxU,'U')
     337           0 :          call grid_average_X2Y('F',strairyT,'T',strairyU,'U')
     338             :       endif
     339             : 
     340           0 :       !$OMP PARALLEL DO PRIVATE(iblk,ilo,ihi,jlo,jhi,this_block,ij,i,j)
     341           0 :       do iblk = 1, nblocks
     342             : 
     343             :       !-----------------------------------------------------------------
     344             :       ! more preparation for dynamics
     345             :       !-----------------------------------------------------------------
     346             : 
     347           0 :          this_block = get_block(blocks_ice(iblk),iblk)
     348           0 :          ilo = this_block%ilo
     349           0 :          ihi = this_block%ihi
     350           0 :          jlo = this_block%jlo
     351           0 :          jhi = this_block%jhi
     352             : 
     353             :          call dyn_prep2 (nx_block,             ny_block,             &
     354             :                          ilo, ihi,             jlo, jhi,             &   ! LCOV_EXCL_LINE
     355             :                          icellT(iblk),         icellU(iblk),         &   ! LCOV_EXCL_LINE
     356             :                          indxTi      (:,iblk), indxTj      (:,iblk), &   ! LCOV_EXCL_LINE
     357             :                          indxUi      (:,iblk), indxUj      (:,iblk), &   ! LCOV_EXCL_LINE
     358             :                          aiU       (:,:,iblk), umass     (:,:,iblk), &   ! LCOV_EXCL_LINE
     359             :                          umassdti  (:,:,iblk), fcor_blk  (:,:,iblk), &   ! LCOV_EXCL_LINE
     360             :                          umask     (:,:,iblk),                       &   ! LCOV_EXCL_LINE
     361             :                          uocnU     (:,:,iblk), vocnU     (:,:,iblk), &   ! LCOV_EXCL_LINE
     362             :                          strairxU  (:,:,iblk), strairyU  (:,:,iblk), &   ! LCOV_EXCL_LINE
     363             :                          ss_tltxU  (:,:,iblk), ss_tltyU  (:,:,iblk), &   ! LCOV_EXCL_LINE
     364             :                          iceTmask  (:,:,iblk), iceUmask  (:,:,iblk), &   ! LCOV_EXCL_LINE
     365             :                          fmU       (:,:,iblk), dt,                   &   ! LCOV_EXCL_LINE
     366             :                          strtltxU  (:,:,iblk), strtltyU  (:,:,iblk), &   ! LCOV_EXCL_LINE
     367             :                          strocnxU  (:,:,iblk), strocnyU  (:,:,iblk), &   ! LCOV_EXCL_LINE
     368             :                          strintxU  (:,:,iblk), strintyU  (:,:,iblk), &   ! LCOV_EXCL_LINE
     369             :                          taubxU    (:,:,iblk), taubyU    (:,:,iblk), &   ! LCOV_EXCL_LINE
     370             :                          waterxU   (:,:,iblk), wateryU   (:,:,iblk), &   ! LCOV_EXCL_LINE
     371             :                          forcexU   (:,:,iblk), forceyU   (:,:,iblk), &   ! LCOV_EXCL_LINE
     372             :                          stressp_1 (:,:,iblk), stressp_2 (:,:,iblk), &   ! LCOV_EXCL_LINE
     373             :                          stressp_3 (:,:,iblk), stressp_4 (:,:,iblk), &   ! LCOV_EXCL_LINE
     374             :                          stressm_1 (:,:,iblk), stressm_2 (:,:,iblk), &   ! LCOV_EXCL_LINE
     375             :                          stressm_3 (:,:,iblk), stressm_4 (:,:,iblk), &   ! LCOV_EXCL_LINE
     376             :                          stress12_1(:,:,iblk), stress12_2(:,:,iblk), &   ! LCOV_EXCL_LINE
     377             :                          stress12_3(:,:,iblk), stress12_4(:,:,iblk), &   ! LCOV_EXCL_LINE
     378             :                          uvel_init (:,:,iblk), vvel_init (:,:,iblk), &   ! LCOV_EXCL_LINE
     379             :                          uvel      (:,:,iblk), vvel      (:,:,iblk), &   ! LCOV_EXCL_LINE
     380           0 :                          TbU       (:,:,iblk))
     381             : 
     382             :          call calc_bfix (nx_block            , ny_block            , &
     383             :                          icellU(iblk)        ,                       &   ! LCOV_EXCL_LINE
     384             :                          indxUi      (:,iblk), indxUj      (:,iblk), &   ! LCOV_EXCL_LINE
     385             :                          umassdti  (:,:,iblk),                       &   ! LCOV_EXCL_LINE
     386             :                          forcexU   (:,:,iblk), forceyU   (:,:,iblk), &   ! LCOV_EXCL_LINE
     387             :                          uvel_init (:,:,iblk), vvel_init (:,:,iblk), &   ! LCOV_EXCL_LINE
     388           0 :                          bxfix     (:,:,iblk), byfix     (:,:,iblk))
     389             : 
     390             :       !-----------------------------------------------------------------
     391             :       ! ice strength
     392             :       !-----------------------------------------------------------------
     393             : 
     394           0 :          strength(:,:,iblk) = c0  ! initialize
     395           0 :          do ij = 1, icellT(iblk)
     396           0 :             i = indxTi(ij, iblk)
     397           0 :             j = indxTj(ij, iblk)
     398             :             call icepack_ice_strength (ncat,                 &
     399             :                                        aice    (i,j,  iblk), &   ! LCOV_EXCL_LINE
     400             :                                        vice    (i,j,  iblk), &   ! LCOV_EXCL_LINE
     401             :                                        aice0   (i,j,  iblk), &   ! LCOV_EXCL_LINE
     402             :                                        aicen   (i,j,:,iblk), &   ! LCOV_EXCL_LINE
     403             :                                        vicen   (i,j,:,iblk), &   ! LCOV_EXCL_LINE
     404           0 :                                        strength(i,j,  iblk))
     405             :          enddo  ! ij
     406             : 
     407             :       enddo  ! iblk
     408             :       !$OMP END PARALLEL DO
     409             : 
     410           0 :       call icepack_warnings_flush(nu_diag)
     411           0 :       if (icepack_warnings_aborted()) call abort_ice(error_message=subname, &
     412           0 :          file=__FILE__, line=__LINE__)
     413             : 
     414           0 :       call ice_timer_start(timer_bound)
     415             :       call ice_HaloUpdate (strength,           halo_info, &
     416           0 :                            field_loc_center,   field_type_scalar)
     417             :       ! velocities may have changed in dyn_prep2
     418           0 :       call stack_fields(uvel, vvel, fld2)
     419             :       call ice_HaloUpdate (fld2,               halo_info, &
     420           0 :                            field_loc_NEcorner, field_type_vector)
     421           0 :       call unstack_fields(fld2, uvel, vvel)
     422           0 :       call ice_timer_stop(timer_bound)
     423             : 
     424           0 :       if (maskhalo_dyn) then
     425           0 :          call ice_timer_start(timer_bound)
     426           0 :          halomask = 0
     427           0 :          where (iceUmask) halomask = 1
     428           0 :          call ice_HaloUpdate (halomask,          halo_info, &
     429           0 :                               field_loc_center,  field_type_scalar)
     430           0 :          call ice_timer_stop(timer_bound)
     431           0 :          call ice_HaloMask(halo_info_mask, halo_info, halomask)
     432             :       endif
     433             : 
     434             :       !-----------------------------------------------------------------
     435             :       ! seabed stress factor TbU (TbU is part of Cb coefficient)
     436             :       !-----------------------------------------------------------------
     437           0 :       if (seabed_stress) then
     438           0 :          if ( seabed_stress_method == 'LKD' ) then
     439           0 :             !$OMP PARALLEL DO PRIVATE(iblk)
     440           0 :             do iblk = 1, nblocks
     441             :                call seabed_stress_factor_LKD (nx_block,         ny_block,       &
     442             :                                               icellU  (iblk),                   &   ! LCOV_EXCL_LINE
     443             :                                               indxUi(:,iblk),   indxUj(:,iblk), &   ! LCOV_EXCL_LINE
     444             :                                               vice(:,:,iblk),   aice(:,:,iblk), &   ! LCOV_EXCL_LINE
     445           0 :                                               hwater(:,:,iblk), TbU(:,:,iblk))
     446             :             enddo
     447             :             !$OMP END PARALLEL DO
     448             : 
     449           0 :          elseif ( seabed_stress_method == 'probabilistic' ) then
     450           0 :             !$OMP PARALLEL DO PRIVATE(iblk)
     451           0 :             do iblk = 1, nblocks
     452             : 
     453             :                call seabed_stress_factor_prob (nx_block,         ny_block,                   &
     454             :                                                icellT(iblk), indxTi(:,iblk), indxTj(:,iblk), &   ! LCOV_EXCL_LINE
     455             :                                                icellU(iblk), indxUi(:,iblk), indxUj(:,iblk), &   ! LCOV_EXCL_LINE
     456             :                                                aicen(:,:,:,iblk), vicen(:,:,:,iblk),         &   ! LCOV_EXCL_LINE
     457           0 :                                                hwater(:,:,iblk), TbU(:,:,iblk))
     458             :             enddo
     459             :             !$OMP END PARALLEL DO
     460             : 
     461             :          endif
     462             :       endif
     463             : 
     464             : 
     465             :       !-----------------------------------------------------------------
     466             :       ! calc size of problem (ntot) and allocate solution vector
     467             :       !-----------------------------------------------------------------
     468             : 
     469           0 :       ntot = 0
     470           0 :       do iblk = 1, nblocks
     471           0 :          ntot = ntot + icellU(iblk)
     472             :       enddo
     473           0 :       ntot = 2 * ntot ! times 2 because of u and v
     474             : 
     475           0 :       allocate(sol(ntot))
     476             : 
     477             :       !-----------------------------------------------------------------
     478             :       ! Start of nonlinear iteration
     479             :       !-----------------------------------------------------------------
     480             :       call anderson_solver (icellT  , icellU , &
     481             :                             indxTi  , indxTj , &   ! LCOV_EXCL_LINE
     482             :                             indxUi  , indxUj , &   ! LCOV_EXCL_LINE
     483             :                             aiU     , ntot   , &   ! LCOV_EXCL_LINE
     484             :                             uocnU   , vocnU  , &   ! LCOV_EXCL_LINE
     485             :                             waterxU , wateryU, &   ! LCOV_EXCL_LINE
     486             :                             bxfix   , byfix  , &   ! LCOV_EXCL_LINE
     487             :                             umassdti, sol    , &   ! LCOV_EXCL_LINE
     488             :                             fpresx  , fpresy , &   ! LCOV_EXCL_LINE
     489             :                             zetax2  , etax2  , &   ! LCOV_EXCL_LINE
     490             :                             rep_prs , cdn_ocnU,&   ! LCOV_EXCL_LINE
     491           0 :                             Cb, halo_info_mask)
     492             :       !-----------------------------------------------------------------
     493             :       ! End of nonlinear iteration
     494             :       !-----------------------------------------------------------------
     495             : 
     496           0 :       deallocate(sol)
     497             : 
     498           0 :       if (maskhalo_dyn) call ice_HaloDestroy(halo_info_mask)
     499             : 
     500             :       !-----------------------------------------------------------------
     501             :       ! Compute stresses
     502             :       !-----------------------------------------------------------------
     503           0 :       !$OMP PARALLEL DO PRIVATE(iblk)
     504           0 :       do iblk = 1, nblocks
     505             :          call stress_vp (nx_block            , ny_block            , &
     506             :                          icellT(iblk)        ,                       &   ! LCOV_EXCL_LINE
     507             :                          indxTi      (:,iblk), indxTj      (:,iblk), &   ! LCOV_EXCL_LINE
     508             :                          uvel      (:,:,iblk), vvel      (:,:,iblk), &   ! LCOV_EXCL_LINE
     509             :                          dxT       (:,:,iblk), dyT       (:,:,iblk), &   ! LCOV_EXCL_LINE
     510             :                          cxp       (:,:,iblk), cyp       (:,:,iblk), &   ! LCOV_EXCL_LINE
     511             :                          cxm       (:,:,iblk), cym       (:,:,iblk), &   ! LCOV_EXCL_LINE
     512             :                          zetax2  (:,:,iblk,:), etax2   (:,:,iblk,:), &   ! LCOV_EXCL_LINE
     513             :                          rep_prs (:,:,iblk,:),                       &   ! LCOV_EXCL_LINE
     514             :                          stressp_1 (:,:,iblk), stressp_2 (:,:,iblk), &   ! LCOV_EXCL_LINE
     515             :                          stressp_3 (:,:,iblk), stressp_4 (:,:,iblk), &   ! LCOV_EXCL_LINE
     516             :                          stressm_1 (:,:,iblk), stressm_2 (:,:,iblk), &   ! LCOV_EXCL_LINE
     517             :                          stressm_3 (:,:,iblk), stressm_4 (:,:,iblk), &   ! LCOV_EXCL_LINE
     518             :                          stress12_1(:,:,iblk), stress12_2(:,:,iblk), &   ! LCOV_EXCL_LINE
     519           0 :                          stress12_3(:,:,iblk), stress12_4(:,:,iblk))
     520             :       enddo ! iblk
     521             :       !$OMP END PARALLEL DO
     522             : 
     523             :       !-----------------------------------------------------------------
     524             :       ! Compute deformations
     525             :       !-----------------------------------------------------------------
     526           0 :       !$OMP PARALLEL DO PRIVATE(iblk)
     527           0 :       do iblk = 1, nblocks
     528             :          call deformations (nx_block            , ny_block            , &
     529             :                             icellT(iblk)        ,                       &   ! LCOV_EXCL_LINE
     530             :                             indxTi      (:,iblk), indxTj      (:,iblk), &   ! LCOV_EXCL_LINE
     531             :                             uvel      (:,:,iblk), vvel      (:,:,iblk), &   ! LCOV_EXCL_LINE
     532             :                             dxT       (:,:,iblk), dyT       (:,:,iblk), &   ! LCOV_EXCL_LINE
     533             :                             cxp       (:,:,iblk), cyp       (:,:,iblk), &   ! LCOV_EXCL_LINE
     534             :                             cxm       (:,:,iblk), cym       (:,:,iblk), &   ! LCOV_EXCL_LINE
     535             :                             tarear    (:,:,iblk),                       &   ! LCOV_EXCL_LINE
     536             :                             shear     (:,:,iblk), divu      (:,:,iblk), &   ! LCOV_EXCL_LINE
     537           0 :                             rdg_conv  (:,:,iblk), rdg_shear (:,:,iblk))
     538             :       enddo
     539             :       !$OMP END PARALLEL DO
     540             : 
     541             :       !-----------------------------------------------------------------
     542             :       ! Compute seabed stress (diagnostic)
     543             :       !-----------------------------------------------------------------
     544           0 :       if (seabed_stress) then
     545           0 :          !$OMP PARALLEL DO PRIVATE(iblk)
     546           0 :          do iblk = 1, nblocks
     547             :             call calc_seabed_stress (nx_block            ,  ny_block           , &
     548             :                                      icellU(iblk)        ,                       &   ! LCOV_EXCL_LINE
     549             :                                      indxUi      (:,iblk), indxUj      (:,iblk), &   ! LCOV_EXCL_LINE
     550             :                                      uvel      (:,:,iblk), vvel      (:,:,iblk), &   ! LCOV_EXCL_LINE
     551             :                                      Cb        (:,:,iblk),                       &   ! LCOV_EXCL_LINE
     552           0 :                                      taubxU    (:,:,iblk), taubyU    (:,:,iblk))
     553             :          enddo
     554             :          !$OMP END PARALLEL DO
     555             :       endif
     556             : 
     557             :       ! Force symmetry across the tripole seam
     558           0 :       if (trim(grid_type) == 'tripole') then
     559           0 :       if (maskhalo_dyn) then
     560             :          !-------------------------------------------------------
     561             :          ! set halomask to zero because ice_HaloMask always keeps
     562             :          ! local copies AND tripole zipper communication
     563             :          !-------------------------------------------------------
     564           0 :          halomask = 0
     565           0 :          call ice_HaloMask(halo_info_mask, halo_info, halomask)
     566             : 
     567             :          call ice_HaloUpdate_stress(stressp_1, stressp_3, halo_info_mask, &
     568           0 :                               field_loc_center,  field_type_scalar)
     569             :          call ice_HaloUpdate_stress(stressp_3, stressp_1, halo_info_mask, &
     570           0 :                               field_loc_center,  field_type_scalar)
     571             :          call ice_HaloUpdate_stress(stressp_2, stressp_4, halo_info_mask, &
     572           0 :                               field_loc_center,  field_type_scalar)
     573             :          call ice_HaloUpdate_stress(stressp_4, stressp_2, halo_info_mask, &
     574           0 :                               field_loc_center,  field_type_scalar)
     575             : 
     576             :          call ice_HaloUpdate_stress(stressm_1, stressm_3, halo_info_mask, &
     577           0 :                               field_loc_center,  field_type_scalar)
     578             :          call ice_HaloUpdate_stress(stressm_3, stressm_1, halo_info_mask, &
     579           0 :                               field_loc_center,  field_type_scalar)
     580             :          call ice_HaloUpdate_stress(stressm_2, stressm_4, halo_info_mask, &
     581           0 :                               field_loc_center,  field_type_scalar)
     582             :          call ice_HaloUpdate_stress(stressm_4, stressm_2, halo_info_mask, &
     583           0 :                               field_loc_center,  field_type_scalar)
     584             : 
     585             :          call ice_HaloUpdate_stress(stress12_1, stress12_3, halo_info_mask, &
     586           0 :                               field_loc_center,  field_type_scalar)
     587             :          call ice_HaloUpdate_stress(stress12_3, stress12_1, halo_info_mask, &
     588           0 :                               field_loc_center,  field_type_scalar)
     589             :          call ice_HaloUpdate_stress(stress12_2, stress12_4, halo_info_mask, &
     590           0 :                               field_loc_center,  field_type_scalar)
     591             :          call ice_HaloUpdate_stress(stress12_4, stress12_2, halo_info_mask, &
     592           0 :                               field_loc_center,  field_type_scalar)
     593             : 
     594           0 :          call ice_HaloDestroy(halo_info_mask)
     595             :       else
     596             :          call ice_HaloUpdate_stress(stressp_1, stressp_3, halo_info, &
     597           0 :                               field_loc_center,  field_type_scalar)
     598             :          call ice_HaloUpdate_stress(stressp_3, stressp_1, halo_info, &
     599           0 :                               field_loc_center,  field_type_scalar)
     600             :          call ice_HaloUpdate_stress(stressp_2, stressp_4, halo_info, &
     601           0 :                               field_loc_center,  field_type_scalar)
     602             :          call ice_HaloUpdate_stress(stressp_4, stressp_2, halo_info, &
     603           0 :                               field_loc_center,  field_type_scalar)
     604             : 
     605             :          call ice_HaloUpdate_stress(stressm_1, stressm_3, halo_info, &
     606           0 :                               field_loc_center,  field_type_scalar)
     607             :          call ice_HaloUpdate_stress(stressm_3, stressm_1, halo_info, &
     608           0 :                               field_loc_center,  field_type_scalar)
     609             :          call ice_HaloUpdate_stress(stressm_2, stressm_4, halo_info, &
     610           0 :                               field_loc_center,  field_type_scalar)
     611             :          call ice_HaloUpdate_stress(stressm_4, stressm_2, halo_info, &
     612           0 :                               field_loc_center,  field_type_scalar)
     613             : 
     614             :          call ice_HaloUpdate_stress(stress12_1, stress12_3, halo_info, &
     615           0 :                               field_loc_center,  field_type_scalar)
     616             :          call ice_HaloUpdate_stress(stress12_3, stress12_1, halo_info, &
     617           0 :                               field_loc_center,  field_type_scalar)
     618             :          call ice_HaloUpdate_stress(stress12_2, stress12_4, halo_info, &
     619           0 :                               field_loc_center,  field_type_scalar)
     620             :          call ice_HaloUpdate_stress(stress12_4, stress12_2, halo_info, &
     621           0 :                               field_loc_center,  field_type_scalar)
     622             :       endif   ! maskhalo
     623             :       endif   ! tripole
     624             : 
     625             :       !-----------------------------------------------------------------
     626             :       ! ice-ocean stress
     627             :       !-----------------------------------------------------------------
     628             : 
     629           0 :       !$OMP PARALLEL DO PRIVATE(iblk)
     630           0 :       do iblk = 1, nblocks
     631             : 
     632             :          call dyn_finish                               &
     633             :               (nx_block,           ny_block,           &   ! LCOV_EXCL_LINE
     634             :                icellU      (iblk), Cdn_ocnU(:,:,iblk), &   ! LCOV_EXCL_LINE
     635             :                indxUi    (:,iblk), indxUj    (:,iblk), &   ! LCOV_EXCL_LINE
     636             :                uvel    (:,:,iblk), vvel    (:,:,iblk), &   ! LCOV_EXCL_LINE
     637             :                uocnU   (:,:,iblk), vocnU   (:,:,iblk), &   ! LCOV_EXCL_LINE
     638             :                aiU     (:,:,iblk), fmU     (:,:,iblk), &   ! LCOV_EXCL_LINE
     639             : !               strintxU(:,:,iblk), strintyU(:,:,iblk), &   ! LCOV_EXCL_LINE
     640             : !               strairxU(:,:,iblk), strairyU(:,:,iblk), &   ! LCOV_EXCL_LINE
     641           0 :                strocnxU(:,:,iblk), strocnyU(:,:,iblk))
     642             : 
     643             :       enddo
     644             :       !$OMP END PARALLEL DO
     645             : 
     646             : ! shift velocity components from CD grid locations (N, E) to B grid location (U) for transport
     647             : ! commented out in order to focus on EVP for now within the cdgrid
     648             : ! should be used when routine is ready
     649             : !      if (grid_ice == 'CD' .or. grid_ice == 'C') then
     650             : !          call grid_average_X2Y('E2US',uvelE,uvel)
     651             : !          call grid_average_X2Y('N2US',vvelN,vvel)
     652             : !      endif
     653             : !end comment out
     654           0 :       call ice_timer_stop(timer_dynamics)    ! dynamics
     655             : 
     656           0 :       end subroutine implicit_solver
     657             : 
     658             : !=======================================================================
     659             : 
     660             : ! Solve the nonlinear equation F(u,v) = 0, where
     661             : ! F(u,v) := A(u,v) * (u,v) - b(u,v)
     662             : ! using Anderson acceleration (accelerated fixed point (Picard) iteration)
     663             : !
     664             : ! author: JF Lemieux, A. Qaddouri, F. Dupont and P. Blain ECCC
     665             : !
     666             : ! Anderson algorithm adadpted from:
     667             : ! H. F. Walker, “Anderson Acceleration: Algorithms and Implementations”
     668             : !   [Online]. Available: https://users.wpi.edu/~walker/Papers/anderson_accn_algs_imps.pdf
     669             : 
     670           0 :       subroutine anderson_solver (icellT  , icellU , &
     671             :                                   indxTi  , indxTj , &   ! LCOV_EXCL_LINE
     672             :                                   indxUi  , indxUj , &   ! LCOV_EXCL_LINE
     673             :                                   aiU     , ntot   , &   ! LCOV_EXCL_LINE
     674             :                                   uocn    , vocn   , &   ! LCOV_EXCL_LINE
     675             :                                   waterxU , wateryU, &   ! LCOV_EXCL_LINE
     676             :                                   bxfix   , byfix  , &   ! LCOV_EXCL_LINE
     677             :                                   umassdti, sol    , &   ! LCOV_EXCL_LINE
     678             :                                   fpresx  , fpresy , &   ! LCOV_EXCL_LINE
     679             :                                   zetax2  , etax2  , &   ! LCOV_EXCL_LINE
     680             :                                   rep_prs , cdn_ocn, &   ! LCOV_EXCL_LINE
     681           0 :                                   Cb, halo_info_mask)
     682             : 
     683             :       use ice_blocks, only: nx_block, ny_block
     684             :       use ice_boundary, only: ice_HaloUpdate
     685             :       use ice_constants, only: c1
     686             :       use ice_domain, only: maskhalo_dyn, halo_info
     687             :       use ice_domain_size, only: max_blocks
     688             :       use ice_flux, only:   fmU, TbU
     689             :       use ice_grid, only: dxT, dyT, dxhy, dyhx, cxp, cyp, cxm, cym, &
     690             :            uarear
     691             :       use ice_dyn_shared, only: DminTarea
     692             :       use ice_state, only: uvel, vvel, strength
     693             :       use ice_timers, only: ice_timer_start, ice_timer_stop, timer_bound
     694             : 
     695             :       integer (kind=int_kind), intent(in) :: &
     696             :          ntot         ! size of problem for Anderson
     697             : 
     698             :       integer (kind=int_kind), dimension(max_blocks), intent(in) :: &
     699             :          icellT   , & ! no. of cells where iceTmask = .true.   ! LCOV_EXCL_LINE
     700             :          icellU       ! no. of cells where iceUmask = .true.
     701             : 
     702             :       integer (kind=int_kind), dimension (nx_block*ny_block, max_blocks), intent(in) :: &
     703             :          indxTi   , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
     704             :          indxTj   , & ! compressed index in j-direction   ! LCOV_EXCL_LINE
     705             :          indxUi   , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
     706             :          indxUj       ! compressed index in j-direction
     707             : 
     708             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks), intent(in) :: &
     709             :          aiU      , & ! ice fraction on u-grid   ! LCOV_EXCL_LINE
     710             :          uocn     , & ! i ocean current (m/s)   ! LCOV_EXCL_LINE
     711             :          vocn     , & ! j ocean current (m/s)   ! LCOV_EXCL_LINE
     712             :          cdn_ocn  , & ! ocn drag coefficient   ! LCOV_EXCL_LINE
     713             :          waterxU  , & ! for ocean stress calculation, x (m/s)   ! LCOV_EXCL_LINE
     714             :          wateryU  , & ! for ocean stress calculation, y (m/s)   ! LCOV_EXCL_LINE
     715             :          bxfix    , & ! part of bx that is constant during Picard   ! LCOV_EXCL_LINE
     716             :          byfix    , & ! part of by that is constant during Picard   ! LCOV_EXCL_LINE
     717             :          umassdti     ! mass of U-cell/dte (kg/m^2 s)
     718             : 
     719             :       real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks,4), intent(out) :: &
     720             :          zetax2   , & ! zetax2 = 2*zeta (bulk viscosity)   ! LCOV_EXCL_LINE
     721             :          etax2    , & ! etax2  = 2*eta  (shear viscosity)   ! LCOV_EXCL_LINE
     722             :          rep_prs      ! replacement pressure
     723             : 
     724             :       type (ice_halo), intent(in) :: &
     725             :          halo_info_mask !  ghost cell update info for masked halo
     726             : 
     727             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks), intent(inout) :: &
     728             :          fpresx   , & ! fixed point residual vector, x components: fx = uvel - uprev_k   ! LCOV_EXCL_LINE
     729             :          fpresy   , & ! fixed point residual vector, y components: fy = vvel - vprev_k   ! LCOV_EXCL_LINE
     730             :          Cb           ! seabed stress coefficient
     731             : 
     732             :       real (kind=dbl_kind), dimension (ntot), intent(inout) :: &
     733             :          sol          ! current approximate solution
     734             : 
     735             :       ! local variables
     736             : 
     737             :       integer (kind=int_kind) :: &
     738             :          it_nl      , & ! nonlinear loop iteration index   ! LCOV_EXCL_LINE
     739             :          res_num    , & ! current number of stored residuals   ! LCOV_EXCL_LINE
     740             :          j          , & ! iteration index for QR update   ! LCOV_EXCL_LINE
     741             :          iblk       , & ! block index   ! LCOV_EXCL_LINE
     742             :          nbiter         ! number of FGMRES iterations performed
     743             : 
     744             :       integer (kind=int_kind), parameter :: &
     745             :          inc = 1        ! increment value for BLAS calls
     746             : 
     747             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks) :: &
     748             :          uprev_k  , & ! uvel at previous Picard iteration   ! LCOV_EXCL_LINE
     749             :          vprev_k  , & ! vvel at previous Picard iteration   ! LCOV_EXCL_LINE
     750             :          ulin     , & ! uvel to linearize vrel   ! LCOV_EXCL_LINE
     751             :          vlin     , & ! vvel to linearize vrel   ! LCOV_EXCL_LINE
     752             :          vrel     , & ! coeff for tauw   ! LCOV_EXCL_LINE
     753             :          bx       , & ! b vector   ! LCOV_EXCL_LINE
     754             :          by       , & ! b vector   ! LCOV_EXCL_LINE
     755             :          diagx    , & ! Diagonal (x component) of the matrix A   ! LCOV_EXCL_LINE
     756             :          diagy    , & ! Diagonal (y component) of the matrix A   ! LCOV_EXCL_LINE
     757             :          Au       , & ! matvec, Fx = bx - Au   ! LCOV_EXCL_LINE
     758             :          Av       , & ! matvec, Fy = by - Av   ! LCOV_EXCL_LINE
     759             :          Fx       , & ! x residual vector, Fx = bx - Au   ! LCOV_EXCL_LINE
     760             :          Fy       , & ! y residual vector, Fy = by - Av   ! LCOV_EXCL_LINE
     761             :          solx     , & ! solution of FGMRES (x components)   ! LCOV_EXCL_LINE
     762           0 :          soly         ! solution of FGMRES (y components)
     763             : 
     764             :       real (kind=dbl_kind), dimension(nx_block,ny_block,8):: &
     765             :          stress_Pr,   & ! x,y-derivatives of the replacement pressure   ! LCOV_EXCL_LINE
     766           0 :          diag_rheo      ! contributions of the rhelogy term to the diagonal
     767             : 
     768             :       real (kind=dbl_kind), dimension (ntot) :: &
     769             :          res        , & ! current residual   ! LCOV_EXCL_LINE
     770             :          res_old    , & ! previous residual   ! LCOV_EXCL_LINE
     771             :          res_diff   , & ! difference between current and previous residuals   ! LCOV_EXCL_LINE
     772             :          fpfunc     , & ! current value of fixed point function   ! LCOV_EXCL_LINE
     773             :          fpfunc_old , & ! previous value of fixed point function   ! LCOV_EXCL_LINE
     774             :          tmp            ! temporary vector for BLAS calls
     775             : 
     776             :       real (kind=dbl_kind), dimension(ntot,dim_andacc) :: &
     777             :          Q        , & ! Q factor for QR factorization of F (residuals) matrix   ! LCOV_EXCL_LINE
     778             :          G_diff       ! Matrix containing the differences of g(x) (fixed point function) evaluations
     779             : 
     780             :       real (kind=dbl_kind), dimension(dim_andacc,dim_andacc) :: &
     781             :          R            ! R factor for QR factorization of F (residuals) matrix
     782             : 
     783             :       real (kind=dbl_kind), dimension(dim_andacc) :: &
     784             :          rhs_tri  , & ! right hand side vector for matrix-vector product   ! LCOV_EXCL_LINE
     785             :          coeffs       ! coeffs used to combine previous solutions
     786             : 
     787             :       real (kind=dbl_kind) :: &
     788             :          ! tol         , & ! tolerance for fixed point convergence: reltol_andacc * (initial fixed point residual norm)  [unused for now]   ! LCOV_EXCL_LINE
     789             :          tol_nl      , & ! tolerance for nonlinear convergence: reltol_nonlin * (initial nonlinear residual norm)   ! LCOV_EXCL_LINE
     790             :          fpres_norm  , & ! norm of current fixed point residual : f(x) = g(x) - x   ! LCOV_EXCL_LINE
     791             :          prog_norm   , & ! norm of difference between current and previous solution   ! LCOV_EXCL_LINE
     792           0 :          nlres_norm      ! norm of current nonlinear residual : F(x) = A(x)x -b(x)
     793             : 
     794             : #ifdef USE_LAPACK
     795             :       real (kind=dbl_kind) :: &
     796             :          ddot, dnrm2     ! external BLAS functions
     797             : #endif
     798             : 
     799             :       character(len=*), parameter :: subname = '(anderson_solver)'
     800             : 
     801             :       ! Initialization
     802           0 :       res_num = 0
     803             : 
     804           0 :       !$OMP PARALLEL DO PRIVATE(iblk)
     805           0 :       do iblk = 1, nblocks
     806           0 :          uprev_k(:,:,iblk) = uvel(:,:,iblk)
     807           0 :          vprev_k(:,:,iblk) = vvel(:,:,iblk)
     808             :       enddo
     809             :       !$OMP END PARALLEL DO
     810             : 
     811             :       ! Start iterations
     812           0 :       do it_nl = 0, maxits_nonlin        ! nonlinear iteration loop
     813             :          ! Compute quantities needed for computing PDE residual and g(x) (fixed point map)
     814             :          !-----------------------------------------------------------------
     815             :          ! Calc zetax2, etax2, dPr/dx, dPr/dy, Cb and vrel = f(uprev_k, vprev_k)
     816             :          !-----------------------------------------------------------------
     817           0 :          !$OMP PARALLEL DO PRIVATE(iblk,stress_Pr)
     818           0 :          do iblk = 1, nblocks
     819             : 
     820           0 :             if (use_mean_vrel) then
     821           0 :                ulin(:,:,iblk) = p5*uprev_k(:,:,iblk) + p5*uvel(:,:,iblk)
     822           0 :                vlin(:,:,iblk) = p5*vprev_k(:,:,iblk) + p5*vvel(:,:,iblk)
     823             :             else
     824           0 :                ulin(:,:,iblk) = uvel(:,:,iblk)
     825           0 :                vlin(:,:,iblk) = vvel(:,:,iblk)
     826             :             endif
     827           0 :             uprev_k(:,:,iblk) = uvel(:,:,iblk)
     828           0 :             vprev_k(:,:,iblk) = vvel(:,:,iblk)
     829             : 
     830             :             call calc_zeta_dPr (nx_block           , ny_block          , &
     831             :                                 icellT       (iblk),                     &   ! LCOV_EXCL_LINE
     832             :                                 indxTi     (:,iblk), indxTj    (:,iblk), &   ! LCOV_EXCL_LINE
     833             :                                 uprev_k  (:,:,iblk), vprev_k (:,:,iblk), &   ! LCOV_EXCL_LINE
     834             :                                 dxT      (:,:,iblk), dyT     (:,:,iblk), &   ! LCOV_EXCL_LINE
     835             :                                 dxhy     (:,:,iblk), dyhx    (:,:,iblk), &   ! LCOV_EXCL_LINE
     836             :                                 cxp      (:,:,iblk), cyp     (:,:,iblk), &   ! LCOV_EXCL_LINE
     837             :                                 cxm      (:,:,iblk), cym     (:,:,iblk), &   ! LCOV_EXCL_LINE
     838             :                                 DminTarea (:,:,iblk),strength (:,:,iblk),&   ! LCOV_EXCL_LINE
     839             :                                 zetax2 (:,:,iblk,:), etax2  (:,:,iblk,:),&   ! LCOV_EXCL_LINE
     840           0 :                                 rep_prs(:,:,iblk,:), stress_Pr  (:,:,:))
     841             : 
     842             :             call calc_vrel_Cb (nx_block           , ny_block          , &
     843             :                                icellU       (iblk), Cdn_ocn (:,:,iblk), &   ! LCOV_EXCL_LINE
     844             :                                indxUi     (:,iblk), indxUj    (:,iblk), &   ! LCOV_EXCL_LINE
     845             :                                aiU      (:,:,iblk), TbU     (:,:,iblk), &   ! LCOV_EXCL_LINE
     846             :                                uocn     (:,:,iblk), vocn    (:,:,iblk), &   ! LCOV_EXCL_LINE
     847             :                                ulin     (:,:,iblk), vlin    (:,:,iblk), &   ! LCOV_EXCL_LINE
     848           0 :                                vrel     (:,:,iblk), Cb      (:,:,iblk))
     849             : 
     850             :             ! prepare b vector (RHS)
     851             :             call calc_bvec (nx_block           , ny_block          , &
     852             :                             icellU       (iblk),                     &   ! LCOV_EXCL_LINE
     853             :                             indxUi     (:,iblk), indxUj    (:,iblk), &   ! LCOV_EXCL_LINE
     854             :                             stress_Pr   (:,:,:), uarear  (:,:,iblk), &   ! LCOV_EXCL_LINE
     855             :                             waterxU  (:,:,iblk), wateryU (:,:,iblk), &   ! LCOV_EXCL_LINE
     856             :                             bxfix    (:,:,iblk), byfix   (:,:,iblk), &   ! LCOV_EXCL_LINE
     857             :                             bx       (:,:,iblk), by      (:,:,iblk), &   ! LCOV_EXCL_LINE
     858           0 :                             vrel     (:,:,iblk))
     859             : 
     860             :             ! Compute nonlinear residual norm (PDE residual)
     861             :             call matvec (nx_block             , ny_block           , &
     862             :                          icellU       (iblk)  , icellT       (iblk), &   ! LCOV_EXCL_LINE
     863             :                          indxUi     (:,iblk)  , indxUj     (:,iblk), &   ! LCOV_EXCL_LINE
     864             :                          indxTi     (:,iblk)  , indxTj     (:,iblk), &   ! LCOV_EXCL_LINE
     865             :                          dxT      (:,:,iblk)  , dyT      (:,:,iblk), &   ! LCOV_EXCL_LINE
     866             :                          dxhy     (:,:,iblk)  , dyhx     (:,:,iblk), &   ! LCOV_EXCL_LINE
     867             :                          cxp      (:,:,iblk)  , cyp      (:,:,iblk), &   ! LCOV_EXCL_LINE
     868             :                          cxm      (:,:,iblk)  , cym      (:,:,iblk), &   ! LCOV_EXCL_LINE
     869             :                          uprev_k  (:,:,iblk)  , vprev_k  (:,:,iblk), &   ! LCOV_EXCL_LINE
     870             :                          vrel     (:,:,iblk)  , Cb       (:,:,iblk), &   ! LCOV_EXCL_LINE
     871             :                          zetax2   (:,:,iblk,:), etax2  (:,:,iblk,:), &   ! LCOV_EXCL_LINE
     872             :                          umassdti (:,:,iblk)  , fmU      (:,:,iblk), &   ! LCOV_EXCL_LINE
     873             :                          uarear   (:,:,iblk)  ,                      &   ! LCOV_EXCL_LINE
     874           0 :                          Au       (:,:,iblk)  , Av       (:,:,iblk))
     875             :             call residual_vec (nx_block           , ny_block          , &
     876             :                                icellU       (iblk),                     &   ! LCOV_EXCL_LINE
     877             :                                indxUi     (:,iblk), indxUj    (:,iblk), &   ! LCOV_EXCL_LINE
     878             :                                bx       (:,:,iblk), by      (:,:,iblk), &   ! LCOV_EXCL_LINE
     879             :                                Au       (:,:,iblk), Av      (:,:,iblk), &   ! LCOV_EXCL_LINE
     880           0 :                                Fx       (:,:,iblk), Fy      (:,:,iblk))
     881             :          enddo
     882             :          !$OMP END PARALLEL DO
     883             :          nlres_norm = global_norm(nx_block, ny_block, &
     884             :                                   icellU  ,           &   ! LCOV_EXCL_LINE
     885             :                                   indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
     886           0 :                                   Fx      , Fy        )
     887           0 :          if (my_task == master_task .and. monitor_nonlin) then
     888           0 :             write(nu_diag, '(a,i4,a,d26.16)') "monitor_nonlin: iter_nonlin= ", it_nl, &
     889           0 :                                               " nonlin_res_L2norm= ", nlres_norm
     890             :          endif
     891             :          ! Compute relative tolerance at first iteration
     892           0 :          if (it_nl == 0) then
     893           0 :             tol_nl = reltol_nonlin*nlres_norm
     894             :          endif
     895             : 
     896             :          ! Check for nonlinear convergence
     897           0 :          if (nlres_norm < tol_nl) then
     898           0 :             exit
     899             :          endif
     900             : 
     901             :          ! Put initial guess for FGMRES in solx,soly and sol (needed for anderson)
     902           0 :          solx = uprev_k
     903           0 :          soly = vprev_k
     904             :          call arrays_to_vec (nx_block       , ny_block       , &
     905             :                              nblocks        , max_blocks     , &   ! LCOV_EXCL_LINE
     906             :                              icellU      (:), ntot           , &   ! LCOV_EXCL_LINE
     907             :                              indxUi    (:,:), indxUj    (:,:), &   ! LCOV_EXCL_LINE
     908             :                              uprev_k (:,:,:), vprev_k (:,:,:), &   ! LCOV_EXCL_LINE
     909           0 :                              sol         (:))
     910             : 
     911             :          ! Compute fixed point map g(x)
     912           0 :          if (fpfunc_andacc == 1) then
     913             :             ! g_1(x) = FGMRES(A(x), b(x))
     914             : 
     915             :             ! Prepare diagonal for preconditioner
     916           0 :             if (precond == 'diag' .or. precond == 'pgmres') then
     917           0 :                !$OMP PARALLEL DO PRIVATE(iblk,diag_rheo)
     918           0 :                do iblk = 1, nblocks
     919             :                   ! first compute diagonal contributions due to rheology term
     920             :                   call formDiag_step1 (nx_block           , ny_block      ,    &
     921             :                                        icellU     (iblk)  ,                    &   ! LCOV_EXCL_LINE
     922             :                                        indxUi   (:,iblk)  , indxUj(:,iblk),    &   ! LCOV_EXCL_LINE
     923             :                                        dxT    (:,:,iblk)  , dyT (:,:,iblk),    &   ! LCOV_EXCL_LINE
     924             :                                        dxhy   (:,:,iblk)  , dyhx(:,:,iblk),    &   ! LCOV_EXCL_LINE
     925             :                                        cxp    (:,:,iblk)  , cyp (:,:,iblk),    &   ! LCOV_EXCL_LINE
     926             :                                        cxm    (:,:,iblk)  , cym (:,:,iblk),    &   ! LCOV_EXCL_LINE
     927             :                                        zetax2 (:,:,iblk,:), etax2(:,:,iblk,:), &   ! LCOV_EXCL_LINE
     928           0 :                                        diag_rheo(:,:,:))
     929             :                   ! second compute the full diagonal
     930             :                   call formDiag_step2 (nx_block           , ny_block          , &
     931             :                                        icellU       (iblk),                     &   ! LCOV_EXCL_LINE
     932             :                                        indxUi     (:,iblk), indxUj    (:,iblk), &   ! LCOV_EXCL_LINE
     933             :                                        diag_rheo   (:,:,:), vrel    (:,:,iblk), &   ! LCOV_EXCL_LINE
     934             :                                        umassdti (:,:,iblk),                     &   ! LCOV_EXCL_LINE
     935             :                                        uarear   (:,:,iblk), Cb      (:,:,iblk), &   ! LCOV_EXCL_LINE
     936           0 :                                        diagx    (:,:,iblk), diagy   (:,:,iblk))
     937             :                enddo
     938             :                !$OMP END PARALLEL DO
     939             :             endif
     940             : 
     941             :             ! FGMRES linear solver
     942             :             call fgmres (zetax2        , etax2     , &
     943             :                          Cb            , vrel      , &   ! LCOV_EXCL_LINE
     944             :                          umassdti      ,             &   ! LCOV_EXCL_LINE
     945             :                          halo_info_mask,             &   ! LCOV_EXCL_LINE
     946             :                          bx            , by        , &   ! LCOV_EXCL_LINE
     947             :                          diagx         , diagy     , &   ! LCOV_EXCL_LINE
     948             :                          reltol_fgmres , dim_fgmres, &   ! LCOV_EXCL_LINE
     949             :                          maxits_fgmres ,             &   ! LCOV_EXCL_LINE
     950             :                          solx          , soly      , &   ! LCOV_EXCL_LINE
     951           0 :                          nbiter)
     952             :             ! Put FGMRES solution solx,soly in fpfunc vector (needed for Anderson)
     953             :             call arrays_to_vec (nx_block       , ny_block     , &
     954             :                                 nblocks        , max_blocks   , &   ! LCOV_EXCL_LINE
     955             :                                 icellU      (:), ntot         , &   ! LCOV_EXCL_LINE
     956             :                                 indxUi    (:,:), indxUj  (:,:), &   ! LCOV_EXCL_LINE
     957             :                                 solx    (:,:,:), soly  (:,:,:), &   ! LCOV_EXCL_LINE
     958           0 :                                 fpfunc      (:))
     959           0 :          elseif (fpfunc_andacc == 2) then
     960             :             ! g_2(x) = x - A(x)x + b(x) = x - F(x)
     961             :             call abort_ice(error_message=subname // " Fixed point function g_2(x) not yet implemented (fpfunc_andacc = 2)" , &
     962           0 :                file=__FILE__, line=__LINE__)
     963             :          endif
     964             : 
     965             :          ! Compute fixed point residual f(x) = g(x) - x
     966           0 :          res = fpfunc - sol
     967             : #ifdef USE_LAPACK
     968             :          fpres_norm = global_sum(dnrm2(size(res), res, inc)**2, distrb_info)
     969             : #else
     970             :          call vec_to_arrays (nx_block      , ny_block    , &
     971             :                              nblocks       , max_blocks  , &   ! LCOV_EXCL_LINE
     972             :                              icellU     (:), ntot        , &   ! LCOV_EXCL_LINE
     973             :                              indxUi   (:,:), indxUj(:,:) , &   ! LCOV_EXCL_LINE
     974             :                              res        (:),               &   ! LCOV_EXCL_LINE
     975           0 :                              fpresx (:,:,:), fpresy (:,:,:))
     976             :          fpres_norm = global_norm(nx_block, ny_block, &
     977             :                                   icellU  ,           &   ! LCOV_EXCL_LINE
     978             :                                   indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
     979           0 :                                   fpresx  , fpresy    )
     980             : #endif
     981           0 :          if (my_task == master_task .and. monitor_nonlin) then
     982           0 :             write(nu_diag, '(a,i4,a,d26.16)') "monitor_nonlin: iter_nonlin= ", it_nl, &
     983           0 :                                               " fixed_point_res_L2norm= ", fpres_norm
     984             :          endif
     985             : 
     986             :          ! Not used for now (only nonlinear residual is checked)
     987             :          ! ! Store initial residual norm
     988             :          ! if (it_nl == 0) then
     989             :          !    tol = reltol_andacc*fpres_norm
     990             :          ! endif
     991             :          !
     992             :          ! ! Check residual
     993             :          ! if (fpres_norm < tol) then
     994             :          !    exit
     995             :          ! endif
     996             : 
     997           0 :          if (dim_andacc == 0 .or. it_nl < start_andacc) then
     998             :             ! Simple fixed point (Picard) iteration in this case
     999           0 :             sol = fpfunc
    1000             :          else
    1001             : #ifdef USE_LAPACK
    1002             :             ! Begin Anderson acceleration
    1003             :             if (get_num_procs() > 1) then
    1004             :                ! Anderson solver is not yet parallelized; abort
    1005             :                if (my_task == master_task) then
    1006             :                   call abort_ice(error_message=subname // " Anderson solver (algo_nonlin = 'anderson') is not yet parallelized, and nprocs > 1 " , &
    1007             :                      file=__FILE__, line=__LINE__)
    1008             :                endif
    1009             :             endif
    1010             :             if (it_nl > start_andacc) then
    1011             :                ! Update residual difference vector
    1012             :                res_diff = res - res_old
    1013             :                ! Update fixed point function difference matrix
    1014             :                if (res_num < dim_andacc) then
    1015             :                   ! Add column
    1016             :                   G_diff(:,res_num+1) = fpfunc - fpfunc_old
    1017             :                else
    1018             :                   ! Delete first column and add column
    1019             :                   G_diff(:,1:res_num-1) = G_diff(:,2:res_num)
    1020             :                   G_diff(:,res_num) = fpfunc - fpfunc_old
    1021             :                endif
    1022             :                res_num = res_num + 1
    1023             :             endif
    1024             :             res_old = res
    1025             :             fpfunc_old = fpfunc
    1026             :             if (res_num == 0) then
    1027             :                sol = fpfunc
    1028             :             else
    1029             :                if (res_num == 1) then
    1030             :                   ! Initialize QR factorization
    1031             :                   R(1,1) = dnrm2(size(res_diff), res_diff, inc)
    1032             :                   Q(:,1) = res_diff/R(1,1)
    1033             :                else
    1034             :                   if (res_num > dim_andacc) then
    1035             :                      ! Update factorization since 1st column was deleted
    1036             :                      call qr_delete(Q,R)
    1037             :                      res_num = res_num - 1
    1038             :                   endif
    1039             :                   ! Update QR factorization for new column
    1040             :                   do j = 1, res_num - 1
    1041             :                      R(j,res_num) = ddot(ntot, Q(:,j), inc, res_diff, inc)
    1042             :                      res_diff = res_diff - R(j,res_num) * Q(:,j)
    1043             :                   enddo
    1044             :                   R(res_num, res_num) = dnrm2(size(res_diff) ,res_diff, inc)
    1045             :                   Q(:,res_num) = res_diff / R(res_num, res_num)
    1046             :                endif
    1047             :                ! TODO: here, drop more columns to improve conditioning
    1048             :                ! if (droptol) then
    1049             : 
    1050             :                ! endif
    1051             :                ! Solve least square problem for coefficients
    1052             :                ! 1. Compute rhs_tri = Q^T * res
    1053             :                call dgemv ('t', size(Q,1), res_num, c1, Q(:,1:res_num), size(Q,1), res, inc, c0, rhs_tri, inc)
    1054             :                ! 2. Solve R*coeffs = rhs_tri, put result in rhs_tri
    1055             :                call dtrsv ('u', 'n', 'n', res_num, R(1:res_num,1:res_num), res_num, rhs_tri, inc)
    1056             :                coeffs = rhs_tri
    1057             :                ! Update approximate solution: x = fpfunc - G_diff*coeffs, put result in fpfunc
    1058             :                call dgemv ('n', size(G_diff,1), res_num, -c1, G_diff(:,1:res_num), size(G_diff,1), coeffs, inc, c1, fpfunc, inc)
    1059             :                sol = fpfunc
    1060             :                ! Apply damping
    1061             :                if (damping_andacc > 0 .and. damping_andacc /= 1) then
    1062             :                   ! x = x - (1-beta) (res - Q*R*coeffs)
    1063             : 
    1064             :                   ! tmp = R*coeffs
    1065             :                   call dgemv ('n', res_num, res_num, c1, R(1:res_num,1:res_num), res_num, coeffs, inc, c0, tmp, inc)
    1066             :                   ! res = res - Q*tmp
    1067             :                   call dgemv ('n', size(Q,1), res_num, -c1, Q(:,1:res_num), size(Q,1), tmp, inc, c1, res, inc)
    1068             :                   ! x = x - (1-beta)*res
    1069             :                   sol = sol - (1-damping_andacc)*res
    1070             :                endif
    1071             :             endif
    1072             : #else
    1073             :             ! Anderson solver is not usable without LAPACK; abort
    1074             :             call abort_ice(error_message=subname // " CICE was not compiled with LAPACK, "// &
    1075             :                            "and Anderson solver was chosen (algo_nonlin = 'anderson')" , &   ! LCOV_EXCL_LINE
    1076           0 :                file=__FILE__, line=__LINE__)
    1077             : #endif
    1078             :          endif
    1079             : 
    1080             :          !-----------------------------------------------------------------------
    1081             :          !     Put vector sol in uvel and vvel arrays
    1082             :          !-----------------------------------------------------------------------
    1083             :          call vec_to_arrays (nx_block    , ny_block    , &
    1084             :                              nblocks     , max_blocks  , &   ! LCOV_EXCL_LINE
    1085             :                              icellU   (:), ntot        , &   ! LCOV_EXCL_LINE
    1086             :                              indxUi (:,:), indxUj (:,:), &   ! LCOV_EXCL_LINE
    1087             :                              sol      (:),               &   ! LCOV_EXCL_LINE
    1088           0 :                              uvel (:,:,:), vvel (:,:,:))
    1089             : 
    1090             :          ! Do halo update so that halo cells contain up to date info for advection
    1091           0 :          call stack_fields(uvel, vvel, fld2)
    1092           0 :          call ice_timer_start(timer_bound)
    1093           0 :          if (maskhalo_dyn) then
    1094             :             call ice_HaloUpdate (fld2,               halo_info_mask, &
    1095           0 :                                  field_loc_NEcorner, field_type_vector)
    1096             :          else
    1097             :             call ice_HaloUpdate (fld2,               halo_info, &
    1098           0 :                                  field_loc_NEcorner, field_type_vector)
    1099             :          endif
    1100           0 :          call ice_timer_stop(timer_bound)
    1101           0 :          call unstack_fields(fld2, uvel, vvel)
    1102             : 
    1103             :          ! Compute "progress" residual norm
    1104           0 :          !$OMP PARALLEL DO PRIVATE(iblk)
    1105           0 :          do iblk = 1, nblocks
    1106           0 :             fpresx(:,:,iblk) = uvel(:,:,iblk) - uprev_k(:,:,iblk)
    1107           0 :             fpresy(:,:,iblk) = vvel(:,:,iblk) - vprev_k(:,:,iblk)
    1108             :          enddo
    1109             :          !$OMP END PARALLEL DO
    1110             :          prog_norm = global_norm(nx_block, ny_block, &
    1111             :                                  icellU  ,           &   ! LCOV_EXCL_LINE
    1112             :                                  indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    1113           0 :                                  fpresx  , fpresy    )
    1114           0 :          if (my_task == master_task .and. monitor_nonlin) then
    1115           0 :             write(nu_diag, '(a,i4,a,d26.16)') "monitor_nonlin: iter_nonlin= ", it_nl, &
    1116           0 :                                               " progress_res_L2norm= ", prog_norm
    1117             :          endif
    1118             : 
    1119             :       enddo ! nonlinear iteration loop
    1120             : 
    1121           0 :       end subroutine anderson_solver
    1122             : 
    1123             : !=======================================================================
    1124             : 
    1125             : ! Computes the viscosities and dPr/dx, dPr/dy
    1126             : 
    1127           0 :       subroutine calc_zeta_dPr (nx_block, ny_block, &
    1128             :                                 icellT  ,           &   ! LCOV_EXCL_LINE
    1129             :                                 indxTi  , indxTj  , &   ! LCOV_EXCL_LINE
    1130             :                                 uvel    , vvel    , &   ! LCOV_EXCL_LINE
    1131             :                                 dxT     , dyT     , &   ! LCOV_EXCL_LINE
    1132             :                                 dxhy    , dyhx    , &   ! LCOV_EXCL_LINE
    1133             :                                 cxp     , cyp     , &   ! LCOV_EXCL_LINE
    1134             :                                 cxm     , cym     , &   ! LCOV_EXCL_LINE
    1135             :                                 DminTarea,strength, &   ! LCOV_EXCL_LINE
    1136             :                                 zetax2  , etax2   , &   ! LCOV_EXCL_LINE
    1137           0 :                                 rep_prs , stPr)
    1138             : 
    1139             :       use ice_dyn_shared, only: strain_rates, visc_replpress, &
    1140             :                                 capping
    1141             : 
    1142             :       integer (kind=int_kind), intent(in) :: &
    1143             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    1144             :          icellT                ! no. of cells where iceTmask = .true.
    1145             : 
    1146             :       integer (kind=int_kind), dimension (nx_block*ny_block), intent(in) :: &
    1147             :          indxTi   , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    1148             :          indxTj       ! compressed index in j-direction
    1149             : 
    1150             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    1151             :          strength , & ! ice strength (N/m)   ! LCOV_EXCL_LINE
    1152             :          uvel     , & ! x-component of velocity (m/s)   ! LCOV_EXCL_LINE
    1153             :          vvel     , & ! y-component of velocity (m/s)   ! LCOV_EXCL_LINE
    1154             :          dxT      , & ! width of T-cell through the middle (m)   ! LCOV_EXCL_LINE
    1155             :          dyT      , & ! height of T-cell through the middle (m)   ! LCOV_EXCL_LINE
    1156             :          dxhy     , & ! 0.5*(HTE - HTW)   ! LCOV_EXCL_LINE
    1157             :          dyhx     , & ! 0.5*(HTN - HTS)   ! LCOV_EXCL_LINE
    1158             :          cyp      , & ! 1.5*HTE - 0.5*HTW   ! LCOV_EXCL_LINE
    1159             :          cxp      , & ! 1.5*HTN - 0.5*HTS   ! LCOV_EXCL_LINE
    1160             :          cym      , & ! 0.5*HTE - 1.5*HTW   ! LCOV_EXCL_LINE
    1161             :          cxm      , & ! 0.5*HTN - 1.5*HTS   ! LCOV_EXCL_LINE
    1162             :          DminTarea    ! deltaminVP*tarea
    1163             : 
    1164             :       real (kind=dbl_kind), dimension(nx_block,ny_block,4), intent(out) :: &
    1165             :          zetax2   , & ! zetax2 = 2*zeta (bulk viscosity)   ! LCOV_EXCL_LINE
    1166             :          etax2    , & ! etax2  = 2*eta  (shear viscosity)   ! LCOV_EXCL_LINE
    1167             :          rep_prs      ! replacement pressure
    1168             : 
    1169             :       real (kind=dbl_kind), dimension(nx_block,ny_block,8), intent(out) :: &
    1170             :          stPr          ! stress combinations from replacement pressure
    1171             : 
    1172             :       ! local variables
    1173             : 
    1174             :       integer (kind=int_kind) :: &
    1175             :          i, j, ij
    1176             : 
    1177             :       real (kind=dbl_kind) :: &
    1178             :         divune, divunw, divuse, divusw                , & ! divergence   ! LCOV_EXCL_LINE
    1179             :         tensionne, tensionnw, tensionse, tensionsw    , & ! tension   ! LCOV_EXCL_LINE
    1180             :         shearne, shearnw, shearse, shearsw            , & ! shearing   ! LCOV_EXCL_LINE
    1181             :         Deltane, Deltanw, Deltase, Deltasw            , & ! Delt   ! LCOV_EXCL_LINE
    1182             :         ssigpn, ssigps, ssigpe, ssigpw, ssigp1, ssigp2, &   ! LCOV_EXCL_LINE
    1183             :         csigpne, csigpnw, csigpsw, csigpse            , &   ! LCOV_EXCL_LINE
    1184             :         stressp_1, stressp_2, stressp_3, stressp_4    , &   ! LCOV_EXCL_LINE
    1185           0 :         strp_tmp
    1186             : 
    1187             :       character(len=*), parameter :: subname = '(calc_zeta_dPr)'
    1188             : 
    1189             :       ! Initialize stPr, zetax2 and etax2 to zero
    1190             :       ! (for cells where iceTmask is false)
    1191           0 :       stPr   = c0
    1192           0 :       zetax2 = c0
    1193           0 :       etax2  = c0
    1194             : 
    1195           0 :       do ij = 1, icellT
    1196           0 :          i = indxTi(ij)
    1197           0 :          j = indxTj(ij)
    1198             : 
    1199             :       !-----------------------------------------------------------------
    1200             :       ! strain rates
    1201             :       ! NOTE these are actually strain rates * area  (m^2/s)
    1202             :       !-----------------------------------------------------------------
    1203             :          call strain_rates (nx_block , ny_block , &
    1204             :                             i        , j        , &   ! LCOV_EXCL_LINE
    1205             :                             uvel     , vvel     , &   ! LCOV_EXCL_LINE
    1206             :                             dxT      , dyT      , &   ! LCOV_EXCL_LINE
    1207             :                             cxp      , cyp      , &   ! LCOV_EXCL_LINE
    1208             :                             cxm      , cym      , &   ! LCOV_EXCL_LINE
    1209             :                             divune   , divunw   , &   ! LCOV_EXCL_LINE
    1210             :                             divuse   , divusw   , &   ! LCOV_EXCL_LINE
    1211             :                             tensionne, tensionnw, &   ! LCOV_EXCL_LINE
    1212             :                             tensionse, tensionsw, &   ! LCOV_EXCL_LINE
    1213             :                             shearne  , shearnw  , &   ! LCOV_EXCL_LINE
    1214             :                             shearse  , shearsw  , &   ! LCOV_EXCL_LINE
    1215             :                             Deltane  , Deltanw  , &   ! LCOV_EXCL_LINE
    1216           0 :                             Deltase  , Deltasw)
    1217             : 
    1218             :       !-----------------------------------------------------------------
    1219             :       ! viscosities and replacement pressure
    1220             :       !-----------------------------------------------------------------
    1221             : 
    1222           0 :          call visc_replpress (strength(i,j)  , DminTarea(i,j)  , &
    1223             :                               Deltane        , zetax2   (i,j,1), &   ! LCOV_EXCL_LINE
    1224             :                               etax2   (i,j,1), rep_prs  (i,j,1), &   ! LCOV_EXCL_LINE
    1225           0 :                               capping)
    1226           0 :          call visc_replpress (strength(i,j)  , DminTarea(i,j)  , &
    1227             :                               Deltanw        , zetax2   (i,j,2), &   ! LCOV_EXCL_LINE
    1228             :                               etax2   (i,j,2), rep_prs  (i,j,2), &   ! LCOV_EXCL_LINE
    1229           0 :                               capping)
    1230           0 :          call visc_replpress (strength(i,j)  , DminTarea(i,j)  , &
    1231             :                               Deltasw        , zetax2   (i,j,3), &   ! LCOV_EXCL_LINE
    1232             :                               etax2   (i,j,3), rep_prs  (i,j,3), &   ! LCOV_EXCL_LINE
    1233           0 :                               capping)
    1234           0 :          call visc_replpress (strength(i,j)  , DminTarea(i,j)  , &
    1235             :                               Deltase        , zetax2   (i,j,4), &   ! LCOV_EXCL_LINE
    1236             :                               etax2   (i,j,4), rep_prs  (i,j,4), &   ! LCOV_EXCL_LINE
    1237           0 :                               capping)
    1238             : 
    1239             :       !-----------------------------------------------------------------
    1240             :       ! the stresses                            ! kg/s^2
    1241             :       ! (1) northeast, (2) northwest, (3) southwest, (4) southeast
    1242             :       !-----------------------------------------------------------------
    1243             : 
    1244           0 :          stressp_1 = -rep_prs(i,j,1)
    1245           0 :          stressp_2 = -rep_prs(i,j,2)
    1246           0 :          stressp_3 = -rep_prs(i,j,3)
    1247           0 :          stressp_4 = -rep_prs(i,j,4)
    1248             : 
    1249             :       !-----------------------------------------------------------------
    1250             :       ! combinations of the Pr related stresses for the momentum equation ! kg/s^2
    1251             :       !-----------------------------------------------------------------
    1252             : 
    1253           0 :          ssigpn  = stressp_1 + stressp_2
    1254           0 :          ssigps  = stressp_3 + stressp_4
    1255           0 :          ssigpe  = stressp_1 + stressp_4
    1256           0 :          ssigpw  = stressp_2 + stressp_3
    1257           0 :          ssigp1  =(stressp_1 + stressp_3)*p055
    1258           0 :          ssigp2  =(stressp_2 + stressp_4)*p055
    1259             : 
    1260           0 :          csigpne = p111*stressp_1 + ssigp2 + p027*stressp_3
    1261           0 :          csigpnw = p111*stressp_2 + ssigp1 + p027*stressp_4
    1262           0 :          csigpsw = p111*stressp_3 + ssigp2 + p027*stressp_1
    1263           0 :          csigpse = p111*stressp_4 + ssigp1 + p027*stressp_2
    1264             : 
    1265             :       !-----------------------------------------------------------------
    1266             :       ! for dF/dx (u momentum)
    1267             :       !-----------------------------------------------------------------
    1268           0 :          strp_tmp  = p25*dyT(i,j)*(p333*ssigpn  + p166*ssigps)
    1269             : 
    1270             :          ! northeast (i,j)
    1271           0 :          stPr(i,j,1) = -strp_tmp &
    1272           0 :               + dxhy(i,j)*(-csigpne)
    1273             : 
    1274             :          ! northwest (i+1,j)
    1275           0 :          stPr(i,j,2) = strp_tmp  &
    1276           0 :               + dxhy(i,j)*(-csigpnw)
    1277             : 
    1278           0 :          strp_tmp  = p25*dyT(i,j)*(p333*ssigps  + p166*ssigpn)
    1279             : 
    1280             :          ! southeast (i,j+1)
    1281           0 :          stPr(i,j,3) = -strp_tmp &
    1282           0 :               + dxhy(i,j)*(-csigpse)
    1283             : 
    1284             :          ! southwest (i+1,j+1)
    1285           0 :          stPr(i,j,4) = strp_tmp  &
    1286           0 :               + dxhy(i,j)*(-csigpsw)
    1287             : 
    1288             :       !-----------------------------------------------------------------
    1289             :       ! for dF/dy (v momentum)
    1290             :       !-----------------------------------------------------------------
    1291           0 :          strp_tmp  = p25*dxT(i,j)*(p333*ssigpe  + p166*ssigpw)
    1292             : 
    1293             :          ! northeast (i,j)
    1294           0 :          stPr(i,j,5) = -strp_tmp &
    1295           0 :               - dyhx(i,j)*(csigpne)
    1296             : 
    1297             :          ! southeast (i,j+1)
    1298           0 :          stPr(i,j,6) = strp_tmp  &
    1299           0 :               - dyhx(i,j)*(csigpse)
    1300             : 
    1301           0 :          strp_tmp  = p25*dxT(i,j)*(p333*ssigpw  + p166*ssigpe)
    1302             : 
    1303             :          ! northwest (i+1,j)
    1304           0 :          stPr(i,j,7) = -strp_tmp &
    1305           0 :               - dyhx(i,j)*(csigpnw)
    1306             : 
    1307             :          ! southwest (i+1,j+1)
    1308           0 :          stPr(i,j,8) = strp_tmp  &
    1309           0 :               - dyhx(i,j)*(csigpsw)
    1310             : 
    1311             :       enddo                     ! ij
    1312             : 
    1313           0 :       end subroutine calc_zeta_dPr
    1314             : 
    1315             : !=======================================================================
    1316             : 
    1317             : ! Computes the VP stresses (as diagnostic)
    1318             : 
    1319             : ! Lemieux, J.-F., and Dupont, F. (2020), On the calculation of normalized
    1320             : ! viscous-plastic sea ice stresses, Geosci. Model Dev., 13, 1763–1769,
    1321             : 
    1322           0 :       subroutine stress_vp (nx_block  , ny_block  , &
    1323             :                             icellT    ,             &   ! LCOV_EXCL_LINE
    1324             :                             indxTi    , indxTj    , &   ! LCOV_EXCL_LINE
    1325             :                             uvel      , vvel      , &   ! LCOV_EXCL_LINE
    1326             :                             dxT       , dyT       , &   ! LCOV_EXCL_LINE
    1327             :                             cxp       , cyp       , &   ! LCOV_EXCL_LINE
    1328             :                             cxm       , cym       , &   ! LCOV_EXCL_LINE
    1329             :                             zetax2    , etax2     , &   ! LCOV_EXCL_LINE
    1330             :                             rep_prs   ,             &   ! LCOV_EXCL_LINE
    1331             :                             stressp_1 , stressp_2 , &   ! LCOV_EXCL_LINE
    1332             :                             stressp_3 , stressp_4 , &   ! LCOV_EXCL_LINE
    1333             :                             stressm_1 , stressm_2 , &   ! LCOV_EXCL_LINE
    1334             :                             stressm_3 , stressm_4 , &   ! LCOV_EXCL_LINE
    1335             :                             stress12_1, stress12_2, &   ! LCOV_EXCL_LINE
    1336           0 :                             stress12_3, stress12_4)
    1337             : 
    1338             :       use ice_dyn_shared, only: strain_rates
    1339             : 
    1340             :       integer (kind=int_kind), intent(in) :: &
    1341             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    1342             :          icellT                ! no. of cells where iceTmask = .true.
    1343             : 
    1344             :       integer (kind=int_kind), dimension (nx_block*ny_block), intent(in) :: &
    1345             :          indxTi   , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    1346             :          indxTj       ! compressed index in j-direction
    1347             : 
    1348             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    1349             :          uvel     , & ! x-component of velocity (m/s)   ! LCOV_EXCL_LINE
    1350             :          vvel     , & ! y-component of velocity (m/s)   ! LCOV_EXCL_LINE
    1351             :          dxT      , & ! width of T-cell through the middle (m)   ! LCOV_EXCL_LINE
    1352             :          dyT      , & ! height of T-cell through the middle (m)   ! LCOV_EXCL_LINE
    1353             :          cyp      , & ! 1.5*HTE - 0.5*HTW   ! LCOV_EXCL_LINE
    1354             :          cxp      , & ! 1.5*HTN - 0.5*HTS   ! LCOV_EXCL_LINE
    1355             :          cym      , & ! 0.5*HTE - 1.5*HTW   ! LCOV_EXCL_LINE
    1356             :          cxm          ! 0.5*HTN - 1.5*HTS
    1357             : 
    1358             :       real (kind=dbl_kind), dimension(nx_block,ny_block,4), intent(in) :: &
    1359             :          zetax2   , & ! zetax2 = 2*zeta (bulk viscosity)   ! LCOV_EXCL_LINE
    1360             :          etax2    , & ! etax2  = 2*eta  (shear viscosity)   ! LCOV_EXCL_LINE
    1361             :          rep_prs
    1362             : 
    1363             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(inout) :: &
    1364             :          stressp_1, stressp_2, stressp_3, stressp_4 , & ! sigma11+sigma22   ! LCOV_EXCL_LINE
    1365             :          stressm_1, stressm_2, stressm_3, stressm_4 , & ! sigma11-sigma22   ! LCOV_EXCL_LINE
    1366             :          stress12_1,stress12_2,stress12_3,stress12_4    ! sigma12
    1367             : 
    1368             :       ! local variables
    1369             : 
    1370             :       integer (kind=int_kind) :: &
    1371             :          i, j, ij
    1372             : 
    1373             :       real (kind=dbl_kind) :: &
    1374             :         divune, divunw, divuse, divusw            , & ! divergence   ! LCOV_EXCL_LINE
    1375             :         tensionne, tensionnw, tensionse, tensionsw, & ! tension   ! LCOV_EXCL_LINE
    1376             :         shearne, shearnw, shearse, shearsw        , & ! shearing   ! LCOV_EXCL_LINE
    1377           0 :         Deltane, Deltanw, Deltase, Deltasw            ! Delt
    1378             : 
    1379             :       character(len=*), parameter :: subname = '(stress_vp)'
    1380             : 
    1381           0 :       do ij = 1, icellT
    1382           0 :          i = indxTi(ij)
    1383           0 :          j = indxTj(ij)
    1384             : 
    1385             :       !-----------------------------------------------------------------
    1386             :       ! strain rates
    1387             :       ! NOTE these are actually strain rates * area  (m^2/s)
    1388             :       !-----------------------------------------------------------------
    1389             :          call strain_rates (nx_block , ny_block , &
    1390             :                             i        , j        , &   ! LCOV_EXCL_LINE
    1391             :                             uvel     , vvel     , &   ! LCOV_EXCL_LINE
    1392             :                             dxT      , dyT      , &   ! LCOV_EXCL_LINE
    1393             :                             cxp      , cyp      , &   ! LCOV_EXCL_LINE
    1394             :                             cxm      , cym      , &   ! LCOV_EXCL_LINE
    1395             :                             divune   , divunw   , &   ! LCOV_EXCL_LINE
    1396             :                             divuse   , divusw   , &   ! LCOV_EXCL_LINE
    1397             :                             tensionne, tensionnw, &   ! LCOV_EXCL_LINE
    1398             :                             tensionse, tensionsw, &   ! LCOV_EXCL_LINE
    1399             :                             shearne  , shearnw  , &   ! LCOV_EXCL_LINE
    1400             :                             shearse  , shearsw  , &   ! LCOV_EXCL_LINE
    1401             :                             Deltane  , Deltanw  , &   ! LCOV_EXCL_LINE
    1402           0 :                             Deltase  , Deltasw)
    1403             : 
    1404             :       !-----------------------------------------------------------------
    1405             :       ! the stresses                            ! kg/s^2
    1406             :       ! (1) northeast, (2) northwest, (3) southwest, (4) southeast
    1407             :       !-----------------------------------------------------------------
    1408             : 
    1409           0 :          stressp_1(i,j) = zetax2(i,j,1)*divune - rep_prs(i,j,1)
    1410           0 :          stressp_2(i,j) = zetax2(i,j,2)*divunw - rep_prs(i,j,2)
    1411           0 :          stressp_3(i,j) = zetax2(i,j,3)*divusw - rep_prs(i,j,3)
    1412           0 :          stressp_4(i,j) = zetax2(i,j,4)*divuse - rep_prs(i,j,4)
    1413             : 
    1414           0 :          stressm_1(i,j) = etax2(i,j,1)*tensionne
    1415           0 :          stressm_2(i,j) = etax2(i,j,2)*tensionnw
    1416           0 :          stressm_3(i,j) = etax2(i,j,3)*tensionsw
    1417           0 :          stressm_4(i,j) = etax2(i,j,4)*tensionse
    1418             : 
    1419           0 :          stress12_1(i,j) = etax2(i,j,1)*shearne*p5
    1420           0 :          stress12_2(i,j) = etax2(i,j,2)*shearnw*p5
    1421           0 :          stress12_3(i,j) = etax2(i,j,3)*shearsw*p5
    1422           0 :          stress12_4(i,j) = etax2(i,j,4)*shearse*p5
    1423             : 
    1424             :       enddo                     ! ij
    1425             : 
    1426           0 :       end subroutine stress_vp
    1427             : 
    1428             : !=======================================================================
    1429             : 
    1430             : ! Compute vrel and seabed stress coefficients
    1431             : 
    1432           0 :       subroutine calc_vrel_Cb (nx_block, ny_block, &
    1433             :                                icellU  , Cw      , &   ! LCOV_EXCL_LINE
    1434             :                                indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    1435             :                                aiU     , TbU     , &   ! LCOV_EXCL_LINE
    1436             :                                uocn    , vocn    , &   ! LCOV_EXCL_LINE
    1437             :                                uvel    , vvel    , &   ! LCOV_EXCL_LINE
    1438           0 :                                vrel    , Cb)
    1439             : 
    1440             :       use ice_dyn_shared, only: u0 ! residual velocity for seabed stress (m/s)
    1441             : 
    1442             :       integer (kind=int_kind), intent(in) :: &
    1443             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    1444             :          icellU                ! total count when iceUmask = .true.
    1445             : 
    1446             :       integer (kind=int_kind), dimension (nx_block*ny_block), intent(in) :: &
    1447             :          indxUi  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    1448             :          indxUj      ! compressed index in j-direction
    1449             : 
    1450             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    1451             :          TbU,      & ! seabed stress factor (N/m^2)   ! LCOV_EXCL_LINE
    1452             :          aiU     , & ! ice fraction on u-grid   ! LCOV_EXCL_LINE
    1453             :          uocn    , & ! ocean current, x-direction (m/s)   ! LCOV_EXCL_LINE
    1454             :          vocn    , & ! ocean current, y-direction (m/s)   ! LCOV_EXCL_LINE
    1455             :          Cw          ! ocean-ice neutral drag coefficient
    1456             : 
    1457             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    1458             :          uvel    , & ! x-component of velocity (m/s)   ! LCOV_EXCL_LINE
    1459             :          vvel        ! y-component of velocity (m/s)
    1460             : 
    1461             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(inout) :: &
    1462             :          vrel      , & ! coeff for tauw   ! LCOV_EXCL_LINE
    1463             :          Cb            ! seabed stress coeff
    1464             : 
    1465             :       ! local variables
    1466             : 
    1467             :       integer (kind=int_kind) :: &
    1468             :          i, j, ij
    1469             : 
    1470             :       real (kind=dbl_kind) :: &
    1471           0 :          rhow                  !
    1472             : 
    1473             :       character(len=*), parameter :: subname = '(calc_vrel_Cb)'
    1474             : 
    1475           0 :       call icepack_query_parameters(rhow_out=rhow)
    1476           0 :       call icepack_warnings_flush(nu_diag)
    1477           0 :       if (icepack_warnings_aborted()) call abort_ice(error_message=subname, &
    1478           0 :          file=__FILE__, line=__LINE__)
    1479             : 
    1480           0 :       do ij = 1, icellU
    1481           0 :          i = indxUi(ij)
    1482           0 :          j = indxUj(ij)
    1483             : 
    1484             :          ! (magnitude of relative ocean current)*rhow*drag*aice
    1485           0 :          vrel(i,j) = aiU(i,j)*rhow*Cw(i,j)*sqrt((uocn(i,j) - uvel(i,j))**2 + &
    1486           0 :                                                 (vocn(i,j) - vvel(i,j))**2)  ! m/s
    1487             : 
    1488           0 :          Cb(i,j)  = TbU(i,j) / (sqrt(uvel(i,j)**2 + vvel(i,j)**2) + u0) ! for seabed stress
    1489             :       enddo                     ! ij
    1490             : 
    1491           0 :       end subroutine calc_vrel_Cb
    1492             : 
    1493             : !=======================================================================
    1494             : 
    1495             : ! Compute seabed stress (diagnostic)
    1496             : 
    1497           0 :       subroutine calc_seabed_stress (nx_block, ny_block, &
    1498             :                                      icellU  ,           &   ! LCOV_EXCL_LINE
    1499             :                                      indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    1500             :                                      uvel    , vvel    , &   ! LCOV_EXCL_LINE
    1501             :                                      Cb      ,           &   ! LCOV_EXCL_LINE
    1502           0 :                                      taubxU  , taubyU)
    1503             : 
    1504             :       integer (kind=int_kind), intent(in) :: &
    1505             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    1506             :          icellU                ! total count when iceUmask = .true.
    1507             : 
    1508             :       integer (kind=int_kind), dimension (nx_block*ny_block), intent(in) :: &
    1509             :          indxUi  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    1510             :          indxUj      ! compressed index in j-direction
    1511             : 
    1512             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    1513             :          uvel    , & ! x-component of velocity (m/s)   ! LCOV_EXCL_LINE
    1514             :          vvel    , & ! y-component of velocity (m/s)   ! LCOV_EXCL_LINE
    1515             :          Cb          ! seabed stress coefficient
    1516             : 
    1517             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(out) :: &
    1518             :          taubxU  , & ! seabed stress, x-direction (N/m^2)   ! LCOV_EXCL_LINE
    1519             :          taubyU      ! seabed stress, y-direction (N/m^2)
    1520             : 
    1521             :       ! local variables
    1522             : 
    1523             :       integer (kind=int_kind) :: &
    1524             :          i, j, ij
    1525             : 
    1526             :       character(len=*), parameter :: subname = '(calc_seabed_stress)'
    1527             : 
    1528           0 :       do ij = 1, icellU
    1529           0 :          i = indxUi(ij)
    1530           0 :          j = indxUj(ij)
    1531             : 
    1532           0 :          taubxU(i,j) = -uvel(i,j)*Cb(i,j)
    1533           0 :          taubyU(i,j) = -vvel(i,j)*Cb(i,j)
    1534             :       enddo                     ! ij
    1535             : 
    1536           0 :       end subroutine calc_seabed_stress
    1537             : 
    1538             : !=======================================================================
    1539             : 
    1540             : ! Computes the matrix vector product A(u,v) * (u,v)
    1541             : ! Au = A(u,v)_[x] * uvel (x components of  A(u,v) * (u,v))
    1542             : ! Av = A(u,v)_[y] * vvel (y components of  A(u,v) * (u,v))
    1543             : 
    1544           0 :       subroutine matvec (nx_block, ny_block, &
    1545             :                          icellU  , icellT  , &   ! LCOV_EXCL_LINE
    1546             :                          indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    1547             :                          indxTi  , indxTj  , &   ! LCOV_EXCL_LINE
    1548             :                          dxT     , dyT     , &   ! LCOV_EXCL_LINE
    1549             :                          dxhy    , dyhx    , &   ! LCOV_EXCL_LINE
    1550             :                          cxp     , cyp     , &   ! LCOV_EXCL_LINE
    1551             :                          cxm     , cym     , &   ! LCOV_EXCL_LINE
    1552             :                          uvel    , vvel    , &   ! LCOV_EXCL_LINE
    1553             :                          vrel    , Cb      , &   ! LCOV_EXCL_LINE
    1554             :                          zetax2  , etax2   , &   ! LCOV_EXCL_LINE
    1555             :                          umassdti, fmU     , &   ! LCOV_EXCL_LINE
    1556             :                          uarear  ,           &   ! LCOV_EXCL_LINE
    1557           0 :                          Au      , Av)
    1558             : 
    1559             :       use ice_dyn_shared, only: strain_rates
    1560             : 
    1561             :       integer (kind=int_kind), intent(in) :: &
    1562             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    1563             :          icellU,             & ! total count when iceUmask = .true.   ! LCOV_EXCL_LINE
    1564             :          icellT                ! total count when iceTmask = .true.
    1565             : 
    1566             :       integer (kind=int_kind), dimension (nx_block*ny_block), intent(in) :: &
    1567             :          indxUi  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    1568             :          indxUj  , & ! compressed index in j-direction   ! LCOV_EXCL_LINE
    1569             :          indxTi  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    1570             :          indxTj      ! compressed index in j-direction
    1571             : 
    1572             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    1573             :          dxT      , & ! width of T-cell through the middle (m)   ! LCOV_EXCL_LINE
    1574             :          dyT      , & ! height of T-cell through the middle (m)   ! LCOV_EXCL_LINE
    1575             :          dxhy     , & ! 0.5*(HTE - HTW)   ! LCOV_EXCL_LINE
    1576             :          dyhx     , & ! 0.5*(HTN - HTS)   ! LCOV_EXCL_LINE
    1577             :          cyp      , & ! 1.5*HTE - 0.5*HTW   ! LCOV_EXCL_LINE
    1578             :          cxp      , & ! 1.5*HTN - 0.5*HTS   ! LCOV_EXCL_LINE
    1579             :          cym      , & ! 0.5*HTE - 1.5*HTW   ! LCOV_EXCL_LINE
    1580             :          cxm          ! 0.5*HTN - 1.5*HTS
    1581             : 
    1582             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    1583             :          uvel    , & ! x-component of velocity (m/s)   ! LCOV_EXCL_LINE
    1584             :          vvel    , & ! y-component of velocity (m/s)   ! LCOV_EXCL_LINE
    1585             :          vrel    , & ! coefficient for tauw   ! LCOV_EXCL_LINE
    1586             :          Cb      , & ! coefficient for seabed stress   ! LCOV_EXCL_LINE
    1587             :          umassdti, & ! mass of U-cell/dt (kg/m^2 s)   ! LCOV_EXCL_LINE
    1588             :          fmU     , & ! Coriolis param. * mass in U-cell (kg/s)   ! LCOV_EXCL_LINE
    1589             :          uarear      ! 1/uarea
    1590             : 
    1591             :       real (kind=dbl_kind), dimension(nx_block,ny_block,4), intent(in) :: &
    1592             :          zetax2   , & ! zetax2 = 2*zeta (bulk viscosity)   ! LCOV_EXCL_LINE
    1593             :          etax2        ! etax2  = 2*eta  (shear viscosity)
    1594             : 
    1595             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(inout) :: &
    1596             :          Au      , & ! matvec, Fx = bx - Au (N/m^2)   ! LCOV_EXCL_LINE
    1597             :          Av          ! matvec, Fy = by - Av (N/m^2)
    1598             : 
    1599             :       ! local variables
    1600             : 
    1601             :       integer (kind=int_kind) :: &
    1602             :          i, j, ij
    1603             : 
    1604             :       real (kind=dbl_kind), dimension(nx_block,ny_block,8):: &
    1605           0 :          str
    1606             : 
    1607             :       real (kind=dbl_kind) :: &
    1608             :          ccaimp,ccb        , & ! intermediate variables   ! LCOV_EXCL_LINE
    1609           0 :          strintx, strinty      ! divergence of the internal stress tensor
    1610             : 
    1611             :       real (kind=dbl_kind) :: &
    1612             :         divune, divunw, divuse, divusw            , & ! divergence   ! LCOV_EXCL_LINE
    1613             :         tensionne, tensionnw, tensionse, tensionsw, & ! tension   ! LCOV_EXCL_LINE
    1614             :         shearne, shearnw, shearse, shearsw        , & ! shearing   ! LCOV_EXCL_LINE
    1615             :         Deltane, Deltanw, Deltase, Deltasw        , & ! Delt   ! LCOV_EXCL_LINE
    1616             :         ssigpn, ssigps, ssigpe, ssigpw            , &   ! LCOV_EXCL_LINE
    1617             :         ssigmn, ssigms, ssigme, ssigmw            , &   ! LCOV_EXCL_LINE
    1618             :         ssig12n, ssig12s, ssig12e, ssig12w        , &   ! LCOV_EXCL_LINE
    1619             :         ssigp1, ssigp2, ssigm1, ssigm2, ssig121, ssig122, &   ! LCOV_EXCL_LINE
    1620             :         csigpne, csigpnw, csigpse, csigpsw        , &   ! LCOV_EXCL_LINE
    1621             :         csigmne, csigmnw, csigmse, csigmsw        , &   ! LCOV_EXCL_LINE
    1622             :         csig12ne, csig12nw, csig12se, csig12sw    , &   ! LCOV_EXCL_LINE
    1623             :         str12ew, str12we, str12ns, str12sn        , &   ! LCOV_EXCL_LINE
    1624           0 :         strp_tmp, strm_tmp
    1625             : 
    1626             :       real (kind=dbl_kind) :: &
    1627             :          stressp_1, stressp_2, stressp_3, stressp_4 , & ! sigma11+sigma22 (without Pr)   ! LCOV_EXCL_LINE
    1628             :          stressm_1, stressm_2, stressm_3, stressm_4 , & ! sigma11-sigma22   ! LCOV_EXCL_LINE
    1629           0 :          stress12_1,stress12_2,stress12_3,stress12_4    ! sigma12
    1630             : 
    1631             :       character(len=*), parameter :: subname = '(matvec)'
    1632             : 
    1633             :       !-----------------------------------------------------------------
    1634             :       ! Initialize
    1635             :       !-----------------------------------------------------------------
    1636             : 
    1637           0 :       str(:,:,:) = c0
    1638             : 
    1639           0 :       do ij = 1, icellT
    1640           0 :          i = indxTi(ij)
    1641           0 :          j = indxTj(ij)
    1642             : 
    1643             :       !-----------------------------------------------------------------
    1644             :       ! strain rates
    1645             :       ! NOTE these are actually strain rates * area  (m^2/s)
    1646             :       !-----------------------------------------------------------------
    1647             :          call strain_rates (nx_block , ny_block , &
    1648             :                             i        , j        , &   ! LCOV_EXCL_LINE
    1649             :                             uvel     , vvel     , &   ! LCOV_EXCL_LINE
    1650             :                             dxT      , dyT      , &   ! LCOV_EXCL_LINE
    1651             :                             cxp      , cyp      , &   ! LCOV_EXCL_LINE
    1652             :                             cxm      , cym      , &   ! LCOV_EXCL_LINE
    1653             :                             divune   , divunw   , &   ! LCOV_EXCL_LINE
    1654             :                             divuse   , divusw   , &   ! LCOV_EXCL_LINE
    1655             :                             tensionne, tensionnw, &   ! LCOV_EXCL_LINE
    1656             :                             tensionse, tensionsw, &   ! LCOV_EXCL_LINE
    1657             :                             shearne  , shearnw  , &   ! LCOV_EXCL_LINE
    1658             :                             shearse  , shearsw  , &   ! LCOV_EXCL_LINE
    1659             :                             Deltane  , Deltanw  , &   ! LCOV_EXCL_LINE
    1660           0 :                             Deltase  , Deltasw)
    1661             : 
    1662             :       !-----------------------------------------------------------------
    1663             :       ! the stresses                            ! kg/s^2
    1664             :       ! (1) northeast, (2) northwest, (3) southwest, (4) southeast
    1665             :       ! NOTE: commented part of stressp is from the replacement pressure Pr
    1666             :       !-----------------------------------------------------------------
    1667             : 
    1668           0 :          stressp_1 = zetax2(i,j,1)*divune! - Deltane*(c1-Ktens))
    1669           0 :          stressp_2 = zetax2(i,j,2)*divunw! - Deltanw*(c1-Ktens))
    1670           0 :          stressp_3 = zetax2(i,j,3)*divusw! - Deltasw*(c1-Ktens))
    1671           0 :          stressp_4 = zetax2(i,j,4)*divuse! - Deltase*(c1-Ktens))
    1672             : 
    1673           0 :          stressm_1 = etax2(i,j,1)*tensionne
    1674           0 :          stressm_2 = etax2(i,j,2)*tensionnw
    1675           0 :          stressm_3 = etax2(i,j,3)*tensionsw
    1676           0 :          stressm_4 = etax2(i,j,4)*tensionse
    1677             : 
    1678           0 :          stress12_1 = etax2(i,j,1)*shearne*p5
    1679           0 :          stress12_2 = etax2(i,j,2)*shearnw*p5
    1680           0 :          stress12_3 = etax2(i,j,3)*shearsw*p5
    1681           0 :          stress12_4 = etax2(i,j,4)*shearse*p5
    1682             : 
    1683             :       !-----------------------------------------------------------------
    1684             :       ! combinations of the stresses for the momentum equation ! kg/s^2
    1685             :       !-----------------------------------------------------------------
    1686             : 
    1687           0 :          ssigpn  = stressp_1 + stressp_2
    1688           0 :          ssigps  = stressp_3 + stressp_4
    1689           0 :          ssigpe  = stressp_1 + stressp_4
    1690           0 :          ssigpw  = stressp_2 + stressp_3
    1691           0 :          ssigp1  =(stressp_1 + stressp_3)*p055
    1692           0 :          ssigp2  =(stressp_2 + stressp_4)*p055
    1693             : 
    1694           0 :          ssigmn  = stressm_1 + stressm_2
    1695           0 :          ssigms  = stressm_3 + stressm_4
    1696           0 :          ssigme  = stressm_1 + stressm_4
    1697           0 :          ssigmw  = stressm_2 + stressm_3
    1698           0 :          ssigm1  =(stressm_1 + stressm_3)*p055
    1699           0 :          ssigm2  =(stressm_2 + stressm_4)*p055
    1700             : 
    1701           0 :          ssig12n = stress12_1 + stress12_2
    1702           0 :          ssig12s = stress12_3 + stress12_4
    1703           0 :          ssig12e = stress12_1 + stress12_4
    1704           0 :          ssig12w = stress12_2 + stress12_3
    1705           0 :          ssig121 =(stress12_1 + stress12_3)*p111
    1706           0 :          ssig122 =(stress12_2 + stress12_4)*p111
    1707             : 
    1708           0 :          csigpne = p111*stressp_1 + ssigp2 + p027*stressp_3
    1709           0 :          csigpnw = p111*stressp_2 + ssigp1 + p027*stressp_4
    1710           0 :          csigpsw = p111*stressp_3 + ssigp2 + p027*stressp_1
    1711           0 :          csigpse = p111*stressp_4 + ssigp1 + p027*stressp_2
    1712             : 
    1713           0 :          csigmne = p111*stressm_1 + ssigm2 + p027*stressm_3
    1714           0 :          csigmnw = p111*stressm_2 + ssigm1 + p027*stressm_4
    1715           0 :          csigmsw = p111*stressm_3 + ssigm2 + p027*stressm_1
    1716           0 :          csigmse = p111*stressm_4 + ssigm1 + p027*stressm_2
    1717             : 
    1718             :          csig12ne = p222*stress12_1 + ssig122 &
    1719           0 :                   + p055*stress12_3
    1720             :          csig12nw = p222*stress12_2 + ssig121 &
    1721           0 :                   + p055*stress12_4
    1722             :          csig12sw = p222*stress12_3 + ssig122 &
    1723           0 :                   + p055*stress12_1
    1724             :          csig12se = p222*stress12_4 + ssig121 &
    1725           0 :                   + p055*stress12_2
    1726             : 
    1727           0 :          str12ew = p5*dxT(i,j)*(p333*ssig12e + p166*ssig12w)
    1728           0 :          str12we = p5*dxT(i,j)*(p333*ssig12w + p166*ssig12e)
    1729           0 :          str12ns = p5*dyT(i,j)*(p333*ssig12n + p166*ssig12s)
    1730           0 :          str12sn = p5*dyT(i,j)*(p333*ssig12s + p166*ssig12n)
    1731             : 
    1732             :       !-----------------------------------------------------------------
    1733             :       ! for dF/dx (u momentum)
    1734             :       !-----------------------------------------------------------------
    1735           0 :          strp_tmp  = p25*dyT(i,j)*(p333*ssigpn  + p166*ssigps)
    1736           0 :          strm_tmp  = p25*dyT(i,j)*(p333*ssigmn  + p166*ssigms)
    1737             : 
    1738             :          ! northeast (i,j)
    1739           0 :          str(i,j,1) = -strp_tmp - strm_tmp - str12ew &
    1740           0 :               + dxhy(i,j)*(-csigpne + csigmne) + dyhx(i,j)*csig12ne
    1741             : 
    1742             :          ! northwest (i+1,j)
    1743           0 :          str(i,j,2) = strp_tmp + strm_tmp - str12we &
    1744           0 :               + dxhy(i,j)*(-csigpnw + csigmnw) + dyhx(i,j)*csig12nw
    1745             : 
    1746           0 :          strp_tmp  = p25*dyT(i,j)*(p333*ssigps  + p166*ssigpn)
    1747           0 :          strm_tmp  = p25*dyT(i,j)*(p333*ssigms  + p166*ssigmn)
    1748             : 
    1749             :          ! southeast (i,j+1)
    1750           0 :          str(i,j,3) = -strp_tmp - strm_tmp + str12ew &
    1751           0 :               + dxhy(i,j)*(-csigpse + csigmse) + dyhx(i,j)*csig12se
    1752             : 
    1753             :          ! southwest (i+1,j+1)
    1754           0 :          str(i,j,4) = strp_tmp + strm_tmp + str12we &
    1755           0 :               + dxhy(i,j)*(-csigpsw + csigmsw) + dyhx(i,j)*csig12sw
    1756             : 
    1757             :       !-----------------------------------------------------------------
    1758             :       ! for dF/dy (v momentum)
    1759             :       !-----------------------------------------------------------------
    1760           0 :          strp_tmp  = p25*dxT(i,j)*(p333*ssigpe  + p166*ssigpw)
    1761           0 :          strm_tmp  = p25*dxT(i,j)*(p333*ssigme  + p166*ssigmw)
    1762             : 
    1763             :          ! northeast (i,j)
    1764           0 :          str(i,j,5) = -strp_tmp + strm_tmp - str12ns &
    1765           0 :               - dyhx(i,j)*(csigpne + csigmne) + dxhy(i,j)*csig12ne
    1766             : 
    1767             :          ! southeast (i,j+1)
    1768           0 :          str(i,j,6) = strp_tmp - strm_tmp - str12sn &
    1769           0 :               - dyhx(i,j)*(csigpse + csigmse) + dxhy(i,j)*csig12se
    1770             : 
    1771           0 :          strp_tmp  = p25*dxT(i,j)*(p333*ssigpw  + p166*ssigpe)
    1772           0 :          strm_tmp  = p25*dxT(i,j)*(p333*ssigmw  + p166*ssigme)
    1773             : 
    1774             :          ! northwest (i+1,j)
    1775           0 :          str(i,j,7) = -strp_tmp + strm_tmp + str12ns &
    1776           0 :               - dyhx(i,j)*(csigpnw + csigmnw) + dxhy(i,j)*csig12nw
    1777             : 
    1778             :          ! southwest (i+1,j+1)
    1779           0 :          str(i,j,8) = strp_tmp - strm_tmp + str12sn &
    1780           0 :               - dyhx(i,j)*(csigpsw + csigmsw) + dxhy(i,j)*csig12sw
    1781             : 
    1782             :       enddo ! ij - icellT
    1783             : 
    1784             :       !-----------------------------------------------------------------
    1785             :       ! Form Au and Av
    1786             :       !-----------------------------------------------------------------
    1787             : 
    1788           0 :       do ij = 1, icellU
    1789           0 :          i = indxUi(ij)
    1790           0 :          j = indxUj(ij)
    1791             : 
    1792           0 :          ccaimp = umassdti(i,j) + vrel(i,j) * cosw + Cb(i,j) ! kg/m^2 s
    1793             : 
    1794           0 :          ccb = fmU(i,j) + sign(c1,fmU(i,j)) * vrel(i,j) * sinw ! kg/m^2 s
    1795             : 
    1796             :          ! divergence of the internal stress tensor
    1797           0 :          strintx = uarear(i,j)* &
    1798           0 :              (str(i,j,1) + str(i+1,j,2) + str(i,j+1,3) + str(i+1,j+1,4))
    1799           0 :          strinty = uarear(i,j)* &
    1800           0 :              (str(i,j,5) + str(i,j+1,6) + str(i+1,j,7) + str(i+1,j+1,8))
    1801             : 
    1802           0 :          Au(i,j) = ccaimp*uvel(i,j) - ccb*vvel(i,j) - strintx
    1803           0 :          Av(i,j) = ccaimp*vvel(i,j) + ccb*uvel(i,j) - strinty
    1804             :       enddo ! ij - icellU
    1805             : 
    1806           0 :       end subroutine matvec
    1807             : 
    1808             : !=======================================================================
    1809             : 
    1810             : ! Compute the constant component of b(u,v) i.e. the part of b(u,v) that
    1811             : ! does not depend on (u,v) and thus do not change during the nonlinear iteration
    1812             : 
    1813           0 :      subroutine calc_bfix  (nx_block , ny_block , &
    1814             :                             icellU   ,            &   ! LCOV_EXCL_LINE
    1815             :                             indxUi   , indxUj   , &   ! LCOV_EXCL_LINE
    1816             :                             umassdti ,            &   ! LCOV_EXCL_LINE
    1817             :                             forcexU  , forceyU  , &   ! LCOV_EXCL_LINE
    1818             :                             uvel_init, vvel_init, &   ! LCOV_EXCL_LINE
    1819           0 :                             bxfix    , byfix)
    1820             : 
    1821             :       integer (kind=int_kind), intent(in) :: &
    1822             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    1823             :          icellU                ! no. of cells where iceUmask = .true.
    1824             : 
    1825             :       integer (kind=int_kind), dimension (nx_block*ny_block), intent(in) :: &
    1826             :          indxUi   , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    1827             :          indxUj       ! compressed index in j-direction
    1828             : 
    1829             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    1830             :          uvel_init,& ! x-component of velocity (m/s), beginning of time step   ! LCOV_EXCL_LINE
    1831             :          vvel_init,& ! y-component of velocity (m/s), beginning of time step   ! LCOV_EXCL_LINE
    1832             :          umassdti, & ! mass of U-cell/dt (kg/m^2 s)   ! LCOV_EXCL_LINE
    1833             :          forcexU , & ! work array: combined atm stress and ocn tilt, x   ! LCOV_EXCL_LINE
    1834             :          forceyU     ! work array: combined atm stress and ocn tilt, y
    1835             : 
    1836             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(out) :: &
    1837             :          bxfix   , & ! bx = taux + bxfix   ! LCOV_EXCL_LINE
    1838             :          byfix       ! by = tauy + byfix
    1839             : 
    1840             :       ! local variables
    1841             : 
    1842             :       integer (kind=int_kind) :: &
    1843             :          i, j, ij
    1844             : 
    1845             :       character(len=*), parameter :: subname = '(calc_bfix)'
    1846             : 
    1847           0 :       do ij = 1, icellU
    1848           0 :          i = indxUi(ij)
    1849           0 :          j = indxUj(ij)
    1850             : 
    1851           0 :          bxfix(i,j) = umassdti(i,j)*uvel_init(i,j) + forcexU(i,j)
    1852           0 :          byfix(i,j) = umassdti(i,j)*vvel_init(i,j) + forceyU(i,j)
    1853             :       enddo
    1854             : 
    1855           0 :       end subroutine calc_bfix
    1856             : 
    1857             : !=======================================================================
    1858             : 
    1859             : ! Compute the vector b(u,v), i.e. the part of the nonlinear function F(u,v)
    1860             : ! that cannot be written as A(u,v)*(u,v), where A(u,v) is a matrix with entries
    1861             : ! depending on (u,v)
    1862             : 
    1863           0 :       subroutine calc_bvec (nx_block, ny_block, &
    1864             :                             icellU  ,           &   ! LCOV_EXCL_LINE
    1865             :                             indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    1866             :                             stPr    , uarear  , &   ! LCOV_EXCL_LINE
    1867             :                             waterxU , wateryU , &   ! LCOV_EXCL_LINE
    1868             :                             bxfix   , byfix   , &   ! LCOV_EXCL_LINE
    1869             :                             bx      , by      , &   ! LCOV_EXCL_LINE
    1870           0 :                             vrel)
    1871             : 
    1872             :       integer (kind=int_kind), intent(in) :: &
    1873             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    1874             :          icellU                ! total count when iceUmask = .true.
    1875             : 
    1876             :       integer (kind=int_kind), dimension (nx_block*ny_block), intent(in) :: &
    1877             :          indxUi  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    1878             :          indxUj      ! compressed index in j-direction
    1879             : 
    1880             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    1881             :          uarear  , & ! 1/uarea   ! LCOV_EXCL_LINE
    1882             :          waterxU , & ! for ocean stress calculation, x (m/s)   ! LCOV_EXCL_LINE
    1883             :          wateryU , & ! for ocean stress calculation, y (m/s)   ! LCOV_EXCL_LINE
    1884             :          bxfix   , & ! bx = taux + bxfix   ! LCOV_EXCL_LINE
    1885             :          byfix   , & ! by = tauy + byfix   ! LCOV_EXCL_LINE
    1886             :          vrel        ! relative ice-ocean velocity
    1887             : 
    1888             :       real (kind=dbl_kind), dimension(nx_block,ny_block,8), intent(in) :: &
    1889             :          stPr
    1890             : 
    1891             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(out) :: &
    1892             :          bx      , & ! b vector, bx = taux + bxfix (N/m^2)   ! LCOV_EXCL_LINE
    1893             :          by          ! b vector, by = tauy + byfix (N/m^2)
    1894             : 
    1895             :       ! local variables
    1896             : 
    1897             :       integer (kind=int_kind) :: &
    1898             :          i, j, ij
    1899             : 
    1900             :       real (kind=dbl_kind) :: &
    1901             :          taux, tauy        , & ! part of ocean stress term   ! LCOV_EXCL_LINE
    1902             :          strintx, strinty  , & ! divergence of the internal stress tensor (only Pr contributions)   ! LCOV_EXCL_LINE
    1903           0 :          rhow                  !
    1904             : 
    1905             :       character(len=*), parameter :: subname = '(calc_bvec)'
    1906             : 
    1907             :       !-----------------------------------------------------------------
    1908             :       ! calc b vector
    1909             :       !-----------------------------------------------------------------
    1910             : 
    1911           0 :       call icepack_query_parameters(rhow_out=rhow)
    1912           0 :       call icepack_warnings_flush(nu_diag)
    1913           0 :       if (icepack_warnings_aborted()) call abort_ice(error_message=subname, &
    1914           0 :          file=__FILE__, line=__LINE__)
    1915             : 
    1916           0 :       do ij = 1, icellU
    1917           0 :          i = indxUi(ij)
    1918           0 :          j = indxUj(ij)
    1919             : 
    1920             :          ! ice/ocean stress
    1921           0 :          taux = vrel(i,j)*waterxU(i,j) ! NOTE this is not the entire
    1922           0 :          tauy = vrel(i,j)*wateryU(i,j) ! ocn stress term
    1923             : 
    1924             :          ! divergence of the internal stress tensor (only Pr part, i.e. dPr/dx, dPr/dy)
    1925           0 :          strintx = uarear(i,j)* &
    1926           0 :              (stPr(i,j,1) + stPr(i+1,j,2) + stPr(i,j+1,3) + stPr(i+1,j+1,4))
    1927           0 :          strinty = uarear(i,j)* &
    1928           0 :              (stPr(i,j,5) + stPr(i,j+1,6) + stPr(i+1,j,7) + stPr(i+1,j+1,8))
    1929             : 
    1930           0 :          bx(i,j) = bxfix(i,j) + taux + strintx
    1931           0 :          by(i,j) = byfix(i,j) + tauy + strinty
    1932             :       enddo                     ! ij
    1933             : 
    1934           0 :       end subroutine calc_bvec
    1935             : 
    1936             : !=======================================================================
    1937             : 
    1938             : ! Compute the non linear residual F(u,v) = b(u,v) - A(u,v) * (u,v),
    1939             : ! with Au, Av precomputed as
    1940             : ! Au = A(u,v)_[x] * uvel (x components of  A(u,v) * (u,v))
    1941             : ! Av = A(u,v)_[y] * vvel (y components of  A(u,v) * (u,v))
    1942             : 
    1943           0 :       subroutine residual_vec (nx_block   , ny_block, &
    1944             :                                icellU     ,           &   ! LCOV_EXCL_LINE
    1945             :                                indxUi     , indxUj  , &   ! LCOV_EXCL_LINE
    1946             :                                bx         , by      , &   ! LCOV_EXCL_LINE
    1947             :                                Au         , Av      , &   ! LCOV_EXCL_LINE
    1948           0 :                                Fx         , Fy        )
    1949             : 
    1950             :       integer (kind=int_kind), intent(in) :: &
    1951             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    1952             :          icellU                ! total count when iceUmask = .true.
    1953             : 
    1954             :       integer (kind=int_kind), dimension (nx_block*ny_block), intent(in) :: &
    1955             :          indxUi  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    1956             :          indxUj      ! compressed index in j-direction
    1957             : 
    1958             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    1959             :          bx       , & ! b vector, bx = taux + bxfix (N/m^2)   ! LCOV_EXCL_LINE
    1960             :          by       , & ! b vector, by = tauy + byfix (N/m^2)   ! LCOV_EXCL_LINE
    1961             :          Au       , & ! matvec, Fx = bx - Au (N/m^2)   ! LCOV_EXCL_LINE
    1962             :          Av           ! matvec, Fy = by - Av (N/m^2)
    1963             : 
    1964             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(inout) :: &
    1965             :          Fx      , & ! x residual vector, Fx = bx - Au (N/m^2)   ! LCOV_EXCL_LINE
    1966             :          Fy          ! y residual vector, Fy = by - Av (N/m^2)
    1967             : 
    1968             :       ! local variables
    1969             : 
    1970             :       integer (kind=int_kind) :: &
    1971             :          i, j, ij
    1972             : 
    1973             :       character(len=*), parameter :: subname = '(residual_vec)'
    1974             : 
    1975             :       !-----------------------------------------------------------------
    1976             :       ! compute residual
    1977             :       !-----------------------------------------------------------------
    1978             : 
    1979           0 :       do ij = 1, icellU
    1980           0 :          i = indxUi(ij)
    1981           0 :          j = indxUj(ij)
    1982             : 
    1983           0 :          Fx(i,j) = bx(i,j) - Au(i,j)
    1984           0 :          Fy(i,j) = by(i,j) - Av(i,j)
    1985             :       enddo                     ! ij
    1986             : 
    1987           0 :       end subroutine residual_vec
    1988             : 
    1989             : !=======================================================================
    1990             : 
    1991             : ! Form the diagonal of the matrix A(u,v) (first part of the computation)
    1992             : ! Part 1: compute the contributions to the diagonal from the rheology term
    1993             : 
    1994           0 :       subroutine formDiag_step1  (nx_block, ny_block, &
    1995             :                                   icellU  ,           &   ! LCOV_EXCL_LINE
    1996             :                                   indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    1997             :                                   dxT     , dyT     , &   ! LCOV_EXCL_LINE
    1998             :                                   dxhy    , dyhx    , &   ! LCOV_EXCL_LINE
    1999             :                                   cxp     , cyp     , &   ! LCOV_EXCL_LINE
    2000             :                                   cxm     , cym     , &   ! LCOV_EXCL_LINE
    2001             :                                   zetax2  , etax2   , &   ! LCOV_EXCL_LINE
    2002           0 :                                   Drheo)
    2003             : 
    2004             :       integer (kind=int_kind), intent(in) :: &
    2005             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    2006             :          icellU                ! no. of cells where iceUmask = .true.
    2007             : 
    2008             :       integer (kind=int_kind), dimension (nx_block*ny_block), intent(in) :: &
    2009             :          indxUi   , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    2010             :          indxUj       ! compressed index in j-direction
    2011             : 
    2012             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    2013             :          dxT      , & ! width of T-cell through the middle (m)   ! LCOV_EXCL_LINE
    2014             :          dyT      , & ! height of T-cell through the middle (m)   ! LCOV_EXCL_LINE
    2015             :          dxhy     , & ! 0.5*(HTE - HTW)   ! LCOV_EXCL_LINE
    2016             :          dyhx     , & ! 0.5*(HTN - HTS)   ! LCOV_EXCL_LINE
    2017             :          cyp      , & ! 1.5*HTE - 0.5*HTW   ! LCOV_EXCL_LINE
    2018             :          cxp      , & ! 1.5*HTN - 0.5*HTS   ! LCOV_EXCL_LINE
    2019             :          cym      , & ! 0.5*HTE - 1.5*HTW   ! LCOV_EXCL_LINE
    2020             :          cxm          ! 0.5*HTN - 1.5*HTS
    2021             : 
    2022             :       real (kind=dbl_kind), dimension(nx_block,ny_block,4), intent(in) :: &
    2023             :          zetax2   , & ! zetax2 = 2*zeta (bulk viscosity)   ! LCOV_EXCL_LINE
    2024             :          etax2        ! etax2  = 2*eta  (shear viscosity)
    2025             : 
    2026             :       real (kind=dbl_kind), dimension(nx_block,ny_block,8), intent(out) :: &
    2027             :          Drheo          ! intermediate value for diagonal components of matrix A associated
    2028             :                        ! with rheology term
    2029             : 
    2030             :       ! local variables
    2031             : 
    2032             :       integer (kind=int_kind) :: &
    2033             :          i, j, ij, iu, ju, di, dj, cc
    2034             : 
    2035             :       real (kind=dbl_kind) :: &
    2036             :         divune, divunw, divuse, divusw            , & ! divergence   ! LCOV_EXCL_LINE
    2037             :         tensionne, tensionnw, tensionse, tensionsw, & ! tension   ! LCOV_EXCL_LINE
    2038             :         shearne, shearnw, shearse, shearsw        , & ! shearing   ! LCOV_EXCL_LINE
    2039             :         uij,ui1j,uij1,ui1j1,vij,vi1j,vij1,vi1j1   , & ! == c0 or c1   ! LCOV_EXCL_LINE
    2040             :         stressp_1, stressp_2, stressp_3, stressp_4, &   ! LCOV_EXCL_LINE
    2041             :         stressm_1, stressm_2, stressm_3, stressm_4, &   ! LCOV_EXCL_LINE
    2042             :         stress12_1,stress12_2,stress12_3,stress12_4,&   ! LCOV_EXCL_LINE
    2043             :         ssigpn, ssigps, ssigpe, ssigpw            , &   ! LCOV_EXCL_LINE
    2044             :         ssigmn, ssigms, ssigme, ssigmw            , &   ! LCOV_EXCL_LINE
    2045             :         ssig12n, ssig12s, ssig12e, ssig12w        , &   ! LCOV_EXCL_LINE
    2046             :         ssigp1, ssigp2, ssigm1, ssigm2, ssig121, ssig122, &   ! LCOV_EXCL_LINE
    2047             :         csigpne, csigpnw, csigpse, csigpsw        , &   ! LCOV_EXCL_LINE
    2048             :         csigmne, csigmnw, csigmse, csigmsw        , &   ! LCOV_EXCL_LINE
    2049             :         csig12ne, csig12nw, csig12se, csig12sw    , &   ! LCOV_EXCL_LINE
    2050             :         str12ew, str12we, str12ns, str12sn        , &   ! LCOV_EXCL_LINE
    2051           0 :         strp_tmp, strm_tmp
    2052             : 
    2053             :       character(len=*), parameter :: subname = '(formDiag_step1)'
    2054             : 
    2055             :       !-----------------------------------------------------------------
    2056             :       ! Initialize
    2057             :       !-----------------------------------------------------------------
    2058             : 
    2059           0 :       Drheo(:,:,:) = c0
    2060             : 
    2061             :       ! Be careful: Drheo contains 4 terms for u and 4 terms for v.
    2062             :       ! These 8 terms come from the surrounding T cells but are all
    2063             :       ! refrerenced to the i,j (u point) :
    2064             : 
    2065             :       ! Drheo(i,j,1) corresponds to str(i,j,1)
    2066             :       ! Drheo(i,j,2) corresponds to str(i+1,j,2)
    2067             :       ! Drheo(i,j,3) corresponds to str(i,j+1,3)
    2068             :       ! Drheo(i,j,4) corresponds to str(i+1,j+1,4))
    2069             :       ! Drheo(i,j,5) corresponds to str(i,j,5)
    2070             :       ! Drheo(i,j,6) corresponds to str(i,j+1,6)
    2071             :       ! Drheo(i,j,7) corresponds to str(i+1,j,7)
    2072             :       ! Drheo(i,j,8) corresponds to str(i+1,j+1,8))
    2073             : 
    2074           0 :       do cc = 1, 8 ! 4 for u and 4 for v
    2075             : 
    2076           0 :          if (cc == 1) then     ! u comp, T cell i,j
    2077           0 :             uij   = c1
    2078           0 :             ui1j  = c0
    2079           0 :             uij1  = c0
    2080           0 :             ui1j1 = c0
    2081           0 :             vij   = c0
    2082           0 :             vi1j  = c0
    2083           0 :             vij1  = c0
    2084           0 :             vi1j1 = c0
    2085           0 :             di    = 0
    2086           0 :             dj    = 0
    2087           0 :          elseif (cc == 2) then ! u comp, T cell i+1,j
    2088           0 :             uij   = c0
    2089           0 :             ui1j  = c1
    2090           0 :             uij1  = c0
    2091           0 :             ui1j1 = c0
    2092           0 :             vij   = c0
    2093           0 :             vi1j  = c0
    2094           0 :             vij1  = c0
    2095           0 :             vi1j1 = c0
    2096           0 :             di    = 1
    2097           0 :             dj    = 0
    2098           0 :          elseif (cc == 3) then ! u comp, T cell i,j+1
    2099           0 :             uij   = c0
    2100           0 :             ui1j  = c0
    2101           0 :             uij1  = c1
    2102           0 :             ui1j1 = c0
    2103           0 :             vij   = c0
    2104           0 :             vi1j  = c0
    2105           0 :             vij1  = c0
    2106           0 :             vi1j1 = c0
    2107           0 :             di    = 0
    2108           0 :             dj    = 1
    2109           0 :          elseif (cc == 4) then ! u comp, T cell i+1,j+1
    2110           0 :             uij   = c0
    2111           0 :             ui1j  = c0
    2112           0 :             uij1  = c0
    2113           0 :             ui1j1 = c1
    2114           0 :             vij   = c0
    2115           0 :             vi1j  = c0
    2116           0 :             vij1  = c0
    2117           0 :             vi1j1 = c0
    2118           0 :             di    = 1
    2119           0 :             dj    = 1
    2120           0 :          elseif (cc == 5) then ! v comp, T cell i,j
    2121           0 :             uij   = c0
    2122           0 :             ui1j  = c0
    2123           0 :             uij1  = c0
    2124           0 :             ui1j1 = c0
    2125           0 :             vij   = c1
    2126           0 :             vi1j  = c0
    2127           0 :             vij1  = c0
    2128           0 :             vi1j1 = c0
    2129           0 :             di    = 0
    2130           0 :             dj    = 0
    2131           0 :          elseif (cc == 6) then ! v comp, T cell i,j+1
    2132           0 :             uij   = c0
    2133           0 :             ui1j  = c0
    2134           0 :             uij1  = c0
    2135           0 :             ui1j1 = c0
    2136           0 :             vij   = c0
    2137           0 :             vi1j  = c0
    2138           0 :             vij1  = c1
    2139           0 :             vi1j1 = c0
    2140           0 :             di    = 0
    2141           0 :             dj    = 1
    2142           0 :          elseif (cc == 7) then ! v comp, T cell i+1,j
    2143           0 :             uij   = c0
    2144           0 :             ui1j  = c0
    2145           0 :             uij1  = c0
    2146           0 :             ui1j1 = c0
    2147           0 :             vij   = c0
    2148           0 :             vi1j  = c1
    2149           0 :             vij1  = c0
    2150           0 :             vi1j1 = c0
    2151           0 :             di    = 1
    2152           0 :             dj    = 0
    2153           0 :          elseif (cc == 8) then ! v comp, T cell i+1,j+1
    2154           0 :             uij   = c0
    2155           0 :             ui1j  = c0
    2156           0 :             uij1  = c0
    2157           0 :             ui1j1 = c0
    2158           0 :             vij   = c0
    2159           0 :             vi1j  = c0
    2160           0 :             vij1  = c0
    2161           0 :             vi1j1 = c1
    2162           0 :             di    = 1
    2163           0 :             dj    = 1
    2164             :          endif
    2165             : 
    2166           0 :          do ij = 1, icellU
    2167             : 
    2168           0 :             iu = indxUi(ij)
    2169           0 :             ju = indxUj(ij)
    2170           0 :             i  = iu + di
    2171           0 :             j  = ju + dj
    2172             : 
    2173             :          !-----------------------------------------------------------------
    2174             :          ! strain rates
    2175             :          ! NOTE these are actually strain rates * area  (m^2/s)
    2176             :          !-----------------------------------------------------------------
    2177             :             ! divergence  =  e_11 + e_22
    2178           0 :             divune    = cyp(i,j)*uij   - dyT(i,j)*ui1j  &
    2179           0 :                       + cxp(i,j)*vij   - dxT(i,j)*vij1
    2180           0 :             divunw    = cym(i,j)*ui1j  + dyT(i,j)*uij   &
    2181           0 :                       + cxp(i,j)*vi1j  - dxT(i,j)*vi1j1
    2182           0 :             divusw    = cym(i,j)*ui1j1 + dyT(i,j)*uij1  &
    2183           0 :                       + cxm(i,j)*vi1j1 + dxT(i,j)*vi1j
    2184           0 :             divuse    = cyp(i,j)*uij1  - dyT(i,j)*ui1j1 &
    2185           0 :                       + cxm(i,j)*vij1  + dxT(i,j)*vij
    2186             : 
    2187             :             ! tension strain rate  =  e_11 - e_22
    2188           0 :             tensionne = -cym(i,j)*uij   - dyT(i,j)*ui1j  &
    2189           0 :                       +  cxm(i,j)*vij   + dxT(i,j)*vij1
    2190           0 :             tensionnw = -cyp(i,j)*ui1j  + dyT(i,j)*uij   &
    2191           0 :                       +  cxm(i,j)*vi1j  + dxT(i,j)*vi1j1
    2192           0 :             tensionsw = -cyp(i,j)*ui1j1 + dyT(i,j)*uij1  &
    2193           0 :                       +  cxp(i,j)*vi1j1 - dxT(i,j)*vi1j
    2194           0 :             tensionse = -cym(i,j)*uij1  - dyT(i,j)*ui1j1 &
    2195           0 :                       +  cxp(i,j)*vij1  - dxT(i,j)*vij
    2196             : 
    2197             :             ! shearing strain rate  =  2*e_12
    2198           0 :             shearne = -cym(i,j)*vij   - dyT(i,j)*vi1j  &
    2199           0 :                     -  cxm(i,j)*uij   - dxT(i,j)*uij1
    2200           0 :             shearnw = -cyp(i,j)*vi1j  + dyT(i,j)*vij   &
    2201           0 :                     -  cxm(i,j)*ui1j  - dxT(i,j)*ui1j1
    2202           0 :             shearsw = -cyp(i,j)*vi1j1 + dyT(i,j)*vij1  &
    2203           0 :                     -  cxp(i,j)*ui1j1 + dxT(i,j)*ui1j
    2204           0 :             shearse = -cym(i,j)*vij1  - dyT(i,j)*vi1j1 &
    2205           0 :                     -  cxp(i,j)*uij1  + dxT(i,j)*uij
    2206             : 
    2207             :          !-----------------------------------------------------------------
    2208             :          ! the stresses                            ! kg/s^2
    2209             :          ! (1) northeast, (2) northwest, (3) southwest, (4) southeast
    2210             :          !-----------------------------------------------------------------
    2211             : 
    2212           0 :             stressp_1 = zetax2(i,j,1)*divune
    2213           0 :             stressp_2 = zetax2(i,j,2)*divunw
    2214           0 :             stressp_3 = zetax2(i,j,3)*divusw
    2215           0 :             stressp_4 = zetax2(i,j,4)*divuse
    2216             : 
    2217           0 :             stressm_1 = etax2(i,j,1)*tensionne
    2218           0 :             stressm_2 = etax2(i,j,2)*tensionnw
    2219           0 :             stressm_3 = etax2(i,j,3)*tensionsw
    2220           0 :             stressm_4 = etax2(i,j,4)*tensionse
    2221             : 
    2222           0 :             stress12_1 = etax2(i,j,1)*shearne*p5
    2223           0 :             stress12_2 = etax2(i,j,2)*shearnw*p5
    2224           0 :             stress12_3 = etax2(i,j,3)*shearsw*p5
    2225           0 :             stress12_4 = etax2(i,j,4)*shearse*p5
    2226             : 
    2227             :          !-----------------------------------------------------------------
    2228             :          ! combinations of the stresses for the momentum equation ! kg/s^2
    2229             :          !-----------------------------------------------------------------
    2230             : 
    2231           0 :             ssigpn  = stressp_1 + stressp_2
    2232           0 :             ssigps  = stressp_3 + stressp_4
    2233           0 :             ssigpe  = stressp_1 + stressp_4
    2234           0 :             ssigpw  = stressp_2 + stressp_3
    2235           0 :             ssigp1  =(stressp_1 + stressp_3)*p055
    2236           0 :             ssigp2  =(stressp_2 + stressp_4)*p055
    2237             : 
    2238           0 :             ssigmn  = stressm_1 + stressm_2
    2239           0 :             ssigms  = stressm_3 + stressm_4
    2240           0 :             ssigme  = stressm_1 + stressm_4
    2241           0 :             ssigmw  = stressm_2 + stressm_3
    2242           0 :             ssigm1  =(stressm_1 + stressm_3)*p055
    2243           0 :             ssigm2  =(stressm_2 + stressm_4)*p055
    2244             : 
    2245           0 :             ssig12n = stress12_1 + stress12_2
    2246           0 :             ssig12s = stress12_3 + stress12_4
    2247           0 :             ssig12e = stress12_1 + stress12_4
    2248           0 :             ssig12w = stress12_2 + stress12_3
    2249           0 :             ssig121 =(stress12_1 + stress12_3)*p111
    2250           0 :             ssig122 =(stress12_2 + stress12_4)*p111
    2251             : 
    2252           0 :             csigpne = p111*stressp_1 + ssigp2 + p027*stressp_3
    2253           0 :             csigpnw = p111*stressp_2 + ssigp1 + p027*stressp_4
    2254           0 :             csigpsw = p111*stressp_3 + ssigp2 + p027*stressp_1
    2255           0 :             csigpse = p111*stressp_4 + ssigp1 + p027*stressp_2
    2256             : 
    2257           0 :             csigmne = p111*stressm_1 + ssigm2 + p027*stressm_3
    2258           0 :             csigmnw = p111*stressm_2 + ssigm1 + p027*stressm_4
    2259           0 :             csigmsw = p111*stressm_3 + ssigm2 + p027*stressm_1
    2260           0 :             csigmse = p111*stressm_4 + ssigm1 + p027*stressm_2
    2261             : 
    2262             :             csig12ne = p222*stress12_1 + ssig122 &
    2263           0 :                      + p055*stress12_3
    2264             :             csig12nw = p222*stress12_2 + ssig121 &
    2265           0 :                      + p055*stress12_4
    2266             :             csig12sw = p222*stress12_3 + ssig122 &
    2267           0 :                      + p055*stress12_1
    2268             :             csig12se = p222*stress12_4 + ssig121 &
    2269           0 :                      + p055*stress12_2
    2270             : 
    2271           0 :             str12ew = p5*dxT(i,j)*(p333*ssig12e + p166*ssig12w)
    2272           0 :             str12we = p5*dxT(i,j)*(p333*ssig12w + p166*ssig12e)
    2273           0 :             str12ns = p5*dyT(i,j)*(p333*ssig12n + p166*ssig12s)
    2274           0 :             str12sn = p5*dyT(i,j)*(p333*ssig12s + p166*ssig12n)
    2275             : 
    2276             :          !-----------------------------------------------------------------
    2277             :          ! for dF/dx (u momentum)
    2278             :          !-----------------------------------------------------------------
    2279             : 
    2280           0 :             if (cc == 1) then ! T cell i,j
    2281             : 
    2282           0 :                strp_tmp  = p25*dyT(i,j)*(p333*ssigpn  + p166*ssigps)
    2283           0 :                strm_tmp  = p25*dyT(i,j)*(p333*ssigmn  + p166*ssigms)
    2284             : 
    2285             :                ! northeast (i,j)
    2286           0 :                Drheo(iu,ju,1) = -strp_tmp - strm_tmp - str12ew &
    2287           0 :                   + dxhy(i,j)*(-csigpne + csigmne) + dyhx(i,j)*csig12ne
    2288             : 
    2289           0 :             elseif (cc == 2) then ! T cell i+1,j
    2290             : 
    2291           0 :                strp_tmp  = p25*dyT(i,j)*(p333*ssigpn  + p166*ssigps)
    2292           0 :                strm_tmp  = p25*dyT(i,j)*(p333*ssigmn  + p166*ssigms)
    2293             : 
    2294             :                ! northwest (i+1,j)
    2295           0 :                Drheo(iu,ju,2) = strp_tmp + strm_tmp - str12we &
    2296           0 :                   + dxhy(i,j)*(-csigpnw + csigmnw) + dyhx(i,j)*csig12nw
    2297             : 
    2298           0 :             elseif (cc == 3) then ! T cell i,j+1
    2299             : 
    2300           0 :                strp_tmp  = p25*dyT(i,j)*(p333*ssigps  + p166*ssigpn)
    2301           0 :                strm_tmp  = p25*dyT(i,j)*(p333*ssigms  + p166*ssigmn)
    2302             : 
    2303             :                ! southeast (i,j+1)
    2304           0 :                Drheo(iu,ju,3) = -strp_tmp - strm_tmp + str12ew &
    2305           0 :                   + dxhy(i,j)*(-csigpse + csigmse) + dyhx(i,j)*csig12se
    2306             : 
    2307           0 :             elseif (cc == 4) then ! T cell i+1,j+1
    2308             : 
    2309           0 :                strp_tmp  = p25*dyT(i,j)*(p333*ssigps  + p166*ssigpn)
    2310           0 :                strm_tmp  = p25*dyT(i,j)*(p333*ssigms  + p166*ssigmn)
    2311             : 
    2312             :                ! southwest (i+1,j+1)
    2313           0 :                Drheo(iu,ju,4) = strp_tmp + strm_tmp + str12we &
    2314           0 :                   + dxhy(i,j)*(-csigpsw + csigmsw) + dyhx(i,j)*csig12sw
    2315             : 
    2316             :          !-----------------------------------------------------------------
    2317             :          ! for dF/dy (v momentum)
    2318             :          !-----------------------------------------------------------------
    2319             : 
    2320           0 :             elseif (cc == 5) then ! T cell i,j
    2321             : 
    2322           0 :                strp_tmp  = p25*dxT(i,j)*(p333*ssigpe  + p166*ssigpw)
    2323           0 :                strm_tmp  = p25*dxT(i,j)*(p333*ssigme  + p166*ssigmw)
    2324             : 
    2325             :                ! northeast (i,j)
    2326           0 :                Drheo(iu,ju,5) = -strp_tmp + strm_tmp - str12ns &
    2327           0 :                   - dyhx(i,j)*(csigpne + csigmne) + dxhy(i,j)*csig12ne
    2328             : 
    2329           0 :             elseif (cc == 6) then ! T cell i,j+1
    2330             : 
    2331           0 :                strp_tmp  = p25*dxT(i,j)*(p333*ssigpe  + p166*ssigpw)
    2332           0 :                strm_tmp  = p25*dxT(i,j)*(p333*ssigme  + p166*ssigmw)
    2333             : 
    2334             :                ! southeast (i,j+1)
    2335           0 :                Drheo(iu,ju,6) = strp_tmp - strm_tmp - str12sn &
    2336           0 :                   - dyhx(i,j)*(csigpse + csigmse) + dxhy(i,j)*csig12se
    2337             : 
    2338           0 :             elseif (cc == 7) then ! T cell i,j+1
    2339             : 
    2340           0 :                strp_tmp  = p25*dxT(i,j)*(p333*ssigpw  + p166*ssigpe)
    2341           0 :                strm_tmp  = p25*dxT(i,j)*(p333*ssigmw  + p166*ssigme)
    2342             : 
    2343             :                ! northwest (i+1,j)
    2344           0 :                Drheo(iu,ju,7) = -strp_tmp + strm_tmp + str12ns &
    2345           0 :                   - dyhx(i,j)*(csigpnw + csigmnw) + dxhy(i,j)*csig12nw
    2346             : 
    2347           0 :             elseif (cc == 8) then ! T cell i+1,j+1
    2348             : 
    2349           0 :                strp_tmp  = p25*dxT(i,j)*(p333*ssigpw  + p166*ssigpe)
    2350           0 :                strm_tmp  = p25*dxT(i,j)*(p333*ssigmw  + p166*ssigme)
    2351             : 
    2352             :                ! southwest (i+1,j+1)
    2353           0 :                Drheo(iu,ju,8) = strp_tmp - strm_tmp + str12sn &
    2354           0 :                   - dyhx(i,j)*(csigpsw + csigmsw) + dxhy(i,j)*csig12sw
    2355             : 
    2356             :             endif
    2357             : 
    2358             :          enddo                     ! ij
    2359             : 
    2360             :       enddo                     ! cc
    2361             : 
    2362           0 :       end subroutine formDiag_step1
    2363             : 
    2364             : !=======================================================================
    2365             : 
    2366             : ! Form the diagonal of the matrix A(u,v) (second part of the computation)
    2367             : ! Part 2: compute diagonal
    2368             : 
    2369           0 :       subroutine formDiag_step2 (nx_block, ny_block, &
    2370             :                                  icellU  ,           &   ! LCOV_EXCL_LINE
    2371             :                                  indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    2372             :                                  Drheo   , vrel    , &   ! LCOV_EXCL_LINE
    2373             :                                  umassdti,           &   ! LCOV_EXCL_LINE
    2374             :                                  uarear  , Cb      , &   ! LCOV_EXCL_LINE
    2375           0 :                                  diagx   , diagy)
    2376             : 
    2377             :       integer (kind=int_kind), intent(in) :: &
    2378             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    2379             :          icellU                ! total count when iceUmask = .true.
    2380             : 
    2381             :       integer (kind=int_kind), dimension (nx_block*ny_block), intent(in) :: &
    2382             :          indxUi  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    2383             :          indxUj      ! compressed index in j-direction
    2384             : 
    2385             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(in) :: &
    2386             :          vrel,     & ! coefficient for tauw   ! LCOV_EXCL_LINE
    2387             :          Cb,       & ! coefficient for seabed stress   ! LCOV_EXCL_LINE
    2388             :          umassdti, & ! mass of U-cell/dt (kg/m^2 s)   ! LCOV_EXCL_LINE
    2389             :          uarear      ! 1/uarea
    2390             : 
    2391             :       real (kind=dbl_kind), dimension(nx_block,ny_block,8), intent(in) :: &
    2392             :          Drheo
    2393             : 
    2394             :       real (kind=dbl_kind), dimension (nx_block,ny_block), intent(out) :: &
    2395             :          diagx   , & ! Diagonal (x component) of the matrix A   ! LCOV_EXCL_LINE
    2396             :          diagy       ! Diagonal (y component) of the matrix A
    2397             : 
    2398             :       ! local variables
    2399             : 
    2400             :       integer (kind=int_kind) :: &
    2401             :          i, j, ij
    2402             : 
    2403             :       real (kind=dbl_kind) :: &
    2404             :          ccaimp             , & ! intermediate variables   ! LCOV_EXCL_LINE
    2405           0 :          strintx, strinty       ! diagonal contributions to the divergence
    2406             : 
    2407             :       character(len=*), parameter :: subname = '(formDiag_step2)'
    2408             : 
    2409             :       !-----------------------------------------------------------------
    2410             :       ! integrate the momentum equation
    2411             :       !-----------------------------------------------------------------
    2412             : 
    2413           0 :       strintx = c0
    2414           0 :       strinty = c0
    2415             : 
    2416             :       ! Be careful: Drheo contains 4 terms for u and 4 terms for v.
    2417             :       ! These 8 terms come from the surrounding T cells but are all
    2418             :       ! refrerenced to the i,j (u point) :
    2419             : 
    2420             :       ! Drheo(i,j,1) corresponds to str(i,j,1)
    2421             :       ! Drheo(i,j,2) corresponds to str(i+1,j,2)
    2422             :       ! Drheo(i,j,3) corresponds to str(i,j+1,3)
    2423             :       ! Drheo(i,j,4) corresponds to str(i+1,j+1,4))
    2424             :       ! Drheo(i,j,5) corresponds to str(i,j,5)
    2425             :       ! Drheo(i,j,6) corresponds to str(i,j+1,6)
    2426             :       ! Drheo(i,j,7) corresponds to str(i+1,j,7)
    2427             :       ! Drheo(i,j,8) corresponds to str(i+1,j+1,8))
    2428             : 
    2429           0 :       do ij = 1, icellU
    2430           0 :          i = indxUi(ij)
    2431           0 :          j = indxUj(ij)
    2432             : 
    2433           0 :          ccaimp = umassdti(i,j) + vrel(i,j) * cosw + Cb(i,j) ! kg/m^2 s
    2434             : 
    2435           0 :          strintx = uarear(i,j)* &
    2436           0 :              (Drheo(i,j,1) + Drheo(i,j,2) + Drheo(i,j,3) + Drheo(i,j,4))
    2437           0 :          strinty = uarear(i,j)* &
    2438           0 :              (Drheo(i,j,5) + Drheo(i,j,6) + Drheo(i,j,7) + Drheo(i,j,8))
    2439             : 
    2440           0 :          diagx(i,j) = ccaimp - strintx
    2441           0 :          diagy(i,j) = ccaimp - strinty
    2442             :       enddo                     ! ij
    2443             : 
    2444           0 :       end subroutine formDiag_step2
    2445             : 
    2446             : !=======================================================================
    2447             : 
    2448             : ! Compute global l^2 norm of a vector field (field_x, field_y)
    2449             : 
    2450           0 :       function global_norm (nx_block, ny_block, &
    2451             :                             icellU  ,           &   ! LCOV_EXCL_LINE
    2452             :                             indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    2453             :                             field_x , field_y ) &   ! LCOV_EXCL_LINE
    2454           0 :                result(norm)
    2455             : 
    2456             :       use ice_domain, only: distrb_info
    2457             :       use ice_domain_size, only: max_blocks
    2458             : 
    2459             :       integer (kind=int_kind), intent(in) :: &
    2460             :          nx_block, ny_block    ! block dimensions
    2461             : 
    2462             :       integer (kind=int_kind), dimension (max_blocks), intent(in) :: &
    2463             :          icellU                ! total count when iceumask is true
    2464             : 
    2465             :       integer (kind=int_kind), dimension (nx_block*ny_block,max_blocks), intent(in) :: &
    2466             :          indxUi  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    2467             :          indxUj      ! compressed index in j-direction
    2468             : 
    2469             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks), intent(in) :: &
    2470             :          field_x     , & ! x-component of vector field   ! LCOV_EXCL_LINE
    2471             :          field_y         ! y-component of vector field
    2472             : 
    2473             :       real (kind=dbl_kind) :: &
    2474             :          norm      ! l^2 norm of vector field
    2475             : 
    2476             :       ! local variables
    2477             : 
    2478             :       integer (kind=int_kind) :: &
    2479             :          i, j, ij, iblk
    2480             : 
    2481             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks) :: &
    2482             :          squared      ! temporary array for summed squared components
    2483             : 
    2484             :       character(len=*), parameter :: subname = '(global_norm)'
    2485             : 
    2486             :       norm = sqrt(global_dot_product (nx_block  , ny_block , &
    2487             :                                       icellU    ,            &   ! LCOV_EXCL_LINE
    2488             :                                       indxUi    , indxUj   , &   ! LCOV_EXCL_LINE
    2489             :                                       field_x   , field_y  , &   ! LCOV_EXCL_LINE
    2490           0 :                                       field_x   , field_y  ))
    2491             : 
    2492           0 :       end function global_norm
    2493             : 
    2494             : !=======================================================================
    2495             : 
    2496             : ! Compute global dot product of two grid vectors, each split into X and Y components
    2497             : 
    2498           0 :       function global_dot_product (nx_block  , ny_block , &
    2499             :                                    icellU    ,            &   ! LCOV_EXCL_LINE
    2500             :                                    indxUi    , indxUj   , &   ! LCOV_EXCL_LINE
    2501             :                                    vector1_x , vector1_y, &   ! LCOV_EXCL_LINE
    2502             :                                    vector2_x , vector2_y) &   ! LCOV_EXCL_LINE
    2503           0 :                result(dot_product)
    2504             : 
    2505             :       use ice_domain, only: distrb_info, ns_boundary_type
    2506             :       use ice_domain_size, only: max_blocks
    2507             :       use ice_fileunits, only: bfbflag
    2508             : 
    2509             :       integer (kind=int_kind), intent(in) :: &
    2510             :          nx_block, ny_block    ! block dimensions
    2511             : 
    2512             :       integer (kind=int_kind), dimension (max_blocks), intent(in) :: &
    2513             :          icellU                ! total count when iceumask is true
    2514             : 
    2515             :       integer (kind=int_kind), dimension (nx_block*ny_block,max_blocks), intent(in) :: &
    2516             :          indxUi  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    2517             :          indxUj      ! compressed index in j-direction
    2518             : 
    2519             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks), intent(in) :: &
    2520             :          vector1_x     , & ! x-component of first vector   ! LCOV_EXCL_LINE
    2521             :          vector1_y     , & ! y-component of first vector   ! LCOV_EXCL_LINE
    2522             :          vector2_x     , & ! x-component of second vector   ! LCOV_EXCL_LINE
    2523             :          vector2_y         ! y-component of second vector
    2524             : 
    2525             :       real (kind=dbl_kind) :: &
    2526             :          dot_product      ! l^2 norm of vector field
    2527             : 
    2528             :       ! local variables
    2529             : 
    2530             :       integer (kind=int_kind) :: &
    2531             :          i, j, ij, iblk
    2532             : 
    2533             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks) :: &
    2534           0 :          prod      ! temporary array
    2535             : 
    2536             :       real (kind=dbl_kind), dimension(max_blocks) :: &
    2537           0 :          dot       ! temporary scalar for accumulating the result
    2538             : 
    2539             :       character(len=*), parameter :: subname = '(global_dot_product)'
    2540             : 
    2541           0 :       prod = c0
    2542           0 :       dot  = c0
    2543             : 
    2544           0 :       !$OMP PARALLEL DO PRIVATE(i, j, ij, iblk)
    2545           0 :       do iblk = 1, nblocks
    2546           0 :          do ij = 1, icellU(iblk)
    2547           0 :             i = indxUi(ij, iblk)
    2548           0 :             j = indxUj(ij, iblk)
    2549           0 :             prod(i,j,iblk) = vector1_x(i,j,iblk)*vector2_x(i,j,iblk) + vector1_y(i,j,iblk)*vector2_y(i,j,iblk)
    2550           0 :             dot(iblk) = dot(iblk) + prod(i,j,iblk)
    2551             :          enddo ! ij
    2552             :       enddo
    2553             :       !$OMP END PARALLEL DO
    2554             : 
    2555             :       ! Use faster local summation result for several bfbflag settings.
    2556             :       ! The local implementation sums over each block, sums over local
    2557             :       ! blocks, and calls global_sum on a scalar and should be just as accurate as
    2558             :       ! bfbflag = 'off', 'lsum8', and 'lsum4' without the extra copies and overhead
    2559             :       ! in the more general array global_sum.  But use the array global_sum
    2560             :       ! if bfbflag is more strict or for tripole grids (requires special masking)
    2561           0 :       if (ns_boundary_type /= 'tripole' .and. ns_boundary_type /= 'tripoleT' .and. &
    2562             :          (bfbflag == 'off' .or. bfbflag == 'lsum8' .or. bfbflag == 'lsum4')) then
    2563           0 :          dot_product = global_sum(sum(dot), distrb_info)
    2564             :       else
    2565           0 :          dot_product = global_sum(prod, distrb_info, field_loc_NEcorner)
    2566             :       endif
    2567             : 
    2568           0 :       end function global_dot_product
    2569             : 
    2570             : !=======================================================================
    2571             : 
    2572             : ! Convert a grid function (tpu,tpv) to a one dimensional vector
    2573             : 
    2574           0 :       subroutine arrays_to_vec (nx_block, ny_block  , &
    2575             :                                 nblocks , max_blocks, &   ! LCOV_EXCL_LINE
    2576             :                                 icellU  , ntot      , &   ! LCOV_EXCL_LINE
    2577             :                                 indxUi  , indxUj    , &   ! LCOV_EXCL_LINE
    2578             :                                 tpu     , tpv       , &   ! LCOV_EXCL_LINE
    2579           0 :                                 outvec)
    2580             : 
    2581             :       integer (kind=int_kind), intent(in) :: &
    2582             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    2583             :          nblocks,            & ! nb of blocks   ! LCOV_EXCL_LINE
    2584             :          max_blocks,         & ! max nb of blocks   ! LCOV_EXCL_LINE
    2585             :          ntot                  ! size of problem for Anderson
    2586             : 
    2587             :       integer (kind=int_kind), dimension (max_blocks), intent(in) :: &
    2588             :          icellU
    2589             : 
    2590             :       integer (kind=int_kind), dimension (nx_block*ny_block, max_blocks), intent(in) :: &
    2591             :          indxUi  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    2592             :          indxUj      ! compressed index in j-direction
    2593             : 
    2594             :       real (kind=dbl_kind), dimension (nx_block,ny_block, max_blocks), intent(in) :: &
    2595             :          tpu     , & ! x-component of vector   ! LCOV_EXCL_LINE
    2596             :          tpv         ! y-component of vector
    2597             : 
    2598             :       real (kind=dbl_kind), dimension (ntot), intent(out) :: &
    2599             :          outvec      ! output 1D vector
    2600             : 
    2601             :       ! local variables
    2602             : 
    2603             :       integer (kind=int_kind) :: &
    2604             :          i, j, iblk, tot, ij
    2605             : 
    2606             :       character(len=*), parameter :: subname = '(arrays_to_vec)'
    2607             : 
    2608             :       !-----------------------------------------------------------------
    2609             :       ! form vector (converts from max_blocks arrays to single vector)
    2610             :       !-----------------------------------------------------------------
    2611             : 
    2612           0 :       outvec(:) = c0
    2613           0 :       tot = 0
    2614             : 
    2615           0 :       do iblk = 1, nblocks
    2616           0 :          do ij = 1, icellU(iblk)
    2617           0 :             i = indxUi(ij, iblk)
    2618           0 :             j = indxUj(ij, iblk)
    2619           0 :             tot = tot + 1
    2620           0 :             outvec(tot) = tpu(i, j, iblk)
    2621           0 :             tot = tot + 1
    2622           0 :             outvec(tot) = tpv(i, j, iblk)
    2623             :          enddo
    2624             :       enddo ! ij
    2625             : 
    2626           0 :       end subroutine arrays_to_vec
    2627             : 
    2628             : !=======================================================================
    2629             : 
    2630             : ! Convert one dimensional vector to a grid function (tpu,tpv)
    2631             : 
    2632           0 :       subroutine vec_to_arrays (nx_block, ny_block  , &
    2633             :                                 nblocks , max_blocks, &   ! LCOV_EXCL_LINE
    2634             :                                 icellU  , ntot      , &   ! LCOV_EXCL_LINE
    2635             :                                 indxUi  , indxUj    , &   ! LCOV_EXCL_LINE
    2636             :                                 invec   ,             &   ! LCOV_EXCL_LINE
    2637           0 :                                 tpu     , tpv)
    2638             : 
    2639             :       integer (kind=int_kind), intent(in) :: &
    2640             :          nx_block, ny_block, & ! block dimensions   ! LCOV_EXCL_LINE
    2641             :          nblocks,            & ! nb of blocks   ! LCOV_EXCL_LINE
    2642             :          max_blocks,         & ! max nb of blocks   ! LCOV_EXCL_LINE
    2643             :          ntot                  ! size of problem for Anderson
    2644             : 
    2645             :       integer (kind=int_kind), dimension (max_blocks), intent(in) :: &
    2646             :          icellU
    2647             : 
    2648             :       integer (kind=int_kind), dimension (nx_block*ny_block, max_blocks), intent(in) :: &
    2649             :          indxUi  , & ! compressed index in i-direction   ! LCOV_EXCL_LINE
    2650             :          indxUj      ! compressed index in j-direction
    2651             : 
    2652             :       real (kind=dbl_kind), dimension (ntot), intent(in) :: &
    2653             :          invec       ! input 1D vector
    2654             : 
    2655             :       real (kind=dbl_kind), dimension (nx_block,ny_block, max_blocks), intent(out) :: &
    2656             :          tpu     , & ! x-component of vector   ! LCOV_EXCL_LINE
    2657             :          tpv         ! y-component of vector
    2658             : 
    2659             :       ! local variables
    2660             : 
    2661             :       integer (kind=int_kind) :: &
    2662             :          i, j, iblk, tot, ij
    2663             : 
    2664             :       character(len=*), parameter :: subname = '(vec_to_arrays)'
    2665             : 
    2666             :       !-----------------------------------------------------------------
    2667             :       ! form arrays (converts from vector to the max_blocks arrays)
    2668             :       !-----------------------------------------------------------------
    2669             : 
    2670           0 :       tpu(:,:,:) = c0
    2671           0 :       tpv(:,:,:) = c0
    2672           0 :       tot = 0
    2673             : 
    2674           0 :       do iblk = 1, nblocks
    2675           0 :          do ij = 1, icellU(iblk)
    2676           0 :             i = indxUi(ij, iblk)
    2677           0 :             j = indxUj(ij, iblk)
    2678           0 :             tot = tot + 1
    2679           0 :             tpu(i, j, iblk) = invec(tot)
    2680           0 :             tot = tot + 1
    2681           0 :             tpv(i, j, iblk) = invec(tot)
    2682             :          enddo
    2683             :       enddo! ij
    2684             : 
    2685           0 :       end subroutine vec_to_arrays
    2686             : 
    2687             : !=======================================================================
    2688             : 
    2689             : ! Update Q and R factors after deletion of the 1st column of G_diff
    2690             : !
    2691             : ! author: P. Blain ECCC
    2692             : !
    2693             : ! adapted from :
    2694             : ! H. F. Walker, “Anderson Acceleration: Algorithms and Implementations”
    2695             : !   [Online]. Available: https://users.wpi.edu/~walker/Papers/anderson_accn_algs_imps.pdf
    2696             : 
    2697           0 :       subroutine qr_delete(Q, R)
    2698             : 
    2699             :       real (kind=dbl_kind), intent(inout) :: &
    2700             :          Q(:,:),  & ! Q factor   ! LCOV_EXCL_LINE
    2701             :          R(:,:)     ! R factor
    2702             : 
    2703             :       ! local variables
    2704             : 
    2705             :       integer (kind=int_kind) :: &
    2706             :          i, j, k, & ! loop indices   ! LCOV_EXCL_LINE
    2707             :          m, n       ! size of Q matrix
    2708             : 
    2709             :       real (kind=dbl_kind) :: &
    2710           0 :          temp, c, s
    2711             : 
    2712             :       character(len=*), parameter :: subname = '(qr_delete)'
    2713             : 
    2714           0 :       n = size(Q, 1)
    2715           0 :       m = size(Q, 2)
    2716           0 :       do i = 1, m-1
    2717           0 :          temp = sqrt(R(i, i+1)**2 + R(i+1, i+1)**2)
    2718           0 :          c = R(i  , i+1) / temp
    2719           0 :          s = R(i+1, i+1) / temp
    2720           0 :          R(i  , i+1) = temp
    2721           0 :          R(i+1, i+1) = 0
    2722           0 :          if (i < m-1) then
    2723           0 :             do j = i+2, m
    2724           0 :                temp      =  c*R(i, j) + s*R(i+1, j)
    2725           0 :                R(i+1, j) = -s*R(i, j) + c*R(i+1, j)
    2726           0 :                R(i  , j) = temp
    2727             :             enddo
    2728             :          endif
    2729           0 :          do k = 1, n
    2730           0 :             temp      =  c*Q(k, i) + s*Q(k, i+1);
    2731           0 :             Q(k, i+1) = -s*Q(k, i) + c*Q(k, i+1);
    2732           0 :             Q(k, i)   = temp
    2733             :          enddo
    2734             :       enddo
    2735           0 :       R(:, 1:m-1) = R(:, 2:m)
    2736             : 
    2737           0 :       end subroutine qr_delete
    2738             : 
    2739             : !=======================================================================
    2740             : 
    2741             : ! FGMRES: Flexible generalized minimum residual method (with restarts).
    2742             : ! Solves the linear system A x = b using GMRES with a varying (right) preconditioner
    2743             : !
    2744             : ! authors: Stéphane Gaudreault, Abdessamad Qaddouri, Philippe Blain, ECCC
    2745             : 
    2746           0 :       subroutine fgmres (zetax2   , etax2   , &
    2747             :                          Cb       , vrel    , &   ! LCOV_EXCL_LINE
    2748             :                          umassdti ,           &   ! LCOV_EXCL_LINE
    2749             :                          halo_info_mask     , &   ! LCOV_EXCL_LINE
    2750             :                          bx       , by      , &   ! LCOV_EXCL_LINE
    2751             :                          diagx    , diagy   , &   ! LCOV_EXCL_LINE
    2752             :                          tolerance, maxinner, &   ! LCOV_EXCL_LINE
    2753             :                          maxouter ,           &   ! LCOV_EXCL_LINE
    2754             :                          solx     , soly    , &   ! LCOV_EXCL_LINE
    2755             :                          nbiter)
    2756             : 
    2757             :       use ice_boundary, only: ice_HaloUpdate
    2758             :       use ice_domain, only: maskhalo_dyn, halo_info
    2759             :       use ice_timers, only: ice_timer_start, ice_timer_stop, timer_bound
    2760             : 
    2761             :       real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks,4), intent(in) :: &
    2762             :          zetax2   , & ! zetax2 = 2*zeta (bulk viscosity)   ! LCOV_EXCL_LINE
    2763             :          etax2        ! etax2  = 2*eta  (shear viscosity)
    2764             : 
    2765             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks), intent(in) :: &
    2766             :          vrel  , & ! coefficient for tauw   ! LCOV_EXCL_LINE
    2767             :          Cb    , & ! seabed stress coefficient   ! LCOV_EXCL_LINE
    2768             :          umassdti  ! mass of U-cell/dte (kg/m^2 s)
    2769             : 
    2770             :       type (ice_halo), intent(in) :: &
    2771             :          halo_info_mask !  ghost cell update info for masked halo
    2772             : 
    2773             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks), intent(in) :: &
    2774             :          bx       , & ! Right hand side of the linear system (x components)   ! LCOV_EXCL_LINE
    2775             :          by       , & ! Right hand side of the linear system (y components)   ! LCOV_EXCL_LINE
    2776             :          diagx    , & ! Diagonal of the system matrix (x components)   ! LCOV_EXCL_LINE
    2777             :          diagy        ! Diagonal of the system matrix (y components)
    2778             : 
    2779             :       real (kind=dbl_kind), intent(in) :: &
    2780             :          tolerance   ! Tolerance to achieve. The algorithm terminates when the relative
    2781             :                      ! residual is below tolerance
    2782             : 
    2783             :       integer (kind=int_kind), intent(in) :: &
    2784             :          maxinner, & ! Restart the method every maxinner inner (Arnoldi) iterations   ! LCOV_EXCL_LINE
    2785             :          maxouter    ! Maximum number of outer (restarts) iterations
    2786             :                      ! Iteration will stop after maxinner*maxouter Arnoldi steps
    2787             :                      ! even if the specified tolerance has not been achieved
    2788             : 
    2789             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks), intent(inout) :: &
    2790             :          solx     , & ! Initial guess on input, approximate solution on output (x components)   ! LCOV_EXCL_LINE
    2791             :          soly         ! Initial guess on input, approximate solution on output (y components)
    2792             : 
    2793             :       integer (kind=int_kind), intent(out) :: &
    2794             :          nbiter      ! Total number of Arnoldi iterations performed
    2795             : 
    2796             :       ! local variables
    2797             : 
    2798             :       integer (kind=int_kind) :: &
    2799             :          iblk    , & ! block index   ! LCOV_EXCL_LINE
    2800             :          ij      , & ! index for indx[t|u][i|j]   ! LCOV_EXCL_LINE
    2801             :          i, j        ! grid indices
    2802             : 
    2803             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks) :: &
    2804             :          workspace_x , & ! work vector (x components)   ! LCOV_EXCL_LINE
    2805           0 :          workspace_y     ! work vector (y components)
    2806             : 
    2807             :       real (kind=dbl_kind), dimension (max_blocks) :: &
    2808           0 :          norm_squared   ! array to accumulate squared norm of grid function over blocks
    2809             : 
    2810             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks, maxinner+1) :: &
    2811             :          arnoldi_basis_x , & ! Arnoldi basis (x components)   ! LCOV_EXCL_LINE
    2812           0 :          arnoldi_basis_y     ! Arnoldi basis (y components)
    2813             : 
    2814             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks, maxinner) :: &
    2815             :          orig_basis_x , & ! original basis (x components)   ! LCOV_EXCL_LINE
    2816           0 :          orig_basis_y     ! original basis (y components)
    2817             : 
    2818             :       real (kind=dbl_kind) :: &
    2819             :          norm_residual   , & ! current L^2 norm of residual vector   ! LCOV_EXCL_LINE
    2820             :          inverse_norm    , & ! inverse of the norm of a vector   ! LCOV_EXCL_LINE
    2821             :          norm_rhs        , & ! L^2 norm of right-hand-side vector   ! LCOV_EXCL_LINE
    2822           0 :          nu, t               ! local temporary values
    2823             : 
    2824             :       integer (kind=int_kind) :: &
    2825             :          initer          , & ! inner (Arnoldi) loop counter   ! LCOV_EXCL_LINE
    2826             :          outiter         , & ! outer (restarts) loop counter   ! LCOV_EXCL_LINE
    2827             :          nextit          , & ! nextit == initer+1   ! LCOV_EXCL_LINE
    2828             :          it, k, ii, jj       ! reusable loop counters
    2829             : 
    2830             :       real (kind=dbl_kind), dimension(maxinner+1) :: &
    2831             :          rot_cos         , & ! cosine elements of Givens rotations   ! LCOV_EXCL_LINE
    2832             :          rot_sin         , & ! sine elements of Givens rotations   ! LCOV_EXCL_LINE
    2833           0 :          rhs_hess            ! right hand side vector of the Hessenberg (least squares) system
    2834             : 
    2835             :       real (kind=dbl_kind), dimension(maxinner+1, maxinner) :: &
    2836           0 :          hessenberg        ! system matrix of the Hessenberg (least squares) system
    2837             : 
    2838             :       character (len=char_len) :: &
    2839             :          precond_type ! type of preconditioner
    2840             : 
    2841             :       real (kind=dbl_kind) :: &
    2842           0 :          relative_tolerance  ! relative_tolerance, i.e. tolerance*norm(initial residual)
    2843             : 
    2844             :       character(len=*), parameter :: subname = '(fgmres)'
    2845             : 
    2846             :       ! Here we go !
    2847             : 
    2848             :       ! Initialize
    2849           0 :       outiter = 0
    2850           0 :       nbiter = 0
    2851             : 
    2852           0 :       norm_squared = c0
    2853           0 :       precond_type = precond
    2854             : 
    2855             :       ! Cells with no ice should be zero-initialized
    2856           0 :       workspace_x = c0
    2857           0 :       workspace_y = c0
    2858           0 :       arnoldi_basis_x = c0
    2859           0 :       arnoldi_basis_y = c0
    2860             : 
    2861             :       ! solution is zero if RHS is zero
    2862             :       norm_rhs = global_norm(nx_block, ny_block, &
    2863             :                              icellU  ,           &   ! LCOV_EXCL_LINE
    2864             :                              indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    2865           0 :                              bx      , by        )
    2866           0 :       if (norm_rhs == c0) then
    2867           0 :          solx = bx
    2868           0 :          soly = by
    2869           0 :          return
    2870             :       endif
    2871             : 
    2872             :       ! Residual of the initial iterate
    2873             : 
    2874           0 :       !$OMP PARALLEL DO PRIVATE(iblk)
    2875           0 :       do iblk = 1, nblocks
    2876             :          call matvec (nx_block               , ny_block             , &
    2877             :                       icellU         (iblk)  , icellT         (iblk), &   ! LCOV_EXCL_LINE
    2878             :                       indxUi       (:,iblk)  , indxUj       (:,iblk), &   ! LCOV_EXCL_LINE
    2879             :                       indxTi       (:,iblk)  , indxTj       (:,iblk), &   ! LCOV_EXCL_LINE
    2880             :                       dxT        (:,:,iblk)  , dyT        (:,:,iblk), &   ! LCOV_EXCL_LINE
    2881             :                       dxhy       (:,:,iblk)  , dyhx       (:,:,iblk), &   ! LCOV_EXCL_LINE
    2882             :                       cxp        (:,:,iblk)  , cyp        (:,:,iblk), &   ! LCOV_EXCL_LINE
    2883             :                       cxm        (:,:,iblk)  , cym        (:,:,iblk), &   ! LCOV_EXCL_LINE
    2884             :                       solx       (:,:,iblk)  , soly       (:,:,iblk), &   ! LCOV_EXCL_LINE
    2885             :                       vrel       (:,:,iblk)  , Cb         (:,:,iblk), &   ! LCOV_EXCL_LINE
    2886             :                       zetax2     (:,:,iblk,:), etax2    (:,:,iblk,:), &   ! LCOV_EXCL_LINE
    2887             :                       umassdti   (:,:,iblk)  , fmU        (:,:,iblk), &   ! LCOV_EXCL_LINE
    2888             :                       uarear     (:,:,iblk)  ,                        &   ! LCOV_EXCL_LINE
    2889           0 :                       workspace_x(:,:,iblk)  , workspace_y(:,:,iblk))
    2890             :          call residual_vec (nx_block             , ny_block             , &
    2891             :                             icellU         (iblk),                        &   ! LCOV_EXCL_LINE
    2892             :                             indxUi       (:,iblk), indxUj       (:,iblk), &   ! LCOV_EXCL_LINE
    2893             :                             bx         (:,:,iblk), by         (:,:,iblk), &   ! LCOV_EXCL_LINE
    2894             :                             workspace_x(:,:,iblk), workspace_y(:,:,iblk), &   ! LCOV_EXCL_LINE
    2895             :                             arnoldi_basis_x (:,:,iblk, 1),                &   ! LCOV_EXCL_LINE
    2896           0 :                             arnoldi_basis_y (:,:,iblk, 1))
    2897             :       enddo
    2898             :       !$OMP END PARALLEL DO
    2899             : 
    2900             :       ! Start outer (restarts) loop
    2901           0 :       do
    2902             :          ! Compute norm of initial residual
    2903             :          norm_residual = global_norm(nx_block, ny_block, &
    2904             :                                      icellU  ,           &   ! LCOV_EXCL_LINE
    2905             :                                      indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    2906             :                                      arnoldi_basis_x(:,:,:, 1), &   ! LCOV_EXCL_LINE
    2907           0 :                                      arnoldi_basis_y(:,:,:, 1))
    2908             : 
    2909           0 :          if (my_task == master_task .and. monitor_fgmres) then
    2910           0 :             write(nu_diag, '(a,i4,a,d26.16)') "monitor_fgmres: iter_fgmres= ", nbiter, &
    2911           0 :                                               " fgmres_L2norm= ", norm_residual
    2912             :          endif
    2913             : 
    2914             :          ! Current guess is a good enough solution TODO: reactivate and test this
    2915             :          ! if (norm_residual < tolerance) then
    2916             :          !    return
    2917             :          ! end if
    2918             : 
    2919             :          ! Normalize the first Arnoldi vector
    2920           0 :          inverse_norm = c1 / norm_residual
    2921           0 :          !$OMP PARALLEL DO PRIVATE(iblk,ij,i,j)
    2922           0 :          do iblk = 1, nblocks
    2923           0 :             do ij = 1, icellU(iblk)
    2924           0 :                i = indxUi(ij, iblk)
    2925           0 :                j = indxUj(ij, iblk)
    2926             : 
    2927           0 :                arnoldi_basis_x(i, j, iblk, 1) = arnoldi_basis_x(i, j, iblk, 1) * inverse_norm
    2928           0 :                arnoldi_basis_y(i, j, iblk, 1) = arnoldi_basis_y(i, j, iblk, 1) * inverse_norm
    2929             :             enddo ! ij
    2930             :          enddo
    2931             :          !$OMP END PARALLEL DO
    2932             : 
    2933           0 :          if (outiter == 0) then
    2934           0 :             relative_tolerance = tolerance * norm_residual
    2935             :          end if
    2936             : 
    2937             :          ! Initialize 1-st term of RHS of Hessenberg system
    2938           0 :          rhs_hess(1)  = norm_residual
    2939           0 :          rhs_hess(2:) = c0
    2940             : 
    2941           0 :          initer = 0
    2942             : 
    2943             :          ! Start of inner (Arnoldi) loop
    2944           0 :          do
    2945             : 
    2946           0 :             nbiter = nbiter + 1
    2947           0 :             initer = initer + 1
    2948           0 :             nextit = initer + 1
    2949             :             ! precondition the current Arnoldi vector
    2950             :             call precondition(zetax2      , etax2          , &
    2951             :                               Cb          , vrel           , &   ! LCOV_EXCL_LINE
    2952             :                               umassdti    ,                  &   ! LCOV_EXCL_LINE
    2953             :                               halo_info_mask,                &   ! LCOV_EXCL_LINE
    2954             :                               arnoldi_basis_x(:,:,:,initer), &   ! LCOV_EXCL_LINE
    2955             :                               arnoldi_basis_y(:,:,:,initer), &   ! LCOV_EXCL_LINE
    2956             :                               diagx       , diagy          , &   ! LCOV_EXCL_LINE
    2957             :                               precond_type,                  &   ! LCOV_EXCL_LINE
    2958           0 :                               workspace_x , workspace_y)
    2959           0 :             orig_basis_x(:,:,:,initer) = workspace_x
    2960           0 :             orig_basis_y(:,:,:,initer) = workspace_y
    2961             : 
    2962             :             ! Update workspace with boundary values
    2963           0 :             call stack_fields(workspace_x, workspace_y, fld2)
    2964           0 :             call ice_timer_start(timer_bound)
    2965           0 :             if (maskhalo_dyn) then
    2966             :                call ice_HaloUpdate (fld2,               halo_info_mask, &
    2967           0 :                                     field_loc_NEcorner, field_type_vector)
    2968             :             else
    2969             :                call ice_HaloUpdate (fld2,               halo_info, &
    2970           0 :                                     field_loc_NEcorner, field_type_vector)
    2971             :             endif
    2972           0 :             call ice_timer_stop(timer_bound)
    2973           0 :             call unstack_fields(fld2, workspace_x, workspace_y)
    2974             : 
    2975           0 :             !$OMP PARALLEL DO PRIVATE(iblk)
    2976           0 :             do iblk = 1, nblocks
    2977             :                call matvec (nx_block               , ny_block             , &
    2978             :                             icellU         (iblk)  , icellT         (iblk), &   ! LCOV_EXCL_LINE
    2979             :                             indxUi       (:,iblk)  , indxUj       (:,iblk), &   ! LCOV_EXCL_LINE
    2980             :                             indxTi       (:,iblk)  , indxTj       (:,iblk), &   ! LCOV_EXCL_LINE
    2981             :                             dxT        (:,:,iblk)  , dyT        (:,:,iblk), &   ! LCOV_EXCL_LINE
    2982             :                             dxhy       (:,:,iblk)  , dyhx       (:,:,iblk), &   ! LCOV_EXCL_LINE
    2983             :                             cxp        (:,:,iblk)  , cyp        (:,:,iblk), &   ! LCOV_EXCL_LINE
    2984             :                             cxm        (:,:,iblk)  , cym        (:,:,iblk), &   ! LCOV_EXCL_LINE
    2985             :                             workspace_x(:,:,iblk)  , workspace_y(:,:,iblk), &   ! LCOV_EXCL_LINE
    2986             :                             vrel       (:,:,iblk)  , Cb         (:,:,iblk), &   ! LCOV_EXCL_LINE
    2987             :                             zetax2     (:,:,iblk,:), etax2    (:,:,iblk,:), &   ! LCOV_EXCL_LINE
    2988             :                             umassdti   (:,:,iblk)  , fmU        (:,:,iblk), &   ! LCOV_EXCL_LINE
    2989             :                             uarear     (:,:,iblk)  ,                        &   ! LCOV_EXCL_LINE
    2990             :                             arnoldi_basis_x(:,:,iblk,nextit),               &   ! LCOV_EXCL_LINE
    2991           0 :                             arnoldi_basis_y(:,:,iblk,nextit))
    2992             :             enddo
    2993             :             !$OMP END PARALLEL DO
    2994             : 
    2995             :             ! Orthogonalize the new vector
    2996             :             call orthogonalize(ortho_type     , initer         , &
    2997             :                                nextit         , maxinner       , &   ! LCOV_EXCL_LINE
    2998             :                                arnoldi_basis_x, arnoldi_basis_y, &   ! LCOV_EXCL_LINE
    2999           0 :                                hessenberg)
    3000             : 
    3001             :             ! Compute norm of new Arnoldi vector and update Hessenberg matrix
    3002           0 :             hessenberg(nextit,initer) = global_norm(nx_block, ny_block, &
    3003             :                                                     icellU  ,           &   ! LCOV_EXCL_LINE
    3004             :                                                     indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    3005             :                                                     arnoldi_basis_x(:,:,:, nextit), &   ! LCOV_EXCL_LINE
    3006           0 :                                                     arnoldi_basis_y(:,:,:, nextit))
    3007             : 
    3008             :             ! Watch out for happy breakdown
    3009           0 :             if (.not. almost_zero( hessenberg(nextit,initer) ) ) then
    3010             :                ! Normalize next Arnoldi vector
    3011           0 :                inverse_norm = c1 / hessenberg(nextit,initer)
    3012           0 :                !$OMP PARALLEL DO PRIVATE(iblk,ij,i,j)
    3013           0 :                do iblk = 1, nblocks
    3014           0 :                   do ij = 1, icellU(iblk)
    3015           0 :                      i = indxUi(ij, iblk)
    3016           0 :                      j = indxUj(ij, iblk)
    3017             : 
    3018           0 :                      arnoldi_basis_x(i, j, iblk, nextit) = arnoldi_basis_x(i, j, iblk, nextit)*inverse_norm
    3019           0 :                      arnoldi_basis_y(i, j, iblk, nextit) = arnoldi_basis_y(i, j, iblk, nextit)*inverse_norm
    3020             :                   enddo ! ij
    3021             :                enddo
    3022             :                !$OMP END PARALLEL DO
    3023             :             end if
    3024             : 
    3025             :             ! Apply previous Givens rotation to the last column of the Hessenberg matrix
    3026           0 :             if (initer > 1) then
    3027           0 :                do k = 2, initer
    3028           0 :                   t = hessenberg(k-1, initer)
    3029           0 :                   hessenberg(k-1, initer) =  rot_cos(k-1)*t + rot_sin(k-1)*hessenberg(k, initer)
    3030           0 :                   hessenberg(k,   initer) = -rot_sin(k-1)*t + rot_cos(k-1)*hessenberg(k, initer)
    3031             :                end do
    3032             :             end if
    3033             : 
    3034             :             ! Compute and apply new Givens rotation
    3035           0 :             nu = sqrt(hessenberg(initer,initer)**2 + hessenberg(nextit,initer)**2)
    3036           0 :             if (.not. almost_zero(nu)) then
    3037           0 :                rot_cos(initer) = hessenberg(initer,initer) / nu
    3038           0 :                rot_sin(initer) = hessenberg(nextit,initer) / nu
    3039             : 
    3040           0 :                rhs_hess(nextit) = -rot_sin(initer) * rhs_hess(initer)
    3041           0 :                rhs_hess(initer) =  rot_cos(initer) * rhs_hess(initer)
    3042             : 
    3043           0 :                hessenberg(initer,initer) = rot_cos(initer) * hessenberg(initer,initer) + rot_sin(initer) * hessenberg(nextit,initer)
    3044             :             end if
    3045             : 
    3046             :             ! Check for convergence
    3047           0 :             norm_residual = abs(rhs_hess(nextit))
    3048             : 
    3049           0 :             if (my_task == master_task .and. monitor_fgmres) then
    3050           0 :                write(nu_diag, '(a,i4,a,d26.16)') "monitor_fgmres: iter_fgmres= ", nbiter, &
    3051           0 :                                                  " fgmres_L2norm= ", norm_residual
    3052             :             endif
    3053             : 
    3054           0 :              if ((initer >= maxinner) .or. (norm_residual <= relative_tolerance)) then
    3055           0 :                exit
    3056             :             endif
    3057             : 
    3058             :          end do ! end of inner (Arnoldi) loop
    3059             : 
    3060             :          ! At this point either the maximum number of inner iterations
    3061             :          ! was reached or the absolute residual is below the scaled tolerance.
    3062             : 
    3063             :          ! Solve the (now upper triangular) system "hessenberg * sol_hess = rhs_hess"
    3064             :          ! (sol_hess is stored in rhs_hess)
    3065           0 :          rhs_hess(initer) = rhs_hess(initer) / hessenberg(initer,initer)
    3066           0 :          do ii = 2, initer
    3067           0 :             k  = initer - ii + 1
    3068           0 :             t  = rhs_hess(k)
    3069           0 :             do j = k + 1, initer
    3070           0 :                t = t - hessenberg(k,j) * rhs_hess(j)
    3071             :             end do
    3072           0 :             rhs_hess(k) = t / hessenberg(k,k)
    3073             :          end do
    3074             : 
    3075             :          ! Form linear combination to get new solution iterate
    3076           0 :          do it = 1, initer
    3077           0 :             t = rhs_hess(it)
    3078           0 :             !$OMP PARALLEL DO PRIVATE(iblk,ij,i,j)
    3079           0 :             do iblk = 1, nblocks
    3080           0 :                do ij = 1, icellU(iblk)
    3081           0 :                   i = indxUi(ij, iblk)
    3082           0 :                   j = indxUj(ij, iblk)
    3083             : 
    3084           0 :                   solx(i, j, iblk) = solx(i, j, iblk) + t * orig_basis_x(i, j, iblk, it)
    3085           0 :                   soly(i, j, iblk) = soly(i, j, iblk) + t * orig_basis_y(i, j, iblk, it)
    3086             :                enddo ! ij
    3087             :             enddo
    3088             :             !$OMP END PARALLEL DO
    3089             :          end do
    3090             : 
    3091             :          ! Increment outer loop counter and check for convergence
    3092           0 :          outiter = outiter + 1
    3093           0 :          if (norm_residual <= relative_tolerance .or. outiter >= maxouter) then
    3094           0 :             return
    3095             :          end if
    3096             : 
    3097             :          ! Solution is not convergent : compute residual vector and continue.
    3098             : 
    3099             :          ! The residual vector is computed here using (see Saad p. 177) :
    3100             :          ! \begin{equation}
    3101             :          !    r =  V_{m+1} * Q_m^T * (\gamma_{m+1} * e_{m+1})
    3102             :          ! \end{equation}
    3103             :          ! where :
    3104             :          ! $r$ is the residual
    3105             :          ! $V_{m+1}$ is a matrix whose columns are the Arnoldi vectors from 1 to nextit (m+1)
    3106             :          ! $Q_m$ is the product of the Givens rotation : Q_m = G_m G_{m-1} ... G_1
    3107             :          ! $gamma_{m+1}$ is the last element of rhs_hess
    3108             :          ! $e_{m+1})$ is the unit vector (0, 0, ..., 1)^T \in \reals^{m+1}
    3109             : 
    3110             :          ! Apply the Givens rotation in reverse order to g := \gamma_{m+1} * e_{m+1},
    3111             :          ! store the result in rhs_hess
    3112           0 :          do it = 1, initer
    3113           0 :             jj = nextit - it + 1
    3114           0 :             rhs_hess(jj-1) = -rot_sin(jj-1) * rhs_hess(jj) ! + rot_cos(jj-1) * g(jj-1) (== 0)
    3115           0 :             rhs_hess(jj)   =  rot_cos(jj-1) * rhs_hess(jj) ! + rot_sin(jj-1) * g(jj-1) (== 0)
    3116             :          end do
    3117             : 
    3118             :          ! Compute the residual by multiplying V_{m+1} and rhs_hess
    3119           0 :          workspace_x = c0
    3120           0 :          workspace_y = c0
    3121           0 :          do it = 1, nextit
    3122           0 :             !$OMP PARALLEL DO PRIVATE(iblk,ij,i,j)
    3123           0 :             do iblk = 1, nblocks
    3124           0 :                do ij = 1, icellU(iblk)
    3125           0 :                   i = indxUi(ij, iblk)
    3126           0 :                   j = indxUj(ij, iblk)
    3127             : 
    3128           0 :                   workspace_x(i, j, iblk) = workspace_x(i, j, iblk) + rhs_hess(it) * arnoldi_basis_x(i, j, iblk, it)
    3129           0 :                   workspace_y(i, j, iblk) = workspace_y(i, j, iblk) + rhs_hess(it) * arnoldi_basis_y(i, j, iblk, it)
    3130             :                enddo ! ij
    3131             :             enddo
    3132             :             !$OMP END PARALLEL DO
    3133           0 :             arnoldi_basis_x(:,:,:,1) = workspace_x
    3134           0 :             arnoldi_basis_y(:,:,:,1) = workspace_y
    3135             :          end do
    3136             :       end do ! end of outer (restarts) loop
    3137             : 
    3138             :       end subroutine fgmres
    3139             : 
    3140             : !=======================================================================
    3141             : 
    3142             : ! PGMRES: Right-preconditioned generalized minimum residual method (with restarts).
    3143             : ! Solves the linear A x = b using GMRES with a right preconditioner
    3144             : !
    3145             : ! authors: Stéphane Gaudreault, Abdessamad Qaddouri, Philippe Blain, ECCC
    3146             : 
    3147           0 :       subroutine pgmres (zetax2   , etax2   , &
    3148             :                          Cb       , vrel    , &   ! LCOV_EXCL_LINE
    3149             :                          umassdti ,           &   ! LCOV_EXCL_LINE
    3150             :                          halo_info_mask,      &   ! LCOV_EXCL_LINE
    3151             :                          bx       , by      , &   ! LCOV_EXCL_LINE
    3152             :                          diagx    , diagy   , &   ! LCOV_EXCL_LINE
    3153             :                          tolerance, maxinner, &   ! LCOV_EXCL_LINE
    3154             :                          maxouter ,           &   ! LCOV_EXCL_LINE
    3155             :                          solx     , soly    , &   ! LCOV_EXCL_LINE
    3156             :                          nbiter)
    3157             : 
    3158             :       use ice_boundary, only: ice_HaloUpdate
    3159             :       use ice_domain, only: maskhalo_dyn, halo_info
    3160             :       use ice_timers, only: ice_timer_start, ice_timer_stop, timer_bound
    3161             : 
    3162             :       real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks,4), intent(in) :: &
    3163             :          zetax2   , & ! zetax2 = 2*zeta (bulk viscosity)   ! LCOV_EXCL_LINE
    3164             :          etax2        ! etax2  = 2*eta  (shear viscosity)
    3165             : 
    3166             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks), intent(in) :: &
    3167             :          vrel  , & ! coefficient for tauw   ! LCOV_EXCL_LINE
    3168             :          Cb    , & ! seabed stress coefficient   ! LCOV_EXCL_LINE
    3169             :          umassdti  ! mass of U-cell/dte (kg/m^2 s)
    3170             : 
    3171             :       type (ice_halo), intent(in) :: &
    3172             :          halo_info_mask !  ghost cell update info for masked halo
    3173             : 
    3174             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks), intent(in) :: &
    3175             :          bx       , & ! Right hand side of the linear system (x components)   ! LCOV_EXCL_LINE
    3176             :          by           ! Right hand side of the linear system (y components)
    3177             : 
    3178             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks), intent(in) :: &
    3179             :          diagx    , & ! Diagonal of the system matrix (x components)   ! LCOV_EXCL_LINE
    3180             :          diagy        ! Diagonal of the system matrix (y components)
    3181             : 
    3182             :       real (kind=dbl_kind), intent(in) :: &
    3183             :          tolerance   ! Tolerance to achieve. The algorithm terminates when the relative
    3184             :                      ! residual is below tolerance
    3185             : 
    3186             :       integer (kind=int_kind), intent(in) :: &
    3187             :          maxinner, & ! Restart the method every maxinner inner (Arnoldi) iterations   ! LCOV_EXCL_LINE
    3188             :          maxouter    ! Maximum number of outer (restarts) iterations
    3189             :                      ! Iteration will stop after maxinner*maxouter Arnoldi steps
    3190             :                      ! even if the specified tolerance has not been achieved
    3191             : 
    3192             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks), intent(inout) :: &
    3193             :          solx     , & ! Initial guess on input, approximate solution on output (x components)   ! LCOV_EXCL_LINE
    3194             :          soly         ! Initial guess on input, approximate solution on output (y components)
    3195             : 
    3196             :       integer (kind=int_kind), intent(out) :: &
    3197             :          nbiter      ! Total number of Arnoldi iterations performed
    3198             : 
    3199             :       ! local variables
    3200             : 
    3201             :       integer (kind=int_kind) :: &
    3202             :          iblk    , & ! block index   ! LCOV_EXCL_LINE
    3203             :          ij      , & ! index for indx[t|u][i|j]   ! LCOV_EXCL_LINE
    3204             :          i, j        ! grid indices
    3205             : 
    3206             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks) :: &
    3207             :          workspace_x , & ! work vector (x components)   ! LCOV_EXCL_LINE
    3208           0 :          workspace_y     ! work vector (y components)
    3209             : 
    3210             :       real (kind=dbl_kind), dimension (max_blocks) :: &
    3211           0 :          norm_squared   ! array to accumulate squared norm of grid function over blocks
    3212             : 
    3213             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks, maxinner+1) :: &
    3214             :          arnoldi_basis_x , & ! Arnoldi basis (x components)   ! LCOV_EXCL_LINE
    3215           0 :          arnoldi_basis_y     ! Arnoldi basis (y components)
    3216             : 
    3217             :       real (kind=dbl_kind) :: &
    3218             :          norm_residual   , & ! current L^2 norm of residual vector   ! LCOV_EXCL_LINE
    3219             :          inverse_norm    , & ! inverse of the norm of a vector   ! LCOV_EXCL_LINE
    3220           0 :          nu, t               ! local temporary values
    3221             : 
    3222             :       integer (kind=int_kind) :: &
    3223             :          initer          , & ! inner (Arnoldi) loop counter   ! LCOV_EXCL_LINE
    3224             :          outiter         , & ! outer (restarts) loop counter   ! LCOV_EXCL_LINE
    3225             :          nextit          , & ! nextit == initer+1   ! LCOV_EXCL_LINE
    3226             :          it, k, ii, jj       ! reusable loop counters
    3227             : 
    3228             :       real (kind=dbl_kind), dimension(maxinner+1) :: &
    3229             :          rot_cos         , & ! cosine elements of Givens rotations   ! LCOV_EXCL_LINE
    3230             :          rot_sin         , & ! sine elements of Givens rotations   ! LCOV_EXCL_LINE
    3231           0 :          rhs_hess            ! right hand side vector of the Hessenberg (least squares) system
    3232             : 
    3233             :       real (kind=dbl_kind), dimension(maxinner+1, maxinner) :: &
    3234           0 :          hessenberg          ! system matrix of the Hessenberg (least squares) system
    3235             : 
    3236             :       character(len=char_len) :: &
    3237             :          precond_type    , & ! type of preconditioner   ! LCOV_EXCL_LINE
    3238             :          ortho_type          ! type of orthogonalization
    3239             : 
    3240             :       real (kind=dbl_kind) :: &
    3241           0 :          relative_tolerance  ! relative_tolerance, i.e. tolerance*norm(initial residual)
    3242             : 
    3243             :       character(len=*), parameter :: subname = '(pgmres)'
    3244             : 
    3245             :       ! Here we go !
    3246             : 
    3247             :       ! Initialize
    3248           0 :       outiter = 0
    3249           0 :       nbiter = 0
    3250             : 
    3251           0 :       norm_squared = c0
    3252           0 :       precond_type = 'diag' ! Jacobi preconditioner
    3253           0 :       ortho_type = 'cgs' ! classical gram-schmidt TODO: try with MGS
    3254             : 
    3255             :       ! Cells with no ice should be zero-initialized
    3256           0 :       workspace_x = c0
    3257           0 :       workspace_y = c0
    3258           0 :       arnoldi_basis_x = c0
    3259           0 :       arnoldi_basis_y = c0
    3260             : 
    3261             :       ! Residual of the initial iterate
    3262             : 
    3263           0 :       !$OMP PARALLEL DO PRIVATE(iblk)
    3264           0 :       do iblk = 1, nblocks
    3265             :          call matvec (nx_block               , ny_block             , &
    3266             :                       icellU         (iblk)  , icellT         (iblk), &   ! LCOV_EXCL_LINE
    3267             :                       indxUi       (:,iblk)  , indxUj       (:,iblk), &   ! LCOV_EXCL_LINE
    3268             :                       indxTi       (:,iblk)  , indxTj       (:,iblk), &   ! LCOV_EXCL_LINE
    3269             :                       dxT        (:,:,iblk)  , dyT        (:,:,iblk), &   ! LCOV_EXCL_LINE
    3270             :                       dxhy       (:,:,iblk)  , dyhx       (:,:,iblk), &   ! LCOV_EXCL_LINE
    3271             :                       cxp        (:,:,iblk)  , cyp        (:,:,iblk), &   ! LCOV_EXCL_LINE
    3272             :                       cxm        (:,:,iblk)  , cym        (:,:,iblk), &   ! LCOV_EXCL_LINE
    3273             :                       solx       (:,:,iblk)  , soly       (:,:,iblk), &   ! LCOV_EXCL_LINE
    3274             :                       vrel       (:,:,iblk)  , Cb         (:,:,iblk), &   ! LCOV_EXCL_LINE
    3275             :                       zetax2     (:,:,iblk,:), etax2    (:,:,iblk,:), &   ! LCOV_EXCL_LINE
    3276             :                       umassdti   (:,:,iblk)  , fmU        (:,:,iblk), &   ! LCOV_EXCL_LINE
    3277             :                       uarear     (:,:,iblk)  ,                        &   ! LCOV_EXCL_LINE
    3278           0 :                       workspace_x(:,:,iblk)  , workspace_y(:,:,iblk))
    3279             :          call residual_vec (nx_block             , ny_block             , &
    3280             :                             icellU         (iblk),                        &   ! LCOV_EXCL_LINE
    3281             :                             indxUi       (:,iblk), indxUj       (:,iblk), &   ! LCOV_EXCL_LINE
    3282             :                             bx         (:,:,iblk), by         (:,:,iblk), &   ! LCOV_EXCL_LINE
    3283             :                             workspace_x(:,:,iblk), workspace_y(:,:,iblk), &   ! LCOV_EXCL_LINE
    3284             :                             arnoldi_basis_x (:,:,iblk, 1),                &   ! LCOV_EXCL_LINE
    3285           0 :                             arnoldi_basis_y (:,:,iblk, 1))
    3286             :       enddo
    3287             :       !$OMP END PARALLEL DO
    3288             : 
    3289             :       ! Start outer (restarts) loop
    3290           0 :       do
    3291             :          ! Compute norm of initial residual
    3292             :          norm_residual = global_norm(nx_block, ny_block, &
    3293             :                                      icellU  ,           &   ! LCOV_EXCL_LINE
    3294             :                                      indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    3295             :                                      arnoldi_basis_x(:,:,:, 1), &   ! LCOV_EXCL_LINE
    3296           0 :                                      arnoldi_basis_y(:,:,:, 1))
    3297             : 
    3298           0 :          if (my_task == master_task .and. monitor_pgmres) then
    3299           0 :             write(nu_diag, '(a,i4,a,d26.16)') "monitor_pgmres: iter_pgmres= ", nbiter, &
    3300           0 :                                               " pgmres_L2norm= ", norm_residual
    3301             :          endif
    3302             : 
    3303             :          ! Current guess is a good enough solution
    3304             :          ! if (norm_residual < tolerance) then
    3305             :          !    return
    3306             :          ! end if
    3307             : 
    3308             :          ! Normalize the first Arnoldi vector
    3309           0 :          inverse_norm = c1 / norm_residual
    3310           0 :          !$OMP PARALLEL DO PRIVATE(iblk,ij,i,j)
    3311           0 :          do iblk = 1, nblocks
    3312           0 :             do ij = 1, icellU(iblk)
    3313           0 :                i = indxUi(ij, iblk)
    3314           0 :                j = indxUj(ij, iblk)
    3315             : 
    3316           0 :                arnoldi_basis_x(i, j, iblk, 1) = arnoldi_basis_x(i, j, iblk, 1) * inverse_norm
    3317           0 :                arnoldi_basis_y(i, j, iblk, 1) = arnoldi_basis_y(i, j, iblk, 1) * inverse_norm
    3318             :             enddo ! ij
    3319             :          enddo
    3320             :          !$OMP END PARALLEL DO
    3321             : 
    3322           0 :          if (outiter == 0) then
    3323           0 :             relative_tolerance = tolerance * norm_residual
    3324             :          end if
    3325             : 
    3326             :          ! Initialize 1-st term of RHS of Hessenberg system
    3327           0 :          rhs_hess(1)  = norm_residual
    3328           0 :          rhs_hess(2:) = c0
    3329             : 
    3330           0 :          initer = 0
    3331             : 
    3332             :          ! Start of inner (Arnoldi) loop
    3333           0 :          do
    3334             : 
    3335           0 :             nbiter = nbiter + 1
    3336           0 :             initer = initer + 1
    3337           0 :             nextit = initer + 1
    3338             : 
    3339             :             ! precondition the current Arnoldi vector
    3340             :             call precondition(zetax2      , etax2          , &
    3341             :                               Cb          , vrel           , &   ! LCOV_EXCL_LINE
    3342             :                               umassdti    ,                  &   ! LCOV_EXCL_LINE
    3343             :                               halo_info_mask,                &   ! LCOV_EXCL_LINE
    3344             :                               arnoldi_basis_x(:,:,:,initer), &   ! LCOV_EXCL_LINE
    3345             :                               arnoldi_basis_y(:,:,:,initer), &   ! LCOV_EXCL_LINE
    3346             :                               diagx       , diagy          , &   ! LCOV_EXCL_LINE
    3347             :                               precond_type,                  &   ! LCOV_EXCL_LINE
    3348           0 :                               workspace_x , workspace_y)
    3349             : 
    3350             :             ! Update workspace with boundary values
    3351           0 :             call stack_fields(workspace_x, workspace_y, fld2)
    3352           0 :             call ice_timer_start(timer_bound)
    3353           0 :             if (maskhalo_dyn) then
    3354             :                call ice_HaloUpdate (fld2,               halo_info_mask, &
    3355           0 :                                     field_loc_NEcorner, field_type_vector)
    3356             :             else
    3357             :                call ice_HaloUpdate (fld2,               halo_info, &
    3358           0 :                                     field_loc_NEcorner, field_type_vector)
    3359             :             endif
    3360           0 :             call ice_timer_stop(timer_bound)
    3361           0 :             call unstack_fields(fld2, workspace_x, workspace_y)
    3362             : 
    3363           0 :             !$OMP PARALLEL DO PRIVATE(iblk)
    3364           0 :             do iblk = 1, nblocks
    3365             :                call matvec (nx_block               , ny_block             , &
    3366             :                             icellU         (iblk)  , icellT         (iblk), &   ! LCOV_EXCL_LINE
    3367             :                             indxUi       (:,iblk)  , indxUj       (:,iblk), &   ! LCOV_EXCL_LINE
    3368             :                             indxTi       (:,iblk)  , indxTj       (:,iblk), &   ! LCOV_EXCL_LINE
    3369             :                             dxT        (:,:,iblk)  , dyT        (:,:,iblk), &   ! LCOV_EXCL_LINE
    3370             :                             dxhy       (:,:,iblk)  , dyhx       (:,:,iblk), &   ! LCOV_EXCL_LINE
    3371             :                             cxp        (:,:,iblk)  , cyp        (:,:,iblk), &   ! LCOV_EXCL_LINE
    3372             :                             cxm        (:,:,iblk)  , cym        (:,:,iblk), &   ! LCOV_EXCL_LINE
    3373             :                             workspace_x(:,:,iblk)  , workspace_y(:,:,iblk), &   ! LCOV_EXCL_LINE
    3374             :                             vrel       (:,:,iblk)  , Cb         (:,:,iblk), &   ! LCOV_EXCL_LINE
    3375             :                             zetax2     (:,:,iblk,:), etax2    (:,:,iblk,:), &   ! LCOV_EXCL_LINE
    3376             :                             umassdti   (:,:,iblk)  , fmU        (:,:,iblk), &   ! LCOV_EXCL_LINE
    3377             :                             uarear     (:,:,iblk)  ,                        &   ! LCOV_EXCL_LINE
    3378             :                             arnoldi_basis_x(:,:,iblk,nextit),               &   ! LCOV_EXCL_LINE
    3379           0 :                             arnoldi_basis_y(:,:,iblk,nextit))
    3380             :             enddo
    3381             :             !$OMP END PARALLEL DO
    3382             : 
    3383             :             ! Orthogonalize the new vector
    3384             :             call orthogonalize(ortho_type     , initer         , &
    3385             :                                nextit         , maxinner       , &   ! LCOV_EXCL_LINE
    3386             :                                arnoldi_basis_x, arnoldi_basis_y, &   ! LCOV_EXCL_LINE
    3387           0 :                                hessenberg)
    3388             : 
    3389             :             ! Compute norm of new Arnoldi vector and update Hessenberg matrix
    3390           0 :             hessenberg(nextit,initer) = global_norm(nx_block, ny_block, &
    3391             :                                                     icellU  ,           &   ! LCOV_EXCL_LINE
    3392             :                                                     indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    3393             :                                                     arnoldi_basis_x(:,:,:, nextit), &   ! LCOV_EXCL_LINE
    3394           0 :                                                     arnoldi_basis_y(:,:,:, nextit))
    3395             : 
    3396             :             ! Watch out for happy breakdown
    3397           0 :             if (.not. almost_zero( hessenberg(nextit,initer) ) ) then
    3398             :                ! Normalize next Arnoldi vector
    3399           0 :                inverse_norm = c1 / hessenberg(nextit,initer)
    3400           0 :                !$OMP PARALLEL DO PRIVATE(iblk,ij,i,j)
    3401           0 :                do iblk = 1, nblocks
    3402           0 :                   do ij = 1, icellU(iblk)
    3403           0 :                      i = indxUi(ij, iblk)
    3404           0 :                      j = indxUj(ij, iblk)
    3405             : 
    3406           0 :                      arnoldi_basis_x(i, j, iblk, nextit) = arnoldi_basis_x(i, j, iblk, nextit)*inverse_norm
    3407           0 :                      arnoldi_basis_y(i, j, iblk, nextit) = arnoldi_basis_y(i, j, iblk, nextit)*inverse_norm
    3408             :                   enddo ! ij
    3409             :                enddo
    3410             :                !$OMP END PARALLEL DO
    3411             :             end if
    3412             : 
    3413             :             ! Apply previous Givens rotation to the last column of the Hessenberg matrix
    3414           0 :             if (initer > 1) then
    3415           0 :                do k = 2, initer
    3416           0 :                   t = hessenberg(k-1, initer)
    3417           0 :                   hessenberg(k-1, initer) =  rot_cos(k-1)*t + rot_sin(k-1)*hessenberg(k, initer)
    3418           0 :                   hessenberg(k,   initer) = -rot_sin(k-1)*t + rot_cos(k-1)*hessenberg(k, initer)
    3419             :                end do
    3420             :             end if
    3421             : 
    3422             :             ! Compute and apply new Givens rotation
    3423           0 :             nu = sqrt(hessenberg(initer,initer)**2 + hessenberg(nextit,initer)**2)
    3424           0 :             if (.not. almost_zero(nu)) then
    3425           0 :                rot_cos(initer) = hessenberg(initer,initer) / nu
    3426           0 :                rot_sin(initer) = hessenberg(nextit,initer) / nu
    3427             : 
    3428           0 :                rhs_hess(nextit) = -rot_sin(initer) * rhs_hess(initer)
    3429           0 :                rhs_hess(initer) =  rot_cos(initer) * rhs_hess(initer)
    3430             : 
    3431           0 :                hessenberg(initer,initer) = rot_cos(initer) * hessenberg(initer,initer) + rot_sin(initer) * hessenberg(nextit,initer)
    3432             :             end if
    3433             : 
    3434             :             ! Check for convergence
    3435           0 :             norm_residual = abs(rhs_hess(nextit))
    3436             : 
    3437           0 :             if (my_task == master_task .and. monitor_pgmres) then
    3438           0 :                write(nu_diag, '(a,i4,a,d26.16)') "monitor_pgmres: iter_pgmres= ", nbiter, &
    3439           0 :                                                  " pgmres_L2norm= ", norm_residual
    3440             :             endif
    3441             : 
    3442           0 :              if ((initer >= maxinner) .or. (norm_residual <= relative_tolerance)) then
    3443           0 :                exit
    3444             :             endif
    3445             : 
    3446             :          end do ! end of inner (Arnoldi) loop
    3447             : 
    3448             :          ! At this point either the maximum number of inner iterations
    3449             :          ! was reached or the absolute residual is below the scaled tolerance.
    3450             : 
    3451             :          ! Solve the (now upper triangular) system "hessenberg * sol_hess = rhs_hess"
    3452             :          ! (sol_hess is stored in rhs_hess)
    3453           0 :          rhs_hess(initer) = rhs_hess(initer) / hessenberg(initer,initer)
    3454           0 :          do ii = 2, initer
    3455           0 :             k  = initer - ii + 1
    3456           0 :             t  = rhs_hess(k)
    3457           0 :             do j = k + 1, initer
    3458           0 :                t = t - hessenberg(k,j) * rhs_hess(j)
    3459             :             end do
    3460           0 :             rhs_hess(k) = t / hessenberg(k,k)
    3461             :          end do
    3462             : 
    3463             :          ! Form linear combination to get new solution iterate
    3464           0 :          workspace_x = c0
    3465           0 :          workspace_y = c0
    3466           0 :          do it = 1, initer
    3467           0 :             t = rhs_hess(it)
    3468           0 :             !$OMP PARALLEL DO PRIVATE(iblk,ij,i,j)
    3469           0 :             do iblk = 1, nblocks
    3470           0 :                do ij = 1, icellU(iblk)
    3471           0 :                   i = indxUi(ij, iblk)
    3472           0 :                   j = indxUj(ij, iblk)
    3473             : 
    3474           0 :                   workspace_x(i, j, iblk) = workspace_x(i, j, iblk) + t * arnoldi_basis_x(i, j, iblk, it)
    3475           0 :                   workspace_y(i, j, iblk) = workspace_y(i, j, iblk) + t * arnoldi_basis_y(i, j, iblk, it)
    3476             :                enddo ! ij
    3477             :             enddo
    3478             :             !$OMP END PARALLEL DO
    3479             :          end do
    3480             : 
    3481             :          ! Call preconditioner
    3482             :          call precondition(zetax2      , etax2      , &
    3483             :                            Cb          , vrel       , &   ! LCOV_EXCL_LINE
    3484             :                            umassdti    ,              &   ! LCOV_EXCL_LINE
    3485             :                            halo_info_mask,            &   ! LCOV_EXCL_LINE
    3486             :                            workspace_x , workspace_y, &   ! LCOV_EXCL_LINE
    3487             :                            diagx       , diagy      , &   ! LCOV_EXCL_LINE
    3488             :                            precond_type,              &   ! LCOV_EXCL_LINE
    3489           0 :                            workspace_x , workspace_y)
    3490             : 
    3491           0 :          solx = solx + workspace_x
    3492           0 :          soly = soly + workspace_y
    3493             : 
    3494             :          ! Increment outer loop counter and check for convergence
    3495           0 :          outiter = outiter + 1
    3496           0 :          if (norm_residual <= relative_tolerance .or. outiter >= maxouter) then
    3497           0 :             return
    3498             :          end if
    3499             : 
    3500             :          ! Solution is not convergent : compute residual vector and continue.
    3501             : 
    3502             :          ! The residual vector is computed here using (see Saad p. 177) :
    3503             :          ! \begin{equation}
    3504             :          !    r =  V_{m+1} * Q_m^T * (\gamma_{m+1} * e_{m+1})
    3505             :          ! \end{equation}
    3506             :          ! where :
    3507             :          ! $r$ is the residual
    3508             :          ! $V_{m+1}$ is a matrix whose columns are the Arnoldi vectors from 1 to nextit (m+1)
    3509             :          ! $Q_m$ is the product of the Givens rotation : Q_m = G_m G_{m-1} ... G_1
    3510             :          ! $gamma_{m+1}$ is the last element of rhs_hess
    3511             :          ! $e_{m+1})$ is the unit vector (0, 0, ..., 1)^T \in \reals^{m+1}
    3512             : 
    3513             :          ! Apply the Givens rotation in reverse order to g := \gamma_{m+1} * e_{m+1},
    3514             :          ! store the result in rhs_hess
    3515           0 :          do it = 1, initer
    3516           0 :             jj = nextit - it + 1
    3517           0 :             rhs_hess(jj-1) = -rot_sin(jj-1) * rhs_hess(jj) ! + rot_cos(jj-1) * g(jj-1) (== 0)
    3518           0 :             rhs_hess(jj)   =  rot_cos(jj-1) * rhs_hess(jj) ! + rot_sin(jj-1) * g(jj-1) (== 0)
    3519             :          end do
    3520             : 
    3521             :          ! Compute the residual by multiplying V_{m+1} and rhs_hess
    3522           0 :          workspace_x = c0
    3523           0 :          workspace_y = c0
    3524           0 :          do it = 1, nextit
    3525           0 :             !$OMP PARALLEL DO PRIVATE(iblk,ij,i,j)
    3526           0 :             do iblk = 1, nblocks
    3527           0 :                do ij = 1, icellU(iblk)
    3528           0 :                   i = indxUi(ij, iblk)
    3529           0 :                   j = indxUj(ij, iblk)
    3530             : 
    3531           0 :                   workspace_x(i, j, iblk) = workspace_x(i, j, iblk) + rhs_hess(it) * arnoldi_basis_x(i, j, iblk, it)
    3532           0 :                   workspace_y(i, j, iblk) = workspace_y(i, j, iblk) + rhs_hess(it) * arnoldi_basis_y(i, j, iblk, it)
    3533             :                enddo ! ij
    3534             :             enddo
    3535             :             !$OMP END PARALLEL DO
    3536           0 :             arnoldi_basis_x(:,:,:,1) = workspace_x
    3537           0 :             arnoldi_basis_y(:,:,:,1) = workspace_y
    3538             :          end do
    3539             :       end do ! end of outer (restarts) loop
    3540             : 
    3541             :       end subroutine pgmres
    3542             : 
    3543             : !=======================================================================
    3544             : 
    3545             : ! Generic routine to precondition a vector
    3546             : !
    3547             : ! authors: Philippe Blain, ECCC
    3548             : 
    3549           0 :       subroutine precondition(zetax2      , etax2, &
    3550             :                               Cb          , vrel , &   ! LCOV_EXCL_LINE
    3551             :                               umassdti    ,        &   ! LCOV_EXCL_LINE
    3552             :                               halo_info_mask,      &   ! LCOV_EXCL_LINE
    3553             :                               vx          , vy   , &   ! LCOV_EXCL_LINE
    3554             :                               diagx       , diagy, &   ! LCOV_EXCL_LINE
    3555             :                               precond_type,        &   ! LCOV_EXCL_LINE
    3556           0 :                               wx          , wy)
    3557             : 
    3558             :       real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks,4), intent(in) :: &
    3559             :          zetax2   , & ! zetax2 = 2*zeta (bulk viscosity)   ! LCOV_EXCL_LINE
    3560             :          etax2        ! etax2  = 2*eta  (shear viscosity)
    3561             : 
    3562             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks), intent(in) :: &
    3563             :          vrel  , & ! coefficient for tauw   ! LCOV_EXCL_LINE
    3564             :          Cb    , & ! seabed stress coefficient   ! LCOV_EXCL_LINE
    3565             :          umassdti  ! mass of U-cell/dte (kg/m^2 s)
    3566             : 
    3567             :       type (ice_halo), intent(in) :: &
    3568             :          halo_info_mask !  ghost cell update info for masked halo
    3569             : 
    3570             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks), intent(in) :: &
    3571             :          vx       , & ! input vector (x components)   ! LCOV_EXCL_LINE
    3572             :          vy           ! input vector (y components)
    3573             : 
    3574             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks), intent(in) :: &
    3575             :          diagx    , & ! diagonal of the system matrix (x components)   ! LCOV_EXCL_LINE
    3576             :          diagy        ! diagonal of the system matrix (y components)
    3577             : 
    3578             :       character (len=char_len), intent(in) :: &
    3579             :          precond_type ! type of preconditioner
    3580             : 
    3581             :       real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks), intent(inout) :: &
    3582             :          wx       , & ! preconditionned vector (x components)   ! LCOV_EXCL_LINE
    3583             :          wy           ! preconditionned vector (y components)
    3584             : 
    3585             :       ! local variables
    3586             : 
    3587             :       integer (kind=int_kind) :: &
    3588             :          iblk    , & ! block index   ! LCOV_EXCL_LINE
    3589             :          ij      , & ! compressed index   ! LCOV_EXCL_LINE
    3590             :          i, j        ! grid indices
    3591             : 
    3592             :       real (kind=dbl_kind) :: &
    3593           0 :          tolerance   ! Tolerance for PGMRES
    3594             : 
    3595             :       integer (kind=int_kind) :: &
    3596             :          maxinner    ! Restart parameter for PGMRES
    3597             : 
    3598             :       integer (kind=int_kind) :: &
    3599             :          maxouter    ! Maximum number of outer iterations for PGMRES
    3600             : 
    3601             :       integer (kind=int_kind) :: &
    3602             :          nbiter      ! Total number of iteration PGMRES performed
    3603             : 
    3604             :       character(len=*), parameter :: subname = '(precondition)'
    3605             : 
    3606           0 :       if     (precond_type == 'ident') then ! identity (no preconditioner)
    3607           0 :          wx = vx
    3608           0 :          wy = vy
    3609           0 :       elseif (precond_type == 'diag') then ! Jacobi preconditioner (diagonal)
    3610           0 :          !$OMP PARALLEL DO PRIVATE(iblk,ij,i,j)
    3611           0 :          do iblk = 1, nblocks
    3612           0 :             do ij = 1, icellU(iblk)
    3613           0 :                i = indxUi(ij, iblk)
    3614           0 :                j = indxUj(ij, iblk)
    3615             : 
    3616           0 :                wx(i,j,iblk) = vx(i,j,iblk) / diagx(i,j,iblk)
    3617           0 :                wy(i,j,iblk) = vy(i,j,iblk) / diagy(i,j,iblk)
    3618             :             enddo ! ij
    3619             :          enddo
    3620             :          !$OMP END PARALLEL DO
    3621           0 :       elseif (precond_type == 'pgmres') then ! PGMRES (Jacobi-preconditioned GMRES)
    3622             :          ! Initialize preconditioned vector to 0 ! TODO: try with wx = vx or vx/diagx
    3623           0 :          wx = c0
    3624           0 :          wy = c0
    3625           0 :          tolerance = reltol_pgmres
    3626           0 :          maxinner = dim_pgmres
    3627           0 :          maxouter = maxits_pgmres
    3628             :          call pgmres (zetax2,    etax2   , &
    3629             :                       Cb       , vrel    , &   ! LCOV_EXCL_LINE
    3630             :                       umassdti ,           &   ! LCOV_EXCL_LINE
    3631             :                       halo_info_mask     , &   ! LCOV_EXCL_LINE
    3632             :                       vx       , vy      , &   ! LCOV_EXCL_LINE
    3633             :                       diagx    , diagy   , &   ! LCOV_EXCL_LINE
    3634             :                       tolerance, maxinner, &   ! LCOV_EXCL_LINE
    3635             :                       maxouter ,           &   ! LCOV_EXCL_LINE
    3636             :                       wx       , wy      , &   ! LCOV_EXCL_LINE
    3637           0 :                       nbiter)
    3638             :       else
    3639             :          call abort_ice(error_message='wrong preconditioner in ' // subname, &
    3640           0 :             file=__FILE__, line=__LINE__)
    3641             :       endif
    3642           0 :       end subroutine precondition
    3643             : 
    3644             : !=======================================================================
    3645             : 
    3646             : ! Generic routine to orthogonalize a vector (arnoldi_basis_[xy](:, :, :, nextit))
    3647             : ! against a set of vectors (arnoldi_basis_[xy](:, :, :, 1:initer))
    3648             : !
    3649             : ! authors: Philippe Blain, ECCC
    3650             : 
    3651           0 :       subroutine orthogonalize(ortho_type     , initer         , &
    3652             :                                nextit         , maxinner       , &   ! LCOV_EXCL_LINE
    3653             :                                arnoldi_basis_x, arnoldi_basis_y, &   ! LCOV_EXCL_LINE
    3654           0 :                                hessenberg)
    3655             : 
    3656             :       character(len=*), intent(in) :: &
    3657             :          ortho_type ! type of orthogonalization
    3658             : 
    3659             :       integer (kind=int_kind), intent(in) :: &
    3660             :          initer  , & ! inner (Arnoldi) loop counter   ! LCOV_EXCL_LINE
    3661             :          nextit  , & ! nextit == initer+1   ! LCOV_EXCL_LINE
    3662             :          maxinner    ! Restart the method every maxinner inner iterations
    3663             : 
    3664             :       real (kind=dbl_kind), dimension(nx_block, ny_block, max_blocks, maxinner+1), intent(inout) :: &
    3665             :          arnoldi_basis_x , & ! arnoldi basis (x components)   ! LCOV_EXCL_LINE
    3666             :          arnoldi_basis_y     ! arnoldi basis (y components)
    3667             : 
    3668             :       real (kind=dbl_kind), dimension(maxinner+1, maxinner), intent(inout) :: &
    3669             :          hessenberg        ! system matrix of the Hessenberg (least squares) system
    3670             : 
    3671             :       ! local variables
    3672             : 
    3673             :       integer (kind=int_kind) :: &
    3674             :          it      , & ! reusable loop counter   ! LCOV_EXCL_LINE
    3675             :          iblk    , & ! block index   ! LCOV_EXCL_LINE
    3676             :          ij      , & ! compressed index   ! LCOV_EXCL_LINE
    3677             :          i, j        ! grid indices
    3678             : 
    3679             :       character(len=*), parameter :: subname = '(orthogonalize)'
    3680             : 
    3681           0 :       if (trim(ortho_type) == 'cgs') then ! Classical Gram-Schmidt
    3682             :          ! Classical Gram-Schmidt orthogonalisation process
    3683             :          ! First loop of Gram-Schmidt (compute coefficients)
    3684           0 :          do it = 1, initer
    3685           0 :             hessenberg(it, initer) = global_dot_product(nx_block, ny_block, &
    3686             :                                                         icellU  ,           &   ! LCOV_EXCL_LINE
    3687             :                                                         indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    3688             :                                                         arnoldi_basis_x(:,:,:, it)    , &   ! LCOV_EXCL_LINE
    3689             :                                                         arnoldi_basis_y(:,:,:, it)    , &   ! LCOV_EXCL_LINE
    3690             :                                                         arnoldi_basis_x(:,:,:, nextit), &   ! LCOV_EXCL_LINE
    3691           0 :                                                         arnoldi_basis_y(:,:,:, nextit))
    3692             :          end do
    3693             :          ! Second loop of Gram-Schmidt (orthonormalize)
    3694           0 :          do it = 1, initer
    3695           0 :             !$OMP PARALLEL DO PRIVATE(iblk,ij,i,j)
    3696           0 :             do iblk = 1, nblocks
    3697           0 :                do ij = 1, icellU(iblk)
    3698           0 :                   i = indxUi(ij, iblk)
    3699           0 :                   j = indxUj(ij, iblk)
    3700             : 
    3701             :                   arnoldi_basis_x(i, j, iblk, nextit) = arnoldi_basis_x(i, j, iblk, nextit) &
    3702           0 :                                                         - hessenberg(it,initer) * arnoldi_basis_x(i, j, iblk, it)
    3703             :                   arnoldi_basis_y(i, j, iblk, nextit) = arnoldi_basis_y(i, j, iblk, nextit) &
    3704           0 :                                                         - hessenberg(it,initer) * arnoldi_basis_y(i, j, iblk, it)
    3705             :                enddo ! ij
    3706             :             enddo
    3707             :             !$OMP END PARALLEL DO
    3708             :          end do
    3709           0 :       elseif (trim(ortho_type) == 'mgs') then ! Modified Gram-Schmidt
    3710             :          ! Modified Gram-Schmidt orthogonalisation process
    3711           0 :          do it = 1, initer
    3712           0 :             hessenberg(it, initer) = global_dot_product(nx_block, ny_block, &
    3713             :                                                         icellU  ,           &   ! LCOV_EXCL_LINE
    3714             :                                                         indxUi  , indxUj  , &   ! LCOV_EXCL_LINE
    3715             :                                                         arnoldi_basis_x(:,:,:, it)    , &   ! LCOV_EXCL_LINE
    3716             :                                                         arnoldi_basis_y(:,:,:, it)    , &   ! LCOV_EXCL_LINE
    3717             :                                                         arnoldi_basis_x(:,:,:, nextit), &   ! LCOV_EXCL_LINE
    3718           0 :                                                         arnoldi_basis_y(:,:,:, nextit))
    3719             : 
    3720           0 :             !$OMP PARALLEL DO PRIVATE(iblk,ij,i,j)
    3721           0 :             do iblk = 1, nblocks
    3722           0 :                do ij = 1, icellU(iblk)
    3723           0 :                   i = indxUi(ij, iblk)
    3724           0 :                   j = indxUj(ij, iblk)
    3725             : 
    3726             :                   arnoldi_basis_x(i, j, iblk, nextit) = arnoldi_basis_x(i, j, iblk, nextit) &
    3727           0 :                                                         - hessenberg(it,initer) * arnoldi_basis_x(i, j, iblk, it)
    3728             :                   arnoldi_basis_y(i, j, iblk, nextit) = arnoldi_basis_y(i, j, iblk, nextit) &
    3729           0 :                                                         - hessenberg(it,initer) * arnoldi_basis_y(i, j, iblk, it)
    3730             :                enddo ! ij
    3731             :             enddo
    3732             :             !$OMP END PARALLEL DO
    3733             :          end do
    3734             :       else
    3735             :          call abort_ice(error_message='wrong orthonalization in ' // subname, &
    3736           0 :          file=__FILE__, line=__LINE__)
    3737             :       endif
    3738             : 
    3739           0 :    end subroutine orthogonalize
    3740             : 
    3741             : !=======================================================================
    3742             : 
    3743             : ! Check if value A is close to zero, up to machine precision
    3744             : !
    3745             : !author
    3746             : !     Stéphane Gaudreault, ECCC -- June 2014
    3747             : !
    3748             : !revision
    3749             : !     v4-80 - Gaudreault S.         - gfortran compatibility
    3750             : !     2019  - Philippe Blain, ECCC  - converted to CICE standards
    3751             : 
    3752           0 :       logical function almost_zero(A) result(retval)
    3753             : 
    3754             :       real (kind=dbl_kind), intent(in) :: A
    3755             : 
    3756             :       ! local variables
    3757             : 
    3758             :       character(len=*), parameter :: subname = '(almost_zero)'
    3759             : 
    3760             :       integer (kind=int8_kind) :: aBit
    3761             :       integer (kind=int8_kind), parameter :: two_complement = int(Z'80000000', kind=int8_kind)
    3762           0 :       aBit = 0
    3763           0 :       aBit = transfer(A, aBit)
    3764           0 :       if (aBit < 0) then
    3765           0 :          aBit = two_complement - aBit
    3766             :       end if
    3767             :       ! lexicographic order test with a tolerance of 1 adjacent float
    3768           0 :       retval = (abs(aBit) <= 1)
    3769             : 
    3770           0 :       end function almost_zero
    3771             : 
    3772             : !=======================================================================
    3773             : 
    3774             :       end module ice_dyn_vp
    3775             : 
    3776             : !=======================================================================

Generated by: LCOV version 1.14-6-g40580cd