!------------------------------------------------------------------------------
!        IST/MARETEC, Water Modelling Group, Mohid modelling system
!------------------------------------------------------------------------------
!
! TITLE         : Mohid Model
! PROJECT       : Mohid Base 1
! MODULE        : Discharges
! URL           : http://www.mohid.com
! AFFILIATION   : IST/MARETEC, Marine Modelling Group
! DATE          : May 2003
! REVISION      : Frank Braunschweig - v4.0
! DESCRIPTION   : Module to Impose Discharges
!
!------------------------------------------------------------------------------
Module ModuleDischarges

    use ModuleGlobalData
    use ModuleTime
    use ModuleEnterData
    use ModuleFunctions, only : InterpolateValueInTime, ConstructPropertyID
    use ModuleTimeSerie, only : StartTimeSerieInput, GetTimeSerieValue, KillTimeSerie

    implicit none 

    private

    !Subroutines & Functions---------------------------------------------------

    !Constructor
    public  :: Construct_Discharges
    private ::      AllocateInstance
    private ::      Construct_DischargeList
    private ::          Add_Discharge
    private ::          Construct_Discharge
    private ::              Construct_Discharge_ID
    private ::              ConstDischargeLoc
    private ::              Read_DataBaseFile
    private ::              Construct_FlowValues
    private ::              Construct_VelocityValues
    private ::              Construct_PropertyList
    private ::                  Construct_Property
    private ::                      Construct_PropertyValues
    private ::                      Add_Property


    !Selector
    public  :: GetDischargesNumber                                  !Returns the number of discharge points
    public  :: GetDischargesGridLocalization
    public  :: GetDischargesNodeID
    public  :: GetDischargeWaterFlow
    public  :: GetDischargeFlowVelocity
    public  :: GetDischargeParameters
    public  :: GetDischargeConcentration
    private ::    Search_Discharge
    private ::    Search_Property

    !Modifier

    !Destructor
    public  :: Kill_Discharges
    private ::      KillIndividualDischarge
    private ::      DeallocateInstance


    !Management
    private ::      Ready

    !Parameter-----------------------------------------------------------------

    !STAT
    integer, parameter :: NO_ID_          =  7    ! No property ID was specified

    ! Time Series 
    integer, parameter :: TIME_COLUMN     = 1
    integer, parameter :: SECONDS         = 1
    integer, parameter :: MINUTES         = 2
    integer, parameter :: HOURS           = 3
    integer, parameter :: DAYS            = 4
    integer, parameter :: MONTHS          = 5
    integer, parameter :: YEARS           = 6

    !Direction
    integer, parameter :: DirectionX_   = 1
    integer, parameter :: DirectionY_   = 2

    character(len=StringLength), parameter :: block_begin               = '<begindischarge>'
    character(len=StringLength), parameter :: block_end                 = '<enddischarge>'
    character(len=StringLength), parameter :: beginproperty             = '<<beginproperty>>'
    character(len=StringLength), parameter :: endproperty               = '<<endproperty>>'

    !Types---------------------------------------------------------------------

    type       T_ID
        integer                                 :: IDnumber    = FillValueInt
        character(LEN = StringLength)           :: name        = Space
        character(LEN = StringLength)           :: description = Space
        character(LEN = StringLength)           :: units       = Space
    end type T_ID

    type       T_Property
        type (T_PropertyID)                     :: ID
        logical                                 :: Variable       = .false.
        integer                                 :: ConcColumn
        real                                    :: scalar         = FillValueReal
        type (T_Property), pointer              :: Next,Prev
    end type T_Property

    type       T_WaterFlow
        logical                                 :: Variable      = .false.
        integer                                 :: FlowColumn
        real                                    :: scalar        = FillValueReal
    end type T_WaterFlow


    type       T_WaterVelocity
        logical                                 :: UVariable
        logical                                 :: VVariable
        integer                                 :: UColumn               
        integer                                 :: VColumn               
        real                                    :: Uscalar = FillValueReal
        real                                    :: Vscalar = FillValueReal
    end type T_WaterVelocity

    type       T_FlowOver
        logical                                 :: On
        real                                    :: WeirLength
        real                                    :: DischargeCoeficient
        real                                    :: CrestHeigth
    end  type T_FlowOver

    type T_GridCoordinates
        integer                                 :: I = FillValueInt
        integer                                 :: J = FillValueInt
        integer                                 :: K = FillValueInt
    end type T_GridCoordinates

    type       T_Localization 
         type (T_GridCoordinates)               :: GridCoordinates
         logical                                :: AlternativeLocations       = .false.
         real                                   :: MinimumDischargeDepth
         logical                                :: UsedWithGrid
         logical                                :: DischargeUniform           = .false.
         integer                                :: NodeID = FillValueInt
    end  type T_Localization

    type       T_IndividualDischarge
         type(T_ID                 )            :: ID
         type(T_Localization       )            :: Localization
         integer                                :: PropertiesNumber = FillValueInt
         character(len=StringLength)            :: DataBaseFile
         logical                                :: TimeSerieON
         integer                                :: TimeSerie        = 0
         type(T_WaterFlow          )            :: WaterFlow   
         type(T_WaterVelocity      )            :: VelocityFlow
         type(T_FlowOver)                       :: FlowOver
         type(T_Property           ), pointer   :: FirstProperty
         type(T_Property           ), pointer   :: LastProperty
         type(T_IndividualDischarge), pointer   :: Next,Prev
    end type T_IndividualDischarge    

    type      T_Discharges
         integer                                :: InstanceID            
         integer                                :: ObjEnterData     = 0
         integer                                :: ObjTime          = 0
         character(len=Pathlength)              :: DataFile
         integer                                :: DischargesNumber= FillValueInt
         type (T_IndividualDischarge), pointer  :: FirstDischarge
         type (T_IndividualDischarge), pointer  :: LastDischarge
         type (T_Discharges), pointer           :: Next
    end type T_Discharges

    !Global Variables
    type (T_Discharges), pointer                :: FirstDischarges
    type (T_Discharges), pointer                :: Me
    
    !--------------------------------------------------------------------------

    contains

    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    !CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR CONSTRUCTOR 

    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    subroutine Construct_Discharges(DischargesID, ObjTime, DataFile, STAT)

        !Arguments--------------------------------------------------------------
        integer                                     :: DischargesID
        integer                                     :: ObjTime
        character(len=*), optional                  :: DataFile
        integer, optional, intent(OUT)              :: STAT

        !Local-----------------------------------------------------------------
        integer                                     :: ready_         
        integer                                     :: STAT_

        integer                                     :: STAT_CALL
                                 
        !----------------------------------------------------------------------

        STAT_ = UNKNOWN_

        !Assures nullification of the global variable
        if (.not. ModuleIsRegistered(mDischarges_)) then
            nullify (FirstDischarges)
            call RegisterModule (mDischarges_) 
        endif

        call Ready(DischargesID, ready_)    

cd0 :   if (ready_ .EQ. OFF_ERR_) then

            !Allocates Instance
            call AllocateInstance

            !Associates Time
            Me%ObjTime = AssociateInstance   (mTIME_, ObjTime)


            if (present(DataFile)) then
                Me%DataFile = DataFile
            else
                call ReadFileName('DISCHARG', Me%DataFile, Message = "Discharges Data File", STAT = STAT_CALL)
                if (STAT_CALL /= SUCCESS_) stop 'Construct_Discharges - ModuleDischarges - ERR01'
            endif
        
            ! Construct one instance to use the moduleEnterData
            call ConstructEnterData(Me%ObjEnterData, Me%DataFile, STAT = STAT_CALL)

