Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
Annual sowing and harvest date outputs #1616
Annual sowing and harvest date outputs #1616
Changes from 9 commits
3f2acc2
7d0acfe
65b0295
ac85009
9360778
3472154
b857d8c
cc42589
bc88cf9
6491189
86a09e0
ac01b14
d1ca586
7601ec8
948bcc9
b878b33
708d8e7
afc1924
b89ea27
7a2c816
071b545
ca90b78
8517646
3aa7d65
d810b0f
0c67c80
a8eca51
5de54d1
c50409a
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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.
What happens to the winter cereals by deleting this code? It seems like this was removed due to the deletion of
cropplant
above, but it's not clear to me the impact it might have.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.
Does the
sowing_count
logic replace thecropplant
logic? If so, do we need to update the winter cereal code to use thesowing_count
logic to allow for continuous annual winter temperate cereals (as the comment implies)?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.
The
sowing_count
logic is indeed intended to replace thecropplant
logic; settingsowing_count
equal to 0 at the beginning of the calendar year should have the same effect as this bit of code for winter wheat.However, you and that comment have got me wondering: It is possible for corn, soy, etc. to have growing seasons spanning the (hemisphere's) New Year. Since they would miss their only chance to get
cropplant
set to false, doesn't that mean they would not be planted again? E.g., for a northern-hemisphere gridcell:cropplant
set to true)croplive
true, socropplant
remains truecroplive
set to falsecropplant
is still truecroplive
false, socropplant
set to falseThere 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.
Good questions. @samsrabin I think your latest comment implies that there might have been situations where the old code did the wrong thing but your new code would do the right thing; is that correct? I'm wondering if it would be important to do a long-ish run (e.g., 20 years or so?) comparing the new and old code to see if this new code changes answers in some situations. I'm not sure whether this is necessary or not; @samsrabin @danicalombardozzi what do you think? The purposes I would see of this are (1) understanding whether this code change fixes any bugs with the old code (intentionally or inadvertently) and if so, how often those bugs appeared; and (2) making sure that the new code isn't changing any answers in an undesirable way.
If we do this, we'll want to compare against #1628 . An easy starting point would be to run the test suite (or maybe first just a couple of tests from the test suite). But that only includes coarse-resolution crop tests (10x15 degrees) and only runs for a few years, so might not capture rare answer changes. Maybe that's enough – maybe we don't care if there are some rare situations where this branch changes answers – but I want to see what both of you think. Again, I'm happy going either way here.
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.
I agree, a test like that seems like a good idea.
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.
@samsrabin Thanks for pointing this out. I agree that it could have caused the original code to do the wrong thing. A test does sound like a good idea. Does running two 20-year 2-degree simulations, one with this new code and another with the original code sound reasonable? Checking the changes in crop yields would be interesting. I'm hoping that the differences aren't huge, but the test will tell!
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.
@billsacks I think this test is the only thing left to do before this PR is ready to go. Is there a nice automated way to perform these runs and/or compare their results for important outputs?
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.
I actually think there is another possible subtle issue here: CropPhenology is currently only called when doalb is .true. Based on a test I just ran, in an I compset, doalb is .false. for both time steps 0 and 1, so CropPhenology is first called in the second time step of Jan 1 – meaning this conditional wouldn't be triggered in the first year of the run. If we're starting from cold start or an old restart file, then the spval check here should handle that situation – doing this start-of-year resetting the first time CropPhenology is called, even though
is_beg_curr_year
will be false. However, I think this will currently cause problems if you start a new run from a restart file created from this branch (not via a real restart, i.e.,CONTINUE_RUN
, but a new startup case with finidat set to point to a restart file created from this branch). If I'm thinking about things right, in this situation,sdates_thisyr
will typically not bespval
(at least, not after you add it to the restart file, which I think is needed for other scenarios) butis_beg_curr_year
won't be triggered in the first year either – and sosowing_count
,harvest_count
, etc. won't get reset in the first year in this scenario.I think the easiest way to fix this is to get rid of the
doalb
check around the call toCropPhenology
, but I want to get some confirmation from others that that is an okay thing to change. @samsrabin please comment if you have any thoughts on this.doalb
. But if not, I think we'll need to come up with a different fix for this issue.Update (2022-02-16): The plan is to fix this via #1628 (which has now been merged in to this branch), so I'm marking this as done.
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.
Yes, I think that logic works.
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.
I agree that this logic should work. Looks as though some of it has already been included.
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.
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.
My thinking was that it could be useful to distinguish "cell-years that had no area of this crop" (which would save as missing) from "cell-years where this crop had area prescribed but sowing criteria were never met" (which would save as -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.
Ah, that reasoning makes sense to me - thanks for the explanation.
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.
jday
in this subroutine is determined by a call toget_curr_calday
, which looks at the time as of the end of the time step – which in this case I think will yieldjday = 1
. So I can imagine a situation where a crop whose planting window starts on Jan. 1 gets planted in this 0th time step. Then on the next time step (time step 1; i.e., the first time step of the year), your new reset code above this will be executed, resettingsowing_count
,sdates_thisyr
, etc. I can see how you might need a correction for this situation. And actually, it seems like this same situation could occur in later years as well. Does what I'm saying ring true? If so, I think you should either:get_prev_calday
instead ofget_curr_calday
: that way, we'll be looking at the date as of the start of the time step rather than the end of the time step, which would be more consistent with the use ofis_beg_curr_year
to determine when to reset these variables. This is likely to be answer-changing, though, and so should be done in a separate PR; probably the best way to do that would be to make this change to jday first (and we could bring that to master), then update this branch with that change and remove this block of code.I am inclined to go with option (3), and that was the motivation for #1623 . But I'm okay with the other options as well if you think they'd be better or just as good. It seems like option (1) has some elements of option (2) for years after the first model year, in that I think it will generally prevent planting from happening on the last time step of the year (i.e., the first time step that is currently labeled Jan 1), since sowing_count will still be 1 at that point. (And actually, as I'm writing that, I'm realizing that that aspect of the current PR could be answer changing to a small extent; we should be aware of that for testing if we stick with the current implementation.) Other than that, one possible issue I see with option (1) (i.e., the current implementation) is: if there is a year in which planting doesn't happen at all (so sowing_count has remained 0), but then planting happens on the last time step of the year (which is viewed as Jan 1), then the diagnostics would be wrong: both this year's and next year's diagnostics will say that planting happened on Jan 1.
So I guess as I'm writing this all out I'm starting to lean more towards option (3) if you're happy with it, but I'm happy to discuss further.
Thoughts?
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.
In our discussion yesterday, @samsrabin helped me see the scenarios where this is needed. Our tentative plan is to do #1623 (my option (3) in the above comment), which will help with this and other issues that @samsrabin has run into. But even with that change, this block of code is still needed to handle our typical end-of-year restart files that were generated with code prior to #1623 being fixed: In the runs that generated these restart files, the last time step of the run was considered to be Jan 1, and so some crop patches have crops that have already been planted, with a planting date of Jan 1. As long as we are still using these restart files, we need this block of code to correctly handle these already-planted-on-Jan-1 crops.
The one remaining thing I'd like here, then, is some more details in this comment so that we know how long we need to maintain this block of code.
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.
Okay, done (ca90b78).
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.
Thanks!
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.
sowing_count(p) == 0
instead of(.not. cropplant(p))
? At a glance it looks like the logic for sowing_count differs from the logic for the old cropplant, but I haven't looked closely. If there is a potential behavior change, can you explain what it is? One particular behavior of the new code appears to be that you only allow a single planting in a given calendar year. Did the old code have a similar restriction, including for the Southern Hemisphere?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.
The intended behavior of
cropplant
was to restrict plantings to once per year. InCropPhenology()
(note the comment at the top here):CTSM/src/biogeochem/CNPhenologyMod.F90
Lines 1779 to 1806 in bf365e0
This is the only place in the code (other than the initialization of the
CropType
instance) wherecropplant
orcropplant_patch
is ever set to false.Although the Southern Hemisphere's "year" spans across calendar years, all sowing date windows are restricted to a single calendar year (as discussed in #1484). I think it follows (although check me on this) that the Southern Hemisphere is also restricted to one planting per calendar year.
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.
Okay, I think I understand. Does this sound right?: Previously, the code itself did not explicitly restrict planting dates to being once per calendar year (for the southern hemisphere, anyway). However, this restriction existed in practice due to a combination of (1) the current crop parameters, and (2) issue #1484 (which prevents the code from working right if the crop parameters were ever changed to try to have a planting window crossing the new year boundary).
Update (2022-02-16) I am marking this as not needed, because upon further reflection, I don't think this comment change is necessary.
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 know, I'm wondering if it even makes sense to leave this extra condition in. If we changed
to just
the restriction would still effectively be in place both with the sowing window method (due to them not spanning multiple calendar years) and the prescribed sowing date method I'm working on (due to hard-codedThis is wrong. Theoretically it could be possible for a crop to be planted at the beginning of its sowing window, then harvested before the end of the sowing window, thus opening up the possibility of it being planted again.mxgrowseas = 1
). If we do want to leave in such a restriction, it might make more sense to throw an actual warning or error message inPlantCrop()
when it's called in a patch that already had a growing season started that year (i.e.,sowing_count(p) > 0
).But I'm not sure I'm right that current outputs can't handle multiple growing seasons in a year. Any relevant daily outputs shouldn't break in-run, although I'm sure it would mess up a lot of people's postprocessing scripts. @slevisconsulting, what do you think?
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.
Thank you for including me in this @samsrabin . I haven't looked at the crop code in long while, so I would need a bit of a refresher before expressing an opinion. I'm open to having a short meeting to discuss if you like.
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.
I'm happy to let you, @slevisconsulting and @danicalombardozzi hash this out. However, reading through your explanation, and especially your point that, without this condition, there could theoretically end up being multiple plantings in a year, I would be inclined to leave it as you currently have it. It sounds like removing this restriction would involve (maybe among other things):
If all of that is needed, then it feels to me like it warrants a separate PR (if it's worth doing at all).
But I don't feel strongly on this, so am happy to let you all work out what makes the most sense here.
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.
I'm not entirely sure I follow the old logic, but I do think it makes sense to constrain the code to one planting per year at this point. Multiple plantings is something that happens and the research community would like to see added, but it might need additional constraints to work realistically (e.g., second sowing only happens a certain amount of time after harvest).
I would think that current outputs should be able to handle this, but probably would need some testing to verify.
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.
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.
I gave this a shot and ran into a problem. Here's what I added for reading
sdates_thisyr
(similar forhdates_thisyear
):But then I get the following error:
I'm assuming this is because
mxgrowseas
isn't in the restart file, right? Is there any way around this?Cross-posted to the CESM Forum, although it's awaiting approval.
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.
Wrapping it like so seems to do the trick:
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.
I don't think you want that check_var_or_dim call. Instead, I think you need to add an ncd_defdim call in restFileMod.F90, similar to this:
CTSM/src/main/restFileMod.F90
Line 546 in 8d9f988
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.
Oh wait, I get it: maybe you already added that defdim call but the problem came in reading an earlier restart file? If so, then something like your proposal makes sense – to do a check before making the restartvar call.
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.
Awesome, this looks great. Thanks for introducing a shared subroutine to do this check.
I have a few minor comments on your latest commit, which I'm marking as optional because if you don't have time to do them I won't hold up the PR for them:
intent(inout)
in your new subroutine then you should be able to get rid of the localncid_local
copy. (I'm not sure if it's reliably safe to make a copy of thencid
variable like you do here, so this would probably be good to change.)check_dim
rather thancheck_var_or_dim
; the latter is mainly intended for use by callers that could have either a dimension or variable name (such as the general-purposefind_var_on_file
subroutine).c
andd
, that would be preferable.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.
Re:
check_dim()
(which I only see in river routing files): Wouldn't it fail when the dimension doesn't exist? I'm not sure whether the call ofpio_inq_dimid()
itself would cause a failure, but if not it'd result indimlen /= value
, right?For reference, from
components/mosart/src/riverroute/RtmIO.F90
: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 check_dim isn't called directly from anywhere else in CTSM, but it is what you want here; in CTSM, check_var_or_dim just delegates to either check_dim or check_var, and the implementation of check_dim differs from the one in RtmIO.F90:
CTSM/src/main/ncdio_pio.F90.in
Lines 304 to 348 in 8d9f988
While it's okay to be using check_var_or_dim here, it's just an unnecessary extra level of indirection.
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.
Good point; I missed that in my search because I was only looking in files ending with
.F90
.Okay, those three tasks are done:
And I've redone the merges, hopefully correctly this time.
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.
Awesome, looks good; thanks for fixing those things; and the merge looks good now.