Skip to content
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

Refactor spitfire fuel calculations #1247

Open
wants to merge 51 commits into
base: main
Choose a base branch
from

Conversation

adrifoster
Copy link
Contributor

@adrifoster adrifoster commented Sep 12, 2024

Refactors the SPITFIRE fuel calculation subroutine and adds a fuel class

Description:

Major changes to the way fuel characteristics are calculated in the SPITFIRE module. Changes are not B4B, but should be round off.

Expectation of Answer Changes:

Round off differences due to order of operation changes. Testing in progress...

Checklist

Contributor

  • The in-code documentation has been updated with descriptive comments
  • The documentation has been assessed to determine if updates are necessary

Integrator

  • FATES PASS/FAIL regression tests were run
  • Evaluation of test results for answer changes was performed and results provided

Test Results:

Testing ongoing... currently having issues with some divide by zero errors (in rate_of_spread) for only some tests... I'm not sure why this is happening since the code should check and not let SAV, bulk density, etc. equal zero.

/glade/derecho/scratch/afoster/tests_0912-094039de

CTSM (or) E3SM (specify which) test hash-tag:

CTSM (or) E3SM (specify which) baseline hash-tag:

FATES baseline hash-tag:

Test Output:

@adrifoster
Copy link
Contributor Author

Okay so I've tracked down this error. And it seems to originate from a negative value in the sum of fine leaf litter. (leaf_fines -2.3394756489679232E-006)

This exists in main branch too - I think the old way of calculating fuel was hiding it.

I am going to file an issue.

@rgknox @glemieux any ideas?

@glemieux
Copy link
Contributor

Okay so I've tracked down this error. And it seems to originate from a negative value in the sum of fine leaf litter. (leaf_fines -2.3394756489679232E-006)

This exists in main branch too - I think the old way of calculating fuel was hiding it.

I am going to file an issue.

@rgknox @glemieux any ideas?

We can ignore this per #1249.

@adrifoster adrifoster changed the title WIP: Refactor spitfire fuel calculations Refactor spitfire fuel calculations Sep 24, 2024
@adrifoster
Copy link
Contributor Author

Okay I think I have fixed all the overflow and divide-by-zero issues. I am re-running testing but I think this is now ready for a review.

@adrifoster
Copy link
Contributor Author

fates test suite tests are in /glade/derecho/scratch/afoster/tests_0924-151742de

all tests PASS or FAIL due to a BASELINE DIFF, as expected

will run through and make sure all DIFF's are round off

@adrifoster
Copy link
Contributor Author

All DIFFs are due to roundoff - this is ready for a review.

@rgknox rgknox self-requested a review October 18, 2024 15:16

integer function dead_leaves(this)
class(fuel_classes_type), intent(in) :: this
dead_leaves = this%dead_leaves_i
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adrifoster , I'm curious, why do we have a function call to report an integer constant? I've seen this type of thing before, but wasn't sure why it was done. It always seemed straightforward to just reference the integer constant directly in the code where its used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's just a getter function. This is a (Fortran-limited) way of carrying the fuel class indices around in a class (rather than having to read each of them in), but still protecting their values.

You unfortunately can't have a protected class variable, only private - which means you have to use a method to get the value.

The setter/getter pattern is fairly common in object-oriented programming. It's a little clunky in Fortran, unfortunately. I was trying it out here but can go back to what we had before if people don't like it. I just found it a lot nicer to just use the fuel_classes class rather than each parameter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other option would be to just have a module with just the fuel classes as constants/parameters in it and allow the use of the whole module, which is effectively the same idea, but goes against our convention of having the use, : only, and obfuscates the origin of each of the constants.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am continually frustrated that Fortran doesn't have an enumerator type....

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think since they are constants, they can be defined as "integer, parameter :: ", which makes them immutable. I have no problem with getters/setters though. It adds one small extra step when someone who is reading the code is tracking what the value, but that's trivial.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rgknox you unfortunately can't have a "parameter" attribute for a class variable. it's really frustrating...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whoa, I can't believe I never ran into that. weird

@adrifoster
Copy link
Contributor Author

@rgknox asked for some functional testing plots:

Plot of Nesterov Index over time using driver data from an interior Alaska site

Nesterov_plot

Corresponding fuel moisture for above NI values, for 3 different synthetic fuel models (see module

fuel_moisture_plot

Fuel loading for fuel types:

Fuel loading_plot

Fractional loading

Fractional fuel loading_plot

Fuel bulk density

Fuel bulk density_plot

Fuel SAV

Fuel surface area to volume ratio_plot

! There are six fuel classes:
! 1) twigs, 2) small branches, 3) large branches 4) trunks
! 5) dead leaves, 6) live grass
integer, private :: twigs_i = 1 ! array index for twigs pool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the verbose convention of implying the index with the trailing i

this%total_loading = 0.0_r8
do i = 1, nfsc
if (i /= fuel_classes%trunks()) then
this%total_loading = this%total_loading + this%loading(i)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be called "non_trunk_loading" or "non_trunk_total_loading" ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea - it is a bit confusing. I can do that.

@rgknox rgknox requested a review from samsrabin October 18, 2024 16:18
@rgknox
Copy link
Contributor

rgknox commented Oct 18, 2024

One general comment. This is something that was already in the code that kind of bothered me. We all know we break up litter into component groups for both decomposition and fire. Both modules use almost the same groups, which are governed by size and location (above and below ground). In general, I'd like this to be a little cleaner, where the super-set of all delineations is contained in a process agnostic module, and decomposition and fire could inherit those delineations and group/use them how they see fit. I don't see this as in-scope for this PR necessarily, but I'm curious how you see all this, and if its still a problem.

Copy link
Contributor

@rgknox rgknox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definite improvement, @adrifoster has already addressed my comments. Thanks!

@adrifoster
Copy link
Contributor Author

One general comment. This is something that was already in the code that kind of bothered me. We all know we break up litter into component groups for both decomposition and fire. Both modules use almost the same groups, which are governed by size and location (above and below ground). In general, I'd like this to be a little cleaner, where the super-set of all delineations is contained in a process agnostic module, and decomposition and fire could inherit those delineations and group/use them how they see fit. I don't see this as in-scope for this PR necessarily, but I'm curious how you see all this, and if its still a problem.

Totally agree. I wanted to try to merge them somehow but they are slightly different in terms of how they are grouped and used, so I wasn't sure how to do it efficiently for this PR. I think it warrants a small group of us sitting down to discuss. If we merged them it would also make further discretizing the litter/fuel easier (i.e. PFT-specific, etc.).

I also don't love that the litter is decayed in one spot, the fuel is combusted in another, etc. And seemingly we do (?) make sure these things align?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Final Testing
Development

Successfully merging this pull request may close these issues.

3 participants