cd1 :       if      ( STAT_CALL .EQ. FILE_NOT_FOUND_ERR_) then

                write(*,*    ) 
                write(*,*    ) 'Fatal error ! Discharges data file not found' 
                write(*,'(A)') 'File : ', trim(adjustl(Me%DataFile))
                write(*,*    ) 'look at DISCHARGES KeyWord at nomfich.dat file  '
                stop 'Construct_Discharges - ModuleDischarges - ERR01'  

            else if ((STAT_CALL .NE. FILE_NOT_FOUND_ERR_) .AND.                &
                     (STAT_CALL .NE. SUCCESS_          )) then cd1
                stop 'Subroutine Construct_Discharges; ModuleDischarges. ERR01.' 
            end if cd1



            ! Constructs the discharge list 
            call Construct_DischargeList


            !User Feed-Back
            call ConstructLog

            call KillEnterData  (Me%ObjEnterData, STAT = STAT_CALL)
            if (STAT_CALL  /= SUCCESS_) stop 'Construct_Discharges - ModuleDischarges - ERR02'

            !Returns ID
            DischargesID    = Me%InstanceID

            STAT_ = SUCCESS_
        else 

            stop 'ModuleDischarges - Construct_Discharges - ERR99' 

        end if cd0


        if (present(STAT)) STAT = STAT_

        !----------------------------------------------------------------------

    end Subroutine Construct_Discharges

    !--------------------------------------------------------------------------

    subroutine AllocateInstance

        !Arguments-------------------------------------------------------------

        !Local-----------------------------------------------------------------
        type (T_Discharges), pointer                :: NewDischarges
        type (T_Discharges), pointer                :: PreviousDischarges


        !Allocates new instance
        allocate (NewDischarges)
        nullify  (NewDischarges%Next)

        !Insert New Instance into list and makes Current point to it
        if (.not. associated(FirstDischarges)) then
            FirstDischarges         => NewDischarges
            Me                      => NewDischarges
        else
            PreviousDischarges      => FirstDischarges
            Me                      => FirstDischarges%Next
            do while (associated(Me))
                PreviousDischarges  => Me
                Me                  => Me%Next
            enddo
            Me                      => NewDischarges
            PreviousDischarges%Next => NewDischarges
        endif

        Me%InstanceID = RegisterNewInstance (mDISCHARGES_)

        ! Initialize the  discharges number   
        Me%DischargesNumber = 0

        ! Initialize the water discharges list   
        nullify (Me%FirstDischarge)
        nullify (Me%LastDischarge)

    end subroutine AllocateInstance

    !--------------------------------------------------------------------------

    subroutine Construct_DischargeList

        !Arguments-------------------------------------------------------------

        !External--------------------------------------------------------------
                                  
        integer :: STAT_CALL
        integer :: IDnumber 
        integer :: ClientNumber

        logical :: BlockFound
                                  
        !Local-----------------------------------------------------------------

        type (T_IndividualDischarge), pointer :: NewDischarge

        !----------------------------------------------------------------------

        IDnumber = 0

do1 :   do
            call ExtractBlockFromBuffer(Me%ObjEnterData, ClientNumber, &
                                        block_begin, block_end, BlockFound,       &
                                        STAT = STAT_CALL)

