Index: utils/tools/DOMAINcfg/src/mpp_lnk_generic.h90
===================================================================
--- utils/tools/DOMAINcfg/src/mpp_lnk_generic.h90	(revision 13204)
+++ utils/tools/DOMAINcfg/src/mpp_lnk_generic.h90	(revision 14623)
@@ -5,5 +5,9 @@
 #   define OPT_K(k)                 ,ipf
 #   if defined DIM_2d
-#      define ARRAY_TYPE(i,j,k,l,f)    TYPE(PTR_2D)                , INTENT(inout) ::   ptab(f)
+#      if defined SINGLE_PRECISION
+#         define ARRAY_TYPE(i,j,k,l,f)    TYPE(PTR_2D_sp)                , INTENT(inout) ::   ptab(f)
+#      else
+#         define ARRAY_TYPE(i,j,k,l,f)    TYPE(PTR_2D_dp)                , INTENT(inout) ::   ptab(f)
+#      endif
 #      define ARRAY_IN(i,j,k,l,f)      ptab(f)%pt2d(i,j)
 #      define K_SIZE(ptab)             1
@@ -11,5 +15,9 @@
 #   endif
 #   if defined DIM_3d
-#      define ARRAY_TYPE(i,j,k,l,f)    TYPE(PTR_3D)                , INTENT(inout) ::   ptab(f)
+#      if defined SINGLE_PRECISION
+#         define ARRAY_TYPE(i,j,k,l,f)    TYPE(PTR_3D_sp)                , INTENT(inout) ::   ptab(f)
+#      else
+#         define ARRAY_TYPE(i,j,k,l,f)    TYPE(PTR_3D_dp)                , INTENT(inout) ::   ptab(f)
+#      endif
 #      define ARRAY_IN(i,j,k,l,f)      ptab(f)%pt3d(i,j,k)
 #      define K_SIZE(ptab)             SIZE(ptab(1)%pt3d,3)
@@ -17,5 +25,9 @@
 #   endif
 #   if defined DIM_4d
-#      define ARRAY_TYPE(i,j,k,l,f)    TYPE(PTR_4D)                , INTENT(inout) ::   ptab(f)
+#      if defined SINGLE_PRECISION
+#         define ARRAY_TYPE(i,j,k,l,f)    TYPE(PTR_4D_sp)                , INTENT(inout) ::   ptab(f)
+#      else
+#         define ARRAY_TYPE(i,j,k,l,f)    TYPE(PTR_4D_dp)                , INTENT(inout) ::   ptab(f)
+#      endif
 #      define ARRAY_IN(i,j,k,l,f)      ptab(f)%pt4d(i,j,k,l)
 #      define K_SIZE(ptab)             SIZE(ptab(1)%pt4d,3)
@@ -23,5 +35,9 @@
 #   endif
 #else
-#   define ARRAY_TYPE(i,j,k,l,f)    REAL(wp)                    , INTENT(inout) ::   ARRAY_IN(i,j,k,l,f)
+#   if defined SINGLE_PRECISION
+#      define ARRAY_TYPE(i,j,k,l,f)    REAL(sp)                    , INTENT(inout) ::   ARRAY_IN(i,j,k,l,f)
+#   else
+#      define ARRAY_TYPE(i,j,k,l,f)    REAL(dp)                    , INTENT(inout) ::   ARRAY_IN(i,j,k,l,f)
+#   endif
 #   define NAT_IN(k)                cd_nat
 #   define SGN_IN(k)                psgn
@@ -45,27 +61,46 @@
 #endif
 
+# if defined SINGLE_PRECISION
+#    define PRECISION sp
+#    define SENDROUTINE mppsend_sp
+#    define RECVROUTINE mpprecv_sp
+# else
+#    define PRECISION dp
+#    define SENDROUTINE mppsend_dp
+#    define RECVROUTINE mpprecv_dp
+# endif
+
 #if defined MULTI
-   SUBROUTINE ROUTINE_LNK( cdname, ptab, cd_nat, psgn, kfld, cd_mpp, pval )
-      INTEGER                     , INTENT(in   ) ::   kfld        ! number of pt3d arrays
+   SUBROUTINE ROUTINE_LNK( cdname, ptab, cd_nat, psgn, kfld, kfillmode, pfillval, lsend, lrecv )
+      INTEGER             , INTENT(in   ) ::   kfld        ! number of pt3d arrays
 #else
