Author

Alois Tilloy

Demo of the Transformed-Stationary Extreme Value Analysis.

Step 1: load an environmental time series

Here we use with discharge data from the HERA hydrological reanalysis.

River network (rivers with an upstream area > 100km2) for which discharge data is available in HERA

RtsEva contains discharge data from the following four rivers:

Ardèche @ Saint Martin:

  • Total length: 120 km
  • Mean flow: 50 m3/s
  • Short description: The Ardèche is mediterranean river mostly known for tourism due to its scenic gorges. The river is known for its extreme autumn floods during the so called “épisodes cévenols”.
  • More: Wiki

Danube @ Vienna:

  • Total length: 2850 km
  • Mean flow: 1800 m3/s
  • Short description: The Danube is the longest river in the European Union. It is an important waterway for international trade, connecting several countries in Central and Eastern Europe.
  • More: Wiki

Ebro @ Zaragoza:

  • Total length: 930 km
  • Mean flow: 197 m3/s
  • Short description: The Ebro is Spain’s longest river, with low and high water levels alternating throughout the year, influenced by winter snowmelt and summer evaporation/human usage. The river is vital for agriculture.
  • More: Wiki

Rhône @ Lyon:

  • Total length: 813 km
  • Mean flow: 507 m3/s
  • Short description: The Rhône is France’s most powerful river, characterized by a significant seasonal variation in flow rates. The Rhône is crucial for transportation, hydropower generation, and irrigation in the region.
  • More: Wiki

We choose the Ardèche for this example. It is however possible to test different rivers in this Shiny app

Code
data=Ardeche$data
longitude=Ardeche$river$lon
latitude=Ardeche$river$lat
timeStamps=data$time

Location of the selected river:

Plot of the original timeseries

Hydrograph of river Ardeche

Different preprocessing depending on which hazard is studied:

  • Flood:
    • no transformation
    • minimum distance between two peaks: 10 days
    • analysis performed on daily maximum discharge
  • Drought:
    • reversed transformation
    • minimum distance between two peaks: 30 days
    • analysis performed on 7-days moving averaged discharged

Step 2: Run TSEVA for flood

Code
haz = "flood"

dt1=min(diff(data$time),na.rm=T)
dt=as.numeric(dt1)
tdim=attributes(dt1)$units
if (tdim=="hours") dt=dt/24
if (dt==1){
  timeDays=data$time
}else{
  timeDays=unique(as.Date(data$time))
}
if (haz=="drought"){
  
  minPeakDistanceInDays=30
  tail="low"
  #7 day average flow for drought analysis
  WindowSize=7
  names(data)=c("date","Qs")
  if (tdim=="hours") dt=dt/24
  nRunMn = ceiling(WindowSize/dt);
  colnames(data)
  data$Q7=rollmean(data$Qs,nRunMn, align = "right", fill=NA)
  
  if (!exists("trans")){trans="rev"}
  print(paste0(trans," transformation used for low flows"))
  
  series=data.frame(data$date,data$Q7)
  
}else if (haz=="flood"){
  tail="high"
  percentile=95
  minPeakDistanceInDays=10
  series <- max_daily_value(data)
  

}
timeAndSeries=series
names(timeAndSeries)=c("timestamp","data")

tsm=1/dt
series=timeAndSeries[,2]
timeWindow = 365.25*30; #time windows in days, the correction is done within the functions
windowSize=366

timeStamps=timeAndSeries$timestamp
transftypes=c("ori","rev")
trendtypes=c("trend","trendPeaks")
trendtrans=expand.grid(transftypes,trendtypes)
trendtrans = data.frame(trendtrans)
names(trendtrans)=c("transformation","trend method")

tt=3
print(trendtrans[tt,])
  transformation trend method
3            ori   trendPeaks
Code
Nonstat<-TsEvaNs(timeAndSeries, timeWindow, transfType=trendtrans[tt,2], ciPercentile= 90, minPeakDistanceInDays = minPeakDistanceInDays, tail, tail = tail, trans=trendtrans[tt,1])
nonStationaryEvaParams=Nonstat[[1]]
stationaryTransformData=Nonstat[[2]]

datex=yday(timeDays)
dtect=c(diff(datex),-1)
last_days <- timeDays[which(dtect<0)]
tindexes=match(last_days,timeDays)
RPgoal=10
timeIndex=1
RLevs100a=ComputeReturnLevels(nonStationaryEvaParams, RPgoal, timeIndex,trans=trendtrans[tt,1])
timeIndex=tindexes[length(tindexes)]-1
RLevs100b=ComputeReturnLevels(nonStationaryEvaParams, RPgoal, timeIndex,trans=trendtrans[tt,1])

FloodRL=data.frame(c(round(RLevs100a$ReturnLevels[3],2),
                     round(RLevs100a$ReturnLevels[3]-RLevs100a$ReturnLevels[5],2),
                     round(RLevs100a$ReturnLevels[3]+RLevs100a$ReturnLevels[5],2)),
                   c(round(RLevs100b$ReturnLevels[3],2),
                     round(RLevs100b$ReturnLevels[3]-RLevs100b$ReturnLevels[5],2),
                     round(RLevs100b$ReturnLevels[3]+RLevs100b$ReturnLevels[5],2)))
