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

Bug in SFMainMod? Don't ever remove trunks from sum_fuel? #1178

Closed
adrifoster opened this issue Mar 26, 2024 · 24 comments
Closed

Bug in SFMainMod? Don't ever remove trunks from sum_fuel? #1178

adrifoster opened this issue Mar 26, 2024 · 24 comments

Comments

@adrifoster
Copy link
Contributor

In refactoring the SPITFIRE code, it seems like we don't actually ever remove trunk litter from patch%sum_fuel. We do remove trunk characteristics from the weighted averages of bulk density, SAV, etc., but from my read of the code we do not ever correct patch%sum_fuel from it's original calculation (here):

       currentPatch%sum_fuel =  sum(litt_c%leaf_fines(:)) + &
                                sum(litt_c%ag_cwd(:)) + &
                                currentPatch%livegrass

Note that litt_c%ag_cwd(:) is defined here:

   integer, public, parameter :: ncwd  = 4    ! number of coarse woody debris pools 
                                              ! (twig,s branch,l branch, trunk)
   real(r8)                   :: ag_cwd(ncwd) ! above ground coarse wood debris (cwd) [kg/m2]

It is then used in the rate of spread subroutine (here):

ir = reaction_v_opt*(currentPatch%sum_fuel/0.45_r8)*SF_val_fuel_energy*moist_damp*SF_val_miner_damp 

Which, according to the original Rothermel equations and the SPITFIRE paper , should not include the 1000-hr (i.e. trunk) fuels.

If my read is correct, updating this will certainly change answers...

Is this an update that happened? or was it always like this?

tagging relevant folks...
@ckoven @rgknox @glemieux @samsrabin

@adrifoster
Copy link
Contributor Author

adrifoster commented Mar 26, 2024

I'll note that the patch-level variable sum_fuel (here) is noted as:

real(r8)              :: sum_fuel                ! total ground fuel related to ROS (omits 1000 hr fuels) [kgC/m2]

So at some point we either intended to or actually did omit the trunks from this variable

@rgknox
Copy link
Contributor

rgknox commented Mar 26, 2024

@adrifoster , my interpretation is that sum fuel should interpret was is actually there, and evaluate all litter that can be considered fuel. If that portion of the litter (trunk wood) is not there or has recently been changed, then it should be reflected in litt_c%ag_cwd as that is the prognostic variable. If there is no change in the amount of litter in existence, and this is more about what litter is included in the sum, then we should be changing how we calculate sum_fuel. Is this kind of what you are getting at?

@adrifoster
Copy link
Contributor Author

If there is no change in the amount of litter in existence, and this is more about what litter is included in the sum, then we should be changing how we calculate sum_fuel. Is this kind of what you are getting at?

Yes, so the 1000-hr fuels (i.e. trunks) are not supposed to be used to calculate fire rate of spread, intensity, etc. So the sum_fuel should either be modified to remove trunks if we are going to use it in those equations, or we need to use a different variable.

@samsrabin
Copy link
Contributor

I think you're right, Adrianna; I don't see anywhere that sum_fuel gets modified.

In addition to the comment at the definition of sum_fuel you mentioned, there's this bit further indicating an intention to exclude trunks from the ROS calculation:

! Correct averaging for the fact that we are not using the trunks pool for fire ROS and intensity (5)
! Consumption of fuel in trunk pool does not influence fire ROS or intensity (Pyne 1996)
currentPatch%fuel_bulkd     = currentPatch%fuel_bulkd     * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf)))
currentPatch%fuel_sav       = currentPatch%fuel_sav       * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf)))
currentPatch%fuel_mef       = currentPatch%fuel_mef       * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf)))
currentPatch%fuel_eff_moist = currentPatch%fuel_eff_moist * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf)))

@adrifoster
Copy link
Contributor Author

adrifoster commented Mar 26, 2024

Okay thanks @samsrabin. So I guess we need to update this... Should this come in as a hot-fix? I'd like to change it first so I can ensure my refactors aren't doing something wonky.

@rgknox
Copy link
Contributor

rgknox commented Mar 26, 2024