-   SUBROUTINE ROUTINE_LNK( cdname, ptab, cd_nat, psgn      , cd_mpp, pval )
+   SUBROUTINE ROUTINE_LNK( cdname, ptab, cd_nat, psgn      , kfillmode, pfillval, lsend, lrecv )
 #endif
       ARRAY_TYPE(:,:,:,:,:)                                        ! array or pointer of arrays on which the boundary condition is applied
-      CHARACTER(len=*)            , INTENT(in   ) ::   cdname      ! name of the calling subroutine
-      CHARACTER(len=1)            , INTENT(in   ) ::   NAT_IN(:)   ! nature of array grid-points
-      REAL(wp)                    , INTENT(in   ) ::   SGN_IN(:)   ! sign used across the north fold boundary
-      CHARACTER(len=3), OPTIONAL  , INTENT(in   ) ::   cd_mpp      ! fill the overlap area only
-      REAL(wp)        , OPTIONAL  , INTENT(in   ) ::   pval        ! background value (used at closed boundaries)
-      !
-      INTEGER  ::    ji,  jj,  jk,  jl, jh, jf   ! dummy loop indices
+      CHARACTER(len=*)              , INTENT(in   ) ::   cdname      ! name of the calling subroutine
+      CHARACTER(len=1)              , INTENT(in   ) ::   NAT_IN(:)   ! nature of array grid-points
+      REAL(wp)                      , INTENT(in   ) ::   SGN_IN(:)   ! sign used across the north fold boundary
+      INTEGER ,             OPTIONAL, INTENT(in   ) ::   kfillmode   ! filling method for halo over land (default = constant)
+      REAL(wp),             OPTIONAL, INTENT(in   ) ::   pfillval    ! background value (used at closed boundaries)
+      LOGICAL, DIMENSION(4),OPTIONAL, INTENT(in   ) ::   lsend, lrecv  ! communication with other 4 proc
+      !
+      INTEGER  ::    ji,  jj,  jk,  jl,  jf      ! dummy loop indices
       INTEGER  ::   ipi, ipj, ipk, ipl, ipf      ! dimension of the input array
-      INTEGER  ::   imigr, iihom, ijhom          ! local integers
-      INTEGER  ::   ml_req1, ml_req2, ml_err     ! for key_mpi_isend
+      INTEGER  ::   isize, ishift, ishift2       ! local integers
+      INTEGER  ::   ireq_we, ireq_ea, ireq_so, ireq_no     ! mpi_request id
       INTEGER  ::   ierr
+      INTEGER  ::   ifill_we, ifill_ea, ifill_so, ifill_no
       REAL(wp) ::   zland
-      INTEGER , DIMENSION(MPI_STATUS_SIZE)      ::   ml_stat        ! for key_mpi_isend
-      REAL(wp), DIMENSION(:,:,:,:,:,:), ALLOCATABLE ::   zt3ns, zt3sn   ! north-south & south-north  halos
-      REAL(wp), DIMENSION(:,:,:,:,:,:), ALLOCATABLE ::   zt3ew, zt3we   ! east -west  & west - east  halos
+      INTEGER , DIMENSION(MPI_STATUS_SIZE)        ::   istat          ! for mpi_isend
+      REAL(PRECISION), DIMENSION(:,:,:,:,:), ALLOCATABLE ::   zsnd_we, zrcv_we, zsnd_ea, zrcv_ea   ! east -west  & west - east  halos
+      REAL(PRECISION), DIMENSION(:,:,:,:,:), ALLOCATABLE ::   zsnd_so, zrcv_so, zsnd_no, zrcv_no   ! north-south & south-north  halos
+      LOGICAL  ::   llsend_we, llsend_ea, llsend_no, llsend_so       ! communication send
+      LOGICAL  ::   llrecv_we, llrecv_ea, llrecv_no, llrecv_so       ! communication receive 
+      LOGICAL  ::   lldo_nfd                                     ! do north pole folding
       !!----------------------------------------------------------------------
+      !
+      ! ----------------------------------------- !
+      !     0. local variables initialization     !
+      ! ----------------------------------------- !
       !
       ipk = K_SIZE(ptab)   ! 3rd dimension
@@ -75,259 +110,285 @@
       IF( narea == 1 .AND. numcom == -1 ) CALL mpp_report( cdname, ipk, ipl, ipf, ld_lbc = .TRUE. )
       !
