#include "cppdefs.h"
      MODULE mod_sources
!
!git $Id$
!svn $Id: mod_sources.F 1151 2023-02-09 03:08:53Z arango $
!================================================== Hernan G. Arango ===
!  Copyright (c) 2002-2023 The ROMS/TOMS Group                         !
!    Licensed under a MIT/X style license                              !
!    See License_ROMS.md                                               !
!=======================================================================
!                                                                      !
!  Msrc       Maximum number of analytical point Sources/Sinks.        !
!  Nsrc       Number of point Sources/Sinks.                           !
!  Dsrc       Direction of point Sources/Sinks:                        !
!               Dsrc(:) = 0,  Along XI-direction.                      !
!               Dsrc(:) > 0,  Along ETA-direction.                     !
!  Fsrc       Point Source/Sinks identification flag:                  !
!               Fsrc(:) = 0,  All Tracer source/sink are off.          !
!               Fsrc(:) = 1,  Only temperature is on.                  !
!               Fsrc(:) = 2,  Only salinity is on.                     !
!               Fsrc(:) = 3,  Both temperature and salinity are on.    !
!               Fsrc(:) = 4,  Both nitrate and salinity are on.        !
!               Fsrc(:) = ... And other combinations.                  !
!                             (We need a more robust logic here)       !
!  Isrc       I-grid location of point Sources/Sinks,                  !
!               1 =< Isrc =< Lm(ng).                                   !
!  Jsrc       J-grid location of point Sources/Sinks,                  !
!               1 =< Jsrc =< Mm(ng).                                   !
!  Qbar       Vertically integrated mass transport (m3/s) of point     !
!               Sources/Sinks at U- or V-points:                       !
!               Qbar -> positive, if the mass transport is in the      !
!                       positive U- or V-direction.                    !
!               Qbar -> negative, if the mass transport is in the      !
!                       negative U- or V-direction.                    !
!  QbarG      Latest two-time snapshots of vertically integrated       !
!               mass transport (m3/s) of point Sources/Sinks.          !
!  Qshape     Nondimensional shape function to distribute mass         !
!               mass point Sources/Sinks vertically.                   !
!  Qsrc       Mass transport profile (m3/s) of point Sources/Sinks.    !
!  Tsrc       Tracer (tracer units) point Sources/Sinks.               !
!  TsrcG      Latest two-time snapshots of tracer (tracer units)       !
!               point Sources/Sinks.                                   !
!                                                                      !
!=======================================================================
!
        USE mod_kinds
        USE mod_param
!
        implicit none
!
        PUBLIC :: allocate_sources
        PUBLIC :: deallocate_sources
!
!-----------------------------------------------------------------------
!  Define T_SOURCES structure.
!-----------------------------------------------------------------------
!
        TYPE T_SOURCES

          integer, pointer :: Isrc(:)
          integer, pointer :: Jsrc(:)

          real(r8), pointer :: Dsrc(:)
          real(r8), pointer :: Fsrc(:)
          real(r8), pointer :: Qbar(:)
          real(r8), pointer :: Qshape(:,:)
          real(r8), pointer :: Qsrc(:,:)
          real(r8), pointer :: Tsrc(:,:,:)
          real(r8), pointer :: Xsrc(:)
          real(r8), pointer :: Ysrc(:)

#ifndef ANA_PSOURCE
          real(r8), pointer :: QbarG(:,:)
          real(r8), pointer :: TsrcG(:,:,:,:)
#endif

#ifdef ADJOINT
          real(r8), pointer :: ad_Qbar(:)
          real(r8), pointer :: ad_Qsrc(:,:)
          real(r8), pointer :: ad_Tsrc(:,:,:)
#endif

#ifdef TANGENT
          real(r8), pointer :: tl_Qbar(:)
          real(r8), pointer :: tl_Qsrc(:,:)
          real(r8), pointer :: tl_Tsrc(:,:,:)
#endif

        END TYPE T_SOURCES
!
        TYPE (T_SOURCES), allocatable :: SOURCES(:)
!
!-----------------------------------------------------------------------
!  Define other variables in module.
!-----------------------------------------------------------------------
!
        integer, allocatable :: Msrc(:)
        integer, allocatable :: Nsrc(:)
