Chapter 7 Chill models
Learning goals for this lesson
- Learn how to run chill models using
chillR
- Learn how to produce your own temperature response model in
chillR
7.1 Chill models in chillR
We already learned how to write a function to calculate Chilling Hours. Unfortunately, you may never have to do that, because chillR
already contains such a function. It’s called Chilling_Hours()
, and here’s what it looks like:
## function (HourTemp, summ = TRUE)
## {
## CH_range <- which(HourTemp <= 7.2 & HourTemp >= 0)
## CH_weights <- rep(0, length(HourTemp))
## CH_weights[CH_range] <- 1
## if (summ == TRUE)
## return(cumsum(CH_weights))
## else return(CH_weights)
## }
## <bytecode: 0x000001fbd0657c38>
## <environment: namespace:chillR>
This is a pretty basic function that takes an hourly temperature dataset (HourTemp
) as input and determines for each hour if temperatures are below 7.2°C and above 0°C. If the argument summ
is TRUE
, the function returns the cumulative Chilling Hours that have accumulated by every hour of the record. If this argument is FALSE
, we just get a list of 1s and 0s to indicate which hours are Chilling Hours and which ones aren’t. The default version of the function is to run it with summ==TRUE
, as you can see in the first line of the function. So if you don’t specify anything for the summ
argument, it will return the cumulative sum of Chilling Hours.
We can easily apply this now to our Winters_hours_gap
dataset:
## [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 2 3 4 5 6
## [23] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [45] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 7 8 9 10 11
## [67] 12 13 14 15 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 17 18 19
## [89] 20 21 22 23 24 25 25 25 25 25 25 25
I only returned the first 100 values. The dataset contains 5974 more. The last number in this entire series is 203.
Chilling Hours are great for an entry-level tutorial on chill modeling, but they’re not a particularly credible metric, so I suggest you forget them right away. Let’s turn our eyes towards more credible models.
The Utah Model (Richardson et al., 1974) is somewhat more credible, since it assumes different weights for different temperatures. This model is also implemented in chillR
:
## function (HourTemp, summ = TRUE)
## return(step_model(HourTemp, df = data.frame(lower = c(-1000,
## 1.4, 2.4, 9.1, 12.4, 15.9, 18), upper = c(1.4, 2.4, 9.1,
## 12.4, 15.9, 18, 1000), weight = c(0, 0.5, 1, 0.5, 0, -0.5,
## -1)), summ = summ))
## <bytecode: 0x000001fbd43ebb38>
## <environment: namespace:chillR>
## [1] 0.0 -0.5 -1.5 -2.5 -3.5 -4.5 -5.5 -6.0 -6.0 -6.0 -5.5 -5.0 -4.0
## [14] -3.0 -2.0 -1.0 0.0 0.5 1.5 2.5 3.5 4.5 5.0 5.0 5.0 4.0
## [27] 3.0 2.0 1.0 0.0 -1.0 -2.0 -2.5 -2.5 -2.0 -1.5 -1.0 -0.5 0.5
## [40] 1.0 1.5 2.0 2.0 2.5 3.0 3.5 4.0 4.0 4.0 3.5 2.5 1.5
## [53] 0.5 -0.5 -1.5 -2.5 -3.0 -3.0 -2.5 -1.5 -0.5 0.5 1.5 2.5 3.5
## [66] 4.5 5.5 6.5 7.5 8.5 9.5 10.0 10.0 9.5 9.0 8.5 8.0 7.5
## [79] 7.0 6.5 6.5 7.0 7.5 8.5 9.5 10.5 11.5 12.5 13.5 14.5 15.5
## [92] 16.5 17.5 18.5 19.0 19.0 19.0 18.5 17.5 16.5
In the definition of this model, you see another function called step_model()
. This is also a chillR
function, which allows you to define your own model, based on temperature thresholds and weights. You could, for example, use this function to implement various variations of the Utah Model that have been developed for different locations. The function takes as input a data.frame
that contains the weights you want to apply to different temperature ranges.
Here’s an example of such a data.frame
, a function called custom()
that implements a chill model based on this, and the application of this function to the Winters_hours_gaps
dataset:
df<-data.frame(
lower= c(-1000, 1, 2, 3, 4, 5, 6),
upper= c( 1, 2, 3, 4, 5, 6, 1000),
weight=c( 0, 1, 2, 3, 2, 1, 0))
kable(df) %>%
kable_styling("striped", position = "left", font_size = 10)
lower | upper | weight |
---|---|---|
-1000 | 1 | 0 |
1 | 2 | 1 |
2 | 3 | 2 |
3 | 4 | 3 |
4 | 5 | 2 |
5 | 6 | 1 |
6 | 1000 | 0 |
## [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 4 7
## [23] 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
## [45] 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 10
## [67] 13 16 19 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 23
## [89] 25 27 29 31 34 37 37 37 37 37 37 37
The Chilling Hours and Utah Models are fairly straightforward. We could probably have calculated these metrics without these functions, though of course the process gets easier with them. What has long been a much greater challenge to dormancy modelers is implementing the ‘Dynamic Model’, which involves pretty complicated equations. The original papers on this model were rather heavy on maths, leaving many horticultural researchers a bit lost. For a long time, the only version of the model that people could easily use was an Excel sheet that was put together a few decades ago. For chillR
, I extracted all the equations from this Excel sheet, to make the Dynamic_Model()
function. This is pretty complicated, and a bit of effort was needed to get this right. But the effort was worth it - now we’ll never have to deal with these equations again, because we have a function that does all the calculations for us.
## [1] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [7] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [13] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [19] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [25] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [31] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [37] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [43] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [49] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [55] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [61] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
## [67] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.9698435
## [73] 0.9698435 0.9698435 0.9698435 0.9698435 0.9698435 0.9698435
## [79] 0.9698435 0.9698435 0.9698435 0.9698435 0.9698435 0.9698435
## [85] 0.9698435 0.9698435 0.9698435 0.9698435 0.9698435 0.9698435
## [91] 0.9698435 0.9698435 0.9698435 0.9698435 0.9698435 0.9698435
## [97] 0.9698435 0.9698435 0.9698435 0.9698435
So chillR
has a few functions that can be applied to hourly temperature data. It also has wrapper functions that allow computing chill between specific start and end dates. The chilling()
function automatically calculates a few basic metrics for us. Note that we have to use the chillR
function make_JDay()
here to add the Julian dates (counts the days of the year) to the dataset for this to work.
output<-chilling(make_JDay(Winters_hours_gaps),Start_JDay = 90, End_JDay = 100)
kable(output) %>%
kable_styling("striped", position = "left", font_size = 10)
Season | End_year | Season_days | Data_days | Perc_complete | Chilling_Hours | Utah_Model | Chill_portions | GDH |
---|---|---|---|---|---|---|---|---|
2007/2008 | 2008 | 11 | 11 | 100 | 40 | 15.5 | 2.009147 | 2406.52 |
So the chilling()
function implements the Chilling Hours, Utah and Dynamic Models, and it also calculates Growing Degree Days (GDH). But maybe we don’t want all of these, or we want other metrics. In that case, we can make use of the tempResponse
function, which is somewhat similar to chilling()
, but it takes as input a list of temperature models to be computed.
output<-tempResponse(make_JDay(Winters_hours_gaps),
Start_JDay = 90, End_JDay = 100,
models=list(Chill_Portions=Dynamic_Model, GDH=GDH))
kable(output) %>%
kable_styling("striped", position = "left", font_size = 10)
Season | End_year | Season_days | Data_days | Perc_complete | Chill_Portions | GDH |
---|---|---|---|---|---|---|
2007/2008 | 2008 | 11 | 11 | 100 | 2.009147 | 2406.52 |
Exercises
on chill models
Please document all results of the following assignments in your learning logbook
.
- Run the
chilling()
function on theWinters_hours_gap
dataset - Create your own temperature-weighting chill model using the
step_model()
function - Run this model on the
Winters_hours_gaps
dataset using thetempResponse()
function.