!! Implement models to compute infiltration rate
!|author: Giovanni Ravazzani
! license: GPL
!
!### History
!
! current version 1.1 - 16th June 2016
!
! | version | date | comment |
! |----------|-------------|----------|
! | 1.0 | 28/May/2014 | Original code |
! | 1.1 | 16/Jun/2016 | added CurveNumber function |
!
!### License
! license: GNU GPL
!
!### Module Description
! Implement models to compute infiltration rate:
!
! * [[Philip(function)]] model
!
! * [[GreenAmpt(function)]] model
!
! * [[SCScurveNumber(function)]] model
!
MODULE Infiltration
USE DataTypeSizes, ONLY : &
! Imported Type Definitions:
short, float, double
USE LogLib,ONLY : &
! imported routines:
Catch
USE IniLib, ONLY : &
!Imported types:
IniList, &
!Imported routines:
IniOpen, IniClose , &
IniReadInt, IniReadReal , &
KeyIsPresent, IniReadString, &
IniReadDouble, SectionIsPresent
USE GridLib, ONLY : &
!imported definitions:
grid_real, grid_integer, &
!imported routines:
NewGrid
USE StringManipulation, ONLY: &
!Imported routines:
ToString
USE GridOperations, ONLY : &
!imported routines:
GridByIni, CRSisEqual !, CellArea, &
!Imported assignment:
!ASSIGNMENT (=)
USE SoilProperties, ONLY : &
!Imported definitions:
SoilType
USE DomainProperties, ONLY : &
!imported variables:
mask
USE Richards, ONLY : &
!imported routines:
SetRichardsBC, SolveRichardsBC, &
!imported variables:
nsteps, parameters, cell, &
dx, S, h0grid, drncum, &
infilcum, evapcum, runoffcum
IMPLICIT NONE
! Global (i.e. public) Declarations:
INTEGER (KIND = short) :: infiltrationModel
!infiltration model labels
INTEGER (KIND = short), PARAMETER :: SCS_CN = 1 !!Soil Conservation Service Curve Number
INTEGER (KIND = short), PARAMETER :: PHILIPEQ = 2 !!Philip's equation
INTEGER (KIND = short), PARAMETER :: GREEN_AMPT = 3 !!Green Ampt
INTEGER (KIND = short), PARAMETER :: ROSS_BC = 4 !!Richards equations solution by Ross with Broooks and Corey SWRC
INTEGER (KIND = short), PARAMETER :: ROSS_VG = 5 !!Richards equations solution by Ross with Van Genuchten SWRC
!soil
TYPE (SoilType), PRIVATE, ALLOCATABLE :: soils (:)
INTEGER (KIND = short) :: soilDivisions !! number of subdivisions of soil layer
!common properties
TYPE (grid_integer), PRIVATE :: soilTypeMap !read in subroutine SetParametersFromDB
TYPE (grid_real), PUBLIC :: ksat !!saturated hydraulic conductivity [m/s]
TYPE (grid_real), PUBLIC :: thetar !!residual water content [m3/m3]
TYPE (grid_real), PUBLIC :: thetas !!saturated water content [m3/m3]
TYPE (grid_real), PUBLIC :: psdi !!pore size distribution index by Brooks and Corey [-]
TYPE (grid_real), PUBLIC :: wiltingPoint !!wilting point [m3/m3]
TYPE (grid_real), PUBLIC :: fieldCapacity !!field capacity [m3/m3]
TYPE (grid_real), PRIVATE :: smax !!maximum soil storage [m] DEBUG non so chi usa questo parametro
!used by PHILIPS, ROSS_BC and ROSS_VG
TYPE (grid_real), PUBLIC :: psic !!bubbling pressure, air entry value [m]
!used by SCS_CN
TYPE (grid_real), PUBLIC :: curveNumber !! curve number [-]
TYPE (grid_real), PUBLIC :: abstractionRatio !! initial abstraction ratio of the SCS-CN [-] default = 0.2
TYPE (grid_real), PUBLIC :: storativity !! storativity of the SCS-CN [mm], default = 254
TYPE (grid_real), PUBLIC :: sEff !! effective soil retention capacity [mm]
TYPE (grid_real), PUBLIC :: raincum !!cumulated gross rainfall [mm]
!used by GREEN_AMPT
TYPE (grid_real), PUBLIC :: phy !!wetting front soil suction head [m]
!used by ROSS_VG
TYPE (grid_real), PRIVATE :: ptort !!tortuosity index [-]
TYPE (grid_real), PRIVATE :: nvg !!n shape parameter for Van Genuchten SWRC [-]
TYPE (grid_real), PRIVATE :: mvg !!m shape parameter for Van Genuchten SWRC [-]
TYPE (grid_real), PRIVATE :: ksatMatrix !!saturated conductivity of soil "matrix",
!different from ksat when macropores impact.
!Implemented only when vG WRC is used
!used by PHILIPEQ and GREEN_AMPT
TYPE (grid_real), PUBLIC :: cuminf !!cumulative infiltration [m]
TYPE (grid_real), PUBLIC :: ism !!soil moisture at the beginning of storm event [m3/m3]
!private declarations:
INTEGER (KIND = short), PRIVATE :: parameterAssigningMethod
!!1 = read each parameter from single file; 2 = assign parameter from soil type map
INTEGER (KIND = short), PRIVATE, PARAMETER :: FROM_FILES = 1
INTEGER (KIND = short), PRIVATE, PARAMETER :: FROM_DB = 2
!public routines:
PUBLIC :: InfiltrationInit
PUBLIC :: Philip
PUBLIC :: GreenAmpt
PUBLIC :: SCScurveNumber
PUBLIC :: Sat2scn
!private routines:
PRIVATE :: ReadSoilTypes
PRIVATE :: SetParametersFromDB
PRIVATE :: SetParametersFromFile
!=======
CONTAINS
!=======
! Define procedures contained in this module.
!==============================================================================
!| Description:
! Initialize evapotranspiration computation
SUBROUTINE InfiltrationInit &
!
( inifile, soilMoisture, soilDepth )
IMPLICIT NONE
!Arguments with intent(in):
CHARACTER (LEN = *), INTENT(IN) :: inifile
TYPE (grid_real), INTENT (IN) :: soilMoisture
TYPE (grid_real), INTENT (IN) :: soilDepth
!local declarations:
TYPE (IniList) :: infiltini
!--------------------------------------end of declarations---------------------
!open and read configuration file
CALL IniOpen (inifile, infiltini)
!read infiltration model
infiltrationModel = IniReadInt ('model', infiltini)
!read number of subdivisions of soil layer
soilDivisions = IniReadInt ('ross-divisions', infiltini)
!check soil division and infiltration model
IF (soilDivisions > 1 .AND. infiltrationModel == SCS_CN .OR. &
soilDivisions > 1 .AND. infiltrationModel == PHILIPEQ .OR. &
soilDivisions > 1 .AND. infiltrationModel == GREEN_AMPT ) THEN
CALL Catch ('warning', 'Infiltration', &
'Infiltration model requires one subdivision of soil layer, divisions forced to 1')
soilDivisions = 1
END IF
!read parameter assigning method
parameterAssigningMethod = IniReadInt ('parameter-assigning-method', infiltini)
IF (parameterAssigningMethod == FROM_DB) THEN
!check if all necessary info are defined
IF (.NOT. KeyIsPresent ('soil-types-file', infiltini) ) THEN
CALL Catch ('error', 'Infiltration', &
'missing ''soil-types-file'' keyword in configuration file')
END IF
IF (.NOT. SectionIsPresent ('soil-type-map', infiltini) ) THEN
CALL Catch ('error', 'Infiltration', &
'missing ''soil-type-map'' section in configuration file')
END IF
!set parameter maps
CALL SetParametersFromDB (infiltini, infiltrationModel)
ELSE
CALL SetParametersFromFile (infiltini, infiltrationModel)
END IF
!used by Philip model
IF (infiltrationModel == PHILIPEQ .OR. &
infiltrationModel == GREEN_AMPT ) THEN
CALL NewGrid (cuminf, mask, 0.)
CALL NewGrid (ism, mask, 0.)
END IF
!used by SCS-CN
IF (infiltrationModel == SCS_CN) THEN
CALL NewGrid (raincum, mask, 0.)
END IF
!when Richards equation solution is required, initialize Ross'parameters
IF (infiltrationModel == ROSS_BC) THEN
CALL SetRichardsBC (mask, ksat, thetas, thetar, psdi, psic, &
soilDepth, soilMoisture, infiltini, soilDivisions)
END IF
! Configuration terminated. Deallocate ini database
CALL IniClose (infiltini)
RETURN
END SUBROUTINE InfiltrationInit
!==============================================================================
!| Description:
! read soil types from external file
SUBROUTINE ReadSoilTypes &
!
(inifile)
IMPLICIT NONE
!Arguments with intent(in):
CHARACTER (LEN = *), INTENT(IN) :: inifile !!stores configuration information
!local declarations
TYPE(IniList) :: soilDB
INTEGER (KIND = short) :: nsoils !number of soil types to read
INTEGER (KIND = short) :: i
!------------end of declaration------------------------------------------------
!open and read soil types file
CALL IniOpen (inifile, soilDB)
!get number of soil types to read
IF (KeyIsPresent ('soil-types', soilDB) ) THEN !mandatory key
nsoils = IniReadInt ('soil-types', soilDB)
ELSE
CALL Catch ('error', 'SoilBalance', &
'missing ''soil-types'' section in soil types file')
END IF
!allocate memory and read data
ALLOCATE (soils(nsoils))
DO i = 1, nsoils
soils (i) % ksat = IniReadDouble ('ksat', soilDB, section = ToString(i))
soils (i) % thetas = IniReadDouble ('thetas', soilDB, section = ToString(i))
soils (i) % thetar = IniReadDouble ('thetar', soilDB, section = ToString(i))
soils (i) % wp = IniReadDouble ('wp', soilDB, section = ToString(i))
soils (i) % fc = IniReadDouble ('fc', soilDB, section = ToString(i))
soils (i) % psic = IniReadDouble ('psic', soilDB, section = ToString(i))
soils (i) % psdi = IniReadDouble ('psdi', soilDB, section = ToString(i))
soils (i) % phy = IniReadDouble ('phy', soilDB, section = ToString(i))
soils (i) % smax = IniReadDouble ('smax', soilDB, section = ToString(i))
soils (i) % m = IniReadDouble ('m', soilDB, section = ToString(i))
soils (i) % n = IniReadDouble ('n', soilDB, section = ToString(i))
soils (i) % pp = IniReadDouble ('p', soilDB, section = ToString(i))
soils (i) % kx = IniReadDouble ('ksat-matrix', soilDB, section = ToString(i))
soils (i) % c = IniReadDouble ('c', soilDB, section = ToString(i))
soils (i) % s0 = IniReadDouble ('s0', soilDB, section = ToString(i))
soils (i) % cn = IniReadDouble ('cn', soilDB, section = ToString(i))
END DO
!deallocate soilDB
CALL IniClose (soilDB)
RETURN
END SUBROUTINE ReadSoilTypes
!==============================================================================
!| Description:
! set parameter maps from soil database
SUBROUTINE SetParametersFromDB &
!
(iniDB, model)
IMPLICIT NONE
! Arguments with intent(in):
TYPE (IniList), INTENT(IN) :: iniDB
INTEGER (KIND = short), INTENT(IN) :: model !infiltration model
!Local declaration:
CHARACTER (LEN = 1000) :: soilTypeFile
INTEGER (KIND = short) ::i, j, id
!------------end of declaration------------------------------------------------
CALL Catch ('info', 'SoilBalance: ', 'setting soil parameters from database: ', &
argument = IniReadString('soil-types-file', iniDB) )
!load soil types
soilTypeFile = IniReadString('soil-types-file', iniDB)
CALL ReadSoilTypes (soilTypeFile)
! load soil type map
CALL GridByIni (iniDB, soilTypeMap, section = 'soil-type-map')
!Set parameter maps used by all models
!first allocate memory
CALL NewGrid (ksat, soilTypeMap)
CALL NewGrid (thetar, soilTypeMap)
CALL NewGrid (thetas, soilTypeMap)
CALL NewGrid (wiltingPoint, soilTypeMap)
CALL NewGrid (fieldCapacity, soilTypeMap)
CALL NewGrid (psdi, soilTypeMap)
!then assigh parameters
DO i = 1, soilTypeMap % idim
DO j = 1, soilTypeMap % jdim
IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN
id = soilTypeMap % mat (i,j)
ksat % mat (i,j) = soils (id) % ksat
thetar % mat (i,j) = soils (id) % thetar
thetas % mat (i,j) = soils (id) % thetas
wiltingPoint % mat (i,j) = soils (id) % wp
fieldCapacity % mat (i,j) = soils (id) % fc
psdi % mat (i,j) = soils (id) % psdi
END IF
END DO
END DO
IF (model == SCS_CN) THEN !read supplementary parameters required by Curve Number
!first allocate memory
CALL NewGrid (curveNumber, soilTypeMap)
CALL NewGrid (abstractionRatio, soilTypeMap)
CALL NewGrid (storativity, soilTypeMap)
!then assign parameters
DO i = 1, soilTypeMap % idim
DO j = 1, soilTypeMap % jdim
IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN
id = soilTypeMap % mat (i,j)
curveNumber % mat (i,j) = soils (id) % cn
abstractionRatio % mat (i,j) = soils (id) % c
storativity % mat (i,j) = soils (id) % s0
END IF
END DO
END DO
END IF
IF (model == PHILIPEQ) THEN !read supplementary parameters required by Philips
!first allocate memory
CALL NewGrid (psic, soilTypeMap)
!then assigh parameters
DO i = 1, soilTypeMap % idim
DO j = 1, soilTypeMap % jdim
IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN
id = soilTypeMap % mat (i,j)
psic % mat (i,j) = soils (id) % psic
END IF
END DO
END DO
END IF
IF (model == GREEN_AMPT) THEN !read supplementary parameters required by Green Ampt
!first allocate memory
CALL NewGrid (phy, soilTypeMap)
!then assigh parameters
DO i = 1, soilTypeMap % idim
DO j = 1, soilTypeMap % jdim
IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN
id = soilTypeMap % mat (i,j)
phy % mat (i,j) = soils (id) % phy
END IF
END DO
END DO
END IF
IF (model == ROSS_BC) THEN !read supplementary parameters required by Ross Brooks and Corey
!first allocate memory
CALL NewGrid (psic, soilTypeMap)
!then assigh parameters
DO i = 1, soilTypeMap % idim
DO j = 1, soilTypeMap % jdim
IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN
id = soilTypeMap % mat (i,j)
psic % mat (i,j) = soils (id) % psic
END IF
END DO
END DO
END IF
IF (model == ROSS_VG) THEN !read supplementary parameters required by Ross Van Genuchten
!first allocate memory
CALL NewGrid (psic, soilTypeMap)
CALL NewGrid (nvg, soilTypeMap)
CALL NewGrid (mvg, soilTypeMap)
CALL NewGrid (ptort, soilTypeMap)
CALL NewGrid (ksatMatrix, soilTypeMap)
!then assigh parameters
DO i = 1, soilTypeMap % idim
DO j = 1, soilTypeMap % jdim
IF (soilTypeMap % mat (i,j) /= soilTypeMap % nodata) THEN
id = soilTypeMap % mat (i,j)
psic % mat (i,j) = soils (id) % psic
nvg % mat (i,j) = soils (id) % n
mvg % mat (i,j) = soils (id) % m
mvg % mat (i,j) = soils (id) % m
ksatMatrix % mat (i,j) = soils (id) % kx
END IF
END DO
END DO
END IF
RETURN
END SUBROUTINE SetParametersFromDB
!==============================================================================
!| Description:
! set parameter maps from separate files
SUBROUTINE SetParametersFromFile &
!
(iniDB, model)
IMPLICIT NONE
! Arguments with intent(in):
TYPE (IniList), INTENT(IN) :: iniDB
INTEGER (KIND = short), INTENT(IN) :: model !infiltration model
!Local declaration:
!------------end of declaration------------------------------------------------
!Set parameter maps used by all models
!Saturated Conductivity
IF (SectionIsPresent('conductivity', iniDB)) THEN
CALL GridByIni (iniDB, ksat, section = 'conductivity')
CALL Catch ('info', 'SoilBalance: ', 'loading saturated conductivity from file: ', &
argument = IniReadString('file', iniDB, section = 'conductivity'))
IF ( .NOT. CRSisEqual (mask = mask, grid = ksat, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in conductivity map' )
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing conductivity section in configuration file' )
END IF
!Saturated water content
IF (SectionIsPresent('saturated-water-content', iniDB)) THEN
CALL GridByIni (iniDB, thetas, section = 'saturated-water-content')
CALL Catch ('info', 'SoilBalance: ', 'loading saturated water content from file: ', &
argument = IniReadString('file', iniDB, section = 'saturated-water-content'))
IF ( .NOT. CRSisEqual (mask = mask, grid = thetas, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in saturated-water-content' )
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing saturated-water-content section in configuration file' )
END IF
!Residual water content
IF (SectionIsPresent('residual-water-content', iniDB)) THEN
CALL GridByIni (iniDB, thetar, section = 'residual-water-content')
CALL Catch ('info', 'SoilrBalance: ', 'loading residual water content from file: ', &
argument = IniReadString('file', iniDB, section = 'residual-water-content'))
IF ( .NOT. CRSisEqual (mask = mask, grid = thetar, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in residual-water-content' )
END IF
ELSE
CALL Catch ('error', 'SoilWaterBalance: ', &
'missing residual-water-content section in configuration file' )
END IF
!Wilting Point
IF (SectionIsPresent('wilting-point', iniDB)) THEN
CALL GridByIni (iniDB, wiltingPoint, section = 'wilting-point')
CALL Catch ('info', 'SoilBalance: ', 'loading wilting point from file: ', &
argument = IniReadString('file', iniDB, section = 'wilting-point'))
IF ( .NOT. CRSisEqual (mask = mask, grid = wiltingPoint, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in wilting-point' )
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing wilting-point section in configuration file' )
END IF
!Field Capacity
IF (SectionIsPresent('field-capacity', iniDB)) THEN
CALL GridByIni (iniDB, fieldCapacity, section = 'field-capacity')
CALL Catch ('info', 'SoilBalance: ', 'loading field capacity from file: ', &
argument = IniReadString('file', iniDB, section = 'field-capacity'))
IF ( .NOT. CRSisEqual (mask = mask, grid = fieldCapacity, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in field-capacity' )
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing field-capacity section in configuration file' )
END IF
!Pore size distribution index
IF (SectionIsPresent('pore-size-index', iniDB)) THEN
CALL GridByIni (iniDB, psdi, section = 'pore-size-index')
CALL Catch ('info', 'SoilBalance: ', 'loading pore size index from file: ', &
argument = IniReadString('file', iniDB, section = 'pore-size-index'))
IF ( .NOT. CRSisEqual (mask = mask, grid = psdi, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in pore-size-index')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing pore-size-idex section in configuration file' )
END IF
!bubbling pressure, air entry value
IF (SectionIsPresent('bubble-pressure', iniDB)) THEN
CALL GridByIni (iniDB, psic, section = 'bubble-pressure')
CALL Catch ('info', 'SoilBalance: ', 'loading bubbling pressure from file: ', &
argument = IniReadString('file', iniDB, section = 'bubble-pressure'))
IF ( .NOT. CRSisEqual (mask = mask, grid = psic, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in bubbling pressure')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing bubble-pressure section in configuration file' )
END IF
IF (model == SCS_CN) THEN !read supplementary parameters required by Curve Number
!Curve Number
IF (SectionIsPresent('curve-number', iniDB)) THEN
CALL GridByIni (iniDB, curveNumber, section = 'curve-number')
CALL Catch ('info', 'SoilBalance: ', 'loading curve number from file: ', &
argument = IniReadString('file', iniDB, section = 'curve-number'))
IF ( .NOT. CRSisEqual (mask = mask, grid = curveNumber, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in curve number')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing curve-number section in configuration file' )
END IF
!Initial abstraction ratio
IF (SectionIsPresent('abstraction-ratio', iniDB)) THEN
CALL GridByIni (iniDB, abstractionRatio, section = 'abstraction-ratio')
CALL Catch ('info', 'SoilBalance: ', 'loading initial abstraction ratio from file: ', &
argument = IniReadString('file', iniDB, section = 'abstraction-ratio'))
IF ( .NOT. CRSisEqual (mask = mask, grid = abstractionRatio, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in initial abstraction ratio')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing abstraction-ratio section in configuration file' )
END IF
!SCS-CN storativity
IF (SectionIsPresent('storativity', iniDB)) THEN
CALL GridByIni (iniDB, storativity, section = 'storativity')
CALL Catch ('info', 'SoilBalance: ', 'loading storativity from file: ', &
argument = IniReadString('file', iniDB, section = 'storativity'))
IF ( .NOT. CRSisEqual (mask = mask, grid = storativity, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in storativity')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing storativity section in configuration file' )
END IF
END IF
!IF (model == PHILIPEQ) THEN !read supplementary parameters required by Philips
!
! !bubbling pressure, air entry value
! IF (SectionIsPresent('bubble-pressure', iniDB)) THEN
! CALL GridByIni (iniDB, psic, section = 'bubble-pressure')
! CALL Catch ('info', 'SoilBalance: ', 'loading bubbling pressure from file: ', &
! argument = IniReadString('file', iniDB, section = 'bubble-pressure'))
! IF ( .NOT. CRSisEqual (mask = mask, grid = psic, checkCells = .TRUE.) ) THEN
! CALL Catch ('error', 'SoilBalance', &
! 'wrong spatial reference in bubbling pressure')
! END IF
! ELSE
! CALL Catch ('error', 'SoilBalance: ', &
! 'missing bubble-pressure section in configuration file' )
! END IF
!
!END IF
IF (model == GREEN_AMPT) THEN !read supplementary parameters required by Green Ampt
!wetting front soil suction head
IF (SectionIsPresent('front-suction-head', iniDB)) THEN
CALL GridByIni (iniDB, phy, section = 'front-suction-head')
CALL Catch ('info', 'SoilBalance: ', 'loading wetting front suction head from file: ', &
argument = IniReadString('file', iniDB, section = 'front-suction-head'))
IF ( .NOT. CRSisEqual (mask = mask, grid = phy, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in wetting front suction head')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing front-suction-head section in configuration file' )
END IF
END IF
IF (model == ROSS_BC) THEN !read supplementary parameters required by Ross Brooks and Corey
!bubbling pressure, air entry value
IF (SectionIsPresent('bubble-pressure', iniDB)) THEN
CALL GridByIni (iniDB, psic, section = 'bubble-pressure')
CALL Catch ('info', 'SoilBalance: ', 'loading bubbling pressure from file: ', &
argument = IniReadString('file', iniDB, section = 'bubble-pressure'))
IF ( .NOT. CRSisEqual (mask = mask, grid = psic, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in bubbling pressure')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing bubble-pressure section in configuration file' )
END IF
END IF
IF (model == ROSS_VG) THEN !read supplementary parameters required by Ross Van Genuchten
!bubbling pressure, air entry value
IF (SectionIsPresent('bubble-pressure', iniDB)) THEN
CALL GridByIni (iniDB, psic, section = 'bubble-pressure')
CALL Catch ('info', 'SoilBalance: ', 'loading bubbling pressure from file: ', &
argument = IniReadString('file', iniDB, section = 'bubble-pressure'))
IF ( .NOT. CRSisEqual (mask = mask, grid = psic, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in bubbling pressure')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing bubble-pressure section in configuration file' )
END IF
!n shape parameter for Van Genuchten SWRC
IF (SectionIsPresent('n-van-genuchten', iniDB)) THEN
CALL GridByIni (iniDB, nvg, section = 'n-van-genuchten')
CALL Catch ('info', 'SoilBalance: ', 'loading n shape parameter from file: ', &
argument = IniReadString('file', iniDB, section = 'n-van-genuchten'))
IF ( .NOT. CRSisEqual (mask = mask, grid = nvg, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in n shape parameter')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing n-van-genuchten section in configuration file' )
END IF
!m shape parameter for Van Genuchten SWRC
IF (SectionIsPresent('m-van-genuchten', iniDB)) THEN
CALL GridByIni (iniDB, mvg, section = 'm-van-genuchten')
CALL Catch ('info', 'SoilBalance: ', 'loading m shape parameter from file: ', &
argument = IniReadString('file', iniDB, section = 'm-van-genuchten'))
IF ( .NOT. CRSisEqual (mask = mask, grid = mvg, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in m shape parameter')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing m-van-genuchten section in configuration file' )
END IF
!tortuosity index
IF (SectionIsPresent('tortuosity-index', iniDB)) THEN
CALL GridByIni (iniDB, ptort, section = 'tortuosity-index')
CALL Catch ('info', 'SoilBalance: ', 'loading tortuosity index from file: ', &
argument = IniReadString('file', iniDB, section = 'tortuosity-index'))
IF ( .NOT. CRSisEqual (mask = mask, grid = ptort, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in tortuosity index')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing tortuosity-index section in configuration file' )
END IF
!saturated conductivity of soil "matrix"
IF (SectionIsPresent('conductivity-matrix', iniDB)) THEN
CALL GridByIni (iniDB, ksatMatrix, section = 'conductivity-matrix')
CALL Catch ('info', 'SoilBalance: ', 'loading soil matrix conductivity from file: ', &
argument = IniReadString('file', iniDB, section = 'conductivity-matrix'))
IF ( .NOT. CRSisEqual (mask = mask, grid = ksatMatrix, checkCells = .TRUE.) ) THEN
CALL Catch ('error', 'SoilBalance', &
'wrong spatial reference in soil matrix conductivity')
END IF
ELSE
CALL Catch ('error', 'SoilBalance: ', &
'missing conductivity-matrix section in configuration file' )
END IF
END IF
RETURN
END SUBROUTINE SetParametersFromFile
!==============================================================================
!| calculates the actual rate of infiltration (m/s) according to
! Curve Number model modified for continuous simulation
!
! References:
!
! Ravazzani, G., Mancini, M., Giudici, I., & Amadio, P.. (2007).
! Effects of soil moisture parameterization on a real- time flood
! forecasting system based on rainfall thresholds.
! IAHS publication, 313, 407–416.
!
! Rabuffetti, D., Ravazzani, G., Corbari, C., & Mancini, M.. (2008).
! Verification of operational quantitative discharge forecast (QDF)
! for a regional warning system – the AMPHORE case studies in the
! upper Po river. Natural hazards and earth system sciences, 8, 161–173.
!
! Ravazzani, G., Amengual, A., Ceppi, A., Homar, V., Romero, R.,
! Lombardi, G., & Mancini, M.. (2016). Potentialities of ensemble
! strategies for flood forecasting over the Milano urban area.
! Journal of hydrology, 539, 237-253.
!
FUNCTION SCScurveNumber &
!
(rain, raincum, c, s, dt, runoff) &
!
RESULT (inf)
IMPLICIT NONE
!Arguments with intent in
REAL (KIND = float), INTENT(IN) :: rain !!rainfall rate (m/s)
REAL (KIND = float), INTENT(IN) :: c !!initial abstraction ratio (-)
REAL (KIND = float), INTENT(IN) :: s !!soil retention capacity (mm)
INTEGER (KIND = short), INTENT(IN) :: dt !!time step (s)
!Arguments with intent inout:
REAL (KIND = float), INTENT(INOUT) :: raincum !!cumulated rainfall from start of storm (mm)
!! is used and updated to be ready for the
!! following step
!Arguments with intent out
REAL (KIND = double), INTENT(OUT) :: runoff !!runoff rate (m/s)
!local declarations:
REAL (KIND = float) :: inf !!infiltration rate (m/s)
REAL (KIND = float) :: raincump !!cumulative precipitation of previous time step (mm)
REAL (KIND = float) :: runoffp !!cumulative runoff of previous time step (mm)
!-------------------------end of declarations----------------------------------
!if retention capacity = 0 (soil is saturated)
! rainfall is transformed to runoff
IF (s == 0.) THEN
raincum = raincum + rain * 1000. * dt !update cumulative rainfall
runoff = rain
inf = 0.
RETURN !no need to continue
END IF
!calculate runoff and infiltration rate
!update cumulative precipitation
raincump = raincum !save cumulated precipitation amount of previous time step
raincum = raincum + rain * dt * 1000. !(mm)
!runoff at current time
IF(raincum >= c*s) THEN
runoff = ((raincum - c*s )**2.) / (raincum + (1.-c) * s)
ELSE
runoff = 0.
END IF
!runoff at previous time
IF(raincump >= c*S) THEN
runoffp = ((raincump - c*S )**2.) / (raincump + (1.-c) * s)
ELSE
runoffp = 0.
END IF
!actual runoff in m/s
runoff = (runoff - runoffp) / 1000. / dt
!actual infiltration rate in m/s
inf = rain - runoff
RETURN
END FUNCTION SCScurveNumber
!==============================================================================
!| compute actual soil retention capacity S of the SCS-CN method
! given soil saturation
SUBROUTINE Sat2scn &
!
(cn2, s0, soilsat, scn)
IMPLICIT NONE
!arguments with intent in:
REAL (KIND = float), INTENT(IN) :: cn2 !!curve number for mean soil moisture
REAL (KIND = float), INTENT(IN) :: s0 !!storativity (mm)
REAL (KIND = float), INTENT(IN) :: soilsat !!soil saturation
!arguments with intent out:
REAL (KIND = float), INTENT(OUT) :: scn !!soil retention capacity [mm]
!local declarations:
REAL (KIND = float) :: cn1, cn3, s1, s2, s3
!-------------------------end of declarations----------------------------------
!compute cn1 and cn3 from cn2
cn1 = cn2 - (20. * (100. - cn2) ) / &
(100. - cn2 + EXP(2.533 - .0636 * (100. - cn2) ) )
IF (cn1 < 0.4 * CN2) cn1 = .4 * cn2
cn3 = cn2 * EXP( .00673 * (100. - cn2) )
!compute s1, s2, and s3
s1 = s0 * (100. / cn1 - 1.)
s2 = s0 * (100. / cn2 - 1.)
s3 = s0 * (100. / cn3 - 1.)
!compute actual S
scn = s1 - soilsat * (s1 - s3)
RETURN
END SUBROUTINE sat2scn
!==============================================================================
!| calculates the actual rate of infiltration (m/s) according to
! Philip's equation. Use time compression approximation.
!
! References:
!
! Philip, J. R. 1954. An infiltration equation with physical
! significance. Soil Science, 77: 153-157.
!
! Milly, P. C. D., An event-based simulation model of moisture and
! energy fluxes at a bare soil surface,
! Water Resour. Res., 22, 1680-! 692, 1986
!
! Sivapalan, M., Beven, K., and Wood, E. F. (1987), On hydrologic similarity:
! 2 . A scaled model of storm runoff production, Water Resour.
! Res., 23( 12), 2266– 2278, doi:10.1029/WR023i012p02266.
!
FUNCTION Philip &
!
(rain, psic, ksat, theta, thetas, thetar, psdi, itheta, dt, cuminf) &
!
RESULT (inf)
IMPLICIT NONE
!Arguments with intent in
REAL (KIND = float), INTENT(IN) :: rain !!rainfall rate (m/s)
REAL (KIND = float), INTENT(IN) :: psic !!bubbling pressure (m)
REAL (KIND = float), INTENT(IN) :: ksat !!saturated hydraulic conductivity (m/s)
REAL (KIND = float), INTENT(IN) :: theta !!volumetric water content (m3/m3)
REAL (KIND = float), INTENT(IN) :: thetas !!saturated volumetric water content (m3/m3)
REAL (KIND = float), INTENT(IN) :: thetar !!residual volumetric water content (m3/m3)
REAL (KIND = float), INTENT(IN) :: psdi !!Brooks & Corey pore size distribution index (-)
INTEGER (KIND = short), INTENT(IN) :: dt !!time step (s)
REAL (KIND = float), INTENT(IN) :: itheta !!initial soil moisture
!Arguments with intent inout:
REAL (KIND = float), INTENT(INOUT) :: cuminf !!cumulative infiltration (m)
!local declarations:
REAL (KIND = float) :: inf !!infiltration rate (m/s)
REAL (KIND = float) :: sorp !!sorptivity
REAL (KIND = float) :: cc = 0. !!gravity term in Philip's infiltration equation
REAL (KIND = float) :: deltrz !! difference between soil moisture at beginning
!! of storm event and residual soil moisture
REAL (KIND = float) :: bcgamm !!2.0 + 3.0 * psdi
REAL (KIND = float) :: infcap !!infiltration capacity (m/s)
!-------------------------end of declarations----------------------------------
! Sivapalan et al. (1987)
bcgamm = 2.0 + 3.0 * psdi
sorp = (((2. * ksat *( (thetas-itheta)**2.) * psic ) / &
(thetas-thetar))*((1./(bcgamm + 0.5 * psdi - 1.)) + &
((thetas-thetar)/ (thetas-itheta) ) ) ) ** 0.5
deltrz = itheta - thetar
IF (deltrz <= 0.) deltrz = 0.
cc = 0.5 * (1. + ( (deltrz / (thetas - thetar))**(bcgamm / psdi) ) )
!If soil is saturated then set infiltration to zero
IF (theta >= thetas) THEN
inf = 0.
!If surface is unsaturated then calculate infiltration
ELSE
!If first step with infiltration then all precipitation is
!infiltrated to avoid division by zero
IF (cuminf == 0.) THEN
inf = rain
!calculate infiltration capacity as a function of cumulative
! infiltration for all other time steps of storm (Milly, 1986)
ELSE
infcap = cc * ksat * (1. + (1./ ((( 1. + (( 4. * cc * ksat * cuminf ) / &
(sorp**2.)))**0.5) - 1.)))
!Take the actual infiltration rate as the minimum of the
! precipitation rate or the infiltration capacity.
inf = MIN (infcap,rain)
END IF
!update cumulative infiltration
cuminf = cuminf + inf * dt
END IF
RETURN
END FUNCTION Philip
!==============================================================================
!| calculates the actual rate of infiltration (m/s) according to
! Green-Ampt equation for unsteady rainfall.
!
! References:
!
! Green, WH., and Ampt, GA., 1911. Studies on soil physics I.
! Flow of air and water through soils. J. Agric. Sci. 4: 1- 24.
!
! Chow, V., Maidment, D., Mays, L. (1988) Applied Hydrology,
! Surface water, pp. 142-145, McGraw-Hill
!
FUNCTION GreenAmpt &
!
(storm, rain, ksat, theta, thetas, thetar, phy, itheta, dt, cuminf) &
!
RESULT (inf)
IMPLICIT NONE
!Arguments with intent in
INTEGER (KIND = short), INTENT(IN) :: storm !!when = 1 first steo of storm event
REAL (KIND = float), INTENT(IN) :: rain !!rainfall rate (m/s)
REAL (KIND = float), INTENT(IN) :: ksat !!saturated hydraulic conductivity (m/s)
REAL (KIND = float), INTENT(IN) :: theta !!volumetric water content (m3/m3)
REAL (KIND = float), INTENT(IN) :: thetas !!saturated volumetric water content (m3/m3)
REAL (KIND = float), INTENT(IN) :: thetar !!residual volumetric water content (m3/m3)
REAL (KIND = float), INTENT(IN) :: phy !!suction head across the wetting front (m)
INTEGER (KIND = short), INTENT(IN) :: dt !!time step (s)
REAL (KIND = float), INTENT(IN) :: itheta !!initial soil moisture
!Arguments with intent inout:
REAL (KIND = float), INTENT(INOUT) :: cuminf !!cumulative infiltration (m)
!local declarations:
REAL (KIND = float) :: inf !!infiltration rate (m/s)
REAL (KIND = float) :: deltrz !! difference between soil moisture at beginning
!! of storm event and residual soil moisture
REAL (KIND = float) :: test !!test value for the cumulative infiltration (m)
REAL (KIND = float) :: ftest !!test value for the cumulative infiltration (m)
INTEGER (KIND = short) :: i !loop
INTEGER (KIND = short) :: maxiter = 100 !maximum number of iteration for
! computing cumulative infiltration
REAL (KIND = float) :: tol = 0.00001 !tolerance to compute cumulative infiltration (m)
REAL (KIND = float) :: deltatfirst !!for ponding time (case 3)
REAL (KIND = float) :: Fponding !!cumulative infiltration at ponding (case 3)
REAL (KIND = float) :: deltatpond !! new deltat calculated for ponding (case 3)
!-------------------------end of declarations----------------------------------
!if this is the first step of storm event:
! initialize variables
IF ( storm == 1) THEN
deltrz = thetas - theta
IF (deltrz <= 0.) THEN
deltrz = 0.
END IF
!assume all precipitation is infiltrated
cuminf = rain * dt
inf = rain
RETURN
END IF
!If soil is saturated then set infiltration to zero
IF (theta >= thetas) THEN
inf = 0.
RETURN
!If surface is unsaturated then calculate infiltration
ELSE
IF (storm == 2) THEN !storm is running
!calculate potential infiltration rate at the beginning of the interval
!from the known value of cumulative infiltration (eq 5.4.1)
inf = ksat * (phy * (thetas-itheta) / cuminf + 1.)
!compare potential infiltration to rainfall rate
IF (inf <= rain) THEN !ponding occurs throughout the interval (case 1)
test = Ksat*dt !first guess for cumulative infiltration
DO i = 1, maxiter
IF (i == maxiter) THEN
CALL Catch ('warning', 'Infiltration', 'maximum number of iterations &
reached while updating cumulative infiltration &
with green-ampt case 1' )
END IF
ftest = cuminf + ksat*dt + (phy*(thetas-itheta))* &
LOG ((test+(phy*(thetas-itheta)))/(cuminf+(phy*(thetas-itheta))))
IF (ABS(ftest-test) <= tol) THEN
cuminf = ftest
!compute infiltration rate from cumulative infiltration
inf = ksat * (phy * (thetas-itheta) / cuminf + 1.)
IF (inf > rain) inf = rain
EXIT
ELSE
test = ftest
END IF
END DO
ELSE !no ponding at the beginning of the interval
!calculate tentative values Assuming that all the rain
!water is penetrated into the soil
test = cuminf + rain * dt
inf = ksat * (phy * (thetas-itheta) / test + 1.)
IF (inf <= rain) THEN !ponding occurs during the interval (case 3)
Fponding = ksat * phy * (thetas-itheta) / (rain - ksat)
deltatfirst = (Fponding - cuminf) / rain
deltatpond = dt - deltatfirst
!compute cumulative infiltration by substituting cuminf = Fponding
!and dt = deltatpond
test = Fponding !Ksat*dt !first guess for cumulative infiltration
DO i = 1, maxiter
IF (i == maxiter) THEN
CALL Catch ('warning', 'Infiltration', 'maximum number of iterations &
reached while updating cumulative infiltration &
with green-ampt case 3' )
END IF
ftest = Fponding + ksat*deltatpond + (phy*(thetas-itheta))* &
LOG ((test+(phy*(thetas-itheta)))/(Fponding+(phy*(thetas-itheta))))
IF (ABS(ftest-test) <= tol) THEN
cuminf = ftest
!compute infiltration rate from cumulative infiltration
inf = ksat * (phy * (thetas-itheta) / cuminf + 1.)
IF (inf > rain) inf = rain
EXIT
ELSE
test = ftest
END IF
END DO
ELSE !no ponding throghout the interval (case 2)
cuminf = test
inf = rain
END IF
END IF
ELSE
inf = 0.
END IF
END IF
END FUNCTION GreenAmpt
END MODULE Infiltration