!
      CONTAINS
!
      SUBROUTINE allocate_sources (ng)
!
!=======================================================================
!                                                                      !
!  This routine allocates and initializes all variables in the module  !
!  for all nested grids.                                               !
!                                                                      !
!=======================================================================
!
      USE mod_param
#ifndef ANA_PSOURCE
      USE mod_parallel
      USE mod_iounits
      USE mod_ncparam
      USE mod_netcdf
# if defined PIO_LIB && defined DISTRIBUTE
      USE mod_pio_netcdf
# endif
      USE mod_scalars
#endif
!
      USE strings_mod, ONLY : FoundError
!
!  Imported variable declarations.
!
      integer :: ng
!
!  Local variable declarations.
!
#ifndef ANA_PSOURCE
      logical :: foundit
!
      integer :: Vid, ifile, nvatt, nvdim
#endif
      integer :: is, itrc, k, mg

      real(r8), parameter :: IniVal = 0.0_r8
!
      character (len=*), parameter :: MyFile =                          &
     &  __FILE__//", allocate_sources"

#ifndef ANA_PSOURCE
# if defined PIO_LIB && defined DISTRIBUTE
!
      TYPE (Var_desc_t)  :: my_pioVar
# endif
#endif
!
!-----------------------------------------------------------------------
!  Allocate module variables.
!-----------------------------------------------------------------------
!
      IF (.not.allocated(Msrc)) THEN
        allocate ( Msrc(Ngrids) )
      END IF

      IF (.not.allocated(Nsrc)) THEN
        allocate ( Nsrc(Ngrids) )
      END IF

#ifndef ANA_PSOURCE
!
!  Inquire about the number of point Sources/Sinks.
!
      IF (ng.eq.1) THEN
        DO mg=1,Ngrids
          foundit=.FALSE.
          IF (LuvSrc(mg).or.LwSrc(mg).or.ANY(LtracerSrc(:,mg))) THEN
            SELECT CASE (SSF(ng)%IOtype)
              CASE (io_nf90)
                CALL netcdf_inq_var (ng, iNLM, SSF(mg)%name,            &
     &                               MyVarName = Vname(1,idRxpo),       &
     &                               SearchVar = foundit,               &
     &                               VarID = Vid,                       &
     &                               nVardim = nvdim,                   &
     &                               nVarAtt = nvatt)

# if defined PIO_LIB && defined DISTRIBUTE
              CASE (io_pio)
                CALL pio_netcdf_inq_var (ng, iNLM, SSF(mg)%name,        &
     &                                   MyVarName = Vname(1,idRxpo),   &
     &                                   SearchVar = foundit,           &
     &                                   pioVar = my_pioVar,            &
     &                                   nVardim = nvdim,               &
     &                                   nVarAtt = nvatt)
# endif
            END SELECT
            IF (FoundError(exit_flag, NoError, __LINE__, MyFile)) RETURN
            IF (foundit) THEN
              Nsrc(mg)=var_Dsize(1)         ! first dimension
              Msrc(mg)=Nsrc(mg)
              CALL check_sources (mg, SSF(mg)%name, Nsrc(mg))
              IF (FoundError(exit_flag, NoError, __LINE__,              &
     &                       MyFile)) RETURN

            END IF
          END IF
        END DO
      END IF
#else
!
!  Set number of point sources to maximum number of analytical sources.
!  Notice that a maximum of 200 analytical sources are set-up here.
!
      Msrc(ng)=200
      Nsrc(ng)=Msrc(ng)
#endif
!
!  Allocate structure.
!
      IF (ng.eq.1) allocate ( SOURCES(Ngrids) )