cd1 :       if      (STAT_CALL .EQ. SUCCESS_      ) then    
cd2 :           if (BlockFound) then                                  
                
                    ! Increments the number of Discharges
                    IDnumber = IDnumber + 1
                    ! Construct a New Property 
                    Call Construct_Discharge(NewDischarge, IDnumber, ClientNumber)
                                             

                    ! Add new Property to the discharge List 
                    Call Add_Discharge(NewDischarge)

                else
                    call Block_Unlock(Me%ObjEnterData, ClientNumber, STAT = STAT_CALL) 

                    if (STAT_CALL .NE. SUCCESS_)                               &
                        stop 'Subroutine Construct_DischargeList; ModuleDischarges. ERR01.'

                    exit do1    !No more blocks
                end if cd2

            else if (STAT_CALL .EQ. BLOCK_END_ERR_) then cd1
                stop 'Subroutine Construct_DischargeList; ModuleDischarges. ERR02.'
            end if cd1
        end do do1

        !----------------------------------------------------------------------

    end subroutine Construct_DischargeList

    !--------------------------------------------------------------------------


    !--------------------------------------------------------------------------
    !This subroutine reads all the information needed to construct a new property.           

    subroutine Construct_Discharge(NewDischarge, IDnumber, ClientNumber)

        !Arguments--------------------------------------------------------------
        type(T_IndividualDischarge), pointer        :: NewDischarge
        integer, intent(IN)                         :: ClientNumber
        integer, intent(IN)                         :: IDnumber 
         
        !----------------------------------------------------------------------


        allocate (NewDischarge)
        nullify  (NewDischarge%Next)
        nullify  (NewDischarge%Prev)


        nullify (NewDischarge%FirstProperty )
        nullify (NewDischarge%LastProperty  )

        !Construct Discharge ID
        call Construct_Discharge_ID           (NewDischarge, IDNumber)

        !Construct Discharge Localization
        call ConstDischargeLoc                (NewDischarge)

        !Read_DataBaseFile
        call Read_DataBaseFile                (NewDischarge)

        !Construct Discharge Flow values
        call Construct_FlowValues             (NewDischarge)

        !Construct Discharge Velocity values
        call Construct_VelocityValues         (NewDischarge)

        !Construct Property List
        call Construct_PropertyList           (NewDischarge, ClientNumber)

        !----------------------------------------------------------------------

    end subroutine Construct_Discharge

    !--------------------------------------------------------------------------



    !--------------------------------------------------------------------------
    ! This subroutine adds a new discharge to the discharge List  

    subroutine Add_Discharge(NewDischarge)

        !Arguments--------------------------------------------------------------
                
        type(T_IndividualDischarge), pointer :: NewDischarge

        !----------------------------------------------------------------------

        ! Add to the discharge list a new discharge
        if (.not.associated(Me%FirstDischarge)) then
            Me%DischargesNumber   = 1
            Me%FirstDischarge     => NewDischarge
            Me%LastDischarge      => NewDischarge
        else
            NewDischarge%Prev     => Me%LastDischarge
            Me%LastDischarge%Next => NewDischarge
            Me%LastDischarge      => NewDischarge
            Me%DischargesNumber   = Me%DischargesNumber + 1
        end if 

        !----------------------------------------------------------------------

    end subroutine Add_Discharge 

    !--------------------------------------------------------------------------



    !--------------------------------------------------------------------------
    !This subroutine reads all the information needed to construct the property ID          

    subroutine Construct_Discharge_ID(NewDischarge,IDNumber)
        
        !Arguments--------------------------------------------------------------
        type(T_IndividualDischarge), pointer    :: NewDischarge
        integer,                     intent(IN) :: IDnumber

        !External--------------------------------------------------------------

        !Local-----------------------------------------------------------------

        integer :: flag

        !----------------------------------------------------------------------
     


        ! The property ID number is incremented when a new discharge is created
        NewDischarge%ID%IDnumber = IDnumber 


        ! Property name and is units don't have a default value. The program stops when a
        ! is not sepecified the property name and untis 
        call GetData(NewDischarge%ID%name,                                              &
                     Me%ObjEnterData,                                                   &
                     flag,                                                              &
                     FromBlock,                                                         &
                     keyword='NAME',                                                    &
                     ClientModule = 'ModuleDischarges')

        if (flag==0) stop 'Discharges without name - Construct_Discharge'


        ! The property description is a character*132 where the user can
        ! store information about the property, example: 
        ! spring climatologic temperature field for the North Atlantic
        call GetData(NewDischarge%ID%Description,                                       &
                     Me%ObjEnterData,                                                   &
                     flag,                                                              &
                     FromBlock,                                                         &
                     keyword='DESCRIPTION',                                             &
                     default='No description was given.',                               &
                     ClientModule = 'ModuleDischarges')


        !----------------------------------------------------------------------

     end subroutine Construct_Discharge_ID

    !--------------------------------------------------------------------------



    !--------------------------------------------------------------------------

    Subroutine ConstDischargeLoc (NewDischarge)
        
        !Arguments--------------------------------------------------------------
        type(T_IndividualDischarge), pointer        :: NewDischarge

        !External--------------------------------------------------------------
        integer                                     :: STAT_CALL
        
        !Local-----------------------------------------------------------------

        integer                                     :: flag
        
        !----------------------------------------------------------------------

        !I Location
        call GetData(NewDischarge%Localization%GridCoordinates%I,                       &
                     Me%ObjEnterData,                                                   &
                     flag,                                                              &
                     FromBlock,                                                         &
                     keyword      ='I_CELL',                                            &
                     ClientModule = 'ModuleDischarges',                                 &
                     STAT         = STAT_CALL)
        if (STAT_CALL .NE. SUCCESS_) stop 'ConstDischargeLoc - ModuleDischarges - ERR10.'

        !When I_CELL is found, the model assumes that the discharge is grid based
        if (flag/=0) then
            NewDischarge%Localization%UsedWithGrid = .true.
        else
            NewDischarge%Localization%UsedWithGrid = .false.
        endif

        if (NewDischarge%Localization%UsedWithGrid) then

            !J Location
            call GetData(NewDischarge%Localization%GridCoordinates%J,                   &
                         Me%ObjEnterData,                                               &
                         flag,                                                          &
                         FromBlock,                                                     &
                         keyword      ='J_CELL',                                        &
                         ClientModule = 'ModuleDischarges',                             &
                         STAT         = STAT_CALL)

            if (STAT_CALL .NE. SUCCESS_)                                                &
                stop 'Subroutine ConstDischargeLoc; Module ModuleDischarges. ERR20.'
            if (flag==0)                                                                &
                stop 'Subroutine ConstDischargeLoc; Module ModuleDischarges. ERR30.'

            call GetData(NewDischarge%Localization%DischargeUniform,                    &
                         Me%ObjEnterData,                                               &
                         flag,                                                          &
                         FromBlock,                                                     &
                         keyword      ='DISCHARGE_UNIFORM',                             &
                         ClientModule = 'ModuleDischarges',                             &
                         default      = .false.,                                        &
                         STAT         = STAT_CALL)
            if (STAT_CALL .NE. SUCCESS_)                                                &
                stop 'Subroutine ConstDischargeLoc; Module ModuleDischarges. ERR40.'

            call GetData( NewDischarge%Localization%GridCoordinates%K,              &
                         Me%ObjEnterData,                                           &
                         flag,                                                      &
                         FromBlock,                                                 &
                         keyword      ='K_CELL',                                    &
                         ClientModule = 'ModuleDischarges',                         &
                         STAT         = STAT_CALL)
            if (STAT_CALL .NE. SUCCESS_)                                            &
                stop 'Subroutine ConstDischargeLoc; Module ModuleDischarges. ERR50.'



            !Searches for alternative locations. These are place where the discharge should
            !happen if the disharge location at a given time is not an open point.
            call GetData(NewDischarge%Localization%AlternativeLocations,                &
                         Me%ObjEnterData,                                               &
                         flag,                                                          &
                         FromBlock,                                                     &
                         keyword      ='ALTERNATIVE_LOCATIONS',                         &
                         ClientModule = 'ModuleDischarges',                             &
                         default      = .false.,                                        &
                         STAT         = STAT_CALL)
            if (STAT_CALL .NE. SUCCESS_)                                                &
                stop 'Subroutine ConstDischargeLoc; Module ModuleDischarges. ERR60.'

            if (NewDischarge%Localization%AlternativeLocations) then
                call GetData(NewDischarge%Localization%MinimumDischargeDepth,           &
                             Me%ObjEnterData,                                           &
                             flag,                                                      &
                             FromBlock,                                                 &
                             keyword      ='MINIMUM_DISCHARGE_DEPTH',                   &
                             ClientModule = 'ModuleDischarges',                         &
                             Default      = 1.0,                                        &
                             STAT         = STAT_CALL)
                if (STAT_CALL .NE. SUCCESS_)                                            &
                    stop 'Subroutine ConstDischargeLoc; Module ModuleDischarges. ERR70'

            endif    

        else

            !I Location
            call GetData(NewDischarge%Localization%NodeID,                              &
                         Me%ObjEnterData,                                               &
                         flag,                                                          &
                         FromBlock,                                                     &
                         keyword      ='NODE_ID',                                       &
                         ClientModule = 'ModuleDischarges',                             &
                         STAT         = STAT_CALL)
            if (STAT_CALL .NE. SUCCESS_) stop 'ConstDischargeLoc - ModuleDischarges - ERR80'
            

        endif


        !----------------------------------------------------------------------

     End Subroutine ConstDischargeLoc

    !--------------------------------------------------------------------------


    !--------------------------------------------------------------------------

    subroutine Read_DataBaseFile(NewDischarge)

        !Arguments-------------------------------------------------------------
        type(T_IndividualDischarge), pointer        :: NewDischarge

        !External--------------------------------------------------------------
        integer                                     :: flag, STAT_CALL

        !----------------------------------------------------------------------


        !Looks for a definition of the data base file. If there is one, this module assumes 
        !that the discharge is time variable
        call GetData(NewDischarge%DataBaseFile,                                         &
                     Me%ObjEnterData,                                                   &
                     flag,                                                              &
                     FromBlock,                                                         &
                     keyword      = 'DATA_BASE_FILE',                                   &
                     ClientModule = 'ModuleDischarges')

        if (flag == 1) then
            NewDischarge%TimeSerieON = .true.
        else 
            NewDischarge%TimeSerieON = .false.
        endif


        !Start TimeSerie Input
        if (NewDischarge%TimeSerieON) then
            call StartTimeSerieInput(NewDischarge%TimeSerie, NewDischarge%DataBaseFile,  &
                                     Me%ObjTime, STAT = STAT_CALL)
            if (STAT_CALL /= SUCCESS_) stop 'Read_DataBaseFile - ModuleDischarges - ERR01'
        end if 

        !----------------------------------------------------------------------

    end subroutine Read_DataBaseFile 

    !--------------------------------------------------------------------------


    !--------------------------------------------------------------------------
    
    subroutine Construct_FlowValues(NewDischarge)

        !Arguments--------------------------------------------------------------
        type(T_IndividualDischarge), pointer        :: NewDischarge

        !External-----------------------------------------------------------------
        integer                                     :: flag

        !----------------------------------------------------------------------


        !Searches for the default flow value, by default the value is zero
        call GetData(NewDischarge%WaterFlow%scalar,                                     &
                     Me%ObjEnterData,                                                   &
                     flag,                                                              &
                     FromBlock,                                                         &
                     keyword      ='DEFAULT_FLOW_VALUE',                                &
                     ClientModule = 'ModuleDischarges',                                 &
                     default      = 0.0)


        !Searches for the flow column (if the discharge is read from a data base)
        if (NewDischarge%TimeSerieON) then
            call GetData(NewDischarge%WaterFlow%FlowColumn,                              &
                         Me%ObjEnterData,                                                &
                         flag,                                                           &
                         FromBlock,                                                      &
                         keyword      ='FLOW_COLUMN',                                    &
                         ClientModule = 'ModuleDischarges')

            if (flag == 1) then
                NewDischarge%WaterFlow%Variable = .true.            
            else
                NewDischarge%WaterFlow%Variable = .false.            
            endif

        endif


        !Check if the discharge is of the type flow over
        call GetData(NewDischarge%FlowOver%On,                                       &
                     Me%ObjEnterData,                                                &
                     flag,                                                           &
                     FromBlock,                                                      &
                     keyword      ='FLOW_OVER',                                      &
                     ClientModule = 'ModuleDischarges',                              &
                     default      = .false.)

        if (NewDischarge%FlowOver%On) then

            call GetData(NewDischarge%FlowOver%WeirLength,                           &
                         Me%ObjEnterData,                                            &
                         flag,                                                       &
                         FromBlock,                                                  &
                         keyword      ='WEIR_LENGTH',                                &
                         ClientModule = 'ModuleDischarges')
            if (flag /= 1) then
                write(*,*) 'Weir Length Missing'
                stop ' Construct_FlowValues - ModuleDischarges - ERR02'
            endif

            call GetData(NewDischarge%FlowOver%DischargeCoeficient,                  &
                         Me%ObjEnterData,                                            &
                         flag,                                                       &
                         FromBlock,                                                  &
                         keyword      ='WEIR_COEF',                                  &
                         ClientModule = 'ModuleDischarges',                          &
                         default      = 0.4)

            call GetData(NewDischarge%FlowOver%CrestHeigth,                          &
                         Me%ObjEnterData,                                            &
                         flag,                                                       &
                         FromBlock,                                                  &
                         keyword      ='CREST_HEIGTH',                               &
                         ClientModule = 'ModuleDischarges')
            if (flag /= 1) then
                write(*,*) 'Crest Height Missing'
                stop ' Construct_FlowValues - ModuleDischarges - ERR03'
            endif

        endif
            
        !----------------------------------------------------------------------

     End Subroutine Construct_FlowValues  

    !--------------------------------------------------------------------------

    !--------------------------------------------------------------------------

     Subroutine Construct_VelocityValues(NewDischarge)

        !Arguments--------------------------------------------------------------
        type(T_IndividualDischarge), pointer        :: NewDischarge

        !External-----------------------------------------------------------------
        integer                                     :: STAT_CALL
        integer                                     :: flag
        real, dimension(:), pointer                 :: Aux 

        !----------------------------------------------------------------------


        !By default the property value in the domain is zero
        allocate(aux(2))
        call GetData(Aux, Me%ObjEnterData, flag,                                         &
                     keyword    = 'DEFAULT_VELOCITY_VALUE',                              &
                     default    = 0.,                                                    &
                     SearchType = FromBlock,                                             &
                     ClientModule = 'ModuleDischarges',                                  &
                     STAT       = STAT_CALL)

        NewDischarge%VelocityFlow%UScalar = Aux(1)
        NewDischarge%VelocityFlow%VScalar = Aux(2)
        deallocate(aux)

        !Searches for the velocity U column (if the discharge is read from a data base)
        if (NewDischarge%TimeSerieON) then
            call GetData(NewDischarge%VelocityFlow%UColumn,                              &
                         Me%ObjEnterData, flag,                                          &
                         keyword    = 'U_COLUMN',                                        &
                         default    = FillValueInt,                                      &
                         SearchType = FromBlock,                                         &
                         ClientModule = 'ModuleDischarges',                              &
                         STAT       = STAT_CALL)

            if (flag == 1) then
                NewDischarge%VelocityFlow%UVariable = .true.            
            else
                NewDischarge%VelocityFlow%UVariable = .false.            
            endif

            call GetData(NewDischarge%VelocityFlow%VColumn,                              &
                         Me%ObjEnterData, flag,                                          &
                         keyword    = 'V_COLUMN',                                        &
                         default    = FillValueInt,                                      &
                         SearchType = FromBlock,                                         &
                         ClientModule = 'ModuleDischarges',                              &
                         STAT       = STAT_CALL)

            if (flag == 1) then
                NewDischarge%VelocityFlow%VVariable = .true.
            else
                NewDischarge%VelocityFlow%VVariable = .false.
            endif

        endif

        !----------------------------------------------------------------------

    end subroutine Construct_VelocityValues

    !--------------------------------------------------------------------------

    subroutine Construct_PropertyList(NewDischarge, ClientNumber)

        !Arguments--------------------------------------------------------------
        type(T_IndividualDischarge), pointer        :: NewDischarge
        integer, intent(IN)                         :: ClientNumber

        !External--------------------------------------------------------------
        logical                                     :: BlockFound
        integer                                     :: STAT_CALL

        !Local-----------------------------------------------------------------
        type (T_Property), pointer                  :: NewProperty

        !----------------------------------------------------------------------