-      IF( PRESENT( pval ) ) THEN   ;   zland = pval      ! set land value
-      ELSE                         ;   zland = 0._wp     ! zero by default
-      ENDIF
+      IF     ( PRESENT(lsend) .AND. PRESENT(lrecv) ) THEN
+         llsend_we = lsend(1)   ;   llsend_ea = lsend(2)   ;   llsend_so = lsend(3)   ;   llsend_no = lsend(4)
+         llrecv_we = lrecv(1)   ;   llrecv_ea = lrecv(2)   ;   llrecv_so = lrecv(3)   ;   llrecv_no = lrecv(4)
+      ELSE IF( PRESENT(lsend) .OR.  PRESENT(lrecv) ) THEN
+         WRITE(ctmp1,*) ' E R R O R : Routine ', cdname, '  is calling lbc_lnk with only one of the two arguments lsend or lrecv'
+         WRITE(ctmp2,*) ' ========== '
+         CALL ctl_stop( ' ', ctmp1, ctmp2, ' ' )
+      ELSE   ! send and receive with every neighbour
+         llsend_we = nbondi ==  1 .OR. nbondi == 0   ! keep for compatibility, should be defined in mppini
+         llsend_ea = nbondi == -1 .OR. nbondi == 0   ! keep for compatibility, should be defined in mppini
+         llsend_so = nbondj ==  1 .OR. nbondj == 0   ! keep for compatibility, should be defined in mppini
+         llsend_no = nbondj == -1 .OR. nbondj == 0   ! keep for compatibility, should be defined in mppini
+         llrecv_we = llsend_we   ;   llrecv_ea = llsend_ea   ;   llrecv_so = llsend_so   ;   llrecv_no = llsend_no
+      END IF
+         
+         
+      lldo_nfd = npolj /= 0                      ! keep for compatibility, should be defined in mppini
 
-      ! ------------------------------- !
-      !   standard boundary treatment   !    ! CAUTION: semi-column notation is often impossible
-      ! ------------------------------- !
-      !
-      IF( .NOT. PRESENT( cd_mpp ) ) THEN     !==  standard close or cyclic treatment  ==!
-         !
-         DO jf = 1, ipf                      ! number of arrays to be treated
-            !
-            !                                ! East-West boundaries
-            IF( l_Iperio ) THEN                    !* cyclic
-               ARRAY_IN( 1 ,:,:,:,jf) = ARRAY_IN(jpim1,:,:,:,jf)
-               ARRAY_IN(jpi,:,:,:,jf) = ARRAY_IN(  2  ,:,:,:,jf)
-            ELSE                                   !* closed
-               IF( .NOT. NAT_IN(jf) == 'F' )   ARRAY_IN(     1       :nn_hls,:,:,:,jf) = zland    ! east except F-point
-                                               ARRAY_IN(nlci-nn_hls+1:jpi   ,:,:,:,jf) = zland    ! west
-            ENDIF
-            !                                ! North-South boundaries
-            IF( l_Jperio ) THEN                    !* cyclic (only with no mpp j-split)
-               ARRAY_IN(:, 1 ,:,:,jf) = ARRAY_IN(:, jpjm1,:,:,jf)
-               ARRAY_IN(:,jpj,:,:,jf) = ARRAY_IN(:,   2  ,:,:,jf)
-            ELSE                                   !* closed
-               IF( .NOT. NAT_IN(jf) == 'F' )   ARRAY_IN(:,     1       :nn_hls,:,:,jf) = zland    ! south except F-point
-                                               ARRAY_IN(:,nlcj-nn_hls+1:jpj   ,:,:,jf) = zland    ! north
-            ENDIF
-         END DO
-         !
-      ENDIF
+      zland = 0._wp                                     ! land filling value: zero by default
+      IF( PRESENT( pfillval ) )   zland = pfillval      ! set land value
 