!
!  Allocate point Sources/Sinks variables.
!
      allocate ( SOURCES(ng) % Isrc(Nsrc(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng),r8)

      allocate ( SOURCES(ng) % Jsrc(Nsrc(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng),r8)

      allocate ( SOURCES(ng) % Dsrc(Nsrc(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng),r8)

      allocate ( SOURCES(ng) % Fsrc(Nsrc(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng),r8)

      allocate ( SOURCES(ng) % Qbar(Nsrc(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng),r8)

      allocate ( SOURCES(ng) % Qshape(Nsrc(ng),N(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng)*N(ng),r8)

      allocate ( SOURCES(ng) % Qsrc(Nsrc(ng),N(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng)*N(ng),r8)

      allocate ( SOURCES(ng) % Tsrc(Nsrc(ng),N(ng),NT(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng)*N(ng)*NT(ng),r8)

      allocate ( SOURCES(ng) % Xsrc(Nsrc(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng),r8)

      allocate ( SOURCES(ng) % Ysrc(Nsrc(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng),r8)

#ifndef ANA_PSOURCE
      allocate ( SOURCES(ng) % QbarG(Nsrc(ng),2) )
      Dmem(ng)=Dmem(ng)+2.0_r8*REAL(Nsrc(ng),r8)

      allocate ( SOURCES(ng) % TsrcG(Nsrc(ng),N(ng),2,NT(ng)) )
      Dmem(ng)=Dmem(ng)+2.0_r8*REAL(Nsrc(ng)*N(ng)*NT(ng),r8)
#endif

#ifdef ADJOINT
      allocate ( SOURCES(ng) % ad_Qbar(Nsrc(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng),r8)

      allocate ( SOURCES(ng) % ad_Qsrc(Nsrc(ng),N(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng)*N(ng),r8)

      allocate ( SOURCES(ng) % ad_Tsrc(Nsrc(ng),N(ng),NT(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng)*N(ng)*NT(ng),r8)
#endif

#ifdef TANGENT
      allocate ( SOURCES(ng) % tl_Qbar(Nsrc(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng),r8)

      allocate ( SOURCES(ng) % tl_Qsrc(Nsrc(ng),N(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng)*N(ng),r8)

      allocate ( SOURCES(ng) % tl_Tsrc(Nsrc(ng),N(ng),NT(ng)) )
      Dmem(ng)=Dmem(ng)+REAL(Nsrc(ng)*N(ng)*NT(ng),r8)
#endif

!
!-----------------------------------------------------------------------
!  Initialize module variables.
!-----------------------------------------------------------------------
!
      DO is=1,Nsrc(ng)
        SOURCES(ng) % Isrc(is) = 0
        SOURCES(ng) % Jsrc(is) = 0
        SOURCES(ng) % Dsrc(is) = IniVal
        SOURCES(ng) % Fsrc(is) = IniVal
        SOURCES(ng) % Xsrc(is) = IniVal
        SOURCES(ng) % Ysrc(is) = IniVal
        SOURCES(ng) % Qbar(is) = IniVal
#ifndef ANA_PSOURCE
        SOURCES(ng) % QbarG(is,1) = IniVal
        SOURCES(ng) % QbarG(is,2) = IniVal
#endif
#ifdef ADJOINT
        SOURCES(ng) % ad_Qbar(is) = IniVal
#endif
#ifdef TANGENT
        SOURCES(ng) % tl_Qbar(is) = IniVal
#endif
      END DO
      DO k=1,N(ng)
        DO is=1,Nsrc(ng)
          SOURCES(ng) % Qshape(is,k) = IniVal
          SOURCES(ng) % Qsrc(is,k) = IniVal
#ifdef ADJOINT
          SOURCES(ng) % ad_Qsrc(is,k) = IniVal
#endif
#ifdef TANGENT
          SOURCES(ng) % tl_Qsrc(is,k) = IniVal
#endif
        END DO
      END DO
      DO itrc=1,NT(ng)
        DO k=1,N(ng)
          DO is=1,Nsrc(ng)
            SOURCES(ng) % Tsrc(is,k,itrc) = IniVal
#ifdef ADJOINT
            SOURCES(ng) % ad_Tsrc(is,k,itrc) = IniVal
#endif
#ifdef TANGENT
            SOURCES(ng) % tl_Tsrc(is,k,itrc) = IniVal
#endif
#ifndef ANA_PSOURCE
            SOURCES(ng) % TsrcG(is,k,1,itrc) = IniVal
            SOURCES(ng) % TsrcG(is,k,2,itrc) = IniVal
#endif
          END DO
        END DO
      END DO
!
      RETURN
      END SUBROUTINE allocate_sources
!
      SUBROUTINE deallocate_sources (ng)
!
!=======================================================================
!                                                                      !
!  This routine deallocates all variables in the module for all nested !
!  grids.                                                              !
!                                                                      !
!=======================================================================

#ifdef SUBOBJECT_DEALLOCATION
!
      USE destroy_mod, ONLY : destroy
#endif
!
!  Imported variable declarations.
!
      integer :: ng
!
!  Local variable declarations.
!
      character (len=*), parameter :: MyFile =                          &
     &  __FILE__//", deallocate_mixing"

#ifdef SUBOBJECT_DEALLOCATION
!
!-----------------------------------------------------------------------
!  Deallocate each variable in the derived-type T_SOURCES structure
!  separately.
!-----------------------------------------------------------------------
!
      IF (.not.destroy(ng, SOURCES(ng)%Isrc, MyFile,                    &
     &                 __LINE__, 'SOURCES(ng)%Isrc')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%Jsrc, MyFile,                    &
     &                 __LINE__, 'SOURCES(ng)%Jsrc')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%Dsrc, MyFile,                    &
     &                 __LINE__, 'SOURCES(ng)%Dsrc')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%Fsrc, MyFile,                    &
     &                 __LINE__, 'SOURCES(ng)%Fsrc')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%Qbar, MyFile,                    &
     &                 __LINE__, 'SOURCES(ng)%Qbar')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%Qshape, MyFile,                  &
     &                 __LINE__, 'SOURCES(ng)%Qshape')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%Qsrc, MyFile,                    &
     &                 __LINE__, 'SOURCES(ng)%Qsrc')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%Tsrc, MyFile,                    &
     &                 __LINE__, 'SOURCES(ng)%Tsrc')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%Xsrc, MyFile,                    &
     &                 __LINE__, 'SOURCES(ng)%Xsrc')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%Ysrc, MyFile,                    &
     &                 __LINE__, 'SOURCES(ng)%Ysrc')) RETURN

# ifndef ANA_PSOURCE
      IF (.not.destroy(ng, SOURCES(ng)%QbarG, MyFile,                   &
     &                 __LINE__, 'SOURCES(ng)%QbarG')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%TsrcG, MyFile,                   &
     &                 __LINE__, 'SOURCES(ng)%TsrcG')) RETURN
# endif

# ifdef ADJOINT
      IF (.not.destroy(ng, SOURCES(ng)%ad_Qbar, MyFile,                 &
     &                 __LINE__, 'SOURCES(ng)%ad_Qbar')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%ad_Qsrc, MyFile,                 &
     &                 __LINE__, 'SOURCES(ng)%ad_Qsrc')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%ad_Tsrc, MyFile,                 &
     &                 __LINE__, 'SOURCES(ng)%ad_Tsrc')) RETURN
# endif

# ifdef TANGENT
      IF (.not.destroy(ng, SOURCES(ng)%tl_Qbar, MyFile,                 &
     &                 __LINE__, 'SOURCES(ng)%tl_Qbar')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%tl_Qsrc, MyFile,                 &
     &                 __LINE__, 'SOURCES(ng)%tl_Qsrc')) RETURN

      IF (.not.destroy(ng, SOURCES(ng)%tl_Tsrc, MyFile,                 &
     &                 __LINE__, 'SOURCES(ng)%tl_Tsrc')) RETURN
# endif
#endif
!
!-----------------------------------------------------------------------
!  Deallocate derived-type SOURCES structure.
!-----------------------------------------------------------------------
!
      IF (ng.eq.Ngrids) THEN
        IF (allocated(SOURCES)) deallocate ( SOURCES )
      END IF
!
!-----------------------------------------------------------------------
!  Deallocate other variables in module.
!-----------------------------------------------------------------------
!
      IF (allocated(Msrc)) THEN
        deallocate ( Msrc )
      END IF

      IF (allocated(Nsrc)) THEN
        deallocate ( Nsrc )
      END IF
!
      RETURN
      END SUBROUTINE deallocate_sources
!
      SUBROUTINE check_sources (ng, ncname, Npsrc)
!
!=======================================================================
!                                                                      !
!  It checks input NetCDF file for correctness in the spefication of   !
!  the point Source/Sink grid-cell face flag values (0, 1, 2) and the  !
!  implementation methodology using "LuvSrc" and or "LwSrc".           !
!                                                                      !
!=======================================================================
!
      USE mod_param
      USE mod_parallel
      USE mod_iounits
      USE mod_netcdf
#if defined PIO_LIB && defined DISTRIBUTE
      USE mod_pio_netcdf
#endif
      USE mod_scalars
!
      USE strings_mod, ONLY : FoundError

!  Imported variable declarations.
!
      integer, intent(in) :: ng, Npsrc
!
      character (len=*), intent(in) :: ncname
!
!  Local variable declarations.
!
      integer :: i, ic_u, ic_v, ic_w
!
      real(r8) :: Dsrc_min, Dsrc_max
!
      real(r8) :: Dsrc(Npsrc)
!
      character (len=*), parameter :: MyFile =                          &
     &  __FILE__//", check_sources"
!
!-----------------------------------------------------------------------
!  Read in Point Source/Sink cell-face flag and check for correct values
!  according to the implementation methodology:
!
!    If LuvSrc = T,  needs Dsrc = 0 (flow across grid cell u-face) or
!                          Dsrc = 1 (flow across grid cell v-face)
!
!    If LwSrc = T,   needs Dsrc = 2 (flow across grid cell w-face)
!-----------------------------------------------------------------------
!
!  Read in Source/Sink cell-face flag.
!
      SELECT CASE (SSF(ng)%IOtype)
        CASE (io_nf90)
          CALL netcdf_get_fvar (ng, iNLM, ncname,                       &
     &                          Vname(1,idRdir),  Dsrc,                 &
     &                          min_val = Dsrc_min,                     &
     &                          max_val = Dsrc_max)

# if defined PIO_LIB && defined DISTRIBUTE
        CASE (io_pio)
          CALL pio_netcdf_get_fvar (ng, iNLM, ncname,                   &
     &                              Vname(1,idRdir),  Dsrc,             &
     &                              min_val = Dsrc_min,                 &
     &                              max_val = Dsrc_max)
# endif
      END SELECT
      IF (FoundError(exit_flag, NoError, __LINE__, MyFile)) RETURN
!
!  Count and report Source/Sink for each cell-face flag value.
!
      ic_u=0
      ic_v=0
      ic_w=0
!
      DO i=1,NpSrc
        IF (INT(Dsrc(i)).eq.0) ic_u=ic_u+1
        IF (INT(Dsrc(i)).eq.1) ic_v=ic_v+1
        IF (INT(Dsrc(i)).eq.2) ic_w=ic_w+1
      END DO
!
      IF (Master) THEN
        IF (ng.eq.1) WRITE (stdout,10)
        WRITE (stdout,20) ng, TRIM(ncname),                             &
                          LuvSrc(ng), ic_u,                             &
                          LuvSrc(ng), ic_v,                             &
                          LwSrc(ng),  ic_w
      END IF
!
!  Stop if illegal configuration.
!
      IF (.not.LwSrc(ng).and.LuvSrc(ng).and.                            &
          (ic_u.eq.0).and.(ic_v.eq.0)) THEN
        IF (Master) WRITE (stdout,30) 'LuvSrc'
        exit_flag=5
      END IF
      IF (.not.LuvSrc(ng).and.LwSrc(ng).and.(ic_w.eq.0)) THEN
        IF (Master) WRITE (stdout,30) 'LwSrc'
        exit_flag=5
      END IF
      IF (FoundError(exit_flag, NoError, __LINE__, MyFile)) RETURN
!
  10  FORMAT (/,1x,'Point Sources/Sinks grid-cell flag locations ',     &
     &        'counter:',/)
  20  FORMAT (4x,'Grid: ',i0,', file: ',a,/,                            &
     &        19x,'LuvSrc = ',l1,2x,'u-face = ',i0,/,                   &
     &        19x,'LuvSrc = ',l1,2x,'v-face = ',i0,/,                   &
     &        19x,'LwSrc  = ',l1,2x,'w-face = ',i0)
  30  FORMAT (/,' CHECK_SOURCES - Cannot find point Souces/Sinks ',     &
     &        "the '",a,"' method.")
!
      RETURN
      END SUBROUTINE check_sources
!
      END MODULE mod_sources