do1 :   do
            call ExtractBlockFromBlock(Me%ObjEnterData, ClientNumber,            &
                                       beginproperty, endproperty, BlockFound,   &
                                       STAT = STAT_CALL)

cd1 :       if      (STAT_CALL .EQ. SUCCESS_      ) then    
cd2 :           if (BlockFound) then                                                  
                    ! Construct a New Property 
                    call Construct_Property(NewDischarge,NewProperty)

                    ! Add new Property to the WaterProperties List 
                    call Add_Property(NewDischarge,NewProperty)
                else
                    exit do1    !No more blocks
                end if cd2

            else if (STAT_CALL .EQ. BLOCK_END_ERR_) then cd1
                stop 'Subroutine Construct_PropertyList; ModuleDischarges. ERR02.'
            end if cd1
        end do do1

        !----------------------------------------------------------------------

    end subroutine Construct_PropertyList

    !--------------------------------------------------------------------------


    !--------------------------------------------------------------------------
    !This subroutine reads all the information needed to construct a new property.           

    subroutine Construct_Property(NewDischarge,NewProperty)

        !Arguments--------------------------------------------------------------
        type(T_property), pointer                   :: NewProperty
        type(T_IndividualDischarge), pointer        :: NewDischarge
        !----------------------------------------------------------------------

        allocate(NewProperty)

        nullify (NewProperty%Prev,NewProperty%Next)


        !Construct property ID
        call ConstructPropertyID     (NewProperty%ID, Me%ObjEnterData, FromBlockInBlock)


        !Construct property values
        call Construct_PropertyValues(NewDischarge, NewProperty)

        !----------------------------------------------------------------------

    end subroutine Construct_Property

    !--------------------------------------------------------------------------
    !This subroutine reads all the information needed to construct the property values       
    ! in the domain and in the boundaries            

    subroutine Construct_PropertyValues(NewDischarge,NewProperty)

        !Arguments--------------------------------------------------------------
        type(T_IndividualDischarge), pointer        :: NewDischarge
        type(T_property),   pointer                 :: NewProperty

        !External-----------------------------------------------------------------

        integer          :: flag

        !----------------------------------------------------------------------

        !By default the property value in the domain is zero
        call GetData(NewProperty%scalar,                                                 &
                     Me%ObjEnterData,                                                    &
                     flag,                                                               &
                     FromBlockinBlock,                                                   &
                     keyword      ='DEFAULTVALUE',                                       &
                     ClientModule ='ModuleDischarges',                                   &
                     default      = 0.0)
                     
        if((.not. NewDischarge%TimeSerieON) .and. (flag .eq. 0))then
            write(*,*)"Please define concentration default value for property :"
            write(*,*)trim(NewProperty%ID%Name)
            write(*,*)"Discharge name : ", trim(NewDischarge%ID%Name)
            stop 'Construct_PropertyValues - ModuleDischarges -  ERR01'
        end if
        
        if (NewDischarge%TimeSerieON) then
            call GetData(NewProperty%ConcColumn,                                         &
                         Me%ObjEnterData,                                                &
                         flag,                                                           &
                         FromBlockinBlock,                                               &
                         keyword      ='TIME_SERIE_COLUMN',                              &
                         ClientModule ='ModuleDischarges')

            if (flag == 1) then
                NewProperty%Variable = .true.
            else
                NewProperty%Variable = .false.
            endif

        endif

        !----------------------------------------------------------------------

    end subroutine Construct_PropertyValues

    !--------------------------------------------------------------------------


    !--------------------------------------------------------------------------
    ! This subroutine adds a new property to the Water Property List  

    subroutine Add_Property(NewDischarge,NewProperty)

        !Arguments 
          
        type(T_IndividualDischarge), pointer    :: NewDischarge
        type(T_property),            pointer    :: NewProperty


        !----------------------------------------------------------------------

        ! Add to the WaterProperty List a new property
        if (.not.associated(NewDischarge%FirstProperty)) then
            NewDischarge%PropertiesNumber = 1
            NewDischarge%FirstProperty    => NewProperty
            NewDischarge%LastProperty     => NewProperty
        else
            NewProperty%Prev                     => NewDischarge%LastProperty
            NewDischarge%LastProperty%Next => NewProperty
            NewDischarge%LastProperty      => NewProperty
            NewDischarge%PropertiesNumber  = &
                   NewDischarge%PropertiesNumber + 1
        end if 

        !----------------------------------------------------------------------

    end subroutine Add_Property 

    !--------------------------------------------------------------------------

    subroutine ConstructLog

        !Arguments-------------------------------------------------------------

        !Local-----------------------------------------------------------------
        type(T_IndividualDischarge), pointer        :: CurrentDischarge

        write(*, *)"----------------------- DISCHARGES -----------------------"
        write(*, *)
        write(*, *)"Number of Discharges : ", Me%DischargesNumber
        write(*, *)

        CurrentDischarge => Me%FirstDischarge
        do while (associated (CurrentDischarge))
            write(*, *)"----Discharge        : ", trim(adjustl(CurrentDischarge%ID%Name))
            write(*, *)"----Num of Properties: ", max(CurrentDischarge%PropertiesNumber, 0)
            CurrentDischarge => CurrentDischarge%Next
        enddo


    end subroutine ConstructLog



    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    !SELECTOR SELECTOR SELECTOR SELECTOR SELECTOR SELECTOR SELECTOR SELECTOR 

    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                            
    !--------------------------------------------------------------------------

    Subroutine GetDischargesNumber(DischargesID, DischargesNumber, STAT)

        !Arguments--------------------------------------------------------------
        integer                                     :: DischargesID
        integer,           intent(OUT)              :: DischargesNumber
        integer, optional, intent(OUT)              :: STAT

        !Local-----------------------------------------------------------------
        integer                                     :: ready_         
        integer                                     :: STAT_
 
        !----------------------------------------------------------------------

        STAT_ = UNKNOWN_

        call Ready(DischargesID, ready_)    
        