-      ! ------------------------------- !
-      !      East and west exchange     !
-      ! ------------------------------- !
-      ! we play with the neigbours AND the row number because of the periodicity
-      !
-      IF( ABS(nbondi) == 1 ) ALLOCATE( zt3ew(jpj,nn_hls,ipk,ipl,ipf,1), zt3we(jpj,nn_hls,ipk,ipl,ipf,1) )
-      IF(     nbondi  == 0 ) ALLOCATE( zt3ew(jpj,nn_hls,ipk,ipl,ipf,2), zt3we(jpj,nn_hls,ipk,ipl,ipf,2) )
-      !
-      SELECT CASE ( nbondi )      ! Read Dirichlet lateral conditions
-      CASE ( -1 )
-         iihom = nlci-nreci
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     zt3we(:,jh,jk,jl,jf,1) = ARRAY_IN(iihom +jh,:,jk,jl,jf)
-                  END DO
-               END DO
-            END DO
-         END DO
-      CASE ( 0 )
-         iihom = nlci-nreci
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     zt3ew(:,jh,jk,jl,jf,1) = ARRAY_IN(nn_hls+jh,:,jk,jl,jf)
-                     zt3we(:,jh,jk,jl,jf,1) = ARRAY_IN(iihom +jh,:,jk,jl,jf)
-                  END DO
-               END DO
-            END DO
-         END DO
-      CASE ( 1 )
-         iihom = nlci-nreci
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     zt3ew(:,jh,jk,jl,jf,1) = ARRAY_IN(nn_hls+jh,:,jk,jl,jf)
-                  END DO
-               END DO
-            END DO
-         END DO
+      ! define the method we will use to fill the halos in each direction
+      IF(              llrecv_we ) THEN   ;   ifill_we = jpfillmpi
+      ELSEIF(           l_Iperio ) THEN   ;   ifill_we = jpfillperio
+      ELSEIF( PRESENT(kfillmode) ) THEN   ;   ifill_we = kfillmode
+      ELSE                                ;   ifill_we = jpfillcst
+      END IF
+      !
+      IF(              llrecv_ea ) THEN   ;   ifill_ea = jpfillmpi
+      ELSEIF(           l_Iperio ) THEN   ;   ifill_ea = jpfillperio
+      ELSEIF( PRESENT(kfillmode) ) THEN   ;   ifill_ea = kfillmode
+      ELSE                                ;   ifill_ea = jpfillcst
+      END IF
+      !
+      IF(              llrecv_so ) THEN   ;   ifill_so = jpfillmpi
+      ELSEIF(           l_Jperio ) THEN   ;   ifill_so = jpfillperio
+      ELSEIF( PRESENT(kfillmode) ) THEN   ;   ifill_so = kfillmode
+      ELSE                                ;   ifill_so = jpfillcst
+      END IF
+      !
+      IF(              llrecv_no ) THEN   ;   ifill_no = jpfillmpi
+      ELSEIF(           l_Jperio ) THEN   ;   ifill_no = jpfillperio
+      ELSEIF( PRESENT(kfillmode) ) THEN   ;   ifill_no = kfillmode
+      ELSE                                ;   ifill_no = jpfillcst
+      END IF
+      !
+#if defined PRINT_CAUTION
+      !
+      ! ================================================================================== !
+      ! CAUTION: semi-column notation is often impossible because of the cpp preprocessing !
+      ! ================================================================================== !
+      !
+#endif
+      !
+      ! -------------------------------------------------- !
+      !     1. Do east and west MPI exchange if needed     !
+      ! -------------------------------------------------- !
+      !
+      ! Must exchange the whole column (from 1 to jpj) to get the corners if we have no south/north neighbourg
+      isize = nn_hls * jpj * ipk * ipl * ipf      
+      !
+      ! Allocate local temporary arrays to be sent/received. Fill arrays to be sent
+      IF( llsend_we )   ALLOCATE( zsnd_we(nn_hls,jpj,ipk,ipl,ipf) )
+      IF( llsend_ea )   ALLOCATE( zsnd_ea(nn_hls,jpj,ipk,ipl,ipf) )
+      IF( llrecv_we )   ALLOCATE( zrcv_we(nn_hls,jpj,ipk,ipl,ipf) )
+      IF( llrecv_ea )   ALLOCATE( zrcv_ea(nn_hls,jpj,ipk,ipl,ipf) )
+      !
+      IF( llsend_we ) THEN   ! copy western side of the inner mpi domain in local temporary array to be sent by MPI
+         ishift = nn_hls
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, jpj   ;   DO ji = 1, nn_hls
+            zsnd_we(ji,jj,jk,jl,jf) = ARRAY_IN(ishift+ji,jj,jk,jl,jf)   ! nn_hls + 1 -> 2*nn_hls
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      ENDIF
+      !
+      IF(llsend_ea  ) THEN   ! copy eastern side of the inner mpi domain in local temporary array to be sent by MPI
+         ishift = jpi - 2 * nn_hls
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, jpj   ;   DO ji = 1, nn_hls
+            zsnd_ea(ji,jj,jk,jl,jf) = ARRAY_IN(ishift+ji,jj,jk,jl,jf)   ! jpi - 2*nn_hls + 1 -> jpi - nn_hls
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      ENDIF
+      !
+      IF( ln_timing ) CALL tic_tac(.TRUE.)
+      !
+      ! non-blocking send of the western/eastern side using local temporary arrays
+      IF( llsend_we )   CALL SENDROUTINE( 1, zsnd_we(1,1,1,1,1), isize, nowe, ireq_we )
+      IF( llsend_ea )   CALL SENDROUTINE( 2, zsnd_ea(1,1,1,1,1), isize, noea, ireq_ea )
+      ! blocking receive of the western/eastern halo in local temporary arrays
+      IF( llrecv_we )   CALL RECVROUTINE( 2, zrcv_we(1,1,1,1,1), isize, nowe )
+      IF( llrecv_ea )   CALL RECVROUTINE( 1, zrcv_ea(1,1,1,1,1), isize, noea )
+      !
+      IF( ln_timing ) CALL tic_tac(.FALSE.)
+      !
+      !
+      ! ----------------------------------- !
+      !     2. Fill east and west halos     !
+      ! ----------------------------------- !
+      !
+      ! 2.1 fill weastern halo
+      ! ----------------------
+      ! ishift = 0                         ! fill halo from ji = 1 to nn_hls
+      SELECT CASE ( ifill_we )
+      CASE ( jpfillnothing )               ! no filling 
+      CASE ( jpfillmpi   )                 ! use data received by MPI 
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, jpj   ;   DO ji = 1, nn_hls
+            ARRAY_IN(ji,jj,jk,jl,jf) = zrcv_we(ji,jj,jk,jl,jf)   ! 1 -> nn_hls
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillperio )                 ! use east-weast periodicity
+         ishift2 = jpi - 2 * nn_hls
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, jpj   ;   DO ji = 1, nn_hls
+            ARRAY_IN(ji,jj,jk,jl,jf) = ARRAY_IN(ishift2+ji,jj,jk,jl,jf)
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillcopy  )                 ! filling with inner domain values
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, jpj   ;   DO ji = 1, nn_hls
+            ARRAY_IN(ji,jj,jk,jl,jf) = ARRAY_IN(nn_hls+1,jj,jk,jl,jf)
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillcst   )                 ! filling with constant value
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, jpj   ;   DO ji = 1, nn_hls
+            ARRAY_IN(ji,jj,jk,jl,jf) = zland
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
       END SELECT
