-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDDRP_cohorts_v1_funcs.R
1950 lines (1792 loc) · 89.9 KB
/
DDRP_cohorts_v1_funcs.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Functions used for DDRP_cohorts_v1 R----
# Last modified on 10/30/19: Modified labels for NumGen, Lifestage by Gen
#### (1). Assign_extent: assign geographic extent ####
# Add new extent definitions here for use in models and plots
# Set up regions
# Use switch() (works like a single use hash)
Assign_extent <- function(region_param = paste0(region_param)) {
REGION <- switch(region_param,
"CONUS" = extent(-125.0, -66.5, 24.54, 49.4),
"WEST" = extent(-125.0, -102, 31.1892, 49.4),
"EAST" = extent(-106.8, -66.5, 24.54, 49.4),
"MIDWEST" = extent(-104.2, -87, 30, 49.3),
"NORTHWEST" = extent(-125.1, -103.8, 40.6, 49.15),
"SOUTHWEST" = extent(-124.6, -101.5, 31.2, 42.3),
"SOUTHCENTRAL" = extent(-83.6, -78.3, 31.8, 35.3),
"NORTHCENTRAL" = extent(-104.3, -80.2, 35.7, 49.4),
"SOUTHEAST" = extent(-107.1, -75.0, 24.54, 39.6),
"NORTHEAST" = extent(-84.2, -64.3, 36.9, 48.1),
"AL" = extent(-88.5294, -84.7506, 30.1186, 35.1911),
"AR" = extent(-94.8878, -89.5094, 2.8189, 36.6936),
"AZ" = extent(-115, -108.98, 31.2, 37),
"CA" = extent(-124.6211, -113.7428, 32.2978, 42.2931),
"CO" = extent(-109.2625, -101.8625, 36.7461, 41.2214),
"CT" = extent(-73.7700, -71.7870, 40.9529, 42.0355),
"DL" = extent(-76.1392, -74.1761, 38.3508, 39.9919),
"FL" = extent(-87.8064, -79.9003, 24.54, 31.1214),
"GA" = extent(-85.7850, -80.5917, 30.1767, 35.1594),
"IA" = extent(-96.8617, -89.9697, 40.1147, 43.7353),
"ID" = extent(-117.3917, -110.6167, 41.4500, 49.15),
"IL" = extent(-91.5897, -87.0461, 36.8903, 42.6375),
"IN" = extent(-88.1686, -84.4686, 37.7836, 41.9794),
"KS" = extent(-102.3342, -94.1756, 36.6369, 40.2836),
"KY" = extent(-89.3581, -81.8425, 36.4208, 39.3347),
"LA" = extent(-94.3019, -88.7758, 28.8333, 33.2994),
"MA" = extent(-73.5639, -69.7961, 41.1689, 42.9525),
"MD" = extent(-79.7014, -74.8833, 37.0631, 39.9075),
"ME" = extent(-71.4056, -66.6667, 42.9525, 47.5228),
"MI" = extent(-90.5542, -82.3047, 41.6311, 47.5739),
"MN" = extent(-97.4000, -89.3786, 43.2550, 49.4),
"MO" = extent(-95.8803, -88.9883, 35.8822, 40.7058),
"MS" = extent(-91.7475, -87.8522, 29.9842, 35.2631),
"MT" = extent(-116.3667, -103.8250, 44.0667, 49.15),
"NC" = extent(-84.44092, -75.3003, 33.6829, 36.6461),
"ND" = extent(-104.2708, -96.3075, 45.6403, 49.15),
"NE" = extent(-104.3553, -95.0464, 39.7506, 43.2022),
"NH" = extent(-72.6617, -70.6142, 42.6256, 45.4700),
"NJ" = extent(-75.9175, -73.1892, 38.8944, 41.5806),
"NM" = extent(-109.2942, -102.6383, 31.1892, 37.2000),
"NV" = extent(-120.3358, -113.6803, 34.7356, 42.2981),
"NY" = extent(-80.0867, -71.7381, 40.4828, 45.1692),
"OH" = extent(-85.0439, -80.2464, 38.2797, 42.0217),
"OK" = extent(-103.2850, -94.1964, 33.3839, 37.2850),
"OR" = extent(-124.7294, -116.2949, 41.7150, 46.4612),
"PA" = extent(-80.7672, -74.5033, 39.4694, 42.5094),
"RI" = extent(-71.8628, -71.1206, 41.1463, 42.0188),
"SC" = extent(-83.6422, -78.3275, 31.8814, 35.3811),
"SD" = extent(-104.3553, -96.0806, 42.3050, 46.2050),
"TN" = extent(-90.3239, -81.5047, 34.5578, 37.1125),
"TX" = extent(-107.1592, -93.2411, 25.8614, 36.7200),
"UT" = extent(-114.2925, -108.7450, 36.7778, 42.2347),
"VA" = extent(-83.8322, -75.6200, 36.3892, 39.7886),
"VT" = extent(-73.6747, -71.4108, 42.5886, 45.1956),
"WA" = extent(-124.9585, -116.8364, 45.4554, 49.15),
"WI" = extent(-93.1572, -86.6822, 42.2733, 46.9914),
"WV" = extent(-82.8783, -77.5114, 37.1158, 40.7836),
"WY" = extent(-111.6167, -103.7333, 40.6667, 45.4833))
return(REGION)
}
#### (2). Base_map: base map for summary plots ####
# Base features used for all summary (PNG) maps in "PlotMap" function
# The "coord_quickmap" function allows the state/region of interest to be
# plotted (otherwise CONUS is plotted)
# geom_raster is faster than geom_tile
# Input data are in a data frame (= df) format
Base_map <- function(df) {
p <- ggplot(states, aes(x = long, y = lat)) +
geom_raster(data = df, aes(x = x, y = y, fill = value)) +
geom_path(aes(group = group), color = "gray20", lwd = 0.4) +
#theme_map(base_size = base_size) +
coord_quickmap(xlim = c(REGION@xmin, REGION@xmax),
ylim = c(REGION@ymin, REGION@ymax), expand = FALSE)
#coord_cartesian(xlim = c(REGION@xmin, REGION@xmax),
#ylim = c(REGION@ymin, REGION@ymax))
}
#### (3). CohortDistrib: cohort emergence distribution ####
# This is an approximation from GAM predictions.
CohortDistrib <- function(dist, numstage, perc) {
ReturnClosestValue <- function(dist, xval) {
out <- dist$CDF[which(dist$x > xval)[1]]
}
low <- (1 - perc)/2
high <- 1 - (1 - perc) / 2
low <- dist$x[which(dist$CDF > low)[1]]
high <- dist$x[which(dist$CDF > high)[1]]
bounds <- seq(low, high, length.out = numstage + 1)
means <- (bounds[1:numstage] + bounds[2:(numstage + 1)]) / 2
weights <- diff(sapply(X = bounds, FUN = ReturnClosestValue, dist = dist),
lag = 1)
return(data.frame(means, weights))
}
#### (4). CombineMaps: merge raster tiles ####
# Merge tiles back together for CONUS or EAST
# SpaDES.tools requires 'sf' package (needs GDAL update), so just use
# "raster::merge"
CombineMaps <- function(brick_files, type, cohort) {
# Search for file type in brick file list
fls_by_type <- brick_files[grep(pattern = paste0(type, "_"), x = brick_files,
fixed = TRUE)]
# Merge tiles back together for the input cohort
fls_by_cohort <- fls_by_type[grep(pattern = paste0("cohort", cohort),
x = fls_by_type, fixed = TRUE)]
mrgd <- Reduce(raster::merge, lapply(fls_by_cohort, brick))
#mrgd <- SpaDES.tools::mergeRaster(brk_by_cohort)
writeRaster(mrgd, filename = paste0(type, "_cohort", cohort, "_all"),
overwrite = TRUE, datatype = "INT2S", format = "GTiff")
}
#### (5). Cond: if then else (conditional) ####
# If then else raster function [sim. to GRASS r.mapcalc if (x,a,b)]
Cond <- function(condition, trueValue, falseValue) {
return(condition * trueValue + (!condition) * falseValue)
}
#### (6). CohortVals: simple way to assign weights for substages (cohorts) ####
# Choose number of substages (= numstage) and the decimal (0, 1) (= perc)
# of population to include
# Outputs standard deviations from mean and weights for substage
CohortVals <- function(numstage, perc) {
low <- qnorm((1 - perc)/2)
high <- qnorm(1 - (1 - perc) / 2)
bounds <- seq(low, high, length.out = numstage + 1)
means <- (bounds[1:numstage] + bounds[2:(numstage + 1)]) / 2
weights <- diff(pnorm(bounds), lag = 1)
return(data.frame(means, weights))
}
#### (7). Colfunc: gradient color ramp for summary maps ####
# Creates a gradient color ramp consisting of n colors
# x and y are color1 and color2
Colfunc <- function(x, y, n) {
colorRampPalette(c(x, y))(n)
}
#### (8). ConvDF: convert raster to data frame ####
# First convert raster (= rast) to a spatial pixels data frame and
# then to a data frame
ConvDF <- function(rast) {
spdf <- as(rast, "SpatialPixelsDataFrame")
df <- as.data.frame(spdf)
colnames(df) <- c("value", "x", "y")
return(df)
}
#### (9). Cut_bins: classify data into bins for plotting ####
# Classify data (= df) so it can be visualized in categories
# (e.g., 1-10, 11-20, 21-30)
Cut_bins <- function(df, breaks) {
df$value_orig <- df$value # keep old value so can sort factors against it
# round decimal places appropriately
df$value <- ifelse(df$value < 0.1, round_any(df$value, 0.01),
ifelse(df$value < 1 & df$value > 0.1, round_any(df$value, .1),
round_any(df$value, 1)))
#df$value <- ifelse(df$value < 1, round_any(df$value, .1), round_any(df$value, 1))
# Cut values into bins; remove brackets, parentheses and dashes; then order
# values will plotted in numerical order
df2 <- df %>% mutate(value = cut(value, breaks = breaks, dig.lab = 4))
df2$value <- gsub(pattern = "[()]|\\[|\\]", replacement = "", df2$value)
df2$value <- gsub(pattern = "[,]", replacement = "-", df2$value)
df2$value <- factor(df2$value,
levels = unique(df2$value[order(df2$value_orig)]))
return(df2)
}
#### (10). DailyLoop: daily loop model ####
# The daily loop is the daily time step used to generate all results for DDRP
# The loop is run for each cohort (= cohort) in parallel. If the study region
# is CONUS or EAST, then each of 4 tiles (= tile_num) are run in parallel as
# well. The template (= template) is needed for setting up data sets to
# populate during the model run, and to convert matrix outputs into raster
# format.
DailyLoop <- function(cohort, tile_num, template) {
setwd(output_dir)
# Generate a daily log file for each cohort -
# this is useful only for trouble-shooting
# if (region_param %in% c("CONUS", "EAST")) {
# daily_logFile <- paste0("Daily_loop_cohort", cohort, "_",
# tile_num, ".txt")
# } else {
# daily_logFile <- paste0("Daily_loop_cohort", cohort, ".txt")
# }
#### * Initialize rasters for all variables ####
# Main rasters - these are built upon within daily loop
DDaccum <- as.matrix(template)
# Track total degree days accumulated, for a single Lifestage (larvae)
DDtotal <- as.matrix(template)
# Track Lifestage for each cell per day (all cells start in OW = stage1)
Lifestage <- as.matrix(template) + 1
# Track voltinism per cell per day, starting at 0
NumGen <- as.matrix(template)
FullGen <- as.matrix(template)
# Additional rasters - created depending on input setting
if (exclusions_stressunits) {
# Create masks for each variable
chillmask <- as.matrix(template) # Daily chill units mask
chillstress <- as.matrix(template) # Count of daily chill units
chillstressTHRESH <- as.matrix(template) # Mask for chillstrs units thres
chillstressTHRESH <- chillstress_threshold # Mask for chillstrs units thres
chillunitsCUM <- as.matrix(template) # Cumulative chill units
chillstressMAX1 <- as.matrix(template) # Max chill before most die
chillstressMAX1 <- chillstress_units_max1 # Max chill before most die
chillstressMAX2 <- as.matrix(template) # Max chill before all die
chillstressMAX2 <- chillstress_units_max2 # Max chill before all die
chillEXCL <- as.matrix(template) # Chill stress exclusion
heatmask <- as.matrix(template) # Daily heat stress units mask
heatstress <- as.matrix(template) # Count of daily heat stress units
heatstressTHRESH <- as.matrix(template) # Mask for heatstress units thres
heatstressTHRESH <- heatstress_threshold # Mask for heatstress units thres
heatunitsCUM <- as.matrix(template) # Cumulative heat stress units
heatstressMAX1 <- as.matrix(template) # Max heat before most die
heatstressMAX1 <- heatstress_units_max1 # Max heat before most die
heatstressMAX2 <- as.matrix(template) # Max heat before all die
heatstressMAX2 <- heatstress_units_max2 # Max heat before all die
heatEXCL <- as.matrix(template) # Heat stress exclusions
AllEXCL <- as.matrix(template) # Combined stress exclusions
}
if (pems) {
if (mapE == 1 & eggEventDD) {
# Event DD for all must be specified in spp.params file for this to run
if (PEMnumgens > 0) {
# Egg DOYs for when cumDDs > eggEvent threshold OW generation
PEMe0 <- as.matrix(template)
# Egg DOYs for when cumDDs > eggEvent threshold 1st Gen
PEMe1 <- as.matrix(template)
}
if (PEMnumgens > 1) {
# Egg DOYs for when cumDDs > eggEvent threshold 2nd Gen
PEMe2 <- as.matrix(template)
}
if (PEMnumgens > 2) {
# Egg DOYs for when cumDDs > eggEvent threshold 3rd Gen
PEMe3 <- as.matrix(template)
}
if (PEMnumgens > 3) {
# Egg DOYs for when cumDDs > eggEvent threshold 4th Gen
PEMe4 <- as.matrix(template)
}
}
if (mapL == 1 & larvaeEventDD) {
if (PEMnumgens > 0) {
# Larval DOYs for when cumDDs > larvaeEvent threshold OW generation
PEMl0 <- as.matrix(template)
# Larval DOYs for when cumDDs > larvaeEvent threshold 1st Gen
PEMl1 <- as.matrix(template)
}
if (PEMnumgens > 1) {
# Larval DOYs for when cumDDs > larvaeEvent threshold 2nd Gen
PEMl2 <- as.matrix(template)
}
if (PEMnumgens > 2) {
# Larval DOYs for when cumDDs > larvaeEvent threshold 3rd Gen
PEMl3 <- as.matrix(template)
}
if (PEMnumgens > 3) {
# Larval DOYs for when cumDDs > larvaeEvent threshold 4th Gen
PEMl4 <- as.matrix(template)
}
}
if (mapP == 1 & pupaeEventDD) {
if (PEMnumgens > 0) {
# Pupal DOYs for when cumDDs > pupalEvent threshold OW generation
PEMp0 <- as.matrix(template)
# Pupal DOYs for when cumDDs > pupalEvent threshold 1st Gen
PEMp1 <- as.matrix(template)
}
if (PEMnumgens > 1) {
# Pupal DOYs for when cumDDs > pupalEvent threshold 2nd Gen
PEMp2 <- as.matrix(template)
}
if (PEMnumgens > 2) {
# Pupal DOYs for when cumDDs > pupalEvent threshold 3rd Gen
PEMp3 <- as.matrix(template)
}
if (PEMnumgens > 3) {
# Pupal DOYs for when cumDDs > pupalEvent threshold 4th Gen
PEMp4 <- as.matrix(template)
}
}
if (mapA == 1 & adultEventDD) {
if (PEMnumgens > 0) {
# Adult DOYs for when cumDDs > adultEvent threshold OW generation
PEMa0 <- as.matrix(template)
# Adult DOYs for when cumDDs > adultEvent threshold 1st Gen
PEMa1 <- as.matrix(template)
}
if (PEMnumgens > 1) {
# Adult DOYs for when cumDDs > adultEvent threshold 2nd Gen
PEMa2 <- as.matrix(template)
}
if (PEMnumgens > 2) {
# Adult DOYs for when cumDDs > adultEvent threshold 3rd Gen
PEMa3 <- as.matrix(template)
}
if (PEMnumgens > 3) {
# Adult DOYs for when cumDDs > adultEvent threshold 4th Gen
PEMa4 <- as.matrix(template)
}
}
}
#### * Step through days ####
# tryCatch(
for (d in 1:length(sublist)) {
#cat("\n\ndoy: ", sublist[d], "\n", file=daily_logFile, append=TRUE)
stage_dd_cohort <- stage_dd[as.integer(cohort), ]
# Get temperature matrices for the day
if (region_param %in% c("CONUS", "EAST")) {
tmax <- as.numeric(tmax_list[[tile_num]][[d]])
tmin <- as.numeric(tmin_list[[tile_num]][[d]])
} else {
tmax <- as.numeric(tmax_list[[d]])
tmin <- as.numeric(tmin_list[[d]])
}
# Assign each raster cell to a Lifestage
# These three matrices assign physiological parameters by cell
ls_ldt <- stage_ldt[Lifestage]
ls_udt <- stage_udt[Lifestage]
ls_dd <- stage_dd_cohort[Lifestage]
# Calculate stage-specific degree-days for each cell per day
dd_tmp <- TriDD(tmax, tmin, ls_ldt, ls_udt)
# Accumulate degree days
DDaccum <- DDaccum + dd_tmp
# Accumulate total DDs across year, using larvae Lifestage
# Can not use DDaccum because this one has values reset when progress = 1
ls_ldt_larv <- stage_ldt[which(stgorder == "L")]
ls_udt_larv <- stage_udt[which(stgorder == "L")]
dd_tmp_larv <- TriDD(tmax, tmin, ls_ldt_larv, ls_udt_larv)
DDtotal <- DDtotal + dd_tmp_larv
# Climate stress exclusions - results will be same for all cohorts,
# so just calculate exclusions for cohort 1
if (exclusions_stressunits) {
# Chill stress accumulation
# Make today's chill mask and calculate today's chill stress DDs
chillmask <- tmin < chillstressTHRESH
chillstress <- chillmask * abs(chillstressTHRESH - tmin)
chillunitsCUM <- chillunitsCUM + chillstress
# ASSUME NEW -2=severe -1=mod 0=none throughout
chillEXCL <- Cond(chillunitsCUM >= chillstressMAX2, -2,
Cond(chillunitsCUM >= chillstressMAX1, -1, 0))
# Heat stress accumulation
# Make today's heat mask and calculate today's heat stress DDs
heatmask <- tmax > heatstressTHRESH
heatstress <- heatmask * abs(tmax - heatstressTHRESH)
heatunitsCUM <- heatunitsCUM + heatstress
heatEXCL <- Cond(heatunitsCUM >= heatstressMAX2, -2,
Cond(heatunitsCUM >= heatstressMAX1, -1, 0))
AllEXCL <- Cond((chillEXCL == 0) & (heatEXCL == 0), 0,
Cond((chillEXCL == -1) & (heatEXCL >= -1),-1,
Cond((chillEXCL >= -1) & (heatEXCL == -1), -1, -2)))
}
# Calculate pest events
# DOYs for when cumDDs > event threshold for a given generation
if (pems) {
# The OW pest event is a percentage of the OW stage DDs
# (e.g. OWEventP = 0.5 would be 50% of the OWlarvaeDD, or half-way
# through OWlarvaeDD). It is specified in the species param file.
OWEventDD <- stage_dd_cohort[1] * OWEventP
# Egg PEMs
if (mapE == 1 & eggEventDD) {
if (PEMnumgens > 0) {
if (owstage == "OE") {
# If owstage = egg, then eggs finish developing after the DD of OWegg
# for that cohort (do NOT use OWeggDD from param file - this is for
# DDRP v2)
PEMe0 <- Cond(PEMe0 == 0 & NumGen == 0 & (DDaccum >= OWEventDD),
d * (Lifestage == which(stgorder == "OE")), PEMe0)
}
# Egg DOYs for when cumDDs > eggEvent threshold 1st gen
PEMe1 <- Cond(PEMe1 == 0 & NumGen == 1 & (DDaccum >= eggEventDD),
d * (Lifestage == which(stgorder == "E")), PEMe1)
}
if (PEMnumgens > 1) {
# Egg DOYs for when cumDDs > eggEvent threshold 2nd gen
PEMe2 <- Cond(PEMe2 == 0 & NumGen == 2 & (DDaccum >= eggEventDD),
d * (Lifestage == which(stgorder == "E")), PEMe2)
}
if (PEMnumgens > 2) {
# Egg DOYs for when cumDDs > eggEvent threshold 3rd gen
PEMe3 <- Cond(PEMe3 == 0 & NumGen == 3 & (DDaccum >= eggEventDD),
d * (Lifestage == which(stgorder == "E")), PEMe3)
}
if (PEMnumgens > 3) {
# Egg DOYs for when cumDDs > eggEvent threshold 4th gen
PEMe4 <- Cond(PEMe4 == 0 & NumGen == 4 & (DDaccum >= eggEventDD),
d * (Lifestage == which(stgorder == "E")), PEMe4)
}
}
# Larvae PEMs
if (mapL == 1 & larvaeEventDD) {
if (PEMnumgens > 0) {
if (owstage == "OL") {
# If owstage = larvae, then larvae finish developing after the DD of
# OWlarvae for that cohort (do NOT use OWlarvaeDD from species
# param file - this is for DDRP v2 only)
PEMl0 <- Cond(PEMl0 == 0 & NumGen == 0 & (DDaccum >= OWEventDD),
d * (Lifestage == which(stgorder == "OL")), PEMl0)
# If owstage = egg, then larvae of this OW gen will have to go through
# full development
} else if (owstage %in% c("OE")) {
PEMl0 <- Cond(PEMl0 == 0 & NumGen == 0 & (DDaccum >= larvaeEventDD),
d * (Lifestage == which(stgorder == "L")), PEMl0)
}
# Larvae DOYs for when cumDDs > larvaeEvent threshold 1st gen
PEMl1 <- Cond(PEMl1 == 0 & NumGen == 1 & (DDaccum >= larvaeEventDD),
d * (Lifestage == which(stgorder == "L")), PEMl1)
}
if (PEMnumgens > 1) {
# Larvae DOYs for when cumDDs > larvaeEvent threshold 2nd gen
PEMl2 <- Cond(PEMl2 == 0 & NumGen == 2 & (DDaccum >= larvaeEventDD),
d * (Lifestage == which(stgorder == "L")), PEMl2)
}
if (PEMnumgens > 2) {
# Larvae DOYs for when cumDDs > larvaeEvent threshold 3rd gen
PEMl3 <- Cond(PEMl3 == 0 & NumGen == 3 & (DDaccum >= larvaeEventDD),
d * (Lifestage == which(stgorder == "L")), PEMl3)
}
if (PEMnumgens > 3) {
# Larvae DOYs for when cumDDs > larvaeEvent threshold 4th gen
PEMl4 <- Cond(PEMl4 == 0 & NumGen == 4 & (DDaccum >= larvaeEventDD),
d * (Lifestage == which(stgorder == "L")), PEMl4)
}
}
# Pupae PEMs
if (mapP == 1 & pupaeEventDD) {
if (PEMnumgens > 0) {
if (owstage == "OP") {
# If owstage = pupae, then pupae finish developing after the DD of
# OWpupae for that cohort (do NOT use OWpupaeDD from species param
# file - this is for DDRP v2)
PEMp0 <- Cond(PEMp0 == 0 & NumGen == 0 & (DDaccum >= OWEventDD),
d * (Lifestage == which(stgorder == "OP")), PEMp0)
} else if (owstage %in% c("OE", "OL")) {
# If owstage = egg or larvae, then pupae of the OW gen will have to
# go through full development
PEMp0 <- Cond(PEMp0 == 0 & NumGen == 0 & (DDaccum >= pupaeEventDD),
d * (Lifestage == which(stgorder == "P")), PEMp0)
}
# Pupae DOYs for when cumDDs > pupaeEvent threshold 1st gen
PEMp1 <- Cond(PEMp1 == 0 & NumGen == 1 & (DDaccum >= pupaeEventDD),
d * (Lifestage == which(stgorder == "P")), PEMp1)
}
if (PEMnumgens > 1) {
# Pupae DOYs for when cumDDs > pupaeEvent threshold 2nd gen
PEMp2 <- Cond(PEMp2 == 0 & NumGen == 2 & (DDaccum >= pupaeEventDD),
d * (Lifestage == which(stgorder == "P")), PEMp2)
}
if (PEMnumgens > 2) {
# Pupae DOYs for when cumDDs > pupaeEvent threshold 3rd gen
PEMp3 <- Cond(PEMp3 == 0 & NumGen == 3 & (DDaccum >= pupaeEventDD),
d * (Lifestage == which(stgorder == "P")), PEMp3)
}
if (PEMnumgens > 3) {
# Pupae DOYs for when cumDDs > pupaeEvent threshold 4th gen
PEMp4 <- Cond(PEMp4 == 0 & NumGen == 4 & (DDaccum >= pupaeEventDD),
d * (Lifestage == which(stgorder == "P")), PEMp4)
}
}
# Adult PEMs
if (mapA == 1 & adultEventDD) {
if (PEMnumgens > 0) {
if (owstage == "OA") {
# If owstage = adult, then adults finish developing after the DD of
# OWadult for that cohort (do NOT use OWadultDD from species param
# file - this is for DDRP v2)
PEMa0 <- Cond(PEMa0 == 0 & NumGen == 0 & (DDaccum >= OWEventDD),
d * (Lifestage == which(stgorder == "OA")), PEMa0)
} else if (owstage %in% c("OL", "OP")) {
# If owstage = larvae or pupae, then adults of the OW gen will
# have to go through full development
PEMa0 <- Cond(PEMa0 == 0 & NumGen == 0 & (DDaccum >= adultEventDD),
d * (Lifestage == which(stgorder == "A")), PEMa0)
}
# Adult DOYs for when cumDDs > adultEvent threshold 1st gen
PEMa1 <- Cond(PEMa1 == 0 & NumGen == 1 & (DDaccum >= adultEventDD),
d * (Lifestage == which(stgorder == "A")), PEMa1)
}
if (PEMnumgens > 1) {
# Adult DOYs for when cumDDs > adultEvent threshold 2nd gen
PEMa2 <- Cond(PEMa2 == 0 & NumGen == 2 & (DDaccum >= adultEventDD),
d * (Lifestage == which(stgorder == "A")), PEMa2)
}
if (PEMnumgens > 2) {
# Adult DOYs for when cumDDs > adultEvent threshold 3rd gen
PEMa3 <- Cond(PEMa3 == 0 & NumGen == 3 & (DDaccum >= adultEventDD),
d * (Lifestage == which(stgorder == "A")), PEMa3)
}
if (PEMnumgens > 3) {
# Adult DOYs for when cumDDs > adultEvent threshold 4th gen
PEMa4 <- Cond(PEMa4 == 0 & NumGen == 4 & (DDaccum >= adultEventDD),
d * (Lifestage == which(stgorder == "A")), PEMa4)
}
}
}
# Calculate Lifestage progression: Is accumulation > Lifestage requirement
# (0 = FALSE, 1 = TRUE)? If species has obligate diapause, then don't
# allow it to progress past the 1st gen overwintering stage.
if (exists("obligate_diapause")) {
if (obligate_diapause == 1) {
if (owstage == "OL") {
progress <- Cond(NumGen <= 1 & Lifestage != which(stgorder == "L"),
as.integer(DDaccum >= ls_dd), 0)
} else if (owstage == "OP") {
progress <- Cond(NumGen <= 1 & Lifestage != which(stgorder == "P"),
as.integer(DDaccum >= ls_dd), 0)
} else if (owstage == "OA") {
progress <- Cond(NumGen <= 1 & Lifestage != which(stgorder == "A"),
as.integer(DDaccum >= ls_dd), 0)
} else if (owstage == "OE") {
progress <- Cond(NumGen <= 1 & Lifestage != which(stgorder == "E"),
as.integer(DDaccum >= ls_dd), 0)
}
}
# If no obligate diapause, then there are no limits on no. of generations
} else {
progress <- as.integer(DDaccum >= ls_dd)
}
# If reproductive adult stage progresses, then that cell has oviposition
# and the generation count increases. If species has OW adults, then need
# to change stage value to "adult" to allow NumGen to increase when it
# progresses. "OA" = 1, and "adult" = 5 for species with OW adults
if (owstage == "OA") {
Lifestage2 <- Lifestage
Lifestage2[Lifestage2 == 1] <- 5
NumGen <- NumGen + (progress == 1 & Lifestage2 == 5)
} else {
# Value for "adult" varies depending on OW stage
NumGen <- NumGen + (progress == 1 & Lifestage == which(stgorder == "A"))
}
#cat("No. gen (max): ", max(NumGen, na.rm=T), "\n", file=daily_logFile,
#append=TRUE)
# FullGen means it reaches the OW stage
FullGen <- FullGen + (progress == 1 & Lifestage == (length(stgorder) - 1))
Lifestage <- Lifestage + progress
# Reset the DDaccum cells to zero for cells that progressed to next stage
DDaccum <- DDaccum - (progress * ls_dd)
#cat("DDaccum (max): ", max(DDaccum, na.rm=T), "\n", file=daily_logFile,
#append=TRUE)
# Reassign cells that progressed past end of stgorder to first non-OW stage
Lifestage <- Cond(Lifestage == (length(stgorder) + 1), 2, Lifestage)
#cat("Lifestage (max): ", max(Lifestage, na.rm=T), file=daily_logFile,
#append=TRUE)
#### * Save data for certain days, specified by sampling frequency ####
# Data from last sampling day of year is also saved
if (sublist[d] %in% sample_pts) {
# Convert Lifestage and Numgen matrices to rasters and put into a brick
mat_list <- list(Lifestage,NumGen,DDtotal)
ext <- as.data.frame(as.matrix(extent(template)))
rast_list <- lapply(mat_list, Mat_to_rast, ext = ext, template = template)
names(rast_list) <- c("Lifestage_rast", "NumGen_rast", "DDtotal_rast")
#cat("\n\n### Adding layers to Lifestage brick for cohort", cohort, ":
#doy =", sublist[d], "\n", file=daily_logFile, append=TRUE)
# Lifestage brick
if (!exists("Lifestage_brick")) {
Lifestage_brick <- brick(rast_list$Lifestage_rast, crs = crs)
} else {
Lifestage_brick <- addLayer(Lifestage_brick, rast_list$Lifestage_rast)
}
#cat("### Adding layers to NumGen brick for cohort", cohort, ": doy =",
#sublist[d], "\n", file=daily_logFile, append=TRUE)
# NumGen brick
if (!exists("NumGen_brick")) {
NumGen_brick <- brick(rast_list$NumGen_rast, crs = crs)
} else {
NumGen_brick <- addLayer(NumGen_brick, rast_list$NumGen_rast)
}
# Only need to do DDtotal brick for a single cohort, because it will be
# the same across all cohorts
if (cohort == 1) {
#cat("### Adding layers to DDtotal brick for cohort", cohort, ": doy =",
# sublist[d], file=daily_logFile, append=TRUE)
if (!exists("DDtotal_brick")) {
DDtotal_brick <- brick(rast_list$DDtotal_rast, crs = crs)
} else {
DDtotal_brick <- addLayer(DDtotal_brick, rast_list$DDtotal_rast)
}
}
# If exclusions_stressunits = 1, then do the same thing for LifestageEXCL
# and NumGenEXCL, after they are calculated
if (exclusions_stressunits) {
# Exclusions included: -2=severe stress, -1=moderate stress
LifestageEXCL1 <- Cond((AllEXCL > -2), Lifestage, -2)
LifestageEXCL2 <- Cond((AllEXCL == -2), -2,
Cond((AllEXCL == -1), -1, Lifestage))
NumGenEXCL1 <- Cond((AllEXCL > -2), NumGen, -2)
NumGenEXCL2 <- Cond((AllEXCL == -2), -2,
Cond((AllEXCL == -1), -1, NumGen))
# Convert LifestageEXCL and NumgenEXCL matrices to rasters and
# put into a brick
mat_list2 <- list(LifestageEXCL1,LifestageEXCL2,
NumGenEXCL1,NumGenEXCL2)
ext <- as.data.frame(as.matrix(extent(template)))
rast_list2 <- lapply(mat_list2, Mat_to_rast, ext = ext,
template = template)
names(rast_list2) <- c("LifestageEXCL1_rast", "LifestageEXCL2_rast",
"NumGenEXCL1_rast", "NumGenEXCL2_rast")
#cat("### Adding layers to Lifestage Stress Exclusion 1 brick for
#cohort", cohort, ": doy =", sublist[d], "\n",
#file=daily_logFile, append=TRUE)
# LifestageEXCL1 brick
if (!exists("LifestageEXCL1_brick")) {
LifestageEXCL1_brick <- brick(rast_list2$LifestageEXCL1_rast,
crs = crs)
} else {
LifestageEXCL1_brick <- addLayer(LifestageEXCL1_brick,
rast_list2$LifestageEXCL1_rast)
}
#cat("### Adding layers to Lifestage Stress Exclusion 2 brick
#for cohort", cohort, ": doy =", sublist[d], "\n",
#file=daily_logFile, append=TRUE)
# LifestageEXCL2 brick
if (!exists("LifestageEXCL2_brick")) {
LifestageEXCL2_brick <- brick(rast_list2$LifestageEXCL2_rast,
crs = crs)
} else {
LifestageEXCL2_brick <- addLayer(LifestageEXCL2_brick,
rast_list2$LifestageEXCL2_rast)
}
#cat("### Adding layers to NumGen Stress Exclusion 1 brick for cohort",
# cohort, ": doy =", sublist[d], "\n", file=daily_logFile, append=TRUE)
# NumGenEXCL1 brick
if (!exists("NumGenEXCL1_brick")) {
NumGenEXCL1_brick <- brick(rast_list2$NumGenEXCL1_rast, crs = crs)
} else {
NumGenEXCL1_brick <- addLayer(NumGenEXCL1_brick,
rast_list2$NumGenEXCL1_rast)
}
#cat("### Adding layers to NumGen Stress Exclusion 2 brick for cohort",
#cohort, ": doy =", sublist[d], file=daily_logFile, append=TRUE)
# NumGenEXCL2 brick
if (!exists("NumGenEXCL2_brick")) {
NumGenEXCL2_brick <- brick(rast_list2$NumGenEXCL2_rast, crs = crs)
} else {
NumGenEXCL2_brick <- addLayer(NumGenEXCL2_brick,
rast_list2$NumGenEXCL2_rast)
}
# Do the same for chill/heat units and chill/heat exclusion, but just
# for cohort 1, because results will be same for all cohorts
if (cohort == 1) {
# Convert matrices to rasters and put them into a raster brick
mat_list3 <- list(chillunitsCUM, chillEXCL, heatunitsCUM,
heatEXCL,AllEXCL)
ext <- as.data.frame(as.matrix(extent(template)))
rast_list3 <- lapply(mat_list3, Mat_to_rast, ext = ext,
template = template)
names(rast_list3) <- c("chillunitsCUM_rast", "chillEXCL_rast",
"heatunitsCUM_rast", "heatEXCL_rast", "AllEXCL_rast")
#cat("\n### Adding layers to Chill Stress Units brick for cohort",
#cohort, ": doy =", sublist[d], "\n", file=daily_logFile, append=TRUE)
# Chill stress unit accumulation brick
if (!exists("chillunitsCUM_brick")) {
chillunitsCUM_brick <- brick(rast_list3$chillunitsCUM_rast,
crs = crs)
} else {
chillunitsCUM_brick <- addLayer(chillunitsCUM_brick,
rast_list3$chillunitsCUM_rast)
}
#cat("### Adding layers to Chill Stress Exclusion brick for cohort",
#cohort, ": doy =", sublist[d], "\n", file=daily_logFile, append=TRUE)
# Chill stress exclusion brick
if (!exists("chillEXCL_brick")) {
chillEXCL_brick <- brick(rast_list3$chillEXCL_rast, crs = crs)
} else {
chillEXCL_brick <- addLayer(chillEXCL_brick,
rast_list3$chillEXCL_rast)
}
#cat("### Adding layers to Heat Stress Units brick for cohort",
#cohort, ": doy =", sublist[d], "\n", file=daily_logFile, append=TRUE)
# Heat stress unit accumulation brick
if (!exists("heatunitsCUM_brick")) {
heatunitsCUM_brick <- brick(rast_list3$heatunitsCUM_rast, crs = crs)
} else {
heatunitsCUM_brick <- addLayer(heatunitsCUM_brick,
rast_list3$heatunitsCUM_rast)
}
#cat("### Adding layers to Heat Stress Exclusion brick for cohort",
#cohort, ": doy =", sublist[d], "\n", file=daily_logFile, append=TRUE)
# Heat stress exclusion brick
if (!exists("heatEXCL_brick")) {
heatEXCL_brick <- brick(rast_list3$heatEXCL_rast, crs = crs)
} else {
heatEXCL_brick <- addLayer(heatEXCL_brick, rast_list3$heatEXCL_rast)
}
#cat("### Adding layers to All Stress Exclusion brick for cohort",
# cohort, ": doy =", sublist[d], file=daily_logFile, append=TRUE)
# All stress exclusion brick (chill stress + heat stress exclusions)
if (!exists("AllEXCL_brick")) {
AllEXCL_brick <- brick(rast_list3$AllEXCL_rast, crs = crs)
} else {
AllEXCL_brick <- addLayer(AllEXCL_brick, rast_list3$AllEXCL_rast)
}
}
}
}
}#,
# error = function(e) {
# # Add error message to the error log file
# write(toString(e), msg, append=TRUE)
# }
# )
### * Daily loop done - save raster bricks ###
# Save non-optional raster bricks = Lifestage and NumGen
SaveRaster(Lifestage_brick, cohort, tile_num, "Lifestage", "INT1U")
SaveRaster(NumGen_brick, cohort, tile_num, "NumGen", "INT1U")
# Save DDtotal brick (only for cohort 1)
if (cohort == 1) {
SaveRaster(DDtotal_brick, cohort, tile_num, "DDtotal", "INT2S")
}
# If Pest Event Maps are specified (pems = 1), then convert PEM matrices
# to rasters and save them
if (pems) {
pem_list <- mget(ls(pattern = "PEMe|PEMl|PEMp|PEMa"))
# Convert each matrix in the list to a raster and save it
for (i in 1:length(pem_list)) {
pem_mat <- pem_list[[i]]
pem_rast <- Mat_to_rast(pem_mat, ext, template)
if (region_param %in% c("CONUS", "EAST")) {
SaveRaster(pem_rast, cohort, tile_num, names(pem_list[i]), "INT2U")
} else {
SaveRaster(pem_rast, cohort, NA, names(pem_list[i]), "INT2U")
}
}
}
# If exclusions_stressunits = 1, then save stress unit and exclusions bricks
if (exclusions_stressunits) {
# Lifestage and NumGen climate stress exclusion files will vary across
# cohorts, so they need to be processed to produce final results in "Data
# Processing" section
SaveRaster(LifestageEXCL1_brick, cohort, tile_num, "LifestageEXCL1",
"INT2S")
SaveRaster(LifestageEXCL2_brick, cohort, tile_num, "LifestageEXCL2",
"INT2S")
SaveRaster(NumGenEXCL1_brick, cohort, tile_num, "NumGenExcl1", "INT2S")
SaveRaster(NumGenEXCL2_brick, cohort, tile_num, "NumGenExcl2", "INT2S")
# Chill and heat stress unit and exclusion bricks will be the same for
# all cohorts, so take only 1st one
if (cohort == 1) {
stress_excl_brick_list <- c(chillunitsCUM_brick, chillEXCL_brick,
heatunitsCUM_brick, heatEXCL_brick,AllEXCL_brick)
names(stress_excl_brick_list) <- c("Chill_Stress_Units",
"Chill_Stress_Excl", "Heat_Stress_Units", "Heat_Stress_Excl",
"All_Stress_Excl")
# Save each raster brick product in the list
for (i in 1:length(stress_excl_brick_list)) {
brk <- stress_excl_brick_list[[i]]
SaveRaster(brk, cohort, tile_num,
paste0(names(stress_excl_brick_list[i])), "INT2S")
}
}
#cat("\n### Finished climate exclusions and stress units raster output
#cohort", cohort, "###\n\n", file = Model_rlogging, append=TRUE)
}
# Remove .xml files generated w/ .tif files for certain raster bricks
# Haven't yet figured out a way to prevent these from being created. The
# only solution I have found is to change a GDAL setting.
delfiles <- dir(path = output_dir, pattern = "*xml")
suppressWarnings(file.remove(file.path = output_dir, delfiles))
gc() # Clear items from the environment - is this necessary?
}
#### (11). Degree Day calculation methods ####
# Equations used to calculate degree-days
# tmax = max. temp. data; tmin = min. temp data; LDT = lower developmental
# temperature threshold; UDT = upper developmental temperature threshold
# Simple Mean Temp DD Calc method: ((tmean > LDT) * (tmean - LDT))
# Same result as max((tmax + tmin)/2 - LDT,0), so no need for tmean PRISM data.
SimpDD <- function(tmax, tmin,LDT) {
return(max((tmax + tmin)/2 - LDT,0))
}
# Averaging DD Calc method (max + min/2 - tlow) but with horizontal
# (substitution) upper threshold:
AvgDD <- function(tmax, tmin, LDT, UDT) {
return(Cond(tmax < LDT, 0, Cond(tmin > UDT, 0,
Cond(tmax > UDT, (UDT + tmin)/2 - LDT,
Cond((tmax + tmin)/2 - LDT < 0,0,
(tmax + tmin)/2 - LDT)))))
}
# Single triangle with upper threshold (Sevachurian et al. 1977) -
# also a good substitution for the single sine method
TriDD <- function(tmax, tmin, LDT, UDT) {
tmax <- Cond(tmax == tmin, tmax + 0.01, tmax)
Tmp1 = 6*((tmax - LDT)*(tmax - LDT))/(tmax - tmin)
Tmp2 = 6*((tmax - UDT)*(tmax - UDT))/(tmax - tmin)
Cond(tmax < LDT,0,
Cond(tmin >= UDT,UDT - LDT,
Cond((tmax < UDT) & (tmin <= LDT), Tmp1/12,
Cond((tmin <= LDT) & (tmax >= UDT), (Tmp1 - Tmp2)/12,
Cond((tmin > LDT) & (tmax >= UDT),
6*(tmax + tmin - 2*LDT)/12 - (Tmp2/12),
Cond((tmin > LDT) & (tmax < UDT),
6*(tmax + tmin - 2*LDT)/12,0))))))
}
#### (12). ExtractBestPRISM: get best PRISM/NMME file from directory ####
# Take .bil files from PRISM or NMME (= forecast_data) yearly directories
# (= files). The function returns the best data for each day. If data are
# from a leap year, then leap day data may be removed or kept (= keep_leap).
ExtractBestPRISM <- function(files, forecast_data, keep_leap) {
numsplits <- str_count(string = files[1], pattern = "/")
pfile <- str_split(string = files, pattern = coll("/"), numsplits) %>%
purrr::map(numsplits)
qa <- str_split(string = pfile, pattern = coll("_"), 6) %>% purrr::map(3) %>%
unlist()
# Extract dates - the dates will always be the largest number, so sort and
# then take first element of vector
dates <- regexpr(pattern = "[0-9]{8}", text = files)
df <- data.frame(dates = regmatches(files, dates),
quality = substr(qa, start = 1, stop = 4),
rownum = 1:length(qa))
# Added to Tyson's version of this function - ability to choose PRISM vs.
# NMME for future dates
if (forecast_data == "PRISM") {
df <- mutate(df, rank = ifelse(quality == "stab", 1,
ifelse(quality == "prov", 2,
ifelse(quality == "earl", 3,
ifelse(quality == "10yr", 4,
ifelse(quality == "30yr", 5,
ifelse(quality == "nmme", 6, NA)))))))
} else if (dat == "NMME") {
df <- mutate(df, rank = ifelse(quality == "stab", 1,
ifelse(quality == "prov", 2,
ifelse(quality == "earl", 3,
ifelse(quality == "nmme", 4,
ifelse(quality == "10yr", 5,
ifelse(quality == "30yr", 6, NA)))))))
}
# Sorting backwards matches data hierarchy
# If PRISM, then stable > provisional > early > 10yr > 30yr > nmme
# If NMME, then stable > provisional > early > nmme > 10yr > 30yr
df2 <- df %>% group_by(dates) %>%
dplyr::filter(rank == min(rank)) %>%
dplyr::filter(1:n() == 1)
best <- files[df2$rownum]
dates <- regexpr(pattern = "[0-9]{8}", text = best)
fileorder <- order(regmatches(best, dates))
files <- best[fileorder]
# Remove leap day (2/29) if the start_year is not a leap year, or if it is
# a leap year but user wants it removed (keep_leap == 0). This doesn't apply
# if 30 yr average data or other non-specific year data are being used
# (in this case, start_year is non-numeric)
if (is.numeric(start_year)) {
if (start_year %% 4 != 0 | start_year %% 4 == 0 & keep_leap == 0) {
files <- files[!grepl(paste0(start_year, "0229"), files)]
}
}
return(files)
}
#### (13). Mat_to_rast: matrix to raster conversion ####
# Converts a matrix (= m) to a raster, which involves specifying the extent
# (= ext) from the template (= template), setting the coordinate system, and
# assigning it a spatial resolution (from the template)
Mat_to_rast <- function(m, ext, template) {
rast <- raster(m, xmn = ext[1,1], xmx = ext[1,2],
ymn = ext[2,1], ymx = ext[2,2])
crs(rast) <- "+proj=longlat +datum=NAD83 +no_defs +ellps=GRS80 +towgs84=0,0,0"
res(rast) <- res(template)
NAvalue(rast) <- NaN
return(rast)
}
#### (14). PlotMap: summary map plotting - main ####
# A VERY large function that generates summary plots for all products generated
# in the DDRP model run
# r = raster input, d = date, lgd = legend title, outfl = outfile name
PlotMap <- function(r, d, titl, lgd, outfl) {
# If data are in raster format, then convert to a data frame
if (grepl("NumGen|Adult_byGen|Adult_Excl1_byGen|Adult_Excl2_byGen", outfl)) {
df <- r # data are already in a data frame
} else {
df <- ConvDF(r) # convert raster to data frame
}
# Format all labels used for the plot
sp <- paste0(fullname, ":") # Species full name
dat <- as.character(format(strptime(d, format = "%Y%m%d"),
format = "%m/%d/%Y")) # Date
titl_orig <- titl # Used for some log captions
# Plot title - if it's not a PEM, then put sampling date in title
if (!grepl("Avg|Earliest", outfl)) {
titl <- paste(titl, dat, sep = " ")
}
if (grepl("PEM", outfl)) {
start_year <- strtrim(d, 4) # if using 30 yr data, need to trim other chars
titl <- paste(titl, start_year, sep = " ")
}
# Subtitle (same for all plots)
subtitl <- paste("Maps and modeling",
format(Sys.Date(), "%m/%d/%Y"), str_wrap("by Oregon State University IPPC
USPEST.ORG and USDA-APHIS-PPQ; climate data from OSU PRISM Climate Group",
width = 150))
# Need to enforce a rule for wrapping title and subtitle on plot
# The title and subtitle go off of page for some states (VT...any else?)
if (asp > 1.55) {
titl_width <- 45
subtitl_width <- 55
} else if (asp >= 1.4 & asp < 1.55) {
titl_width <- 55
subtitl_width <- 65
} else {
titl_width <- 65
subtitl_width <- 75
}
# Code for plots will vary depending on the product type, as specified below
#
#### * DDtotal ####
if (grepl("DDtotal", outfl)) {
# Caption for log file
log_capt <- paste("- Number of accumulated degree-days on",
format(as.Date(d, "%Y%m%d"), "%m/%d/%Y"))
# Create plot separately for rasters where all DDtotal values = 0
if (all(df$value == 0)) {
df$value <- factor(df$value)
p <- Base_map(df) +