cd1 :   if ((ready_ .EQ. IDLE_ERR_     ) .OR.                                  &
            (ready_ .EQ. READ_LOCK_ERR_)) then
           
            DischargesNumber = Me%DischargesNumber

            STAT_ = SUCCESS_
        else 
            STAT_ = ready_
        end if cd1


        if (present(STAT))                                                    &
            STAT = STAT_

        !----------------------------------------------------------------------

    end Subroutine GetDischargesNumber

    !--------------------------------------------------------------------------

    subroutine GetDischargesGridLocalization(DischargesID, DischargeIDNumber, Igrid,    &
                                             JGrid, KGrid, DischargeUniform,            &
                                             WaterColumnZ, Batimetry, OpenPoints3D, STAT)

        !Arguments-------------------------------------------------------------
        integer                                         :: DischargesID
        integer,           intent(IN )                  :: DischargeIDNumber
        integer, optional, intent(OUT)                  :: IGrid, JGrid, KGrid
        logical, optional, intent(OUT)                  :: DischargeUniform
        integer, optional, dimension(:, :, :), pointer  :: OpenPoints3D
        real   , optional, dimension(:, :   ), pointer  :: WaterColumnZ
        real   , optional, dimension(:, :   ), pointer  :: Batimetry        

        integer, optional, intent(OUT)                  :: STAT

        !External--------------------------------------------------------------
        integer                                         :: STAT_CALL
        type(T_IndividualDischarge), pointer            :: DischargeX

        !Local-----------------------------------------------------------------
        integer                                         :: ready_         
        integer                                         :: STAT_
        type (T_GridCoordinates)                        :: CurrentLocation
        integer                                         :: WorkSizeILB, WorkSizeIUB, i
        integer                                         :: WorkSizeJLB, WorkSizeJUB, j
        integer                                         :: k
        integer                                         :: MoveDirection
        logical                                         :: NewLocationFound
        integer, parameter                              :: NONE_    = 1
        integer, parameter                              :: NORTH_   = 2
        integer, parameter                              :: EAST_    = 3
        integer, parameter                              :: SOUTH_   = 4
        integer, parameter                              :: WEST_    = 5
        real                                            :: Depth, DepthCurrent
        real                                            :: Bottom, BtomCurrent
        logical, dimension(:,:), allocatable            :: PossibleDischargePoint

        !----------------------------------------------------------------------

        STAT_ = UNKNOWN_

        call Ready(DischargesID, ready_)    
        