-      !                           ! Migrations
-      imigr = nn_hls * jpj * ipk * ipl * ipf      
-      !
-      SELECT CASE ( nbondi )
-      CASE ( -1 )
-         CALL mppsend( 2, zt3we(1,1,1,1,1,1), imigr, noea, ml_req1 )
-         CALL mpprecv( 1, zt3ew(1,1,1,1,1,1), imigr, noea )
-         IF(l_isend)   CALL mpi_wait(ml_req1, ml_stat, ml_err)
-      CASE ( 0 )
-         CALL mppsend( 1, zt3ew(1,1,1,1,1,1), imigr, nowe, ml_req1 )
-         CALL mppsend( 2, zt3we(1,1,1,1,1,1), imigr, noea, ml_req2 )
-         CALL mpprecv( 1, zt3ew(1,1,1,1,1,2), imigr, noea )
-         CALL mpprecv( 2, zt3we(1,1,1,1,1,2), imigr, nowe )
-         IF(l_isend)   CALL mpi_wait(ml_req1, ml_stat, ml_err)
-         IF(l_isend)   CALL mpi_wait(ml_req2, ml_stat, ml_err)
-      CASE ( 1 )
-         CALL mppsend( 1, zt3ew(1,1,1,1,1,1), imigr, nowe, ml_req1 )
-         CALL mpprecv( 2, zt3we(1,1,1,1,1,1), imigr, nowe )
-         IF(l_isend)   CALL mpi_wait(ml_req1, ml_stat, ml_err )
+      !
+      ! 2.2 fill eastern halo
+      ! ---------------------
+      ishift = jpi - nn_hls                ! fill halo from ji = jpi-nn_hls+1 to jpi 
+      SELECT CASE ( ifill_ea )
+      CASE ( jpfillnothing )               ! no filling 
+      CASE ( jpfillmpi   )                 ! use data received by MPI 
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, jpj   ;   DO ji = 1, nn_hls
+            ARRAY_IN(ishift+ji,jj,jk,jl,jf) = zrcv_ea(ji,jj,jk,jl,jf)   ! jpi - nn_hls + 1 -> jpi
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillperio )                 ! use east-weast periodicity
+         ishift2 = nn_hls
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, jpj   ;   DO ji = 1, nn_hls
+            ARRAY_IN(ishift+ji,jj,jk,jl,jf) = ARRAY_IN(ishift2+ji,jj,jk,jl,jf)
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillcopy  )                 ! filling with inner domain values
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, jpj   ;   DO ji = 1, nn_hls
+            ARRAY_IN(ishift+ji,jj,jk,jl,jf) = ARRAY_IN(ishift,jj,jk,jl,jf)
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillcst   )                 ! filling with constant value
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, jpj   ;   DO ji = 1, nn_hls
+            ARRAY_IN(ishift+ji,jj,jk,jl,jf) = zland
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
       END SELECT
