-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FF16 Rainfall API #324
FF16 Rainfall API #324
Conversation
Codecov Report
@@ Coverage Diff @@
## develop #324 +/- ##
==========================================
Coverage ? 79.54%
==========================================
Files ? 95
Lines ? 8600
Branches ? 0
==========================================
Hits ? 6841
Misses ? 1759
Partials ? 0 Continue to review full report at Codecov.
|
Nice one @devmitch! I think the next step is to show that it accumulates correctly - i.e. accessing the spline from We now want to replace |
Hi @devmitch great work. I'm really happy to see this coming together. Well done setting it up and extending in a way that keeps all tests passing (and adds new tests) I agree with Andrew's suggested next steps. |
I've set a default spline of y = 0 to stay in line with the default soil infiltration rate of 0.0 in Now the rainfall spline will be set in either of 3 ways:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really great progress @devmitch .
Some minor suggestions included in this review. @aornugent may have more to mention
R/ff16w.R
Outdated
FF16w_make_environment <- function(canopy_light_tol = 1e-4, | ||
canopy_light_nbase = 17, | ||
canopy_light_max_depth = 16, | ||
canopy_rescale_usually = TRUE, | ||
soil_number_of_depths = 1, | ||
soil_initial_state = 0.0, | ||
soil_infiltration_rate = 0.0) { | ||
rainfall_x = seq(0, 9, 1), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right that need x & y. I would rather pass in a single data frame than an array, so perhaps change this accordingly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So single data frame for FF15w_make_environment()
argument which is split into two arrays to pass into rainfall_add_points()
?
tests/testthat/test-strategy-ff16w.R
Outdated
|
||
# not needed anymore? should we still be able to set the states manually? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably. We will occasionally want to specify an exact environment for a non-dynamic use
After discussions with @dfalster and @itowers1, the rainfall spline (which now exists in the Construction of the rainfall spline is now done in either of 3 ways: # default rainfall spline of y = 1
env <- make_environment("FF16w")
# rainfall spline of y = 5
env <- make_environment("FF16w", rainfall=5)
# custom rainfall spline based on set of control points
env <- make_environment("FF16w")
x <- seq(0, 10, 1)
y <- x^2
env$set_extrinsic_driver("rainfall", x, y) # overwrites previous spline of y = 1 Querying the spline now requires the user to pass in the name of the extrinsic driver they wish to query: # determine the rainfall value at time 84
res <- env$extrinsic_driver_evaluate("rainfall", 84)
# determine the rainfall values over the range of integer times from 0 to 100
res <- env$extrinsic_driver_evaluate_range("rainfall", seq(0, 100, 1)) The list of potentially active extrinsic_drivers is now also available from any environment:
Two more things that need to be looked at:
# context: env is an FF16w environment
env_size <- env$ode_size
env_state <- patch$ode_state
env_rates <- patch$ode_rates
expect_equal(patch$ode_size, env_size)
# either 0 or numeric(0)
expect_identical(patch$ode_state, numeric(env_size))
expect_identical(patch$ode_rates, numeric(env_size)) # FAILS, is actually 1 I'm not exactly sure what the relationship between
Thoughts @dfalster @aornugent ? |
Tackling the failing test first! # context: env is an FF16w environment
env_size <- env$ode_size
env_state <- patch$ode_state
env_rates <- patch$ode_rates
expect_equal(patch$ode_size, env_size)
# these two are typos that previously passed because we initialised at 0
-expect_identical(patch$ode_state, numeric(env_size))
+expect_identical(patch$ode_state, env_state)
-expect_identical(patch$ode_rates, numeric(env_size))
+expect_identical(patch$ode_rates, env_rates) |
This is awesome work @devmitch. I really like the approach of storing multiple drivers in a map- it makes it much more general and hopefully we can apply the same pattern to a variety of new model processes. To your second point:
I wasn't able to find a way to inherit from In this case, the uninitialised driver fails loudly, which I think is a good thing:
My only outstanding question is what happens when a spline has been initialised for a shorter duration than the model simulation? I've done a little tinkering and the spline will continue to interpolate outside the bounds of which it has been initialised, but often with strange behaviour: env$set_extrinsic_driver("rainfall", x = c(1, 2, 3), y = c(10, 1, 0))
env$extrinsic_driver_evaluate_range('rainfall', c(1, 2, 3, 10, 50, 100, 1000))
> 10 1 0 7 47 97 997 I suggest then that we stick with the philosophy of 'fail loudly' and have a simulation stop if it goes beyond the length of the spline. This might require modifying I'd also suggest running this check in the Patch constructor which has access to Let me know if you'd like to discuss! |
Ah I see, makes sense. I think I was confusing myself a little as well when I was considering this.
Yeah it seems to be smart enough to extrapolate correctly for simple curves like the linear y = k spline constructed for
Another solution that comes to me is adding a boolean flag in double Interpolator::eval(double u) const {
check_active();
if (not extrapolate and (u < min() or u > max())) { // min() & max() already implemented
util::stop("Extrapolation disabled and evaluation point of " + u + " outside of interpolated domain.");
}
return tk_spline(u);
} It then seems ideal to also provide a faster, less safe method for spline evaluation as well (this is how it is done in the STL with maps for example - double interpolator::operator()(double u) const {
return tk_spline(u);
} However, if we were to disable extrapolation for rainfall splines, how do we know what domain to construct the default spline of y = k in |
Sounds very tidy! Could we then enable extrapolation in the default constructor, but reset the flag to
Not if we can avoid it. It'd be nice to re-use the same environment for a variety of simulations. My suggestion to run the extrapolation check in I see the tests are failing!
My intuition is it doesn't like calling things that haven't been initialised on Windows and Ubuntu (strange that it passes on OSX). All tests passed locally on my Ubuntu machine the other day, which is a bit curly. Maybe try |
Good work @devmitch . I agree with @aornugent 's suggestions above. |
Yeah I originally meant this but accidentally said false (disabled) by default.
The following is currently how the default spline of y = k is generated in FF16w_make_environment <- function(canopy_light_tol = 1e-4,
canopy_light_nbase = 17,
canopy_light_max_depth = 16,
canopy_rescale_usually = TRUE,
soil_number_of_depths = 1,
soil_initial_state = 0.0,
rainfall = 1) {
# ...
x <- seq(0, 10, 1)
y <- rep(rainfall, 11)
e$set_extrinsic_driver("rainfall", x, y)
} If we disable extrapolation for the rainfall spline, then evaluating it at any point > 10 will throw an error as extrapolation is disabled and we are attempting to evaluate the spline above the maximum control point. Since the normal patch lifetime is up to 105 years, this obviously won't work well when we try to evaluate these larger numbers. Since I'm guessing patch lifetime is arbitrary, how can we construct the spline with a large enough domain of control points to account for any arbitrary patch lifetime?
Git tells me there are no changes to these files after running this command... |
Ah ha- if we're handling construction on the R side: FF16w_make_environment <- function(canopy_light_tol = 1e-4,
canopy_light_nbase = 17,
canopy_light_max_depth = 16,
canopy_rescale_usually = TRUE,
soil_number_of_depths = 1,
soil_initial_state = 0.0,
rainfall = 1) {
# ...
x <- seq(0, 10, 1)
y <- rep(rainfall, 11)
- e$set_extrinsic_driver("rainfall", x, y)
+ e$set_extrinsic_driver("rainfall", x, y, extrapolate = TRUE)
} Users can then update the environment with more complex rainfall scenarios: env <- FF16w_make_environment(rainfall = 1)
x <- seq(0, 105, len = 100)
y <- x^2
# extrapolate = FALSE by default
env$set_extrinsic_driver("rainfall, x, y) Then, if the patch lifetime exceeds the length of the control points, the simulation will fail (hopefully with a useful error). This is particularly useful where the extrinisic driver comes from real data- we want to prevent the case where people start analysing results that go beyond their domain of interest. If they want to forecast (i.e. extrapolate beyond the available data) they can make an informed decision to set
Darn, that's more concerning then. I'll try to check out these changes tonight and see what might be happening, please let me know if you find anything that might address the problem. My hunch is still that the uninitialised splines will be causing trouble in FF16 and K93, but my hunches are nearly always wrong so more methodical investigation is needed. |
I wasn't able to figure out much, google tells me that it might have something to do with the R packages installed, not sure. Anyway, it seems like Rcpp can't handle default arguments, so I've gone with the following for the default linear spline in x <- seq(0, 10, 1)
y <- rep(rainfall, 11)
e$set_extrinsic_driver("rainfall", x, y)
e$extrinsic_driver_extrapolation("rainfall", TRUE); (unless there is another way you know of to get them working...) |
This PR begins to implement the rainfall model in the FF16 environment. Currently only a few necessary getters, setters and spline computation functions are exposed, we can add/remove depending on what will be required for the model.
A basic test is included, and some slight refactoring was done to the
Interpolator
class.This may need to wait for #304 to be merged.