cd1 :   if ((ready_ .EQ. IDLE_ERR_     ) .OR.                                  &
            (ready_ .EQ. READ_LOCK_ERR_)) then

            call Search_Discharge(DischargeX, STAT_CALL, DischargeXIDNumber=DischargeIDNumber)
            if (STAT_CALL/=SUCCESS_) then 
                write(*,*) 'Can not find discharge number ', DischargeIDNumber, '.'
                stop       'Subroutine GetDischargesGridLocalization; Module ModuleDischarges. ERR01.'
            endif

            if (.not. DischargeX%Localization%UsedWithGrid) then
                write(*,*)'Discharge location not given in Grid Coordinates'
                write(*,*)trim(adjustl(DischargeX%ID%Name))
                stop 'GetDischargesGridLocalization - ModuleDischarges - ERR01a'
            endif

            if (present(IGrid           )) IGrid              = DischargeX%Localization%GridCoordinates%I
            if (present(JGrid           )) JGrid              = DischargeX%Localization%GridCoordinates%J
            if (present(KGrid           )) KGrid              = DischargeX%Localization%GridCoordinates%K
            if (present(DischargeUniform)) DischargeUniform   = DischargeX%Localization%DischargeUniform

            !If OpenPoints is present an DischargeX have alternative locations, 
            !check out which locations to use.
            if (present(WaterColumnZ)) then

                WorkSizeILB = lbound(WaterColumnZ, dim = 1) + 1
                WorkSizeIUB = ubound(WaterColumnZ, dim = 1) - 1

                WorkSizeJLB = lbound(WaterColumnZ, dim = 2) + 1
                WorkSizeJUB = ubound(WaterColumnZ, dim = 2) - 1

                if (IGrid < WorkSizeILB .or. IGrid > WorkSizeIUB)                       &
                    stop  'GetDischargesGridLocalization; ModuleDischarges. ERR02.'

                if (JGrid < WorkSizeJLB .or. JGrid > WorkSizeJUB)                       &
                    stop  'GetDischargesGridLocalization; ModuleDischarges. ERR03.'
                
                if (WaterColumnZ(IGrid, JGrid) <                                        &
                    DischargeX%Localization%MinimumDischargeDepth .and.                 &
                    DischargeX%Localization%AlternativeLocations) then                    

                    !Allocates temporary Matrix of possible discharge points
                    allocate(PossibleDischargePoint(WorkSizeILB:WorkSizeIUB,             &
                                                    WorkSizeJLB:WorkSizeJUB))
                    PossibleDischargePoint = .true.

                    !Search the lowest point in the sourring points
                    CurrentLocation  = DischargeX%Localization%GridCoordinates
                    NewLocationFound = .false.
                    i = CurrentLocation%I
                    j = CurrentLocation%J
                    k = CurrentLocation%K
                    
                    DepthCurrent  = WaterColumnZ(i, j)
                    BtomCurrent   = Batimetry   (i, j)

                    PossibleDischargePoint(i, j) = .false.

                    do while (.not. NewLocationFound)

                        MoveDirection = NONE_                    
                            
                            if (OpenPoints3D(i,j,k) == OpenPoint) then
                            !neste caso compara-se as colunas de agua 
                                
                                !Point in the North
                                if (i < WorkSizeIUB) then
                            
                                    Depth = WaterColumnZ(i+1, j)                               
                                    if (Depth >= DepthCurrent .and. PossibleDischargePoint(i+1, j)) then
                                        MoveDirection = NORTH_
                                        DepthCurrent  = Depth
                                    endif

                                endif

                                !Point in the East
                                if (j < WorkSizeJUB) then
                                    Depth = WaterColumnZ(i, j+1)
                                    if (Depth >= DepthCurrent .and. PossibleDischargePoint(i, j+1)) then
                                        MoveDirection = EAST_
                                        DepthCurrent  = Depth
                                    endif
                                endif

                                !Point in the South
                                if (i > WorkSizeILB) then
                                    Depth = WaterColumnZ(i-1, j)
                                    if (Depth >= DepthCurrent .and. PossibleDischargePoint(i-1, j)) then
                                        MoveDirection = SOUTH_
                                        DepthCurrent  = Depth
                                    endif
                                endif

                                !Point in the West
                                if (j > WorkSizeJLB) then
                                    Depth = WaterColumnZ(i, j-1)
                                    if (Depth >= DepthCurrent .and. PossibleDischargePoint(i, j-1)) then
                                        MoveDirection = WEST_
                                        DepthCurrent  = Depth
                                    endif
                                endif

                            else
                            !neste caso comparam-se as cotas (os openpoints n ficam todos bem com a minWC)
                                
                                !Point in the North
                                if (i < WorkSizeIUB) then
                            
                                    Bottom = Batimetry(i+1, j)                               
                                    if (Bottom >= BtomCurrent .and. PossibleDischargePoint(i+1, j)) then
                                        MoveDirection = NORTH_
                                        BtomCurrent   = Bottom
                                    endif

                                endif

                                !Point in the East
                                if (j < WorkSizeJUB) then
                                    Bottom = Batimetry(i, j+1)
                                    if (Bottom >= BtomCurrent .and. PossibleDischargePoint(i, j+1)) then
                                        MoveDirection = EAST_
                                        BtomCurrent   = Bottom
                                    endif
                                endif

                                !Point in the South
                                if (i > WorkSizeILB) then
                                    Bottom = Batimetry(i-1, j)
                                    if (Bottom >= BtomCurrent .and. PossibleDischargePoint(i-1, j)) then
                                        MoveDirection = SOUTH_
                                        BtomCurrent   = Bottom
                                    endif
                                endif

                                !Point in the West
                                if (j > WorkSizeJLB) then
                                    Bottom = Batimetry (i, j-1)
                                    if (Bottom >= BtomCurrent .and. PossibleDischargePoint(i, j-1)) then
                                        MoveDirection = WEST_
                                        BtomCurrent   = Bottom
                                    endif
                                endif

                            endif                           

                                            
                        select case (MoveDirection)

                            case (NORTH_)
                                i = i + 1
                                PossibleDischargePoint(i, j) = .false.

                            case (EAST_ )
                                j = j + 1
                                PossibleDischargePoint(i, j) = .false.

                            case (SOUTH_)
                                i = i - 1
                                PossibleDischargePoint(i, j) = .false.

                            case (WEST_ )
                                j = j - 1
                                PossibleDischargePoint(i, j) = .false.

                            case (NONE_)
                                NewLocationFound = .true.
                                IGrid            = i
                                JGrid            = j

                        end select

                        !Checks out if the new defined point is an openpoint
                        if (WaterColumnZ(i, j) > DischargeX%Localization%MinimumDischargeDepth) then
                            NewLocationFound = .true.
                            IGrid            = i
                            JGrid            = j
                        endif

                    enddo

                    !Deallocates temporary matrix
                    deallocate(PossibleDischargePoint)

                endif
            endif

            STAT_ = SUCCESS_
        else 
            STAT_ = ready_
        end if cd1


        if (present(STAT)) STAT = STAT_

        !----------------------------------------------------------------------

    end subroutine GetDischargesGridLocalization

    !--------------------------------------------------------------------------

    subroutine GetDischargesNodeID (DischargesID, DischargeIDNumber, NodeID, STAT)

        !Arguments-------------------------------------------------------------
        integer                                         :: DischargesID
        integer,           intent(IN )                  :: DischargeIDNumber
        integer,           intent(OUT)                  :: NodeID
        integer, optional, intent(OUT)                  :: STAT

        !Local-----------------------------------------------------------------
        integer                                         :: STAT_CALL, ready_, STAT_
        type(T_IndividualDischarge), pointer            :: DischargeX


        call Ready(DischargesID, ready_)    
        
cd1 :   if ((ready_ .EQ. IDLE_ERR_     ) .OR.                                  &
            (ready_ .EQ. READ_LOCK_ERR_)) then

            call Search_Discharge(DischargeX, STAT_CALL, DischargeXIDNumber=DischargeIDNumber)
            if (STAT_CALL/=SUCCESS_) then 
                write(*,*) 'Can not find discharge number ', DischargeIDNumber
                stop       'GetDischargesGridLocalization - ModuleDischarges - ERR01'
            endif

            if (DischargeX%Localization%UsedWithGrid) then
                write(*,*)'Discharge location not given as Node ID'
                write(*,*)trim(adjustl(DischargeX%ID%Name))
                stop 'GetDischargesGridLocalization - ModuleDischarges - ERR01a'
            endif

            NodeID = DischargeX%Localization%NodeID

            STAT_ = SUCCESS_
        else 
            STAT_ = ready_
        end if cd1


        if (present(STAT))  STAT = STAT_


    end subroutine GetDischargesNodeID

    !--------------------------------------------------------------------------


    !--------------------------------------------------------------------------

    Subroutine GetDischargeWaterFlow(DischargesID, TimeX, DischargeIDNumber,  &
                                     SurfaceElevation, Flow, STAT)

        !Arguments-------------------------------------------------------------
        integer                                     :: DischargesID
        type(T_Time),                   intent(IN ) :: TimeX
        integer,                        intent(IN ) :: DischargeIDNumber
        real,                           intent(IN)  :: SurfaceElevation
        real,                           intent(OUT) :: Flow
        integer, optional,              intent(OUT) :: STAT

        !Local-----------------------------------------------------------------
        integer                                     :: ready_
        integer                                     :: STAT_
        type(T_IndividualDischarge), pointer        :: DischargeX
        type(T_Time)                                :: Time1, Time2
        real                                        :: Value1, Value2, NewValue
        logical                                     :: TimeCycle
        integer                                     :: STAT_CALL

        !----------------------------------------------------------------------

        STAT_ = UNKNOWN_

        call Ready(DischargesID, ready_)    
        
cd1 :   if ((ready_ .EQ. IDLE_ERR_     ) .OR.                                  &
            (ready_ .EQ. READ_LOCK_ERR_)) then



            call Search_Discharge(DischargeX, STAT_CALL, DischargeXIDNumber=DischargeIDNumber)

cd3 :       if (STAT_CALL/=SUCCESS_) then 
                write(*,*) ' can not find discharge number ',DischargeIDNumber
                    stop       'Subroutine GetDischargeWaterFlow; Module ModuleDischarges. ERR01.'
            end if cd3


