100
100
# ' @param n.spells.year = c('fw','spell') if 'fw' then estimate number of spells according to 365.25 else estimate number of events from \code{\link{spell}}.
101
101
# ' @param alpha.scaling TRUE scale the low-probability events according to alpha in DOI:10.1088/1748-9326/ab2bb2
102
102
# ' @param alpha values for alpha-scaling
103
- # ' @param ensure.fw TRUE then WG tries to ensure that fw of simulations match those of observations or prescribed by adding or substracting wet days.
103
+ # ' @param ensure.fw TRUE then WG tries to ensure that fw of simulations match those of observations or prescribed by adding or subtracting wet days.
104
+ # ' @param w.fw.ac weighting to balance how the wet day occurrences follows seasonal cycle or randomness. 0 - no seasonal cycle; 1000 - mainly determined by climatology (default=30).
105
+ # ' @param w.mu.ac same as above, but for wet-day mean precipitation (default=10).
104
106
# ' @param \dots additional arguments
105
107
# ' @author R.E. Benestad
106
108
# ' @keywords manip
128
130
# ' lines(c(0, max(sy,sz,na.rm=TRUE)), c(0,max(sy,sz,na.rm=TRUE)), lty=2, col='red')
129
131
# ' points(sy, sz2, col='blue', cex=0.7)
130
132
# '
131
- # ' ## Test the WG
133
+ # '
134
+ # ' ## Simple simulation of contnued trends in wet-day mean precipitation and frequency
135
+ # ' mu <- annual(bjornholt,FUN='wetmean',nmin=270) # Avoid missing values (NA)
136
+ # ' fw <- annual(bjornholt,FUN='wetfreq',nmin=270) # Avoid missing values (NA)
137
+ # ' mu.trend <- trend(mu)
138
+ # ' fw.trend <- trend(fw)
139
+ # ' ## Construct precipitation statistics for input to WG
140
+ # ' mu2 <- c(mu,zoo(coredata(mu)+coredata(max(mu.trend)-min(mu.trend)),order.by=max(index(mu))+1:length(mu)))
141
+ # ' fw2 <- c(fw,zoo(coredata(fw)+coredata(max(fw.trend)-min(fw.trend)),order.by=max(index(fw))+1:length(fw)))
142
+ # ' z <- WG(bjornholt,mu=mu2,fw=fw2,verbose=TRUE)
143
+ # ' plot(z)
144
+ # '
145
+ # ' #' ## Test the WG
146
+ # ' z2 <- WG(bjornholt,w.mu.ac=1000,plot=TRUE,verbose=TRUE)
147
+ # ' plot(aggregate(z2,by=month,FUN='wetmean')); lines(aggregate(bjornholt,by=month,FUN='wetmean'))
148
+ # ' z3 <- WG(bjornholt,w.fw.ac=1000,plot=TRUE,verbose=TRUE)
149
+ # ' plot(aggregate(z3,by=month,FUN='wetfreq')); lines(aggregate(bjornholt,by=month,FUN='wetfreq'))
150
+ # '
151
+ # ' ## Test-routine for WG
132
152
# ' test.WG.fwmu.day.precip()
133
153
# ' @export WG
134
154
WG <- function (x ,... ) UseMethod(" WG" )
@@ -162,15 +182,15 @@ WG.FT.day.t2m <- function(x=NULL,...,amean=NULL,asd=NULL,t=NULL,ip=1:4,
162
182
x <- ferder
163
183
rm(' ferder' )
164
184
}
165
-
185
+
166
186
# # Get the daily anomalies and the climatology
167
187
xa <- anomaly(x ); clim <- x - xa
168
-
188
+
169
189
# # KMP 2024-05-31: If amean or asd are NULL, the function fails! Is amean and asd supposed to be the
170
190
# # annual mean and standard deviation of x? Adding a check to see if amean and asd exist and if not calculate them based on x.
171
191
if (is.null(amean )) amean <- as.annual(x , FUN = " mean" , na.rm = TRUE )
172
192
if (is.null(asd )) asd <- as.annual(x , FUN = " sd" , na.rm = TRUE )
173
-
193
+
174
194
# # Define time axis for projection based on the annual mean data either from station or
175
195
# # downscaled projections
176
196
if (is.null(t )) {
@@ -239,15 +259,15 @@ WG.fwmu.day.precip <- function(x=NULL,...) {
239
259
plot <- args $ plot ; if (is.null(plot )) plot <- FALSE
240
260
verbose <- args $ verbose ; if (is.null(verbose )) verbose <- FALSE
241
261
mu = args $ mu
242
- fw = args $ fr
262
+ fw = args $ fw
243
263
t = args $ t
244
264
threshold <- args $ threshold ; if (is.null(threshold )) threshold <- 1
245
265
alpha.scaling <- args $ alpha.scaling
246
266
if (is.null(alpha.scaling )) alpha.scaling <- TRUE
247
267
# # Use alpha scaling estimates from DOI:10.1088/1748-9326/abd4ab - same as in ERL::IDF()
248
268
alpha <- args $ alpha ; if (is.null(alpha )) alpha = c(1.256 ,0.064 )
249
269
# # Weighting function to determine the degree which the mean seasonal cycle determines the results
250
- w.fw.ac <- args $ w.fw.ac ; if (is.null(w.fw.ac )) w.fw.ac <- 100
270
+ w.fw.ac <- args $ w.fw.ac ; if (is.null(w.fw.ac )) w.fw.ac <- 30
251
271
w.mu.ac <- args $ w.mu.ac ; if (is.null(w.mu.ac )) w.mu.ac <- 10
252
272
253
273
if (verbose ) print(' WG.fwmu.day.precip' )
@@ -263,13 +283,10 @@ WG.fwmu.day.precip <- function(x=NULL,...) {
263
283
# # Estimate climatology for mean seasonal cycle in total precipitation. Use this information
264
284
# # as a guide for which months to add wet days to ensure correct wet-day frequency fw -
265
285
# # this is important for locations with a rainy season
266
- # pt.ac <- aggregate(x,month,FUN='mean',na.rm=TRUE)
267
- # pt.ac <- 3 * pt.ac/sum(coredata(pt.ac)) ## Normal distr.: N(1,1) ~[-3,3]
268
- # pt.ac <- approx(1:12,pt.ac,xout = seq(1,12,length=366))$y
269
- # # Also find the climatology for the wet-day frequency fw
270
286
fw.ac <- aggregate(x ,month ,FUN = ' wetfreq' ,threshold = 1 ,na.rm = TRUE )
271
287
fw.ac <- w.fw.ac * fw.ac / sum(coredata(fw.ac )) # # Normal distr.: N(1,1) ~[-3,3]
272
288
fw.ac <- approx(1 : 12 ,fw.ac ,xout = seq(1 ,12 ,length = 366 ))$ y
289
+
273
290
# # Also find the climatology for the wet-day mean precipitation mu
274
291
mu.ac <- aggregate(x ,month ,FUN = ' wetmean' ,threshold = 1 ,na.rm = TRUE )
275
292
mu.ac <- w.mu.ac * mu.ac / sum(coredata(mu.ac )) # # Normal distr.: N(1,1) ~[-3,3]
@@ -284,52 +301,22 @@ WG.fwmu.day.precip <- function(x=NULL,...) {
284
301
# Number of consecutive wet/dry days
285
302
ncd <- subset(spell(x ,threshold = threshold ),is = 1 )
286
303
# # Annual mean number of consecutive wet days
287
-
288
304
amncwd <- subset(annual(ncd , nmin = 30 ), is = 1 )
289
305
# extract the time interval between the start of each dry spell
290
306
dt1 <- diff(julian(as.Date(index(ncd [is.finite(ncd [,1 ]),1 ]))))
291
307
292
- if (plot ) {
293
- # # Timing between each precipitation event
294
- dev.new()
295
- par(mfrow = c(2 ,2 ),cex.main = 0.7 )
296
- # f.k <- dgeom(0:max(dt1), prob=1/(mean(dt1)+1))
297
- # hist(dt1,freq=FALSE,col="grey",xlab="days",
298
- # main="The time between the start of each precipitation event",
299
- # sub="Test: Red curve is the fitted geometric distribution")
300
- # lines(0:max(dt1),f.k,lwd=5,col="red")
301
- # grid()
308
+ if (plot ) {
309
+ # # Timing between each precipitation event
310
+ dev.new()
311
+ par(mfrow = c(2 ,2 ),cex.main = 0.7 )
312
+ f.k <- dgeom(0 : max(dt1 ), prob = 1 / (mean(dt1 )+ 1 ))
313
+ hist(dt1 ,freq = FALSE ,col = " grey" ,xlab = " days" ,
314
+ main = " The time between the start of each precipitation event" ,
315
+ sub = " Test: Red curve is the fitted geometric distribution" )
316
+ lines(0 : max(dt1 ),f.k ,lwd = 5 ,col = " red" )
317
+ grid()
302
318
}
303
319
304
- # # Annual mean number of days between start of each rain event
305
- # # Remove first and last elements to avoid cut-off problems at start and
306
- # # end of the time series
307
- # amndse <- annual(zoo(x=dt1,order.by=index(dt1)))[-c(1,length(dt1))]
308
-
309
- # # Wet-day spell duration statistics:
310
- # wetsd <- subset(ncd,is=1)
311
- # # Remove the first and last estimate to avoid cut-off problems
312
- # wetsd <- subset(wetsd,it=c(FALSE,rep(TRUE,length(wetsd)-2),FALSE))
313
- # amwetsd <- annual(wetsd,FUN='mean',nmin=1)
314
- # # Annual number of wet events
315
- # nwes <- aggregate(wetsd,by=year(wetsd),FUN="nv")
316
- # if (plot) {
317
- # ## Number of events per year
318
- # hist(coredata(nwes),breaks=seq(0,100,by=5),freq=FALSE,col="grey",
319
- # main="Number of wet events per year",xlab="days",
320
- # sub="Test: Red curve is the fitted Poisson distribution")
321
- # lines(seq(0,100,by=1),dpois(seq(0,100,by=1),lambda=mean(coredata(nwes))),
322
- # col="red",lwd=3)
323
- # grid()
324
- # }
325
-
326
- # # Estimate climatology for mean seasonal cycle in total precipitation. Use this information
327
- # # as a guide for which months to add wet days to ensure correct wet-day frequency fw
328
- # KMP 2024-05-31: y has not been defined yet and is not an input to the function!
329
- # Is it supposed to be x or was this moved up here from after line 409 where a y is defined?
330
- # pt.ac isn't used anywhere so I am am commenting it out for now.
331
- # pt.ac <- aggregate(y, month, FUN='mean', na.rm=TRUE)
332
-
333
320
# Wet-day mean: from DS or from observations
334
321
if (verbose ) print(' wet-day mean' )
335
322
if (is.null(mu ))
@@ -342,35 +329,35 @@ WG.fwmu.day.precip <- function(x=NULL,...) {
342
329
343
330
# Wet-day frequency: from DS or from observations
344
331
if (verbose ) print(' wet-day frequency' )
345
- if (is.null(fw )) fw <- zoo(FTscramble(x.fw ),order.by = index(x.fw )) else
332
+ if (is.null(fw ))
333
+ fw <- zoo(FTscramble(x.fw ),order.by = index(x.fw )) else
346
334
# # fw is introduced as a change factor
347
335
if (length(fw )== 1 ) {
348
336
fw <- fw + zoo(FTscramble(x.mu ),order.by = index(x.mu ))
349
337
}
350
338
rm(' x.fw' )
351
339
352
- # if (plot) {
353
- # ## Number of events per year
354
- # hist(coredata(ncd),breaks=seq(0,40,by=2),freq=FALSE,col="grey",
355
- # main="Duration of wet spells",xlab="days",
356
- # sub="Test: Red curve is the fitted geometric distribution")
357
- # lines(seq(0,40,by=1),dgeom(seq(0,40,by=1),prob=1/mean(coredata(amncwd))),
358
- # col="red",lwd=3)
359
- # grid()
360
- # }
340
+ if (plot ) {
341
+ # # Number of events per year
342
+ hist(coredata(ncd ),breaks = seq(0 ,40 ,by = 2 ),freq = FALSE ,col = " grey" ,
343
+ main = " Duration of wet spells" ,xlab = " days" ,
344
+ sub = " Test: Red curve is the fitted geometric distribution" )
345
+ lines(seq(0 ,40 ,by = 1 ),dgeom(seq(0 ,40 ,by = 1 ),prob = 1 / mean(coredata(amncwd ))),
346
+ col = " red" ,lwd = 3 )
347
+ grid()
348
+ }
361
349
362
350
# # Time axis for projection:
363
351
if (verbose ) print(' Time axis for projection' )
364
352
if (is.null(t )) {
365
- ly <- max(year(mu ))
353
+ nxy <- range(year(mu ))
354
+ t <- seq(as.Date(paste0(nxy [1 ],' -01-01' )),as.Date(paste0(nxy [2 ],' -12-31' )),by = 1 )
355
+ # # Number of years
366
356
ny <- length(rownames(table(year(mu ))))
367
- interval <- c(ly - ny + 1 ,ny )
368
- t <- index(x )
369
- t <- t - julian(as.Date(t [1 ])) +
370
- julian(as.Date(paste(interval [1 ],month(x )[1 ],day(x )[1 ],sep = ' -' )))
371
- if (verbose ) print(interval )
357
+ if (verbose ) print(range(t ))
372
358
}
373
- n <- length(t )
359
+ # # Number of days
360
+ nd <- length(t )
374
361
yrs <- as.numeric(rownames(table(year(t ))))
375
362
376
363
# Estimate the annual number of rainy days:
@@ -383,29 +370,32 @@ WG.fwmu.day.precip <- function(x=NULL,...) {
383
370
mu.err <- mu / sqrt(anwd - 1 )
384
371
385
372
# set up a record with no rain:
386
- z <- zoo(rep(0 ,length( t ) ),order.by = t )
373
+ z <- zoo(rep(0 ,nd ),order.by = t )
387
374
388
375
# add rain events:
389
- if (verbose ) print(paste(' loop over year:' ,1 ,' -' ,ny ))
376
+ if (verbose ) print(paste(' loop over year:' ,1 ,' -' ,ny ,' number of days=' ,nd ,length(z ),
377
+ ' length(mu)=' ,length(mu ),' length(fw)=' ,length(fw ),length(anwd )))
390
378
for ( i in 1 : ny ) {
391
- # # Julian day
392
- jd <- 1 : 366
393
379
394
380
# # Duration of wet events
395
- ncwd <- rgeom(366 ,prob = 1 / (amncwd [i ])) + 1
381
+ if (i < = length(amncwd )) ncwd <- rgeom(366 ,prob = 1 / amncwd [i ]) + 1 else
382
+ ncwd <- rgeom(366 ,prob = 1 / mean(amncwd ,na.rm = TRUE )) + 1
396
383
397
384
# # White noise to introduce stochastic weather
398
385
wn <- rnorm(366 )
399
386
# # Find most suitable times of the year with stochastic influence
400
- ij <- order( fw.ac + wn , decreasing = FALSE )
401
- # # Use jd as index for timing wet events
402
- jd <- jd [ ij ]
387
+ fw.ac.wn <- fw.ac + wn
388
+ # # Use ij as index for timing wet events
389
+ ij <- order( fw.ac.wn , decreasing = TRUE )
403
390
404
391
# # Repeat for the procedure using climatology and stochastic weather for mu,
405
392
# # but with 1/3 less weight on climatology and more on random order
406
- # # kl is the julian day ordered by intensity of rainfall
407
- kl <- order(mu.ac + rnorm(366 ),decreasing = FALSE )
408
- kd <- (1 : 366 )[kl ]
393
+ # # kl is the julian day ordered by seasonal mean intensity of rainfall plus random noise
394
+ # # The first indices tend to represent higher intensities
395
+ mu.ac.wn <- mu.ac + rnorm(366 )
396
+ # # Use kl as index for timing amounts
397
+ kl <- order(mu.ac.wn ,decreasing = TRUE )
398
+
409
399
if ( (plot ) & (i == 1 ) ) {
410
400
plot(ij ,main = ' fw/mu sorting' ,xlab = ' index' ,ylab = ' day' ,type = ' b' )
411
401
points(kl ,col = ' blue' ,pch = 19 ,type = ' b' )
@@ -417,59 +407,48 @@ WG.fwmu.day.precip <- function(x=NULL,...) {
417
407
while ( (length(wet ) < anwd [i ]) & (nes < = 366 ) ) {
418
408
# # Check whether the selected days are available: start with the first julian day in the year
419
409
idy1 <- 1
410
+ # # TRUE if found available sequence of wet days
420
411
d.available <- FALSE
421
412
# # We search the days in the year for sequences that include the wet spell duration
422
413
# # padded by dry days
423
414
while ( (! d.available ) & (idy1 < = 366 ) ) {
424
415
# # sequence of days: wet spell padded by dry days
425
- iseq <- jd [idy1 ] + seq(0 ,ncwd [1 ]+ 1 ,by = 1 )
426
- if (length(intersect(iseq ,jd ))== length(iseq )) d.available <- TRUE else
416
+ iseq <- ij [idy1 ] + seq(- 1 ,ncwd [1 ]+ 1 ,by = 1 )
417
+ if (length(intersect(iseq ,ij ))== length(iseq )) d.available <- TRUE else
427
418
idy1 <- idy1 + 1
428
419
}
429
420
# # If no available sequence of days was found, then pick just random individual days available
430
421
# # from the pool of remaining days
431
422
if (! d.available ) {
432
- iseq <- jd [seq(1 ,length(ncwd [1 ])+ 2 ,by = 1 )]
423
+ iseq <- ij [seq(1 ,length(ncwd [1 ])+ 2 ,by = 1 )]
433
424
}
434
- # # Check that dry and wet contain valid julian days from jd also, if there are elements
435
- # # out of sample, then add new random elements from jd
425
+ # # Check that dry and wet contain valid julian days from ij also, if there are elements
426
+ # # out of sample, then add new random elements from ij
436
427
nseq <- length(iseq )
437
- iseq <- intersect(iseq ,jd )
438
- dseq <- setdiff(iseq ,jd )
428
+ iseq <- intersect(iseq ,ij )
429
+ dseq <- setdiff(iseq ,ij )
439
430
diffseq <- nseq - length(iseq )
440
431
if (diffseq > 0 ) iseq <- c(iseq ,dseq [sort(rnorm(length(dseq )))][1 : diffseq ])
441
- if (nseq != length(iseq )) browser()
442
432
# # Once a suitable sequence of days have been located, use it to define wet spell padded
443
433
# # with dry days
444
- dry <- c( dry , jd [iseq [c(1 ,length(iseq ))]] )
445
- wet <- c( wet , jd [iseq [- c(1 ,length(iseq ))]] )
434
+
435
+ dry <- c( dry , iseq [c(1 ,length(iseq ))] )
436
+ wet <- c( wet , iseq [2 : (length(iseq )- 1 )] )
446
437
447
438
# # Remove duplicates - for some reason, there are some of them...
448
439
ndupl <- sum(duplicated(c(dry ,wet )))
449
440
wet <- wet [! duplicated(wet )]
450
441
dry <- dry [! duplicated(dry )]
451
442
452
443
# # Remove used indices and used wet-spell duration
453
- jd <- jd [! is.element(jd ,intersect(c(dry ,wet ),jd ))]; ncwd <- ncwd [- 1 ]
454
- # if (verbose) print(paste(length(dry),'dry days,',length(wet),'wet days =',anwd[i],': ',
455
- # length(jd),'remaining days,',length(ncwd),'spell lengths,',
456
- # length(iseq),'length of day sequence, #event=',nes,', duplicated',
457
- # ndupl,idy1,d.available))
458
-
459
- # inboth <- intersect(wet,dry)
460
- # # If cases are classified as both wet and dry, then set them to dry and
461
- # # add new wet days
462
- # if (length(inboth)>0) {
463
- # wet <- wet[!is.element(wet,inboth)]
464
- # wet <- c(wet,jd[1:length(inboth)])
465
- # jd <- jd[-c(1:length(inboth))]
466
- # }
444
+ ij <- ij [! is.element(ij ,intersect(c(dry ,wet ),ij ))]; ncwd <- ncwd [- 1 ]
445
+
467
446
# # Increment number of events
468
447
nes <- nes + 1
469
448
}
470
449
471
450
# # Finish dividing all the 366 days into wet and dry
472
- dry <- sort(c(dry ,jd )); wet <- sort(wet ); rm( ' jd ' )
451
+ dry <- sort(c(dry ,ij )); wet <- sort(wet )
473
452
# # This should not happen, but ...
474
453
dry <- dry [! duplicated(dry )]; wet <- wet [! duplicated(wet )]
475
454
# # deal with cases where days are classified as both dry and wet
@@ -484,12 +463,11 @@ WG.fwmu.day.precip <- function(x=NULL,...) {
484
463
swap <- order(rnorm(length(wet )))[1 : nwdd ]
485
464
dry <- sort(c(dry ,wet [swap ])); wet <- sort(wet [- swap ])
486
465
}
487
- # if (verbose) print(paste(length(dry),'dry days,',length(wet),'wet days =',anwd[i],': ',
488
- # length(dry)+length(wet),'assigned days, #event=',
489
- # nes,', duplicated',sum(duplicated(wet))))
490
466
467
+ if (i > length(mu )) browser()
491
468
# # The wet-day mean precipitation amount
492
469
if (! is.finite(mu [i ])) mu [i ] <- mean(mu ,na.rm = TRUE )
470
+
493
471
# # The daily amounts for wet days - first sort the data according to magnitude
494
472
# # then shuffle them according to a mix of chance and mu climatology
495
473
y <- sort(round(rexp(366 ,rate = 1 / coredata(mu [i ])),1 ),decreasing = TRUE ) + threshold
@@ -518,19 +496,17 @@ WG.fwmu.day.precip <- function(x=NULL,...) {
518
496
}
519
497
# add rain to the appropriate year:
520
498
ii <- is.element(year(t ),yrs [i ])
521
- rain <- rep(0 ,sum(ii )); iii <- 0
522
- # if (verbose) print(wet)
523
- rain [wet ] <- y [kl [wet ]]
524
-
525
- # # Make it a zoo object to assign months
526
- # if (verbose) print(range(as.Date(paste0(year(fw[i])-1,'-12-31'))+1:length(rain)))
527
- # rain <- zoo(rain,order.by=as.Date(paste0(year(fw[i])-1,'-12-31'))+1:length(rain))
499
+ rain <- rep(0 ,sum(ii ))
500
+ # # the amounts in y are sorted from high to low values - make sure y has a seasonality that
501
+ # # reflects climatology. Insert the wet days of y into rain
502
+ rain [kl ] <- y
503
+ rain [dry ] <- 0
528
504
529
- if (verbose ) print(paste(yrs [i ],' tot rain' ,round(sum(rain ,na.rm = TRUE )),
505
+ if (verbose ) print(paste(yrs [i ],i , ' tot rain' ,round(sum(rain ,na.rm = TRUE )),
530
506
' mm/year, #wet days=' ,length(wet ),' =' ,sum(rain > = 1 ),' n*fw[i]=' ,anwd [i ],
531
- ' mu[i]=' ,round(mu [i ],1 ),' #events=' ,nes ,' ii:' ,sum(ii ),
532
- ' [' ,min((1 : n )[ii ]),' ,' ,max((1 : n )[ii ]),' ]' ))
533
- z [ii ] <- rain
507
+ ' mu[i]=' ,round(mu [i ],1 ),' #events=' ,nes ,' ii:' ,sum(ii ),length( rain ),
508
+ ' [' ,min((1 : nd )[ii ]),' ,' ,max((1 : nd )[ii ]),' ]' ))
509
+ z [ii ] <- rain [ 1 : sum( ii )]
534
510
}
535
511
z <- zoo(z ,order.by = t )
536
512
class(z ) <- class(x )
0 commit comments