I'm happy to help fast track this and get it in before we update to API 35. I'd recommend getting the fix based on main though, and not wrapping it into the fire refactor

@adrifoster
Copy link
Contributor Author

I'm happy to help fast track this and get it in before we update to API 35. I'd recommend getting the fix based on main though, and not wrapping it into the fire refactor

thanks! working on sending a quick fix PR now.

@adamhb
Copy link
Contributor

adamhb commented Mar 27, 2024

Oh wow, thanks @adrifoster for finding this. I've had a lot of issues with fire intensity being too high for my simulations in Californian mixed conifer forests, and I guess this would explain why. So if I understand correctly what you found, the model would essentially treat logs on the landscape as if they had the properties of finer fuels (SAV etc.) and then include all that extra mass in the calculations of intensity / spread?

@samsrabin
Copy link
Contributor

@adamhb From what I can tell, this should only influence rate of spread. The code I reference here should mean that trunks aren't included in fuel_bulkd, fuel_sav, fuel_mef, and fuel_eff_moist.

@ckoven
Copy link
Contributor

ckoven commented Mar 27, 2024

@adamhb From what I can tell, this should only influence rate of spread. The code I reference here should mean that trunks aren't included in fuel_bulkd, fuel_sav, fuel_mef, and fuel_eff_moist.

@samsrabin but if this affects rate of spread, then it should also affect intensity and area burned too, since those are both dependent on rate of spread, correct?

@samsrabin
Copy link
Contributor

Oh yeah, it would definitely affect burned area. I didn't think that ROS entered into the intensity (kW/m) calculations, but if that's the case then yes that will be affected too.

@samsrabin
Copy link
Contributor

And yes, you're right:

fates/fire/SFMainMod.F90

Lines 857 to 859 in b054cd0

! EQ 15 Thonicke et al 2010
!units of fire intensity = (kJ/kg)*(kgBiomass/m2)*(m/min)
currentPatch%FI = SF_val_fuel_energy * W * ROS !kj/m/s, or kW/m

So yes, @adamhb, this will affect intensity!

@adamhb
Copy link
Contributor

adamhb commented Mar 27, 2024

Ok thanks! Most simulations Ive run have very large 1000 fuel loads, so this will def change results. Especially because the 1000 hr fuel isnt actually consumed...

@adrifoster
Copy link
Contributor Author

adrifoster commented Mar 27, 2024

Hi @adamhb yes, this bug fix should decrease rate of spread, intensity, mortality, etc. like @samsrabin said.

But also yeah as @samsrabin said, it's only erroneously included in the sum_loading variable part of ROS, NOT in the calculations for SAV, bulk density, etc.

I'm still running my "very long" (i.e. 10 years) simulations to test potential differences so I will post those here, but please feel free to add any if you have a simulation you want to kick off.

@adrifoster
Copy link
Contributor Author

Ok thanks! Most simulations Ive run have very large 1000 fuel loads, so this will def change results. Especially because the 1000 hr fuel isnt actually consumed...

@adamhb is that true? I think it should be consumed... just not used to calculate ROS or FI...

@adamhb
Copy link
Contributor

adamhb commented Mar 27, 2024

@adrifoster these lines of code suggest that trunk fuel is not consumed right?
!---calculate overall fuel consumed by spreading fire ---
! ignore 1000hr fuels. Just interested in fuels affecting ROS
currentPatch%TFC_ROS = sum(FC_ground)-FC_ground(tr_sf)

"currentPatch%TFC_ROS" is defined here as "total fuel consumed by flaming front (kgC/m2 of burned area)"

I think the theory behind this is that logs generally are consumed by smoldering, which is not really a capability of spitfire, which is more geared towards the dynamics of ROS and flaming front.

@adamhb
Copy link
Contributor

adamhb commented Mar 27, 2024

@adrifoster However, I think it would be great to having smoldering as a capability to avoid unrealistic build up of trunk fuel.

@adrifoster
Copy link
Contributor Author