cd2:        if (DischargeX%WaterFlow%Variable) then

                call GetTimeSerieValue(DischargeX%TimeSerie, TimeX,                      &
                                       DischargeX%WaterFlow%FlowColumn, Time1, Value1,   &
                                       Time2, Value2, TimeCycle, STAT)

                if (TimeCycle) then
                    NewValue = Value1
                else
                    !Interpolates Value for current instant
                    call InterpolateValueInTime(TimeX, Time1, Value1, Time2, Value2,     &
                                                NewValue)
                endif

                Flow = NewValue

            elseif (DischargeX%FlowOver%On) then

                !Q = cv * b * sqrt(2*g) * H^(1.5)
                if (SurfaceElevation > DischargeX%FlowOver%CrestHeigth) then
                    Flow = -sqrt(19.6) * DischargeX%FlowOver%DischargeCoeficient *       &
                                         DischargeX%FlowOver%WeirLength          *       &
                           (SurfaceElevation - DischargeX%FlowOver%CrestHeigth) ** 1.5
                else
                    Flow = 0.
                endif

            else

                Flow = DischargeX%WaterFlow%Scalar

            end if cd2

            nullify(DischargeX)


            STAT_ = SUCCESS_
        else 
            STAT_ = ready_
        end if cd1


        if (present(STAT))                                                    &
            STAT = STAT_

        !----------------------------------------------------------------------

    end Subroutine GetDischargeWaterFlow

    !--------------------------------------------------------------------------

    !--------------------------------------------------------------------------

    subroutine GetDischargeFlowVelocity(DischargesID, TimeX, DischargeIDNumber,          &
                                        VelocityU, VelocityV ,STAT)

        !Arguments-------------------------------------------------------------
        integer                                     :: DischargesID
        real,    optional, intent(OUT)              :: VelocityU, VelocityV
        integer, optional, intent(OUT)              :: STAT
        integer,           intent(IN )              :: DischargeIDNumber
        type(T_Time),      intent(IN )              :: TimeX

        !Local-----------------------------------------------------------------
        integer                                     :: ready_         
        integer                                     :: STAT_
        type(T_IndividualDischarge), pointer        :: DischargeX
        type(T_Time)                                :: Time1, Time2
        real                                        :: Value1, Value2, NewValue
        logical                                     :: TimeCycle
        integer                                     :: STAT_CALL

        !----------------------------------------------------------------------

        STAT_ = UNKNOWN_

        call Ready(DischargesID, ready_)    
        
cd1 :   if ((ready_ .EQ. IDLE_ERR_     ) .OR.                                            &
            (ready_ .EQ. READ_LOCK_ERR_)) then

            if (.not. present(VelocityU) .and. .not. present(VelocityV))                 &
                stop 'Subroutine GetDischargeFlowVelocity; Module ModuleDischarges. ERR01.'

            call Search_Discharge(DischargeX, STAT_CALL, DischargeXIDNumber = DischargeIDNumber)
                

cd3 :       if (STAT_CALL /= SUCCESS_) then 
                write(*,*) ' can not find discharge number ',DischargeIDNumber
                    stop 'Subroutine GetDischargeFlowVelocity; Module ModuleDischarges. ERR02.'
            end if cd3


cd4 :       if (Present(VelocityU)) then 

cd2:            if (DischargeX%VelocityFlow%UVariable) then

                    call GetTimeSerieValue(DischargeX%TimeSerie, TimeX,                      &
                                           DischargeX%VelocityFlow%UColumn, Time1, Value1,   &
                                           Time2, Value2, TimeCycle, STAT)

                    if (TimeCycle) then
                        NewValue = Value1
                    else
                        !Interpolates Value for current instant
                        call InterpolateValueInTime(TimeX, Time1, Value1, Time2, Value2,     &
                                                    NewValue)
                    endif

                    VelocityU = NewValue

                else

                    VelocityU = DischargeX%VelocityFlow%UScalar

                end if cd2

            endif cd4

cd5 :       if (Present(VelocityV)) then 

cd6:            if (DischargeX%VelocityFlow%VVariable) then

                    call GetTimeSerieValue(DischargeX%TimeSerie, TimeX,                      &
                                           DischargeX%VelocityFlow%VColumn, Time1, Value1,   &
                                           Time2, Value2, TimeCycle, STAT)

                    if (TimeCycle) then
                        NewValue = Value1
                    else
                        !Interpolates Value for current instant
                        call InterpolateValueInTime(TimeX, Time1, Value1, Time2, Value2,     &
                                                    NewValue)
                    endif

                    VelocityV = NewValue

                else
                    VelocityV = DischargeX%VelocityFlow%VScalar

                end if cd6

            endif cd5


            nullify(DischargeX)

            STAT_ = SUCCESS_
        else 
            STAT_ = ready_
        end if cd1


        if (present(STAT))                                                    &
            STAT = STAT_

        !----------------------------------------------------------------------

    end subroutine GetDischargeFlowVelocity

    !--------------------------------------------------------------------------

    subroutine GetDischargeConcentration(DischargesID, TimeX,DischargeIDNumber,          &
                                         Concentration, PropertyIDNumber, STAT)

        !Arguments-------------------------------------------------------------
        integer                                     :: DischargesID
        type(T_Time),      intent(IN)               :: TimeX
        integer,           intent(IN)               :: DischargeIDNumber
        real,              intent(OUT)              :: Concentration
        integer,           intent(IN)               :: PropertyIDNumber
        integer, optional, intent(OUT)              :: STAT

        !Local-----------------------------------------------------------------
        type(T_IndividualDischarge), pointer        :: DischargeX
        type(T_Property),            pointer        :: PropertyX
        type(T_Time)                                :: Time1, Time2
        real                                        :: Value1, Value2, NewValue
        logical                                     :: TimeCycle
        integer                                     :: ready_
        integer                                     :: STAT_
        integer                                     :: STAT_CALL

        !----------------------------------------------------------------------

        STAT_ = UNKNOWN_

        call Ready(DischargesID, ready_)    
        
cd1 :   if ((ready_ .EQ. IDLE_ERR_     ) .OR.                                  &
            (ready_ .EQ. READ_LOCK_ERR_)) then

            call Search_Discharge(DischargeX, STAT_CALL, DischargeXIDNumber=DischargeIDNumber)

            if (STAT_CALL/=SUCCESS_) then 
                write(*,*) ' can not find discharge number ',DischargeIDNumber
                stop  'Sub. GetDischargeConcentration - ModuleDischarges - ERR01'
            endif
             

            call Search_Property(DischargeX, PropertyX, STAT_CALL, PropertyXIDNumber=PropertyIDNumber)

            if (STAT_CALL/=SUCCESS_) then 
                !If the proeprty is not found the program don't stop is return a error 
                !not found
                if (STAT_CALL /= NOT_FOUND_ERR_) then 
                    stop  'Sub. GetDischargeConcentration - ModuleDischarges - ERR05'
                endif

            endif


            
cd2 :       if (STAT_CALL == SUCCESS_) then
                                                                         
                if (PropertyX%Variable) then

                    call GetTimeSerieValue(DischargeX%TimeSerie, TimeX,                  &
                                           PropertyX%ConcColumn, Time1, Value1,          &
                                           Time2, Value2, TimeCycle, STAT)

                    if (TimeCycle) then
                        NewValue = Value1
                    else
                        !Interpolates Value for current instant
                        call InterpolateValueInTime(TimeX, Time1, Value1, Time2, Value2, &
                                                    NewValue)
                    endif

                    Concentration = NewValue

                else
 
                    Concentration = PropertyX%Scalar

                endif
             

                nullify(PropertyX)

                nullify(DischargeX)

                STAT_ = SUCCESS_

            else if (STAT_CALL == NOT_FOUND_ERR_) then cd2


                nullify(PropertyX)

                nullify(DischargeX)

                STAT_ = NOT_FOUND_ERR_


            end if cd2
            

        else 

            STAT_ = ready_

        end if cd1


        if (present(STAT))                                                    &
            STAT = STAT_

        !----------------------------------------------------------------------

    end Subroutine GetDischargeConcentration

    !--------------------------------------------------------------------------



    !--------------------------------------------------------------------------

    subroutine Search_Discharge(DischargeX, STAT_, DischargeXIDNumber)

        !Arguments--------------------------------------------------------------
        type(T_IndividualDischarge),  pointer         :: DischargeX
        integer,                      intent (OUT)    :: STAT_
        integer,                      intent (IN)     :: DischargeXIDNumber

        !Begin-----------------------------------------------------------------

        STAT_  = NOT_FOUND_ERR_

        DischargeX => Me%FirstDischarge

        do while (associated(DischargeX)) 
            if (DischargeX%ID%IDNumber==DischargeXIDNumber) then
                STAT_ = SUCCESS_
                exit
            else
                DischargeX => DischargeX%Next
            endif
        enddo

    end subroutine Search_Discharge

    !--------------------------------------------------------------------------

    subroutine Search_Property(DischargeX, PropertyX, STAT_, PropertyXIDNumber)

        !External--------------------------------------------------------------

        type(T_IndividualDischarge),pointer           :: DischargeX
        type(T_Property),           pointer           :: PropertyX
        integer         ,           intent (OUT)      :: STAT_
        integer         ,           intent (IN)       :: PropertyXIDNumber

        !Local-----------------------------------------------------------------

        !----------------------------------------------------------------------

        STAT_  = UNKNOWN_

        PropertyX => DischargeX%FirstProperty

        do while (associated(PropertyX)) 
           if (PropertyX%ID%IDNumber==PropertyXIDNumber) then
               exit
           else
               PropertyX => PropertyX%Next                 
           endif
        enddo

        if (associated(PropertyX)) then

                   STAT_ = SUCCESS_ ! The PropertyX was found
        else
                   STAT_  = NOT_FOUND_ERR_ ! The PropertyX wasn't found
                
        endif

        !----------------------------------------------------------------------
      
    end subroutine Search_Property

    !--------------------------------------------------------------------------
  
    subroutine GetDischargeParameters (DirectionX, DirectionY)

        !Arguments-------------------------------------------------------------

        integer, optional, intent(OUT) :: DirectionX      
        integer, optional, intent(OUT) :: DirectionY       
    
        !----------------------------------------------------------------------

        if (present(DirectionX           )) DirectionX        = DirectionX_
        if (present(DirectionY           )) DirectionY        = DirectionY_
                                                         
        !----------------------------------------------------------------------

    end subroutine GetDischargeParameters

    !--------------------------------------------------------------------------

    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    !DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR  

    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    subroutine Kill_Discharges(DischargesID, STAT)

        !Arguments-------------------------------------------------------------
        integer                                     :: DischargesID
        integer, optional, intent(OUT)              :: STAT

        !Local-----------------------------------------------------------------
        integer                                     :: ready_, STAT_            
        type(T_IndividualDischarge), pointer        :: DischargeX, DischargeToKill
        integer                                     :: nUsers

        !----------------------------------------------------------------------

        STAT_ = UNKNOWN_

        call Ready(DischargesID, ready_)    