-      !
-      !                           ! Write Dirichlet lateral conditions
-      iihom = nlci-nn_hls
-      !
-      SELECT CASE ( nbondi )
-      CASE ( -1 )
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     ARRAY_IN(iihom+jh,:,jk,jl,jf) = zt3ew(:,jh,jk,jl,jf,1)
-                  END DO
-               END DO
-            END DO
-         END DO
-      CASE ( 0 )
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     ARRAY_IN(jh      ,:,jk,jl,jf) = zt3we(:,jh,jk,jl,jf,2)
-                     ARRAY_IN(iihom+jh,:,jk,jl,jf) = zt3ew(:,jh,jk,jl,jf,2)
-                  END DO
-               END DO
-            END DO
-         END DO
-      CASE ( 1 )
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     ARRAY_IN(jh      ,:,jk,jl,jf) = zt3we(:,jh,jk,jl,jf,1)
-                  END DO
-               END DO
-            END DO
-         END DO
-      END SELECT
-      !
-      IF( nbondi /= 2 ) DEALLOCATE( zt3ew, zt3we )
       !
       ! ------------------------------- !
       !     3. north fold treatment     !
       ! ------------------------------- !
+      !
       ! do it before south directions so concerned processes can do it without waiting for the comm with the sourthern neighbor
-      IF( npolj /= 0 .AND. .NOT. PRESENT(cd_mpp) ) THEN
+      !
+      IF( lldo_nfd .AND. ifill_no /= jpfillnothing ) THEN
          !
          SELECT CASE ( jpni )
-         CASE ( 1 )     ;   CALL lbc_nfd( ptab, NAT_IN(:), SGN_IN(:) OPT_K(:) )   ! only 1 northern proc, no mpp
-         CASE DEFAULT   ;   CALL mpp_nfd( ptab, NAT_IN(:), SGN_IN(:) OPT_K(:) )   ! for all northern procs.
+         CASE ( 1 )     ;   CALL lbc_nfd( ptab, NAT_IN(:), SGN_IN(:)                  OPT_K(:) )   ! only 1 northern proc, no mpp
+         CASE DEFAULT   ;   CALL mpp_nfd( ptab, NAT_IN(:), SGN_IN(:), ifill_no, zland OPT_K(:) )   ! for all northern procs.
          END SELECT
          !
