This repository has been archived by the owner on Sep 14, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathEDLoggingMortalityMod.F90
475 lines (376 loc) · 22.7 KB
/
EDLoggingMortalityMod.F90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
module EDLoggingMortalityMod
! ====================================================================================
! Purpose: 1. create logging mortalities:
! (a) direct logging mortality (cohort level)
! (b) collateral mortality (cohort level)
! (c) infrastructure mortality (cohort level)
! 2. move the logged trunk fluxes from live into product pool
! 3. move logging-associated mortality fluxes from live to CWD
! 4. keep carbon balance (in ed_total_balance_check)
!
! Yi Xu & M.Huang
! Date: 09/2017
! Last updated: 10/2017
! ====================================================================================
use FatesConstantsMod , only : r8 => fates_r8
use EDTypesMod , only : ed_cohort_type
use EDTypesMod , only : ed_patch_type
use EDTypesMod , only : ncwd
use EDTypesMod , only : ed_site_type
use EDTypesMod , only : ed_resources_management_type
use EDTypesMod , only : dtype_ilog
use EDTypesMod , only : dtype_ifall
use EDTypesMod , only : dtype_ifire
use EDPftvarcon , only : EDPftvarcon_inst
use EDParamsMod , only : logging_event_code
use EDParamsMod , only : logging_dbhmin
use EDParamsMod , only : logging_collateral_frac
use EDParamsMod , only : logging_direct_frac
use EDParamsMod , only : logging_mechanical_frac
use EDParamsMod , only : logging_coll_under_frac
use EDParamsMod , only : logging_dbhmax_infra
use FatesInterfaceMod , only : hlm_current_year
use FatesInterfaceMod , only : hlm_current_month
use FatesInterfaceMod , only : hlm_current_day
use FatesInterfaceMod , only : hlm_model_day
use FatesInterfaceMod , only : hlm_day_of_year
use FatesInterfaceMod , only : hlm_days_per_year
use FatesInterfaceMod , only : hlm_use_logging
use FatesInterfaceMod , only : hlm_use_planthydro
use FatesConstantsMod , only : itrue,ifalse
use FatesGlobals , only : endrun => fates_endrun
use FatesGlobals , only : fates_log
use shr_log_mod , only : errMsg => shr_log_errMsg
use FatesPlantHydraulicsMod, only : AccumulateMortalityWaterStorage
implicit none
private
logical, protected :: logging_time ! If true, logging should be
! performed during the current time-step
character(len=*), parameter, private :: sourcefile = &
__FILE__
public :: LoggingMortality_frac
public :: logging_litter_fluxes
public :: logging_time
public :: IsItLoggingTime
contains
subroutine IsItLoggingTime(is_master,currentSite)
! -------------------------------------------------------------------------------
! This subroutine determines if the current dynamics step should enact
! the logging module.
! This is done by comparing the current model time to the logging event
! ids. If there is a match, it is logging time.
! -------------------------------------------------------------------------------
integer, intent(in) :: is_master
type(ed_site_type), intent(inout), target :: currentSite ! site structure
integer :: icode ! Integer equivalent of the event code (parameter file only allows reals)
integer :: log_date ! Day of month for logging exctracted from event code
integer :: log_month ! Month of year for logging extraced from event code
integer :: log_year ! Year for logging extracted from event code
character(len=64) :: fmt = '(a,i2.2,a,i2.2,a,i4.4)'
logging_time = .false.
icode = int(logging_event_code)
if(hlm_use_logging.eq.ifalse) return
if(icode .eq. 1) then
! Logging is turned off
logging_time = .false.
else if(icode .eq. 2) then
! Logging event on the first step
if( hlm_model_day.eq.1 ) then
logging_time = .true.
end if
else if(icode .eq. 3) then
! Logging event every day
logging_time = .true.
else if(icode .eq. 4) then
! logging event once a month
if(hlm_current_day.eq.1 ) then
logging_time = .true.
end if
else if(icode < 0 .and. icode > -366) then
! Logging event every year on specific day of year
if(hlm_day_of_year .eq. icode ) then
logging_time = .true.
end if
else if(icode > 10000 ) then
! Specific Event: YYYYMMDD
log_date = icode - int(100* floor(real(icode)/100))
log_year = floor(real(icode)/10000)
log_month = floor(real(icode)/100) - log_year*100
if( hlm_current_day.eq.log_date .and. &
hlm_current_month.eq.log_month .and. &
hlm_current_year.eq.log_year ) then
logging_time = .true.
end if
else
! Bad logging event flag
write(fates_log(),*) 'An invalid logging code was specified in fates_params'
write(fates_log(),*) 'Check EDLoggingMortalityMod.F90:IsItLoggingTime()'
write(fates_log(),*) 'for a breakdown of the valid codes and change'
write(fates_log(),*) 'fates_logging_event_code in the file accordingly.'
write(fates_log(),*) 'exiting'
call endrun(msg=errMsg(sourcefile, __LINE__))
end if
! Initialize some site level diagnostics that are calculated for each event
currentSite%resources_management%delta_litter_stock = 0.0_r8
currentSite%resources_management%delta_biomass_stock = 0.0_r8
currentSite%resources_management%delta_individual = 0.0_r8
if(logging_time .and. (is_master.eq.itrue) ) then
write(fates_log(),fmt) 'Logging Event Enacted on date: ', &
hlm_current_month,'-',hlm_current_day,'-',hlm_current_year
end if
return
end subroutine IsItLoggingTime
! ======================================================================================
subroutine LoggingMortality_frac( pft_i, dbh, lmort_direct,lmort_collateral,lmort_infra )
! Arguments
integer, intent(in) :: pft_i ! pft index
real(r8), intent(in) :: dbh ! diameter at breast height (cm)
real(r8), intent(out) :: lmort_direct ! direct (harvestable) mortality fraction
real(r8), intent(out) :: lmort_collateral ! collateral damage mortality fraction
real(r8), intent(out) :: lmort_infra ! infrastructure mortality fraction
! Parameters
real(r8), parameter :: adjustment = 1.0 ! adjustment for mortality rates
if (logging_time) then
if(EDPftvarcon_inst%woody(pft_i) == 1)then ! only set logging rates for trees
! Pass logging rates to cohort level
if (dbh >= logging_dbhmin ) then
lmort_direct = logging_direct_frac * adjustment
lmort_collateral = logging_collateral_frac * adjustment
else
lmort_direct = 0.0_r8
lmort_collateral = 0.0_r8
end if
if (dbh >= logging_dbhmax_infra) then
lmort_infra = 0.0_r8
else
lmort_infra = logging_mechanical_frac * adjustment
end if
!damage rates for size class < & > threshold_size need to be specified seperately
! Collateral damage to smaller plants below the direct logging size threshold
! will be applied via "understory_death" via the disturbance algorithm
else
lmort_direct = 0.0_r8
lmort_collateral = 0.0_r8
lmort_infra = 0.0_r8
end if
else
lmort_direct = 0.0_r8
lmort_collateral = 0.0_r8
lmort_infra = 0.0_r8
end if
end subroutine LoggingMortality_frac
! ============================================================================
subroutine logging_litter_fluxes(currentSite, currentPatch, newPatch, patch_site_areadis)
! -------------------------------------------------------------------------------------------
!
! DESCRIPTION:
! Carbon going from ongoing mortality into CWD pools.
! This module includes only those fluxes associated with a disturbance generated by logging.
! Purpose:
! 1) move logging-associated carbon to CWD and litter pool
! 2) move the logging trunk from live into product pool
! 3) generate fluxes used in carbon balance checking
! E.g,:
! Remove trunk of logged trees from litter/CWD
! Add other parts of logged trees and all parts of collaterally and mechanically
! damaged trees into CWD/litter
!
! This routine is only called if logging disturbance is the dominant disturbance.
!
!
! Note: The litter losses due to disturbance in the logging case is almost
! exactly like the natural tree-fall case. The big differences are that
! the mortality rates governing the fluxes, follow a different rule set.
! We also compute an export flux (product) that does not go to litter.
!
! Trunk Product Flux: Only usable wood is exported from a site. This is the above-ground
! portion of the bole, and only boles associated with direct-logging,
! not inftrastructure or collateral damage mortality.
!
! -------------------------------------------------------------------------------------------
!USES:
use SFParamsMod, only : SF_val_cwd_frac
use EDtypesMod, only : area
use EDtypesMod, only : ed_site_type
use EDtypesMod, only : ed_patch_type
use EDtypesMod, only : ed_cohort_type
use FatesAllometryMod , only : carea_allom
! !ARGUMENTS:
type(ed_site_type) , intent(inout), target :: currentSite
type(ed_patch_type) , intent(inout), target :: currentPatch
type(ed_patch_type) , intent(inout), target :: newPatch
real(r8) , intent(in) :: patch_site_areadis
!LOCAL VARIABLES:
type(ed_cohort_type), pointer :: currentCohort
real(r8) :: litter_area ! area over which to distribute this litter (m2/site).
real(r8) :: np_mult ! Fraction of the new patch which came from the current patch
real(r8) :: direct_dead ! Mortality count through direct logging
real(r8) :: indirect_dead ! Mortality count through: impacts, infrastructure and collateral damage
real(r8) :: trunk_product_site ! flux of carbon in trunk products exported off site [ kgC/site ]
! (note we are accumulating over the patch, but scale is site level)
real(r8) :: delta_litter_stock ! flux of carbon in total litter flux [ kgC/site ]
real(r8) :: delta_biomass_stock ! total flux of carbon through mortality (litter+product) [ kgC/site ]
real(r8) :: delta_individual ! change in plant number through mortality [ plants/site ]
real(r8) :: cwd_litter_density ! Component woody biomass transferred through mortality [kgC/m2]
! (works with canopy_mortality_woody_litter, breaks into CWD partition
! and converts units to /m2)
real(r8) :: woody_litter ! Woody biomass transferred through mortality [kgC/site]
real(r8) :: leaf_litter ! Leafy biomass transferred through mortality [kgC/site]
real(r8) :: root_litter ! Rooty + storage biomass transferred through mort [kgC/site]
real(r8) :: agb_frac ! local copy of the above ground biomass fraction [fraction]
integer :: p ! pft index
integer :: c ! cwd index
! Zero some site level accumulator diagnsotics
trunk_product_site = 0.0_r8
delta_litter_stock = 0.0_r8
delta_biomass_stock = 0.0_r8
delta_individual = 0.0_r8
currentCohort => currentPatch%shortest
do while(associated(currentCohort))
p = currentCohort%pft
if(currentCohort%canopy_layer == 1)then
direct_dead = currentCohort%n * currentCohort%lmort_direct
indirect_dead = currentCohort%n * &
(currentCohort%lmort_collateral + currentCohort%lmort_infra)
else
if(EDPftvarcon_inst%woody(currentCohort%pft) == 1)then
direct_dead = 0.0_r8
indirect_dead = logging_coll_under_frac * currentCohort%n * &
(patch_site_areadis/currentPatch%area) !kgC/site/day
else
! If the cohort of interest is grass, it will not experience
! any mortality associated with the logging disturbance
direct_dead = 0.0_r8
indirect_dead = 0.0_r8
end if
end if
agb_frac = EDPftvarcon_inst%allom_agb_frac(currentCohort%pft)
litter_area = currentPatch%area
np_mult = patch_site_areadis/newPatch%area
if( hlm_use_planthydro == itrue ) then
call AccumulateMortalityWaterStorage(currentSite,currentCohort,(direct_dead+indirect_dead))
end if
! ----------------------------------------------------------------------------------------
! Handle woody litter flux for non-bole components of biomass
! This litter is distributed between the current and new patches, &
! not to any other patches. This is really the eventually area of the current patch &
! (currentPatch%area-patch_site_areadis) +patch_site_areadis...
! For the new patch, only some fraction of its land area (patch_areadis/np%area) is
! derived from the current patch, so we need to multiply by patch_areadis/np%area
! ----------------------------------------------------------------------------------------
do c = 1,ncwd-1
woody_litter = (direct_dead+indirect_dead) * &
(currentCohort%bdead+currentCohort%bsw)
cwd_litter_density = SF_val_CWD_frac(c) * woody_litter / litter_area
newPatch%cwd_ag(c) = newPatch%cwd_ag(c) + agb_frac * cwd_litter_density * np_mult
currentPatch%cwd_ag(c) = currentPatch%cwd_ag(c) + agb_frac * cwd_litter_density
newPatch%cwd_bg(c) = newPatch%cwd_bg(c) + (1._r8-agb_frac) * cwd_litter_density * np_mult
currentPatch%cwd_bg(c) = currentPatch%cwd_bg(c) + (1._r8-agb_frac) * cwd_litter_density
! Diagnostics on fluxes into the AG and BG CWD pools
currentSite%CWD_AG_diagnostic_input_carbonflux(c) = &
currentSite%CWD_AG_diagnostic_input_carbonflux(c) + &
SF_val_CWD_frac(c) * woody_litter * hlm_days_per_year * agb_frac/ AREA
currentSite%CWD_BG_diagnostic_input_carbonflux(c) = &
currentSite%CWD_BG_diagnostic_input_carbonflux(c) + &
SF_val_CWD_frac(c) * woody_litter * hlm_days_per_year * (1.0_r8 - agb_frac) / AREA
! Diagnostic specific to resource management code
delta_litter_stock = delta_litter_stock + woody_litter * SF_val_CWD_frac(c)
enddo
! ----------------------------------------------------------------------------------------
! Handle litter flux for the boles of infrastucture and collateral damage mort
! In this case the boles from direct logging are exported off-site and are not added
! to the litter pools. That is why we handle this outside the loop above. Only the
! collateral damange and infrastructure logging is applied to bole litter
! ----------------------------------------------------------------------------------------
woody_litter = indirect_dead * (currentCohort%bdead+currentCohort%bsw)
cwd_litter_density = SF_val_CWD_frac(ncwd) * woody_litter / litter_area
newPatch%cwd_ag(ncwd) = newPatch%cwd_ag(ncwd) + agb_frac * cwd_litter_density * np_mult
currentPatch%cwd_ag(ncwd) = currentPatch%cwd_ag(ncwd) + agb_frac * cwd_litter_density
newPatch%cwd_bg(ncwd) = newPatch%cwd_bg(ncwd) + (1._r8-agb_frac) * cwd_litter_density * np_mult
currentPatch%cwd_bg(ncwd) = currentPatch%cwd_bg(ncwd) + (1._r8-agb_frac) * cwd_litter_density
currentSite%CWD_AG_diagnostic_input_carbonflux(ncwd) = &
currentSite%CWD_AG_diagnostic_input_carbonflux(ncwd) + &
SF_val_CWD_frac(ncwd) * woody_litter * hlm_days_per_year * agb_frac/ AREA
currentSite%CWD_BG_diagnostic_input_carbonflux(ncwd) = &
currentSite%CWD_BG_diagnostic_input_carbonflux(ncwd) + &
SF_val_CWD_frac(ncwd) * woody_litter * hlm_days_per_year * (1.0_r8 - agb_frac) / AREA
delta_litter_stock = delta_litter_stock + woody_litter * SF_val_CWD_frac(ncwd)
! ----------------------------------------------------------------------------------------
! Handle litter flux for the belowground portion of directly logged boles
! ----------------------------------------------------------------------------------------
woody_litter = direct_dead * (currentCohort%bdead+currentCohort%bsw)
cwd_litter_density = SF_val_CWD_frac(ncwd) * woody_litter / litter_area
newPatch%cwd_bg(ncwd) = newPatch%cwd_bg(ncwd) + &
(1._r8-agb_frac) * cwd_litter_density * np_mult
currentPatch%cwd_bg(ncwd) = currentPatch%cwd_bg(ncwd) + &
(1._r8-agb_frac) * cwd_litter_density
currentSite%CWD_BG_diagnostic_input_carbonflux(ncwd) = &
currentSite%CWD_BG_diagnostic_input_carbonflux(ncwd) + &
SF_val_CWD_frac(ncwd) * woody_litter * hlm_days_per_year * (1.0_r8 - agb_frac) / AREA
! ----------------------------------------------------------------------------------------
! Handle harvest (export, flux-out) flux for the above ground boles
! In this case the boles from direct logging are exported off-site and are not added
! to the litter pools. That is why we handle this outside the loop above. Only the
! collateral damange and infrastructure logging is applied to litter
!
! Losses to the system as a whole, for C-balancing (kGC/site/day)
! Site level product, (kgC/site, accumulated over simulation)
! ----------------------------------------------------------------------------------------
trunk_product_site = trunk_product_site + &
SF_val_CWD_frac(ncwd) * agb_frac * direct_dead * (currentCohort%bdead+currentCohort%bsw)
! ----------------------------------------------------------------------------------------
! Handle fluxes of leaf, root and storage carbon into litter pools.
! (none of these are exported)
! ----------------------------------------------------------------------------------------
leaf_litter = (direct_dead+indirect_dead)*currentCohort%bl
root_litter = (direct_dead+indirect_dead)*(currentCohort%br+currentCohort%bstore)
newPatch%leaf_litter(p) = newPatch%leaf_litter(p) + leaf_litter / litter_area * np_mult
newPatch%root_litter(p) = newPatch%root_litter(p) + root_litter / litter_area * np_mult
currentPatch%leaf_litter(p) = currentPatch%leaf_litter(p) + leaf_litter / litter_area
currentPatch%root_litter(p) = currentPatch%root_litter(p) + root_litter / litter_area
! track as diagnostic fluxes
currentSite%leaf_litter_diagnostic_input_carbonflux(p) = &
currentSite%leaf_litter_diagnostic_input_carbonflux(p) + &
leaf_litter * hlm_days_per_year / AREA
currentSite%root_litter_diagnostic_input_carbonflux(p) = &
currentSite%root_litter_diagnostic_input_carbonflux(p) + &
root_litter * hlm_days_per_year / AREA
! Logging specific diagnostics
! ----------------------------------------------------------------------------------------
! Note that litter stock also has terms above in the CWD loop
delta_litter_stock = delta_litter_stock + &
leaf_litter + &
root_litter
delta_biomass_stock = delta_biomass_stock + &
leaf_litter + &
root_litter + &
(direct_dead+indirect_dead) * (currentCohort%bdead+currentCohort%bsw)
delta_individual = delta_individual + &
direct_dead + &
indirect_dead
currentCohort => currentCohort%taller
end do
! Update the amount of carbon exported from the site through logging
! operations. Currently we assume only above-ground portion
! of the tree bole that experienced "direct" logging is exported
! This portion is known as "trunk_product_site
currentSite%flux_out = currentSite%flux_out + trunk_product_site
currentSite%resources_management%trunk_product_site = &
currentSite%resources_management%trunk_product_site + &
trunk_product_site
currentSite%resources_management%delta_litter_stock = &
currentSite%resources_management%delta_litter_stock + &
delta_litter_stock
currentSite%resources_management%delta_biomass_stock = &
currentSite%resources_management%delta_biomass_stock + &
delta_biomass_stock
currentSite%resources_management%delta_individual = &
currentSite%resources_management%delta_individual + &
delta_individual
currentCohort => newPatch%shortest
do while(associated(currentCohort))
call carea_allom(currentCohort%dbh,currentCohort%n,currentSite%spread,currentCohort%pft,currentCohort%c_area)
currentCohort => currentCohort%taller
enddo
end subroutine logging_litter_fluxes
end module EDLoggingMortalityMod