cd1 :   if (ready_ .NE. OFF_ERR_) then

            nUsers = DeassociateInstance(mDISCHARGES_,  Me%InstanceID)
  
            if (nUsers == 0) then
                
                nUsers = DeassociateInstance (mTIME_, Me%ObjTime)
                if (nUsers == 0) stop 'Kill_Discharges - ModuleDischarges - ERR01'

                ! Deallocates all the Discharges
                DischargeX=> Me%FirstDischarge

                do while(associated(DischargeX))  

                    DischargeToKill => DischargeX
                    DischargeX      => DischargeX%Next
                    call KillIndividualDischarge(DischargeToKill)

                end do
                nullify   (Me%FirstDischarge,Me%LastDischarge)

                call DeallocateInstance

                DischargesID = 0
            
                STAT_ = SUCCESS_
            
            end if

        else 

            STAT_ = ready_

        end if cd1


        if (present(STAT)) STAT = STAT_

        !----------------------------------------------------------------------

    end subroutine Kill_Discharges

    !--------------------------------------------------------------------------

    subroutine KillIndividualDischarge(DischargeToDelete)

        !Arguments-------------------------------------------------------------
        type(T_IndividualDischarge), pointer        :: DischargeToDelete

        !Local-----------------------------------------------------------------
        type(T_IndividualDischarge), pointer        :: CurrentDischarge
        type(T_IndividualDischarge), pointer        :: Prev
        type(T_IndividualDischarge), pointer        :: Next
        type(T_Property           ), pointer        :: PropertyX
        integer                                     :: STAT_CALL


        CurrentDischarge => Me%FirstDischarge

        do 
            if (CurrentDischarge%ID%IDnumber == DischargeToDelete%ID%IDnumber) then

                Prev => CurrentDischarge%Prev
                Next => CurrentDischarge%Next

                !Updates foward pointer
                if (associated(CurrentDischarge%Prev)) then
                    Prev%Next  => Next
                endif

                !Updates backward pointer
                if (associated(CurrentDischarge%Next)) then
                    Next%Prev      => Prev
                endif

                !Updates first domain
                if (DischargeToDelete%ID%IDnumber == Me%FirstDischarge%ID%IDnumber) then
                    Me%FirstDischarge => Next
                endif

                !Updates last domain
                if (DischargeToDelete%ID%IDnumber == Me%LastDischarge%ID%IDnumber) then
                    Me%LastDischarge => Prev
                endif


                if (DischargeToDelete%TimeSerie /= 0) then
                    call KillTimeSerie(DischargeToDelete%TimeSerie, STAT = STAT_CALL)
                end if


                PropertyX => DischargeToDelete%FirstProperty


                do while(associated(PropertyX))  

                    if (associated(PropertyX%Next)) then
                        PropertyX => PropertyX%Next
                        deallocate(PropertyX%Prev, STAT = STAT_CALL)
                        if (STAT_CALL .NE. SUCCESS_)                           &
                            stop 'Subroutine Kill_Discharges; ModuleDischarges. ERR06.'

                        nullify    (PropertyX%Prev)
                    else 
                        deallocate(PropertyX, STAT = STAT_CALL)
                        if (STAT_CALL .NE. SUCCESS_)                           &
                            stop 'Subroutine Kill_Discharges; ModuleDischarges. ERR07.' 
                                           
                        nullify    (PropertyX)
                    end if
                end do

                nullify(DischargeToDelete%FirstProperty, DischargeToDelete%LastProperty)


                nullify   (DischargeToDelete%Next)
                nullify   (DischargeToDelete%Prev)
                deallocate(DischargeToDelete)
                nullify   (DischargeToDelete)

                return

            endif
        
            CurrentDischarge => CurrentDischarge%Next

        enddo

    end subroutine KillIndividualDischarge

    !--------------------------------------------------------------------------

    subroutine DeallocateInstance

        !Arguments-------------------------------------------------------------

        !Local-----------------------------------------------------------------
        type (T_Discharges), pointer                :: AuxDischarges
        type (T_Discharges), pointer                :: PreviousDischarges

        !Updates pointers
        if (Me%InstanceID == FirstDischarges%InstanceID) then
            FirstDischarges => FirstDischarges%Next
        else
            PreviousDischarges => FirstDischarges
            AuxDischarges      => FirstDischarges%Next
            do while (AuxDischarges%InstanceID /= Me%InstanceID)
                PreviousDischarges => AuxDischarges
                AuxDischarges      => AuxDischarges%Next
            enddo

            !Now update linked list
            PreviousDischarges%Next => AuxDischarges%Next

        endif

        !Deallocates instance
        deallocate (Me)
        nullify    (Me) 
            
    end subroutine DeallocateInstance

    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    !MANAGEMENT MANAGEMENT MANAGEMENT MANAGEMENT MANAGEMENT MANAGEMENT MANAGEME

    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    subroutine Ready (DischargesID, ready_) 

        !Arguments-------------------------------------------------------------
        integer                                     :: DischargesID
        integer                                     :: ready_

        !----------------------------------------------------------------------

        nullify (Me)

cd1:    if (DischargesID > 0) then
            call LocateObjDischarges (DischargesID)
            ready_ = VerifyReadLock (mDISCHARGES_, Me%InstanceID)
        else
            ready_ = OFF_ERR_
        end if cd1

        !----------------------------------------------------------------------

    end subroutine Ready

    !--------------------------------------------------------------------------

    subroutine LocateObjDischarges (DischargesID)

        !Arguments-------------------------------------------------------------
        integer                                     :: DischargesID

        !Local-----------------------------------------------------------------

        Me => FirstDischarges
        do while (associated (Me))
            if (Me%InstanceID == DischargesID) exit
            Me => Me%Next
        enddo

        if (.not. associated(Me))                                          &
            stop 'ModuleDischarges - LocateObjDischarges - ERR01'

    end subroutine LocateObjDischarges

    !--------------------------------------------------------------------------

end module ModuleDischarges