-      ENDIF
-      !
-      ! ------------------------------- !
-      !  4. North and south directions  !
-      ! ------------------------------- !
-      ! always closed : we play only with the neigbours
-      !
-      IF( ABS(nbondj) == 1 ) ALLOCATE( zt3ns(jpi,nn_hls,ipk,ipl,ipf,1), zt3sn(jpi,nn_hls,ipk,ipl,ipf,1) )
-      IF(     nbondj  == 0 ) ALLOCATE( zt3ns(jpi,nn_hls,ipk,ipl,ipf,2), zt3sn(jpi,nn_hls,ipk,ipl,ipf,2) )
-      !
-      SELECT CASE ( nbondj )
-      CASE ( -1 )
-         ijhom = nlcj-nrecj
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     zt3sn(:,jh,jk,jl,jf,1) = ARRAY_IN(:,ijhom +jh,jk,jl,jf)
-                  END DO
-               END DO
-            END DO
-         END DO
-      CASE ( 0 )
-         ijhom = nlcj-nrecj
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     zt3sn(:,jh,jk,jl,jf,1) = ARRAY_IN(:,ijhom +jh,jk,jl,jf)
-                     zt3ns(:,jh,jk,jl,jf,1) = ARRAY_IN(:,nn_hls+jh,jk,jl,jf)
-                  END DO
-               END DO
-            END DO
-         END DO
-      CASE ( 1 )
-         ijhom = nlcj-nrecj
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     zt3ns(:,jh,jk,jl,jf,1) = ARRAY_IN(:,nn_hls+jh,jk,jl,jf)
-                  END DO
-               END DO
-            END DO
-         END DO
+         ifill_no = jpfillnothing  ! force to do nothing for the northern halo as we just done the north pole folding
+         !
+      ENDIF
+      !
+      ! ---------------------------------------------------- !
+      !     4. Do north and south MPI exchange if needed     !
+      ! ---------------------------------------------------- !
+      !
+      IF( llsend_so )   ALLOCATE( zsnd_so(jpi,nn_hls,ipk,ipl,ipf) )
+      IF( llsend_no )   ALLOCATE( zsnd_no(jpi,nn_hls,ipk,ipl,ipf) )
+      IF( llrecv_so )   ALLOCATE( zrcv_so(jpi,nn_hls,ipk,ipl,ipf) )
+      IF( llrecv_no )   ALLOCATE( zrcv_no(jpi,nn_hls,ipk,ipl,ipf) )
+      !
+      isize = jpi * nn_hls * ipk * ipl * ipf      
+
+      ! allocate local temporary arrays to be sent/received. Fill arrays to be sent
+      IF( llsend_so ) THEN   ! copy sourhern side of the inner mpi domain in local temporary array to be sent by MPI
+         ishift = nn_hls
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, nn_hls   ;   DO ji = 1, jpi
+            zsnd_so(ji,jj,jk,jl,jf) = ARRAY_IN(ji,ishift+jj,jk,jl,jf)   ! nn_hls+1 -> 2*nn_hls
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      ENDIF
+      !
+      IF( llsend_no ) THEN   ! copy eastern side of the inner mpi domain in local temporary array to be sent by MPI
+         ishift = jpj - 2 * nn_hls
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, nn_hls   ;   DO ji = 1, jpi
+            zsnd_no(ji,jj,jk,jl,jf) = ARRAY_IN(ji,ishift+jj,jk,jl,jf)   ! jpj-2*nn_hls+1 -> jpj-nn_hls
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      ENDIF
+      !
+      IF( ln_timing ) CALL tic_tac(.TRUE.)
+      !
+      ! non-blocking send of the southern/northern side
+      IF( llsend_so )   CALL SENDROUTINE( 3, zsnd_so(1,1,1,1,1), isize, noso, ireq_so )
+      IF( llsend_no )   CALL SENDROUTINE( 4, zsnd_no(1,1,1,1,1), isize, nono, ireq_no )
+      ! blocking receive of the southern/northern halo
+      IF( llrecv_so )   CALL RECVROUTINE( 4, zrcv_so(1,1,1,1,1), isize, noso )
+      IF( llrecv_no )   CALL RECVROUTINE( 3, zrcv_no(1,1,1,1,1), isize, nono )
+      !
+      IF( ln_timing ) CALL tic_tac(.FALSE.)
+      !
+      ! ------------------------------------- !
+      !     5. Fill south and north halos     !
+      ! ------------------------------------- !
+      !
+      ! 5.1 fill southern halo
+      ! ----------------------
+      ! ishift = 0                         ! fill halo from jj = 1 to nn_hls
+      SELECT CASE ( ifill_so )
+      CASE ( jpfillnothing )               ! no filling 
+      CASE ( jpfillmpi   )                 ! use data received by MPI 
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, nn_hls   ;   DO ji = 1, jpi
+            ARRAY_IN(ji,jj,jk,jl,jf) = zrcv_so(ji,jj,jk,jl,jf)   ! 1 -> nn_hls
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillperio )                 ! use north-south periodicity
+         ishift2 = jpj - 2 * nn_hls
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, nn_hls   ;   DO ji = 1, jpi
+            ARRAY_IN(ji,jj,jk,jl,jf) = ARRAY_IN(ji,ishift2+jj,jk,jl,jf)
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillcopy  )                 ! filling with inner domain values
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, nn_hls   ;   DO ji = 1, jpi
+            ARRAY_IN(ji,jj,jk,jl,jf) = ARRAY_IN(ji,nn_hls+1,jk,jl,jf)
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillcst   )                 ! filling with constant value
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, nn_hls   ;   DO ji = 1, jpi 
+            ARRAY_IN(ji,jj,jk,jl,jf) = zland
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
       END SELECT
       !