@adamhb true, it's not included in TFC_ROS but here it's being consumed:

       do c = 1,ncwd
             
          ! Transfer above ground CWD
          donatable_mass     = curr_litt%ag_cwd(c) * patch_site_areadis * &
                               (1._r8 - currentPatch%burnt_frac_litter(c))


          burned_mass        = curr_litt%ag_cwd(c) * patch_site_areadis * &
                               currentPatch%burnt_frac_litter(c)
 
          new_litt%ag_cwd(c) = new_litt%ag_cwd(c) + donatable_mass*donate_m2
          curr_litt%ag_cwd(c) = curr_litt%ag_cwd(c) + donatable_mass*retain_m2


          site_mass%burn_flux_to_atm = site_mass%burn_flux_to_atm + burned_mass
             
          ! Transfer below ground CWD (none burns)
          
          do sl = 1,currentSite%nlevsoil
             donatable_mass         = curr_litt%bg_cwd(c,sl) * patch_site_areadis
             new_litt%bg_cwd(c,sl)  = new_litt%bg_cwd(c,sl) + donatable_mass*donate_m2
             curr_litt%bg_cwd(c,sl) = curr_litt%bg_cwd(c,sl) + donatable_mass*retain_m2
          end do

@adamhb
Copy link
Contributor

adamhb commented Mar 27, 2024

@adrifoster ok yes I see. I suspect that the brunt_frac_litter value for trunk fuel is typically near zero as calculated here (but that's a separate issue and I haven't confirmed in).

@adrifoster
Copy link
Contributor Author

@adamhb okay good to know. Happy to discuss with you if you want to go over it, otherwise I can be sure to add some specific unit testing for it during my refactoring work.

Incidentally, I actually updated this set of equations (for a different model) based on some observational data I had (specific to boreal region...) but we could think about investigating

        real, dimension(FL_LEVS), parameter :: PARA = [-1.36, -1.36, -1.32,    &
            -0.83, -0.17, 0.06, -1.72, -1.72, 0.06, -1.72]
        real, dimension(FL_LEVS), parameter :: PARB = [0.54, 0.54, 0.41,       &
            -0.22, -0.82, -0.87, 0.57, 0.57, -0.87, 0.57]
        real, dimension(FL_LEVS), parameter :: PARC = [0.95, 0.95, 0.96, 1.02, &
            0.98, 0.55, 0.98, 0.98, 0.82, 0.98]

       do ic = 1, FL_LEVS
            if (soil%fuels(ic) > epsilon(1.0)) then

                lmoist = soil%litter_moist(ic)/soil%litter_mef(ic)

                if (lmoist <= MIN_MOISTURE(ic)) then
                    ! Dry litter
                    soil%frac_burnt(ic) = 1.0
                    burned(ic) = soil%fuels(ic)

                else if (lmoist > MIN_MOISTURE(ic) .and. lmoist <= 1.0) then

                    soil%frac_burnt(ic) = max(0.0, min(1.0, PARA(ic)*lmoist**2 +   &
                        PARB(ic)*lmoist + PARC(ic)))
                    burned(ic) = soil%frac_burnt(ic)*soil%fuels(ic)

                else if (lmoist > 1.0) then
                    ! High moisture
                    soil%frac_burnt(ic) = 0.0
                    burned(ic) = 0.0
                end if
            end if
        end do

@adamhb
Copy link
Contributor

adamhb commented Mar 28, 2024

@adrifoster Thanks for sharing! I think a unit test would be a good idea. Just looking back at some old output, the trunk fuel moisture didn't really change going into the dry season (stayed very high), so not much of it burned. But, this might be what should happen in a model that focuses on the dynamics at the flaming front...

@glemieux
Copy link
Contributor

glemieux commented Apr 1, 2024

@adrifoster can we close this per #1180? Or is this issue broader than just that fix?

@adrifoster
Copy link
Contributor Author

@glemieux no we can close

@ckoven
Copy link
Contributor

ckoven commented May 6, 2024

just noticed that this was fixed by #1180, but still open. closing.

@ckoven ckoven closed this as completed May 6, 2024
@github-project-automation github-project-automation bot moved this from ❕Todo to ✔ Done in FATES issue board May 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

No branches or pull requests

6 participants