colnames(FloodRL)=c("Y1951","Y2020")
rownames(FloodRL)=c("RL","infCI","SupCI")
FloodRL=as.data.frame(FloodRL)
FloodRL$change=round((FloodRL$Y2020-FloodRL$Y1951)/FloodRL$Y1951*100,1)

for more details on the different transformation and trend methods, the reader can refer to the RtsEva package documentation: https://cran.r-project.org/web/packages/RtsEva/RtsEva.pdf

Step 4: Plot results for flood

Timeseries with peaks and evolving GPD density

Return Level curve in 1951

Curve beam (all curves from 1951 to 2020)

Step 5: Run TSEVA for drought

Code
haz = "drought"
rm(trans)

dt1=min(diff(data$time),na.rm=T)
dt=as.numeric(dt1)
tdim=attributes(dt1)$units
if (tdim=="hours") dt=dt/24
if (dt==1){
  timeDays=data$time
}else{
  timeDays=unique(as.Date(data$time))
}
if (haz=="drought"){
  
  minPeakDistanceInDays=30
  tail="low"
  #7 day average flow for drought analysis
  WindowSize=7
  names(data)=c("date","Qs")
  if (tdim=="hours") dt=dt/24
  nRunMn = ceiling(WindowSize/dt);
  colnames(data)
  data$Q7=rollmean(data$Qs,nRunMn, align = "right", fill=NA)
  
  if (!exists("trans")){trans="rev"}
  print(paste0(trans," transformation used for low flows"))
  
  series=data.frame(data$date,data$Q7)
  
}else if (haz=="flood"){
  tail="high"
  percentile=95
  minPeakDistanceInDays=10
  series <- max_daily_value(data)
  

}
[1] "rev transformation used for low flows"
Code
timeAndSeries=series
names(timeAndSeries)=c("timestamp","data")
timeStamps=timeAndSeries$timestamp

tt=4
print(trendtrans[tt,])
  transformation trend method
4            rev   trendPeaks
Code
Nonstat<-TsEvaNs(timeAndSeries, timeWindow, transfType=trendtrans[tt,2], ciPercentile= 90, minPeakDistanceInDays = minPeakDistanceInDays, tail, tail = tail, trans=trendtrans[tt,1])
nonStationaryEvaParams=Nonstat[[1]]
stationaryTransformData=Nonstat[[2]]

stationaryTransformData$timeStampsDay=unique(as.Date(as.character(stationaryTransformData$timeStamps)))
dt1=min(diff(timeStamps),na.rm=T)
dt=as.numeric(dt1)
tdim=attributes(dt1)$units
if (tdim=="hours") dt=dt/24
if (dt==1){
  timeDays=stationaryTransformData$timeStamps
}else{
  timeDays=stationaryTransformData$timeStampsDay
    }
    
datex=yday(timeDays)
dtect=c(diff(datex),-1)
last_days <- timeDays[which(dtect<0)]
tindexes=match(last_days,timeDays)
RPgoal=10
timeIndex=1
RLevs100a=ComputeReturnLevels(nonStationaryEvaParams, RPgoal, timeIndex,trans=trendtrans[tt,1])
timeIndex=tindexes[length(tindexes)]-1
RLevs100b=ComputeReturnLevels(nonStationaryEvaParams, RPgoal, timeIndex,trans=trendtrans[tt,1])

DryRL=data.frame(c(round(RLevs100a$ReturnLevels[3],2),
                     round(RLevs100a$ReturnLevels[3]-RLevs100a$ReturnLevels[5],2),
                     round(RLevs100a$ReturnLevels[3]+RLevs100a$ReturnLevels[5],2)),
                   c(round(RLevs100b$ReturnLevels[3],2),
                     round(RLevs100b$ReturnLevels[3]-RLevs100b$ReturnLevels[5],2),
                     round(RLevs100b$ReturnLevels[3]+RLevs100b$ReturnLevels[5],2)))
colnames(DryRL)=c("Y1951","Y2020")
rownames(DryRL)=c("RL","infCI","SupCI")
DryRL=as.data.frame(DryRL)
DryRL$change=round((DryRL$Y2020-DryRL$Y1951)/DryRL$Y1951*100,1)

Step 6: Plot results for drought

Timeseries with peaks and evolving GPD density

Return Level curve in 1951

Curve bean (all curves from 1951 to 2020)

Summary of the results for the Ardèche

The table shows the 10 years return level of high flows (daily maximum flow) and low flows (7 days averaged flow) for 1951 and 2020.

Changes in high and low flows
RL in 1951 (m3/s) [68% CI] RL in 2020 (m3/s) [68% CI] Relative change (%) [68% CI]
831.39 [762.24 -900.53] 799.23 [732.18 - 866.27] -3.9 [-3.9 - -3.8]
19.05 [17.24 - 20.87] 18.42 [16.64 - 20.2] -3.3 [-3.5 - -3.2]

Although the river displays a non-linear trend, the transformed-stationary method estimates a slight decrease in both extreme high an low flows on the Ardèche between 1951 and 2020.