-      !                           ! Migrations
-      imigr = nn_hls * jpi * ipk * ipl * ipf
-      !
-      SELECT CASE ( nbondj )
-      CASE ( -1 )
-         CALL mppsend( 4, zt3sn(1,1,1,1,1,1), imigr, nono, ml_req1 )
-         CALL mpprecv( 3, zt3ns(1,1,1,1,1,1), imigr, nono )
-         IF(l_isend) CALL mpi_wait(ml_req1, ml_stat, ml_err )
-      CASE ( 0 )
-         CALL mppsend( 3, zt3ns(1,1,1,1,1,1), imigr, noso, ml_req1 )
-         CALL mppsend( 4, zt3sn(1,1,1,1,1,1), imigr, nono, ml_req2 )
-         CALL mpprecv( 3, zt3ns(1,1,1,1,1,2), imigr, nono )
-         CALL mpprecv( 4, zt3sn(1,1,1,1,1,2), imigr, noso )
-         IF(l_isend)   CALL mpi_wait(ml_req1, ml_stat, ml_err )
-         IF(l_isend)   CALL mpi_wait(ml_req2, ml_stat, ml_err )
-      CASE ( 1 )
-         CALL mppsend( 3, zt3ns(1,1,1,1,1,1), imigr, noso, ml_req1 )
-         CALL mpprecv( 4, zt3sn(1,1,1,1,1,1), imigr, noso )
-         IF(l_isend)   CALL mpi_wait(ml_req1, ml_stat, ml_err )
+      ! 5.2 fill northern halo
+      ! ----------------------
+      ishift = jpj - nn_hls                ! fill halo from jj = jpj-nn_hls+1 to jpj 
+      SELECT CASE ( ifill_no )
+      CASE ( jpfillnothing )               ! no filling 
+      CASE ( jpfillmpi   )                 ! use data received by MPI 
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, nn_hls   ;   DO ji = 1, jpi
+            ARRAY_IN(ji,ishift+jj,jk,jl,jf) = zrcv_no(ji,jj,jk,jl,jf)   ! jpj-nn_hls+1 -> jpj
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillperio )                 ! use north-south periodicity
+         ishift2 = nn_hls
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, nn_hls   ;   DO ji = 1, jpi
+            ARRAY_IN(ji,ishift+jj,jk,jl,jf) = ARRAY_IN(ji,ishift2+jj,jk,jl,jf)
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillcopy  )                 ! filling with inner domain values
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, nn_hls   ;   DO ji = 1, jpi
+            ARRAY_IN(ji,ishift+jj,jk,jl,jf) = ARRAY_IN(ji,ishift,jk,jl,jf)
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
+      CASE ( jpfillcst   )                 ! filling with constant value
+         DO jf = 1, ipf   ;   DO jl = 1, ipl   ;   DO jk = 1, ipk   ;   DO jj = 1, nn_hls   ;   DO ji = 1, jpi
+            ARRAY_IN(ji,ishift+jj,jk,jl,jf) = zland
+         END DO   ;   END DO   ;   END DO   ;   END DO   ;   END DO
       END SELECT
       !
-      ijhom = nlcj-nn_hls
-      !
-      SELECT CASE ( nbondj )
-      CASE ( -1 )
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     ARRAY_IN(:,ijhom+jh,jk,jl,jf) = zt3ns(:,jh,jk,jl,jf,1)
-                  END DO
-               END DO
-            END DO
-         END DO
-      CASE ( 0 )
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     ARRAY_IN(:,      jh,jk,jl,jf) = zt3sn(:,jh,jk,jl,jf,2)
-                     ARRAY_IN(:,ijhom+jh,jk,jl,jf) = zt3ns(:,jh,jk,jl,jf,2)
-                  END DO
-               END DO
-            END DO
-         END DO
-      CASE ( 1 )
-         DO jf = 1, ipf
-            DO jl = 1, ipl
-               DO jk = 1, ipk
-                  DO jh = 1, nn_hls
-                     ARRAY_IN(:,jh,jk,jl,jf) = zt3sn(:,jh,jk,jl,jf,1)
-                  END DO
-               END DO
-            END DO
-         END DO
-      END SELECT
-      !
-      IF( nbondj /= 2 ) DEALLOCATE( zt3ns, zt3sn )
+      ! -------------------------------------------- !
+      !     6. deallocate local temporary arrays     !
+      ! -------------------------------------------- !
+      !
+      IF( llsend_we ) THEN
+         CALL mpi_wait(ireq_we, istat, ierr )
+         DEALLOCATE( zsnd_we )
+      ENDIF
+      IF( llsend_ea )  THEN
+         CALL mpi_wait(ireq_ea, istat, ierr )
+         DEALLOCATE( zsnd_ea )
+      ENDIF
+      IF( llsend_so ) THEN
+         CALL mpi_wait(ireq_so, istat, ierr )
+         DEALLOCATE( zsnd_so )
+      ENDIF
+      IF( llsend_no ) THEN
+         CALL mpi_wait(ireq_no, istat, ierr )
+         DEALLOCATE( zsnd_no )
+      ENDIF
+      !
+      IF( llrecv_we )   DEALLOCATE( zrcv_we )
+      IF( llrecv_ea )   DEALLOCATE( zrcv_ea )
+      IF( llrecv_so )   DEALLOCATE( zrcv_so )
+      IF( llrecv_no )   DEALLOCATE( zrcv_no )
       !
    END SUBROUTINE ROUTINE_LNK
-
+#undef PRECISION
+#undef SENDROUTINE
+#undef RECVROUTINE
 #undef ARRAY_TYPE
 #undef NAT_IN
